1fb57fc78SJithu Joseph // SPDX-License-Identifier: GPL-2.0-only 2fb57fc78SJithu Joseph /* Copyright(c) 2022 Intel Corporation. */ 3fb57fc78SJithu Joseph 4fb57fc78SJithu Joseph #include <linux/firmware.h> 507f47c01SJithu Joseph #include <linux/sizes.h> 6846e751fSJithu Joseph #include <asm/cpu.h> 782ad097bSAshok Raj #include <asm/microcode.h> 8fb57fc78SJithu Joseph 9fb57fc78SJithu Joseph #include "ifs.h" 10fb57fc78SJithu Joseph 1148c6e7dcSJithu Joseph #define IFS_CHUNK_ALIGNMENT 256 1248c6e7dcSJithu Joseph union meta_data { 1348c6e7dcSJithu Joseph struct { 1448c6e7dcSJithu Joseph u32 meta_type; // metadata type 1548c6e7dcSJithu Joseph u32 meta_size; // size of this entire struct including hdrs. 1648c6e7dcSJithu Joseph u32 test_type; // IFS test type 1748c6e7dcSJithu Joseph u32 fusa_info; // Fusa info 1848c6e7dcSJithu Joseph u32 total_images; // Total number of images 1948c6e7dcSJithu Joseph u32 current_image; // Current Image # 2048c6e7dcSJithu Joseph u32 total_chunks; // Total number of chunks in this image 2148c6e7dcSJithu Joseph u32 starting_chunk; // Starting chunk number in this image 2248c6e7dcSJithu Joseph u32 size_per_chunk; // size of each chunk 2348c6e7dcSJithu Joseph u32 chunks_per_stride; // number of chunks in a stride 2448c6e7dcSJithu Joseph }; 2548c6e7dcSJithu Joseph u8 padding[IFS_CHUNK_ALIGNMENT]; 2648c6e7dcSJithu Joseph }; 2748c6e7dcSJithu Joseph 28aa63e0fdSJithu Joseph #define IFS_HEADER_SIZE (sizeof(struct microcode_header_intel)) 2948c6e7dcSJithu Joseph #define META_TYPE_IFS 1 3007f47c01SJithu Joseph #define INVALIDATE_STRIDE 0x1UL 3107f47c01SJithu Joseph #define IFS_GEN_STRIDE_AWARE 2 3207f47c01SJithu Joseph #define AUTH_INTERRUPTED_ERROR 5 3307f47c01SJithu Joseph #define IFS_AUTH_RETRY_CT 10 3407f47c01SJithu Joseph 35aa63e0fdSJithu Joseph static struct microcode_header_intel *ifs_header_ptr; /* pointer to the ifs image header */ 36684ec215SJithu Joseph static u64 ifs_hash_ptr; /* Address of ifs metadata (hash) */ 37684ec215SJithu Joseph static u64 ifs_test_image_ptr; /* 256B aligned address of test pattern */ 38684ec215SJithu Joseph static DECLARE_COMPLETION(ifs_done); 39684ec215SJithu Joseph 40684ec215SJithu Joseph static const char * const scan_hash_status[] = { 41684ec215SJithu Joseph [0] = "No error reported", 42684ec215SJithu Joseph [1] = "Attempt to copy scan hashes when copy already in progress", 43684ec215SJithu Joseph [2] = "Secure Memory not set up correctly", 44684ec215SJithu Joseph [3] = "FuSaInfo.ProgramID does not match or ff-mm-ss does not match", 45684ec215SJithu Joseph [4] = "Reserved", 46684ec215SJithu Joseph [5] = "Integrity check failed", 47684ec215SJithu Joseph [6] = "Scan reload or test is in progress" 48684ec215SJithu Joseph }; 49684ec215SJithu Joseph 50684ec215SJithu Joseph static const char * const scan_authentication_status[] = { 51684ec215SJithu Joseph [0] = "No error reported", 52684ec215SJithu Joseph [1] = "Attempt to authenticate a chunk which is already marked as authentic", 5307f47c01SJithu Joseph [2] = "Chunk authentication error. The hash of chunk did not match expected value", 5407f47c01SJithu Joseph [3] = "Reserved", 5507f47c01SJithu Joseph [4] = "Chunk outside the current stride", 5607f47c01SJithu Joseph [5] = "Authentication flow interrupted", 57684ec215SJithu Joseph }; 58684ec215SJithu Joseph 598382fee3SAshok Raj #define MC_HEADER_META_TYPE_END (0) 608382fee3SAshok Raj 618382fee3SAshok Raj struct metadata_header { 628382fee3SAshok Raj unsigned int type; 638382fee3SAshok Raj unsigned int blk_size; 648382fee3SAshok Raj }; 658382fee3SAshok Raj 668382fee3SAshok Raj static struct metadata_header *find_meta_data(void *ucode, unsigned int meta_type) 678382fee3SAshok Raj { 68b0e67db1SAshok Raj struct microcode_header_intel *hdr = &((struct microcode_intel *)ucode)->hdr; 698382fee3SAshok Raj struct metadata_header *meta_header; 708382fee3SAshok Raj unsigned long data_size, total_meta; 718382fee3SAshok Raj unsigned long meta_size = 0; 728382fee3SAshok Raj 73b0e67db1SAshok Raj data_size = intel_microcode_get_datasize(hdr); 74b0e67db1SAshok Raj total_meta = hdr->metasize; 758382fee3SAshok Raj if (!total_meta) 768382fee3SAshok Raj return NULL; 778382fee3SAshok Raj 788382fee3SAshok Raj meta_header = (ucode + MC_HEADER_SIZE + data_size) - total_meta; 798382fee3SAshok Raj 808382fee3SAshok Raj while (meta_header->type != MC_HEADER_META_TYPE_END && 818382fee3SAshok Raj meta_header->blk_size && 828382fee3SAshok Raj meta_size < total_meta) { 838382fee3SAshok Raj meta_size += meta_header->blk_size; 848382fee3SAshok Raj if (meta_header->type == meta_type) 858382fee3SAshok Raj return meta_header; 868382fee3SAshok Raj 878382fee3SAshok Raj meta_header = (void *)meta_header + meta_header->blk_size; 888382fee3SAshok Raj } 898382fee3SAshok Raj return NULL; 908382fee3SAshok Raj } 918382fee3SAshok Raj 92a138ac26SJithu Joseph static void hashcopy_err_message(struct device *dev, u32 err_code) 93a138ac26SJithu Joseph { 94a138ac26SJithu Joseph if (err_code >= ARRAY_SIZE(scan_hash_status)) 95a138ac26SJithu Joseph dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code); 96a138ac26SJithu Joseph else 97a138ac26SJithu Joseph dev_err(dev, "Hash copy error : %s\n", scan_hash_status[err_code]); 98a138ac26SJithu Joseph } 99a138ac26SJithu Joseph 100a138ac26SJithu Joseph static void auth_err_message(struct device *dev, u32 err_code) 101a138ac26SJithu Joseph { 102a138ac26SJithu Joseph if (err_code >= ARRAY_SIZE(scan_authentication_status)) 103a138ac26SJithu Joseph dev_err(dev, "invalid error code 0x%x for authentication\n", err_code); 104a138ac26SJithu Joseph else 105a138ac26SJithu Joseph dev_err(dev, "Chunk authentication error : %s\n", 106a138ac26SJithu Joseph scan_authentication_status[err_code]); 107a138ac26SJithu Joseph } 108a138ac26SJithu Joseph 109684ec215SJithu Joseph /* 110684ec215SJithu Joseph * To copy scan hashes and authenticate test chunks, the initiating cpu must point 111684ec215SJithu Joseph * to the EDX:EAX to the test image in linear address. 112684ec215SJithu Joseph * Run wrmsr(MSR_COPY_SCAN_HASHES) for scan hash copy and run wrmsr(MSR_AUTHENTICATE_AND_COPY_CHUNK) 113684ec215SJithu Joseph * for scan hash copy and test chunk authentication. 114684ec215SJithu Joseph */ 115684ec215SJithu Joseph static void copy_hashes_authenticate_chunks(struct work_struct *work) 116684ec215SJithu Joseph { 117684ec215SJithu Joseph struct ifs_work *local_work = container_of(work, struct ifs_work, w); 118684ec215SJithu Joseph union ifs_scan_hashes_status hashes_status; 119684ec215SJithu Joseph union ifs_chunks_auth_status chunk_status; 120684ec215SJithu Joseph struct device *dev = local_work->dev; 121684ec215SJithu Joseph int i, num_chunks, chunk_size; 122684ec215SJithu Joseph struct ifs_data *ifsd; 123684ec215SJithu Joseph u64 linear_addr, base; 124684ec215SJithu Joseph u32 err_code; 125684ec215SJithu Joseph 126684ec215SJithu Joseph ifsd = ifs_get_data(dev); 127684ec215SJithu Joseph /* run scan hash copy */ 128684ec215SJithu Joseph wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr); 129684ec215SJithu Joseph rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data); 130684ec215SJithu Joseph 131684ec215SJithu Joseph /* enumerate the scan image information */ 132684ec215SJithu Joseph num_chunks = hashes_status.num_chunks; 133684ec215SJithu Joseph chunk_size = hashes_status.chunk_size * 1024; 134684ec215SJithu Joseph err_code = hashes_status.error_code; 135684ec215SJithu Joseph 136684ec215SJithu Joseph if (!hashes_status.valid) { 137684ec215SJithu Joseph ifsd->loading_error = true; 138a138ac26SJithu Joseph hashcopy_err_message(dev, err_code); 139684ec215SJithu Joseph goto done; 140684ec215SJithu Joseph } 141684ec215SJithu Joseph 142684ec215SJithu Joseph /* base linear address to the scan data */ 143684ec215SJithu Joseph base = ifs_test_image_ptr; 144684ec215SJithu Joseph 145684ec215SJithu Joseph /* scan data authentication and copy chunks to secured memory */ 146684ec215SJithu Joseph for (i = 0; i < num_chunks; i++) { 147684ec215SJithu Joseph linear_addr = base + i * chunk_size; 148684ec215SJithu Joseph linear_addr |= i; 149684ec215SJithu Joseph 150684ec215SJithu Joseph wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, linear_addr); 151684ec215SJithu Joseph rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data); 152684ec215SJithu Joseph 153684ec215SJithu Joseph ifsd->valid_chunks = chunk_status.valid_chunks; 154684ec215SJithu Joseph err_code = chunk_status.error_code; 155684ec215SJithu Joseph 156684ec215SJithu Joseph if (err_code) { 157684ec215SJithu Joseph ifsd->loading_error = true; 158a138ac26SJithu Joseph auth_err_message(dev, err_code); 159684ec215SJithu Joseph goto done; 160684ec215SJithu Joseph } 161684ec215SJithu Joseph } 162684ec215SJithu Joseph done: 163684ec215SJithu Joseph complete(&ifs_done); 164684ec215SJithu Joseph } 165684ec215SJithu Joseph 16607f47c01SJithu Joseph static int get_num_chunks(int gen, union ifs_scan_hashes_status_gen2 status) 16707f47c01SJithu Joseph { 16807f47c01SJithu Joseph return gen >= IFS_GEN_STRIDE_AWARE ? status.chunks_in_stride : status.num_chunks; 16907f47c01SJithu Joseph } 17007f47c01SJithu Joseph 17107f47c01SJithu Joseph static bool need_copy_scan_hashes(struct ifs_data *ifsd) 17207f47c01SJithu Joseph { 17307f47c01SJithu Joseph return !ifsd->loaded || 17407f47c01SJithu Joseph ifsd->generation < IFS_GEN_STRIDE_AWARE || 17507f47c01SJithu Joseph ifsd->loaded_version != ifs_header_ptr->rev; 17607f47c01SJithu Joseph } 17707f47c01SJithu Joseph 17807f47c01SJithu Joseph static int copy_hashes_authenticate_chunks_gen2(struct device *dev) 17907f47c01SJithu Joseph { 18007f47c01SJithu Joseph union ifs_scan_hashes_status_gen2 hashes_status; 18107f47c01SJithu Joseph union ifs_chunks_auth_status_gen2 chunk_status; 18207f47c01SJithu Joseph u32 err_code, valid_chunks, total_chunks; 18307f47c01SJithu Joseph int i, num_chunks, chunk_size; 18407f47c01SJithu Joseph union meta_data *ifs_meta; 18507f47c01SJithu Joseph int starting_chunk_nr; 18607f47c01SJithu Joseph struct ifs_data *ifsd; 18707f47c01SJithu Joseph u64 linear_addr, base; 18807f47c01SJithu Joseph u64 chunk_table[2]; 18907f47c01SJithu Joseph int retry_count; 19007f47c01SJithu Joseph 19107f47c01SJithu Joseph ifsd = ifs_get_data(dev); 19207f47c01SJithu Joseph 19307f47c01SJithu Joseph if (need_copy_scan_hashes(ifsd)) { 19407f47c01SJithu Joseph wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr); 19507f47c01SJithu Joseph rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data); 19607f47c01SJithu Joseph 19707f47c01SJithu Joseph /* enumerate the scan image information */ 19807f47c01SJithu Joseph chunk_size = hashes_status.chunk_size * SZ_1K; 19907f47c01SJithu Joseph err_code = hashes_status.error_code; 20007f47c01SJithu Joseph 20107f47c01SJithu Joseph num_chunks = get_num_chunks(ifsd->generation, hashes_status); 20207f47c01SJithu Joseph 20307f47c01SJithu Joseph if (!hashes_status.valid) { 20407f47c01SJithu Joseph hashcopy_err_message(dev, err_code); 20507f47c01SJithu Joseph return -EIO; 20607f47c01SJithu Joseph } 20707f47c01SJithu Joseph ifsd->loaded_version = ifs_header_ptr->rev; 20807f47c01SJithu Joseph ifsd->chunk_size = chunk_size; 20907f47c01SJithu Joseph } else { 21007f47c01SJithu Joseph num_chunks = ifsd->valid_chunks; 21107f47c01SJithu Joseph chunk_size = ifsd->chunk_size; 21207f47c01SJithu Joseph } 21307f47c01SJithu Joseph 21407f47c01SJithu Joseph if (ifsd->generation >= IFS_GEN_STRIDE_AWARE) { 21507f47c01SJithu Joseph wrmsrl(MSR_SAF_CTRL, INVALIDATE_STRIDE); 21607f47c01SJithu Joseph rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data); 21707f47c01SJithu Joseph if (chunk_status.valid_chunks != 0) { 21807f47c01SJithu Joseph dev_err(dev, "Couldn't invalidate installed stride - %d\n", 21907f47c01SJithu Joseph chunk_status.valid_chunks); 22007f47c01SJithu Joseph return -EIO; 22107f47c01SJithu Joseph } 22207f47c01SJithu Joseph } 22307f47c01SJithu Joseph 22407f47c01SJithu Joseph base = ifs_test_image_ptr; 22507f47c01SJithu Joseph ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS); 22607f47c01SJithu Joseph starting_chunk_nr = ifs_meta->starting_chunk; 22707f47c01SJithu Joseph 22807f47c01SJithu Joseph /* scan data authentication and copy chunks to secured memory */ 22907f47c01SJithu Joseph for (i = 0; i < num_chunks; i++) { 23007f47c01SJithu Joseph retry_count = IFS_AUTH_RETRY_CT; 23107f47c01SJithu Joseph linear_addr = base + i * chunk_size; 23207f47c01SJithu Joseph 23307f47c01SJithu Joseph chunk_table[0] = starting_chunk_nr + i; 23407f47c01SJithu Joseph chunk_table[1] = linear_addr; 23507f47c01SJithu Joseph do { 23607f47c01SJithu Joseph wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, (u64)chunk_table); 23707f47c01SJithu Joseph rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data); 23807f47c01SJithu Joseph err_code = chunk_status.error_code; 23907f47c01SJithu Joseph } while (err_code == AUTH_INTERRUPTED_ERROR && --retry_count); 24007f47c01SJithu Joseph 24107f47c01SJithu Joseph if (err_code) { 24207f47c01SJithu Joseph ifsd->loading_error = true; 24307f47c01SJithu Joseph auth_err_message(dev, err_code); 24407f47c01SJithu Joseph return -EIO; 24507f47c01SJithu Joseph } 24607f47c01SJithu Joseph } 24707f47c01SJithu Joseph 24807f47c01SJithu Joseph valid_chunks = chunk_status.valid_chunks; 24907f47c01SJithu Joseph total_chunks = chunk_status.total_chunks; 25007f47c01SJithu Joseph 25107f47c01SJithu Joseph if (valid_chunks != total_chunks) { 25207f47c01SJithu Joseph ifsd->loading_error = true; 25307f47c01SJithu Joseph dev_err(dev, "Couldn't authenticate all the chunks. Authenticated %d total %d.\n", 25407f47c01SJithu Joseph valid_chunks, total_chunks); 25507f47c01SJithu Joseph return -EIO; 25607f47c01SJithu Joseph } 25707f47c01SJithu Joseph ifsd->valid_chunks = valid_chunks; 25807f47c01SJithu Joseph 25907f47c01SJithu Joseph return 0; 26007f47c01SJithu Joseph } 26107f47c01SJithu Joseph 26248c6e7dcSJithu Joseph static int validate_ifs_metadata(struct device *dev) 26348c6e7dcSJithu Joseph { 26448c6e7dcSJithu Joseph struct ifs_data *ifsd = ifs_get_data(dev); 26548c6e7dcSJithu Joseph union meta_data *ifs_meta; 26648c6e7dcSJithu Joseph char test_file[64]; 26748c6e7dcSJithu Joseph int ret = -EINVAL; 26848c6e7dcSJithu Joseph 26948c6e7dcSJithu Joseph snprintf(test_file, sizeof(test_file), "%02x-%02x-%02x-%02x.scan", 27048c6e7dcSJithu Joseph boot_cpu_data.x86, boot_cpu_data.x86_model, 27148c6e7dcSJithu Joseph boot_cpu_data.x86_stepping, ifsd->cur_batch); 27248c6e7dcSJithu Joseph 27348c6e7dcSJithu Joseph ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS); 27448c6e7dcSJithu Joseph if (!ifs_meta) { 27548c6e7dcSJithu Joseph dev_err(dev, "IFS Metadata missing in file %s\n", test_file); 27648c6e7dcSJithu Joseph return ret; 27748c6e7dcSJithu Joseph } 27848c6e7dcSJithu Joseph 27948c6e7dcSJithu Joseph ifs_test_image_ptr = (u64)ifs_meta + sizeof(union meta_data); 28048c6e7dcSJithu Joseph 28148c6e7dcSJithu Joseph /* Scan chunk start must be 256 byte aligned */ 28248c6e7dcSJithu Joseph if (!IS_ALIGNED(ifs_test_image_ptr, IFS_CHUNK_ALIGNMENT)) { 28348c6e7dcSJithu Joseph dev_err(dev, "Scan pattern is not aligned on %d bytes aligned in %s\n", 28448c6e7dcSJithu Joseph IFS_CHUNK_ALIGNMENT, test_file); 28548c6e7dcSJithu Joseph return ret; 28648c6e7dcSJithu Joseph } 28748c6e7dcSJithu Joseph 28848c6e7dcSJithu Joseph if (ifs_meta->current_image != ifsd->cur_batch) { 28948c6e7dcSJithu Joseph dev_warn(dev, "Mismatch between filename %s and batch metadata 0x%02x\n", 29048c6e7dcSJithu Joseph test_file, ifs_meta->current_image); 29148c6e7dcSJithu Joseph return ret; 29248c6e7dcSJithu Joseph } 29348c6e7dcSJithu Joseph 29460d2e1b3SJithu Joseph if (ifs_meta->chunks_per_stride && 29560d2e1b3SJithu Joseph (ifs_meta->starting_chunk % ifs_meta->chunks_per_stride != 0)) { 29660d2e1b3SJithu Joseph dev_warn(dev, "Starting chunk num %u not a multiple of chunks_per_stride %u\n", 29760d2e1b3SJithu Joseph ifs_meta->starting_chunk, ifs_meta->chunks_per_stride); 29860d2e1b3SJithu Joseph return ret; 29960d2e1b3SJithu Joseph } 30060d2e1b3SJithu Joseph 30148c6e7dcSJithu Joseph return 0; 30248c6e7dcSJithu Joseph } 30348c6e7dcSJithu Joseph 304684ec215SJithu Joseph /* 305684ec215SJithu Joseph * IFS requires scan chunks authenticated per each socket in the platform. 306684ec215SJithu Joseph * Once the test chunk is authenticated, it is automatically copied to secured memory 307684ec215SJithu Joseph * and proceed the authentication for the next chunk. 308684ec215SJithu Joseph */ 309684ec215SJithu Joseph static int scan_chunks_sanity_check(struct device *dev) 310684ec215SJithu Joseph { 311684ec215SJithu Joseph struct ifs_data *ifsd = ifs_get_data(dev); 312684ec215SJithu Joseph struct ifs_work local_work; 313aa63e0fdSJithu Joseph int curr_pkg, cpu, ret; 314aa63e0fdSJithu Joseph 31567f88ffaSJithu Joseph memset(ifs_pkg_auth, 0, (topology_max_packages() * sizeof(bool))); 31648c6e7dcSJithu Joseph ret = validate_ifs_metadata(dev); 31748c6e7dcSJithu Joseph if (ret) 31848c6e7dcSJithu Joseph return ret; 31948c6e7dcSJithu Joseph 320684ec215SJithu Joseph ifsd->loading_error = false; 32107f47c01SJithu Joseph 32207f47c01SJithu Joseph if (ifsd->generation > 0) 32307f47c01SJithu Joseph return copy_hashes_authenticate_chunks_gen2(dev); 324684ec215SJithu Joseph 325684ec215SJithu Joseph /* copy the scan hash and authenticate per package */ 326684ec215SJithu Joseph cpus_read_lock(); 327684ec215SJithu Joseph for_each_online_cpu(cpu) { 328684ec215SJithu Joseph curr_pkg = topology_physical_package_id(cpu); 32967f88ffaSJithu Joseph if (ifs_pkg_auth[curr_pkg]) 330684ec215SJithu Joseph continue; 331684ec215SJithu Joseph reinit_completion(&ifs_done); 332684ec215SJithu Joseph local_work.dev = dev; 3333279decbSDavid Arcari INIT_WORK_ONSTACK(&local_work.w, copy_hashes_authenticate_chunks); 334684ec215SJithu Joseph schedule_work_on(cpu, &local_work.w); 335684ec215SJithu Joseph wait_for_completion(&ifs_done); 336f4e209e9SJithu Joseph if (ifsd->loading_error) { 337f4e209e9SJithu Joseph ret = -EIO; 338684ec215SJithu Joseph goto out; 339f4e209e9SJithu Joseph } 34067f88ffaSJithu Joseph ifs_pkg_auth[curr_pkg] = 1; 341684ec215SJithu Joseph } 342684ec215SJithu Joseph ret = 0; 34307f47c01SJithu Joseph ifsd->loaded_version = ifs_header_ptr->rev; 344684ec215SJithu Joseph out: 345684ec215SJithu Joseph cpus_read_unlock(); 346684ec215SJithu Joseph 347684ec215SJithu Joseph return ret; 348684ec215SJithu Joseph } 349684ec215SJithu Joseph 350aa63e0fdSJithu Joseph static int image_sanity_check(struct device *dev, const struct microcode_header_intel *data) 351846e751fSJithu Joseph { 352164aa1caSThomas Gleixner struct cpu_signature sig; 353846e751fSJithu Joseph 354aa63e0fdSJithu Joseph /* Provide a specific error message when loading an older/unsupported image */ 355aa63e0fdSJithu Joseph if (data->hdrver != MC_HEADER_TYPE_IFS) { 356aa63e0fdSJithu Joseph dev_err(dev, "Header version %d not supported\n", data->hdrver); 357846e751fSJithu Joseph return -EINVAL; 358846e751fSJithu Joseph } 359846e751fSJithu Joseph 360aa63e0fdSJithu Joseph if (intel_microcode_sanity_check((void *)data, true, MC_HEADER_TYPE_IFS)) { 361aa63e0fdSJithu Joseph dev_err(dev, "sanity check failed\n"); 362846e751fSJithu Joseph return -EINVAL; 363846e751fSJithu Joseph } 364846e751fSJithu Joseph 365164aa1caSThomas Gleixner intel_collect_cpu_info(&sig); 366846e751fSJithu Joseph 367b7fcd995SThomas Gleixner if (!intel_find_matching_signature((void *)data, &sig)) { 368aa63e0fdSJithu Joseph dev_err(dev, "cpu signature, processor flags not matching\n"); 369846e751fSJithu Joseph return -EINVAL; 370846e751fSJithu Joseph } 371846e751fSJithu Joseph 372846e751fSJithu Joseph return 0; 373846e751fSJithu Joseph } 374846e751fSJithu Joseph 375fb57fc78SJithu Joseph /* 376fb57fc78SJithu Joseph * Load ifs image. Before loading ifs module, the ifs image must be located 3774fb858f3SJithu Joseph * in /lib/firmware/intel/ifs_x/ and named as family-model-stepping-02x.{testname}. 378fb57fc78SJithu Joseph */ 3794fb858f3SJithu Joseph int ifs_load_firmware(struct device *dev) 380fb57fc78SJithu Joseph { 38154c9fcd1SJithu Joseph const struct ifs_test_caps *test = ifs_get_test_caps(dev); 382684ec215SJithu Joseph struct ifs_data *ifsd = ifs_get_data(dev); 38325a76dbbSJithu Joseph unsigned int expected_size; 384fb57fc78SJithu Joseph const struct firmware *fw; 3854fb858f3SJithu Joseph char scan_path[64]; 386*682c259aSIlpo Järvinen int ret; 387fb57fc78SJithu Joseph 3884fb858f3SJithu Joseph snprintf(scan_path, sizeof(scan_path), "intel/ifs_%d/%02x-%02x-%02x-%02x.scan", 38954c9fcd1SJithu Joseph test->test_num, boot_cpu_data.x86, boot_cpu_data.x86_model, 3904fb858f3SJithu Joseph boot_cpu_data.x86_stepping, ifsd->cur_batch); 391fb57fc78SJithu Joseph 392fb57fc78SJithu Joseph ret = request_firmware_direct(&fw, scan_path, dev); 393fb57fc78SJithu Joseph if (ret) { 394fb57fc78SJithu Joseph dev_err(dev, "ifs file %s load failed\n", scan_path); 395684ec215SJithu Joseph goto done; 396fb57fc78SJithu Joseph } 397fb57fc78SJithu Joseph 39825a76dbbSJithu Joseph expected_size = ((struct microcode_header_intel *)fw->data)->totalsize; 39925a76dbbSJithu Joseph if (fw->size != expected_size) { 40025a76dbbSJithu Joseph dev_err(dev, "File size mismatch (expected %u, actual %zu). Corrupted IFS image.\n", 40125a76dbbSJithu Joseph expected_size, fw->size); 40225a76dbbSJithu Joseph return -EINVAL; 40325a76dbbSJithu Joseph } 40425a76dbbSJithu Joseph 405aa63e0fdSJithu Joseph ret = image_sanity_check(dev, (struct microcode_header_intel *)fw->data); 406aa63e0fdSJithu Joseph if (ret) 407684ec215SJithu Joseph goto release; 408846e751fSJithu Joseph 409aa63e0fdSJithu Joseph ifs_header_ptr = (struct microcode_header_intel *)fw->data; 410684ec215SJithu Joseph ifs_hash_ptr = (u64)(ifs_header_ptr + 1); 411684ec215SJithu Joseph 412684ec215SJithu Joseph ret = scan_chunks_sanity_check(dev); 4134fb858f3SJithu Joseph if (ret) 4144fb858f3SJithu Joseph dev_err(dev, "Load failure for batch: %02x\n", ifsd->cur_batch); 4154fb858f3SJithu Joseph 416684ec215SJithu Joseph release: 417fb57fc78SJithu Joseph release_firmware(fw); 418684ec215SJithu Joseph done: 419684ec215SJithu Joseph ifsd->loaded = (ret == 0); 4204fb858f3SJithu Joseph 4214fb858f3SJithu Joseph return ret; 422fb57fc78SJithu Joseph } 423