Patchwork Raw payload extraction support in cbfstool

login
register
about
Submitter Aurélien
Date 2010-09-11 14:11:24
Message ID <AANLkTinCuuRNfNz4VGiRwXycb3iHGKHrgi_Wt_ZMgLDY@mail.gmail.com>
Download mbox | patch
Permalink /patch/1917/
State New
Headers show

Comments

Aurélien - 2010-09-11 14:11:24
Hi,

If someone is interested by the feature, here's a patch to extract a raw
component (other types need decoding functions, which I did not write) from
a coreboot ROM.

My particular use-case it that I want to embed a chunk of data (own S/N, P/N
and things like that in my coreboot rom, so that this data is really tied to
the hardware and survives compact flash changes, etc). It was suggested that
I use DMI for this, and indeed it seems interesting, but my Alix.2 board has
currently no DMI support, and the current embedding method supposes a
recompilation of the rom. Hence, this method of extraction at run-time.

I found that using dd on /dev/mem to extract the running rom works well, at
the condition of not having STRICT_DEVMEM in the kernel, and reading the
whole image in one block. On my board:

# dd if=/dev/mem of=/tmp/dump.bin bs=512K count=1 skip=8191
# cbfstool /tmp/dump.bin extract boardata boarddata.bin

fills boarddata.bin with the contents of the boarddata cbfs component. Of
course you can use any rom image instead of the one extracted from RAM.

I tried to make a patch which reads from /dev/mem directly in 2 ways:
 - mmap()ing /dev/mem, but it seemed that it would be too specific a
modification to be accepted.
 - modifying the loadfile code to extensively use lseek to navigate in the
file, reading it like starting at the end, and deducing the size from the
CBFS header. This method works well for files, but does not for /dev/mem. So
it's relatively useless. I think the problem is due to a bug/feature in
/dev/mem implementation.

Signed-off-by: Aurelien Guillaume <aurelien@iwi.me>

Best regards.
Patrick Georgi - 2010-09-27 22:13:04
Am 11.09.2010 16:11, schrieb Aurélien:
> Hi,
> 
> If someone is interested by the feature, here's a patch to extract a raw
> component (other types need decoding functions, which I did not write)
> from a coreboot ROM.
> 
> My particular use-case it that I want to embed a chunk of data (own S/N,
> P/N and things like that in my coreboot rom, so that this data is really
> tied to the hardware and survives compact flash changes, etc). It was
> suggested that I use DMI for this, and indeed it seems interesting, but
> my Alix.2 board has currently no DMI support, and the current embedding
> method supposes a recompilation of the rom. Hence, this method of
> extraction at run-time.
> 
> I found that using dd on /dev/mem to extract the running rom works well,
> at the condition of not having STRICT_DEVMEM in the kernel, and reading
> the whole image in one block. On my board:
> 
> # dd if=/dev/mem of=/tmp/dump.bin bs=512K count=1 skip=8191
> # cbfstool /tmp/dump.bin extract boardata boarddata.bin
> 
> fills boarddata.bin with the contents of the boarddata cbfs component.
> Of course you can use any rom image instead of the one extracted from RAM.
> 
> I tried to make a patch which reads from /dev/mem directly in 2 ways:
>  - mmap()ing /dev/mem, but it seemed that it would be too specific a
> modification to be accepted.
>  - modifying the loadfile code to extensively use lseek to navigate in
> the file, reading it like starting at the end, and deducing the size
> from the CBFS header. This method works well for files, but does not for
> /dev/mem. So it's relatively useless. I think the problem is due to a
> bug/feature in /dev/mem implementation.
> 
> Signed-off-by: Aurelien Guillaume <aurelien@iwi.me>
I'll take care of that patch soonish, just quick (because it's late here
and I'm tired), so it's not forgotten: The writing code should open the
target file with "wb" to prevent CRLF mangling on windows.


Patrick
Peter Stuge - 2010-09-28 18:22:56
Aurélien wrote:
> I tried to make a patch which reads from /dev/mem directly in 2 ways:
>  - mmap()ing /dev/mem, but it seemed that it would be too specific a
> modification to be accepted.

See http://stuge.se/physrd.c for a fairly generic tool to do this.


//Peter
Aurélien - 2010-09-28 19:18:22
On Tue, Sep 28, 2010 at 8:22 PM, Peter Stuge <peter@stuge.se> wrote:

> Aurélien wrote:
> > I tried to make a patch which reads from /dev/mem directly in 2 ways:
> >  - mmap()ing /dev/mem, but it seemed that it would be too specific a
> > modification to be accepted.
>
> See http://stuge.se/physrd.c for a fairly generic tool to do this.
>
>
You're right, splitting the feature in two tools seems much more correct.
This way we can extract the ROM image, then extract the specific payload.

Thanks :)
Peter Stuge - 2010-09-28 19:55:39
Aurélien wrote:
> > > I tried to make a patch which reads from /dev/mem directly in 2 ways:
> > >  - mmap()ing /dev/mem, but it seemed that it would be too specific a
> > > modification to be accepted.
> >
> > See http://stuge.se/physrd.c for a fairly generic tool to do this.
> 
> You're right, splitting the feature in two tools seems much more
> correct. This way we can extract the ROM image, then extract the
> specific payload.

Well, for that purpose it's much better to simply use flashrom.


//Peter
Aurélien - 2010-09-28 20:16:50
On Tue, Sep 28, 2010 at 9:55 PM, Peter Stuge <peter@stuge.se> wrote:

> Aurélien wrote:
> > > > I tried to make a patch which reads from /dev/mem directly in 2 ways:
> > > >  - mmap()ing /dev/mem, but it seemed that it would be too specific a
> > > > modification to be accepted.
> > >
> > > See http://stuge.se/physrd.c for a fairly generic tool to do this.
> >
> > You're right, splitting the feature in two tools seems much more
> > correct. This way we can extract the ROM image, then extract the
> > specific payload.
>
> Well, for that purpose it's much better to simply use flashrom.
>
>
Probably, but flashrom takes slighly more time due to various calibration
routines (I could not find a way to disable those, but I didn't try very
hard), and is less integrable that just reading like this. I don't need much
portability between mainboards anyways.

In the general case however, you are right, the flashrom method seems much
more robust.
Carl-Daniel Hailfinger - 2010-09-28 23:27:47
[adding flashrom@flashrom.org to CC]

On 28.09.2010 22:16, Aurélien wrote:
> On Tue, Sep 28, 2010 at 9:55 PM, Peter Stuge <peter@stuge.se> wrote:
>> Aurélien wrote:
>>     
>>>>> I tried to make a patch which reads from /dev/mem directly in 2 ways:
>>>>>  - mmap()ing /dev/mem, but it seemed that it would be too specific a
>>>>> modification to be accepted.
>>>>>           
>>>> See http://stuge.se/physrd.c for a fairly generic tool to do this.
>>>>         
>>> You're right, splitting the feature in two tools seems much more
>>> correct. This way we can extract the ROM image, then extract the
>>> specific payload.
>>>       
>> Well, for that purpose it's much better to simply use flashrom.
>>
>>     
> Probably, but flashrom takes slighly more time due to various calibration
> routines (I could not find a way to disable those, but I didn't try very
> hard), 

If you already have a known-good delay function with microsecond
precision, you could use that instead of waiting for flashrom to
calibrate its own delay loop.


> and is less integrable that just reading like this. I don't need much
> portability between mainboards anyways.
>   

Yes, libflashrom is still not completely done. Most of the parts are
there, and we even have a bunch of different frontends, but the exported
interface needs to be decided upon before we start offering libflashrom


> In the general case however, you are right, the flashrom method seems much
> more robust.
>   

Thanks!

Regards,
Carl-Daniel
Peter Stuge - 2010-09-28 23:32:35
Carl-Daniel Hailfinger wrote:
> > flashrom takes slighly more time due to various calibration
> > routines (I could not find a way to disable those, but I didn't
> > try very hard), 
> 
> If you already have a known-good delay function with microsecond
> precision, you could use that instead of waiting for flashrom to
> calibrate its own delay loop.

I'd suggest a setting which makes flashrom skip all parallel flash
chips, to remove any need for calibration.

(To be more precise, the deciding factor is whether the chip is on
the local bus, or if there are some bus master(s) in between, but
that's generally equivalent to parallel vs. all others.)


//Peter
Carl-Daniel Hailfinger - 2010-09-29 00:02:39
On 29.09.2010 01:32, Peter Stuge wrote:
> Carl-Daniel Hailfinger wrote:
>   
>>> flashrom takes slighly more time due to various calibration
>>> routines (I could not find a way to disable those, but I didn't
>>> try very hard), 
>>>       
>> If you already have a known-good delay function with microsecond
>> precision, you could use that instead of waiting for flashrom to
>> calibrate its own delay loop.
>>     
>
> I'd suggest a setting which makes flashrom skip all parallel flash
> chips, to remove any need for calibration.
>   

That would break some Winbond LPC flash chips which require a few
milliseconds of delay between JEDEC toggle reads on erase.
And we also noticed that some SPI chips will react badly (corruption) to
a too tight RDSR instruction schedule.

flashrom on libpayload uses the libpayload-provided delay functions and
skips calibration. Given that LPC/FWH/SPI flash chips usually tolerate
longer than expected delays without problem, you could hook up
programmer_delay to udelay and save a second or so for calibration if
you don't need parallel flash.


> (To be more precise, the deciding factor is whether the chip is on
> the local bus, or if there are some bus master(s) in between, but
> that's generally equivalent to parallel vs. all others.)
>   

Network cards with parallel flash would be classified as "local bus"?

Regards,
Carl-Daniel
Peter Stuge - 2010-09-29 00:13:42
Carl-Daniel Hailfinger wrote:
> > I'd suggest a setting which makes flashrom skip all parallel flash
> > chips, to remove any need for calibration.
> 
> That would break some Winbond LPC flash chips which require a few
> milliseconds of delay between JEDEC toggle reads on erase.
> And we also noticed that some SPI chips will react badly (corruption)
> to a too tight RDSR instruction schedule.

Yay. I guess they would be disabled too, unless calibration has run.


> Given that LPC/FWH/SPI flash chips usually tolerate longer than
> expected delays without problem, you could hook up programmer_delay
> to udelay and save a second or so for calibration if you don't need
> parallel flash.

That sounds good!


> > (To be more precise, the deciding factor is whether the chip is on
> > the local bus, or if there are some bus master(s) in between, but
> > that's generally equivalent to parallel vs. all others.)
> 
> Network cards with parallel flash would be classified as "local bus"?

I believe bridges can make things more complicated. The assumption is
that any bus master will always ensure correct timing for the bus
where the chip is connected. You mentioned that there are exceptions,
to that, but I think it'll hold in general. A bridge in a PCI chip
that decodes into ROM may or may not ensure correct timing. I think
it would have to be set on a per-chip basis.


//Peter

Patch

Index: common.c
===================================================================
--- common.c	(revision 5802)
+++ common.c	(working copy)
@@ -207,6 +207,74 @@ 
 	}
 }
 
+int extract_file_from_cbfs(const char *filename, const char *payloadname, const char *outpath)
+{
+	// Identify the coreboot image.
+	printf(
+	     "%s: %d kB, bootblocksize %d, romsize %d, offset 0x%x\nAlignment: %d bytes\n\n",
+	     basename((char *)filename), romsize / 1024, ntohl(master_header->bootblocksize),
+	     romsize, ntohl(master_header->offset), align);
+
+	FILE *outfile = NULL;
+	uint32_t current = phys_start;
+	while (current < phys_end) {
+		if (!cbfs_file_header(current)) {
+			current += align;
+			continue;
+		}
+
+		// Locate the file start struct
+		struct cbfs_file *thisfile =
+		    (struct cbfs_file *)phys_to_virt(current);
+		// And its length
+		uint32_t length = ntohl(thisfile->len);
+		// Locate the file name
+		char *fname = (char *)(phys_to_virt(current) + sizeof(struct cbfs_file));
+		// It's not the file we are looking for..
+		if (strcmp(fname, payloadname) != 0)
+		{
+			current =
+			   ALIGN(current + ntohl(thisfile->len) +
+				  ntohl(thisfile->offset), align);
+			continue;
+		}
+
+		// Else, it's our file.
+		printf("Found %.30s payload at 0x%x, type %.12s, size %d\n", fname,
+		       current - phys_start, strfiletype(ntohl(thisfile->type)),
+		       length);
+
+		// If we are not dumping to stdout, open the out file.
+		outfile = fopen(outpath, "w");
+		if (!outfile)
+		{
+			printf("Could not open the file %s for writing. Aborting.\n", outpath); 
+			return 1;
+		}
+
+		switch (ntohl(thisfile->type))
+		{
+		case CBFS_COMPONENT_RAW:
+			fwrite(((char *)thisfile)
+					+ ntohl(thisfile->offset), length, 1, outfile);
+			break;
+
+		default:
+			printf("Error: this file type cannot be dumped.\n"
+				   "Supported file types: raw\n");
+			return 2;
+		}
+
+		fclose(outfile);
+		printf("Successfully dumped the payload.\n");
+
+		// We'll only dump one file.
+		return 0;
+	}
+	
+}
+
+
 int add_file_to_cbfs(void *content, uint32_t contentsize, uint32_t location)
 {
 	uint32_t current = phys_start;
Index: cbfstool.c
===================================================================
--- cbfstool.c	(revision 5802)
+++ cbfstool.c	(working copy)
@@ -30,7 +30,8 @@ 
 	CMD_ADD_STAGE,
 	CMD_CREATE,
 	CMD_LOCATE,
-	CMD_PRINT
+	CMD_PRINT,
+	CMD_EXTRACT,
 } cmd_t;
 
 struct command {
@@ -245,13 +246,34 @@ 
 	return 0;
 }
 
+static int cbfs_extract(int argc, char **argv)
+{
+	char *romname = argv[1];
+	char *cmd = argv[2];
+	void *rom = loadrom(romname);
+
+	if (rom == NULL) {
+		printf("Could not load ROM image '%s'.\n", romname);
+		return 1;
+	}
+	
+	if (argc != 5)
+	{
+		printf("Error: you must specify a CBFS name and a file to dump it in.\n");
+		return 1;
+	}
+
+	return extract_file_from_cbfs(romname, argv[3], argv[4]);
+}
+
 struct command commands[] = {
 	{CMD_ADD, "add", cbfs_add},
 	{CMD_ADD_PAYLOAD, "add-payload", cbfs_add_payload},
 	{CMD_ADD_STAGE, "add-stage", cbfs_add_stage},
 	{CMD_CREATE, "create", cbfs_create},
 	{CMD_LOCATE, "locate", cbfs_locate},
-	{CMD_PRINT, "print", cbfs_print}
+	{CMD_PRINT, "print", cbfs_print},
+	{CMD_EXTRACT, "extract", cbfs_extract},
 };
 
 void usage(void)
@@ -267,7 +289,8 @@ 
 	     " add-stage FILE NAME [COMP] [base]    Add a stage to the ROM\n"
 	     " create SIZE BOOTBLOCK [ALIGN]        Create a ROM file\n"
 	     " locate FILE NAME ALIGN               Find a place for a file of that size\n"
-	     " print                                Show the contents of the ROM\n\n"
+	     " print                                Show the contents of the ROM\n"
+	     " extract NAME FILE                    Extracts a raw payload from ROM\n\n"
 	     "TYPEs:\n"
 	     );
 	print_supported_filetypes();
Index: common.h
===================================================================
--- common.h	(revision 5802)
+++ common.h	(working copy)
@@ -68,6 +68,7 @@ 
 
 int add_file_to_cbfs(void *content, uint32_t contentsize, uint32_t location);
 void print_cbfs_directory(const char *filename);
+int extract_file_from_cbfs(const char *filename, const char *payloadname, const char *outpath);
 
 uint32_t cbfs_find_location(const char *romfile, uint32_t filesize,
 			    const char *filename, uint32_t align);