Merge tag 'pci-v6.7-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci
[linux-2.6-microblaze.git] / drivers / platform / x86 / intel / ifs / load.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2022 Intel Corporation. */
3
4 #include <linux/firmware.h>
5 #include <linux/sizes.h>
6 #include <asm/cpu.h>
7 #include <asm/microcode.h>
8
9 #include "ifs.h"
10
11 #define IFS_CHUNK_ALIGNMENT     256
12 union meta_data {
13         struct {
14                 u32 meta_type;          // metadata type
15                 u32 meta_size;          // size of this entire struct including hdrs.
16                 u32 test_type;          // IFS test type
17                 u32 fusa_info;          // Fusa info
18                 u32 total_images;       // Total number of images
19                 u32 current_image;      // Current Image #
20                 u32 total_chunks;       // Total number of chunks in this image
21                 u32 starting_chunk;     // Starting chunk number in this image
22                 u32 size_per_chunk;     // size of each chunk
23                 u32 chunks_per_stride;  // number of chunks in a stride
24         };
25         u8 padding[IFS_CHUNK_ALIGNMENT];
26 };
27
28 #define IFS_HEADER_SIZE (sizeof(struct microcode_header_intel))
29 #define META_TYPE_IFS   1
30 #define INVALIDATE_STRIDE       0x1UL
31 #define IFS_GEN_STRIDE_AWARE    2
32 #define AUTH_INTERRUPTED_ERROR  5
33 #define IFS_AUTH_RETRY_CT       10
34
35 static  struct microcode_header_intel *ifs_header_ptr;  /* pointer to the ifs image header */
36 static u64 ifs_hash_ptr;                        /* Address of ifs metadata (hash) */
37 static u64 ifs_test_image_ptr;                  /* 256B aligned address of test pattern */
38 static DECLARE_COMPLETION(ifs_done);
39
40 static const char * const scan_hash_status[] = {
41         [0] = "No error reported",
42         [1] = "Attempt to copy scan hashes when copy already in progress",
43         [2] = "Secure Memory not set up correctly",
44         [3] = "FuSaInfo.ProgramID does not match or ff-mm-ss does not match",
45         [4] = "Reserved",
46         [5] = "Integrity check failed",
47         [6] = "Scan reload or test is in progress"
48 };
49
50 static const char * const scan_authentication_status[] = {
51         [0] = "No error reported",
52         [1] = "Attempt to authenticate a chunk which is already marked as authentic",
53         [2] = "Chunk authentication error. The hash of chunk did not match expected value",
54         [3] = "Reserved",
55         [4] = "Chunk outside the current stride",
56         [5] = "Authentication flow interrupted",
57 };
58
59 #define MC_HEADER_META_TYPE_END         (0)
60
61 struct metadata_header {
62         unsigned int            type;
63         unsigned int            blk_size;
64 };
65
66 static struct metadata_header *find_meta_data(void *ucode, unsigned int meta_type)
67 {
68         struct microcode_header_intel *hdr = &((struct microcode_intel *)ucode)->hdr;
69         struct metadata_header *meta_header;
70         unsigned long data_size, total_meta;
71         unsigned long meta_size = 0;
72
73         data_size = intel_microcode_get_datasize(hdr);
74         total_meta = hdr->metasize;
75         if (!total_meta)
76                 return NULL;
77
78         meta_header = (ucode + MC_HEADER_SIZE + data_size) - total_meta;
79
80         while (meta_header->type != MC_HEADER_META_TYPE_END &&
81                meta_header->blk_size &&
82                meta_size < total_meta) {
83                 meta_size += meta_header->blk_size;
84                 if (meta_header->type == meta_type)
85                         return meta_header;
86
87                 meta_header = (void *)meta_header + meta_header->blk_size;
88         }
89         return NULL;
90 }
91
92 static void hashcopy_err_message(struct device *dev, u32 err_code)
93 {
94         if (err_code >= ARRAY_SIZE(scan_hash_status))
95                 dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code);
96         else
97                 dev_err(dev, "Hash copy error : %s\n", scan_hash_status[err_code]);
98 }
99
100 static void auth_err_message(struct device *dev, u32 err_code)
101 {
102         if (err_code >= ARRAY_SIZE(scan_authentication_status))
103                 dev_err(dev, "invalid error code 0x%x for authentication\n", err_code);
104         else
105                 dev_err(dev, "Chunk authentication error : %s\n",
106                         scan_authentication_status[err_code]);
107 }
108
109 /*
110  * To copy scan hashes and authenticate test chunks, the initiating cpu must point
111  * to the EDX:EAX to the test image in linear address.
112  * Run wrmsr(MSR_COPY_SCAN_HASHES) for scan hash copy and run wrmsr(MSR_AUTHENTICATE_AND_COPY_CHUNK)
113  * for scan hash copy and test chunk authentication.
114  */
115 static void copy_hashes_authenticate_chunks(struct work_struct *work)
116 {
117         struct ifs_work *local_work = container_of(work, struct ifs_work, w);
118         union ifs_scan_hashes_status hashes_status;
119         union ifs_chunks_auth_status chunk_status;
120         struct device *dev = local_work->dev;
121         int i, num_chunks, chunk_size;
122         struct ifs_data *ifsd;
123         u64 linear_addr, base;
124         u32 err_code;
125
126         ifsd = ifs_get_data(dev);
127         /* run scan hash copy */
128         wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr);
129         rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data);
130
131         /* enumerate the scan image information */
132         num_chunks = hashes_status.num_chunks;
133         chunk_size = hashes_status.chunk_size * 1024;
134         err_code = hashes_status.error_code;
135
136         if (!hashes_status.valid) {
137                 ifsd->loading_error = true;
138                 hashcopy_err_message(dev, err_code);
139                 goto done;
140         }
141
142         /* base linear address to the scan data */
143         base = ifs_test_image_ptr;
144
145         /* scan data authentication and copy chunks to secured memory */
146         for (i = 0; i < num_chunks; i++) {
147                 linear_addr = base + i * chunk_size;
148                 linear_addr |= i;
149
150                 wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, linear_addr);
151                 rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
152
153                 ifsd->valid_chunks = chunk_status.valid_chunks;
154                 err_code = chunk_status.error_code;
155
156                 if (err_code) {
157                         ifsd->loading_error = true;
158                         auth_err_message(dev, err_code);
159                         goto done;
160                 }
161         }
162 done:
163         complete(&ifs_done);
164 }
165
166 static int get_num_chunks(int gen, union ifs_scan_hashes_status_gen2 status)
167 {
168         return gen >= IFS_GEN_STRIDE_AWARE ? status.chunks_in_stride : status.num_chunks;
169 }
170
171 static bool need_copy_scan_hashes(struct ifs_data *ifsd)
172 {
173         return !ifsd->loaded ||
174                 ifsd->generation < IFS_GEN_STRIDE_AWARE ||
175                 ifsd->loaded_version != ifs_header_ptr->rev;
176 }
177
178 static int copy_hashes_authenticate_chunks_gen2(struct device *dev)
179 {
180         union ifs_scan_hashes_status_gen2 hashes_status;
181         union ifs_chunks_auth_status_gen2 chunk_status;
182         u32 err_code, valid_chunks, total_chunks;
183         int i, num_chunks, chunk_size;
184         union meta_data *ifs_meta;
185         int starting_chunk_nr;
186         struct ifs_data *ifsd;
187         u64 linear_addr, base;
188         u64 chunk_table[2];
189         int retry_count;
190
191         ifsd = ifs_get_data(dev);
192
193         if (need_copy_scan_hashes(ifsd)) {
194                 wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr);
195                 rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data);
196
197                 /* enumerate the scan image information */
198                 chunk_size = hashes_status.chunk_size * SZ_1K;
199                 err_code = hashes_status.error_code;
200
201                 num_chunks = get_num_chunks(ifsd->generation, hashes_status);
202
203                 if (!hashes_status.valid) {
204                         hashcopy_err_message(dev, err_code);
205                         return -EIO;
206                 }
207                 ifsd->loaded_version = ifs_header_ptr->rev;
208                 ifsd->chunk_size = chunk_size;
209         } else {
210                 num_chunks = ifsd->valid_chunks;
211                 chunk_size = ifsd->chunk_size;
212         }
213
214         if (ifsd->generation >= IFS_GEN_STRIDE_AWARE) {
215                 wrmsrl(MSR_SAF_CTRL, INVALIDATE_STRIDE);
216                 rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
217                 if (chunk_status.valid_chunks != 0) {
218                         dev_err(dev, "Couldn't invalidate installed stride - %d\n",
219                                 chunk_status.valid_chunks);
220                         return -EIO;
221                 }
222         }
223
224         base = ifs_test_image_ptr;
225         ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS);
226         starting_chunk_nr = ifs_meta->starting_chunk;
227
228         /* scan data authentication and copy chunks to secured memory */
229         for (i = 0; i < num_chunks; i++) {
230                 retry_count = IFS_AUTH_RETRY_CT;
231                 linear_addr = base + i * chunk_size;
232
233                 chunk_table[0] = starting_chunk_nr + i;
234                 chunk_table[1] = linear_addr;
235                 do {
236                         wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, (u64)chunk_table);
237                         rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
238                         err_code = chunk_status.error_code;
239                 } while (err_code == AUTH_INTERRUPTED_ERROR && --retry_count);
240
241                 if (err_code) {
242                         ifsd->loading_error = true;
243                         auth_err_message(dev, err_code);
244                         return -EIO;
245                 }
246         }
247
248         valid_chunks = chunk_status.valid_chunks;
249         total_chunks = chunk_status.total_chunks;
250
251         if (valid_chunks != total_chunks) {
252                 ifsd->loading_error = true;
253                 dev_err(dev, "Couldn't authenticate all the chunks. Authenticated %d total %d.\n",
254                         valid_chunks, total_chunks);
255                 return -EIO;
256         }
257         ifsd->valid_chunks = valid_chunks;
258
259         return 0;
260 }
261
262 static int validate_ifs_metadata(struct device *dev)
263 {
264         struct ifs_data *ifsd = ifs_get_data(dev);
265         union meta_data *ifs_meta;
266         char test_file[64];
267         int ret = -EINVAL;
268
269         snprintf(test_file, sizeof(test_file), "%02x-%02x-%02x-%02x.scan",
270                  boot_cpu_data.x86, boot_cpu_data.x86_model,
271                  boot_cpu_data.x86_stepping, ifsd->cur_batch);
272
273         ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS);
274         if (!ifs_meta) {
275                 dev_err(dev, "IFS Metadata missing in file %s\n", test_file);
276                 return ret;
277         }
278
279         ifs_test_image_ptr = (u64)ifs_meta + sizeof(union meta_data);
280
281         /* Scan chunk start must be 256 byte aligned */
282         if (!IS_ALIGNED(ifs_test_image_ptr, IFS_CHUNK_ALIGNMENT)) {
283                 dev_err(dev, "Scan pattern is not aligned on %d bytes aligned in %s\n",
284                         IFS_CHUNK_ALIGNMENT, test_file);
285                 return ret;
286         }
287
288         if (ifs_meta->current_image != ifsd->cur_batch) {
289                 dev_warn(dev, "Mismatch between filename %s and batch metadata 0x%02x\n",
290                          test_file, ifs_meta->current_image);
291                 return ret;
292         }
293
294         if (ifs_meta->chunks_per_stride &&
295             (ifs_meta->starting_chunk % ifs_meta->chunks_per_stride != 0)) {
296                 dev_warn(dev, "Starting chunk num %u not a multiple of chunks_per_stride %u\n",
297                          ifs_meta->starting_chunk, ifs_meta->chunks_per_stride);
298                 return ret;
299         }
300
301         return 0;
302 }
303
304 /*
305  * IFS requires scan chunks authenticated per each socket in the platform.
306  * Once the test chunk is authenticated, it is automatically copied to secured memory
307  * and proceed the authentication for the next chunk.
308  */
309 static int scan_chunks_sanity_check(struct device *dev)
310 {
311         struct ifs_data *ifsd = ifs_get_data(dev);
312         struct ifs_work local_work;
313         int curr_pkg, cpu, ret;
314
315         memset(ifs_pkg_auth, 0, (topology_max_packages() * sizeof(bool)));
316         ret = validate_ifs_metadata(dev);
317         if (ret)
318                 return ret;
319
320         ifsd->loading_error = false;
321
322         if (ifsd->generation > 0)
323                 return copy_hashes_authenticate_chunks_gen2(dev);
324
325         /* copy the scan hash and authenticate per package */
326         cpus_read_lock();
327         for_each_online_cpu(cpu) {
328                 curr_pkg = topology_physical_package_id(cpu);
329                 if (ifs_pkg_auth[curr_pkg])
330                         continue;
331                 reinit_completion(&ifs_done);
332                 local_work.dev = dev;
333                 INIT_WORK_ONSTACK(&local_work.w, copy_hashes_authenticate_chunks);
334                 schedule_work_on(cpu, &local_work.w);
335                 wait_for_completion(&ifs_done);
336                 if (ifsd->loading_error) {
337                         ret = -EIO;
338                         goto out;
339                 }
340                 ifs_pkg_auth[curr_pkg] = 1;
341         }
342         ret = 0;
343         ifsd->loaded_version = ifs_header_ptr->rev;
344 out:
345         cpus_read_unlock();
346
347         return ret;
348 }
349
350 static int image_sanity_check(struct device *dev, const struct microcode_header_intel *data)
351 {
352         struct ucode_cpu_info uci;
353
354         /* Provide a specific error message when loading an older/unsupported image */
355         if (data->hdrver != MC_HEADER_TYPE_IFS) {
356                 dev_err(dev, "Header version %d not supported\n", data->hdrver);
357                 return -EINVAL;
358         }
359
360         if (intel_microcode_sanity_check((void *)data, true, MC_HEADER_TYPE_IFS)) {
361                 dev_err(dev, "sanity check failed\n");
362                 return -EINVAL;
363         }
364
365         intel_cpu_collect_info(&uci);
366
367         if (!intel_find_matching_signature((void *)data,
368                                            uci.cpu_sig.sig,
369                                            uci.cpu_sig.pf)) {
370                 dev_err(dev, "cpu signature, processor flags not matching\n");
371                 return -EINVAL;
372         }
373
374         return 0;
375 }
376
377 /*
378  * Load ifs image. Before loading ifs module, the ifs image must be located
379  * in /lib/firmware/intel/ifs_x/ and named as family-model-stepping-02x.{testname}.
380  */
381 int ifs_load_firmware(struct device *dev)
382 {
383         const struct ifs_test_caps *test = ifs_get_test_caps(dev);
384         struct ifs_data *ifsd = ifs_get_data(dev);
385         unsigned int expected_size;
386         const struct firmware *fw;
387         char scan_path[64];
388         int ret = -EINVAL;
389
390         snprintf(scan_path, sizeof(scan_path), "intel/ifs_%d/%02x-%02x-%02x-%02x.scan",
391                  test->test_num, boot_cpu_data.x86, boot_cpu_data.x86_model,
392                  boot_cpu_data.x86_stepping, ifsd->cur_batch);
393
394         ret = request_firmware_direct(&fw, scan_path, dev);
395         if (ret) {
396                 dev_err(dev, "ifs file %s load failed\n", scan_path);
397                 goto done;
398         }
399
400         expected_size = ((struct microcode_header_intel *)fw->data)->totalsize;
401         if (fw->size != expected_size) {
402                 dev_err(dev, "File size mismatch (expected %u, actual %zu). Corrupted IFS image.\n",
403                         expected_size, fw->size);
404                 return -EINVAL;
405         }
406
407         ret = image_sanity_check(dev, (struct microcode_header_intel *)fw->data);
408         if (ret)
409                 goto release;
410
411         ifs_header_ptr = (struct microcode_header_intel *)fw->data;
412         ifs_hash_ptr = (u64)(ifs_header_ptr + 1);
413
414         ret = scan_chunks_sanity_check(dev);
415         if (ret)
416                 dev_err(dev, "Load failure for batch: %02x\n", ifsd->cur_batch);
417
418 release:
419         release_firmware(fw);
420 done:
421         ifsd->loaded = (ret == 0);
422
423         return ret;
424 }