int cbfs_print_entry_info(struct cbfs_image *image, struct cbfs_file *entry, void *arg) { const char *name = CBFS_NAME(entry); struct cbfs_payload_segment *payload; FILE *fp = (FILE *)arg; if (!cbfs_is_valid_entry(image, entry)) { ERROR("cbfs_print_entry_info: Invalid entry at 0x%x\n", cbfs_get_entry_addr(image, entry)); return -1; } if (!fp) fp = stdout; fprintf(fp, "%-30s 0x%-8x %-12s %d\n", *name ? name : "(empty)", cbfs_get_entry_addr(image, entry), get_cbfs_entry_type_name(ntohl(entry->type)), ntohl(entry->len)); if (!verbose) return 0; DEBUG(" cbfs_file=0x%x, offset=0x%x, content_address=0x%x+0x%x\n", cbfs_get_entry_addr(image, entry), ntohl(entry->offset), cbfs_get_entry_addr(image, entry) + ntohl(entry->offset), ntohl(entry->len)); /* note the components of the subheader may be in host order ... */ switch (ntohl(entry->type)) { case CBFS_COMPONENT_STAGE: cbfs_print_stage_info((struct cbfs_stage *) CBFS_SUBHEADER(entry), fp); break; case CBFS_COMPONENT_PAYLOAD: payload = (struct cbfs_payload_segment *) CBFS_SUBHEADER(entry); while (payload) { /* Stop when PAYLOAD_SEGMENT_ENTRY seen. */ if (cbfs_print_payload_segment_info(payload, fp)) break; payload ++; } break; default: break; } return 0; }
/* Copy SPD data for on-board memory */ static void copy_spd(struct pei_data *peid) { const int gpio_vector[] = {67, 68, 69, -1}; int spd_index = get_gpios(gpio_vector); struct cbfs_file *spd_file; printk(BIOS_DEBUG, "SPD index %d\n", spd_index); spd_file = cbfs_get_file(CBFS_DEFAULT_MEDIA, "spd.bin"); if (!spd_file) die("SPD data not found."); if (ntohl(spd_file->len) < ((spd_index + 1) * sizeof(peid->spd_data[0]))) { printk(BIOS_ERR, "SPD index override to 0 - old hardware?\n"); spd_index = 0; } if (spd_file->len < sizeof(peid->spd_data[0])) die("Missing SPD data."); memcpy(peid->spd_data[0], ((char*)CBFS_SUBHEADER(spd_file)) + spd_index * sizeof(peid->spd_data[0]), sizeof(peid->spd_data[0])); }
void mainboard_romstage_entry(struct romstage_params *rp) { struct cbfs_file *spd_file; void *spd_content; int dual_channel = 0; struct mrc_params mp = { .mainboard = { .dram_type = DRAM_DDR3L, .dram_info_location = DRAM_INFO_SPD_MEM, .weaker_odt_settings = 1, }, }; spd_file = cbfs_get_file(CBFS_DEFAULT_MEDIA, "spd.bin"); if (!spd_file) die("SPD data not found."); spd_content = get_spd_pointer(CBFS_SUBHEADER(spd_file), ntohl(spd_file->len) / SPD_SIZE, &dual_channel); mp.mainboard.dram_data[0] = spd_content; if (dual_channel) mp.mainboard.dram_data[1] = spd_content; rp->mrc_params = ∓ romstage_common(rp); }
int cbfs_export_entry(struct cbfs_image *image, const char *entry_name, const char *filename) { struct cbfs_file *entry = cbfs_get_entry(image, entry_name); struct buffer buffer; if (!entry) { ERROR("File not found: %s\n", entry_name); return -1; } LOG("Found file %.30s at 0x%x, type %.12s, size %d\n", entry_name, cbfs_get_entry_addr(image, entry), get_cbfs_entry_type_name(ntohl(entry->type)), ntohl(entry->len)); if (ntohl(entry->type) != CBFS_COMPONENT_RAW) { WARN("Only 'raw' files are safe to extract.\n"); } buffer.data = CBFS_SUBHEADER(entry); buffer.size = ntohl(entry->len); buffer.name = (char *)"(cbfs_export_entry)"; if (buffer_write_file(&buffer, filename) != 0) { ERROR("Failed to write %s into %s.\n", entry_name, filename); return -1; } INFO("Successfully dumped the file to: %s\n", filename); return 0; }
void *cbfs_load_payload(struct cbfs_media *media, const char *name) { int file_len; void *file_start; struct cbfs_file *file; file_start = vboot_get_payload(&file_len); if (file_start != NULL) return spi_mirror(file_start, file_len); file = cbfs_get_file(media, name); if (file == NULL) return NULL; if (ntohl(file->type) != CBFS_TYPE_PAYLOAD) return NULL; file_len = ntohl(file->len); file_start = CBFS_SUBHEADER(file); return spi_mirror(file_start, file_len); }
static void vga_init(device_t dev) { printk(BIOS_INFO, "Starting Graphics Initialization\n"); struct cbfs_file *file = cbfs_get_file(CBFS_DEFAULT_MEDIA, "mbi.bin"); void *mbi = NULL; unsigned int mbi_len = 0; if (file) { if (ntohl(file->type) != CBFS_TYPE_MBI) { printk(BIOS_INFO, "CBFS: MBI binary is of type %x instead of" "type %x\n", file->type, CBFS_TYPE_MBI); } else { mbi = (void *) CBFS_SUBHEADER(file); mbi_len = ntohl(file->len); } } else { printk(BIOS_INFO, "Could not find MBI.\n"); } if (mbi && mbi_len) { /* The GDT or coreboot table is going to live here. But * a long time after we relocated the GNVS, so this is * not troublesome. */ *(u32 *)0x500 = (u32)mbi; *(u32 *)0x504 = (u32)mbi_len; outb(0xeb, 0xb2); } pci_dev_init(dev); printk(BIOS_INFO, "Graphics Initialization Complete\n"); /* Enable TV-Out */ #if CONFIG_PCI_OPTION_ROM_RUN_YABEL #define PIPE_A_CRT (1 << 0) #define PIPE_A_LFP (1 << 1) #define PIPE_A_TV (1 << 3) #define PIPE_B_CRT (1 << 8) #define PIPE_B_TV (1 << 10) printk(BIOS_DEBUG, "Enabling TV-Out\n"); void runInt10(void); X86_AX = 0x5f64; X86_BX = 0x0001; // Set Display Device, force execution X86_CX = PIPE_A_CRT | PIPE_A_TV; // M.x86.R_CX = PIPE_B_TV; runInt10(); switch (X86_AX) { case 0x005f: printk(BIOS_DEBUG, "... failed.\n"); break; case 0x015f: printk(BIOS_DEBUG, "... ok.\n"); break; default: printk(BIOS_DEBUG, "... not supported.\n"); break; } #endif }
int cbfs_create_empty_entry(struct cbfs_image *image, struct cbfs_file *entry, size_t len, const char *name) { memset(entry, CBFS_CONTENT_DEFAULT_VALUE, sizeof(*entry)); memcpy(entry->magic, CBFS_FILE_MAGIC, sizeof(entry->magic)); entry->type = htonl(CBFS_COMPONENT_NULL); entry->len = htonl(len); entry->checksum = 0; // TODO Build a checksum algorithm. entry->offset = htonl(cbfs_calculate_file_header_size(name)); memset(CBFS_NAME(entry), 0, ntohl(entry->offset) - sizeof(*entry)); strcpy(CBFS_NAME(entry), name); memset(CBFS_SUBHEADER(entry), CBFS_CONTENT_DEFAULT_VALUE, len); return 0; }
void *cbfs_find_file(const char *name, unsigned int type, unsigned int *len) { struct cbfs_file *file = cbfs_find(name); if (file == NULL) { printf("CBFS: Could not find file %s\n", name); return NULL; } if (ntohl(file->type) != type) { printf("CBFS: File %s is of type %x instead of" "type %x\n", name, file->type, type); return NULL; } if (len != NULL) *len = file->len; return (void *) CBFS_SUBHEADER(file); }
int cbfs_remove_entry(struct cbfs_image *image, const char *name) { struct cbfs_file *entry, *next; size_t len; entry = cbfs_get_entry(image, name); if (!entry) { ERROR("CBFS file %s not found.\n", name); return -1; } next = cbfs_find_next_entry(image, entry); assert(next); DEBUG("cbfs_remove_entry: Removed %s @ 0x%x\n", CBFS_NAME(entry), cbfs_get_entry_addr(image, entry)); entry->type = htonl(CBFS_COMPONENT_DELETED); len = (cbfs_get_entry_addr(image, next) - cbfs_get_entry_addr(image, entry)); entry->offset = htonl(cbfs_calculate_file_header_size("")); entry->len = htonl(len - ntohl(entry->offset)); memset(CBFS_NAME(entry), 0, ntohl(entry->offset) - sizeof(*entry)); memset(CBFS_SUBHEADER(entry), CBFS_CONTENT_DEFAULT_VALUE, ntohl(entry->len)); return 0; }
void *cbfs_get_file_content(struct cbfs_media *media, const char *name, int type, size_t *sz) { struct cbfs_file *file = cbfs_get_file(media, name); if (sz) *sz = 0; if (file == NULL) { ERROR("Could not find file '%s'.\n", name); return NULL; } if (ntohl(file->type) != type) { ERROR("File '%s' is of type %x, but we requested %x.\n", name, ntohl(file->type), type); return NULL; } if (sz) *sz = ntohl(file->len); return (void *)CBFS_SUBHEADER(file); }
void *cbfs_get_file_content(struct cbfs_media *media, const char *name, int type, size_t *sz) { struct cbfs_media default_media; if (media == CBFS_DEFAULT_MEDIA) { media = &default_media; if (init_default_cbfs_media(media) != 0) { ERROR("Failed to initialize default media.\n"); return NULL; } } struct cbfs_file *file = cbfs_get_file(media, name); if (sz) *sz = 0; if (file == NULL) { ERROR("Could not find file '%s'.\n", name); return NULL; } if (ntohl(file->type) != type) { ERROR("File '%s' is of type %x, but we requested %x.\n", name, ntohl(file->type), type); return NULL; } void *file_content = (void *)CBFS_SUBHEADER(file); struct cbfs_file_attribute *attr = cbfs_file_find_attr(file, CBFS_FILE_ATTR_TAG_COMPRESSION); size_t final_size = ntohl(file->len); int compression_algo = CBFS_COMPRESS_NONE; if (attr) { struct cbfs_file_attr_compression *comp = (struct cbfs_file_attr_compression *)attr; compression_algo = ntohl(comp->compression); DEBUG("File '%s' is compressed (alg=%d)\n", name, compression_algo); final_size = ntohl(comp->decompressed_size); } void *dst = malloc(final_size); if (dst == NULL) goto err; if (!cbfs_decompress(compression_algo, file_content, dst, final_size)) goto err; if (sz) *sz = final_size; media->unmap(media, file); return dst; err: media->unmap(media, file); free(dst); return NULL; }
int cbfs_add_entry(struct cbfs_image *image, struct buffer *buffer, const char *name, uint32_t type, uint32_t content_offset) { uint32_t entry_type; uint32_t addr, addr_next; struct cbfs_file *entry, *next; uint32_t header_size, need_size, new_size; header_size = cbfs_calculate_file_header_size(name); need_size = header_size + buffer->size; DEBUG("cbfs_add_entry('%s'@0x%x) => need_size = %u+%zu=%u\n", name, content_offset, header_size, buffer->size, need_size); if (IS_TOP_ALIGNED_ADDRESS(content_offset)) { // legacy cbfstool takes top-aligned address. uint32_t theromsize = image->header->romsize; INFO("Converting top-aligned address 0x%x to offset: 0x%x\n", content_offset, content_offset + theromsize); content_offset += theromsize; } // Merge empty entries. DEBUG("(trying to merge empty entries...)\n"); cbfs_walk(image, cbfs_merge_empty_entry, NULL); for (entry = cbfs_find_first_entry(image); entry && cbfs_is_valid_entry(image, entry); entry = cbfs_find_next_entry(image, entry)) { entry_type = ntohl(entry->type); if (entry_type != CBFS_COMPONENT_NULL) continue; addr = cbfs_get_entry_addr(image, entry); next = cbfs_find_next_entry(image, entry); addr_next = cbfs_get_entry_addr(image, next); DEBUG("cbfs_add_entry: space at 0x%x+0x%x(%d) bytes\n", addr, addr_next - addr, addr_next - addr); /* Will the file fit? Don't yet worry if we have space for a new * "empty" entry. We take care of that later. */ if (addr + need_size > addr_next) continue; // Can we simply put object here? if (!content_offset || content_offset == addr + header_size) { DEBUG("Filling new entry data (%zd bytes).\n", buffer->size); cbfs_create_empty_entry(image, entry, buffer->size, name); entry->type = htonl(type); memcpy(CBFS_SUBHEADER(entry), buffer->data, buffer->size); if (verbose) cbfs_print_entry_info(image, entry, stderr); // setup new entry DEBUG("Setting new empty entry.\n"); entry = cbfs_find_next_entry(image, entry); new_size = (cbfs_get_entry_addr(image, next) - cbfs_get_entry_addr(image, entry)); /* Entry was added and no space for new "empty" entry */ if (new_size < cbfs_calculate_file_header_size("")) { DEBUG("No need for new \"empty\" entry\n"); /* No need to increase the size of the just * stored file to extend to next file. Alignment * of next file takes care of this. */ return 0; } new_size -= cbfs_calculate_file_header_size(""); DEBUG("new size: %d\n", new_size); cbfs_create_empty_entry(image, entry, new_size, ""); if (verbose) cbfs_print_entry_info(image, entry, stderr); return 0; } // We need to put content here, and the case is really // complicated... assert(content_offset); if (addr_next < content_offset) { DEBUG("Not for specified offset yet"); continue; } else if (addr > content_offset) { DEBUG("Exceed specified content_offset."); break; } else if (addr + header_size > content_offset) { ERROR("Not enough space for header.\n"); break; } else if (content_offset + buffer->size > addr_next) { ERROR("Not enough space for content.\n"); break; } // TODO there are more few tricky cases that we may // want to fit by altering offset. DEBUG("section 0x%x+0x%x for content_offset 0x%x.\n", addr, addr_next - addr, content_offset); if (cbfs_add_entry_at(image, entry, buffer->size, name, type, buffer->data, content_offset) == 0) { return 0; } break; } ERROR("Could not add [%s, %zd bytes (%zd KB)@0x%x]; too big?\n", buffer->name, buffer->size, buffer->size / 1024, content_offset); return -1; }
/* Tries to add an entry with its data (CBFS_SUBHEADER) at given offset. */ static int cbfs_add_entry_at(struct cbfs_image *image, struct cbfs_file *entry, uint32_t size, const char *name, uint32_t type, const void *data, uint32_t content_offset) { struct cbfs_file *next = cbfs_find_next_entry(image, entry); uint32_t addr = cbfs_get_entry_addr(image, entry), addr_next = cbfs_get_entry_addr(image, next); uint32_t header_size = cbfs_calculate_file_header_size(name), min_entry_size = cbfs_calculate_file_header_size(""); uint32_t len, target; uint32_t align = image->header->align; target = content_offset - header_size; if (target % align) target -= target % align; if (target < addr) { ERROR("No space to hold cbfs_file header."); return -1; } // Process buffer BEFORE content_offset. if (target - addr > min_entry_size) { DEBUG("|min|...|header|content|... <create new entry>\n"); len = target - addr - min_entry_size; cbfs_create_empty_entry(image, entry, len, ""); if (verbose > 1) cbfs_print_entry_info(image, entry, stderr); entry = cbfs_find_next_entry(image, entry); addr = cbfs_get_entry_addr(image, entry); } len = size + (content_offset - addr - header_size); cbfs_create_empty_entry(image, entry, len, name); if (len != size) { DEBUG("|..|header|content|... <use offset to create entry>\n"); DEBUG("before: offset=0x%x, len=0x%x\n", ntohl(entry->offset), ntohl(entry->len)); // TODO reset expanded name buffer to 0xFF. entry->offset = htonl(ntohl(entry->offset) + (len - size)); entry->len = htonl(size); DEBUG("after: offset=0x%x, len=0x%x\n", ntohl(entry->offset), ntohl(entry->len)); } // Ready to fill data into entry. assert(ntohl(entry->len) == size); entry->type = htonl(type); DEBUG("content_offset: 0x%x, entry location: %x\n", content_offset, (int)((char*)CBFS_SUBHEADER(entry) - image->buffer.data)); assert((char*)CBFS_SUBHEADER(entry) - image->buffer.data == content_offset); memcpy(CBFS_SUBHEADER(entry), data, size); if (verbose > 1) cbfs_print_entry_info(image, entry, stderr); // Process buffer AFTER entry. entry = cbfs_find_next_entry(image, entry); addr = cbfs_get_entry_addr(image, entry); assert(addr < addr_next); if (addr_next - addr < min_entry_size) { DEBUG("No space after content to keep CBFS structure.\n"); return -1; } len = addr_next - addr - min_entry_size; cbfs_create_empty_entry(image, entry, len, ""); if (verbose > 1) cbfs_print_entry_info(image, entry, stderr); return 0; }