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; 1217e597d49SKuppuswamy Sathyanarayanan const struct ifs_test_msrs *msrs; 122684ec215SJithu Joseph int i, num_chunks, chunk_size; 123684ec215SJithu Joseph struct ifs_data *ifsd; 124684ec215SJithu Joseph u64 linear_addr, base; 125684ec215SJithu Joseph u32 err_code; 126684ec215SJithu Joseph 127684ec215SJithu Joseph ifsd = ifs_get_data(dev); 1287e597d49SKuppuswamy Sathyanarayanan msrs = ifs_get_test_msrs(dev); 129684ec215SJithu Joseph /* run scan hash copy */ 1307e597d49SKuppuswamy Sathyanarayanan wrmsrl(msrs->copy_hashes, ifs_hash_ptr); 1317e597d49SKuppuswamy Sathyanarayanan rdmsrl(msrs->copy_hashes_status, hashes_status.data); 132684ec215SJithu Joseph 133684ec215SJithu Joseph /* enumerate the scan image information */ 134684ec215SJithu Joseph num_chunks = hashes_status.num_chunks; 135684ec215SJithu Joseph chunk_size = hashes_status.chunk_size * 1024; 136684ec215SJithu Joseph err_code = hashes_status.error_code; 137684ec215SJithu Joseph 138684ec215SJithu Joseph if (!hashes_status.valid) { 139684ec215SJithu Joseph ifsd->loading_error = true; 140a138ac26SJithu Joseph hashcopy_err_message(dev, err_code); 141684ec215SJithu Joseph goto done; 142684ec215SJithu Joseph } 143684ec215SJithu Joseph 144684ec215SJithu Joseph /* base linear address to the scan data */ 145684ec215SJithu Joseph base = ifs_test_image_ptr; 146684ec215SJithu Joseph 147684ec215SJithu Joseph /* scan data authentication and copy chunks to secured memory */ 148684ec215SJithu Joseph for (i = 0; i < num_chunks; i++) { 149684ec215SJithu Joseph linear_addr = base + i * chunk_size; 150684ec215SJithu Joseph linear_addr |= i; 151684ec215SJithu Joseph 1527e597d49SKuppuswamy Sathyanarayanan wrmsrl(msrs->copy_chunks, linear_addr); 1537e597d49SKuppuswamy Sathyanarayanan rdmsrl(msrs->copy_chunks_status, chunk_status.data); 154684ec215SJithu Joseph 155684ec215SJithu Joseph ifsd->valid_chunks = chunk_status.valid_chunks; 156684ec215SJithu Joseph err_code = chunk_status.error_code; 157684ec215SJithu Joseph 158684ec215SJithu Joseph if (err_code) { 159684ec215SJithu Joseph ifsd->loading_error = true; 160a138ac26SJithu Joseph auth_err_message(dev, err_code); 161684ec215SJithu Joseph goto done; 162684ec215SJithu Joseph } 163684ec215SJithu Joseph } 164684ec215SJithu Joseph done: 165684ec215SJithu Joseph complete(&ifs_done); 166684ec215SJithu Joseph } 167684ec215SJithu Joseph 16807f47c01SJithu Joseph static int get_num_chunks(int gen, union ifs_scan_hashes_status_gen2 status) 16907f47c01SJithu Joseph { 17007f47c01SJithu Joseph return gen >= IFS_GEN_STRIDE_AWARE ? status.chunks_in_stride : status.num_chunks; 17107f47c01SJithu Joseph } 17207f47c01SJithu Joseph 17307f47c01SJithu Joseph static bool need_copy_scan_hashes(struct ifs_data *ifsd) 17407f47c01SJithu Joseph { 17507f47c01SJithu Joseph return !ifsd->loaded || 17607f47c01SJithu Joseph ifsd->generation < IFS_GEN_STRIDE_AWARE || 17707f47c01SJithu Joseph ifsd->loaded_version != ifs_header_ptr->rev; 17807f47c01SJithu Joseph } 17907f47c01SJithu Joseph 18007f47c01SJithu Joseph static int copy_hashes_authenticate_chunks_gen2(struct device *dev) 18107f47c01SJithu Joseph { 18207f47c01SJithu Joseph union ifs_scan_hashes_status_gen2 hashes_status; 18307f47c01SJithu Joseph union ifs_chunks_auth_status_gen2 chunk_status; 18407f47c01SJithu Joseph u32 err_code, valid_chunks, total_chunks; 1857e597d49SKuppuswamy Sathyanarayanan const struct ifs_test_msrs *msrs; 18607f47c01SJithu Joseph int i, num_chunks, chunk_size; 18707f47c01SJithu Joseph union meta_data *ifs_meta; 18807f47c01SJithu Joseph int starting_chunk_nr; 18907f47c01SJithu Joseph struct ifs_data *ifsd; 19007f47c01SJithu Joseph u64 linear_addr, base; 19107f47c01SJithu Joseph u64 chunk_table[2]; 19207f47c01SJithu Joseph int retry_count; 19307f47c01SJithu Joseph 19407f47c01SJithu Joseph ifsd = ifs_get_data(dev); 1957e597d49SKuppuswamy Sathyanarayanan msrs = ifs_get_test_msrs(dev); 19607f47c01SJithu Joseph 19707f47c01SJithu Joseph if (need_copy_scan_hashes(ifsd)) { 1987e597d49SKuppuswamy Sathyanarayanan wrmsrl(msrs->copy_hashes, ifs_hash_ptr); 1997e597d49SKuppuswamy Sathyanarayanan rdmsrl(msrs->copy_hashes_status, hashes_status.data); 20007f47c01SJithu Joseph 20107f47c01SJithu Joseph /* enumerate the scan image information */ 20207f47c01SJithu Joseph chunk_size = hashes_status.chunk_size * SZ_1K; 20307f47c01SJithu Joseph err_code = hashes_status.error_code; 20407f47c01SJithu Joseph 20507f47c01SJithu Joseph num_chunks = get_num_chunks(ifsd->generation, hashes_status); 20607f47c01SJithu Joseph 20707f47c01SJithu Joseph if (!hashes_status.valid) { 20807f47c01SJithu Joseph hashcopy_err_message(dev, err_code); 20907f47c01SJithu Joseph return -EIO; 21007f47c01SJithu Joseph } 21107f47c01SJithu Joseph ifsd->loaded_version = ifs_header_ptr->rev; 21207f47c01SJithu Joseph ifsd->chunk_size = chunk_size; 21307f47c01SJithu Joseph } else { 21407f47c01SJithu Joseph num_chunks = ifsd->valid_chunks; 21507f47c01SJithu Joseph chunk_size = ifsd->chunk_size; 21607f47c01SJithu Joseph } 21707f47c01SJithu Joseph 21807f47c01SJithu Joseph if (ifsd->generation >= IFS_GEN_STRIDE_AWARE) { 2197e597d49SKuppuswamy Sathyanarayanan wrmsrl(msrs->test_ctrl, INVALIDATE_STRIDE); 2207e597d49SKuppuswamy Sathyanarayanan rdmsrl(msrs->copy_chunks_status, chunk_status.data); 22107f47c01SJithu Joseph if (chunk_status.valid_chunks != 0) { 22207f47c01SJithu Joseph dev_err(dev, "Couldn't invalidate installed stride - %d\n", 22307f47c01SJithu Joseph chunk_status.valid_chunks); 22407f47c01SJithu Joseph return -EIO; 22507f47c01SJithu Joseph } 22607f47c01SJithu Joseph } 22707f47c01SJithu Joseph 22807f47c01SJithu Joseph base = ifs_test_image_ptr; 22907f47c01SJithu Joseph ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS); 23007f47c01SJithu Joseph starting_chunk_nr = ifs_meta->starting_chunk; 23107f47c01SJithu Joseph 23207f47c01SJithu Joseph /* scan data authentication and copy chunks to secured memory */ 23307f47c01SJithu Joseph for (i = 0; i < num_chunks; i++) { 23407f47c01SJithu Joseph retry_count = IFS_AUTH_RETRY_CT; 23507f47c01SJithu Joseph linear_addr = base + i * chunk_size; 23607f47c01SJithu Joseph 23707f47c01SJithu Joseph chunk_table[0] = starting_chunk_nr + i; 23807f47c01SJithu Joseph chunk_table[1] = linear_addr; 23907f47c01SJithu Joseph do { 240bd25a3f5SJithu Joseph local_irq_disable(); 2417e597d49SKuppuswamy Sathyanarayanan wrmsrl(msrs->copy_chunks, (u64)chunk_table); 242bd25a3f5SJithu Joseph local_irq_enable(); 2437e597d49SKuppuswamy Sathyanarayanan rdmsrl(msrs->copy_chunks_status, chunk_status.data); 24407f47c01SJithu Joseph err_code = chunk_status.error_code; 24507f47c01SJithu Joseph } while (err_code == AUTH_INTERRUPTED_ERROR && --retry_count); 24607f47c01SJithu Joseph 24707f47c01SJithu Joseph if (err_code) { 24807f47c01SJithu Joseph ifsd->loading_error = true; 24907f47c01SJithu Joseph auth_err_message(dev, err_code); 25007f47c01SJithu Joseph return -EIO; 25107f47c01SJithu Joseph } 25207f47c01SJithu Joseph } 25307f47c01SJithu Joseph 25407f47c01SJithu Joseph valid_chunks = chunk_status.valid_chunks; 25507f47c01SJithu Joseph total_chunks = chunk_status.total_chunks; 25607f47c01SJithu Joseph 25707f47c01SJithu Joseph if (valid_chunks != total_chunks) { 25807f47c01SJithu Joseph ifsd->loading_error = true; 25907f47c01SJithu Joseph dev_err(dev, "Couldn't authenticate all the chunks. Authenticated %d total %d.\n", 26007f47c01SJithu Joseph valid_chunks, total_chunks); 26107f47c01SJithu Joseph return -EIO; 26207f47c01SJithu Joseph } 26307f47c01SJithu Joseph ifsd->valid_chunks = valid_chunks; 264*0a3e4e94SJithu Joseph ifsd->max_bundle = chunk_status.max_bundle; 26507f47c01SJithu Joseph 26607f47c01SJithu Joseph return 0; 26707f47c01SJithu Joseph } 26807f47c01SJithu Joseph 26948c6e7dcSJithu Joseph static int validate_ifs_metadata(struct device *dev) 27048c6e7dcSJithu Joseph { 271*0a3e4e94SJithu Joseph const struct ifs_test_caps *test = ifs_get_test_caps(dev); 27248c6e7dcSJithu Joseph struct ifs_data *ifsd = ifs_get_data(dev); 27348c6e7dcSJithu Joseph union meta_data *ifs_meta; 27448c6e7dcSJithu Joseph char test_file[64]; 27548c6e7dcSJithu Joseph int ret = -EINVAL; 27648c6e7dcSJithu Joseph 277*0a3e4e94SJithu Joseph snprintf(test_file, sizeof(test_file), "%02x-%02x-%02x-%02x.%s", 27848c6e7dcSJithu Joseph boot_cpu_data.x86, boot_cpu_data.x86_model, 279*0a3e4e94SJithu Joseph boot_cpu_data.x86_stepping, ifsd->cur_batch, test->image_suffix); 28048c6e7dcSJithu Joseph 28148c6e7dcSJithu Joseph ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS); 28248c6e7dcSJithu Joseph if (!ifs_meta) { 28348c6e7dcSJithu Joseph dev_err(dev, "IFS Metadata missing in file %s\n", test_file); 28448c6e7dcSJithu Joseph return ret; 28548c6e7dcSJithu Joseph } 28648c6e7dcSJithu Joseph 28748c6e7dcSJithu Joseph ifs_test_image_ptr = (u64)ifs_meta + sizeof(union meta_data); 28848c6e7dcSJithu Joseph 28948c6e7dcSJithu Joseph /* Scan chunk start must be 256 byte aligned */ 29048c6e7dcSJithu Joseph if (!IS_ALIGNED(ifs_test_image_ptr, IFS_CHUNK_ALIGNMENT)) { 29148c6e7dcSJithu Joseph dev_err(dev, "Scan pattern is not aligned on %d bytes aligned in %s\n", 29248c6e7dcSJithu Joseph IFS_CHUNK_ALIGNMENT, test_file); 29348c6e7dcSJithu Joseph return ret; 29448c6e7dcSJithu Joseph } 29548c6e7dcSJithu Joseph 29648c6e7dcSJithu Joseph if (ifs_meta->current_image != ifsd->cur_batch) { 29748c6e7dcSJithu Joseph dev_warn(dev, "Mismatch between filename %s and batch metadata 0x%02x\n", 29848c6e7dcSJithu Joseph test_file, ifs_meta->current_image); 29948c6e7dcSJithu Joseph return ret; 30048c6e7dcSJithu Joseph } 30148c6e7dcSJithu Joseph 30260d2e1b3SJithu Joseph if (ifs_meta->chunks_per_stride && 30360d2e1b3SJithu Joseph (ifs_meta->starting_chunk % ifs_meta->chunks_per_stride != 0)) { 30460d2e1b3SJithu Joseph dev_warn(dev, "Starting chunk num %u not a multiple of chunks_per_stride %u\n", 30560d2e1b3SJithu Joseph ifs_meta->starting_chunk, ifs_meta->chunks_per_stride); 30660d2e1b3SJithu Joseph return ret; 30760d2e1b3SJithu Joseph } 30860d2e1b3SJithu Joseph 309*0a3e4e94SJithu Joseph if (ifs_meta->test_type != test->test_num) { 310*0a3e4e94SJithu Joseph dev_warn(dev, "Metadata test_type %d mismatches with device type\n", 311*0a3e4e94SJithu Joseph ifs_meta->test_type); 312*0a3e4e94SJithu Joseph return ret; 313*0a3e4e94SJithu Joseph } 314*0a3e4e94SJithu Joseph 31548c6e7dcSJithu Joseph return 0; 31648c6e7dcSJithu Joseph } 31748c6e7dcSJithu Joseph 318684ec215SJithu Joseph /* 319684ec215SJithu Joseph * IFS requires scan chunks authenticated per each socket in the platform. 320684ec215SJithu Joseph * Once the test chunk is authenticated, it is automatically copied to secured memory 321684ec215SJithu Joseph * and proceed the authentication for the next chunk. 322684ec215SJithu Joseph */ 323684ec215SJithu Joseph static int scan_chunks_sanity_check(struct device *dev) 324684ec215SJithu Joseph { 325684ec215SJithu Joseph struct ifs_data *ifsd = ifs_get_data(dev); 326684ec215SJithu Joseph struct ifs_work local_work; 327aa63e0fdSJithu Joseph int curr_pkg, cpu, ret; 328aa63e0fdSJithu Joseph 32967f88ffaSJithu Joseph memset(ifs_pkg_auth, 0, (topology_max_packages() * sizeof(bool))); 33048c6e7dcSJithu Joseph ret = validate_ifs_metadata(dev); 33148c6e7dcSJithu Joseph if (ret) 33248c6e7dcSJithu Joseph return ret; 33348c6e7dcSJithu Joseph 334684ec215SJithu Joseph ifsd->loading_error = false; 33507f47c01SJithu Joseph 33607f47c01SJithu Joseph if (ifsd->generation > 0) 33707f47c01SJithu Joseph return copy_hashes_authenticate_chunks_gen2(dev); 338684ec215SJithu Joseph 339684ec215SJithu Joseph /* copy the scan hash and authenticate per package */ 340684ec215SJithu Joseph cpus_read_lock(); 341684ec215SJithu Joseph for_each_online_cpu(cpu) { 342684ec215SJithu Joseph curr_pkg = topology_physical_package_id(cpu); 34367f88ffaSJithu Joseph if (ifs_pkg_auth[curr_pkg]) 344684ec215SJithu Joseph continue; 345684ec215SJithu Joseph reinit_completion(&ifs_done); 346684ec215SJithu Joseph local_work.dev = dev; 3473279decbSDavid Arcari INIT_WORK_ONSTACK(&local_work.w, copy_hashes_authenticate_chunks); 348684ec215SJithu Joseph schedule_work_on(cpu, &local_work.w); 349684ec215SJithu Joseph wait_for_completion(&ifs_done); 350f4e209e9SJithu Joseph if (ifsd->loading_error) { 351f4e209e9SJithu Joseph ret = -EIO; 352684ec215SJithu Joseph goto out; 353f4e209e9SJithu Joseph } 35467f88ffaSJithu Joseph ifs_pkg_auth[curr_pkg] = 1; 355684ec215SJithu Joseph } 356684ec215SJithu Joseph ret = 0; 35707f47c01SJithu Joseph ifsd->loaded_version = ifs_header_ptr->rev; 358684ec215SJithu Joseph out: 359684ec215SJithu Joseph cpus_read_unlock(); 360684ec215SJithu Joseph 361684ec215SJithu Joseph return ret; 362684ec215SJithu Joseph } 363684ec215SJithu Joseph 364aa63e0fdSJithu Joseph static int image_sanity_check(struct device *dev, const struct microcode_header_intel *data) 365846e751fSJithu Joseph { 366164aa1caSThomas Gleixner struct cpu_signature sig; 367846e751fSJithu Joseph 368aa63e0fdSJithu Joseph /* Provide a specific error message when loading an older/unsupported image */ 369aa63e0fdSJithu Joseph if (data->hdrver != MC_HEADER_TYPE_IFS) { 370aa63e0fdSJithu Joseph dev_err(dev, "Header version %d not supported\n", data->hdrver); 371846e751fSJithu Joseph return -EINVAL; 372846e751fSJithu Joseph } 373846e751fSJithu Joseph 374aa63e0fdSJithu Joseph if (intel_microcode_sanity_check((void *)data, true, MC_HEADER_TYPE_IFS)) { 375aa63e0fdSJithu Joseph dev_err(dev, "sanity check failed\n"); 376846e751fSJithu Joseph return -EINVAL; 377846e751fSJithu Joseph } 378846e751fSJithu Joseph 379164aa1caSThomas Gleixner intel_collect_cpu_info(&sig); 380846e751fSJithu Joseph 381b7fcd995SThomas Gleixner if (!intel_find_matching_signature((void *)data, &sig)) { 382aa63e0fdSJithu Joseph dev_err(dev, "cpu signature, processor flags not matching\n"); 383846e751fSJithu Joseph return -EINVAL; 384846e751fSJithu Joseph } 385846e751fSJithu Joseph 386846e751fSJithu Joseph return 0; 387846e751fSJithu Joseph } 388846e751fSJithu Joseph 389fb57fc78SJithu Joseph /* 390fb57fc78SJithu Joseph * Load ifs image. Before loading ifs module, the ifs image must be located 3914fb858f3SJithu Joseph * in /lib/firmware/intel/ifs_x/ and named as family-model-stepping-02x.{testname}. 392fb57fc78SJithu Joseph */ 3934fb858f3SJithu Joseph int ifs_load_firmware(struct device *dev) 394fb57fc78SJithu Joseph { 39554c9fcd1SJithu Joseph const struct ifs_test_caps *test = ifs_get_test_caps(dev); 396684ec215SJithu Joseph struct ifs_data *ifsd = ifs_get_data(dev); 39725a76dbbSJithu Joseph unsigned int expected_size; 398fb57fc78SJithu Joseph const struct firmware *fw; 3994fb858f3SJithu Joseph char scan_path[64]; 400682c259aSIlpo Järvinen int ret; 401fb57fc78SJithu Joseph 402*0a3e4e94SJithu Joseph snprintf(scan_path, sizeof(scan_path), "intel/ifs_%d/%02x-%02x-%02x-%02x.%s", 40354c9fcd1SJithu Joseph test->test_num, boot_cpu_data.x86, boot_cpu_data.x86_model, 404*0a3e4e94SJithu Joseph boot_cpu_data.x86_stepping, ifsd->cur_batch, test->image_suffix); 405fb57fc78SJithu Joseph 406fb57fc78SJithu Joseph ret = request_firmware_direct(&fw, scan_path, dev); 407fb57fc78SJithu Joseph if (ret) { 408fb57fc78SJithu Joseph dev_err(dev, "ifs file %s load failed\n", scan_path); 409684ec215SJithu Joseph goto done; 410fb57fc78SJithu Joseph } 411fb57fc78SJithu Joseph 41225a76dbbSJithu Joseph expected_size = ((struct microcode_header_intel *)fw->data)->totalsize; 41325a76dbbSJithu Joseph if (fw->size != expected_size) { 41425a76dbbSJithu Joseph dev_err(dev, "File size mismatch (expected %u, actual %zu). Corrupted IFS image.\n", 41525a76dbbSJithu Joseph expected_size, fw->size); 4168c898ec0SJithu Joseph ret = -EINVAL; 4178c898ec0SJithu Joseph goto release; 41825a76dbbSJithu Joseph } 41925a76dbbSJithu Joseph 420aa63e0fdSJithu Joseph ret = image_sanity_check(dev, (struct microcode_header_intel *)fw->data); 421aa63e0fdSJithu Joseph if (ret) 422684ec215SJithu Joseph goto release; 423846e751fSJithu Joseph 424aa63e0fdSJithu Joseph ifs_header_ptr = (struct microcode_header_intel *)fw->data; 425684ec215SJithu Joseph ifs_hash_ptr = (u64)(ifs_header_ptr + 1); 426684ec215SJithu Joseph 427684ec215SJithu Joseph ret = scan_chunks_sanity_check(dev); 4284fb858f3SJithu Joseph if (ret) 4294fb858f3SJithu Joseph dev_err(dev, "Load failure for batch: %02x\n", ifsd->cur_batch); 4304fb858f3SJithu Joseph 431684ec215SJithu Joseph release: 432fb57fc78SJithu Joseph release_firmware(fw); 433684ec215SJithu Joseph done: 434684ec215SJithu Joseph ifsd->loaded = (ret == 0); 4354fb858f3SJithu Joseph 4364fb858f3SJithu Joseph return ret; 437fb57fc78SJithu Joseph } 438