2019-12-07 04:42:18 +00:00
|
|
|
// SPDX-License-Identifier: Intel
|
|
|
|
/*
|
|
|
|
* Copyright 2019 Google LLC
|
|
|
|
* Written by Simon Glass <sjg@chromium.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common.h>
|
|
|
|
#include <dm.h>
|
2020-05-10 17:40:05 +00:00
|
|
|
#include <log.h>
|
2019-12-07 04:42:18 +00:00
|
|
|
#include <spi_flash.h>
|
|
|
|
#include <asm/fsp/fsp_support.h>
|
|
|
|
#include <asm/fsp2/fsp_internal.h>
|
|
|
|
|
|
|
|
/* The amount of the FSP header to probe to obtain what we need */
|
|
|
|
#define PROBE_BUF_SIZE 0x180
|
|
|
|
|
|
|
|
int fsp_get_header(ulong offset, ulong size, bool use_spi_flash,
|
|
|
|
struct fsp_header **fspp)
|
|
|
|
{
|
|
|
|
static efi_guid_t guid = FSP_HEADER_GUID;
|
|
|
|
struct fv_ext_header *exhdr;
|
|
|
|
struct fsp_header *fsp;
|
|
|
|
struct ffs_file_header *file_hdr;
|
|
|
|
struct fv_header *fv;
|
|
|
|
struct raw_section *raw;
|
|
|
|
void *ptr, *base;
|
|
|
|
u8 buf[PROBE_BUF_SIZE];
|
|
|
|
struct udevice *dev;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There are quite a very steps to work through all the headers in this
|
|
|
|
* file and the structs have similar names. Turn on debugging if needed
|
|
|
|
* to understand what is going wrong.
|
|
|
|
*
|
|
|
|
* You are in a maze of twisty little headers all alike.
|
|
|
|
*/
|
2020-09-22 18:45:38 +00:00
|
|
|
log_debug("offset=%x buf=%x, use_spi_flash=%d\n", (uint)offset,
|
|
|
|
(uint)buf, use_spi_flash);
|
2019-12-07 04:42:18 +00:00
|
|
|
if (use_spi_flash) {
|
|
|
|
ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev);
|
|
|
|
if (ret)
|
|
|
|
return log_msg_ret("Cannot find flash device", ret);
|
|
|
|
ret = spi_flash_read_dm(dev, offset, PROBE_BUF_SIZE, buf);
|
|
|
|
if (ret)
|
|
|
|
return log_msg_ret("Cannot read flash", ret);
|
|
|
|
} else {
|
|
|
|
memcpy(buf, (void *)offset, PROBE_BUF_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initalise the FSP base */
|
|
|
|
ptr = buf;
|
|
|
|
fv = ptr;
|
|
|
|
|
|
|
|
/* Check the FV signature, _FVH */
|
2020-09-22 18:45:38 +00:00
|
|
|
log_debug("offset=%x sign=%x\n", (uint)offset, (uint)fv->sign);
|
2019-12-07 04:42:18 +00:00
|
|
|
if (fv->sign != EFI_FVH_SIGNATURE)
|
|
|
|
return log_msg_ret("Base FV signature", -EINVAL);
|
|
|
|
|
|
|
|
/* Go to the end of the FV header and align the address */
|
2020-09-22 18:45:38 +00:00
|
|
|
log_debug("fv->ext_hdr_off = %x\n", fv->ext_hdr_off);
|
2019-12-07 04:42:18 +00:00
|
|
|
ptr += fv->ext_hdr_off;
|
|
|
|
exhdr = ptr;
|
|
|
|
ptr += ALIGN(exhdr->ext_hdr_size, 8);
|
2020-09-22 18:45:38 +00:00
|
|
|
log_debug("ptr=%x\n", ptr - (void *)buf);
|
2019-12-07 04:42:18 +00:00
|
|
|
|
|
|
|
/* Check the FFS GUID */
|
|
|
|
file_hdr = ptr;
|
|
|
|
if (memcmp(&file_hdr->name, &guid, sizeof(guid)))
|
|
|
|
return log_msg_ret("Base FFS GUID", -ENXIO);
|
|
|
|
/* Add the FFS header size to find the raw section header */
|
|
|
|
ptr = file_hdr + 1;
|
|
|
|
|
|
|
|
raw = ptr;
|
2020-09-22 18:45:38 +00:00
|
|
|
log_debug("raw->type = %x\n", raw->type);
|
2019-12-07 04:42:18 +00:00
|
|
|
if (raw->type != EFI_SECTION_RAW)
|
|
|
|
return log_msg_ret("Section type not RAW", -ENOEXEC);
|
|
|
|
|
|
|
|
/* Add the raw section header size to find the FSP header */
|
|
|
|
ptr = raw + 1;
|
|
|
|
fsp = ptr;
|
|
|
|
|
|
|
|
/* Check the FSPH header */
|
2020-09-22 18:45:38 +00:00
|
|
|
log_debug("fsp %x, fsp-buf=%x, si=%x\n", (uint)fsp, ptr - (void *)buf,
|
|
|
|
(void *)&fsp->fsp_silicon_init - (void *)buf);
|
2019-12-07 04:42:18 +00:00
|
|
|
if (fsp->sign != EFI_FSPH_SIGNATURE)
|
|
|
|
return log_msg_ret("Base FSPH signature", -EACCES);
|
|
|
|
|
|
|
|
base = (void *)fsp->img_base;
|
2020-09-22 18:45:38 +00:00
|
|
|
log_debug("image base %x\n", (uint)base);
|
|
|
|
if (fsp->fsp_mem_init)
|
|
|
|
log_debug("mem_init offset %x\n", (uint)fsp->fsp_mem_init);
|
|
|
|
else if (fsp->fsp_silicon_init)
|
|
|
|
log_debug("silicon_init offset %x\n",
|
|
|
|
(uint)fsp->fsp_silicon_init);
|
2019-12-07 04:42:18 +00:00
|
|
|
if (use_spi_flash) {
|
|
|
|
ret = spi_flash_read_dm(dev, offset, size, base);
|
|
|
|
if (ret)
|
|
|
|
return log_msg_ret("Could not read FPS-M", ret);
|
|
|
|
} else {
|
|
|
|
memcpy(base, (void *)offset, size);
|
|
|
|
}
|
|
|
|
ptr = base + (ptr - (void *)buf);
|
|
|
|
*fspp = ptr;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 = gd->arch.fsp_s_hdr;
|
|
|
|
|
|
|
|
if (!fsp_hdr)
|
|
|
|
return log_msg_ret("no FSP", -ENOENT);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|