Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Copyright(c) 2022 Intel Corporation. */
0003 
0004 #include <linux/firmware.h>
0005 #include <asm/cpu.h>
0006 #include <linux/slab.h>
0007 #include <asm/microcode_intel.h>
0008 
0009 #include "ifs.h"
0010 
0011 struct ifs_header {
0012     u32 header_ver;
0013     u32 blob_revision;
0014     u32 date;
0015     u32 processor_sig;
0016     u32 check_sum;
0017     u32 loader_rev;
0018     u32 processor_flags;
0019     u32 metadata_size;
0020     u32 total_size;
0021     u32 fusa_info;
0022     u64 reserved;
0023 };
0024 
0025 #define IFS_HEADER_SIZE (sizeof(struct ifs_header))
0026 static struct ifs_header *ifs_header_ptr;   /* pointer to the ifs image header */
0027 static u64 ifs_hash_ptr;            /* Address of ifs metadata (hash) */
0028 static u64 ifs_test_image_ptr;          /* 256B aligned address of test pattern */
0029 static DECLARE_COMPLETION(ifs_done);
0030 
0031 static const char * const scan_hash_status[] = {
0032     [0] = "No error reported",
0033     [1] = "Attempt to copy scan hashes when copy already in progress",
0034     [2] = "Secure Memory not set up correctly",
0035     [3] = "FuSaInfo.ProgramID does not match or ff-mm-ss does not match",
0036     [4] = "Reserved",
0037     [5] = "Integrity check failed",
0038     [6] = "Scan reload or test is in progress"
0039 };
0040 
0041 static const char * const scan_authentication_status[] = {
0042     [0] = "No error reported",
0043     [1] = "Attempt to authenticate a chunk which is already marked as authentic",
0044     [2] = "Chunk authentication error. The hash of chunk did not match expected value"
0045 };
0046 
0047 /*
0048  * To copy scan hashes and authenticate test chunks, the initiating cpu must point
0049  * to the EDX:EAX to the test image in linear address.
0050  * Run wrmsr(MSR_COPY_SCAN_HASHES) for scan hash copy and run wrmsr(MSR_AUTHENTICATE_AND_COPY_CHUNK)
0051  * for scan hash copy and test chunk authentication.
0052  */
0053 static void copy_hashes_authenticate_chunks(struct work_struct *work)
0054 {
0055     struct ifs_work *local_work = container_of(work, struct ifs_work, w);
0056     union ifs_scan_hashes_status hashes_status;
0057     union ifs_chunks_auth_status chunk_status;
0058     struct device *dev = local_work->dev;
0059     int i, num_chunks, chunk_size;
0060     struct ifs_data *ifsd;
0061     u64 linear_addr, base;
0062     u32 err_code;
0063 
0064     ifsd = ifs_get_data(dev);
0065     /* run scan hash copy */
0066     wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr);
0067     rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data);
0068 
0069     /* enumerate the scan image information */
0070     num_chunks = hashes_status.num_chunks;
0071     chunk_size = hashes_status.chunk_size * 1024;
0072     err_code = hashes_status.error_code;
0073 
0074     if (!hashes_status.valid) {
0075         ifsd->loading_error = true;
0076         if (err_code >= ARRAY_SIZE(scan_hash_status)) {
0077             dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code);
0078             goto done;
0079         }
0080         dev_err(dev, "Hash copy error : %s", scan_hash_status[err_code]);
0081         goto done;
0082     }
0083 
0084     /* base linear address to the scan data */
0085     base = ifs_test_image_ptr;
0086 
0087     /* scan data authentication and copy chunks to secured memory */
0088     for (i = 0; i < num_chunks; i++) {
0089         linear_addr = base + i * chunk_size;
0090         linear_addr |= i;
0091 
0092         wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, linear_addr);
0093         rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
0094 
0095         ifsd->valid_chunks = chunk_status.valid_chunks;
0096         err_code = chunk_status.error_code;
0097 
0098         if (err_code) {
0099             ifsd->loading_error = true;
0100             if (err_code >= ARRAY_SIZE(scan_authentication_status)) {
0101                 dev_err(dev,
0102                     "invalid error code 0x%x for authentication\n", err_code);
0103                 goto done;
0104             }
0105             dev_err(dev, "Chunk authentication error %s\n",
0106                 scan_authentication_status[err_code]);
0107             goto done;
0108         }
0109     }
0110 done:
0111     complete(&ifs_done);
0112 }
0113 
0114 /*
0115  * IFS requires scan chunks authenticated per each socket in the platform.
0116  * Once the test chunk is authenticated, it is automatically copied to secured memory
0117  * and proceed the authentication for the next chunk.
0118  */
0119 static int scan_chunks_sanity_check(struct device *dev)
0120 {
0121     int metadata_size, curr_pkg, cpu, ret = -ENOMEM;
0122     struct ifs_data *ifsd = ifs_get_data(dev);
0123     bool *package_authenticated;
0124     struct ifs_work local_work;
0125     char *test_ptr;
0126 
0127     package_authenticated = kcalloc(topology_max_packages(), sizeof(bool), GFP_KERNEL);
0128     if (!package_authenticated)
0129         return ret;
0130 
0131     metadata_size = ifs_header_ptr->metadata_size;
0132 
0133     /* Spec says that if the Meta Data Size = 0 then it should be treated as 2000 */
0134     if (metadata_size == 0)
0135         metadata_size = 2000;
0136 
0137     /* Scan chunk start must be 256 byte aligned */
0138     if ((metadata_size + IFS_HEADER_SIZE) % 256) {
0139         dev_err(dev, "Scan pattern offset within the binary is not 256 byte aligned\n");
0140         return -EINVAL;
0141     }
0142 
0143     test_ptr = (char *)ifs_header_ptr + IFS_HEADER_SIZE + metadata_size;
0144     ifsd->loading_error = false;
0145 
0146     ifs_test_image_ptr = (u64)test_ptr;
0147     ifsd->loaded_version = ifs_header_ptr->blob_revision;
0148 
0149     /* copy the scan hash and authenticate per package */
0150     cpus_read_lock();
0151     for_each_online_cpu(cpu) {
0152         curr_pkg = topology_physical_package_id(cpu);
0153         if (package_authenticated[curr_pkg])
0154             continue;
0155         reinit_completion(&ifs_done);
0156         local_work.dev = dev;
0157         INIT_WORK(&local_work.w, copy_hashes_authenticate_chunks);
0158         schedule_work_on(cpu, &local_work.w);
0159         wait_for_completion(&ifs_done);
0160         if (ifsd->loading_error)
0161             goto out;
0162         package_authenticated[curr_pkg] = 1;
0163     }
0164     ret = 0;
0165 out:
0166     cpus_read_unlock();
0167     kfree(package_authenticated);
0168 
0169     return ret;
0170 }
0171 
0172 static int ifs_sanity_check(struct device *dev,
0173                 const struct microcode_header_intel *mc_header)
0174 {
0175     unsigned long total_size, data_size;
0176     u32 sum, *mc;
0177 
0178     total_size = get_totalsize(mc_header);
0179     data_size = get_datasize(mc_header);
0180 
0181     if ((data_size + MC_HEADER_SIZE > total_size) || (total_size % sizeof(u32))) {
0182         dev_err(dev, "bad ifs data file size.\n");
0183         return -EINVAL;
0184     }
0185 
0186     if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
0187         dev_err(dev, "invalid/unknown ifs update format.\n");
0188         return -EINVAL;
0189     }
0190 
0191     mc = (u32 *)mc_header;
0192     sum = 0;
0193     for (int i = 0; i < total_size / sizeof(u32); i++)
0194         sum += mc[i];
0195 
0196     if (sum) {
0197         dev_err(dev, "bad ifs data checksum, aborting.\n");
0198         return -EINVAL;
0199     }
0200 
0201     return 0;
0202 }
0203 
0204 static bool find_ifs_matching_signature(struct device *dev, struct ucode_cpu_info *uci,
0205                     const struct microcode_header_intel *shdr)
0206 {
0207     unsigned int mc_size;
0208 
0209     mc_size = get_totalsize(shdr);
0210 
0211     if (!mc_size || ifs_sanity_check(dev, shdr) < 0) {
0212         dev_err(dev, "ifs sanity check failure\n");
0213         return false;
0214     }
0215 
0216     if (!intel_cpu_signatures_match(uci->cpu_sig.sig, uci->cpu_sig.pf, shdr->sig, shdr->pf)) {
0217         dev_err(dev, "ifs signature, pf not matching\n");
0218         return false;
0219     }
0220 
0221     return true;
0222 }
0223 
0224 static bool ifs_image_sanity_check(struct device *dev, const struct microcode_header_intel *data)
0225 {
0226     struct ucode_cpu_info uci;
0227 
0228     intel_cpu_collect_info(&uci);
0229 
0230     return find_ifs_matching_signature(dev, &uci, data);
0231 }
0232 
0233 /*
0234  * Load ifs image. Before loading ifs module, the ifs image must be located
0235  * in /lib/firmware/intel/ifs and named as {family/model/stepping}.{testname}.
0236  */
0237 void ifs_load_firmware(struct device *dev)
0238 {
0239     struct ifs_data *ifsd = ifs_get_data(dev);
0240     const struct firmware *fw;
0241     char scan_path[32];
0242     int ret;
0243 
0244     snprintf(scan_path, sizeof(scan_path), "intel/ifs/%02x-%02x-%02x.scan",
0245          boot_cpu_data.x86, boot_cpu_data.x86_model, boot_cpu_data.x86_stepping);
0246 
0247     ret = request_firmware_direct(&fw, scan_path, dev);
0248     if (ret) {
0249         dev_err(dev, "ifs file %s load failed\n", scan_path);
0250         goto done;
0251     }
0252 
0253     if (!ifs_image_sanity_check(dev, (struct microcode_header_intel *)fw->data)) {
0254         dev_err(dev, "ifs header sanity check failed\n");
0255         goto release;
0256     }
0257 
0258     ifs_header_ptr = (struct ifs_header *)fw->data;
0259     ifs_hash_ptr = (u64)(ifs_header_ptr + 1);
0260 
0261     ret = scan_chunks_sanity_check(dev);
0262 release:
0263     release_firmware(fw);
0264 done:
0265     ifsd->loaded = (ret == 0);
0266 }