xref: /aosp_15_r20/external/coreboot/src/soc/intel/apollolake/cse.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <device/mmio.h>
4 #include <bootstate.h>
5 #include <commonlib/region.h>
6 #include <console/console.h>
7 #include <fmap.h>
8 #include <intelblocks/cse.h>
9 #include <intelblocks/p2sb.h>
10 #include <intelblocks/pcr.h>
11 #include <soc/cse.h>
12 #include <soc/heci.h>
13 #include <soc/iomap.h>
14 #include <soc/pcr_ids.h>
15 #include <soc/pci_devs.h>
16 #include <device/pci_ops.h>
17 #include <stdint.h>
18 
19 #define MKHI_GROUP_ID_MCA			0x0a
20 #define READ_FILE				0x02
21 #define   READ_FILE_FLAG_DEFAULT		(1 << 0)
22 #define   READ_FILE_FLAG_HASH			(1 << 1)
23 #define   READ_FILE_FLAG_EMULATED		(1 << 2)
24 #define   READ_FILE_FLAG_HW			(1 << 3)
25 
26 #define MCA_MAX_FILE_PATH_SIZE			64
27 
28 #define FUSE_LOCK_FILE				"/fpf/intel/SocCfgLock"
29 
30 /* Status values are made in such a way erase is not needed */
31 static enum fuse_flash_state {
32 	FUSE_FLASH_FUSED = 0xfc,
33 	FUSE_FLASH_UNFUSED = 0xfe,
34 	FUSE_FLASH_UNKNOWN = 0xff,
35 } g_fuse_state;
36 
37 #define FPF_STATUS_FMAP				"FPF_STATUS"
38 
39 /*
40  * Read file from CSE internal filesystem.
41  * size is maximum length of provided buffer buff, which is updated with actual
42  * size of the file read. flags indicate whether real file or fuse is used.
43  * Returns 1 on success and 0 otherwise.
44  */
read_cse_file(const char * path,void * buff,size_t * size,size_t offset,uint32_t flags)45 static int read_cse_file(const char *path, void *buff, size_t *size,
46 						size_t offset, uint32_t flags)
47 {
48 	size_t reply_size;
49 
50 	struct mca_command {
51 		struct mkhi_hdr hdr;
52 		char file_name[MCA_MAX_FILE_PATH_SIZE];
53 		uint32_t offset;
54 		uint32_t data_size;
55 		uint8_t flags;
56 	} __packed msg;
57 
58 	struct mca_response {
59 		struct mkhi_hdr hdr;
60 		uint32_t data_size;
61 		uint8_t buffer[128];
62 	} __packed rmsg;
63 
64 	if (sizeof(rmsg.buffer) < *size) {
65 		printk(BIOS_ERR, "internal buffer is too small\n");
66 		return 0;
67 	}
68 
69 	if (strnlen(path, sizeof(msg.file_name)) >= sizeof(msg.file_name)) {
70 		printk(BIOS_ERR, "path too big for msg.file_name buffer\n");
71 		return 0;
72 	}
73 	strncpy(msg.file_name, path, sizeof(msg.file_name));
74 	msg.hdr.group_id = MKHI_GROUP_ID_MCA;
75 	msg.hdr.command = READ_FILE;
76 	msg.flags = flags;
77 	msg.data_size = *size;
78 	msg.offset = offset;
79 
80 	reply_size = sizeof(rmsg);
81 
82 	if (heci_send_receive(&msg, sizeof(msg), &rmsg, &reply_size, HECI_MKHI_ADDR)) {
83 		printk(BIOS_ERR, "HECI: Failed to read file\n");
84 		return 0;
85 	}
86 
87 	if (rmsg.data_size > *size) {
88 		printk(BIOS_ERR, "reply is too large\n");
89 		return 0;
90 	}
91 
92 	memcpy(buff, rmsg.buffer, rmsg.data_size);
93 	*size = rmsg.data_size;
94 
95 	return 1;
96 }
97 
load_cached_fpf(struct region_device * rdev)98 static enum fuse_flash_state load_cached_fpf(struct region_device *rdev)
99 {
100 	enum fuse_flash_state state;
101 	uint8_t buff;
102 
103 	state = FUSE_FLASH_UNKNOWN;
104 
105 	if (rdev_readat(rdev, &buff, 0, sizeof(buff)) >= 0) {
106 		state = read8(&buff);
107 		return state;
108 	}
109 
110 	printk(BIOS_WARNING, "failed to load cached FPF value\n");
111 
112 	return state;
113 }
114 
115 static
save_fpf_state(enum fuse_flash_state state,struct region_device * rdev)116 int save_fpf_state(enum fuse_flash_state state, struct region_device *rdev)
117 {
118 	uint8_t buff;
119 
120 	write8(&buff, (uint8_t)state);
121 	return rdev_writeat(rdev, &buff, 0, sizeof(buff));
122 }
123 
fpf_blown(void * unused)124 static void fpf_blown(void *unused)
125 {
126 	uint8_t fuse;
127 	struct region_device rdev;
128 	size_t sz = sizeof(fuse);
129 	bool rdev_valid = false;
130 
131 	if (fmap_locate_area_as_rdev_rw(FPF_STATUS_FMAP, &rdev) == 0) {
132 		rdev_valid = true;
133 		g_fuse_state = load_cached_fpf(&rdev);
134 		if (g_fuse_state != FUSE_FLASH_UNKNOWN)
135 			return;
136 	}
137 
138 	if (!read_cse_file(FUSE_LOCK_FILE, &fuse, &sz, 0, READ_FILE_FLAG_HW))
139 		return;
140 
141 	g_fuse_state = fuse == 1 ? FUSE_FLASH_FUSED : FUSE_FLASH_UNFUSED;
142 
143 	if (rdev_valid && (save_fpf_state(g_fuse_state, &rdev) < 0))
144 		printk(BIOS_CRIT, "failed to save FPF state\n");
145 }
146 
dump_status(int index,int reg_addr)147 static uint32_t dump_status(int index, int reg_addr)
148 {
149 	uint32_t reg;
150 
151 	reg = me_read_config32(reg_addr);
152 
153 	printk(BIOS_DEBUG, "CSE FWSTS%d: 0x%08x\n", index, reg);
154 
155 	return reg;
156 }
157 
dump_cse_state(void)158 static void dump_cse_state(void)
159 {
160 	union cse_fwsts1 fwsts1;
161 	union cse_fwsts3 fwsts3;
162 	union cse_fwsts4 fwsts4;
163 	union cse_fwsts5 fwsts5;
164 	union cse_fwsts6 fwsts6;
165 
166 	if (!is_cse_enabled())
167 		return;
168 
169 	fwsts1.data = dump_status(1, PCI_ME_HFSTS1);
170 	dump_status(2, PCI_ME_HFSTS2);
171 	fwsts3.data = dump_status(3, PCI_ME_HFSTS3);
172 	fwsts4.data = dump_status(4, PCI_ME_HFSTS4);
173 	fwsts5.data = dump_status(5, PCI_ME_HFSTS5);
174 	fwsts6.data = dump_status(6, PCI_ME_HFSTS6);
175 
176 	printk(BIOS_DEBUG, "CSE: Working State          : %u\n",
177 		fwsts1.fields.working_state);
178 	printk(BIOS_DEBUG, "CSE: Manufacturing Mode     : %s\n",
179 		fwsts1.fields.mfg_mode ? "YES" : "NO");
180 	printk(BIOS_DEBUG, "CSE: Operation State        : %u\n",
181 		fwsts1.fields.operation_state);
182 	printk(BIOS_DEBUG, "CSE: FW Init Complete       : %s\n",
183 		fwsts1.fields.fw_init_complete ? "YES" : "NO");
184 	printk(BIOS_DEBUG, "CSE: Error Code             : %u\n",
185 		fwsts1.fields.error_code);
186 	printk(BIOS_DEBUG, "CSE: Operation Mode         : %u\n",
187 		fwsts1.fields.operation_mode);
188 	printk(BIOS_DEBUG, "CSE: IBB Verification Result: %s\n",
189 		fwsts3.fields.ibb_verif_result ? "PASS" : "FAIL");
190 	printk(BIOS_DEBUG, "CSE: IBB Verification Done  : %s\n",
191 		fwsts3.fields.ibb_verif_done ? "YES" : "NO");
192 	printk(BIOS_DEBUG, "CSE: Actual IBB Size        : %u\n",
193 		fwsts3.fields.ibb_size);
194 	printk(BIOS_DEBUG, "CSE: Verified Boot Valid    : %s\n",
195 		fwsts4.fields.txe_veri_boot_valid ? "PASS" : "FAIL");
196 	printk(BIOS_DEBUG, "CSE: Verified Boot Test     : %s\n",
197 		fwsts4.fields.txe_veri_boot_test ? "YES" : "NO");
198 	printk(BIOS_DEBUG, "CSE: FPF status             : %s\n",
199 		fwsts6.fields.fpf_commited ? "FUSED" : "UNFUSED");
200 	printk(BIOS_DEBUG, "CSE: Error Status Code      : %u\n",
201 		fwsts5.fields.error_status_code);
202 }
203 
204 #define PCR_PSFX_T0_SHDW_PCIEN		0x1C
205 #define PCR_PSFX_T0_SHDW_PCIEN_FUNDIS	(1 << 8)
206 
soc_disable_heci1_using_pcr(void)207 void soc_disable_heci1_using_pcr(void)
208 {
209 	pcr_or32(PID_PSF3, PSF3_BASE_ADDRESS + PCR_PSFX_T0_SHDW_PCIEN,
210 		 PCR_PSFX_T0_SHDW_PCIEN_FUNDIS);
211 }
212 
heci_cse_lockdown(void)213 void heci_cse_lockdown(void)
214 {
215 	dump_cse_state();
216 
217 	/*
218 	 * It is safe to disable HECI1 now since we won't be talking to the ME
219 	 * anymore.
220 	 */
221 	if (CONFIG(DISABLE_HECI1_AT_PRE_BOOT))
222 		heci1_disable();
223 }
224 
225 BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_ENTRY, fpf_blown, NULL);
226 BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, print_me_fw_version, NULL);
227