blob: 0a04b443f7e4389d26c59ee69e0caeeca14978a6 [file] [log] [blame]
Simon Glass466c7852019-12-06 21:42:18 -07001// SPDX-License-Identifier: Intel
2/*
3 * Copyright 2019 Google LLC
4 * Written by Simon Glass <sjg@chromium.org>
5 */
6
7#include <common.h>
8#include <dm.h>
9#include <spi_flash.h>
10#include <asm/fsp/fsp_support.h>
11#include <asm/fsp2/fsp_internal.h>
12
13/* The amount of the FSP header to probe to obtain what we need */
14#define PROBE_BUF_SIZE 0x180
15
16int fsp_get_header(ulong offset, ulong size, bool use_spi_flash,
17 struct fsp_header **fspp)
18{
19 static efi_guid_t guid = FSP_HEADER_GUID;
20 struct fv_ext_header *exhdr;
21 struct fsp_header *fsp;
22 struct ffs_file_header *file_hdr;
23 struct fv_header *fv;
24 struct raw_section *raw;
25 void *ptr, *base;
26 u8 buf[PROBE_BUF_SIZE];
27 struct udevice *dev;
28 int ret;
29
30 /*
31 * There are quite a very steps to work through all the headers in this
32 * file and the structs have similar names. Turn on debugging if needed
33 * to understand what is going wrong.
34 *
35 * You are in a maze of twisty little headers all alike.
36 */
37 debug("offset=%x buf=%x\n", (uint)offset, (uint)buf);
38 if (use_spi_flash) {
39 ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev);
40 if (ret)
41 return log_msg_ret("Cannot find flash device", ret);
42 ret = spi_flash_read_dm(dev, offset, PROBE_BUF_SIZE, buf);
43 if (ret)
44 return log_msg_ret("Cannot read flash", ret);
45 } else {
46 memcpy(buf, (void *)offset, PROBE_BUF_SIZE);
47 }
48
49 /* Initalise the FSP base */
50 ptr = buf;
51 fv = ptr;
52
53 /* Check the FV signature, _FVH */
54 debug("offset=%x sign=%x\n", (uint)offset, (uint)fv->sign);
55 if (fv->sign != EFI_FVH_SIGNATURE)
56 return log_msg_ret("Base FV signature", -EINVAL);
57
58 /* Go to the end of the FV header and align the address */
59 debug("fv->ext_hdr_off = %x\n", fv->ext_hdr_off);
60 ptr += fv->ext_hdr_off;
61 exhdr = ptr;
62 ptr += ALIGN(exhdr->ext_hdr_size, 8);
63 debug("ptr=%x\n", ptr - (void *)buf);
64
65 /* Check the FFS GUID */
66 file_hdr = ptr;
67 if (memcmp(&file_hdr->name, &guid, sizeof(guid)))
68 return log_msg_ret("Base FFS GUID", -ENXIO);
69 /* Add the FFS header size to find the raw section header */
70 ptr = file_hdr + 1;
71
72 raw = ptr;
73 debug("raw->type = %x\n", raw->type);
74 if (raw->type != EFI_SECTION_RAW)
75 return log_msg_ret("Section type not RAW", -ENOEXEC);
76
77 /* Add the raw section header size to find the FSP header */
78 ptr = raw + 1;
79 fsp = ptr;
80
81 /* Check the FSPH header */
82 debug("fsp %x\n", (uint)fsp);
83 if (fsp->sign != EFI_FSPH_SIGNATURE)
84 return log_msg_ret("Base FSPH signature", -EACCES);
85
86 base = (void *)fsp->img_base;
87 debug("Image base %x\n", (uint)base);
88 debug("Image addr %x\n", (uint)fsp->fsp_mem_init);
89 if (use_spi_flash) {
90 ret = spi_flash_read_dm(dev, offset, size, base);
91 if (ret)
92 return log_msg_ret("Could not read FPS-M", ret);
93 } else {
94 memcpy(base, (void *)offset, size);
95 }
96 ptr = base + (ptr - (void *)buf);
97 *fspp = ptr;
98
99 return 0;
100}
101
102u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase)
103{
104 fsp_notify_f notify;
105 struct fsp_notify_params params;
106 struct fsp_notify_params *params_ptr;
107 u32 status;
108
109 if (!fsp_hdr)
110 fsp_hdr = gd->arch.fsp_s_hdr;
111
112 if (!fsp_hdr)
113 return log_msg_ret("no FSP", -ENOENT);
114
115 notify = (fsp_notify_f)(fsp_hdr->img_base + fsp_hdr->fsp_notify);
116 params.phase = phase;
117 params_ptr = &params;
118
119 /*
120 * Use ASM code to ensure correct parameter is on the stack for
121 * FspNotify as U-Boot is using different ABI from FSP
122 */
123 asm volatile (
124 "pushl %1;" /* push notify phase */
125 "call *%%eax;" /* call FspNotify */
126 "addl $4, %%esp;" /* clean up the stack */
127 : "=a"(status) : "m"(params_ptr), "a"(notify), "m"(*params_ptr)
128 );
129
130 return status;
131}