xref: /openbmc/u-boot/arch/x86/lib/fsp/fsp_support.c (revision e8f80a5a)
1 // SPDX-License-Identifier: Intel
2 /*
3  * Copyright (C) 2013, Intel Corporation
4  * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
5  */
6 
7 #include <common.h>
8 #include <asm/fsp/fsp_support.h>
9 #include <asm/post.h>
10 
11 /**
12  * Compares two GUIDs
13  *
14  * If the GUIDs are identical then true is returned.
15  * If there are any bit differences in the two GUIDs, then false is returned.
16  *
17  * @guid1:        A pointer to a 128 bit GUID.
18  * @guid2:        A pointer to a 128 bit GUID.
19  *
20  * @retval true:  guid1 and guid2 are identical.
21  * @retval false: guid1 and guid2 are not identical.
22  */
compare_guid(const struct efi_guid * guid1,const struct efi_guid * guid2)23 static bool compare_guid(const struct efi_guid *guid1,
24 			 const struct efi_guid *guid2)
25 {
26 	if (memcmp(guid1, guid2, sizeof(struct efi_guid)) == 0)
27 		return true;
28 	else
29 		return false;
30 }
31 
find_fsp_header(void)32 struct fsp_header *__attribute__((optimize("O0"))) find_fsp_header(void)
33 {
34 	/*
35 	 * This function may be called before the a stack is established,
36 	 * so special care must be taken. First, it cannot declare any local
37 	 * variable using stack. Only register variable can be used here.
38 	 * Secondly, some compiler version will add prolog or epilog code
39 	 * for the C function. If so the function call may not work before
40 	 * stack is ready.
41 	 *
42 	 * GCC 4.8.1 has been verified to be working for the following codes.
43 	 */
44 	volatile register u8 *fsp asm("eax");
45 
46 	/* Initalize the FSP base */
47 	fsp = (u8 *)CONFIG_FSP_ADDR;
48 
49 	/* Check the FV signature, _FVH */
50 	if (((struct fv_header *)fsp)->sign == EFI_FVH_SIGNATURE) {
51 		/* Go to the end of the FV header and align the address */
52 		fsp += ((struct fv_header *)fsp)->ext_hdr_off;
53 		fsp += ((struct fv_ext_header *)fsp)->ext_hdr_size;
54 		fsp  = (u8 *)(((u32)fsp + 7) & 0xFFFFFFF8);
55 	} else {
56 		fsp  = 0;
57 	}
58 
59 	/* Check the FFS GUID */
60 	if (fsp &&
61 	    ((struct ffs_file_header *)fsp)->name.data1 == FSP_GUID_DATA1 &&
62 	    ((struct ffs_file_header *)fsp)->name.data2 == FSP_GUID_DATA2 &&
63 	    ((struct ffs_file_header *)fsp)->name.data3 == FSP_GUID_DATA3 &&
64 	    ((struct ffs_file_header *)fsp)->name.data4[0] == FSP_GUID_DATA4_0 &&
65 	    ((struct ffs_file_header *)fsp)->name.data4[1] == FSP_GUID_DATA4_1 &&
66 	    ((struct ffs_file_header *)fsp)->name.data4[2] == FSP_GUID_DATA4_2 &&
67 	    ((struct ffs_file_header *)fsp)->name.data4[3] == FSP_GUID_DATA4_3 &&
68 	    ((struct ffs_file_header *)fsp)->name.data4[4] == FSP_GUID_DATA4_4 &&
69 	    ((struct ffs_file_header *)fsp)->name.data4[5] == FSP_GUID_DATA4_5 &&
70 	    ((struct ffs_file_header *)fsp)->name.data4[6] == FSP_GUID_DATA4_6 &&
71 	    ((struct ffs_file_header *)fsp)->name.data4[7] == FSP_GUID_DATA4_7) {
72 		/* Add the FFS header size to find the raw section header */
73 		fsp += sizeof(struct ffs_file_header);
74 	} else {
75 		fsp = 0;
76 	}
77 
78 	if (fsp &&
79 	    ((struct raw_section *)fsp)->type == EFI_SECTION_RAW) {
80 		/* Add the raw section header size to find the FSP header */
81 		fsp += sizeof(struct raw_section);
82 	} else {
83 		fsp = 0;
84 	}
85 
86 	return (struct fsp_header *)fsp;
87 }
88 
fsp_continue(u32 status,void * hob_list)89 void fsp_continue(u32 status, void *hob_list)
90 {
91 	post_code(POST_MRC);
92 
93 	assert(status == 0);
94 
95 	/* The boot loader main function entry */
96 	fsp_init_done(hob_list);
97 }
98 
fsp_init(u32 stack_top,u32 boot_mode,void * nvs_buf)99 void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf)
100 {
101 	struct fsp_config_data config_data;
102 	fsp_init_f init;
103 	struct fsp_init_params params;
104 	struct fspinit_rtbuf rt_buf;
105 	struct fsp_header *fsp_hdr;
106 	struct fsp_init_params *params_ptr;
107 #ifdef CONFIG_FSP_USE_UPD
108 	struct vpd_region *fsp_vpd;
109 	struct upd_region *fsp_upd;
110 #endif
111 
112 	fsp_hdr = find_fsp_header();
113 	if (fsp_hdr == NULL) {
114 		/* No valid FSP info header was found */
115 		panic("Invalid FSP header");
116 	}
117 
118 	config_data.common.fsp_hdr = fsp_hdr;
119 	config_data.common.stack_top = stack_top;
120 	config_data.common.boot_mode = boot_mode;
121 
122 #ifdef CONFIG_FSP_USE_UPD
123 	/* Get VPD region start */
124 	fsp_vpd = (struct vpd_region *)(fsp_hdr->img_base +
125 			fsp_hdr->cfg_region_off);
126 
127 	/* Verify the VPD data region is valid */
128 	assert(fsp_vpd->sign == VPD_IMAGE_ID);
129 
130 	fsp_upd = &config_data.fsp_upd;
131 
132 	/* Copy default data from Flash */
133 	memcpy(fsp_upd, (void *)(fsp_hdr->img_base + fsp_vpd->upd_offset),
134 	       sizeof(struct upd_region));
135 
136 	/* Verify the UPD data region is valid */
137 	assert(fsp_upd->terminator == UPD_TERMINATOR);
138 #endif
139 
140 	memset(&rt_buf, 0, sizeof(struct fspinit_rtbuf));
141 
142 	/* Override any configuration if required */
143 	update_fsp_configs(&config_data, &rt_buf);
144 
145 	memset(&params, 0, sizeof(struct fsp_init_params));
146 	params.nvs_buf = nvs_buf;
147 	params.rt_buf = (struct fspinit_rtbuf *)&rt_buf;
148 	params.continuation = (fsp_continuation_f)asm_continuation;
149 
150 	init = (fsp_init_f)(fsp_hdr->img_base + fsp_hdr->fsp_init);
151 	params_ptr = &params;
152 
153 	post_code(POST_PRE_MRC);
154 
155 	/* Load GDT for FSP */
156 	setup_fsp_gdt();
157 
158 	/*
159 	 * Use ASM code to ensure the register value in EAX & EDX
160 	 * will be passed into fsp_continue
161 	 */
162 	asm volatile (
163 		"pushl	%0;"
164 		"call	*%%eax;"
165 		".global asm_continuation;"
166 		"asm_continuation:;"
167 		"movl	4(%%esp), %%eax;"	/* status */
168 		"movl	8(%%esp), %%edx;"	/* hob_list */
169 		"jmp	fsp_continue;"
170 		: : "m"(params_ptr), "a"(init)
171 	);
172 
173 	/*
174 	 * Should never get here.
175 	 * Control will continue from fsp_continue.
176 	 * This line below is to prevent the compiler from optimizing
177 	 * structure intialization.
178 	 *
179 	 * DO NOT REMOVE!
180 	 */
181 	init(&params);
182 }
183 
fsp_notify(struct fsp_header * fsp_hdr,u32 phase)184 u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase)
185 {
186 	fsp_notify_f notify;
187 	struct fsp_notify_params params;
188 	struct fsp_notify_params *params_ptr;
189 	u32 status;
190 
191 	if (!fsp_hdr)
192 		fsp_hdr = (struct fsp_header *)find_fsp_header();
193 
194 	if (fsp_hdr == NULL) {
195 		/* No valid FSP info header */
196 		panic("Invalid FSP header");
197 	}
198 
199 	notify = (fsp_notify_f)(fsp_hdr->img_base + fsp_hdr->fsp_notify);
200 	params.phase = phase;
201 	params_ptr = &params;
202 
203 	/*
204 	 * Use ASM code to ensure correct parameter is on the stack for
205 	 * FspNotify as U-Boot is using different ABI from FSP
206 	 */
207 	asm volatile (
208 		"pushl	%1;"		/* push notify phase */
209 		"call	*%%eax;"	/* call FspNotify */
210 		"addl	$4, %%esp;"	/* clean up the stack */
211 		: "=a"(status) : "m"(params_ptr), "a"(notify), "m"(*params_ptr)
212 	);
213 
214 	return status;
215 }
216 
fsp_get_usable_lowmem_top(const void * hob_list)217 u32 fsp_get_usable_lowmem_top(const void *hob_list)
218 {
219 	const struct hob_header *hdr;
220 	struct hob_res_desc *res_desc;
221 	phys_addr_t phys_start;
222 	u32 top;
223 #ifdef CONFIG_FSP_BROKEN_HOB
224 	struct hob_mem_alloc *res_mem;
225 	phys_addr_t mem_base = 0;
226 #endif
227 
228 	/* Get the HOB list for processing */
229 	hdr = hob_list;
230 
231 	/* * Collect memory ranges */
232 	top = FSP_LOWMEM_BASE;
233 	while (!end_of_hob(hdr)) {
234 		if (hdr->type == HOB_TYPE_RES_DESC) {
235 			res_desc = (struct hob_res_desc *)hdr;
236 			if (res_desc->type == RES_SYS_MEM) {
237 				phys_start = res_desc->phys_start;
238 				/* Need memory above 1MB to be collected here */
239 				if (phys_start >= FSP_LOWMEM_BASE &&
240 				    phys_start < (phys_addr_t)FSP_HIGHMEM_BASE)
241 					top += (u32)(res_desc->len);
242 			}
243 		}
244 
245 #ifdef CONFIG_FSP_BROKEN_HOB
246 		/*
247 		 * Find out the lowest memory base address allocated by FSP
248 		 * for the boot service data
249 		 */
250 		if (hdr->type == HOB_TYPE_MEM_ALLOC) {
251 			res_mem = (struct hob_mem_alloc *)hdr;
252 			if (!mem_base)
253 				mem_base = res_mem->mem_base;
254 			if (res_mem->mem_base < mem_base)
255 				mem_base = res_mem->mem_base;
256 		}
257 #endif
258 
259 		hdr = get_next_hob(hdr);
260 	}
261 
262 #ifdef CONFIG_FSP_BROKEN_HOB
263 	/*
264 	 * Check whether the memory top address is below the FSP HOB list.
265 	 * If not, use the lowest memory base address allocated by FSP as
266 	 * the memory top address. This is to prevent U-Boot relocation
267 	 * overwrites the important boot service data which is used by FSP,
268 	 * otherwise the subsequent call to fsp_notify() will fail.
269 	 */
270 	if (top > (u32)hob_list) {
271 		debug("Adjust memory top address due to a buggy FSP\n");
272 		top = (u32)mem_base;
273 	}
274 #endif
275 
276 	return top;
277 }
278 
fsp_get_usable_highmem_top(const void * hob_list)279 u64 fsp_get_usable_highmem_top(const void *hob_list)
280 {
281 	const struct hob_header *hdr;
282 	struct hob_res_desc *res_desc;
283 	phys_addr_t phys_start;
284 	u64 top;
285 
286 	/* Get the HOB list for processing */
287 	hdr = hob_list;
288 
289 	/* Collect memory ranges */
290 	top = FSP_HIGHMEM_BASE;
291 	while (!end_of_hob(hdr)) {
292 		if (hdr->type == HOB_TYPE_RES_DESC) {
293 			res_desc = (struct hob_res_desc *)hdr;
294 			if (res_desc->type == RES_SYS_MEM) {
295 				phys_start = res_desc->phys_start;
296 				/* Need memory above 4GB to be collected here */
297 				if (phys_start >= (phys_addr_t)FSP_HIGHMEM_BASE)
298 					top += (u32)(res_desc->len);
299 			}
300 		}
301 		hdr = get_next_hob(hdr);
302 	}
303 
304 	return top;
305 }
306 
fsp_get_reserved_mem_from_guid(const void * hob_list,u64 * len,struct efi_guid * guid)307 u64 fsp_get_reserved_mem_from_guid(const void *hob_list, u64 *len,
308 				   struct efi_guid *guid)
309 {
310 	const struct hob_header *hdr;
311 	struct hob_res_desc *res_desc;
312 
313 	/* Get the HOB list for processing */
314 	hdr = hob_list;
315 
316 	/* Collect memory ranges */
317 	while (!end_of_hob(hdr)) {
318 		if (hdr->type == HOB_TYPE_RES_DESC) {
319 			res_desc = (struct hob_res_desc *)hdr;
320 			if (res_desc->type == RES_MEM_RESERVED) {
321 				if (compare_guid(&res_desc->owner, guid)) {
322 					if (len)
323 						*len = (u32)(res_desc->len);
324 
325 					return (u64)(res_desc->phys_start);
326 				}
327 			}
328 		}
329 		hdr = get_next_hob(hdr);
330 	}
331 
332 	return 0;
333 }
334 
fsp_get_fsp_reserved_mem(const void * hob_list,u32 * len)335 u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len)
336 {
337 	const struct efi_guid guid = FSP_HOB_RESOURCE_OWNER_FSP_GUID;
338 	u64 length;
339 	u32 base;
340 
341 	base = (u32)fsp_get_reserved_mem_from_guid(hob_list,
342 			&length, (struct efi_guid *)&guid);
343 	if ((len != 0) && (base != 0))
344 		*len = (u32)length;
345 
346 	return base;
347 }
348 
fsp_get_tseg_reserved_mem(const void * hob_list,u32 * len)349 u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len)
350 {
351 	const struct efi_guid guid = FSP_HOB_RESOURCE_OWNER_TSEG_GUID;
352 	u64 length;
353 	u32 base;
354 
355 	base = (u32)fsp_get_reserved_mem_from_guid(hob_list,
356 			&length, (struct efi_guid *)&guid);
357 	if ((len != 0) && (base != 0))
358 		*len = (u32)length;
359 
360 	return base;
361 }
362 
fsp_get_next_hob(uint type,const void * hob_list)363 const struct hob_header *fsp_get_next_hob(uint type, const void *hob_list)
364 {
365 	const struct hob_header *hdr;
366 
367 	hdr = hob_list;
368 
369 	/* Parse the HOB list until end of list or matching type is found */
370 	while (!end_of_hob(hdr)) {
371 		if (hdr->type == type)
372 			return hdr;
373 
374 		hdr = get_next_hob(hdr);
375 	}
376 
377 	return NULL;
378 }
379 
fsp_get_next_guid_hob(const struct efi_guid * guid,const void * hob_list)380 const struct hob_header *fsp_get_next_guid_hob(const struct efi_guid *guid,
381 					       const void *hob_list)
382 {
383 	const struct hob_header *hdr;
384 	struct hob_guid *guid_hob;
385 
386 	hdr = hob_list;
387 	while ((hdr = fsp_get_next_hob(HOB_TYPE_GUID_EXT,
388 			hdr)) != NULL) {
389 		guid_hob = (struct hob_guid *)hdr;
390 		if (compare_guid(guid, &(guid_hob->name)))
391 			break;
392 		hdr = get_next_hob(hdr);
393 	}
394 
395 	return hdr;
396 }
397 
fsp_get_guid_hob_data(const void * hob_list,u32 * len,struct efi_guid * guid)398 void *fsp_get_guid_hob_data(const void *hob_list, u32 *len,
399 			    struct efi_guid *guid)
400 {
401 	const struct hob_header *guid_hob;
402 
403 	guid_hob = fsp_get_next_guid_hob(guid, hob_list);
404 	if (guid_hob == NULL) {
405 		return NULL;
406 	} else {
407 		if (len)
408 			*len = get_guid_hob_data_size(guid_hob);
409 
410 		return get_guid_hob_data(guid_hob);
411 	}
412 }
413 
fsp_get_nvs_data(const void * hob_list,u32 * len)414 void *fsp_get_nvs_data(const void *hob_list, u32 *len)
415 {
416 	const struct efi_guid guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID;
417 
418 	return fsp_get_guid_hob_data(hob_list, len, (struct efi_guid *)&guid);
419 }
420 
fsp_get_bootloader_tmp_mem(const void * hob_list,u32 * len)421 void *fsp_get_bootloader_tmp_mem(const void *hob_list, u32 *len)
422 {
423 	const struct efi_guid guid = FSP_BOOTLOADER_TEMP_MEM_HOB_GUID;
424 
425 	return fsp_get_guid_hob_data(hob_list, len, (struct efi_guid *)&guid);
426 }
427 
fsp_get_graphics_info(const void * hob_list,u32 * len)428 void *fsp_get_graphics_info(const void *hob_list, u32 *len)
429 {
430 	const struct efi_guid guid = FSP_GRAPHICS_INFO_HOB_GUID;
431 
432 	return fsp_get_guid_hob_data(hob_list, len, (struct efi_guid *)&guid);
433 }
434