2020-03-04 15:10:45 +01:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
2016-03-18 18:21:23 +01:00
|
|
|
|
2019-08-16 19:34:25 +02:00
|
|
|
#include <arch/romstage.h>
|
2016-03-18 18:21:23 +01:00
|
|
|
#include <cbmem.h>
|
|
|
|
#include <console/console.h>
|
2016-12-06 13:00:05 +01:00
|
|
|
#include <cpu/cpu.h>
|
2016-03-18 18:21:23 +01:00
|
|
|
#include <cpu/x86/msr.h>
|
|
|
|
#include <cpu/x86/mtrr.h>
|
2019-08-22 08:00:52 +02:00
|
|
|
#include <cpu/x86/smm.h>
|
2016-03-18 18:21:23 +01:00
|
|
|
#include <program_loading.h>
|
2019-12-18 18:40:48 +01:00
|
|
|
#include <reset.h>
|
2016-03-18 18:21:23 +01:00
|
|
|
#include <rmodule.h>
|
2016-11-29 22:52:08 +01:00
|
|
|
#include <romstage_handoff.h>
|
|
|
|
#include <stage_cache.h>
|
2019-02-25 16:01:22 +01:00
|
|
|
#include <timestamp.h>
|
2019-11-01 10:22:22 +01:00
|
|
|
#include <security/vboot/vboot_common.h>
|
2016-03-18 18:21:23 +01:00
|
|
|
|
|
|
|
static inline void stack_push(struct postcar_frame *pcf, uint32_t val)
|
|
|
|
{
|
|
|
|
uint32_t *ptr;
|
|
|
|
|
|
|
|
pcf->stack -= sizeof(val);
|
|
|
|
ptr = (void *)pcf->stack;
|
|
|
|
*ptr = val;
|
|
|
|
}
|
|
|
|
|
2016-12-02 18:47:07 +01:00
|
|
|
static void postcar_frame_prepare(struct postcar_frame *pcf)
|
2016-03-18 18:21:23 +01:00
|
|
|
{
|
|
|
|
msr_t msr;
|
|
|
|
msr = rdmsr(MTRR_CAP_MSR);
|
|
|
|
|
2016-12-02 18:47:07 +01:00
|
|
|
pcf->upper_mask = (1 << (cpu_phys_address_size() - 32)) - 1;
|
2017-09-12 09:36:49 +02:00
|
|
|
pcf->max_var_mtrrs = msr.lo & MTRR_CAP_VCNT;
|
|
|
|
pcf->num_var_mtrrs = 0;
|
2016-12-02 18:47:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int postcar_frame_init(struct postcar_frame *pcf, size_t stack_size)
|
|
|
|
{
|
|
|
|
void *stack;
|
|
|
|
|
2019-06-28 09:08:51 +02:00
|
|
|
/*
|
|
|
|
* Use default postcar stack size of 4 KiB. This value should
|
|
|
|
* not be decreased, because if mainboards use vboot, 1 KiB will
|
|
|
|
* not be enough anymore.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (stack_size == 0)
|
|
|
|
stack_size = 4 * KiB;
|
|
|
|
|
2016-03-18 18:21:23 +01:00
|
|
|
stack = cbmem_add(CBMEM_ID_ROMSTAGE_RAM_STACK, stack_size);
|
|
|
|
if (stack == NULL) {
|
|
|
|
printk(BIOS_ERR, "Couldn't add %zd byte stack in cbmem.\n",
|
|
|
|
stack_size);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-12-02 18:47:07 +01:00
|
|
|
postcar_frame_prepare(pcf);
|
2016-03-18 18:21:23 +01:00
|
|
|
pcf->stack = (uintptr_t)stack;
|
|
|
|
pcf->stack += stack_size;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void postcar_frame_add_mtrr(struct postcar_frame *pcf,
|
|
|
|
uintptr_t addr, size_t size, int type)
|
|
|
|
{
|
2016-09-07 16:48:17 +02:00
|
|
|
/*
|
|
|
|
* Utilize additional MTRRs if the specified size is greater than the
|
|
|
|
* base address alignment.
|
|
|
|
*/
|
|
|
|
while (size != 0) {
|
|
|
|
uint32_t addr_lsb;
|
|
|
|
uint32_t size_msb;
|
|
|
|
uint32_t mtrr_size;
|
|
|
|
|
2017-09-12 09:36:49 +02:00
|
|
|
if (pcf->num_var_mtrrs >= pcf->max_var_mtrrs) {
|
2016-09-07 16:48:17 +02:00
|
|
|
printk(BIOS_ERR, "No more variable MTRRs: %d\n",
|
2017-09-12 09:36:49 +02:00
|
|
|
pcf->max_var_mtrrs);
|
2016-09-07 16:48:17 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr_lsb = fls(addr);
|
|
|
|
size_msb = fms(size);
|
|
|
|
|
|
|
|
/* All MTRR entries need to have their base aligned to the mask
|
|
|
|
* size. The maximum size is calculated by a function of the
|
|
|
|
* min base bit set and maximum size bit set. */
|
|
|
|
if (addr_lsb > size_msb)
|
|
|
|
mtrr_size = 1 << size_msb;
|
|
|
|
else
|
|
|
|
mtrr_size = 1 << addr_lsb;
|
|
|
|
|
|
|
|
printk(BIOS_DEBUG, "MTRR Range: Start=%lx End=%lx (Size %x)\n",
|
|
|
|
addr, addr + mtrr_size, mtrr_size);
|
|
|
|
|
|
|
|
stack_push(pcf, pcf->upper_mask);
|
|
|
|
stack_push(pcf, ~(mtrr_size - 1) | MTRR_PHYS_MASK_VALID);
|
|
|
|
stack_push(pcf, 0);
|
|
|
|
stack_push(pcf, addr | type);
|
2017-09-12 09:36:49 +02:00
|
|
|
pcf->num_var_mtrrs++;
|
2016-09-07 16:48:17 +02:00
|
|
|
|
|
|
|
size -= mtrr_size;
|
|
|
|
addr += mtrr_size;
|
2016-03-18 18:21:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-27 14:32:27 +02:00
|
|
|
void postcar_frame_add_romcache(struct postcar_frame *pcf, int type)
|
|
|
|
{
|
2019-03-06 01:53:33 +01:00
|
|
|
if (!CONFIG(BOOT_DEVICE_MEMORY_MAPPED))
|
2018-05-27 14:32:27 +02:00
|
|
|
return;
|
|
|
|
postcar_frame_add_mtrr(pcf, CACHE_ROM_BASE, CACHE_ROM_SIZE, type);
|
|
|
|
}
|
|
|
|
|
2020-04-29 22:20:05 +02:00
|
|
|
static void postcar_frame_common_mtrrs(struct postcar_frame *pcf)
|
2019-08-09 10:41:15 +02:00
|
|
|
{
|
|
|
|
if (pcf->skip_common_mtrr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Cache the ROM as WP just below 4GiB. */
|
|
|
|
postcar_frame_add_romcache(pcf, MTRR_TYPE_WRPROT);
|
|
|
|
}
|
|
|
|
|
2019-08-17 19:51:08 +02:00
|
|
|
/* prepare_and_run_postcar() determines the stack to use after
|
|
|
|
* cache-as-ram is torn down as well as the MTRR settings to use. */
|
|
|
|
void prepare_and_run_postcar(struct postcar_frame *pcf)
|
|
|
|
{
|
|
|
|
if (postcar_frame_init(pcf, 0))
|
|
|
|
die("Unable to initialize postcar frame.\n");
|
|
|
|
|
|
|
|
fill_postcar_frame(pcf);
|
|
|
|
|
|
|
|
postcar_frame_common_mtrrs(pcf);
|
|
|
|
|
|
|
|
run_postcar_phase(pcf);
|
|
|
|
/* We do not return here. */
|
|
|
|
}
|
|
|
|
|
2019-08-28 04:22:40 +02:00
|
|
|
static void postcar_commit_mtrrs(struct postcar_frame *pcf)
|
2016-08-26 17:38:50 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Place the number of used variable MTRRs on stack then max number
|
|
|
|
* of variable MTRRs supported in the system.
|
|
|
|
*/
|
2017-09-12 09:36:49 +02:00
|
|
|
stack_push(pcf, pcf->num_var_mtrrs);
|
|
|
|
stack_push(pcf, pcf->max_var_mtrrs);
|
2016-08-26 17:38:50 +02:00
|
|
|
}
|
|
|
|
|
2017-09-05 21:43:05 +02:00
|
|
|
static void finalize_load(uintptr_t *stack_top_ptr, uintptr_t stack_top)
|
|
|
|
{
|
|
|
|
*stack_top_ptr = stack_top;
|
|
|
|
/*
|
|
|
|
* Signal to rest of system that another update was made to the
|
|
|
|
* postcar program prior to running it.
|
|
|
|
*/
|
|
|
|
prog_segment_loaded((uintptr_t)stack_top_ptr, sizeof(uintptr_t),
|
|
|
|
SEG_FINAL);
|
|
|
|
}
|
|
|
|
|
2016-11-29 22:52:08 +01:00
|
|
|
static void load_postcar_cbfs(struct prog *prog, struct postcar_frame *pcf)
|
2016-03-18 18:21:23 +01:00
|
|
|
{
|
|
|
|
struct rmod_stage_load rsl = {
|
|
|
|
.cbmem_id = CBMEM_ID_AFTER_CAR,
|
2016-11-29 22:52:08 +01:00
|
|
|
.prog = prog,
|
2016-03-18 18:21:23 +01:00
|
|
|
};
|
|
|
|
|
2019-11-01 10:22:22 +01:00
|
|
|
vboot_run_logic();
|
|
|
|
|
2016-11-29 22:52:08 +01:00
|
|
|
if (prog_locate(prog))
|
2019-05-07 00:12:57 +02:00
|
|
|
die_with_post_code(POST_INVALID_ROM,
|
|
|
|
"Failed to locate after CAR program.\n");
|
2016-03-18 18:21:23 +01:00
|
|
|
if (rmodule_stage_load(&rsl))
|
2019-05-07 00:12:57 +02:00
|
|
|
die_with_post_code(POST_INVALID_ROM,
|
|
|
|
"Failed to load after CAR program.\n");
|
2016-03-18 18:21:23 +01:00
|
|
|
|
|
|
|
/* Set the stack pointer within parameters of the program loaded. */
|
|
|
|
if (rsl.params == NULL)
|
2019-05-07 00:12:57 +02:00
|
|
|
die_with_post_code(POST_INVALID_ROM,
|
|
|
|
"No parameters found in after CAR program.\n");
|
2016-03-18 18:21:23 +01:00
|
|
|
|
2017-09-05 21:43:05 +02:00
|
|
|
finalize_load(rsl.params, pcf->stack);
|
2016-03-31 20:36:33 +02:00
|
|
|
|
2019-06-11 14:22:06 +02:00
|
|
|
stage_cache_add(STAGE_POSTCAR, prog);
|
2016-11-29 22:52:08 +01:00
|
|
|
}
|
|
|
|
|
2019-08-22 08:00:52 +02:00
|
|
|
/*
|
|
|
|
* Cache the TSEG region at the top of ram. This region is
|
|
|
|
* not restricted to SMM mode until SMM has been relocated.
|
|
|
|
* By setting the region to cacheable it provides faster access
|
|
|
|
* when relocating the SMM handler as well as using the TSEG
|
|
|
|
* region for other purposes.
|
|
|
|
*/
|
|
|
|
void postcar_enable_tseg_cache(struct postcar_frame *pcf)
|
|
|
|
{
|
|
|
|
uintptr_t smm_base;
|
|
|
|
size_t smm_size;
|
|
|
|
|
|
|
|
smm_region(&smm_base, &smm_size);
|
|
|
|
postcar_frame_add_mtrr(pcf, smm_base, smm_size,
|
|
|
|
MTRR_TYPE_WRBACK);
|
|
|
|
}
|
|
|
|
|
2019-12-18 18:40:48 +01:00
|
|
|
static void postcar_cache_invalid(void)
|
|
|
|
{
|
|
|
|
printk(BIOS_ERR, "postcar cache invalid.\n");
|
|
|
|
board_reset();
|
|
|
|
}
|
|
|
|
|
2016-11-29 22:52:08 +01:00
|
|
|
void run_postcar_phase(struct postcar_frame *pcf)
|
|
|
|
{
|
|
|
|
struct prog prog =
|
2018-11-08 10:39:39 +01:00
|
|
|
PROG_INIT(PROG_POSTCAR, CONFIG_CBFS_PREFIX "/postcar");
|
2016-11-29 22:52:08 +01:00
|
|
|
|
|
|
|
postcar_commit_mtrrs(pcf);
|
|
|
|
|
2019-03-06 01:53:33 +01:00
|
|
|
if (!CONFIG(NO_STAGE_CACHE) &&
|
2017-09-05 21:43:05 +02:00
|
|
|
romstage_handoff_is_resume()) {
|
2016-11-29 22:52:08 +01:00
|
|
|
stage_cache_load_stage(STAGE_POSTCAR, &prog);
|
2018-04-23 22:55:09 +02:00
|
|
|
/* This is here to allow platforms to pass different stack
|
|
|
|
parameters between S3 resume and normal boot. On the
|
|
|
|
platforms where the values are the same it's a nop. */
|
2017-09-05 21:43:05 +02:00
|
|
|
finalize_load(prog.arg, pcf->stack);
|
2019-12-18 18:40:48 +01:00
|
|
|
|
|
|
|
if (prog_entry(&prog) == NULL)
|
|
|
|
postcar_cache_invalid();
|
2017-09-05 21:43:05 +02:00
|
|
|
} else
|
2016-11-29 22:52:08 +01:00
|
|
|
load_postcar_cbfs(&prog, pcf);
|
|
|
|
|
2019-02-25 16:01:22 +01:00
|
|
|
/* As postcar exist, it's end of romstage here */
|
|
|
|
timestamp_add_now(TS_END_ROMSTAGE);
|
|
|
|
|
2019-11-02 13:12:18 +01:00
|
|
|
console_time_report();
|
|
|
|
|
2019-10-23 17:07:15 +02:00
|
|
|
prog_set_arg(&prog, cbmem_top());
|
|
|
|
|
2016-03-18 18:21:23 +01:00
|
|
|
prog_run(&prog);
|
|
|
|
}
|