int find_fmap_entry(const char name[], void **pointer) { MAYBE_STATIC const struct fmap *fmap = NULL; const struct fmap_area *area; void *base = NULL; if (!fmap) fmap = fmap_find(); area = find_fmap_area(fmap, name); if (!area) return -1; /* Right now cros_bundle_firmware does not write a valid * base address into the FMAP. Hence, if base is 0, assume * 4GB-8MB as base address. */ if (fmap->base) { base = (void *)(unsigned long)fmap->base; printk(BIOS_DEBUG, "FMAP: %s base at %p\n", name, base); } else { #if CONFIG_ARCH_X86 base = (void *)(0 - CONFIG_ROM_SIZE); printk(BIOS_WARNING, "FMAP: No valid base address, using" " 0x%p\n", base); #endif } *pointer = (void*) ((uintptr_t)base + area->offset); printk(BIOS_DEBUG, "FMAP: %s at %p (offset %x)\n", name, *pointer, area->offset); return area->size; }
partitioned_file_t *partitioned_file_create(const char *filename, struct buffer *flashmap) { assert(filename); assert(flashmap); assert(flashmap->data); if (fmap_find((const uint8_t *)flashmap->data, flashmap->size) != 0) { ERROR("Attempted to create a partitioned image out of something that isn't an FMAP\n"); return NULL; } struct fmap *bootstrap_fmap = (struct fmap *)flashmap->data; const struct fmap_area *fmap_area = fmap_find_area(bootstrap_fmap, SECTION_NAME_FMAP); if (!fmap_area) { ERROR("Provided FMAP missing '%s' region\n", SECTION_NAME_FMAP); return NULL; } if (count_selected_fmap_entries(bootstrap_fmap, partitioned_file_fmap_select_children_of, fmap_area)) { ERROR("Provided FMAP's '%s' region contains other regions\n", SECTION_NAME_FMAP); return NULL; } int fmap_len = fmap_size(bootstrap_fmap); if (fmap_len < 0) { ERROR("Unable to determine size of provided FMAP\n"); return NULL; } assert((size_t)fmap_len <= flashmap->size); if ((uint32_t)fmap_len > fmap_area->size) { ERROR("Provided FMAP's '%s' region needs to be at least %d bytes\n", SECTION_NAME_FMAP, fmap_len); return NULL; } partitioned_file_t *file = partitioned_file_create_flat(filename, bootstrap_fmap->size); if (!file) return NULL; struct buffer fmap_region; buffer_splice(&fmap_region, &file->buffer, fmap_area->offset, fmap_area->size); memcpy(fmap_region.data, bootstrap_fmap, fmap_len); if (!partitioned_file_write_region(file, &fmap_region)) { partitioned_file_close(file); return NULL; } file->fmap = (struct fmap *)(file->buffer.data + fmap_area->offset); return file; }
int ft_show_bios(const char *name, uint8_t *buf, uint32_t len, void *data) { FmapHeader *fmap; FmapAreaHeader *ah = 0; char ah_name[FMAP_NAMELEN + 1]; enum bios_component c; int retval = 0; struct bios_state_s state; memset(&state, 0, sizeof(state)); printf("BIOS: %s\n", name); /* We've already checked, so we know this will work. */ fmap = fmap_find(buf, len); for (c = 0; c < NUM_BIOS_COMPONENTS; c++) { /* We know one of these will work, too */ if (fmap_find_by_name(buf, len, fmap, fmap_name[c], &ah) || fmap_find_by_name(buf, len, fmap, fmap_oldname[c], &ah)) { /* But the file might be truncated */ fmap_limit_area(ah, len); /* The name is not necessarily null-terminated */ snprintf(ah_name, sizeof(ah_name), "%s", ah->area_name); /* Update the state we're passing around */ state.c = c; state.area[c].offset = ah->area_offset; state.area[c].buf = buf + ah->area_offset; state.area[c].len = ah->area_size; Debug("%s() showing FMAP area %d (%s)," " offset=0x%08x len=0x%08x\n", __func__, c, ah_name, ah->area_offset, ah->area_size); /* Go look at it. */ if (fmap_show_fn[c]) retval += fmap_show_fn[c](ah_name, state.area[c].buf, state.area[c].len, &state); } } return retval; }
partitioned_file_t *partitioned_file_reopen(const char *filename, partitioned_file_flat_decider_t flat_override) { assert(filename); partitioned_file_t *file = reopen_flat_file(filename); if (!file) return NULL; if (flat_override && flat_override(&file->buffer)) { INFO("Opening image as a flat file in response to explicit request\n"); return file; } long fmap_region_offset = fmap_find((const uint8_t *)file->buffer.data, file->buffer.size); if (fmap_region_offset < 0) { INFO("Opening image as a flat file because it doesn't contain any FMAP\n"); return file; } file->fmap = (struct fmap *)(file->buffer.data + fmap_region_offset); if (file->fmap->size > file->buffer.size) { int fmap_region_size = fmap_size(file->fmap); ERROR("FMAP records image size as %u, but file is only %zu bytes%s\n", file->fmap->size, file->buffer.size, fmap_region_offset == 0 && (signed)file->buffer.size == fmap_region_size ? " (is it really an image, or *just* an FMAP?)" : " (did something truncate this file?)"); partitioned_file_close(file); return NULL; } const struct fmap_area *fmap_fmap_entry = fmap_find_area(file->fmap, SECTION_NAME_FMAP); if ((long)fmap_fmap_entry->offset != fmap_region_offset) { ERROR("FMAP's '%s' section doesn't point back to FMAP start (did something corrupt this file?)\n", SECTION_NAME_FMAP); partitioned_file_close(file); return NULL; } return file; }
/* get SHA1 sum of all static regions described by the flashmap and copy into *digest (which will be allocated and must be freed by the caller), */ int fmap_get_csum(const uint8_t *image, unsigned int image_len, uint8_t **digest) { int i; struct fmap *fmap; int fmap_offset; SHA_CTX ctx; if ((image == NULL)) return -1; if ((fmap_offset = fmap_find(image, image_len)) < 0) return -1; fmap = (struct fmap *)(image + fmap_offset); SHA_init(&ctx); /* Iterate through flash map and calculate the checksum piece-wise. */ for (i = 0; i < fmap->nareas; i++) { /* skip non-static areas */ if (!(fmap->areas[i].flags & FMAP_AREA_STATIC)) continue; /* sanity check the offset */ if (fmap->areas[i].size + fmap->areas[i].offset > image_len) { fprintf(stderr, "(%s) invalid parameter detected in area %d\n", __func__, i); return -1; } SHA_update(&ctx, image + fmap->areas[i].offset, fmap->areas[i].size); } SHA_final(&ctx); *digest = malloc(SHA_DIGEST_SIZE); memcpy(*digest, ctx.buf, SHA_DIGEST_SIZE); return SHA_DIGEST_SIZE; }
enum futil_file_type ft_recognize_bios_image(uint8_t *buf, uint32_t len) { FmapHeader *fmap; enum bios_component c; fmap = fmap_find(buf, len); if (!fmap) return FILE_TYPE_UNKNOWN; for (c = 0; c < NUM_BIOS_COMPONENTS; c++) if (!fmap_find_by_name(buf, len, fmap, fmap_name[c], 0)) break; if (c == NUM_BIOS_COMPONENTS) return FILE_TYPE_BIOS_IMAGE; for (c = 0; c < NUM_BIOS_COMPONENTS; c++) if (!fmap_find_by_name(buf, len, fmap, fmap_oldname[c], 0)) break; if (c == NUM_BIOS_COMPONENTS) return FILE_TYPE_OLD_BIOS_IMAGE; return FILE_TYPE_UNKNOWN; }
static int fmap_find_test(struct fmap *fmap) { uint8_t *buf; size_t total_size, offset; status = fail; /* * Note: In these tests, we'll use fmap_find() and control usage of * lsearch and bsearch by using a power-of-2 total_size. For lsearch, * use total_size - 1. For bsearch, use total_size. */ total_size = 0x100000; buf = calloc(total_size, 1); /* test if image length is zero */ if (fmap_find(buf, 0) >= 0) { printf("FAILURE: failed to abort on zero-length image\n"); goto fmap_find_test_exit; } /* test if no fmap exists */ if (fmap_find(buf, total_size - 1) >= 0) { printf("FAILURE: lsearch returned false positive\n"); goto fmap_find_test_exit; } if (fmap_find(buf, total_size) >= 0) { printf("FAILURE: bsearch returned false positive\n"); goto fmap_find_test_exit; } /* simple test case: fmap at (total_size / 2) + 1 */ offset = (total_size / 2) + 1; memcpy(&buf[offset], fmap, fmap_size(fmap)); if ((unsigned)fmap_find(buf, total_size - 1) != offset) { printf("FAILURE: lsearch failed to find fmap\n"); goto fmap_find_test_exit; } if ((unsigned)fmap_find(buf, total_size) != offset) { printf("FAILURE: bsearch failed to find fmap\n"); goto fmap_find_test_exit; } /* test bsearch if offset is at 0 */ offset = 0; memset(buf, 0, total_size); memcpy(buf, fmap, fmap_size(fmap)); if ((unsigned)fmap_find(buf, total_size) != offset) { printf("FAILURE: bsearch failed to find fmap at offset 0\n"); goto fmap_find_test_exit; } /* test overrun detection */ memset(buf, 0, total_size); memcpy(&buf[total_size - fmap_size(fmap) + 1], fmap, fmap_size(fmap) + 1); if (fmap_find(buf, total_size - 1) >= 0) { printf("FAILURE: lsearch failed to catch overrun\n"); goto fmap_find_test_exit; } if (fmap_find(buf, total_size) >= 0) { printf("FAILURE: bsearch failed to catch overrun\n"); goto fmap_find_test_exit; } status = pass; fmap_find_test_exit: free(buf); return status; }