xref: /aosp_15_r20/external/coreboot/src/drivers/intel/fsp2_0/util.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <boot/coreboot_tables.h>
4 #include <device/mmio.h>
5 #include <cbfs.h>
6 #include <cf9_reset.h>
7 #include <commonlib/bsd/compression.h>
8 #include <commonlib/fsp.h>
9 #include <console/console.h>
10 #include <fsp/util.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <types.h>
14 #include <assert.h>
15 
fsp_hdr_get_expected_min_length(void)16 static uint32_t fsp_hdr_get_expected_min_length(void)
17 {
18 	if (CONFIG(PLATFORM_USES_FSP2_3))
19 		return 80;
20 	else if (CONFIG(PLATFORM_USES_FSP2_2))
21 		return 76;
22 	else if (CONFIG(PLATFORM_USES_FSP2_1))
23 		return 72;
24 	else if (CONFIG(PLATFORM_USES_FSP2_0))
25 		return 72;
26 	else
27 		return dead_code_t(uint32_t);
28 }
29 
looks_like_fsp_header(struct fsp_header * hdr)30 static bool looks_like_fsp_header(struct fsp_header *hdr)
31 {
32 	if (memcmp(&hdr->signature, FSP_HDR_SIGNATURE, 4)) {
33 		printk(BIOS_ALERT, "Did not find a valid FSP signature\n");
34 		return false;
35 	}
36 
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);
43 		return false;
44 	}
45 
46 	return true;
47 }
48 
fsp_identify(struct fsp_header * hdr,const void * fsp_blob)49 enum cb_err fsp_identify(struct fsp_header *hdr, const void *fsp_blob)
50 {
51 	memcpy(hdr, fsp_blob, sizeof(struct fsp_header));
52 	if (!looks_like_fsp_header(hdr))
53 		return CB_ERR;
54 
55 	return CB_SUCCESS;
56 }
57 
fsp_validate_component(struct fsp_header * hdr,void * fsp_file,size_t file_size)58 enum cb_err fsp_validate_component(struct fsp_header *hdr, void *fsp_file, size_t file_size)
59 {
60 	void *raw_hdr = fsp_file + FSP_HDR_OFFSET;
61 
62 	if (file_size < FSP_HDR_OFFSET + fsp_hdr_get_expected_min_length()) {
63 		printk(BIOS_CRIT, "FSP blob too small.\n");
64 		return CB_ERR;
65 	}
66 
67 	if (fsp_identify(hdr, raw_hdr) != CB_SUCCESS) {
68 		printk(BIOS_CRIT, "No valid FSP header\n");
69 		return CB_ERR;
70 	}
71 
72 	if (CONFIG(DISPLAY_FSP_HEADER))
73 		fsp_print_header_info(hdr);
74 
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");
78 		return CB_ERR;
79 	}
80 
81 	if (ENV_RAMINIT)
82 		soc_validate_fspm_header(hdr);
83 
84 	return CB_SUCCESS;
85 }
86 
fsp_reset_requested(efi_return_status_t status)87 static bool fsp_reset_requested(efi_return_status_t status)
88 {
89 	return (status >= FSP_STATUS_RESET_REQUIRED_COLD &&
90 		status <= FSP_STATUS_RESET_REQUIRED_8);
91 }
92 
fsp_handle_reset(efi_return_status_t status)93 void fsp_handle_reset(efi_return_status_t status)
94 {
95 	if (!fsp_reset_requested(status))
96 		return;
97 
98 	fsp_printk(status, BIOS_SPEW, "FSP: handling reset type");
99 
100 	switch (status) {
101 	case FSP_STATUS_RESET_REQUIRED_COLD:
102 		full_reset();
103 		break;
104 	case FSP_STATUS_RESET_REQUIRED_WARM:
105 		system_reset();
106 		break;
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);
114 		break;
115 	default:
116 		break;
117 	}
118 }
119 
fspm_env(void)120 static inline bool fspm_env(void)
121 {
122 	if (ENV_RAMINIT)
123 		return true;
124 	return false;
125 }
126 
fspm_xip(void)127 static inline bool fspm_xip(void)
128 {
129 	/* FSP-M is assumed to be loaded in romstage. */
130 	if (fspm_env() && CONFIG(FSP_M_XIP))
131 		return true;
132 	return false;
133 }
134 
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. */
fsp_load_component(struct fsp_load_descriptor * fspld,struct fsp_header * hdr)137 enum cb_err fsp_load_component(struct fsp_load_descriptor *fspld, struct fsp_header *hdr)
138 {
139 	size_t output_size;
140 	void *dest;
141 	struct prog *fsp_prog = &fspld->fsp_prog;
142 
143 	dest = cbfs_alloc(prog_name(fsp_prog), fspld->alloc, fspld, &output_size);
144 	if (!dest)
145 		return CB_ERR;
146 
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");
150 		return CB_ERR;
151 	}
152 
153 	prog_set_area(fsp_prog, dest, output_size);
154 
155 	if (fsp_validate_component(hdr, dest, output_size) != CB_SUCCESS) {
156 		printk(BIOS_ERR, "Invalid FSP header after load!\n");
157 		return CB_ERR;
158 	}
159 
160 	/* Signal that FSP component has been loaded. */
161 	prog_segment_loaded(hdr->image_base, hdr->image_size, SEG_FINAL);
162 
163 	return CB_SUCCESS;
164 }
165 
166 /* Only call this function when FSP header has been read and validated */
fsp_get_version(char * buf)167 void fsp_get_version(char *buf)
168 {
169 	struct fsp_header *hdr = &fsps_hdr;
170 	union fsp_revision revision;
171 
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);
176 }
177 
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(). */
fsp_verify_upd_header_signature(uint64_t upd_signature,uint64_t expected_signature)181 void fsp_verify_upd_header_signature(uint64_t upd_signature, uint64_t expected_signature)
182 {
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);
190 	}
191 }
192 
193 /* Add FSP version to coreboot table LB_TAG_PLATFORM_BLOB_VERSION */
lb_string_platform_blob_version(struct lb_header * header)194 void lb_string_platform_blob_version(struct lb_header *header)
195 {
196 	struct lb_string *rec;
197 	size_t len;
198 	char fsp_version[FSP_VER_LEN] = {0};
199 
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);
206 }
207 
soc_validate_fspm_header(const struct fsp_header * hdr)208 __weak void soc_validate_fspm_header(const struct fsp_header *hdr)
209 {
210 }
211