From 678234467f232b147bec7cda753bbced4e67da25 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Mon, 13 Apr 2009 14:14:51 -0400 Subject: [PATCH] Initial support for running CBFS payloads. Add boot menu option for CBFS payloads. Rework "override" system so that it is done per BEV. Add file prefix scanning code to CBFS. Add CBFS payload launching support. --- src/boot.c | 61 ++++++++++++++++------ src/boot.h | 4 +- src/coreboot.c | 134 ++++++++++++++++++++++++++++++++++++++++++------- src/util.c | 27 +++++++++- src/util.h | 6 ++- 5 files changed, 196 insertions(+), 36 deletions(-) diff --git a/src/boot.c b/src/boot.c index 6b4e985..fe1c6bf 100644 --- a/src/boot.c +++ b/src/boot.c @@ -47,6 +47,12 @@ boot_setup() ie++; } + if (CONFIG_COREBOOT_FLASH) { + ie->type = IPL_TYPE_CBFS; + ie->description = "CBFS"; + ie++; + } + IPL.bevcount = ie - IPL.bev; SET_EBDA(boot_sequence, 0xffff); if (CONFIG_COREBOOT) { @@ -170,6 +176,23 @@ menu_show_cdrom(struct ipl_entry_s *ie, int menupos) return ATA.cdcount; } +// Show coreboot-fs menu item. +static int +menu_show_cbfs(struct ipl_entry_s *ie, int menupos) +{ + int count = 0; + for (;;) { + const char *filename = cbfs_findNprefix("img/", count); + if (!filename) + break; + printf("%d. Payload [%s]\n", menupos + count, &filename[4]); + count++; + if (count > 8) + break; + } + return count; +} + // Show IPL option menu. static void interactive_bootmenu() @@ -208,6 +231,9 @@ interactive_bootmenu() case IPL_TYPE_CDROM: sc = menu_show_cdrom(ie, menupos); break; + case IPL_TYPE_CBFS: + sc = menu_show_cbfs(ie, menupos); + break; default: sc = menu_show_default(ie, menupos); break; @@ -231,17 +257,7 @@ interactive_bootmenu() choice -= subcount[bev]; bev++; } - - switch (IPL.bev[bev].type) { - case IPL_TYPE_HARDDISK: - // A harddrive request enables a BCV order. - IPL.bcv_override = choice-1; - break; - case IPL_TYPE_CDROM: - // Select cdrom to boot from. - IPL.cdrom_override = choice-1; - break; - } + IPL.bev[bev].subchoice = choice-1; // Add user choice to the boot order. IPL.bootorder = (IPL.bootorder << 4) | (bev+1); @@ -275,7 +291,7 @@ boot_prep() interactive_bootmenu(); // Run BCVs - int override = IPL.bcv_override; + int override = IPL.bev[1].subchoice; if (override < IPL.bcvcount) run_bcv(&IPL.bcv[override]); int i; @@ -343,11 +359,11 @@ boot_disk(u8 bootdrv, int checksig) // Boot from a CD-ROM static void -boot_cdrom() +boot_cdrom(struct ipl_entry_s *ie) { if (! CONFIG_CDROM_BOOT) return; - int status = cdrom_boot(IPL.cdrom_override); + int status = cdrom_boot(ie->subchoice); if (status) { printf("Boot failed: Could not read from CDROM (code %04x)\n", status); return; @@ -363,6 +379,18 @@ boot_cdrom() call_boot_entry(bootseg, bootip, bootdrv); } +// Boot from a CD-ROM +static void +boot_cbfs(struct ipl_entry_s *ie) +{ + if (! CONFIG_COREBOOT_FLASH) + return; + const char *filename = cbfs_findNprefix("img/", ie->subchoice); + if (! filename) + return; + cbfs_run_payload(filename); +} + static void do_boot(u16 seq_nr) { @@ -403,7 +431,10 @@ do_boot(u16 seq_nr) boot_disk(0x80, 1); break; case IPL_TYPE_CDROM: - boot_cdrom(); + boot_cdrom(ie); + break; + case IPL_TYPE_CBFS: + boot_cbfs(ie); break; case IPL_TYPE_BEV: call_boot_entry(ie->vector >> 16, ie->vector & 0xffff, 0); diff --git a/src/boot.h b/src/boot.h index f251096..816fed5 100644 --- a/src/boot.h +++ b/src/boot.h @@ -9,7 +9,7 @@ struct ipl_entry_s { u16 type; - u16 flags; + u16 subchoice; u32 vector; const char *description; }; @@ -18,7 +18,6 @@ struct ipl_s { struct ipl_entry_s bev[8]; struct ipl_entry_s bcv[8]; int bevcount, bcvcount; - int bcv_override, cdrom_override; u32 bootorder; int checkfloppysig; }; @@ -26,6 +25,7 @@ struct ipl_s { #define IPL_TYPE_FLOPPY 0x01 #define IPL_TYPE_HARDDISK 0x02 #define IPL_TYPE_CDROM 0x03 +#define IPL_TYPE_CBFS 0x20 #define IPL_TYPE_BEV 0x80 diff --git a/src/coreboot.c b/src/coreboot.c index 9fd5e0f..feccad3 100644 --- a/src/coreboot.c +++ b/src/coreboot.c @@ -322,32 +322,70 @@ struct cbfs_file { u32 type; u32 checksum; u32 offset; + char filename[0]; } PACKED; static struct cbfs_file * -cbfs_find(char *fname) +cbfs_search(struct cbfs_file *file) +{ + for (;;) { + if (file < (struct cbfs_file *)(0xFFFFFFFF - ntohl(CBHDR->romsize))) + return NULL; + if (file->magic == CBFS_FILE_MAGIC) + return file; + file = (void*)file + ntohl(CBHDR->align); + } +} + +static struct cbfs_file * +cbfs_getfirst() { - if (! CONFIG_COREBOOT_FLASH) - return NULL; if (! CBHDR) return NULL; + return cbfs_search((void *)(0 - ntohl(CBHDR->romsize) + ntohl(CBHDR->offset))); +} - dprintf(3, "Searching CBFS for %s\n", fname); +static struct cbfs_file * +cbfs_getnext(struct cbfs_file *file) +{ + file = (void*)file + ALIGN(ntohl(file->len) + ntohl(file->offset), ntohl(CBHDR->align)); + return cbfs_search(file); +} - struct cbfs_file *file = (void *)(0 - ntohl(CBHDR->romsize) + ntohl(CBHDR->offset)); - for (;;) { - if (file < (struct cbfs_file *)(0xFFFFFFFF - ntohl(CBHDR->romsize))) - return NULL; - if (file->magic != CBFS_FILE_MAGIC) { - file = (void*)file + ntohl(CBHDR->align); - continue; - } +static struct cbfs_file * +cbfs_findfile(const char *fname) +{ + if (! CONFIG_COREBOOT_FLASH) + return NULL; - dprintf(3, "Found CBFS file %s\n", (char*)file + sizeof(*file)); - if (streq(fname, (char*)file + sizeof(*file))) + dprintf(3, "Searching CBFS for %s\n", fname); + struct cbfs_file *file; + for (file = cbfs_getfirst(); file; file = cbfs_getnext(file)) { + dprintf(3, "Found CBFS file %s\n", file->filename); + if (streq(fname, file->filename)) return file; - file = (void*)file + ALIGN(ntohl(file->len) + ntohl(file->offset), ntohl(CBHDR->align)); } + return NULL; +} + +const char * +cbfs_findNprefix(const char *prefix, int n) +{ + if (! CONFIG_COREBOOT_FLASH) + return NULL; + + dprintf(3, "Searching CBFS for prefix %s\n", prefix); + int len = strlen(prefix); + struct cbfs_file *file; + for (file = cbfs_getfirst(); file; file = cbfs_getnext(file)) { + dprintf(3, "Found CBFS file %s\n", file->filename); + if (memeq(prefix, file->filename, len)) { + if (n <= 0) + return file->filename; + n--; + } + } + return NULL; } static char @@ -375,14 +413,14 @@ cb_find_optionrom(u32 vendev) char fname[17]; // Ughh - poor man's sprintf of "pci%04x,%04x.rom" - *(u32*)fname = 0x20696370; // "pci" + *(u32*)fname = 0x20696370; // "pci " *(u32*)&fname[3] = hexify4(vendev); fname[7] = ','; *(u32*)&fname[8] = hexify4(vendev >> 16); *(u32*)&fname[12] = 0x6d6f722e; // ".rom" fname[16] = '\0'; - struct cbfs_file *file = cbfs_find(fname); + struct cbfs_file *file = cbfs_findfile(fname); if (!file) return NULL; // Found it. @@ -390,6 +428,68 @@ cb_find_optionrom(u32 vendev) return (void*)file + ntohl(file->offset); } +struct cbfs_payload_segment { + u32 type; + u32 compression; + u32 offset; + u64 load_addr; + u32 len; + u32 mem_len; +} PACKED; + +#define PAYLOAD_SEGMENT_BSS 0x20535342 +#define PAYLOAD_SEGMENT_ENTRY 0x52544E45 + +#define CBFS_COMPRESS_NONE 0 + +struct cbfs_payload { + struct cbfs_payload_segment segments[1]; +}; + +void +cbfs_run_payload(const char *filename) +{ + dprintf(1, "Run %s\n", filename); + struct cbfs_file *file = cbfs_findfile(filename); + if (!file) + return; + struct cbfs_payload *pay = (void*)file + ntohl(file->offset); + struct cbfs_payload_segment *seg = pay->segments; + for (;;) { + if (seg->compression != htonl(CBFS_COMPRESS_NONE)) { + dprintf(1, "No support for compressed payloads (%x)\n" + , seg->compression); + return; + } + void *src = (void*)pay + ntohl(seg->offset); + void *dest = (void*)ntohl((u32)seg->load_addr); + u32 src_len = ntohl(seg->len); + u32 dest_len = ntohl(seg->mem_len); + switch (seg->type) { + case PAYLOAD_SEGMENT_BSS: + dprintf(3, "BSS segment %d@%p\n", dest_len, dest); + memset(dest, 0, dest_len); + break; + case PAYLOAD_SEGMENT_ENTRY: { + dprintf(1, "Calling addr %p\n", dest); + void (*func)() = dest; + func(); + return; + } + default: + dprintf(3, "Segment %x %d@%p -> %d@%p\n" + , seg->type, src_len, src, dest_len, dest); + if (src_len > dest_len) + src_len = dest_len; + memcpy(dest, src, src_len); + if (dest_len > src_len) + memset(dest + src_len, 0, dest_len - src_len); + break; + } + seg++; + } +} + void coreboot_setup(void) { diff --git a/src/util.c b/src/util.c index 2b46ea2..df0e993 100644 --- a/src/util.c +++ b/src/util.c @@ -117,9 +117,34 @@ checksum(void *buf, u32 len) return checksum_far(GET_SEG(SS), buf, len); } +size_t +strlen(const char *s) +{ + if (__builtin_constant_p(s)) + return __builtin_strlen(s); + const char *p = s; + while (*p) + p++; + return p-s; +} + +// Compare two areas of memory. +int +memeq(const void *s1, const void *s2, size_t n) +{ + while (n) { + if (*(u8*)s1 != *(u8*)s2) + return 0; + s1++; + s2++; + n--; + } + return 1; +} + // Compare two strings. int -streq(char *s1, char *s2) +streq(const char *s1, const char *s2) { for (;;) { if (*s1 != *s2) diff --git a/src/util.h b/src/util.h index 9ce220a..cb2d46f 100644 --- a/src/util.h +++ b/src/util.h @@ -69,7 +69,9 @@ static inline u64 rdtscll(void) inline u32 stack_hop(u32 eax, u32 edx, u32 ecx, void *func); u8 checksum_far(u16 buf_seg, void *buf_far, u32 len); u8 checksum(void *buf, u32 len); -int streq(char *s1, char *s2); +int memeq(const void *s1, const void *s2, size_t n); +size_t strlen(const char *s); +int streq(const char *s1, const char *s2); void *memset(void *s, int c, size_t n); void *memcpy(void *d1, const void *s1, size_t len); inline void memcpy_far(u16 d_seg, void *d_far @@ -165,7 +167,9 @@ void smp_probe_setup(void); void smbios_init(void); // coreboot.c +const char *cbfs_findNprefix(const char *prefix, int n); void *cb_find_optionrom(u32 vendev); +void cbfs_run_payload(const char *filename); void coreboot_setup(); // vgahooks.c -- 2.25.1