xref: /aosp_15_r20/external/coreboot/src/arch/x86/postcar_loader.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <arch/romstage.h>
4 #include <cbmem.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>
10 #include <reset.h>
11 #include <rmodule.h>
12 #include <romstage_handoff.h>
13 #include <security/vboot/vboot_common.h>
14 #include <stage_cache.h>
15 #include <timestamp.h>
16 #include <types.h>
17 
var_mtrr_ctx_size(void)18 static size_t var_mtrr_ctx_size(void)
19 {
20 	int mtrr_count = get_var_mtrr_count();
21 	return sizeof(struct var_mtrr_context) + mtrr_count * 2 * sizeof(msr_t);
22 }
23 
postcar_frame_init(struct postcar_frame * pcf)24 static enum cb_err postcar_frame_init(struct postcar_frame *pcf)
25 {
26 	memset(pcf, 0, sizeof(*pcf));
27 
28 	struct var_mtrr_context *ctx;
29 
30 	ctx = cbmem_add(CBMEM_ID_ROMSTAGE_RAM_STACK, var_mtrr_ctx_size());
31 	if (ctx == NULL) {
32 		printk(BIOS_ERR, "Couldn't add var_mtrr_ctx setup in cbmem.\n");
33 		return CB_ERR;
34 	}
35 
36 	pcf->mtrr = ctx;
37 	var_mtrr_context_init(pcf->mtrr);
38 
39 	return CB_SUCCESS;
40 }
41 
postcar_frame_add_mtrr(struct postcar_frame * pcf,uintptr_t addr,size_t size,int type)42 void postcar_frame_add_mtrr(struct postcar_frame *pcf,
43 				uintptr_t addr, size_t size, int type)
44 {
45 	var_mtrr_set(pcf->mtrr, addr, size, type);
46 }
47 
postcar_frame_add_romcache(struct postcar_frame * pcf,int type)48 void postcar_frame_add_romcache(struct postcar_frame *pcf, int type)
49 {
50 	if (!CONFIG(BOOT_DEVICE_MEMORY_MAPPED))
51 		return;
52 	postcar_frame_add_mtrr(pcf, CACHE_ROM_BASE, CACHE_ROM_SIZE, type);
53 }
54 
postcar_frame_common_mtrrs(struct postcar_frame * pcf)55 static void postcar_frame_common_mtrrs(struct postcar_frame *pcf)
56 {
57 	if (pcf->skip_common_mtrr)
58 		return;
59 
60 	/* Cache the ROM as WP just below 4GiB. */
61 	postcar_frame_add_romcache(pcf, MTRR_TYPE_WRPROT);
62 }
63 
64 static void run_postcar_phase(struct postcar_frame *pcf);
65 
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. */
prepare_and_run_postcar(void)68 void __noreturn prepare_and_run_postcar(void)
69 {
70 	struct postcar_frame pcf;
71 
72 	if (postcar_frame_init(&pcf))
73 		die("Unable to initialize postcar frame.\n");
74 
75 	fill_postcar_frame(&pcf);
76 
77 	postcar_frame_common_mtrrs(&pcf);
78 
79 	run_postcar_phase(&pcf);
80 	/* We do not return here. */
81 	die("Failed to load postcar\n!");
82 }
83 
finalize_load(uintptr_t * reloc_params,uintptr_t mtrr_frame_ptr)84 static void finalize_load(uintptr_t *reloc_params, uintptr_t mtrr_frame_ptr)
85 {
86 	*reloc_params = mtrr_frame_ptr;
87 	/*
88 	 * Signal to rest of system that another update was made to the
89 	 * postcar program prior to running it.
90 	 */
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);
93 }
94 
load_postcar_cbfs(struct prog * prog,struct postcar_frame * pcf)95 static void load_postcar_cbfs(struct prog *prog, struct postcar_frame *pcf)
96 {
97 	struct rmod_stage_load rsl = {
98 		.cbmem_id = CBMEM_ID_AFTER_CAR,
99 		.prog = prog,
100 	};
101 
102 	if (rmodule_stage_load(&rsl))
103 		die_with_post_code(POSTCODE_INVALID_ROM,
104 				   "Failed to load after CAR program.\n");
105 
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");
110 
111 	finalize_load(rsl.params, (uintptr_t)pcf->mtrr);
112 
113 	stage_cache_add(STAGE_POSTCAR, prog);
114 }
115 
116 /*
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.
122  */
postcar_enable_tseg_cache(struct postcar_frame * pcf)123 void postcar_enable_tseg_cache(struct postcar_frame *pcf)
124 {
125 	uintptr_t smm_base;
126 	size_t smm_size;
127 
128 	smm_region(&smm_base, &smm_size);
129 	postcar_frame_add_mtrr(pcf, smm_base, smm_size,
130 				MTRR_TYPE_WRBACK);
131 }
132 
postcar_cache_invalid(void)133 static void postcar_cache_invalid(void)
134 {
135 	printk(BIOS_ERR, "postcar cache invalid.\n");
136 	board_reset();
137 }
138 
139 /*
140  * POSTCAR will call invd so don't make assumptions on cbmem
141  * and external stage cache being UC.
142  */
postcar_flush_cache(void)143 static void postcar_flush_cache(void)
144 {
145 	uintptr_t cbmem_base;
146 	size_t cbmem_size;
147 	uintptr_t stage_cache_base;
148 	size_t stage_cache_size;
149 
150 	cbmem_get_region((void **)&cbmem_base, &cbmem_size);
151 	prog_segment_loaded(cbmem_base, cbmem_size, SEG_FINAL);
152 	if (CONFIG(TSEG_STAGE_CACHE) && !romstage_handoff_is_resume()) {
153 		stage_cache_external_region((void **)&stage_cache_base, &stage_cache_size);
154 		prog_segment_loaded(stage_cache_base, stage_cache_size, SEG_FINAL);
155 	}
156 }
157 
run_postcar_phase(struct postcar_frame * pcf)158 static void run_postcar_phase(struct postcar_frame *pcf)
159 {
160 	struct prog prog =
161 		PROG_INIT(PROG_POSTCAR, CONFIG_CBFS_PREFIX "/postcar");
162 
163 	vboot_run_logic();
164 
165 	if (resume_from_stage_cache()) {
166 		stage_cache_load_stage(STAGE_POSTCAR, &prog);
167 		/* This is here to allow platforms to pass different stack
168 		   parameters between S3 resume and normal boot. On the
169 		   platforms where the values are the same it's a nop. */
170 		finalize_load(prog.arg, (uintptr_t)pcf->mtrr);
171 
172 		if (prog_entry(&prog) == NULL)
173 			postcar_cache_invalid();
174 	} else
175 		load_postcar_cbfs(&prog, pcf);
176 
177 	/* As postcar exist, it's end of romstage here */
178 	timestamp_add_now(TS_ROMSTAGE_END);
179 
180 	console_time_report();
181 
182 	postcar_flush_cache();
183 
184 	prog_set_arg(&prog, (void *)cbmem_top());
185 
186 	prog_run(&prog);
187 }
188