1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2022 Intel Corporation. */
3
4 #include <linux/firmware.h>
5 #include <asm/cpu.h>
6 #include <linux/slab.h>
7 #include <asm/microcode_intel.h>
8
9 #include "ifs.h"
10
11 struct ifs_header {
12 u32 header_ver;
13 u32 blob_revision;
14 u32 date;
15 u32 processor_sig;
16 u32 check_sum;
17 u32 loader_rev;
18 u32 processor_flags;
19 u32 metadata_size;
20 u32 total_size;
21 u32 fusa_info;
22 u64 reserved;
23 };
24
25 #define IFS_HEADER_SIZE (sizeof(struct ifs_header))
26 static struct ifs_header *ifs_header_ptr; /* pointer to the ifs image header */
27 static u64 ifs_hash_ptr; /* Address of ifs metadata (hash) */
28 static u64 ifs_test_image_ptr; /* 256B aligned address of test pattern */
29 static DECLARE_COMPLETION(ifs_done);
30
31 static const char * const scan_hash_status[] = {
32 [0] = "No error reported",
33 [1] = "Attempt to copy scan hashes when copy already in progress",
34 [2] = "Secure Memory not set up correctly",
35 [3] = "FuSaInfo.ProgramID does not match or ff-mm-ss does not match",
36 [4] = "Reserved",
37 [5] = "Integrity check failed",
38 [6] = "Scan reload or test is in progress"
39 };
40
41 static const char * const scan_authentication_status[] = {
42 [0] = "No error reported",
43 [1] = "Attempt to authenticate a chunk which is already marked as authentic",
44 [2] = "Chunk authentication error. The hash of chunk did not match expected value"
45 };
46
47 /*
48 * To copy scan hashes and authenticate test chunks, the initiating cpu must point
49 * to the EDX:EAX to the test image in linear address.
50 * Run wrmsr(MSR_COPY_SCAN_HASHES) for scan hash copy and run wrmsr(MSR_AUTHENTICATE_AND_COPY_CHUNK)
51 * for scan hash copy and test chunk authentication.
52 */
copy_hashes_authenticate_chunks(struct work_struct * work)53 static void copy_hashes_authenticate_chunks(struct work_struct *work)
54 {
55 struct ifs_work *local_work = container_of(work, struct ifs_work, w);
56 union ifs_scan_hashes_status hashes_status;
57 union ifs_chunks_auth_status chunk_status;
58 struct device *dev = local_work->dev;
59 int i, num_chunks, chunk_size;
60 struct ifs_data *ifsd;
61 u64 linear_addr, base;
62 u32 err_code;
63
64 ifsd = ifs_get_data(dev);
65 /* run scan hash copy */
66 wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr);
67 rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data);
68
69 /* enumerate the scan image information */
70 num_chunks = hashes_status.num_chunks;
71 chunk_size = hashes_status.chunk_size * 1024;
72 err_code = hashes_status.error_code;
73
74 if (!hashes_status.valid) {
75 ifsd->loading_error = true;
76 if (err_code >= ARRAY_SIZE(scan_hash_status)) {
77 dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code);
78 goto done;
79 }
80 dev_err(dev, "Hash copy error : %s", scan_hash_status[err_code]);
81 goto done;
82 }
83
84 /* base linear address to the scan data */
85 base = ifs_test_image_ptr;
86
87 /* scan data authentication and copy chunks to secured memory */
88 for (i = 0; i < num_chunks; i++) {
89 linear_addr = base + i * chunk_size;
90 linear_addr |= i;
91
92 wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, linear_addr);
93 rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
94
95 ifsd->valid_chunks = chunk_status.valid_chunks;
96 err_code = chunk_status.error_code;
97
98 if (err_code) {
99 ifsd->loading_error = true;
100 if (err_code >= ARRAY_SIZE(scan_authentication_status)) {
101 dev_err(dev,
102 "invalid error code 0x%x for authentication\n", err_code);
103 goto done;
104 }
105 dev_err(dev, "Chunk authentication error %s\n",
106 scan_authentication_status[err_code]);
107 goto done;
108 }
109 }
110 done:
111 complete(&ifs_done);
112 }
113
114 /*
115 * IFS requires scan chunks authenticated per each socket in the platform.
116 * Once the test chunk is authenticated, it is automatically copied to secured memory
117 * and proceed the authentication for the next chunk.
118 */
scan_chunks_sanity_check(struct device * dev)119 static int scan_chunks_sanity_check(struct device *dev)
120 {
121 int metadata_size, curr_pkg, cpu, ret = -ENOMEM;
122 struct ifs_data *ifsd = ifs_get_data(dev);
123 bool *package_authenticated;
124 struct ifs_work local_work;
125 char *test_ptr;
126
127 package_authenticated = kcalloc(topology_max_packages(), sizeof(bool), GFP_KERNEL);
128 if (!package_authenticated)
129 return ret;
130
131 metadata_size = ifs_header_ptr->metadata_size;
132
133 /* Spec says that if the Meta Data Size = 0 then it should be treated as 2000 */
134 if (metadata_size == 0)
135 metadata_size = 2000;
136
137 /* Scan chunk start must be 256 byte aligned */
138 if ((metadata_size + IFS_HEADER_SIZE) % 256) {
139 dev_err(dev, "Scan pattern offset within the binary is not 256 byte aligned\n");
140 return -EINVAL;
141 }
142
143 test_ptr = (char *)ifs_header_ptr + IFS_HEADER_SIZE + metadata_size;
144 ifsd->loading_error = false;
145
146 ifs_test_image_ptr = (u64)test_ptr;
147 ifsd->loaded_version = ifs_header_ptr->blob_revision;
148
149 /* copy the scan hash and authenticate per package */
150 cpus_read_lock();
151 for_each_online_cpu(cpu) {
152 curr_pkg = topology_physical_package_id(cpu);
153 if (package_authenticated[curr_pkg])
154 continue;
155 reinit_completion(&ifs_done);
156 local_work.dev = dev;
157 INIT_WORK(&local_work.w, copy_hashes_authenticate_chunks);
158 schedule_work_on(cpu, &local_work.w);
159 wait_for_completion(&ifs_done);
160 if (ifsd->loading_error)
161 goto out;
162 package_authenticated[curr_pkg] = 1;
163 }
164 ret = 0;
165 out:
166 cpus_read_unlock();
167 kfree(package_authenticated);
168
169 return ret;
170 }
171
ifs_sanity_check(struct device * dev,const struct microcode_header_intel * mc_header)172 static int ifs_sanity_check(struct device *dev,
173 const struct microcode_header_intel *mc_header)
174 {
175 unsigned long total_size, data_size;
176 u32 sum, *mc;
177
178 total_size = get_totalsize(mc_header);
179 data_size = get_datasize(mc_header);
180
181 if ((data_size + MC_HEADER_SIZE > total_size) || (total_size % sizeof(u32))) {
182 dev_err(dev, "bad ifs data file size.\n");
183 return -EINVAL;
184 }
185
186 if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
187 dev_err(dev, "invalid/unknown ifs update format.\n");
188 return -EINVAL;
189 }
190
191 mc = (u32 *)mc_header;
192 sum = 0;
193 for (int i = 0; i < total_size / sizeof(u32); i++)
194 sum += mc[i];
195
196 if (sum) {
197 dev_err(dev, "bad ifs data checksum, aborting.\n");
198 return -EINVAL;
199 }
200
201 return 0;
202 }
203
find_ifs_matching_signature(struct device * dev,struct ucode_cpu_info * uci,const struct microcode_header_intel * shdr)204 static bool find_ifs_matching_signature(struct device *dev, struct ucode_cpu_info *uci,
205 const struct microcode_header_intel *shdr)
206 {
207 unsigned int mc_size;
208
209 mc_size = get_totalsize(shdr);
210
211 if (!mc_size || ifs_sanity_check(dev, shdr) < 0) {
212 dev_err(dev, "ifs sanity check failure\n");
213 return false;
214 }
215
216 if (!intel_cpu_signatures_match(uci->cpu_sig.sig, uci->cpu_sig.pf, shdr->sig, shdr->pf)) {
217 dev_err(dev, "ifs signature, pf not matching\n");
218 return false;
219 }
220
221 return true;
222 }
223
ifs_image_sanity_check(struct device * dev,const struct microcode_header_intel * data)224 static bool ifs_image_sanity_check(struct device *dev, const struct microcode_header_intel *data)
225 {
226 struct ucode_cpu_info uci;
227
228 intel_cpu_collect_info(&uci);
229
230 return find_ifs_matching_signature(dev, &uci, data);
231 }
232
233 /*
234 * Load ifs image. Before loading ifs module, the ifs image must be located
235 * in /lib/firmware/intel/ifs and named as {family/model/stepping}.{testname}.
236 */
ifs_load_firmware(struct device * dev)237 void ifs_load_firmware(struct device *dev)
238 {
239 struct ifs_data *ifsd = ifs_get_data(dev);
240 const struct firmware *fw;
241 char scan_path[32];
242 int ret;
243
244 snprintf(scan_path, sizeof(scan_path), "intel/ifs/%02x-%02x-%02x.scan",
245 boot_cpu_data.x86, boot_cpu_data.x86_model, boot_cpu_data.x86_stepping);
246
247 ret = request_firmware_direct(&fw, scan_path, dev);
248 if (ret) {
249 dev_err(dev, "ifs file %s load failed\n", scan_path);
250 goto done;
251 }
252
253 if (!ifs_image_sanity_check(dev, (struct microcode_header_intel *)fw->data)) {
254 dev_err(dev, "ifs header sanity check failed\n");
255 goto release;
256 }
257
258 ifs_header_ptr = (struct ifs_header *)fw->data;
259 ifs_hash_ptr = (u64)(ifs_header_ptr + 1);
260
261 ret = scan_chunks_sanity_check(dev);
262 release:
263 release_firmware(fw);
264 done:
265 ifsd->loaded = (ret == 0);
266 }
267