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; }
int rmodule_stage_load(struct rmod_stage_load *rsl) { struct rmodule rmod_stage; size_t region_size; char *stage_region; int rmodule_offset; int load_offset; struct cbfs_stage stage; void *rmod_loc; struct region_device *fh; if (rsl->prog == NULL || prog_name(rsl->prog) == NULL) return -1; fh = prog_rdev(rsl->prog); if (rdev_readat(fh, &stage, 0, sizeof(stage)) != sizeof(stage)) return -1; rmodule_offset = rmodule_calc_region(DYN_CBMEM_ALIGN_SIZE, stage.memlen, ®ion_size, &load_offset); stage_region = cbmem_add(rsl->cbmem_id, region_size); if (stage_region == NULL) return -1; rmod_loc = &stage_region[rmodule_offset]; printk(BIOS_INFO, "Decompressing stage %s @ 0x%p (%d bytes)\n", prog_name(rsl->prog), rmod_loc, stage.memlen); if (!cbfs_load_and_decompress(fh, sizeof(stage), stage.len, rmod_loc, stage.memlen, stage.compression)) return -1; if (rmodule_parse(rmod_loc, &rmod_stage)) return -1; if (rmodule_load(&stage_region[load_offset], &rmod_stage)) return -1; prog_set_area(rsl->prog, rmod_stage.location, rmodule_memory_size(&rmod_stage)); prog_set_entry(rsl->prog, rmodule_entry(&rmod_stage), NULL); /* Allow caller to pick up parameters, if available. */ rsl->params = rmodule_parameters(&rmod_stage); return 0; }
int prog_locate(struct prog *prog) { struct cbfsf file; cbfs_prepare_program_locate(); if (cbfs_boot_locate(&file, prog_name(prog), NULL)) return -1; cbfs_file_data(prog_rdev(prog), &file); return 0; }
static void vboot_prepare(void) { int run_verification; run_verification = verification_should_run(); if (run_verification) { verstage_main(); car_set_var(vboot_executed, 1); } else if (verstage_should_load()) { struct cbfsf file; struct prog verstage = PROG_INIT(PROG_VERSTAGE, CONFIG_CBFS_PREFIX "/verstage"); printk(BIOS_DEBUG, "VBOOT: Loading verstage.\n"); /* load verstage from RO */ if (cbfs_boot_locate(&file, prog_name(&verstage), NULL)) die("failed to load verstage"); cbfs_file_data(prog_rdev(&verstage), &file); if (cbfs_prog_stage_load(&verstage)) die("failed to load verstage"); /* verify and select a slot */ prog_run(&verstage); /* This is not actually possible to hit this condition at * runtime, but this provides a hint to the compiler for dead * code elimination below. */ if (!IS_ENABLED(CONFIG_RETURN_FROM_VERSTAGE)) return; car_set_var(vboot_executed, 1); } /* * Fill in vboot cbmem objects before moving to ramstage so all * downstream users have access to vboot results. This path only * applies to platforms employing VBOOT_DYNAMIC_WORK_BUFFER because * cbmem comes online prior to vboot verification taking place. For * other platforms the vboot cbmem objects are initialized when * cbmem comes online. */ if (ENV_ROMSTAGE && IS_ENABLED(CONFIG_VBOOT_DYNAMIC_WORK_BUFFER)) { vb2_store_selected_region(); vboot_fill_handoff(); } }
/* Entry point taken when romstage is called after a separate verstage. */ asmlinkage void *romstage_after_verstage(void) { /* Need to locate the current FSP_INFO_HEADER. The cache-as-ram * is still enabled. We can directly access work buffer here. */ FSP_INFO_HEADER *fih; struct prog fsp = PROG_INIT(PROG_REFCODE, "fsp.bin"); console_init(); if (prog_locate(&fsp)) { fih = NULL; printk(BIOS_ERR, "Unable to locate %s\n", prog_name(&fsp)); } else /* This leaks a mapping which this code assumes is benign as * the flash is memory mapped CPU's address space. */ fih = find_fsp((uintptr_t)rdev_mmap_full(prog_rdev(&fsp))); set_fih_car(fih); /* Return new stack value in ram back to assembly stub. */ return cache_as_ram_stage_main(fih); }
/* * Parse the uImage FIT, choose a configuration and extract images. */ void fit_payload(struct prog *payload) { struct device_tree *dt = NULL; struct region kernel = {0}, fdt = {0}, initrd = {0}; void *data; data = rdev_mmap_full(prog_rdev(payload)); if (data == NULL) return; printk(BIOS_INFO, "FIT: Examine payload %s\n", payload->name); struct fit_config_node *config = fit_load(data); if (!config || !config->kernel_node) { printk(BIOS_ERR, "ERROR: Could not load FIT\n"); rdev_munmap(prog_rdev(payload), data); return; } if (config->fdt_node) { dt = fdt_unflatten(config->fdt_node->data); if (!dt) { printk(BIOS_ERR, "ERROR: Failed to unflatten the FDT.\n"); rdev_munmap(prog_rdev(payload), data); return; } dt_apply_fixups(dt); /* Insert coreboot specific information */ add_cb_fdt_data(dt); /* Update device_tree */ #if defined(CONFIG_LINUX_COMMAND_LINE) fit_update_chosen(dt, (char *)CONFIG_LINUX_COMMAND_LINE); #endif fit_update_memory(dt); } /* Collect infos for fit_payload_arch */ kernel.size = config->kernel_node->size; fdt.size = dt ? dt_flat_size(dt) : 0; initrd.size = config->ramdisk_node ? config->ramdisk_node->size : 0; /* Invoke arch specific payload placement and fixups */ if (!fit_payload_arch(payload, config, &kernel, &fdt, &initrd)) { printk(BIOS_ERR, "ERROR: Failed to find free memory region\n"); bootmem_dump_ranges(); rdev_munmap(prog_rdev(payload), data); return; } /* Load the images to given position */ if (config->fdt_node) { /* Update device_tree */ if (config->ramdisk_node) fit_add_ramdisk(dt, (void *)initrd.offset, initrd.size); pack_fdt(&fdt, dt); } if (config->ramdisk_node && extract(&initrd, config->ramdisk_node)) { printk(BIOS_ERR, "ERROR: Failed to extract initrd\n"); prog_set_entry(payload, NULL, NULL); rdev_munmap(prog_rdev(payload), data); return; } timestamp_add_now(TS_KERNEL_DECOMPRESSION); if (extract(&kernel, config->kernel_node)) { printk(BIOS_ERR, "ERROR: Failed to extract kernel\n"); prog_set_entry(payload, NULL, NULL); rdev_munmap(prog_rdev(payload), data); return; } timestamp_add_now(TS_START_KERNEL); rdev_munmap(prog_rdev(payload), data); }
uint32_t vboot_init_crtm(void) { struct prog bootblock = PROG_INIT(PROG_BOOTBLOCK, "bootblock"); struct prog verstage = PROG_INIT(PROG_VERSTAGE, CONFIG_CBFS_PREFIX "/verstage"); struct prog romstage = PROG_INIT(PROG_ROMSTAGE, CONFIG_CBFS_PREFIX "/romstage"); char tcpa_metadata[TCPA_PCR_HASH_NAME]; /* Initialize TCPE PRERAM log. */ tcpa_preram_log_clear(); /* measure bootblock from RO */ struct cbfsf bootblock_data; struct region_device bootblock_fmap; if (fmap_locate_area_as_rdev("BOOTBLOCK", &bootblock_fmap) == 0) { if (tpm_measure_region(&bootblock_fmap, TPM_CRTM_PCR, "FMAP: BOOTBLOCK")) return VB2_ERROR_UNKNOWN; } else { if (cbfs_boot_locate(&bootblock_data, prog_name(&bootblock), NULL) == 0) { cbfs_file_data(prog_rdev(&bootblock), &bootblock_data); if (create_tcpa_metadata(prog_rdev(&bootblock), prog_name(&bootblock), tcpa_metadata) < 0) return VB2_ERROR_UNKNOWN; if (tpm_measure_region(prog_rdev(&bootblock), TPM_CRTM_PCR, tcpa_metadata)) return VB2_ERROR_UNKNOWN; } else { printk(BIOS_INFO, "VBOOT: Couldn't measure bootblock into CRTM!\n"); return VB2_ERROR_UNKNOWN; } } if (CONFIG(VBOOT_STARTS_IN_ROMSTAGE)) { struct cbfsf romstage_data; /* measure romstage from RO */ if (cbfs_boot_locate(&romstage_data, prog_name(&romstage), NULL) == 0) { cbfs_file_data(prog_rdev(&romstage), &romstage_data); if (create_tcpa_metadata(prog_rdev(&romstage), prog_name(&romstage), tcpa_metadata) < 0) return VB2_ERROR_UNKNOWN; if (tpm_measure_region(prog_rdev(&romstage), TPM_CRTM_PCR, tcpa_metadata)) return VB2_ERROR_UNKNOWN; } else { printk(BIOS_INFO, "VBOOT: Couldn't measure %s into CRTM!\n", CONFIG_CBFS_PREFIX "/romstage"); return VB2_ERROR_UNKNOWN; } } if (CONFIG(VBOOT_SEPARATE_VERSTAGE)) { struct cbfsf verstage_data; /* measure verstage from RO */ if (cbfs_boot_locate(&verstage_data, prog_name(&verstage), NULL) == 0) { cbfs_file_data(prog_rdev(&verstage), &verstage_data); if (create_tcpa_metadata(prog_rdev(&verstage), prog_name(&verstage), tcpa_metadata) < 0) return VB2_ERROR_UNKNOWN; if (tpm_measure_region(prog_rdev(&verstage), TPM_CRTM_PCR, tcpa_metadata)) return VB2_ERROR_UNKNOWN; } else { printk(BIOS_INFO, "VBOOT: Couldn't measure %s into CRTM!\n", CONFIG_CBFS_PREFIX "/verstage"); return VB2_ERROR_UNKNOWN; } } return VB2_SUCCESS; }
static void vboot_prepare(void) { if (verification_should_run()) { /* Note: this path is not used for VBOOT_RETURN_FROM_VERSTAGE */ verstage_main(); car_set_var(vboot_executed, 1); vb2_save_recovery_reason_vbnv(); /* * Avoid double memory retrain when the EC is running RW code * and a recovery request came in through an EC host event. The * double retrain happens because the EC won't be rebooted * until kernel verification notices the EC isn't running RO * code which is after memory training. Therefore, reboot the * EC after we've saved the potential recovery request so it's * not lost. Lastly, only perform this sequence on x86 * platforms since those are the ones that currently do a * costly memory training in recovery mode. */ if (IS_ENABLED(CONFIG_EC_GOOGLE_CHROMEEC) && IS_ENABLED(CONFIG_ARCH_X86)) google_chromeec_early_init(); } else if (verstage_should_load()) { struct cbfsf file; struct prog verstage = PROG_INIT(PROG_VERSTAGE, CONFIG_CBFS_PREFIX "/verstage"); printk(BIOS_DEBUG, "VBOOT: Loading verstage.\n"); /* load verstage from RO */ if (cbfs_boot_locate(&file, prog_name(&verstage), NULL)) die("failed to load verstage"); cbfs_file_data(prog_rdev(&verstage), &file); if (cbfs_prog_stage_load(&verstage)) die("failed to load verstage"); /* verify and select a slot */ prog_run(&verstage); /* This is not actually possible to hit this condition at * runtime, but this provides a hint to the compiler for dead * code elimination below. */ if (!IS_ENABLED(CONFIG_VBOOT_RETURN_FROM_VERSTAGE)) return; car_set_var(vboot_executed, 1); } /* * Fill in vboot cbmem objects before moving to ramstage so all * downstream users have access to vboot results. This path only * applies to platforms employing VBOOT_STARTS_IN_ROMSTAGE because * cbmem comes online prior to vboot verification taking place. For * other platforms the vboot cbmem objects are initialized when * cbmem comes online. */ if (ENV_ROMSTAGE && IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE)) { vb2_store_selected_region(); vboot_fill_handoff(); } }