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 } 267