avionic design with actual uboot and tooling
submodule of avionic design uboot bootloader and with included tools to get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
11
u-boot/arch/x86/lib/fsp/Makefile
Normal file
11
u-boot/arch/x86/lib/fsp/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Copyright (C) 2015 Google, Inc
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += cmd_fsp.o
|
||||
obj-y += fsp_car.o
|
||||
obj-y += fsp_common.o
|
||||
obj-y += fsp_dram.o
|
||||
obj-y += fsp_support.o
|
||||
132
u-boot/arch/x86/lib/fsp/cmd_fsp.c
Normal file
132
u-boot/arch/x86/lib/fsp/cmd_fsp.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <asm/fsp/fsp_support.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static char *hob_type[] = {
|
||||
"reserved",
|
||||
"Hand-off",
|
||||
"Mem Alloc",
|
||||
"Res Desc",
|
||||
"GUID Ext",
|
||||
"FV",
|
||||
"CPU",
|
||||
"Mem Pool",
|
||||
"reserved",
|
||||
"FV2",
|
||||
"Load PEIM",
|
||||
"Capsule",
|
||||
};
|
||||
|
||||
static int do_hdr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
struct fsp_header *hdr = find_fsp_header();
|
||||
u32 img_addr = hdr->img_base;
|
||||
char *sign = (char *)&hdr->sign;
|
||||
int i;
|
||||
|
||||
printf("FSP : binary 0x%08x, header 0x%08x\n",
|
||||
CONFIG_FSP_ADDR, (int)hdr);
|
||||
printf("Header : sign ");
|
||||
for (i = 0; i < sizeof(hdr->sign); i++)
|
||||
printf("%c", *sign++);
|
||||
printf(", size %d, rev %d\n", hdr->hdr_len, hdr->hdr_rev);
|
||||
printf("Image : rev %d.%d, id ",
|
||||
(hdr->img_rev >> 8) & 0xff, hdr->img_rev & 0xff);
|
||||
for (i = 0; i < ARRAY_SIZE(hdr->img_id); i++)
|
||||
printf("%c", hdr->img_id[i]);
|
||||
printf(", addr 0x%08x, size %d\n", img_addr, hdr->img_size);
|
||||
printf("VPD : addr 0x%08x, size %d\n",
|
||||
hdr->cfg_region_off + img_addr, hdr->cfg_region_size);
|
||||
printf("\nNumber of APIs Supported : %d\n", hdr->api_num);
|
||||
printf("\tTempRamInit : 0x%08x\n", hdr->fsp_tempram_init + img_addr);
|
||||
printf("\tFspInit : 0x%08x\n", hdr->fsp_init + img_addr);
|
||||
printf("\tFspNotify : 0x%08x\n", hdr->fsp_notify + img_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_hob(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
const struct hob_header *hdr;
|
||||
uint type;
|
||||
char *desc;
|
||||
int i = 0;
|
||||
|
||||
hdr = gd->arch.hob_list;
|
||||
|
||||
printf("HOB list address: 0x%08x\n\n", (unsigned int)hdr);
|
||||
|
||||
printf("# | Address | Type | Len | ");
|
||||
printf("%42s\n", "GUID");
|
||||
printf("---|----------|-----------|------|-");
|
||||
printf("------------------------------------------\n");
|
||||
while (!end_of_hob(hdr)) {
|
||||
printf("%02x | %08x | ", i, (unsigned int)hdr);
|
||||
type = hdr->type;
|
||||
if (type == HOB_TYPE_UNUSED)
|
||||
desc = "*Unused*";
|
||||
else if (type == HOB_TYPE_EOH)
|
||||
desc = "*EOH*";
|
||||
else if (type >= 0 && type <= ARRAY_SIZE(hob_type))
|
||||
desc = hob_type[type];
|
||||
else
|
||||
desc = "*Invalid*";
|
||||
printf("%-9s | %04x | ", desc, hdr->len);
|
||||
|
||||
if (type == HOB_TYPE_MEM_ALLOC || type == HOB_TYPE_RES_DESC ||
|
||||
type == HOB_TYPE_GUID_EXT) {
|
||||
struct efi_guid *guid = (struct efi_guid *)(hdr + 1);
|
||||
int j;
|
||||
|
||||
printf("%08x-%04x-%04x", guid->data1,
|
||||
guid->data2, guid->data3);
|
||||
for (j = 0; j < ARRAY_SIZE(guid->data4); j++)
|
||||
printf("-%02x", guid->data4[j]);
|
||||
} else {
|
||||
printf("%42s", "Not Available");
|
||||
}
|
||||
printf("\n");
|
||||
hdr = get_next_hob(hdr);
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cmd_tbl_t fsp_commands[] = {
|
||||
U_BOOT_CMD_MKENT(hdr, 0, 1, do_hdr, "", ""),
|
||||
U_BOOT_CMD_MKENT(hob, 0, 1, do_hob, "", ""),
|
||||
};
|
||||
|
||||
static int do_fsp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
cmd_tbl_t *fsp_cmd;
|
||||
int ret;
|
||||
|
||||
if (argc < 2)
|
||||
return CMD_RET_USAGE;
|
||||
fsp_cmd = find_cmd_tbl(argv[1], fsp_commands, ARRAY_SIZE(fsp_commands));
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
if (!fsp_cmd || argc > fsp_cmd->maxargs)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
ret = fsp_cmd->cmd(fsp_cmd, flag, argc, argv);
|
||||
|
||||
return cmd_process_error(fsp_cmd, ret);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fsp, 2, 1, do_fsp,
|
||||
"Show Intel Firmware Support Package (FSP) related information",
|
||||
"hdr - Print FSP header information\n"
|
||||
"fsp hob - Print FSP Hand-Off Block (HOB) information"
|
||||
);
|
||||
110
u-boot/arch/x86/lib/fsp/fsp_car.S
Normal file
110
u-boot/arch/x86/lib/fsp/fsp_car.S
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm/post.h>
|
||||
|
||||
.globl car_init
|
||||
car_init:
|
||||
/*
|
||||
* Note: ebp holds the BIST value (built-in self test) so far, but ebp
|
||||
* will be destroyed through the FSP call, thus we have to test the
|
||||
* BIST value here before we call into FSP.
|
||||
*/
|
||||
test %ebp, %ebp
|
||||
jz car_init_start
|
||||
post_code(POST_BIST_FAILURE)
|
||||
jmp die
|
||||
|
||||
car_init_start:
|
||||
post_code(POST_CAR_START)
|
||||
lea find_fsp_header_romstack, %esp
|
||||
jmp find_fsp_header
|
||||
|
||||
find_fsp_header_ret:
|
||||
/* EAX points to FSP_INFO_HEADER */
|
||||
mov %eax, %ebp
|
||||
|
||||
/* sanity test */
|
||||
cmp $CONFIG_FSP_ADDR, %eax
|
||||
jb die
|
||||
|
||||
/* calculate TempRamInitEntry address */
|
||||
mov 0x30(%ebp), %eax
|
||||
add 0x1c(%ebp), %eax
|
||||
|
||||
/* call FSP TempRamInitEntry to setup temporary stack */
|
||||
lea temp_ram_init_romstack, %esp
|
||||
jmp *%eax
|
||||
|
||||
temp_ram_init_ret:
|
||||
addl $4, %esp
|
||||
cmp $0, %eax
|
||||
jnz car_init_fail
|
||||
|
||||
post_code(POST_CAR_CPU_CACHE)
|
||||
|
||||
/*
|
||||
* The FSP TempRamInit initializes the ecx and edx registers to
|
||||
* point to a temporary but writable memory range (Cache-As-RAM).
|
||||
* ecx: the start of this temporary memory range,
|
||||
* edx: the end of this range.
|
||||
*/
|
||||
|
||||
/* stack grows down from top of CAR */
|
||||
movl %edx, %esp
|
||||
subl $4, %esp
|
||||
|
||||
xor %esi, %esi
|
||||
jmp car_init_done
|
||||
|
||||
.global fsp_init_done
|
||||
fsp_init_done:
|
||||
/*
|
||||
* We come here from fsp_continue() with eax pointing to the HOB list.
|
||||
* Save eax to esi temporarily.
|
||||
*/
|
||||
movl %eax, %esi
|
||||
|
||||
car_init_done:
|
||||
/*
|
||||
* Re-initialize the ebp (BIST) to zero, as we already reach here
|
||||
* which means we passed BIST testing before.
|
||||
*/
|
||||
xorl %ebp, %ebp
|
||||
jmp car_init_ret
|
||||
|
||||
car_init_fail:
|
||||
post_code(POST_CAR_FAILURE)
|
||||
|
||||
die:
|
||||
hlt
|
||||
jmp die
|
||||
hlt
|
||||
|
||||
/*
|
||||
* The function call before CAR initialization is tricky. It cannot
|
||||
* be called using the 'call' instruction but only the 'jmp' with
|
||||
* the help of a handcrafted stack in the ROM. The stack needs to
|
||||
* contain the function return address as well as the parameters.
|
||||
*/
|
||||
.balign 4
|
||||
find_fsp_header_romstack:
|
||||
.long find_fsp_header_ret
|
||||
|
||||
.balign 4
|
||||
temp_ram_init_romstack:
|
||||
.long temp_ram_init_ret
|
||||
.long temp_ram_init_params
|
||||
temp_ram_init_params:
|
||||
_dt_ucode_base_size:
|
||||
/* These next two fields are filled in by ifdtool */
|
||||
.globl ucode_base
|
||||
ucode_base: /* Declared in micrcode.h */
|
||||
.long 0 /* microcode base */
|
||||
.long 0 /* microcode size */
|
||||
.long CONFIG_SYS_MONITOR_BASE /* code region base */
|
||||
.long CONFIG_SYS_MONITOR_LEN /* code region size */
|
||||
100
u-boot/arch/x86/lib/fsp/fsp_common.c
Normal file
100
u-boot/arch/x86/lib/fsp/fsp_common.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mrccache.h>
|
||||
#include <asm/post.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/fsp/fsp_support.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
post_code(POST_CPU_INFO);
|
||||
return default_print_cpuinfo();
|
||||
}
|
||||
|
||||
int fsp_init_phase_pci(void)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
/* call into FspNotify */
|
||||
debug("Calling into FSP (notify phase INIT_PHASE_PCI): ");
|
||||
status = fsp_notify(NULL, INIT_PHASE_PCI);
|
||||
if (status)
|
||||
debug("fail, error code %x\n", status);
|
||||
else
|
||||
debug("OK\n");
|
||||
|
||||
return status ? -EPERM : 0;
|
||||
}
|
||||
|
||||
void board_final_cleanup(void)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
/* call into FspNotify */
|
||||
debug("Calling into FSP (notify phase INIT_PHASE_BOOT): ");
|
||||
status = fsp_notify(NULL, INIT_PHASE_BOOT);
|
||||
if (status)
|
||||
debug("fail, error code %x\n", status);
|
||||
else
|
||||
debug("OK\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static __maybe_unused void *fsp_prepare_mrc_cache(void)
|
||||
{
|
||||
struct mrc_data_container *cache;
|
||||
struct mrc_region entry;
|
||||
int ret;
|
||||
|
||||
ret = mrccache_get_region(NULL, &entry);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
cache = mrccache_find_current(&entry);
|
||||
if (!cache)
|
||||
return NULL;
|
||||
|
||||
debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__,
|
||||
cache->data, cache->data_size, cache->checksum);
|
||||
|
||||
return cache->data;
|
||||
}
|
||||
|
||||
int x86_fsp_init(void)
|
||||
{
|
||||
void *nvs;
|
||||
|
||||
if (!gd->arch.hob_list) {
|
||||
#ifdef CONFIG_ENABLE_MRC_CACHE
|
||||
nvs = fsp_prepare_mrc_cache();
|
||||
#else
|
||||
nvs = NULL;
|
||||
#endif
|
||||
/*
|
||||
* The first time we enter here, call fsp_init().
|
||||
* Note the execution does not return to this function,
|
||||
* instead it jumps to fsp_continue().
|
||||
*/
|
||||
fsp_init(CONFIG_FSP_TEMP_RAM_ADDR, BOOT_FULL_CONFIG, nvs);
|
||||
} else {
|
||||
/*
|
||||
* The second time we enter here, adjust the size of malloc()
|
||||
* pool before relocation. Given gd->malloc_base was adjusted
|
||||
* after the call to board_init_f_init_reserve() in arch/x86/
|
||||
* cpu/start.S, we should fix up gd->malloc_limit here.
|
||||
*/
|
||||
gd->malloc_limit += CONFIG_FSP_SYS_MALLOC_F_LEN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
94
u-boot/arch/x86/lib/fsp/fsp_dram.c
Normal file
94
u-boot/arch/x86/lib/fsp/fsp_dram.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/fsp/fsp_support.h>
|
||||
#include <asm/e820.h>
|
||||
#include <asm/mrccache.h>
|
||||
#include <asm/post.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int dram_init(void)
|
||||
{
|
||||
phys_size_t ram_size = 0;
|
||||
const struct hob_header *hdr;
|
||||
struct hob_res_desc *res_desc;
|
||||
|
||||
hdr = gd->arch.hob_list;
|
||||
while (!end_of_hob(hdr)) {
|
||||
if (hdr->type == HOB_TYPE_RES_DESC) {
|
||||
res_desc = (struct hob_res_desc *)hdr;
|
||||
if (res_desc->type == RES_SYS_MEM ||
|
||||
res_desc->type == RES_MEM_RESERVED) {
|
||||
ram_size += res_desc->len;
|
||||
}
|
||||
}
|
||||
hdr = get_next_hob(hdr);
|
||||
}
|
||||
|
||||
gd->ram_size = ram_size;
|
||||
post_code(POST_DRAM);
|
||||
|
||||
#ifdef CONFIG_ENABLE_MRC_CACHE
|
||||
gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list,
|
||||
&gd->arch.mrc_output_len);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dram_init_banksize(void)
|
||||
{
|
||||
gd->bd->bi_dram[0].start = 0;
|
||||
gd->bd->bi_dram[0].size = gd->ram_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function looks for the highest region of memory lower than 4GB which
|
||||
* has enough space for U-Boot where U-Boot is aligned on a page boundary.
|
||||
* It overrides the default implementation found elsewhere which simply
|
||||
* picks the end of ram, wherever that may be. The location of the stack,
|
||||
* the relocation address, and how far U-Boot is moved by relocation are
|
||||
* set in the global data structure.
|
||||
*/
|
||||
ulong board_get_usable_ram_top(ulong total_size)
|
||||
{
|
||||
return fsp_get_usable_lowmem_top(gd->arch.hob_list);
|
||||
}
|
||||
|
||||
unsigned install_e820_map(unsigned max_entries, struct e820entry *entries)
|
||||
{
|
||||
unsigned num_entries = 0;
|
||||
const struct hob_header *hdr;
|
||||
struct hob_res_desc *res_desc;
|
||||
|
||||
hdr = gd->arch.hob_list;
|
||||
|
||||
while (!end_of_hob(hdr)) {
|
||||
if (hdr->type == HOB_TYPE_RES_DESC) {
|
||||
res_desc = (struct hob_res_desc *)hdr;
|
||||
entries[num_entries].addr = res_desc->phys_start;
|
||||
entries[num_entries].size = res_desc->len;
|
||||
|
||||
if (res_desc->type == RES_SYS_MEM)
|
||||
entries[num_entries].type = E820_RAM;
|
||||
else if (res_desc->type == RES_MEM_RESERVED)
|
||||
entries[num_entries].type = E820_RESERVED;
|
||||
|
||||
num_entries++;
|
||||
}
|
||||
hdr = get_next_hob(hdr);
|
||||
}
|
||||
|
||||
/* Mark PCIe ECAM address range as reserved */
|
||||
entries[num_entries].addr = CONFIG_PCIE_ECAM_BASE;
|
||||
entries[num_entries].size = CONFIG_PCIE_ECAM_SIZE;
|
||||
entries[num_entries].type = E820_RESERVED;
|
||||
num_entries++;
|
||||
|
||||
return num_entries;
|
||||
}
|
||||
431
u-boot/arch/x86/lib/fsp/fsp_support.c
Normal file
431
u-boot/arch/x86/lib/fsp/fsp_support.c
Normal file
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Intel
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/fsp/fsp_support.h>
|
||||
#include <asm/post.h>
|
||||
|
||||
/**
|
||||
* Compares two GUIDs
|
||||
*
|
||||
* If the GUIDs are identical then true is returned.
|
||||
* If there are any bit differences in the two GUIDs, then false is returned.
|
||||
*
|
||||
* @guid1: A pointer to a 128 bit GUID.
|
||||
* @guid2: A pointer to a 128 bit GUID.
|
||||
*
|
||||
* @retval true: guid1 and guid2 are identical.
|
||||
* @retval false: guid1 and guid2 are not identical.
|
||||
*/
|
||||
static bool compare_guid(const struct efi_guid *guid1,
|
||||
const struct efi_guid *guid2)
|
||||
{
|
||||
if (memcmp(guid1, guid2, sizeof(struct efi_guid)) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
struct fsp_header *__attribute__((optimize("O0"))) find_fsp_header(void)
|
||||
{
|
||||
/*
|
||||
* This function may be called before the a stack is established,
|
||||
* so special care must be taken. First, it cannot declare any local
|
||||
* variable using stack. Only register variable can be used here.
|
||||
* Secondly, some compiler version will add prolog or epilog code
|
||||
* for the C function. If so the function call may not work before
|
||||
* stack is ready.
|
||||
*
|
||||
* GCC 4.8.1 has been verified to be working for the following codes.
|
||||
*/
|
||||
volatile register u8 *fsp asm("eax");
|
||||
|
||||
/* Initalize the FSP base */
|
||||
fsp = (u8 *)CONFIG_FSP_ADDR;
|
||||
|
||||
/* Check the FV signature, _FVH */
|
||||
if (((struct fv_header *)fsp)->sign == EFI_FVH_SIGNATURE) {
|
||||
/* Go to the end of the FV header and align the address */
|
||||
fsp += ((struct fv_header *)fsp)->ext_hdr_off;
|
||||
fsp += ((struct fv_ext_header *)fsp)->ext_hdr_size;
|
||||
fsp = (u8 *)(((u32)fsp + 7) & 0xFFFFFFF8);
|
||||
} else {
|
||||
fsp = 0;
|
||||
}
|
||||
|
||||
/* Check the FFS GUID */
|
||||
if (fsp &&
|
||||
((struct ffs_file_header *)fsp)->name.data1 == FSP_GUID_DATA1 &&
|
||||
((struct ffs_file_header *)fsp)->name.data2 == FSP_GUID_DATA2 &&
|
||||
((struct ffs_file_header *)fsp)->name.data3 == FSP_GUID_DATA3 &&
|
||||
((struct ffs_file_header *)fsp)->name.data4[0] == FSP_GUID_DATA4_0 &&
|
||||
((struct ffs_file_header *)fsp)->name.data4[1] == FSP_GUID_DATA4_1 &&
|
||||
((struct ffs_file_header *)fsp)->name.data4[2] == FSP_GUID_DATA4_2 &&
|
||||
((struct ffs_file_header *)fsp)->name.data4[3] == FSP_GUID_DATA4_3 &&
|
||||
((struct ffs_file_header *)fsp)->name.data4[4] == FSP_GUID_DATA4_4 &&
|
||||
((struct ffs_file_header *)fsp)->name.data4[5] == FSP_GUID_DATA4_5 &&
|
||||
((struct ffs_file_header *)fsp)->name.data4[6] == FSP_GUID_DATA4_6 &&
|
||||
((struct ffs_file_header *)fsp)->name.data4[7] == FSP_GUID_DATA4_7) {
|
||||
/* Add the FFS header size to find the raw section header */
|
||||
fsp += sizeof(struct ffs_file_header);
|
||||
} else {
|
||||
fsp = 0;
|
||||
}
|
||||
|
||||
if (fsp &&
|
||||
((struct raw_section *)fsp)->type == EFI_SECTION_RAW) {
|
||||
/* Add the raw section header size to find the FSP header */
|
||||
fsp += sizeof(struct raw_section);
|
||||
} else {
|
||||
fsp = 0;
|
||||
}
|
||||
|
||||
return (struct fsp_header *)fsp;
|
||||
}
|
||||
|
||||
void fsp_continue(u32 status, void *hob_list)
|
||||
{
|
||||
post_code(POST_MRC);
|
||||
|
||||
assert(status == 0);
|
||||
|
||||
/* The boot loader main function entry */
|
||||
fsp_init_done(hob_list);
|
||||
}
|
||||
|
||||
void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf)
|
||||
{
|
||||
struct fsp_config_data config_data;
|
||||
fsp_init_f init;
|
||||
struct fsp_init_params params;
|
||||
struct fspinit_rtbuf rt_buf;
|
||||
struct fsp_header *fsp_hdr;
|
||||
struct fsp_init_params *params_ptr;
|
||||
#ifdef CONFIG_FSP_USE_UPD
|
||||
struct vpd_region *fsp_vpd;
|
||||
struct upd_region *fsp_upd;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART
|
||||
setup_internal_uart(1);
|
||||
#endif
|
||||
|
||||
fsp_hdr = find_fsp_header();
|
||||
if (fsp_hdr == NULL) {
|
||||
/* No valid FSP info header was found */
|
||||
panic("Invalid FSP header");
|
||||
}
|
||||
|
||||
config_data.common.fsp_hdr = fsp_hdr;
|
||||
config_data.common.stack_top = stack_top;
|
||||
config_data.common.boot_mode = boot_mode;
|
||||
|
||||
#ifdef CONFIG_FSP_USE_UPD
|
||||
/* Get VPD region start */
|
||||
fsp_vpd = (struct vpd_region *)(fsp_hdr->img_base +
|
||||
fsp_hdr->cfg_region_off);
|
||||
|
||||
/* Verify the VPD data region is valid */
|
||||
assert(fsp_vpd->sign == VPD_IMAGE_ID);
|
||||
|
||||
fsp_upd = &config_data.fsp_upd;
|
||||
|
||||
/* Copy default data from Flash */
|
||||
memcpy(fsp_upd, (void *)(fsp_hdr->img_base + fsp_vpd->upd_offset),
|
||||
sizeof(struct upd_region));
|
||||
|
||||
/* Verify the UPD data region is valid */
|
||||
assert(fsp_upd->terminator == UPD_TERMINATOR);
|
||||
#endif
|
||||
|
||||
memset(&rt_buf, 0, sizeof(struct fspinit_rtbuf));
|
||||
|
||||
/* Override any configuration if required */
|
||||
update_fsp_configs(&config_data, &rt_buf);
|
||||
|
||||
memset(¶ms, 0, sizeof(struct fsp_init_params));
|
||||
params.nvs_buf = nvs_buf;
|
||||
params.rt_buf = (struct fspinit_rtbuf *)&rt_buf;
|
||||
params.continuation = (fsp_continuation_f)asm_continuation;
|
||||
|
||||
init = (fsp_init_f)(fsp_hdr->img_base + fsp_hdr->fsp_init);
|
||||
params_ptr = ¶ms;
|
||||
|
||||
post_code(POST_PRE_MRC);
|
||||
|
||||
/* Load GDT for FSP */
|
||||
setup_fsp_gdt();
|
||||
|
||||
/*
|
||||
* Use ASM code to ensure the register value in EAX & EDX
|
||||
* will be passed into fsp_continue
|
||||
*/
|
||||
asm volatile (
|
||||
"pushl %0;"
|
||||
"call *%%eax;"
|
||||
".global asm_continuation;"
|
||||
"asm_continuation:;"
|
||||
"movl 4(%%esp), %%eax;" /* status */
|
||||
"movl 8(%%esp), %%edx;" /* hob_list */
|
||||
"jmp fsp_continue;"
|
||||
: : "m"(params_ptr), "a"(init)
|
||||
);
|
||||
|
||||
/*
|
||||
* Should never get here.
|
||||
* Control will continue from fsp_continue.
|
||||
* This line below is to prevent the compiler from optimizing
|
||||
* structure intialization.
|
||||
*
|
||||
* DO NOT REMOVE!
|
||||
*/
|
||||
init(¶ms);
|
||||
}
|
||||
|
||||
u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase)
|
||||
{
|
||||
fsp_notify_f notify;
|
||||
struct fsp_notify_params params;
|
||||
struct fsp_notify_params *params_ptr;
|
||||
u32 status;
|
||||
|
||||
if (!fsp_hdr)
|
||||
fsp_hdr = (struct fsp_header *)find_fsp_header();
|
||||
|
||||
if (fsp_hdr == NULL) {
|
||||
/* No valid FSP info header */
|
||||
panic("Invalid FSP header");
|
||||
}
|
||||
|
||||
notify = (fsp_notify_f)(fsp_hdr->img_base + fsp_hdr->fsp_notify);
|
||||
params.phase = phase;
|
||||
params_ptr = ¶ms;
|
||||
|
||||
/*
|
||||
* Use ASM code to ensure correct parameter is on the stack for
|
||||
* FspNotify as U-Boot is using different ABI from FSP
|
||||
*/
|
||||
asm volatile (
|
||||
"pushl %1;" /* push notify phase */
|
||||
"call *%%eax;" /* call FspNotify */
|
||||
"addl $4, %%esp;" /* clean up the stack */
|
||||
: "=a"(status) : "m"(params_ptr), "a"(notify), "m"(*params_ptr)
|
||||
);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
u32 fsp_get_usable_lowmem_top(const void *hob_list)
|
||||
{
|
||||
const struct hob_header *hdr;
|
||||
struct hob_res_desc *res_desc;
|
||||
phys_addr_t phys_start;
|
||||
u32 top;
|
||||
#ifdef CONFIG_FSP_BROKEN_HOB
|
||||
struct hob_mem_alloc *res_mem;
|
||||
phys_addr_t mem_base = 0;
|
||||
#endif
|
||||
|
||||
/* Get the HOB list for processing */
|
||||
hdr = hob_list;
|
||||
|
||||
/* * Collect memory ranges */
|
||||
top = FSP_LOWMEM_BASE;
|
||||
while (!end_of_hob(hdr)) {
|
||||
if (hdr->type == HOB_TYPE_RES_DESC) {
|
||||
res_desc = (struct hob_res_desc *)hdr;
|
||||
if (res_desc->type == RES_SYS_MEM) {
|
||||
phys_start = res_desc->phys_start;
|
||||
/* Need memory above 1MB to be collected here */
|
||||
if (phys_start >= FSP_LOWMEM_BASE &&
|
||||
phys_start < (phys_addr_t)FSP_HIGHMEM_BASE)
|
||||
top += (u32)(res_desc->len);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FSP_BROKEN_HOB
|
||||
/*
|
||||
* Find out the lowest memory base address allocated by FSP
|
||||
* for the boot service data
|
||||
*/
|
||||
if (hdr->type == HOB_TYPE_MEM_ALLOC) {
|
||||
res_mem = (struct hob_mem_alloc *)hdr;
|
||||
if (!mem_base)
|
||||
mem_base = res_mem->mem_base;
|
||||
if (res_mem->mem_base < mem_base)
|
||||
mem_base = res_mem->mem_base;
|
||||
}
|
||||
#endif
|
||||
|
||||
hdr = get_next_hob(hdr);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FSP_BROKEN_HOB
|
||||
/*
|
||||
* Check whether the memory top address is below the FSP HOB list.
|
||||
* If not, use the lowest memory base address allocated by FSP as
|
||||
* the memory top address. This is to prevent U-Boot relocation
|
||||
* overwrites the important boot service data which is used by FSP,
|
||||
* otherwise the subsequent call to fsp_notify() will fail.
|
||||
*/
|
||||
if (top > (u32)hob_list) {
|
||||
debug("Adjust memory top address due to a buggy FSP\n");
|
||||
top = (u32)mem_base;
|
||||
}
|
||||
#endif
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
u64 fsp_get_usable_highmem_top(const void *hob_list)
|
||||
{
|
||||
const struct hob_header *hdr;
|
||||
struct hob_res_desc *res_desc;
|
||||
phys_addr_t phys_start;
|
||||
u64 top;
|
||||
|
||||
/* Get the HOB list for processing */
|
||||
hdr = hob_list;
|
||||
|
||||
/* Collect memory ranges */
|
||||
top = FSP_HIGHMEM_BASE;
|
||||
while (!end_of_hob(hdr)) {
|
||||
if (hdr->type == HOB_TYPE_RES_DESC) {
|
||||
res_desc = (struct hob_res_desc *)hdr;
|
||||
if (res_desc->type == RES_SYS_MEM) {
|
||||
phys_start = res_desc->phys_start;
|
||||
/* Need memory above 4GB to be collected here */
|
||||
if (phys_start >= (phys_addr_t)FSP_HIGHMEM_BASE)
|
||||
top += (u32)(res_desc->len);
|
||||
}
|
||||
}
|
||||
hdr = get_next_hob(hdr);
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
u64 fsp_get_reserved_mem_from_guid(const void *hob_list, u64 *len,
|
||||
struct efi_guid *guid)
|
||||
{
|
||||
const struct hob_header *hdr;
|
||||
struct hob_res_desc *res_desc;
|
||||
|
||||
/* Get the HOB list for processing */
|
||||
hdr = hob_list;
|
||||
|
||||
/* Collect memory ranges */
|
||||
while (!end_of_hob(hdr)) {
|
||||
if (hdr->type == HOB_TYPE_RES_DESC) {
|
||||
res_desc = (struct hob_res_desc *)hdr;
|
||||
if (res_desc->type == RES_MEM_RESERVED) {
|
||||
if (compare_guid(&res_desc->owner, guid)) {
|
||||
if (len)
|
||||
*len = (u32)(res_desc->len);
|
||||
|
||||
return (u64)(res_desc->phys_start);
|
||||
}
|
||||
}
|
||||
}
|
||||
hdr = get_next_hob(hdr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len)
|
||||
{
|
||||
const struct efi_guid guid = FSP_HOB_RESOURCE_OWNER_FSP_GUID;
|
||||
u64 length;
|
||||
u32 base;
|
||||
|
||||
base = (u32)fsp_get_reserved_mem_from_guid(hob_list,
|
||||
&length, (struct efi_guid *)&guid);
|
||||
if ((len != 0) && (base != 0))
|
||||
*len = (u32)length;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len)
|
||||
{
|
||||
const struct efi_guid guid = FSP_HOB_RESOURCE_OWNER_TSEG_GUID;
|
||||
u64 length;
|
||||
u32 base;
|
||||
|
||||
base = (u32)fsp_get_reserved_mem_from_guid(hob_list,
|
||||
&length, (struct efi_guid *)&guid);
|
||||
if ((len != 0) && (base != 0))
|
||||
*len = (u32)length;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
const struct hob_header *fsp_get_next_hob(uint type, const void *hob_list)
|
||||
{
|
||||
const struct hob_header *hdr;
|
||||
|
||||
hdr = hob_list;
|
||||
|
||||
/* Parse the HOB list until end of list or matching type is found */
|
||||
while (!end_of_hob(hdr)) {
|
||||
if (hdr->type == type)
|
||||
return hdr;
|
||||
|
||||
hdr = get_next_hob(hdr);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct hob_header *fsp_get_next_guid_hob(const struct efi_guid *guid,
|
||||
const void *hob_list)
|
||||
{
|
||||
const struct hob_header *hdr;
|
||||
struct hob_guid *guid_hob;
|
||||
|
||||
hdr = hob_list;
|
||||
while ((hdr = fsp_get_next_hob(HOB_TYPE_GUID_EXT,
|
||||
hdr)) != NULL) {
|
||||
guid_hob = (struct hob_guid *)hdr;
|
||||
if (compare_guid(guid, &(guid_hob->name)))
|
||||
break;
|
||||
hdr = get_next_hob(hdr);
|
||||
}
|
||||
|
||||
return hdr;
|
||||
}
|
||||
|
||||
void *fsp_get_guid_hob_data(const void *hob_list, u32 *len,
|
||||
struct efi_guid *guid)
|
||||
{
|
||||
const struct hob_header *guid_hob;
|
||||
|
||||
guid_hob = fsp_get_next_guid_hob(guid, hob_list);
|
||||
if (guid_hob == NULL) {
|
||||
return NULL;
|
||||
} else {
|
||||
if (len)
|
||||
*len = get_guid_hob_data_size(guid_hob);
|
||||
|
||||
return get_guid_hob_data(guid_hob);
|
||||
}
|
||||
}
|
||||
|
||||
void *fsp_get_nvs_data(const void *hob_list, u32 *len)
|
||||
{
|
||||
const struct efi_guid guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID;
|
||||
|
||||
return fsp_get_guid_hob_data(hob_list, len, (struct efi_guid *)&guid);
|
||||
}
|
||||
|
||||
void *fsp_get_bootloader_tmp_mem(const void *hob_list, u32 *len)
|
||||
{
|
||||
const struct efi_guid guid = FSP_BOOTLOADER_TEMP_MEM_HOB_GUID;
|
||||
|
||||
return fsp_get_guid_hob_data(hob_list, len, (struct efi_guid *)&guid);
|
||||
}
|
||||
Reference in New Issue
Block a user