Home | History | Annotate | Download | only in fsp
      1 // SPDX-License-Identifier: Intel
      2 /*
      3  * Copyright (C) 2013, Intel Corporation
      4  * Copyright (C) 2014, Bin Meng <bmeng.cn (at) 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  */
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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