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