1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <arch/romstage.h>
5 #include <console/console.h>
6 #include <cpu/x86/msr.h>
7 #include <cpu/x86/mtrr.h>
8 #include <cpu/x86/smm.h>
9 #include <program_loading.h>
12 #include <romstage_handoff.h>
13 #include <security/vboot/vboot_common.h>
14 #include <stage_cache.h>
15 #include <timestamp.h>
18 static size_t var_mtrr_ctx_size(void)
20 int mtrr_count
= get_var_mtrr_count();
21 return sizeof(struct var_mtrr_context
) + mtrr_count
* 2 * sizeof(msr_t
);
24 static enum cb_err
postcar_frame_init(struct postcar_frame
*pcf
)
26 memset(pcf
, 0, sizeof(*pcf
));
28 struct var_mtrr_context
*ctx
;
30 ctx
= cbmem_add(CBMEM_ID_ROMSTAGE_RAM_STACK
, var_mtrr_ctx_size());
32 printk(BIOS_ERR
, "Couldn't add var_mtrr_ctx setup in cbmem.\n");
37 var_mtrr_context_init(pcf
->mtrr
);
42 void postcar_frame_add_mtrr(struct postcar_frame
*pcf
,
43 uintptr_t addr
, size_t size
, int type
)
45 var_mtrr_set(pcf
->mtrr
, addr
, size
, type
);
48 void postcar_frame_add_romcache(struct postcar_frame
*pcf
, int type
)
50 if (!CONFIG(BOOT_DEVICE_MEMORY_MAPPED
))
52 postcar_frame_add_mtrr(pcf
, CACHE_ROM_BASE
, CACHE_ROM_SIZE
, type
);
55 static void postcar_frame_common_mtrrs(struct postcar_frame
*pcf
)
57 if (pcf
->skip_common_mtrr
)
60 /* Cache the ROM as WP just below 4GiB. */
61 postcar_frame_add_romcache(pcf
, MTRR_TYPE_WRPROT
);
64 static void run_postcar_phase(struct postcar_frame
*pcf
);
66 /* prepare_and_run_postcar() determines the stack to use after
67 * cache-as-ram is torn down as well as the MTRR settings to use. */
68 void __noreturn
prepare_and_run_postcar(void)
70 struct postcar_frame pcf
;
72 if (postcar_frame_init(&pcf
))
73 die("Unable to initialize postcar frame.\n");
75 fill_postcar_frame(&pcf
);
77 postcar_frame_common_mtrrs(&pcf
);
79 run_postcar_phase(&pcf
);
80 /* We do not return here. */
81 die("Failed to load postcar\n!");
84 static void finalize_load(uintptr_t *reloc_params
, uintptr_t mtrr_frame_ptr
)
86 *reloc_params
= mtrr_frame_ptr
;
88 * Signal to rest of system that another update was made to the
89 * postcar program prior to running it.
91 prog_segment_loaded((uintptr_t)reloc_params
, sizeof(uintptr_t), SEG_FINAL
);
92 prog_segment_loaded((uintptr_t)mtrr_frame_ptr
, var_mtrr_ctx_size(), SEG_FINAL
);
95 static void load_postcar_cbfs(struct prog
*prog
, struct postcar_frame
*pcf
)
97 struct rmod_stage_load rsl
= {
98 .cbmem_id
= CBMEM_ID_AFTER_CAR
,
102 if (rmodule_stage_load(&rsl
))
103 die_with_post_code(POSTCODE_INVALID_ROM
,
104 "Failed to load after CAR program.\n");
106 /* Set the stack pointer within parameters of the program loaded. */
107 if (rsl
.params
== NULL
)
108 die_with_post_code(POSTCODE_INVALID_ROM
,
109 "No parameters found in after CAR program.\n");
111 finalize_load(rsl
.params
, (uintptr_t)pcf
->mtrr
);
113 stage_cache_add(STAGE_POSTCAR
, prog
);
117 * Cache the TSEG region at the top of ram. This region is
118 * not restricted to SMM mode until SMM has been relocated.
119 * By setting the region to cacheable it provides faster access
120 * when relocating the SMM handler as well as using the TSEG
121 * region for other purposes.
123 void postcar_enable_tseg_cache(struct postcar_frame
*pcf
)
128 smm_region(&smm_base
, &smm_size
);
129 postcar_frame_add_mtrr(pcf
, smm_base
, smm_size
,
133 static void postcar_cache_invalid(void)
135 printk(BIOS_ERR
, "postcar cache invalid.\n");
140 * POSTCAR will call invd so don't make assumptions on cbmem
141 * and external stage cache being UC.
143 static void postcar_flush_cache(void)
145 uintptr_t cbmem_base
;
147 uintptr_t stage_cache_base
;
148 size_t stage_cache_size
;
150 if (cbmem_get_region((void **)&cbmem_base
, &cbmem_size
))
151 die("Could not find cbmem region");
152 prog_segment_loaded(cbmem_base
, cbmem_size
, SEG_FINAL
);
153 if (CONFIG(TSEG_STAGE_CACHE
) && !romstage_handoff_is_resume()) {
154 stage_cache_external_region((void **)&stage_cache_base
, &stage_cache_size
);
155 prog_segment_loaded(stage_cache_base
, stage_cache_size
, SEG_FINAL
);
159 static void run_postcar_phase(struct postcar_frame
*pcf
)
162 PROG_INIT(PROG_POSTCAR
, CONFIG_CBFS_PREFIX
"/postcar");
166 if (resume_from_stage_cache()) {
167 stage_cache_load_stage(STAGE_POSTCAR
, &prog
);
168 /* This is here to allow platforms to pass different stack
169 parameters between S3 resume and normal boot. On the
170 platforms where the values are the same it's a nop. */
171 finalize_load(prog
.arg
, (uintptr_t)pcf
->mtrr
);
173 if (prog_entry(&prog
) == NULL
)
174 postcar_cache_invalid();
176 load_postcar_cbfs(&prog
, pcf
);
178 /* As postcar exist, it's end of romstage here */
179 timestamp_add_now(TS_ROMSTAGE_END
);
181 console_time_report();
183 postcar_flush_cache();
185 prog_set_arg(&prog
, (void *)cbmem_top());