X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=util%2Fcbfstool%2Fcommon.c;h=cbf0757aaab152ba045394fd583b45d75df868ea;hb=fde7025b611c58888fca4f6ba6444708930b9107;hp=9227337c57a6c6aff9f5440ffb3601e9458bcab3;hpb=45d8a83b29e9eb2e20f4ca39914a42561a2c1f79;p=coreboot.git diff --git a/util/cbfstool/common.c b/util/cbfstool/common.c index 9227337c5..cbf0757aa 100644 --- a/util/cbfstool/common.c +++ b/util/cbfstool/common.c @@ -21,12 +21,23 @@ #include #include #include +#include #include "common.h" #include "cbfs.h" #include "elf.h" #define dprintf +uint32_t getfilesize(const char *filename) +{ + uint32_t size; + FILE *file = fopen(filename, "rb"); + fseek(file, 0, SEEK_END); + size = ftell(file); + fclose(file); + return size; +} + void *loadfile(const char *filename, uint32_t * romsize_p, void *content, int place) { @@ -36,10 +47,16 @@ void *loadfile(const char *filename, uint32_t * romsize_p, void *content, fseek(file, 0, SEEK_END); *romsize_p = ftell(file); fseek(file, 0, SEEK_SET); - if (!content) + if (!content) { content = malloc(*romsize_p); - else if (place == SEEK_END) + if (!content) { + printf("Could not get %d bytes for file %s\n", + *romsize_p, filename); + exit(1); + } + } else if (place == SEEK_END) content -= *romsize_p; + if (!fread(content, *romsize_p, 1, file)) { printf("failed to read %s\n", filename); return NULL; @@ -73,11 +90,23 @@ void *loadrom(const char *filename) return romarea; } -void writerom(const char *filename, void *start, uint32_t size) +int writerom(const char *filename, void *start, uint32_t size) { FILE *file = fopen(filename, "wb"); - fwrite(start, size, 1, file); + if (!file) { + fprintf(stderr, "Could not open '%s' for writing: ", filename); + perror(""); + return 1; + } + + if (fwrite(start, size, 1, file) != 1) { + fprintf(stderr, "Could not write to '%s': ", filename); + perror(""); + return 1; + } + fclose(file); + return 0; } int cbfs_file_header(uint32_t physaddr) @@ -111,10 +140,27 @@ struct filetypes_t { {CBFS_COMPONENT_STAGE, "stage"}, {CBFS_COMPONENT_PAYLOAD, "payload"}, {CBFS_COMPONENT_OPTIONROM, "optionrom"}, + {CBFS_COMPONENT_BOOTSPLASH, "bootsplash"}, + {CBFS_COMPONENT_RAW, "raw"}, + {CBFS_COMPONENT_VSA, "vsa"}, + {CBFS_COMPONENT_MBI, "mbi"}, + {CBFS_COMPONENT_MICROCODE, "microcode"}, + {CBFS_COMPONENT_CMOS_DEFAULT, "cmos default"}, {CBFS_COMPONENT_DELETED, "deleted"}, {CBFS_COMPONENT_NULL, "null"} }; +void print_supported_filetypes(void) +{ + int i, number = ARRAY_SIZE(filetypes); + + for (i=0; ibootblocksize), + basename((char *)filename), romsize / 1024, ntohl(master_header->bootblocksize), romsize, ntohl(master_header->offset), align); printf("%-30s %-10s %-12s Size\n", "Name", "Offset", "Type"); uint32_t current = phys_start; @@ -149,9 +195,11 @@ void print_cbfs_directory(const char *filename) struct cbfs_file *thisfile = (struct cbfs_file *)phys_to_virt(current); uint32_t length = ntohl(thisfile->len); - printf("%-30s 0x%-8x %-12s %d\n", - (const char *)(phys_to_virt(current) + - sizeof(struct cbfs_file)), + char *fname = (char *)(phys_to_virt(current) + sizeof(struct cbfs_file)); + if (strlen(fname) == 0) + fname = "(empty)"; + + printf("%-30s 0x%-8x %-12s %d\n", fname, current - phys_start, strfiletype(ntohl(thisfile->type)), length); current = @@ -160,6 +208,69 @@ void print_cbfs_directory(const char *filename) } } +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 file %.30s 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, "wb"); + if (!outfile) + { + printf("Could not open the file %s for writing. Aborting.\n", outpath); + return 1; + } + + if (ntohl(thisfile->type) != CBFS_COMPONENT_RAW) + { + printf("Warning: only 'raw' files are safe to extract.\n"); + } + + fwrite(((char *)thisfile) + + ntohl(thisfile->offset), length, 1, outfile); + + fclose(outfile); + printf("Successfully dumped the file.\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; @@ -199,40 +310,43 @@ int add_file_to_cbfs(void *content, uint32_t contentsize, uint32_t location) dprintf("copying data\n"); memcpy(phys_to_virt(current), content, contentsize); - break; - } - if (location == 0) - continue; - - /* CBFS has the constraint that the chain always moves up in memory. so once - we're past the place we seek, we don't need to look any further */ - if (current > location) { - printf - ("the requested space is not available\n"); - return 1; + return 0; } + if (location != 0) { + /* CBFS has the constraint that the chain always moves up in memory. so once + we're past the place we seek, we don't need to look any further */ + if (current > location) { + printf + ("the requested space is not available\n"); + return 1; + } - /* Is the requested location inside the current chunk? */ - if ((current < location) - && ((location + contentsize) <= (current + length))) { - /* Split it up. In the next iteration the code will be at the right place. */ - dprintf("split up. new length: %x\n", - location - current - - ntohl(thisfile->offset)); - thisfile->len = - htonl(location - current - - ntohl(thisfile->offset)); - struct cbfs_file *nextfile = - cbfs_create_empty_file(location, - length - (location - - current)); + /* Is the requested location inside the current chunk? */ + if ((current < location) + && ((location + contentsize) <= + (current + length))) { + /* Split it up. In the next iteration the code will be at the right place. */ + dprintf("split up. new length: %x\n", + location - current - + ntohl(thisfile->offset)); + thisfile->len = + htonl(location - current - + ntohl(thisfile->offset)); + struct cbfs_file *nextfile = + cbfs_create_empty_file(location, + length - + (location - + current)); + } } } current = ALIGN(current + ntohl(thisfile->len) + ntohl(thisfile->offset), align); } - return 0; + printf("Could not add the file to CBFS, it's probably too big.\n"); + printf("File size: %d bytes (%d KB).\n", contentsize, contentsize/1024); + return 1; } /* returns new data block with cbfs_file header, suitable to dump into the ROM. location returns @@ -255,6 +369,12 @@ void *create_cbfs_file(const char *filename, void *data, uint32_t * datasize, *location -= headersize; } void *newdata = malloc(*datasize + headersize); + if (!newdata) { + printf("Could not get %d bytes for CBFS file.\n", *datasize + + headersize); + exit(1); + } + memset(newdata, 0xff, *datasize + headersize); struct cbfs_file *nextfile = (struct cbfs_file *)newdata; strncpy(nextfile->magic, "LARCHIVE", 8); nextfile->len = htonl(*datasize); @@ -272,8 +392,15 @@ int create_cbfs_image(const char *romfile, uint32_t _romsize, { romsize = _romsize; unsigned char *romarea = malloc(romsize); + if (!romarea) { + printf("Could not get %d bytes of memory for CBFS image.\n", + romsize); + exit(1); + } memset(romarea, 0xff, romsize); - recalculate_rom_geometry(romarea); + + // Set up physical/virtual mapping + offset = romarea + romsize - 0x100000000ULL; if (align == 0) align = 64; @@ -291,6 +418,9 @@ int create_cbfs_image(const char *romfile, uint32_t _romsize, master_header->offset = htonl(0); ((uint32_t *) phys_to_virt(0xfffffffc))[0] = virt_to_phys(master_header); + + recalculate_rom_geometry(romarea); + struct cbfs_file *one_empty_file = cbfs_create_empty_file((0 - romsize) & 0xffffffff, romsize - bootblocksize - @@ -300,3 +430,58 @@ int create_cbfs_image(const char *romfile, uint32_t _romsize, writerom(romfile, romarea, romsize); return 0; } + +static int in_segment(int addr, int size, int gran) +{ + return ((addr & ~(gran - 1)) == ((addr + size) & ~(gran - 1))); +} + +uint32_t cbfs_find_location(const char *romfile, uint32_t filesize, + const char *filename, uint32_t alignment) +{ + void *rom = loadrom(romfile); + int filename_size = strlen(filename); + + int headersize = + sizeof(struct cbfs_file) + ALIGN(filename_size + 1, + 16) + sizeof(struct cbfs_stage); + int totalsize = headersize + filesize; + + uint32_t current = phys_start; + while (current < phys_end) { + if (!cbfs_file_header(current)) { + current += align; + continue; + } + struct cbfs_file *thisfile = + (struct cbfs_file *)phys_to_virt(current); + + uint32_t top = + current + ntohl(thisfile->len) + ntohl(thisfile->offset); + if (((ntohl(thisfile->type) == 0x0) + || (ntohl(thisfile->type) == 0xffffffff)) + && (ntohl(thisfile->len) + ntohl(thisfile->offset) >= + totalsize)) { + if (in_segment + (current + headersize, filesize, alignment)) + return current + headersize; + if ((ALIGN(current, alignment) + filesize < top) + && (ALIGN(current, alignment) - headersize > + current) + && in_segment(ALIGN(current, alignment), filesize, + alignment)) + return ALIGN(current, alignment); + if ((ALIGN(current, alignment) + alignment + filesize < + top) + && (ALIGN(current, alignment) + alignment - + headersize > current) + && in_segment(ALIGN(current, alignment) + alignment, + filesize, alignment)) + return ALIGN(current, alignment) + alignment; + } + current = + ALIGN(current + ntohl(thisfile->len) + + ntohl(thisfile->offset), align); + } + return 0; +}