blob: 49934fe6de0f0b6330ab58eefd0be7e6cc401925 [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
Andrey Petrov97389702016-02-25 14:15:37 -08002
Johnny Linb8899ef2020-05-28 14:04:58 +08003#include <boot/coreboot_tables.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +02004#include <device/mmio.h>
Aaron Durbina85febc2020-05-15 15:09:10 -06005#include <cbfs.h>
Patrick Rudolphf677d172018-10-01 19:17:11 +02006#include <cf9_reset.h>
Aaron Durbina85febc2020-05-15 15:09:10 -06007#include <commonlib/bsd/compression.h>
8#include <commonlib/fsp.h>
Andrey Petrov97389702016-02-25 14:15:37 -08009#include <console/console.h>
10#include <fsp/util.h>
Andrey Petrov97389702016-02-25 14:15:37 -080011#include <string.h>
Elyes HAOUASbd1683d2019-05-15 21:05:37 +020012#include <types.h>
Nikolai Vyssotski3c3d2cf2021-07-09 18:36:27 -050013#include <assert.h>
14
15static uint32_t fsp_hdr_get_expected_min_length(void)
16{
17 if (CONFIG(PLATFORM_USES_FSP2_2))
18 return 76;
19 else if (CONFIG(PLATFORM_USES_FSP2_1))
20 return 72;
21 else if (CONFIG(PLATFORM_USES_FSP2_0))
22 return 72;
23 else
24 return dead_code_t(uint32_t);
25}
Andrey Petrov97389702016-02-25 14:15:37 -080026
27static bool looks_like_fsp_header(const uint8_t *raw_hdr)
28{
Nikolai Vyssotski3c3d2cf2021-07-09 18:36:27 -050029 uint32_t fsp_header_length = read32(raw_hdr + 4);
30
Andrey Petrov97389702016-02-25 14:15:37 -080031 if (memcmp(raw_hdr, FSP_HDR_SIGNATURE, 4)) {
32 printk(BIOS_ALERT, "Did not find a valid FSP signature\n");
33 return false;
34 }
35
Nikolai Vyssotski3c3d2cf2021-07-09 18:36:27 -050036 /* It is possible to build FSP with any version of EDK2 which could have introduced new
37 fields in FSP_INFO_HEADER. The new fields will be ignored based on the reported FSP
38 version. This check ensures that the reported header length is at least what the
39 reported FSP version requires so that we do not access any out-of-bound bytes. */
40 if (fsp_header_length < fsp_hdr_get_expected_min_length()) {
41 printk(BIOS_ALERT, "FSP header has invalid length: %d\n", fsp_header_length);
Andrey Petrov97389702016-02-25 14:15:37 -080042 return false;
43 }
44
45 return true;
46}
47
48enum cb_err fsp_identify(struct fsp_header *hdr, const void *fsp_blob)
49{
50 const uint8_t *raw_hdr = fsp_blob;
51
52 if (!looks_like_fsp_header(raw_hdr))
53 return CB_ERR;
54
Andrey Petrovd5a6eb42016-05-04 17:30:16 -070055 hdr->spec_version = read8(raw_hdr + 10);
Andrey Petrov97389702016-02-25 14:15:37 -080056 hdr->revision = read8(raw_hdr + 11);
57 hdr->fsp_revision = read32(raw_hdr + 12);
58 memcpy(hdr->image_id, raw_hdr + 16, ARRAY_SIZE(hdr->image_id));
59 hdr->image_id[ARRAY_SIZE(hdr->image_id) - 1] = '\0';
60 hdr->image_size = read32(raw_hdr + 24);
61 hdr->image_base = read32(raw_hdr + 28);
Andrey Petrovd5a6eb42016-05-04 17:30:16 -070062 hdr->image_attribute = read16(raw_hdr + 32);
63 hdr->component_attribute = read16(raw_hdr + 34);
Andrey Petrov97389702016-02-25 14:15:37 -080064 hdr->cfg_region_offset = read32(raw_hdr + 36);
65 hdr->cfg_region_size = read32(raw_hdr + 40);
Brenton Dong0a5971c2016-10-18 11:35:15 -070066 hdr->temp_ram_init_entry = read32(raw_hdr + 48);
67 hdr->temp_ram_exit_entry = read32(raw_hdr + 64);
Andrey Petrov97389702016-02-25 14:15:37 -080068 hdr->notify_phase_entry_offset = read32(raw_hdr + 56);
69 hdr->memory_init_entry_offset = read32(raw_hdr + 60);
70 hdr->silicon_init_entry_offset = read32(raw_hdr + 68);
Subrata Banik33d9c4a2020-05-26 18:26:54 +053071 if (CONFIG(PLATFORM_USES_FSP2_2))
72 hdr->multi_phase_si_init_entry_offset = read32(raw_hdr + 72);
Andrey Petrov97389702016-02-25 14:15:37 -080073
74 return CB_SUCCESS;
75}
76
Julius Werner43c9d702021-04-12 17:00:16 -070077enum cb_err fsp_validate_component(struct fsp_header *hdr, void *fsp_file, size_t file_size)
Aaron Durbina413e5e2016-07-17 23:06:03 -050078{
Julius Werner43c9d702021-04-12 17:00:16 -070079 void *raw_hdr = fsp_file + FSP_HDR_OFFSET;
Aaron Durbina413e5e2016-07-17 23:06:03 -050080
Nikolai Vyssotski3c3d2cf2021-07-09 18:36:27 -050081 if (file_size < FSP_HDR_OFFSET + fsp_hdr_get_expected_min_length()) {
Julius Werner43c9d702021-04-12 17:00:16 -070082 printk(BIOS_CRIT, "FSP blob too small.\n");
Aaron Durbina413e5e2016-07-17 23:06:03 -050083 return CB_ERR;
84 }
85
Julius Werner43c9d702021-04-12 17:00:16 -070086 if (fsp_identify(hdr, raw_hdr) != CB_SUCCESS) {
Lee Leahyb20d4ba2016-07-31 16:49:28 -070087 printk(BIOS_CRIT, "No valid FSP header\n");
Aaron Durbina413e5e2016-07-17 23:06:03 -050088 return CB_ERR;
89 }
90
Julius Wernercd49cce2019-03-05 16:53:33 -080091 if (CONFIG(DISPLAY_FSP_HEADER))
Lee Leahy37b5ef22016-07-31 14:15:49 -070092 fsp_print_header_info(hdr);
Aaron Durbina413e5e2016-07-17 23:06:03 -050093
94 /* Check if size specified in the header matches the cbfs file size */
Julius Werner43c9d702021-04-12 17:00:16 -070095 if (file_size < hdr->image_size) {
Lee Leahyb20d4ba2016-07-31 16:49:28 -070096 printk(BIOS_CRIT, "Component size bigger than cbfs file.\n");
Aaron Durbina413e5e2016-07-17 23:06:03 -050097 return CB_ERR;
98 }
99
Johnny Lin5b47d772020-11-13 17:21:25 +0800100 if (ENV_ROMSTAGE)
Felix Held42df9af2021-08-24 19:26:56 +0200101 soc_validate_fspm_header(hdr);
Johnny Lin5b47d772020-11-13 17:21:25 +0800102
Aaron Durbina413e5e2016-07-17 23:06:03 -0500103 return CB_SUCCESS;
104}
105
Brandon Breitensteinc31ba0e2016-07-27 17:34:45 -0700106static bool fsp_reset_requested(uint32_t status)
Andrey Petrov3a94a3b2016-07-18 00:15:41 -0700107{
108 return (status >= FSP_STATUS_RESET_REQUIRED_COLD &&
109 status <= FSP_STATUS_RESET_REQUIRED_8);
110}
111
Brandon Breitensteinc31ba0e2016-07-27 17:34:45 -0700112void fsp_handle_reset(uint32_t status)
Andrey Petrov901e43c2016-06-22 19:22:30 -0700113{
Andrey Petrov3a94a3b2016-07-18 00:15:41 -0700114 if (!fsp_reset_requested(status))
115 return;
116
Lee Leahyb20d4ba2016-07-31 16:49:28 -0700117 printk(BIOS_SPEW, "FSP: handling reset type %x\n", status);
Andrey Petrov3a94a3b2016-07-18 00:15:41 -0700118
Lee Leahyb2b97a52017-03-10 08:40:18 -0800119 switch (status) {
Andrey Petrov901e43c2016-06-22 19:22:30 -0700120 case FSP_STATUS_RESET_REQUIRED_COLD:
Patrick Rudolphf677d172018-10-01 19:17:11 +0200121 full_reset();
Andrey Petrov901e43c2016-06-22 19:22:30 -0700122 break;
123 case FSP_STATUS_RESET_REQUIRED_WARM:
Patrick Rudolphf677d172018-10-01 19:17:11 +0200124 system_reset();
Andrey Petrov901e43c2016-06-22 19:22:30 -0700125 break;
Andrey Petrov3a94a3b2016-07-18 00:15:41 -0700126 case FSP_STATUS_RESET_REQUIRED_3:
127 case FSP_STATUS_RESET_REQUIRED_4:
128 case FSP_STATUS_RESET_REQUIRED_5:
129 case FSP_STATUS_RESET_REQUIRED_6:
130 case FSP_STATUS_RESET_REQUIRED_7:
131 case FSP_STATUS_RESET_REQUIRED_8:
132 chipset_handle_reset(status);
Andrey Petrov901e43c2016-06-22 19:22:30 -0700133 break;
134 default:
135 break;
136 }
137}
Aaron Durbina85febc2020-05-15 15:09:10 -0600138
Aaron Durbinecbfa992020-05-15 17:01:58 -0600139static inline bool fspm_env(void)
140{
141 if (ENV_ROMSTAGE)
142 return true;
143 return false;
144}
145
146static inline bool fspm_xip(void)
147{
148 /* FSP-M is assumed to be loaded in romstage. */
149 if (fspm_env() && CONFIG(FSP_M_XIP))
150 return true;
151 return false;
152}
153
Aaron Durbina85febc2020-05-15 15:09:10 -0600154/* Load the FSP component described by fsp_load_descriptor from cbfs. The FSP
155 * header object will be validated and filled in on successful load. */
156enum cb_err fsp_load_component(struct fsp_load_descriptor *fspld, struct fsp_header *hdr)
157{
Aaron Durbina85febc2020-05-15 15:09:10 -0600158 size_t output_size;
159 void *dest;
Aaron Durbina85febc2020-05-15 15:09:10 -0600160 struct prog *fsp_prog = &fspld->fsp_prog;
161
Julius Werner8205ce62021-03-10 17:25:01 -0800162 dest = cbfs_alloc(prog_name(fsp_prog), fspld->alloc, fspld, &output_size);
163 if (!dest)
Aaron Durbina85febc2020-05-15 15:09:10 -0600164 return CB_ERR;
165
Raul E Rangel4911dc72021-11-05 10:29:24 -0600166 /* Don't allow FSP-M relocation when XIP. */
167 if (!fspm_xip() && fsp_component_relocate((uintptr_t)dest, dest, output_size) < 0) {
Julius Werner8205ce62021-03-10 17:25:01 -0800168 printk(BIOS_ERR, "Unable to relocate FSP component!\n");
Aaron Durbina85febc2020-05-15 15:09:10 -0600169 return CB_ERR;
Julius Werner8205ce62021-03-10 17:25:01 -0800170 }
Aaron Durbina85febc2020-05-15 15:09:10 -0600171
172 prog_set_area(fsp_prog, dest, output_size);
173
Julius Werner43c9d702021-04-12 17:00:16 -0700174 if (fsp_validate_component(hdr, dest, output_size) != CB_SUCCESS) {
Aaron Durbina85febc2020-05-15 15:09:10 -0600175 printk(BIOS_ERR, "Invalid FSP header after load!\n");
176 return CB_ERR;
177 }
178
179 /* Signal that FSP component has been loaded. */
180 prog_segment_loaded(hdr->image_base, hdr->image_size, SEG_FINAL);
181
182 return CB_SUCCESS;
183}
Johnny Linb8899ef2020-05-28 14:04:58 +0800184
185/* Only call this function when FSP header has been read and validated */
186void fsp_get_version(char *buf)
187{
188 struct fsp_header *hdr = &fsps_hdr;
Johnny Lin5b47d772020-11-13 17:21:25 +0800189 union fsp_revision revision;
Johnny Linb8899ef2020-05-28 14:04:58 +0800190
191 revision.val = hdr->fsp_revision;
192 snprintf(buf, FSP_VER_LEN, "%u.%u-%u.%u.%u.%u", (hdr->spec_version >> 4),
193 hdr->spec_version & 0xf, revision.rev.major,
194 revision.rev.minor, revision.rev.revision, revision.rev.bld_num);
195}
196
Felix Held88995982021-01-28 22:43:52 +0100197/* Check if the signature in the UPD header matches the expected one. If it doesn't match, the
198 FSP binaries in CBFS are for a different platform than the platform code trying to use it
199 in which case the function calls die(). */
200void fsp_verify_upd_header_signature(uint64_t upd_signature, uint64_t expected_signature)
201{
202 if (upd_signature != expected_signature) {
203 /* The UPD signatures are non-zero-terminated ASCII stored as a little endian
204 uint64_t, so this needs some casts. */
205 die_with_post_code(POST_INVALID_VENDOR_BINARY,
206 "Invalid UPD signature! FSP provided \"%8s\", expected was \"%8s\".\n",
207 (char *)&upd_signature,
208 (char *)&expected_signature);
209 }
210}
211
Johnny Linb8899ef2020-05-28 14:04:58 +0800212/* Add FSP version to coreboot table LB_TAG_PLATFORM_BLOB_VERSION */
213void lb_string_platform_blob_version(struct lb_header *header)
214{
215 struct lb_string *rec;
216 size_t len;
217 char fsp_version[FSP_VER_LEN] = {0};
218
219 fsp_get_version(fsp_version);
220 rec = (struct lb_string *)lb_new_record(header);
221 rec->tag = LB_TAG_PLATFORM_BLOB_VERSION;
222 len = strlen(fsp_version);
223 rec->size = ALIGN_UP(sizeof(*rec) + len + 1, 8);
224 memcpy(rec->string, fsp_version, len+1);
225}
Johnny Lin5b47d772020-11-13 17:21:25 +0800226
Felix Held42df9af2021-08-24 19:26:56 +0200227__weak void soc_validate_fspm_header(const struct fsp_header *hdr)
Johnny Lin5b47d772020-11-13 17:21:25 +0800228{
Johnny Lin5b47d772020-11-13 17:21:25 +0800229}