1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <boot/coreboot_tables.h>
4 #include <device/mmio.h>
7 #include <commonlib/bsd/compression.h>
8 #include <commonlib/fsp.h>
9 #include <console/console.h>
16 static uint32_t fsp_hdr_get_expected_min_length(void)
18 if (CONFIG(PLATFORM_USES_FSP2_3
))
20 else if (CONFIG(PLATFORM_USES_FSP2_2
))
22 else if (CONFIG(PLATFORM_USES_FSP2_1
))
24 else if (CONFIG(PLATFORM_USES_FSP2_0
))
27 return dead_code_t(uint32_t);
30 static bool looks_like_fsp_header(struct fsp_header
*hdr
)
32 if (memcmp(&hdr
->signature
, FSP_HDR_SIGNATURE
, 4)) {
33 printk(BIOS_ALERT
, "Did not find a valid FSP signature\n");
37 /* It is possible to build FSP with any version of edk2 which could have introduced new
38 fields in FSP_INFO_HEADER. The new fields will be ignored based on the reported FSP
39 version. This check ensures that the reported header length is at least what the
40 reported FSP version requires so that we do not access any out-of-bound bytes. */
41 if (hdr
->header_length
< fsp_hdr_get_expected_min_length()) {
42 printk(BIOS_ALERT
, "FSP header has invalid length: %d\n", hdr
->header_length
);
49 enum cb_err
fsp_identify(struct fsp_header
*hdr
, const void *fsp_blob
)
51 memcpy(hdr
, fsp_blob
, sizeof(struct fsp_header
));
52 if (!looks_like_fsp_header(hdr
))
58 enum cb_err
fsp_validate_component(struct fsp_header
*hdr
, void *fsp_file
, size_t file_size
)
60 void *raw_hdr
= fsp_file
+ FSP_HDR_OFFSET
;
62 if (file_size
< FSP_HDR_OFFSET
+ fsp_hdr_get_expected_min_length()) {
63 printk(BIOS_CRIT
, "FSP blob too small.\n");
67 if (fsp_identify(hdr
, raw_hdr
) != CB_SUCCESS
) {
68 printk(BIOS_CRIT
, "No valid FSP header\n");
72 if (CONFIG(DISPLAY_FSP_HEADER
))
73 fsp_print_header_info(hdr
);
75 /* Check if size specified in the header matches the cbfs file size */
76 if (file_size
< hdr
->image_size
) {
77 printk(BIOS_CRIT
, "Component size bigger than cbfs file.\n");
82 soc_validate_fspm_header(hdr
);
87 static bool fsp_reset_requested(efi_return_status_t status
)
89 return (status
>= FSP_STATUS_RESET_REQUIRED_COLD
&&
90 status
<= FSP_STATUS_RESET_REQUIRED_8
);
93 void fsp_handle_reset(efi_return_status_t status
)
95 if (!fsp_reset_requested(status
))
98 fsp_printk(status
, BIOS_SPEW
, "FSP: handling reset type");
101 case FSP_STATUS_RESET_REQUIRED_COLD
:
104 case FSP_STATUS_RESET_REQUIRED_WARM
:
107 case FSP_STATUS_RESET_REQUIRED_3
:
108 case FSP_STATUS_RESET_REQUIRED_4
:
109 case FSP_STATUS_RESET_REQUIRED_5
:
110 case FSP_STATUS_RESET_REQUIRED_6
:
111 case FSP_STATUS_RESET_REQUIRED_7
:
112 case FSP_STATUS_RESET_REQUIRED_8
:
113 chipset_handle_reset(status
);
120 static inline bool fspm_env(void)
127 static inline bool fspm_xip(void)
129 /* FSP-M is assumed to be loaded in romstage. */
130 if (fspm_env() && CONFIG(FSP_M_XIP
))
135 /* Load the FSP component described by fsp_load_descriptor from cbfs. The FSP
136 * header object will be validated and filled in on successful load. */
137 enum cb_err
fsp_load_component(struct fsp_load_descriptor
*fspld
, struct fsp_header
*hdr
)
141 struct prog
*fsp_prog
= &fspld
->fsp_prog
;
143 dest
= cbfs_alloc(prog_name(fsp_prog
), fspld
->alloc
, fspld
, &output_size
);
147 /* Don't allow FSP-M relocation when XIP. */
148 if (!fspm_xip() && fsp_component_relocate((uintptr_t)dest
, dest
, output_size
) < 0) {
149 printk(BIOS_ERR
, "Unable to relocate FSP component!\n");
153 prog_set_area(fsp_prog
, dest
, output_size
);
155 if (fsp_validate_component(hdr
, dest
, output_size
) != CB_SUCCESS
) {
156 printk(BIOS_ERR
, "Invalid FSP header after load!\n");
160 /* Signal that FSP component has been loaded. */
161 prog_segment_loaded(hdr
->image_base
, hdr
->image_size
, SEG_FINAL
);
166 /* Only call this function when FSP header has been read and validated */
167 void fsp_get_version(char *buf
)
169 struct fsp_header
*hdr
= &fsps_hdr
;
170 union fsp_revision revision
;
172 revision
.val
= hdr
->image_revision
;
173 snprintf(buf
, FSP_VER_LEN
, "%u.%u-%u.%u.%u.%u", (hdr
->spec_version
>> 4),
174 hdr
->spec_version
& 0xf, revision
.rev
.major
,
175 revision
.rev
.minor
, revision
.rev
.revision
, revision
.rev
.bld_num
);
178 /* Check if the signature in the UPD header matches the expected one. If it doesn't match, the
179 FSP binaries in CBFS are for a different platform than the platform code trying to use it
180 in which case the function calls die(). */
181 void fsp_verify_upd_header_signature(uint64_t upd_signature
, uint64_t expected_signature
)
183 if (upd_signature
!= expected_signature
) {
184 /* The UPD signatures are non-zero-terminated ASCII stored as a little endian
185 uint64_t, so this needs some casts. */
186 die_with_post_code(POSTCODE_INVALID_VENDOR_BINARY
,
187 "Invalid UPD signature! FSP provided \"%.8s\", expected was \"%.8s\".\n",
188 (char *)&upd_signature
,
189 (char *)&expected_signature
);
193 /* Add FSP version to coreboot table LB_TAG_PLATFORM_BLOB_VERSION */
194 void lb_string_platform_blob_version(struct lb_header
*header
)
196 struct lb_string
*rec
;
198 char fsp_version
[FSP_VER_LEN
] = {0};
200 fsp_get_version(fsp_version
);
201 rec
= (struct lb_string
*)lb_new_record(header
);
202 rec
->tag
= LB_TAG_PLATFORM_BLOB_VERSION
;
203 len
= strlen(fsp_version
);
204 rec
->size
= ALIGN_UP(sizeof(*rec
) + len
+ 1, 8);
205 memcpy(rec
->string
, fsp_version
, len
+1);
208 __weak
void soc_validate_fspm_header(const struct fsp_header
*hdr
)