/* returns the size of data in a VPD 2.0 formatted fmap region, or 0 */ static int32_t get_vpd_size(const char *fmap_name, int32_t *base) { struct google_vpd_info info; struct region_device vpd; int32_t size; if (fmap_locate_area_as_rdev(fmap_name, &vpd)) { printk(BIOS_ERR, "%s: No %s FMAP section.\n", __func__, fmap_name); return 0; } size = region_device_sz(&vpd); if ((size < GOOGLE_VPD_2_0_OFFSET + sizeof(info)) || rdev_chain(&vpd, &vpd, GOOGLE_VPD_2_0_OFFSET, size - GOOGLE_VPD_2_0_OFFSET)) { printk(BIOS_ERR, "%s: Too small (%d) for Google VPD 2.0.\n", __func__, size); return 0; } /* Try if we can find a google_vpd_info, otherwise read whole VPD. */ if (rdev_readat(&vpd, &info, *base, sizeof(info)) == sizeof(info) && memcmp(info.header.magic, VPD_INFO_MAGIC, sizeof(info.header.magic)) == 0 && size >= info.size + sizeof(info)) { *base += sizeof(info); size = info.size; } else { size -= GOOGLE_VPD_2_0_OFFSET; } return size; }
void fsps_load(bool s3wake) { struct fsp_header *hdr = &fsps_hdr; struct cbfsf file_desc; struct region_device rdev; const char *name = CONFIG_FSP_S_CBFS; void *dest; size_t size; struct prog fsps = PROG_INIT(PROG_REFCODE, name); static int load_done; if (load_done) return; if (s3wake && !IS_ENABLED(CONFIG_NO_STAGE_CACHE)) { printk(BIOS_DEBUG, "Loading FSPS from stage_cache\n"); stage_cache_load_stage(STAGE_REFCODE, &fsps); if (fsp_validate_component(hdr, prog_rdev(&fsps)) != CB_SUCCESS) die("On resume fsps header is invalid\n"); load_done = 1; return; } if (cbfs_boot_locate(&file_desc, name, NULL)) { printk(BIOS_ERR, "Could not locate %s in CBFS\n", name); die("FSPS not available!\n"); } cbfs_file_data(&rdev, &file_desc); /* Load and relocate into CBMEM. */ size = region_device_sz(&rdev); dest = cbmem_add(CBMEM_ID_REFCODE, size); if (dest == NULL) die("Could not add FSPS to CBMEM!\n"); if (rdev_readat(&rdev, dest, 0, size) < 0) die("Failed to read FSPS!\n"); if (fsp_component_relocate((uintptr_t)dest, dest, size) < 0) die("Unable to relocate FSPS!\n"); /* Create new region device in memory after relocation. */ rdev_chain(&rdev, &addrspace_32bit.rdev, (uintptr_t)dest, size); if (fsp_validate_component(hdr, &rdev) != CB_SUCCESS) die("Invalid FSPS header!\n"); prog_set_area(&fsps, dest, size); stage_cache_add(STAGE_REFCODE, &fsps); /* Signal that FSP component has been loaded. */ prog_segment_loaded(hdr->image_base, hdr->image_size, SEG_FINAL); load_done = 1; }
/* returns the size of data in a VPD 2.0 formatted fmap region, or 0 */ static int32_t get_vpd_size(const char *fmap_name, int32_t *base) { struct google_vpd_info info; struct region_device vpd; int32_t size; if (fmap_locate_area_as_rdev(fmap_name, &vpd)) { printk(BIOS_ERR, "%s: No %s FMAP section.\n", __func__, fmap_name); return 0; } size = region_device_sz(&vpd); if ((size < GOOGLE_VPD_2_0_OFFSET + sizeof(info)) || rdev_chain(&vpd, &vpd, GOOGLE_VPD_2_0_OFFSET, size - GOOGLE_VPD_2_0_OFFSET)) { printk(BIOS_ERR, "%s: Too small (%d) for Google VPD 2.0.\n", __func__, size); return 0; } /* Try if we can find a google_vpd_info, otherwise read whole VPD. */ if (rdev_readat(&vpd, &info, *base, sizeof(info)) != sizeof(info)) { printk(BIOS_ERR, "ERROR: Failed to read %s header.\n", fmap_name); return 0; } if (memcmp(info.header.magic, VPD_INFO_MAGIC, sizeof(info.header.magic)) == 0 && size >= info.size + sizeof(info)) { *base += sizeof(info); size = info.size; } else if (info.header.tlv.type == VPD_TYPE_TERMINATOR || info.header.tlv.type == VPD_TYPE_IMPLICIT_TERMINATOR) { printk(BIOS_WARNING, "WARNING: %s is uninitialized or empty.\n", fmap_name); size = 0; } else { size -= GOOGLE_VPD_2_0_OFFSET; } return size; }
enum fsp_status fsp_silicon_init(void) { struct fsp_header *hdr = &fsps_hdr; struct cbfsf file_desc; struct region_device rdev; const char *name = CONFIG_FSP_S_CBFS; void *dest; size_t size; if (cbfs_boot_locate(&file_desc, name, NULL)) { printk(BIOS_ERR, "Could not locate %s in CBFS\n", name); return FSP_NOT_FOUND; } cbfs_file_data(&rdev, &file_desc); /* Load and relocate into CBMEM. */ size = region_device_sz(&rdev); dest = cbmem_add(CBMEM_ID_REFCODE, size); if (dest == NULL) { printk(BIOS_ERR, "Could not add FSPS to CBMEM.\n"); return FSP_NOT_FOUND; } if (rdev_readat(&rdev, dest, 0, size) < 0) return FSP_NOT_FOUND; if (fsp_component_relocate((uintptr_t)dest, dest, size) < 0) { printk(BIOS_ERR, "Unable to relocate FSPS.\n"); return FSP_NOT_FOUND; } /* Create new region device in memory after relocation. */ rdev_chain(&rdev, &addrspace_32bit.rdev, (uintptr_t)dest, size); if (fsp_validate_component(hdr, &rdev) != CB_SUCCESS) return FSP_NOT_FOUND; /* Signal that FSP component has been loaded. */ prog_segment_loaded(hdr->image_base, hdr->image_size, SEG_FINAL); return do_silicon_init(hdr); }
int cbfs_boot_locate(struct cbfsf *fh, const char *name, uint32_t *type) { struct region_device rdev; const struct region_device *boot_dev; struct cbfs_props props; if (cbfs_boot_region_properties(&props)) return -1; /* All boot CBFS operations are performed using the RO devie. */ boot_dev = boot_device_ro(); if (boot_dev == NULL) return -1; if (rdev_chain(&rdev, boot_dev, props.offset, props.size)) return -1; return cbfs_locate(fh, &rdev, name, type); }
static void cbmem_add_cros_vpd(int is_recovery) { struct region_device vpd; struct vpd_cbmem *cbmem; int32_t ro_vpd_base = 0, rw_vpd_base = 0; int32_t ro_vpd_size, rw_vpd_size; timestamp_add_now(TS_START_COPYVPD); ro_vpd_size = get_vpd_size("RO_VPD", &ro_vpd_base); rw_vpd_size = get_vpd_size("RW_VPD", &rw_vpd_base); /* no VPD at all? nothing to do then */ if ((ro_vpd_size == 0) && (rw_vpd_size == 0)) return; cbmem = cbmem_add(CBMEM_ID_VPD, sizeof(*cbmem) + ro_vpd_size + rw_vpd_size); if (!cbmem) { printk(BIOS_ERR, "%s: Failed to allocate CBMEM (%u+%u).\n", __func__, ro_vpd_size, rw_vpd_size); return; } cbmem->magic = CROSVPD_CBMEM_MAGIC; cbmem->version = CROSVPD_CBMEM_VERSION; cbmem->ro_size = 0; cbmem->rw_size = 0; if (ro_vpd_size) { if (fmap_locate_area_as_rdev("RO_VPD", &vpd)) { /* shouldn't happen, but let's be extra defensive */ printk(BIOS_ERR, "%s: No RO_VPD FMAP section.\n", __func__); return; } rdev_chain(&vpd, &vpd, GOOGLE_VPD_2_0_OFFSET, region_device_sz(&vpd) - GOOGLE_VPD_2_0_OFFSET); if (rdev_readat(&vpd, cbmem->blob, ro_vpd_base, ro_vpd_size) == ro_vpd_size) { cbmem->ro_size = ro_vpd_size; } else { printk(BIOS_ERR, "%s: Reading RO_VPD FMAP section failed.\n", __func__); ro_vpd_size = 0; } timestamp_add_now(TS_END_COPYVPD_RO); } if (rw_vpd_size) { if (fmap_locate_area_as_rdev("RW_VPD", &vpd)) { /* shouldn't happen, but let's be extra defensive */ printk(BIOS_ERR, "%s: No RW_VPD FMAP section.\n", __func__); return; } rdev_chain(&vpd, &vpd, GOOGLE_VPD_2_0_OFFSET, region_device_sz(&vpd) - GOOGLE_VPD_2_0_OFFSET); if (rdev_readat(&vpd, cbmem->blob + ro_vpd_size, rw_vpd_base, rw_vpd_size) == rw_vpd_size) { cbmem->rw_size = rw_vpd_size; } else { printk(BIOS_ERR, "%s: Reading RW_VPD FMAP section failed.\n", __func__); } timestamp_add_now(TS_END_COPYVPD_RW); } }
static int hash_body(struct vb2_context *ctx, struct region_device *fw_main) { uint64_t load_ts; uint32_t expected_size; uint8_t block[TODO_BLOCK_SIZE]; uint8_t hash_digest[VBOOT_MAX_HASH_SIZE]; const size_t hash_digest_sz = sizeof(hash_digest); size_t block_size = sizeof(block); size_t offset; int rv; /* Clear the full digest so that any hash digests less than the * max have trailing zeros. */ memset(hash_digest, 0, hash_digest_sz); /* * Since loading the firmware and calculating its hash is intertwined, * we use this little trick to measure them separately and pretend it * was first loaded and then hashed in one piece with the timestamps. * (This split won't make sense with memory-mapped media like on x86.) */ load_ts = timestamp_get(); timestamp_add(TS_START_HASH_BODY, load_ts); expected_size = region_device_sz(fw_main); offset = 0; /* Start the body hash */ rv = vb2api_init_hash(ctx, VB2_HASH_TAG_FW_BODY, &expected_size); if (rv) return rv; /* * Honor vboot's RW slot size. The expected size is pulled out of * the preamble and obtained through vb2api_init_hash() above. By * creating sub region the RW slot portion of the boot media is * limited. */ if (rdev_chain(fw_main, fw_main, 0, expected_size)) { printk(BIOS_ERR, "Unable to restrict CBFS size.\n"); return VB2_ERROR_UNKNOWN; } /* Extend over the body */ while (expected_size) { uint64_t temp_ts; if (block_size > expected_size) block_size = expected_size; temp_ts = timestamp_get(); if (rdev_readat(fw_main, block, offset, block_size) < 0) return VB2_ERROR_UNKNOWN; load_ts += timestamp_get() - temp_ts; rv = vb2api_extend_hash(ctx, block, block_size); if (rv) return rv; expected_size -= block_size; offset += block_size; } timestamp_add(TS_DONE_LOADING, load_ts); timestamp_add_now(TS_DONE_HASHING); /* Check the result (with RSA signature verification) */ rv = vb2api_check_hash_get_digest(ctx, hash_digest, hash_digest_sz); if (rv) return rv; timestamp_add_now(TS_END_HASH_BODY); if (handle_digest_result(hash_digest, hash_digest_sz)) return VB2_ERROR_UNKNOWN; return VB2_SUCCESS; }