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