Alexandru Gagniuc (mr.nuke.me@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4810
-gerrit
commit cb733af72e3fd026c21fe6d8e85064c1918fa80a Author: Alexandru Gagniuc mr.nuke.me@gmail.com Date: Fri Jan 24 19:49:07 2014 -0600
YOU SHALL NOT MERGE!
, _,- (\ _,-',' \ ,-" ,' \ ,' ,' \ _:.----__.-."-._,-._ \ .-".:--`:::::.:.:' ) `-. \ `. ::L .::::::'`-._ ( ) : \ ":::::::' `-. `-_ ) ,' \.._/_`:::,' `. . `-: :" _ """ `-_ . ` `. "\"":--\ `-.__ ` . `. \':: \ _-"__`--.__ ` . `. _,--..- \ :: _-":)( ""-._ ` `.-'' \`:`-":::/ \ . . `-. : :\:::::::' \ ` . `. : :\:':':' . \ `, : : : \ . \ . `. : ,- __`:\ . \ . ` ,' ,: : ,-' _,---"" : \ ' \ . :-" ,' ,-"" : \: . : \ ` ' ,' / ' : : \ . \ . _,' ,-' : . ' : :` `,-' ,--' : : : ,'-._,' ,-' _: : :8: ,--' :dd`-._,'-._.__-""' ,' ,----' _.----' __..--"" ""
cbfstool: add preliminary partitioning suport
Based on Proposal 2 of my user page
Change-Id: I6770a9f8a459b4f204f5a75b98897a502af3ac66 Signed-off-by: Alexandru Gagniuc mr.nuke.me@gmail.com --- util/cbfstool/Makefile.inc | 1 + util/cbfstool/cbfs.h | 15 ++++++- util/cbfstool/cbfs_image.c | 58 ++++++++++++++++++++++++ util/cbfstool/cbfs_image.h | 2 + util/cbfstool/cbfs_partition.c | 100 +++++++++++++++++++++++++++++++++++++++++ util/cbfstool/cbfs_partition.h | 24 ++++++++++ util/cbfstool/cbfstool.c | 2 + 7 files changed, 201 insertions(+), 1 deletion(-)
diff --git a/util/cbfstool/Makefile.inc b/util/cbfstool/Makefile.inc index fc120f3..c5d284c 100644 --- a/util/cbfstool/Makefile.inc +++ b/util/cbfstool/Makefile.inc @@ -3,6 +3,7 @@ cbfsobj += cbfstool.o cbfsobj += common.o cbfsobj += compress.o cbfsobj += cbfs_image.o +cbfsobj += cbfs_partition.o cbfsobj += cbfs-mkstage.o cbfsobj += cbfs-mkpayload.o cbfsobj += fit.o diff --git a/util/cbfstool/cbfs.h b/util/cbfstool/cbfs.h index 35d0670..423e903 100644 --- a/util/cbfstool/cbfs.h +++ b/util/cbfstool/cbfs.h @@ -35,13 +35,26 @@ struct cbfs_header { uint32_t align; uint32_t offset; uint32_t architecture; /* Version 2 */ - uint32_t pad[1]; + uint32_t ptable_offset; } __attribute__ ((packed));
#define CBFS_ARCHITECTURE_UNKNOWN 0xFFFFFFFF #define CBFS_ARCHITECTURE_X86 0x00000001 #define CBFS_ARCHITECTURE_ARMV7 0x00000010
+#define CBFS_PARTITION_MAGIC 0x43425054 /* "CBPT" in ASCII */ +#define CBFS_PARTITION_NAME_LEN 32 +#define CBFS_PARTITION_ENTRY_LEN 0x30 +#define CBFS_PARTITION_ENTRY_ALIGN 0x10 + +struct cbfs_partition { + uint32_t magic; + uint32_t offset; + uint32_t size; + uint32_t flags; + char name[32]; +}; /* Don't fucking pack this. If you need this packed, you have a bug */ + #define CBFS_FILE_MAGIC "LARCHIVE"
struct cbfs_file { diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c index 401654e..966aeea 100644 --- a/util/cbfstool/cbfs_image.c +++ b/util/cbfstool/cbfs_image.c @@ -25,6 +25,7 @@
#include "common.h" #include "cbfs_image.h" +#include "cbfs_partition.h"
/* The file name align is not defined in CBFS spec -- only a preference by * (old) cbfstool. */ @@ -145,10 +146,12 @@ int cbfs_image_create(struct cbfs_image *image, struct buffer *bootblock, int32_t bootblock_offset, int32_t header_offset, + int32_t ptable_offset, int32_t entries_offset) { struct cbfs_header *header; struct cbfs_file *entry; + struct cbfs_partition part; uint32_t cbfs_len; size_t entry_header_len;
@@ -159,6 +162,8 @@ int cbfs_image_create(struct cbfs_image *image,
if (buffer_create(&image->buffer, size, "(new)") != 0) return -1; + if ((image->ptable = malloc(sizeof(part) * 11)) == NULL) + return -1; image->header = NULL; memset(image->buffer.data, CBFS_CONTENT_DEFAULT_VALUE, size);
@@ -229,6 +234,33 @@ int cbfs_image_create(struct cbfs_image *image, if (header_offset > entries_offset && header_offset < cbfs_len) cbfs_len = header_offset; cbfs_len -= entries_offset + align + entry_header_len; + + /* + * Now find space for the partition table. + * Pre-allocate 10 entries for now. This should be sufficient for most + * use-cases, and makes sure we don't have to reduce the final entry. + * FIXME: Only works for bootblock on top. We really should listen to + * the wisdom of the caller and put this where requested. + */ + ptable_offset = header_offset - cbfs_ptable_calc_size(10); + /* Align down */ + ptable_offset &= ~(CBFS_PARTITION_ENTRY_ALIGN - 1); + cbfs_len -= (bootblock_offset - ptable_offset); + if (IS_TOP_ALIGNED_ADDRESS(header_offset)) + header_offset += (int32_t) size; + header->ptable_offset = ntohl(ptable_offset); + + LOG("pizdatable offset 0x%x\n", ptable_offset); + + /* No, don't use ntohl shit here */ + cbfs_partition_entry_init(&image->ptable[0], + "coreboot", entries_offset, cbfs_len, 0); + /* Terminate ptable list */ + image->ptable[1].magic = 0xFFFFFFFF; + + cbfs_ptable_serialize(image->buffer.data + ptable_offset, + image->ptable); + cbfs_create_empty_entry(image, entry, cbfs_len, ""); LOG("Created CBFS image (capacity = %d bytes)\n", cbfs_len); return 0; @@ -236,6 +268,9 @@ int cbfs_image_create(struct cbfs_image *image,
int cbfs_image_from_file(struct cbfs_image *image, const char *filename) { + uint32_t ptable_offset; + size_t parts; + if (buffer_from_file(&image->buffer, filename) != 0) return -1; DEBUG("read_cbfs_image: %s (%zd bytes)\n", image->buffer.name, @@ -247,6 +282,24 @@ int cbfs_image_from_file(struct cbfs_image *image, const char *filename) cbfs_image_delete(image); return -1; } + + ptable_offset = ntohl(image->header->ptable_offset); + if (ptable_offset == 0xffffffff) { + LOG("No partition table found. Old image format?\n"); + image->ptable = NULL; + } else { + /* Make this a debug. We'll print more info later */ + DEBUG("Partition table found at 0x" PRIu32 "\n", ptable_offset); + parts = cbfs_ptable_find_num_entries(image->buffer.data + ptable_offset, + image->buffer.size - ptable_offset); + DEBUG("Found %lu entries\n", parts); + if (parts) { + image->ptable = malloc(CBFS_PARTITION_ENTRY_LEN * parts); + cbfs_ptable_deserialize(image->ptable, image->buffer.data + ptable_offset); + } + + } + cbfs_fix_legacy_size(image);
return 0; @@ -261,7 +314,10 @@ int cbfs_image_write_file(struct cbfs_image *image, const char *filename) int cbfs_image_delete(struct cbfs_image *image) { buffer_delete(&image->buffer); + if (image->ptable) + free(image->ptable); image->header = NULL; + image->ptable = NULL; return 0; }
@@ -658,6 +714,8 @@ int cbfs_print_entry_info(struct cbfs_image *image, struct cbfs_file *entry, int cbfs_print_directory(struct cbfs_image *image) { cbfs_print_header_info(image); + printf("%-30s %-10s Size\n", "Partition name", "Offset"); + cbfs_print_partitions(image->ptable); printf("%-30s %-10s %-12s Size\n", "Name", "Offset", "Type"); cbfs_walk(image, cbfs_print_entry_info, NULL); return 0; diff --git a/util/cbfstool/cbfs_image.h b/util/cbfstool/cbfs_image.h index 7ad418a..847ee5d 100644 --- a/util/cbfstool/cbfs_image.h +++ b/util/cbfstool/cbfs_image.h @@ -29,6 +29,7 @@ struct cbfs_image { struct buffer buffer; struct cbfs_header *header; + struct cbfs_partition *ptable; };
/* Creates an empty CBFS image by given size, and description to its content @@ -43,6 +44,7 @@ int cbfs_image_create(struct cbfs_image *image, struct buffer *bootblock, int32_t bootblock_offset, int32_t header_offset, + int32_t ptable_offset, int32_t entries_offset);
/* Loads a CBFS image from file. Returns 0 on success, otherwise non-zero. */ diff --git a/util/cbfstool/cbfs_partition.c b/util/cbfstool/cbfs_partition.c new file mode 100644 index 0000000..3de71e1 --- /dev/null +++ b/util/cbfstool/cbfs_partition.c @@ -0,0 +1,100 @@ +/* + * Manipulators for CBFS partitions + * + * Copyright (C) 2014 Alexandru Gagniuc mr.nuke.me@gmail.com + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#include "cbfs_partition.h" +#include "endian_stream.h" + +#include <stdio.h> +#include <string.h> + +size_t cbfs_ptable_calc_size(size_t num_entries) +{ + /* The last 4 bytes are the table terminator */ + return CBFS_PARTITION_ENTRY_LEN * num_entries + 4; +} + +void cbfs_partition_entry_init(struct cbfs_partition *part, const char *name, + uint32_t offset, uint32_t size, uint32_t fags) +{ + part->magic = CBFS_PARTITION_MAGIC; + part->offset = offset; + part->size = size; + part->flags = fags; + strncpy(part->name, name, CBFS_PARTITION_NAME_LEN); +} + +void cbfs_partition_serialize(void *dest, const struct cbfs_partition *part) +{ + h_to_be32(part->magic, dest + 0); + h_to_be32(part->offset, dest + 4); + h_to_be32(part->size, dest + 8); + h_to_be32(part->flags, dest + 12); + memset(dest + 16, 0xff, CBFS_PARTITION_NAME_LEN); + strncpy(dest + 16, part->name, CBFS_PARTITION_NAME_LEN); +} + +void cbfs_partition_deserialize(struct cbfs_partition *part, const void *src) +{ + part->magic = be32_to_h(src + 0); + part->offset = be32_to_h(src + 4); + part->size = be32_to_h(src + 8); + part->flags = be32_to_h(src + 12); + strncpy(part->name, src + 16, CBFS_PARTITION_NAME_LEN); +} + +void cbfs_ptable_serialize(void *dest, const struct cbfs_partition *part) +{ + while (part->magic == CBFS_PARTITION_MAGIC) { + cbfs_partition_serialize(dest, part); + part++; + dest += CBFS_PARTITION_ENTRY_LEN; + } + /* Terminate the list */ + h_to_be32(0xffffffff, dest); +} + +void cbfs_ptable_deserialize(struct cbfs_partition *part, const void *src) +{ + do { + cbfs_partition_deserialize(part, src); + part++; + src += CBFS_PARTITION_ENTRY_LEN; + } while(part->magic == CBFS_PARTITION_MAGIC); +} + +/* + * Find the number of partition table entries in a given memory block + */ +size_t cbfs_ptable_find_num_entries(void *ptable, size_t memlen) +{ + uint32_t magic; + size_t offset = 0, num_entries = 0; + + while (be32_to_h(ptable + offset) == CBFS_PARTITION_MAGIC) { + /* Complete entry? */ + if (offset + CBFS_PARTITION_ENTRY_LEN > memlen) + break; + + offset += CBFS_PARTITION_ENTRY_LEN; + num_entries++; + + if (offset > memlen) + break; + } + return num_entries; +} + +void cbfs_print_partitions(const struct cbfs_partition *ptable) +{ + while (ptable->magic == CBFS_PARTITION_MAGIC) { + printf("%-30s 0x%-8x %d\n", + ptable->name, + ptable->offset, + ptable->size); + ptable++; + } +} diff --git a/util/cbfstool/cbfs_partition.h b/util/cbfstool/cbfs_partition.h new file mode 100644 index 0000000..f1d8129 --- /dev/null +++ b/util/cbfstool/cbfs_partition.h @@ -0,0 +1,24 @@ +/* + * Prototypes for manipulating for CBFS partitions + * + * Copyright (C) 2014 Alexandru Gagniuc mr.nuke.me@gmail.com + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#ifndef __CBFS_PARTITION_H +#define __CBFS_PARTITION_H + +#include "cbfs.h" +#include <stddef.h> + +void cbfs_partition_entry_init(struct cbfs_partition *part, const char *name, + uint32_t offset, uint32_t size, uint32_t flags); +void cbfs_partition_serialize(void *dest, const struct cbfs_partition *part); +void cbfs_partition_deserialize(struct cbfs_partition *part, const void *src); +size_t cbfs_ptable_calc_size(size_t num_entries); +void cbfs_ptable_serialize(void *dest, const struct cbfs_partition *part); +void cbfs_ptable_deserialize(struct cbfs_partition *part, const void *src); +size_t cbfs_ptable_find_num_entries(void *ptable, size_t memlen); + +void cbfs_print_partitions(const struct cbfs_partition *ptable); +#endif /* __CBFS_PARTITION_H */ diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c index 34002a9..0040a98 100644 --- a/util/cbfstool/cbfstool.c +++ b/util/cbfstool/cbfstool.c @@ -55,6 +55,7 @@ static struct param { uint32_t pagesize; uint32_t offset; uint32_t top_aligned; + uint32_t ptable_offset; int fit_empty_entries; comp_algo algo; /* for linux payloads */ @@ -373,6 +374,7 @@ static int cbfs_create(void) &bootblock, param.baseaddress, param.headeroffset, + param.ptable_offset, param.offset) != 0) { ERROR("Failed to create %s.\n", param.cbfs_name); return 1;