xref: /aosp_15_r20/external/vboot_reference/futility/platform_csme.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1*8617a60dSAndroid Build Coastguard Worker /* Copyright 2023 The ChromiumOS Authors
2*8617a60dSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
3*8617a60dSAndroid Build Coastguard Worker  * found in the LICENSE file.
4*8617a60dSAndroid Build Coastguard Worker  *
5*8617a60dSAndroid Build Coastguard Worker  * Utility functions for Intel Flash Descriptor (ifd) and the 'Converged
6*8617a60dSAndroid Build Coastguard Worker  * Security and Manageability Engine' (CSME).
7*8617a60dSAndroid Build Coastguard Worker  */
8*8617a60dSAndroid Build Coastguard Worker 
9*8617a60dSAndroid Build Coastguard Worker #include <string.h>
10*8617a60dSAndroid Build Coastguard Worker 
11*8617a60dSAndroid Build Coastguard Worker #include "cbfstool.h"
12*8617a60dSAndroid Build Coastguard Worker #include "platform_csme.h"
13*8617a60dSAndroid Build Coastguard Worker #include "updater.h"
14*8617a60dSAndroid Build Coastguard Worker 
15*8617a60dSAndroid Build Coastguard Worker /* Structure from coreboot util/ifdtool/ifdtool.h */
16*8617a60dSAndroid Build Coastguard Worker // flash descriptor
17*8617a60dSAndroid Build Coastguard Worker struct fdbar {
18*8617a60dSAndroid Build Coastguard Worker 	uint32_t flvalsig;
19*8617a60dSAndroid Build Coastguard Worker 	uint32_t flmap0;
20*8617a60dSAndroid Build Coastguard Worker 	uint32_t flmap1;
21*8617a60dSAndroid Build Coastguard Worker 	uint32_t flmap2;
22*8617a60dSAndroid Build Coastguard Worker 	uint32_t flmap3; // Exist for 500 series onwards
23*8617a60dSAndroid Build Coastguard Worker } __attribute__((packed));
24*8617a60dSAndroid Build Coastguard Worker 
25*8617a60dSAndroid Build Coastguard Worker // flash master
26*8617a60dSAndroid Build Coastguard Worker struct fmba {
27*8617a60dSAndroid Build Coastguard Worker 	uint32_t flmstr1;
28*8617a60dSAndroid Build Coastguard Worker 	uint32_t flmstr2;
29*8617a60dSAndroid Build Coastguard Worker 	uint32_t flmstr3;
30*8617a60dSAndroid Build Coastguard Worker 	uint32_t flmstr4;
31*8617a60dSAndroid Build Coastguard Worker 	uint32_t flmstr5;
32*8617a60dSAndroid Build Coastguard Worker 	uint32_t flmstr6;
33*8617a60dSAndroid Build Coastguard Worker } __attribute__((packed));
34*8617a60dSAndroid Build Coastguard Worker 
find_fmba(const struct firmware_image * image)35*8617a60dSAndroid Build Coastguard Worker static struct fmba * const find_fmba(const struct firmware_image *image) {
36*8617a60dSAndroid Build Coastguard Worker 	struct firmware_section section;
37*8617a60dSAndroid Build Coastguard Worker 	const uint32_t signature = 0x0FF0A55A;
38*8617a60dSAndroid Build Coastguard Worker 	const struct fdbar *fd;
39*8617a60dSAndroid Build Coastguard Worker 
40*8617a60dSAndroid Build Coastguard Worker 	if (!image->size)
41*8617a60dSAndroid Build Coastguard Worker 		return NULL;
42*8617a60dSAndroid Build Coastguard Worker 	if (find_firmware_section(&section, image, FMAP_SI_DESC))
43*8617a60dSAndroid Build Coastguard Worker 		return NULL;
44*8617a60dSAndroid Build Coastguard Worker 
45*8617a60dSAndroid Build Coastguard Worker 	if (section.size < sizeof(*fd) + sizeof(struct fmba))
46*8617a60dSAndroid Build Coastguard Worker 		return NULL;
47*8617a60dSAndroid Build Coastguard Worker 	fd = memmem(section.data, section.size - sizeof(*fd),
48*8617a60dSAndroid Build Coastguard Worker 		    (const void *)&signature, sizeof(signature));
49*8617a60dSAndroid Build Coastguard Worker 	if (!fd)
50*8617a60dSAndroid Build Coastguard Worker 		return NULL;
51*8617a60dSAndroid Build Coastguard Worker 
52*8617a60dSAndroid Build Coastguard Worker 	const uint64_t offset = (fd->flmap1 & 0xff) << 4;
53*8617a60dSAndroid Build Coastguard Worker 	if (offset + sizeof(struct fmba) > section.size)
54*8617a60dSAndroid Build Coastguard Worker 		return NULL;
55*8617a60dSAndroid Build Coastguard Worker 
56*8617a60dSAndroid Build Coastguard Worker 	return (struct fmba * const)(section.data + offset);
57*8617a60dSAndroid Build Coastguard Worker }
58*8617a60dSAndroid Build Coastguard Worker 
is_flmstr1_locked(const struct fmba * const fmba)59*8617a60dSAndroid Build Coastguard Worker static bool is_flmstr1_locked(const struct fmba * const fmba)
60*8617a60dSAndroid Build Coastguard Worker {
61*8617a60dSAndroid Build Coastguard Worker 	/*
62*8617a60dSAndroid Build Coastguard Worker 	 * (from idftool.c) There are multiple versions of IFD but there are no
63*8617a60dSAndroid Build Coastguard Worker 	 * version tags in the descriptor. Starting from Apollolake all
64*8617a60dSAndroid Build Coastguard Worker 	 * Chromebooks should be using IFD v2 so we'll check only the v2 values.
65*8617a60dSAndroid Build Coastguard Worker 	 * V2: unlocked FLMSTR is 0xfffffff?? (31:20=write, 19:8=read)
66*8617a60dSAndroid Build Coastguard Worker 	 */
67*8617a60dSAndroid Build Coastguard Worker 	const bool is_locked = (fmba->flmstr1 & 0xfff00000) != 0xfff00000;
68*8617a60dSAndroid Build Coastguard Worker 	VB2_DEBUG("FLMSTR1 = %#08x (%s)\n", fmba->flmstr1, is_locked ? "LOCKED" : "unlocked");
69*8617a60dSAndroid Build Coastguard Worker 
70*8617a60dSAndroid Build Coastguard Worker 	return is_locked;
71*8617a60dSAndroid Build Coastguard Worker }
72*8617a60dSAndroid Build Coastguard Worker 
is_flash_descriptor_locked(const struct firmware_image * image)73*8617a60dSAndroid Build Coastguard Worker bool is_flash_descriptor_locked(const struct firmware_image *image)
74*8617a60dSAndroid Build Coastguard Worker {
75*8617a60dSAndroid Build Coastguard Worker 	/*
76*8617a60dSAndroid Build Coastguard Worker 	 * TODO(roccochen) When the flashrom supports exporting FRAP,
77*8617a60dSAndroid Build Coastguard Worker 	 * we can replace the parsing of FLMSTRs to rely on FRAP for deciding if
78*8617a60dSAndroid Build Coastguard Worker 	 * AP RO is locked or not.
79*8617a60dSAndroid Build Coastguard Worker 	 */
80*8617a60dSAndroid Build Coastguard Worker 	const struct fmba *fmba = find_fmba(image);
81*8617a60dSAndroid Build Coastguard Worker 	if (!fmba) {
82*8617a60dSAndroid Build Coastguard Worker 		WARN("Failed to find flash master. Assuming unlocked.\n");
83*8617a60dSAndroid Build Coastguard Worker 		return false;
84*8617a60dSAndroid Build Coastguard Worker 	}
85*8617a60dSAndroid Build Coastguard Worker 	return is_flmstr1_locked(fmba);
86*8617a60dSAndroid Build Coastguard Worker }
87*8617a60dSAndroid Build Coastguard Worker 
88*8617a60dSAndroid Build Coastguard Worker /*
89*8617a60dSAndroid Build Coastguard Worker  * Unlock the flash descriptor by rewriting the FLMSTR1.
90*8617a60dSAndroid Build Coastguard Worker  *
91*8617a60dSAndroid Build Coastguard Worker  * Returns 0 on success, any other values for failure.
92*8617a60dSAndroid Build Coastguard Worker  */
unlock_flmstrs(struct firmware_image * image,uint32_t flmstr1,uint32_t flmstr2,uint32_t flmstr3)93*8617a60dSAndroid Build Coastguard Worker static int unlock_flmstrs(struct firmware_image *image,
94*8617a60dSAndroid Build Coastguard Worker 			  uint32_t flmstr1, uint32_t flmstr2, uint32_t flmstr3)
95*8617a60dSAndroid Build Coastguard Worker {
96*8617a60dSAndroid Build Coastguard Worker 	struct fmba * const fmba = find_fmba(image);
97*8617a60dSAndroid Build Coastguard Worker 
98*8617a60dSAndroid Build Coastguard Worker 	if (!fmba) {
99*8617a60dSAndroid Build Coastguard Worker 		ERROR("Failed to unlock the Flash Master values.\n");
100*8617a60dSAndroid Build Coastguard Worker 		return -1;
101*8617a60dSAndroid Build Coastguard Worker 	}
102*8617a60dSAndroid Build Coastguard Worker 
103*8617a60dSAndroid Build Coastguard Worker 	if (fmba->flmstr1 == flmstr1 &&
104*8617a60dSAndroid Build Coastguard Worker 	    fmba->flmstr2 == flmstr2 &&
105*8617a60dSAndroid Build Coastguard Worker 	    fmba->flmstr3 == flmstr3) {
106*8617a60dSAndroid Build Coastguard Worker 		VB2_DEBUG("No need to change the Flash Master values.\n");
107*8617a60dSAndroid Build Coastguard Worker 		return 0;
108*8617a60dSAndroid Build Coastguard Worker 	}
109*8617a60dSAndroid Build Coastguard Worker 	VB2_DEBUG("Change flmstr1=%#08x->%#08x\n", fmba->flmstr1, flmstr1);
110*8617a60dSAndroid Build Coastguard Worker 	VB2_DEBUG("Change flmstr2=%#08x->%#08x\n", fmba->flmstr2, flmstr2);
111*8617a60dSAndroid Build Coastguard Worker 	VB2_DEBUG("Change flmstr3=%#08x->%#08x\n", fmba->flmstr3, flmstr3);
112*8617a60dSAndroid Build Coastguard Worker 
113*8617a60dSAndroid Build Coastguard Worker 	fmba->flmstr1 = flmstr1;
114*8617a60dSAndroid Build Coastguard Worker 	fmba->flmstr2 = flmstr2;
115*8617a60dSAndroid Build Coastguard Worker 	fmba->flmstr3 = flmstr3;
116*8617a60dSAndroid Build Coastguard Worker 	INFO("Changed Flash Master values to unlocked.\n");
117*8617a60dSAndroid Build Coastguard Worker 	return 0;
118*8617a60dSAndroid Build Coastguard Worker }
119*8617a60dSAndroid Build Coastguard Worker 
120*8617a60dSAndroid Build Coastguard Worker /*
121*8617a60dSAndroid Build Coastguard Worker  * Unlock the flash descriptor for Skylake and Kabylake platforms.
122*8617a60dSAndroid Build Coastguard Worker  *
123*8617a60dSAndroid Build Coastguard Worker  * The FLMSTR settings are dedicated for the Skylake (glados) and Kabylake (eve)
124*8617a60dSAndroid Build Coastguard Worker  * platforms, and are slightly different to those in the common
125*8617a60dSAndroid Build Coastguard Worker  * unlock_flash_master() function. The common settings might work, but we keep
126*8617a60dSAndroid Build Coastguard Worker  * these as is for now to avoid breaking things on old devices. These settings
127*8617a60dSAndroid Build Coastguard Worker  * are also hardcoded in postinst scripts (e.g. https://crrev.com/i/252522), so
128*8617a60dSAndroid Build Coastguard Worker  * those would probably need to be changed too.
129*8617a60dSAndroid Build Coastguard Worker  */
unlock_csme_eve(struct firmware_image * image)130*8617a60dSAndroid Build Coastguard Worker int unlock_csme_eve(struct firmware_image *image)
131*8617a60dSAndroid Build Coastguard Worker {
132*8617a60dSAndroid Build Coastguard Worker 	return unlock_flmstrs(image, 0xffffff00, 0xffffff00, 0xffffff00);
133*8617a60dSAndroid Build Coastguard Worker }
134*8617a60dSAndroid Build Coastguard Worker 
135*8617a60dSAndroid Build Coastguard Worker /*
136*8617a60dSAndroid Build Coastguard Worker  * Determine the platform to pass to ifdtool (e.g. 'adl') by extracting
137*8617a60dSAndroid Build Coastguard Worker  * CONFIG_IFD_CHIPSET from the config file in CBFS. However, old nissa firmware
138*8617a60dSAndroid Build Coastguard Worker  * may not have all config fields in the CBFS file, so fall back to a hack of
139*8617a60dSAndroid Build Coastguard Worker  * checking for 'nissa' in the descriptor file path.
140*8617a60dSAndroid Build Coastguard Worker  *
141*8617a60dSAndroid Build Coastguard Worker  * On success, returns the platform, which must be freed by the caller.
142*8617a60dSAndroid Build Coastguard Worker  * On failure, returns NULL.
143*8617a60dSAndroid Build Coastguard Worker  */
determine_ifd_platform(const char * image_path)144*8617a60dSAndroid Build Coastguard Worker static char *determine_ifd_platform(const char *image_path)
145*8617a60dSAndroid Build Coastguard Worker {
146*8617a60dSAndroid Build Coastguard Worker 	char *platform;
147*8617a60dSAndroid Build Coastguard Worker 	char *ifd_path;
148*8617a60dSAndroid Build Coastguard Worker 
149*8617a60dSAndroid Build Coastguard Worker 	cbfstool_get_config_string(image_path, NULL, "CONFIG_IFD_CHIPSET", &platform);
150*8617a60dSAndroid Build Coastguard Worker 	if (platform)
151*8617a60dSAndroid Build Coastguard Worker 		return platform;
152*8617a60dSAndroid Build Coastguard Worker 
153*8617a60dSAndroid Build Coastguard Worker 	/* Fall back to checking for nissa in the descriptor file path */
154*8617a60dSAndroid Build Coastguard Worker 	cbfstool_get_config_string(image_path, NULL, "CONFIG_IFD_BIN_PATH", &ifd_path);
155*8617a60dSAndroid Build Coastguard Worker 	if (ifd_path && strstr(ifd_path, "/nissa/")) {
156*8617a60dSAndroid Build Coastguard Worker 		VB2_DEBUG("Use platform 'adl' since descriptor path contains 'nissa'\n");
157*8617a60dSAndroid Build Coastguard Worker 		ASPRINTF(&platform, "adl");
158*8617a60dSAndroid Build Coastguard Worker 	}
159*8617a60dSAndroid Build Coastguard Worker 
160*8617a60dSAndroid Build Coastguard Worker 	if (ifd_path)
161*8617a60dSAndroid Build Coastguard Worker 		free(ifd_path);
162*8617a60dSAndroid Build Coastguard Worker 
163*8617a60dSAndroid Build Coastguard Worker 	return platform;
164*8617a60dSAndroid Build Coastguard Worker }
165*8617a60dSAndroid Build Coastguard Worker 
166*8617a60dSAndroid Build Coastguard Worker /*
167*8617a60dSAndroid Build Coastguard Worker  * Run ifdtool with the given options.
168*8617a60dSAndroid Build Coastguard Worker  *
169*8617a60dSAndroid Build Coastguard Worker  * Returns 0 on success, otherwise failure.
170*8617a60dSAndroid Build Coastguard Worker  */
run_ifdtool(const char * image_path,char * platform,const char * extra_options)171*8617a60dSAndroid Build Coastguard Worker static int run_ifdtool(const char *image_path, char *platform, const char *extra_options)
172*8617a60dSAndroid Build Coastguard Worker {
173*8617a60dSAndroid Build Coastguard Worker 	char *command;
174*8617a60dSAndroid Build Coastguard Worker 	int ret = 0;
175*8617a60dSAndroid Build Coastguard Worker 
176*8617a60dSAndroid Build Coastguard Worker 	ASPRINTF(&command, "ifdtool -p \"%s\" -O \"%s\" \"%s\" %s 2>&1",
177*8617a60dSAndroid Build Coastguard Worker 		 platform, image_path, image_path, extra_options);
178*8617a60dSAndroid Build Coastguard Worker 	if (system(command)) {
179*8617a60dSAndroid Build Coastguard Worker 		ERROR("Failed to run: %s\n", command);
180*8617a60dSAndroid Build Coastguard Worker 		ret = -1;
181*8617a60dSAndroid Build Coastguard Worker 	}
182*8617a60dSAndroid Build Coastguard Worker 
183*8617a60dSAndroid Build Coastguard Worker 	free(command);
184*8617a60dSAndroid Build Coastguard Worker 	return ret;
185*8617a60dSAndroid Build Coastguard Worker }
186*8617a60dSAndroid Build Coastguard Worker 
187*8617a60dSAndroid Build Coastguard Worker /*
188*8617a60dSAndroid Build Coastguard Worker  * Unlock the CSME for recent Intel platforms (CML onwards).
189*8617a60dSAndroid Build Coastguard Worker  *
190*8617a60dSAndroid Build Coastguard Worker  * This allows the SI_DESC and SI_ME regions to be updated.
191*8617a60dSAndroid Build Coastguard Worker  *
192*8617a60dSAndroid Build Coastguard Worker  * Returns 0 on success, otherwise failure.
193*8617a60dSAndroid Build Coastguard Worker  */
unlock_csme(struct updater_config * cfg)194*8617a60dSAndroid Build Coastguard Worker int unlock_csme(struct updater_config *cfg)
195*8617a60dSAndroid Build Coastguard Worker {
196*8617a60dSAndroid Build Coastguard Worker 	const char *temp_path;
197*8617a60dSAndroid Build Coastguard Worker 	char *platform;
198*8617a60dSAndroid Build Coastguard Worker 	int ret = -1;
199*8617a60dSAndroid Build Coastguard Worker 
200*8617a60dSAndroid Build Coastguard Worker 	temp_path = get_firmware_image_temp_file(&cfg->image, &cfg->tempfiles);
201*8617a60dSAndroid Build Coastguard Worker 	if (!temp_path) {
202*8617a60dSAndroid Build Coastguard Worker 		ERROR("Failed to get image temp file\n");
203*8617a60dSAndroid Build Coastguard Worker 		return ret;
204*8617a60dSAndroid Build Coastguard Worker 	}
205*8617a60dSAndroid Build Coastguard Worker 
206*8617a60dSAndroid Build Coastguard Worker 	platform = determine_ifd_platform(temp_path);
207*8617a60dSAndroid Build Coastguard Worker 	if (!platform) {
208*8617a60dSAndroid Build Coastguard Worker 		ERROR("Failed to determine IFD platform\n");
209*8617a60dSAndroid Build Coastguard Worker 		return ret;
210*8617a60dSAndroid Build Coastguard Worker 	}
211*8617a60dSAndroid Build Coastguard Worker 
212*8617a60dSAndroid Build Coastguard Worker 	VB2_DEBUG("Using platform '%s'\n", platform);
213*8617a60dSAndroid Build Coastguard Worker 
214*8617a60dSAndroid Build Coastguard Worker 	/* Unlock FMLSTRs */
215*8617a60dSAndroid Build Coastguard Worker 	if (run_ifdtool(temp_path, platform, "-u")) {
216*8617a60dSAndroid Build Coastguard Worker 		ERROR("Failed to unlock FLMSTRs\n");
217*8617a60dSAndroid Build Coastguard Worker 		goto cleanup;
218*8617a60dSAndroid Build Coastguard Worker 	}
219*8617a60dSAndroid Build Coastguard Worker 
220*8617a60dSAndroid Build Coastguard Worker 	/*
221*8617a60dSAndroid Build Coastguard Worker 	 * Disable GPR0 (Global Protected Range). When enabled, it provides
222*8617a60dSAndroid Build Coastguard Worker 	 * write-protection to part of the SI_ME region, specifically CSE_RO and
223*8617a60dSAndroid Build Coastguard Worker 	 * part of CSE_DATA, so it must be disabled to allow updating SI_ME.
224*8617a60dSAndroid Build Coastguard Worker 	 */
225*8617a60dSAndroid Build Coastguard Worker 	if (run_ifdtool(temp_path, platform, "-g")) {
226*8617a60dSAndroid Build Coastguard Worker 		ERROR("Failed to disable GPR0\n");
227*8617a60dSAndroid Build Coastguard Worker 		goto cleanup;
228*8617a60dSAndroid Build Coastguard Worker 	}
229*8617a60dSAndroid Build Coastguard Worker 
230*8617a60dSAndroid Build Coastguard Worker 	if (reload_firmware_image(temp_path, &cfg->image)) {
231*8617a60dSAndroid Build Coastguard Worker 		ERROR("Failed to reload firmware image\n");
232*8617a60dSAndroid Build Coastguard Worker 		goto cleanup;
233*8617a60dSAndroid Build Coastguard Worker 	}
234*8617a60dSAndroid Build Coastguard Worker 
235*8617a60dSAndroid Build Coastguard Worker 	/* Double check the descriptor was actually unlocked */
236*8617a60dSAndroid Build Coastguard Worker 	if (is_flash_descriptor_locked(&cfg->image)) {
237*8617a60dSAndroid Build Coastguard Worker 		ERROR("Descriptor is still locked after running ifdtool\n");
238*8617a60dSAndroid Build Coastguard Worker 		goto cleanup;
239*8617a60dSAndroid Build Coastguard Worker 	}
240*8617a60dSAndroid Build Coastguard Worker 
241*8617a60dSAndroid Build Coastguard Worker 	INFO("Unlocked Intel ME on platform '%s'\n", platform);
242*8617a60dSAndroid Build Coastguard Worker 	ret = 0;
243*8617a60dSAndroid Build Coastguard Worker 
244*8617a60dSAndroid Build Coastguard Worker cleanup:
245*8617a60dSAndroid Build Coastguard Worker 	free(platform);
246*8617a60dSAndroid Build Coastguard Worker 
247*8617a60dSAndroid Build Coastguard Worker 	return ret;
248*8617a60dSAndroid Build Coastguard Worker }
249