]> Git Repo - linux.git/blob - drivers/platform/x86/intel/ifs/load.c
Merge tag 'cgroup-for-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
[linux.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 <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  */
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  */
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
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
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
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  */
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 }
This page took 0.053154 seconds and 4 git commands to generate.