From 1f7e25db5d244c3435051721b5f6b7dda2b808a0 Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Fri, 6 May 2022 15:53:59 -0700 Subject: [PATCH 01/14] x86/microcode/intel: Expose collect_cpu_info_early() for IFS mainline inclusion from mainline-v5.19-rc1 commit d3287fb0d3c8afdfd4870a6cd4a852abc9008b3b category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=d3287fb0d3c8afdfd4870a6cd4a852abc9008b3b Intel-SIG: commit d3287fb0d3c8 ("x86/microcode/intel: Expose collect_cpu_info_early() for IFS") ------------------------------------- x86/microcode/intel: Expose collect_cpu_info_early() for IFS IFS is a CPU feature that allows a binary blob, similar to microcode, to be loaded and consumed to perform low level validation of CPU circuitry. In fact, it carries the same Processor Signature (family/model/stepping) details that are contained in Intel microcode blobs. In support of an IFS driver to trigger loading, validation, and running of these tests blobs, make the functionality of cpu_signatures_match() and collect_cpu_info_early() available outside of the microcode driver. Add an "intel_" prefix and drop the "_early" suffix from collect_cpu_info_early() and EXPORT_SYMBOL_GPL() it. Add declaration to x86 Make cpu_signatures_match() an inline function in x86 , and also give it an "intel_" prefix. No functional change intended. Reviewed-by: Dan Williams Signed-off-by: Jithu Joseph Co-developed-by: Tony Luck Signed-off-by: Tony Luck Reviewed-by: Thomas Gleixner Acked-by: Borislav Petkov Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20220506225410.1652287-2-tony.luck@intel.com Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- arch/x86/include/asm/cpu.h | 19 +++++++++ arch/x86/kernel/cpu/intel.c | 32 +++++++++++++++ arch/x86/kernel/cpu/microcode/intel.c | 59 ++++----------------------- 3 files changed, 58 insertions(+), 52 deletions(-) diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 0d7fc0e2bfc9..c12681677d03 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -66,4 +66,23 @@ void init_ia32_feat_ctl(struct cpuinfo_x86 *c); #else static inline void init_ia32_feat_ctl(struct cpuinfo_x86 *c) {} #endif + +struct ucode_cpu_info; + +int intel_cpu_collect_info(struct ucode_cpu_info *uci); + +static inline bool intel_cpu_signatures_match(unsigned int s1, unsigned int p1, + unsigned int s2, unsigned int p2) +{ + if (s1 != s2) + return false; + + /* Processor flags are either both 0 ... */ + if (!p1 && !p2) + return true; + + /* ... or they intersect. */ + return p1 & p2; +} + #endif /* _ASM_X86_CPU_H */ diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 5c5a2c6d5d4d..c83f9658feb2 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -181,6 +181,38 @@ static bool bad_spectre_microcode(struct cpuinfo_x86 *c) return false; } +int intel_cpu_collect_info(struct ucode_cpu_info *uci) +{ + unsigned int val[2]; + unsigned int family, model; + struct cpu_signature csig = { 0 }; + unsigned int eax, ebx, ecx, edx; + + memset(uci, 0, sizeof(*uci)); + + eax = 0x00000001; + ecx = 0; + native_cpuid(&eax, &ebx, &ecx, &edx); + csig.sig = eax; + + family = x86_family(eax); + model = x86_model(eax); + + if (model >= 5 || family > 6) { + /* get processor flags from MSR 0x17 */ + native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); + csig.pf = 1 << ((val[1] >> 18) & 7); + } + + csig.rev = intel_get_microcode_revision(); + + uci->cpu_sig = csig; + uci->valid = 1; + + return 0; +} +EXPORT_SYMBOL_GPL(intel_cpu_collect_info); + static void early_init_intel(struct cpuinfo_x86 *c) { u64 misc_enable; diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 7e8e07bddd5f..3fc03db929f2 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -45,20 +45,6 @@ static struct microcode_intel *intel_ucode_patch; /* last level cache size per core */ static int llc_size_per_core; -static inline bool cpu_signatures_match(unsigned int s1, unsigned int p1, - unsigned int s2, unsigned int p2) -{ - if (s1 != s2) - return false; - - /* Processor flags are either both 0 ... */ - if (!p1 && !p2) - return true; - - /* ... or they intersect. */ - return p1 & p2; -} - /* * Returns 1 if update has been found, 0 otherwise. */ @@ -69,7 +55,7 @@ static int find_matching_signature(void *mc, unsigned int csig, int cpf) struct extended_signature *ext_sig; int i; - if (cpu_signatures_match(csig, cpf, mc_hdr->sig, mc_hdr->pf)) + if (intel_cpu_signatures_match(csig, cpf, mc_hdr->sig, mc_hdr->pf)) return 1; /* Look for ext. headers: */ @@ -80,7 +66,7 @@ static int find_matching_signature(void *mc, unsigned int csig, int cpf) ext_sig = (void *)ext_hdr + EXT_HEADER_SIZE; for (i = 0; i < ext_hdr->count; i++) { - if (cpu_signatures_match(csig, cpf, ext_sig->sig, ext_sig->pf)) + if (intel_cpu_signatures_match(csig, cpf, ext_sig->sig, ext_sig->pf)) return 1; ext_sig++; } @@ -342,37 +328,6 @@ scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save) return patch; } -static int collect_cpu_info_early(struct ucode_cpu_info *uci) -{ - unsigned int val[2]; - unsigned int family, model; - struct cpu_signature csig = { 0 }; - unsigned int eax, ebx, ecx, edx; - - memset(uci, 0, sizeof(*uci)); - - eax = 0x00000001; - ecx = 0; - native_cpuid(&eax, &ebx, &ecx, &edx); - csig.sig = eax; - - family = x86_family(eax); - model = x86_model(eax); - - if ((model >= 5) || (family > 6)) { - /* get processor flags from MSR 0x17 */ - native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); - csig.pf = 1 << ((val[1] >> 18) & 7); - } - - csig.rev = intel_get_microcode_revision(); - - uci->cpu_sig = csig; - uci->valid = 1; - - return 0; -} - static void show_saved_mc(void) { #ifdef DEBUG @@ -386,7 +341,7 @@ static void show_saved_mc(void) return; } - collect_cpu_info_early(&uci); + intel_cpu_collect_info(&uci); sig = uci.cpu_sig.sig; pf = uci.cpu_sig.pf; @@ -495,7 +450,7 @@ void show_ucode_info_early(void) struct ucode_cpu_info uci; if (delay_ucode_info) { - collect_cpu_info_early(&uci); + intel_cpu_collect_info(&uci); print_ucode_info(&uci, current_mc_date); delay_ucode_info = 0; } @@ -597,7 +552,7 @@ int __init save_microcode_in_initrd_intel(void) if (!(cp.data && cp.size)) return 0; - collect_cpu_info_early(&uci); + intel_cpu_collect_info(&uci); scan_microcode(cp.data, cp.size, &uci, true); @@ -630,7 +585,7 @@ static struct microcode_intel *__load_ucode_intel(struct ucode_cpu_info *uci) if (!(cp.data && cp.size)) return NULL; - collect_cpu_info_early(uci); + intel_cpu_collect_info(uci); return scan_microcode(cp.data, cp.size, uci, false); } @@ -705,7 +660,7 @@ void reload_ucode_intel(void) struct microcode_intel *p; struct ucode_cpu_info uci; - collect_cpu_info_early(&uci); + intel_cpu_collect_info(&uci); p = find_patch(&uci); if (!p) -- Gitee From 2f2752ed9e14189ef7d136e717091db57cbbca6a Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 6 May 2022 15:54:00 -0700 Subject: [PATCH 02/14] x86/msr-index: Define INTEGRITY_CAPABILITIES MSR mainline inclusion from mainline-v5.19-rc1 commit db1af12929c99d15fc04cc5c4447b87ab51eab0a category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=db1af12929c99d15fc04cc5c4447b87ab51eab0a Intel-SIG: commit db1af12929c9 ("x86/msr-index: Define INTEGRITY_CAPABILITIES MSR") ------------------------------------- x86/msr-index: Define INTEGRITY_CAPABILITIES MSR The INTEGRITY_CAPABILITIES MSR is enumerated by bit 2 of the CORE_CAPABILITIES MSR. Add defines for the CORE_CAPS enumeration as well as for the integrity MSR. Reviewed-by: Dan Williams Signed-off-by: Tony Luck Reviewed-by: Greg Kroah-Hartman Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/20220506225410.1652287-3-tony.luck@intel.com Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- arch/x86/include/asm/msr-index.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index b727107178af..ab58529f5928 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -78,6 +78,8 @@ /* Abbreviated from Intel SDM name IA32_CORE_CAPABILITIES */ #define MSR_IA32_CORE_CAPS 0x000000cf +#define MSR_IA32_CORE_CAPS_INTEGRITY_CAPS_BIT 2 +#define MSR_IA32_CORE_CAPS_INTEGRITY_CAPS BIT(MSR_IA32_CORE_CAPS_INTEGRITY_CAPS_BIT) #define MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT_BIT 5 #define MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT BIT(MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT_BIT) @@ -192,6 +194,11 @@ #define MSR_IA32_POWER_CTL 0x000001fc #define MSR_IA32_POWER_CTL_BIT_EE 19 +/* Abbreviated from Intel SDM name IA32_INTEGRITY_CAPABILITIES */ +#define MSR_INTEGRITY_CAPS 0x000002d9 +#define MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT 4 +#define MSR_INTEGRITY_CAPS_PERIODIC_BIST BIT(MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT) + #define MSR_LBR_NHM_FROM 0x00000680 #define MSR_LBR_NHM_TO 0x000006c0 #define MSR_LBR_CORE_FROM 0x00000040 -- Gitee From 1e9666c97c1224235c0de2605d969d218bdfabef Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 6 May 2022 15:54:01 -0700 Subject: [PATCH 03/14] stop_machine: Add stop_core_cpuslocked() for per-core operations mainline inclusion from mainline-v5.19-rc1 commit 2760f5a415c3b86c6394738c6cff740c8b4ce664 category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=2760f5a415c3b86c6394738c6cff740c8b4ce664 Intel-SIG: commit 2760f5a415c3 ("stop_machine: Add stop_core_cpuslocked() for per-core operations") ------------------------------------- stop_machine: Add stop_core_cpuslocked() for per-core operations Hardware core level testing features require near simultaneous execution of WRMSR instructions on all threads of a core to initiate a test. Provide a customized cut down version of stop_machine_cpuslocked() that just operates on the threads of a single core. Suggested-by: Thomas Gleixner Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Tony Luck Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/20220506225410.1652287-4-tony.luck@intel.com Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- include/linux/stop_machine.h | 16 ++++++++++++++++ kernel/stop_machine.c | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h index 08ec8e2fd9b2..2959b9e52af4 100644 --- a/include/linux/stop_machine.h +++ b/include/linux/stop_machine.h @@ -121,6 +121,22 @@ int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus); */ int stop_machine_cpuslocked(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus); +/** + * stop_core_cpuslocked: - stop all threads on just one core + * @cpu: any cpu in the targeted core + * @fn: the function to run + * @data: the data ptr for @fn() + * + * Same as above, but instead of every CPU, only the logical CPUs of a + * single core are affected. + * + * Context: Must be called from within a cpus_read_lock() protected region. + * + * Return: 0 if all executions of @fn returned 0, any non zero return + * value if any returned non zero. + */ +int stop_core_cpuslocked(unsigned int cpu, cpu_stop_fn_t fn, void *data); + int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus); #else /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */ diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index dd5aeddbed5d..d0bf6da49322 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -624,6 +624,27 @@ int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus) } EXPORT_SYMBOL_GPL(stop_machine); +#ifdef CONFIG_SCHED_SMT +int stop_core_cpuslocked(unsigned int cpu, cpu_stop_fn_t fn, void *data) +{ + const struct cpumask *smt_mask = cpu_smt_mask(cpu); + + struct multi_stop_data msdata = { + .fn = fn, + .data = data, + .num_threads = cpumask_weight(smt_mask), + .active_cpus = smt_mask, + }; + + lockdep_assert_cpus_held(); + + /* Set the initial state and stop all online cpus. */ + set_state(&msdata, MULTI_STOP_PREPARE); + return stop_cpus(smt_mask, multi_cpu_stop, &msdata); +} +EXPORT_SYMBOL_GPL(stop_core_cpuslocked); +#endif + /** * stop_machine_from_inactive_cpu - stop_machine() from inactive CPU * @fn: the function to run -- Gitee From 67588c071e360be7f9529237611aec5c0a50ec19 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 6 May 2022 15:54:02 -0700 Subject: [PATCH 04/14] platform/x86/intel/ifs: Add stub driver for In-Field Scan mainline inclusion from mainline-v5.19-rc1 commit 67896ef13c4db88082a914e96d958044cd3392e8 category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=67896ef13c4db88082a914e96d958044cd3392e8 Intel-SIG: commit 67896ef13c4d ("platform/x86/intel/ifs: Add stub driver for In-Field Scan") ------------------------------------- platform/x86/intel/ifs: Add stub driver for In-Field Scan Cloud Service Providers that operate fleets of servers have reported [1] occasions where they can detect that a CPU has gone bad due to effects like electromigration, or isolated manufacturing defects. However, that detection method is A/B testing seemingly random application failures looking for a pattern. In-Field Scan (IFS) is a driver for a platform capability to load a crafted 'scan image' to run targeted low level diagnostics outside of the CPU's architectural error detection capabilities. Stub version of driver just does initial part of check for the IFS feature. MSR_IA32_CORE_CAPS must enumerate the presence of the MSR_INTEGRITY_CAPS MSR. [1]: https://www.youtube.com/watch?v=QMF3rqhjYuM Reviewed-by: Dan Williams Signed-off-by: Tony Luck Acked-by: Hans de Goede Reviewed-by: Greg Kroah-Hartman Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/20220506225410.1652287-5-tony.luck@intel.com Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- MAINTAINERS | 7 ++++ drivers/platform/x86/Kconfig | 2 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel/ifs/Kconfig | 13 +++++++ drivers/platform/x86/intel/ifs/Makefile | 3 ++ drivers/platform/x86/intel/ifs/core.c | 48 +++++++++++++++++++++++++ 6 files changed, 74 insertions(+) create mode 100644 drivers/platform/x86/intel/ifs/Kconfig create mode 100644 drivers/platform/x86/intel/ifs/Makefile create mode 100644 drivers/platform/x86/intel/ifs/core.c diff --git a/MAINTAINERS b/MAINTAINERS index bb290c569c73..71cbeae822a6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8966,6 +8966,13 @@ B: https://bugzilla.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git F: drivers/idle/intel_idle.c +INTEL IN FIELD SCAN (IFS) DEVICE +M: Jithu Joseph +R: Ashok Raj +R: Tony Luck +S: Maintained +F: drivers/platform/x86/intel/ifs + INTEL INTEGRATED SENSOR HUB DRIVER M: Srinivas Pandruvada M: Jiri Kosina diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 0045aa34087c..af7a36f79410 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -16,6 +16,8 @@ menuconfig X86_PLATFORM_DEVICES if X86_PLATFORM_DEVICES +source "drivers/platform/x86/intel/ifs/Kconfig" + config ACPI_WMI tristate "WMI" depends on ACPI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index a20115785b81..16b08d1683b0 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -83,6 +83,7 @@ obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o +obj-$(CONFIG_INTEL_IFS) += intel/ifs/ # Microsoft obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o diff --git a/drivers/platform/x86/intel/ifs/Kconfig b/drivers/platform/x86/intel/ifs/Kconfig new file mode 100644 index 000000000000..d84491cfb0db --- /dev/null +++ b/drivers/platform/x86/intel/ifs/Kconfig @@ -0,0 +1,13 @@ +config INTEL_IFS + tristate "Intel In Field Scan" + depends on X86 && 64BIT && SMP + select INTEL_IFS_DEVICE + help + Enable support for the In Field Scan capability in select + CPUs. The capability allows for running low level tests via + a scan image distributed by Intel via Github to validate CPU + operation beyond baseline RAS capabilities. To compile this + support as a module, choose M here. The module will be called + intel_ifs. + + If unsure, say N. diff --git a/drivers/platform/x86/intel/ifs/Makefile b/drivers/platform/x86/intel/ifs/Makefile new file mode 100644 index 000000000000..af904880e959 --- /dev/null +++ b/drivers/platform/x86/intel/ifs/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_INTEL_IFS) += intel_ifs.o + +intel_ifs-objs := core.o diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c new file mode 100644 index 000000000000..e3623ac691b5 --- /dev/null +++ b/drivers/platform/x86/intel/ifs/core.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2022 Intel Corporation. */ + +#include +#include + +#include + +#define X86_MATCH(model) \ + X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \ + INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, NULL) + +static const struct x86_cpu_id ifs_cpu_ids[] __initconst = { + X86_MATCH(SAPPHIRERAPIDS_X), + {} +}; +MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids); + +static int __init ifs_init(void) +{ + const struct x86_cpu_id *m; + u64 msrval; + + m = x86_match_cpu(ifs_cpu_ids); + if (!m) + return -ENODEV; + + if (rdmsrl_safe(MSR_IA32_CORE_CAPS, &msrval)) + return -ENODEV; + + if (!(msrval & MSR_IA32_CORE_CAPS_INTEGRITY_CAPS)) + return -ENODEV; + + if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval)) + return -ENODEV; + + return 0; +} + +static void __exit ifs_exit(void) +{ +} + +module_init(ifs_init); +module_exit(ifs_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Intel In Field Scan (IFS) device"); -- Gitee From d731e7d2cee816126759eec6f08b5cca1cafb88b Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Fri, 6 May 2022 15:54:03 -0700 Subject: [PATCH 05/14] platform/x86/intel/ifs: Read IFS firmware image mainline inclusion from mainline-v5.19-rc1 commit fb57fc785ed3b71a3e8188d4914471bd1360bc53 category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=fb57fc785ed3b71a3e8188d4914471bd1360bc53 Intel-SIG: commit fb57fc785ed3 ("platform/x86/intel/ifs: Read IFS firmware image") ------------------------------------- platform/x86/intel/ifs: Read IFS firmware image Driver probe routine allocates structure to communicate status and parameters between functions in the driver. Also call load_ifs_binary() to load the scan image file. There is a separate scan image file for each processor family, model, stepping combination. This is read from the static path: /lib/firmware/intel/ifs/{ff-mm-ss}.scan Step 1 in loading is to generate the correct path and use request_firmware_direct() to load into memory. Subsequent patches will use the IFS MSR interfaces to copy the image to BIOS reserved memory and validate the SHA256 checksums. Reviewed-by: Dan Williams Signed-off-by: Jithu Joseph Co-developed-by: Tony Luck Signed-off-by: Tony Luck Acked-by: Hans de Goede Reviewed-by: Greg Kroah-Hartman Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/20220506225410.1652287-6-tony.luck@intel.com Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- drivers/platform/x86/intel/ifs/Makefile | 2 +- drivers/platform/x86/intel/ifs/core.c | 22 ++++++++++++++++++- drivers/platform/x86/intel/ifs/ifs.h | 25 ++++++++++++++++++++++ drivers/platform/x86/intel/ifs/load.c | 28 +++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 drivers/platform/x86/intel/ifs/ifs.h create mode 100644 drivers/platform/x86/intel/ifs/load.c diff --git a/drivers/platform/x86/intel/ifs/Makefile b/drivers/platform/x86/intel/ifs/Makefile index af904880e959..98b6fde15689 100644 --- a/drivers/platform/x86/intel/ifs/Makefile +++ b/drivers/platform/x86/intel/ifs/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_INTEL_IFS) += intel_ifs.o -intel_ifs-objs := core.o +intel_ifs-objs := core.o load.o diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c index e3623ac691b5..f62578dae8e9 100644 --- a/drivers/platform/x86/intel/ifs/core.c +++ b/drivers/platform/x86/intel/ifs/core.c @@ -6,6 +6,8 @@ #include +#include "ifs.h" + #define X86_MATCH(model) \ X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \ INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, NULL) @@ -16,6 +18,17 @@ static const struct x86_cpu_id ifs_cpu_ids[] __initconst = { }; MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids); +static struct ifs_device ifs_device = { + .data = { + .integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT, + }, + .misc = { + .name = "intel_ifs_0", + .nodename = "intel_ifs/0", + .minor = MISC_DYNAMIC_MINOR, + }, +}; + static int __init ifs_init(void) { const struct x86_cpu_id *m; @@ -34,11 +47,18 @@ static int __init ifs_init(void) if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval)) return -ENODEV; - return 0; + if ((msrval & BIT(ifs_device.data.integrity_cap_bit)) && + !misc_register(&ifs_device.misc)) { + ifs_load_firmware(ifs_device.misc.this_device); + return 0; + } + + return -ENODEV; } static void __exit ifs_exit(void) { + misc_deregister(&ifs_device.misc); } module_init(ifs_init); diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h new file mode 100644 index 000000000000..9d151324ae83 --- /dev/null +++ b/drivers/platform/x86/intel/ifs/ifs.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright(c) 2022 Intel Corporation. */ + +#ifndef _IFS_H_ +#define _IFS_H_ + +#include +#include + +/** + * struct ifs_data - attributes related to intel IFS driver + * @integrity_cap_bit: MSR_INTEGRITY_CAPS bit enumerating this test + */ +struct ifs_data { + int integrity_cap_bit; +}; + +struct ifs_device { + struct ifs_data data; + struct miscdevice misc; +}; + +void ifs_load_firmware(struct device *dev); + +#endif diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c new file mode 100644 index 000000000000..9fb71d38c819 --- /dev/null +++ b/drivers/platform/x86/intel/ifs/load.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2022 Intel Corporation. */ + +#include + +#include "ifs.h" + +/* + * Load ifs image. Before loading ifs module, the ifs image must be located + * in /lib/firmware/intel/ifs and named as {family/model/stepping}.{testname}. + */ +void ifs_load_firmware(struct device *dev) +{ + const struct firmware *fw; + char scan_path[32]; + int ret; + + snprintf(scan_path, sizeof(scan_path), "intel/ifs/%02x-%02x-%02x.scan", + boot_cpu_data.x86, boot_cpu_data.x86_model, boot_cpu_data.x86_stepping); + + ret = request_firmware_direct(&fw, scan_path, dev); + if (ret) { + dev_err(dev, "ifs file %s load failed\n", scan_path); + return; + } + + release_firmware(fw); +} -- Gitee From 475a6badcfcd14a1e51edc1324baba1dd0f3652e Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Fri, 6 May 2022 15:54:04 -0700 Subject: [PATCH 06/14] platform/x86/intel/ifs: Check IFS Image sanity mainline inclusion from mainline-v5.19-rc1 commit 846e751ff37e8ab2d161de04314435f9c1d729ca category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=846e751ff37e8ab2d161de04314435f9c1d729ca Intel-SIG: commit 846e751ff37e ("platform/x86/intel/ifs: Check IFS Image sanity") ------------------------------------- platform/x86/intel/ifs: Check IFS Image sanity IFS image is designed specifically for a given family, model and stepping of the processor. Like Intel microcode header, the IFS image has the Processor Signature, Checksum and Processor Flags that must be matched with the information returned by the CPUID. Reviewed-by: Dan Williams Signed-off-by: Jithu Joseph Co-developed-by: Tony Luck Signed-off-by: Tony Luck Acked-by: Hans de Goede Reviewed-by: Greg Kroah-Hartman Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/20220506225410.1652287-7-tony.luck@intel.com Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- drivers/platform/x86/intel/ifs/load.c | 66 +++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c index 9fb71d38c819..cfbf62494c89 100644 --- a/drivers/platform/x86/intel/ifs/load.c +++ b/drivers/platform/x86/intel/ifs/load.c @@ -2,9 +2,72 @@ /* Copyright(c) 2022 Intel Corporation. */ #include +#include +#include #include "ifs.h" +static int ifs_sanity_check(struct device *dev, + const struct microcode_header_intel *mc_header) +{ + unsigned long total_size, data_size; + u32 sum, *mc; + + total_size = get_totalsize(mc_header); + data_size = get_datasize(mc_header); + + if ((data_size + MC_HEADER_SIZE > total_size) || (total_size % sizeof(u32))) { + dev_err(dev, "bad ifs data file size.\n"); + return -EINVAL; + } + + if (mc_header->ldrver != 1 || mc_header->hdrver != 1) { + dev_err(dev, "invalid/unknown ifs update format.\n"); + return -EINVAL; + } + + mc = (u32 *)mc_header; + sum = 0; + for (int i = 0; i < total_size / sizeof(u32); i++) + sum += mc[i]; + + if (sum) { + dev_err(dev, "bad ifs data checksum, aborting.\n"); + return -EINVAL; + } + + return 0; +} + +static bool find_ifs_matching_signature(struct device *dev, struct ucode_cpu_info *uci, + const struct microcode_header_intel *shdr) +{ + unsigned int mc_size; + + mc_size = get_totalsize(shdr); + + if (!mc_size || ifs_sanity_check(dev, shdr) < 0) { + dev_err(dev, "ifs sanity check failure\n"); + return false; + } + + if (!intel_cpu_signatures_match(uci->cpu_sig.sig, uci->cpu_sig.pf, shdr->sig, shdr->pf)) { + dev_err(dev, "ifs signature, pf not matching\n"); + return false; + } + + return true; +} + +static bool ifs_image_sanity_check(struct device *dev, const struct microcode_header_intel *data) +{ + struct ucode_cpu_info uci; + + intel_cpu_collect_info(&uci); + + return find_ifs_matching_signature(dev, &uci, data); +} + /* * Load ifs image. Before loading ifs module, the ifs image must be located * in /lib/firmware/intel/ifs and named as {family/model/stepping}.{testname}. @@ -24,5 +87,8 @@ void ifs_load_firmware(struct device *dev) return; } + if (!ifs_image_sanity_check(dev, (struct microcode_header_intel *)fw->data)) + dev_err(dev, "ifs header sanity check failed\n"); + release_firmware(fw); } -- Gitee From d411d129dc3cd777194d9736d1ebb43003648bee Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Fri, 6 May 2022 15:54:05 -0700 Subject: [PATCH 07/14] platform/x86/intel/ifs: Authenticate and copy to secured memory mainline inclusion from mainline-v5.19-rc1 commit 684ec215706d449f78da232aae125c0bc14f22a9 category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=684ec215706d449f78da232aae125c0bc14f22a9 Intel-SIG: commit 684ec215706d ("platform/x86/intel/ifs: Authenticate and copy to secured memory") ------------------------------------- platform/x86/intel/ifs: Authenticate and copy to secured memory The IFS image contains hashes that will be used to authenticate the ifs test chunks. First, use WRMSR to copy the hashes and enumerate the number of test chunks, chunk size and the maximum number of cores that can run scan test simultaneously. Next, use WRMSR to authenticate each and every scan test chunk which is stored in the IFS image. The CPU will check if the test chunks match the hashes, otherwise failure is indicated to system software. If the test chunk is authenticated, it is automatically copied to secured memory. Use schedule_work_on() to perform the hash copy and authentication. Note this needs only be done on the first logical cpu of each socket. Reviewed-by: Dan Williams Signed-off-by: Jithu Joseph Co-developed-by: Tony Luck Signed-off-by: Tony Luck Acked-by: Hans de Goede Reviewed-by: Greg Kroah-Hartman Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/20220506225410.1652287-8-tony.luck@intel.com Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- drivers/platform/x86/intel/ifs/ifs.h | 52 ++++++++ drivers/platform/x86/intel/ifs/load.c | 176 +++++++++++++++++++++++++- 2 files changed, 226 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h index 9d151324ae83..bed70dc1e5b7 100644 --- a/drivers/platform/x86/intel/ifs/ifs.h +++ b/drivers/platform/x86/intel/ifs/ifs.h @@ -7,12 +7,56 @@ #include #include +#define MSR_COPY_SCAN_HASHES 0x000002c2 +#define MSR_SCAN_HASHES_STATUS 0x000002c3 +#define MSR_AUTHENTICATE_AND_COPY_CHUNK 0x000002c4 +#define MSR_CHUNKS_AUTHENTICATION_STATUS 0x000002c5 + +/* MSR_SCAN_HASHES_STATUS bit fields */ +union ifs_scan_hashes_status { + u64 data; + struct { + u32 chunk_size :16; + u32 num_chunks :8; + u32 rsvd1 :8; + u32 error_code :8; + u32 rsvd2 :11; + u32 max_core_limit :12; + u32 valid :1; + }; +}; + +/* MSR_CHUNKS_AUTH_STATUS bit fields */ +union ifs_chunks_auth_status { + u64 data; + struct { + u32 valid_chunks :8; + u32 total_chunks :8; + u32 rsvd1 :16; + u32 error_code :8; + u32 rsvd2 :24; + }; +}; + /** * struct ifs_data - attributes related to intel IFS driver * @integrity_cap_bit: MSR_INTEGRITY_CAPS bit enumerating this test + * @loaded_version: stores the currently loaded ifs image version. + * @loaded: If a valid test binary has been loaded into the memory + * @loading_error: Error occurred on another CPU while loading image + * @valid_chunks: number of chunks which could be validated. */ struct ifs_data { int integrity_cap_bit; + int loaded_version; + bool loaded; + bool loading_error; + int valid_chunks; +}; + +struct ifs_work { + struct work_struct w; + struct device *dev; }; struct ifs_device { @@ -20,6 +64,14 @@ struct ifs_device { struct miscdevice misc; }; +static inline struct ifs_data *ifs_get_data(struct device *dev) +{ + struct miscdevice *m = dev_get_drvdata(dev); + struct ifs_device *d = container_of(m, struct ifs_device, misc); + + return &d->data; +} + void ifs_load_firmware(struct device *dev); #endif diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c index cfbf62494c89..d056617ddc85 100644 --- a/drivers/platform/x86/intel/ifs/load.c +++ b/drivers/platform/x86/intel/ifs/load.c @@ -3,10 +3,172 @@ #include #include +#include #include #include "ifs.h" +struct ifs_header { + u32 header_ver; + u32 blob_revision; + u32 date; + u32 processor_sig; + u32 check_sum; + u32 loader_rev; + u32 processor_flags; + u32 metadata_size; + u32 total_size; + u32 fusa_info; + u64 reserved; +}; + +#define IFS_HEADER_SIZE (sizeof(struct ifs_header)) +static struct ifs_header *ifs_header_ptr; /* pointer to the ifs image header */ +static u64 ifs_hash_ptr; /* Address of ifs metadata (hash) */ +static u64 ifs_test_image_ptr; /* 256B aligned address of test pattern */ +static DECLARE_COMPLETION(ifs_done); + +static const char * const scan_hash_status[] = { + [0] = "No error reported", + [1] = "Attempt to copy scan hashes when copy already in progress", + [2] = "Secure Memory not set up correctly", + [3] = "FuSaInfo.ProgramID does not match or ff-mm-ss does not match", + [4] = "Reserved", + [5] = "Integrity check failed", + [6] = "Scan reload or test is in progress" +}; + +static const char * const scan_authentication_status[] = { + [0] = "No error reported", + [1] = "Attempt to authenticate a chunk which is already marked as authentic", + [2] = "Chunk authentication error. The hash of chunk did not match expected value" +}; + +/* + * To copy scan hashes and authenticate test chunks, the initiating cpu must point + * to the EDX:EAX to the test image in linear address. + * Run wrmsr(MSR_COPY_SCAN_HASHES) for scan hash copy and run wrmsr(MSR_AUTHENTICATE_AND_COPY_CHUNK) + * for scan hash copy and test chunk authentication. + */ +static void copy_hashes_authenticate_chunks(struct work_struct *work) +{ + struct ifs_work *local_work = container_of(work, struct ifs_work, w); + union ifs_scan_hashes_status hashes_status; + union ifs_chunks_auth_status chunk_status; + struct device *dev = local_work->dev; + int i, num_chunks, chunk_size; + struct ifs_data *ifsd; + u64 linear_addr, base; + u32 err_code; + + ifsd = ifs_get_data(dev); + /* run scan hash copy */ + wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr); + rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data); + + /* enumerate the scan image information */ + num_chunks = hashes_status.num_chunks; + chunk_size = hashes_status.chunk_size * 1024; + err_code = hashes_status.error_code; + + if (!hashes_status.valid) { + ifsd->loading_error = true; + if (err_code >= ARRAY_SIZE(scan_hash_status)) { + dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code); + goto done; + } + dev_err(dev, "Hash copy error : %s", scan_hash_status[err_code]); + goto done; + } + + /* base linear address to the scan data */ + base = ifs_test_image_ptr; + + /* scan data authentication and copy chunks to secured memory */ + for (i = 0; i < num_chunks; i++) { + linear_addr = base + i * chunk_size; + linear_addr |= i; + + wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, linear_addr); + rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data); + + ifsd->valid_chunks = chunk_status.valid_chunks; + err_code = chunk_status.error_code; + + if (err_code) { + ifsd->loading_error = true; + if (err_code >= ARRAY_SIZE(scan_authentication_status)) { + dev_err(dev, + "invalid error code 0x%x for authentication\n", err_code); + goto done; + } + dev_err(dev, "Chunk authentication error %s\n", + scan_authentication_status[err_code]); + goto done; + } + } +done: + complete(&ifs_done); +} + +/* + * IFS requires scan chunks authenticated per each socket in the platform. + * Once the test chunk is authenticated, it is automatically copied to secured memory + * and proceed the authentication for the next chunk. + */ +static int scan_chunks_sanity_check(struct device *dev) +{ + int metadata_size, curr_pkg, cpu, ret = -ENOMEM; + struct ifs_data *ifsd = ifs_get_data(dev); + bool *package_authenticated; + struct ifs_work local_work; + char *test_ptr; + + package_authenticated = kcalloc(topology_max_packages(), sizeof(bool), GFP_KERNEL); + if (!package_authenticated) + return ret; + + metadata_size = ifs_header_ptr->metadata_size; + + /* Spec says that if the Meta Data Size = 0 then it should be treated as 2000 */ + if (metadata_size == 0) + metadata_size = 2000; + + /* Scan chunk start must be 256 byte aligned */ + if ((metadata_size + IFS_HEADER_SIZE) % 256) { + dev_err(dev, "Scan pattern offset within the binary is not 256 byte aligned\n"); + return -EINVAL; + } + + test_ptr = (char *)ifs_header_ptr + IFS_HEADER_SIZE + metadata_size; + ifsd->loading_error = false; + + ifs_test_image_ptr = (u64)test_ptr; + ifsd->loaded_version = ifs_header_ptr->blob_revision; + + /* copy the scan hash and authenticate per package */ + cpus_read_lock(); + for_each_online_cpu(cpu) { + curr_pkg = topology_physical_package_id(cpu); + if (package_authenticated[curr_pkg]) + continue; + reinit_completion(&ifs_done); + local_work.dev = dev; + INIT_WORK(&local_work.w, copy_hashes_authenticate_chunks); + schedule_work_on(cpu, &local_work.w); + wait_for_completion(&ifs_done); + if (ifsd->loading_error) + goto out; + package_authenticated[curr_pkg] = 1; + } + ret = 0; +out: + cpus_read_unlock(); + kfree(package_authenticated); + + return ret; +} + static int ifs_sanity_check(struct device *dev, const struct microcode_header_intel *mc_header) { @@ -74,6 +236,7 @@ static bool ifs_image_sanity_check(struct device *dev, const struct microcode_he */ void ifs_load_firmware(struct device *dev) { + struct ifs_data *ifsd = ifs_get_data(dev); const struct firmware *fw; char scan_path[32]; int ret; @@ -84,11 +247,20 @@ void ifs_load_firmware(struct device *dev) ret = request_firmware_direct(&fw, scan_path, dev); if (ret) { dev_err(dev, "ifs file %s load failed\n", scan_path); - return; + goto done; } - if (!ifs_image_sanity_check(dev, (struct microcode_header_intel *)fw->data)) + if (!ifs_image_sanity_check(dev, (struct microcode_header_intel *)fw->data)) { dev_err(dev, "ifs header sanity check failed\n"); + goto release; + } + + ifs_header_ptr = (struct ifs_header *)fw->data; + ifs_hash_ptr = (u64)(ifs_header_ptr + 1); + ret = scan_chunks_sanity_check(dev); +release: release_firmware(fw); +done: + ifsd->loaded = (ret == 0); } -- Gitee From 195bb628a0e0c885602f040cb16376334957e4f8 Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Fri, 6 May 2022 15:54:06 -0700 Subject: [PATCH 08/14] platform/x86/intel/ifs: Add scan test support mainline inclusion from mainline-v5.19-rc1 commit 2b40e654b73ae061f1acbe28fbec6007914ba8d8 category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=2b40e654b73ae061f1acbe28fbec6007914ba8d8 Intel-SIG: commit 2b40e654b73a ("platform/x86/intel/ifs: Add scan test support") ------------------------------------- platform/x86/intel/ifs: Add scan test support In a core, the scan engine is shared between sibling cpus. When a Scan test (for a particular core) is triggered by the user, the scan chunks are executed on all the threads on the core using stop_core_cpuslocked. Scan may be aborted by some reasons. Scan test will be aborted in certain circumstances such as when interrupt occurred or cpu does not have enough power budget for scan. In this case, the kernel restart scan from the chunk where it stopped. Scan will also be aborted when the test is failed. In this case, the test is immediately stopped without retry. Reviewed-by: Dan Williams Signed-off-by: Jithu Joseph Co-developed-by: Tony Luck Signed-off-by: Tony Luck Acked-by: Hans de Goede Reviewed-by: Greg Kroah-Hartman Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/20220506225410.1652287-9-tony.luck@intel.com Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- drivers/platform/x86/intel/ifs/Makefile | 2 +- drivers/platform/x86/intel/ifs/ifs.h | 44 ++++ drivers/platform/x86/intel/ifs/runtest.c | 247 +++++++++++++++++++++++ 3 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 drivers/platform/x86/intel/ifs/runtest.c diff --git a/drivers/platform/x86/intel/ifs/Makefile b/drivers/platform/x86/intel/ifs/Makefile index 98b6fde15689..cedcb103f860 100644 --- a/drivers/platform/x86/intel/ifs/Makefile +++ b/drivers/platform/x86/intel/ifs/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_INTEL_IFS) += intel_ifs.o -intel_ifs-objs := core.o load.o +intel_ifs-objs := core.o load.o runtest.o diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h index bed70dc1e5b7..b648cccda3ec 100644 --- a/drivers/platform/x86/intel/ifs/ifs.h +++ b/drivers/platform/x86/intel/ifs/ifs.h @@ -11,6 +11,11 @@ #define MSR_SCAN_HASHES_STATUS 0x000002c3 #define MSR_AUTHENTICATE_AND_COPY_CHUNK 0x000002c4 #define MSR_CHUNKS_AUTHENTICATION_STATUS 0x000002c5 +#define MSR_ACTIVATE_SCAN 0x000002c6 +#define MSR_SCAN_STATUS 0x000002c7 +#define SCAN_NOT_TESTED 0 +#define SCAN_TEST_PASS 1 +#define SCAN_TEST_FAIL 2 /* MSR_SCAN_HASHES_STATUS bit fields */ union ifs_scan_hashes_status { @@ -38,6 +43,40 @@ union ifs_chunks_auth_status { }; }; +/* MSR_ACTIVATE_SCAN bit fields */ +union ifs_scan { + u64 data; + struct { + u32 start :8; + u32 stop :8; + u32 rsvd :16; + u32 delay :31; + u32 sigmce :1; + }; +}; + +/* MSR_SCAN_STATUS bit fields */ +union ifs_status { + u64 data; + struct { + u32 chunk_num :8; + u32 chunk_stop_index :8; + u32 rsvd1 :16; + u32 error_code :8; + u32 rsvd2 :22; + u32 control_error :1; + u32 signature_error :1; + }; +}; + +/* + * Driver populated error-codes + * 0xFD: Test timed out before completing all the chunks. + * 0xFE: not all scan chunks were executed. Maximum forward progress retries exceeded. + */ +#define IFS_SW_TIMEOUT 0xFD +#define IFS_SW_PARTIAL_COMPLETION 0xFE + /** * struct ifs_data - attributes related to intel IFS driver * @integrity_cap_bit: MSR_INTEGRITY_CAPS bit enumerating this test @@ -45,6 +84,8 @@ union ifs_chunks_auth_status { * @loaded: If a valid test binary has been loaded into the memory * @loading_error: Error occurred on another CPU while loading image * @valid_chunks: number of chunks which could be validated. + * @status: it holds simple status pass/fail/untested + * @scan_details: opaque scan status code from h/w */ struct ifs_data { int integrity_cap_bit; @@ -52,6 +93,8 @@ struct ifs_data { bool loaded; bool loading_error; int valid_chunks; + int status; + u64 scan_details; }; struct ifs_work { @@ -73,5 +116,6 @@ static inline struct ifs_data *ifs_get_data(struct device *dev) } void ifs_load_firmware(struct device *dev); +int do_core_test(int cpu, struct device *dev); #endif diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c new file mode 100644 index 000000000000..7efcce35e0e9 --- /dev/null +++ b/drivers/platform/x86/intel/ifs/runtest.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2022 Intel Corporation. */ + +#include +#include +#include +#include +#include +#include + +#include "ifs.h" + +/* + * Note all code and data in this file is protected by + * ifs_sem. On HT systems all threads on a core will + * execute together, but only the first thread on the + * core will update results of the test. + */ + +/* Max retries on the same chunk */ +#define MAX_IFS_RETRIES 5 + +/* + * Number of TSC cycles that a logical CPU will wait for the other + * logical CPU on the core in the WRMSR(ACTIVATE_SCAN). + */ +#define IFS_THREAD_WAIT 100000 + +enum ifs_status_err_code { + IFS_NO_ERROR = 0, + IFS_OTHER_THREAD_COULD_NOT_JOIN = 1, + IFS_INTERRUPTED_BEFORE_RENDEZVOUS = 2, + IFS_POWER_MGMT_INADEQUATE_FOR_SCAN = 3, + IFS_INVALID_CHUNK_RANGE = 4, + IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS = 5, + IFS_CORE_NOT_CAPABLE_CURRENTLY = 6, + IFS_UNASSIGNED_ERROR_CODE = 7, + IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT = 8, + IFS_INTERRUPTED_DURING_EXECUTION = 9, +}; + +static const char * const scan_test_status[] = { + [IFS_NO_ERROR] = "SCAN no error", + [IFS_OTHER_THREAD_COULD_NOT_JOIN] = "Other thread could not join.", + [IFS_INTERRUPTED_BEFORE_RENDEZVOUS] = "Interrupt occurred prior to SCAN coordination.", + [IFS_POWER_MGMT_INADEQUATE_FOR_SCAN] = + "Core Abort SCAN Response due to power management condition.", + [IFS_INVALID_CHUNK_RANGE] = "Non valid chunks in the range", + [IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS] = "Mismatch in arguments between threads T0/T1.", + [IFS_CORE_NOT_CAPABLE_CURRENTLY] = "Core not capable of performing SCAN currently", + [IFS_UNASSIGNED_ERROR_CODE] = "Unassigned error code 0x7", + [IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT] = + "Exceeded number of Logical Processors (LP) allowed to run Scan-At-Field concurrently", + [IFS_INTERRUPTED_DURING_EXECUTION] = "Interrupt occurred prior to SCAN start", +}; + +static void message_not_tested(struct device *dev, int cpu, union ifs_status status) +{ + if (status.error_code < ARRAY_SIZE(scan_test_status)) { + dev_info(dev, "CPU(s) %*pbl: SCAN operation did not start. %s\n", + cpumask_pr_args(cpu_smt_mask(cpu)), + scan_test_status[status.error_code]); + } else if (status.error_code == IFS_SW_TIMEOUT) { + dev_info(dev, "CPU(s) %*pbl: software timeout during scan\n", + cpumask_pr_args(cpu_smt_mask(cpu))); + } else if (status.error_code == IFS_SW_PARTIAL_COMPLETION) { + dev_info(dev, "CPU(s) %*pbl: %s\n", + cpumask_pr_args(cpu_smt_mask(cpu)), + "Not all scan chunks were executed. Maximum forward progress retries exceeded"); + } else { + dev_info(dev, "CPU(s) %*pbl: SCAN unknown status %llx\n", + cpumask_pr_args(cpu_smt_mask(cpu)), status.data); + } +} + +static void message_fail(struct device *dev, int cpu, union ifs_status status) +{ + /* + * control_error is set when the microcode runs into a problem + * loading the image from the reserved BIOS memory, or it has + * been corrupted. Reloading the image may fix this issue. + */ + if (status.control_error) { + dev_err(dev, "CPU(s) %*pbl: could not execute from loaded scan image\n", + cpumask_pr_args(cpu_smt_mask(cpu))); + } + + /* + * signature_error is set when the output from the scan chains does not + * match the expected signature. This might be a transient problem (e.g. + * due to a bit flip from an alpha particle or neutron). If the problem + * repeats on a subsequent test, then it indicates an actual problem in + * the core being tested. + */ + if (status.signature_error) { + dev_err(dev, "CPU(s) %*pbl: test signature incorrect.\n", + cpumask_pr_args(cpu_smt_mask(cpu))); + } +} + +static bool can_restart(union ifs_status status) +{ + enum ifs_status_err_code err_code = status.error_code; + + /* Signature for chunk is bad, or scan test failed */ + if (status.signature_error || status.control_error) + return false; + + switch (err_code) { + case IFS_NO_ERROR: + case IFS_OTHER_THREAD_COULD_NOT_JOIN: + case IFS_INTERRUPTED_BEFORE_RENDEZVOUS: + case IFS_POWER_MGMT_INADEQUATE_FOR_SCAN: + case IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT: + case IFS_INTERRUPTED_DURING_EXECUTION: + return true; + case IFS_INVALID_CHUNK_RANGE: + case IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS: + case IFS_CORE_NOT_CAPABLE_CURRENTLY: + case IFS_UNASSIGNED_ERROR_CODE: + break; + } + return false; +} + +/* + * Execute the scan. Called "simultaneously" on all threads of a core + * at high priority using the stop_cpus mechanism. + */ +static int doscan(void *data) +{ + int cpu = smp_processor_id(); + u64 *msrs = data; + int first; + + /* Only the first logical CPU on a core reports result */ + first = cpumask_first(cpu_smt_mask(cpu)); + + /* + * This WRMSR will wait for other HT threads to also write + * to this MSR (at most for activate.delay cycles). Then it + * starts scan of each requested chunk. The core scan happens + * during the "execution" of the WRMSR. This instruction can + * take up to 200 milliseconds (in the case where all chunks + * are processed in a single pass) before it retires. + */ + wrmsrl(MSR_ACTIVATE_SCAN, msrs[0]); + + if (cpu == first) { + /* Pass back the result of the scan */ + rdmsrl(MSR_SCAN_STATUS, msrs[1]); + } + + return 0; +} + +/* + * Use stop_core_cpuslocked() to synchronize writing to MSR_ACTIVATE_SCAN + * on all threads of the core to be tested. Loop if necessary to complete + * run of all chunks. Include some defensive tests to make sure forward + * progress is made, and that the whole test completes in a reasonable time. + */ +static void ifs_test_core(int cpu, struct device *dev) +{ + union ifs_scan activate; + union ifs_status status; + unsigned long timeout; + struct ifs_data *ifsd; + u64 msrvals[2]; + int retries; + + ifsd = ifs_get_data(dev); + + activate.rsvd = 0; + activate.delay = IFS_THREAD_WAIT; + activate.sigmce = 0; + activate.start = 0; + activate.stop = ifsd->valid_chunks - 1; + + timeout = jiffies + HZ / 2; + retries = MAX_IFS_RETRIES; + + while (activate.start <= activate.stop) { + if (time_after(jiffies, timeout)) { + status.error_code = IFS_SW_TIMEOUT; + break; + } + + msrvals[0] = activate.data; + stop_core_cpuslocked(cpu, doscan, msrvals); + + status.data = msrvals[1]; + + /* Some cases can be retried, give up for others */ + if (!can_restart(status)) + break; + + if (status.chunk_num == activate.start) { + /* Check for forward progress */ + if (--retries == 0) { + if (status.error_code == IFS_NO_ERROR) + status.error_code = IFS_SW_PARTIAL_COMPLETION; + break; + } + } else { + retries = MAX_IFS_RETRIES; + activate.start = status.chunk_num; + } + } + + /* Update status for this core */ + ifsd->scan_details = status.data; + + if (status.control_error || status.signature_error) { + ifsd->status = SCAN_TEST_FAIL; + message_fail(dev, cpu, status); + } else if (status.error_code) { + ifsd->status = SCAN_NOT_TESTED; + message_not_tested(dev, cpu, status); + } else { + ifsd->status = SCAN_TEST_PASS; + } +} + +/* + * Initiate per core test. It wakes up work queue threads on the target cpu and + * its sibling cpu. Once all sibling threads wake up, the scan test gets executed and + * wait for all sibling threads to finish the scan test. + */ +int do_core_test(int cpu, struct device *dev) +{ + int ret = 0; + + /* Prevent CPUs from being taken offline during the scan test */ + cpus_read_lock(); + + if (!cpu_online(cpu)) { + dev_info(dev, "cannot test on the offline cpu %d\n", cpu); + ret = -EINVAL; + goto out; + } + + ifs_test_core(cpu, dev); +out: + cpus_read_unlock(); + return ret; +} -- Gitee From e04196721f0039942f9ba4d802c5d7e832d2c25f Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Fri, 6 May 2022 15:54:07 -0700 Subject: [PATCH 09/14] platform/x86/intel/ifs: Add IFS sysfs interface mainline inclusion from mainline-v5.19-rc1 commit 6f33a92b92f9cc37f31137cd5a2060ec714d486b category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=6f33a92b92f9cc37f31137cd5a2060ec714d486b Intel-SIG: commit 6f33a92b92f9 ("platform/x86/intel/ifs: Add IFS sysfs interface") ------------------------------------- platform/x86/intel/ifs: Add IFS sysfs interface Implement sysfs interface to trigger ifs test for a specific cpu. Additional interfaces related to checking the status of the scan test and seeing the version of the loaded IFS binary are also added. The basic usage is as below. - To start test, for example on cpu5: echo 5 > /sys/devices/platform/intel_ifs/run_test - To see the status of the last test cat /sys/devices/platform/intel_ifs/status - To see the version of the loaded scan binary cat /sys/devices/platform/intel_ifs/image_version Reviewed-by: Dan Williams Signed-off-by: Jithu Joseph Co-developed-by: Tony Luck Signed-off-by: Tony Luck Acked-by: Hans de Goede Reviewed-by: Greg Kroah-Hartman Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/20220506225410.1652287-10-tony.luck@intel.com Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- drivers/platform/x86/intel/ifs/Makefile | 2 +- drivers/platform/x86/intel/ifs/core.c | 5 + drivers/platform/x86/intel/ifs/ifs.h | 3 + drivers/platform/x86/intel/ifs/sysfs.c | 149 ++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 drivers/platform/x86/intel/ifs/sysfs.c diff --git a/drivers/platform/x86/intel/ifs/Makefile b/drivers/platform/x86/intel/ifs/Makefile index cedcb103f860..30f035ef5581 100644 --- a/drivers/platform/x86/intel/ifs/Makefile +++ b/drivers/platform/x86/intel/ifs/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_INTEL_IFS) += intel_ifs.o -intel_ifs-objs := core.o load.o runtest.o +intel_ifs-objs := core.o load.o runtest.o sysfs.o diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c index f62578dae8e9..27204e3d674d 100644 --- a/drivers/platform/x86/intel/ifs/core.c +++ b/drivers/platform/x86/intel/ifs/core.c @@ -3,6 +3,7 @@ #include #include +#include #include @@ -47,9 +48,13 @@ static int __init ifs_init(void) if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval)) return -ENODEV; + ifs_device.misc.groups = ifs_get_groups(); + if ((msrval & BIT(ifs_device.data.integrity_cap_bit)) && !misc_register(&ifs_device.misc)) { + down(&ifs_sem); ifs_load_firmware(ifs_device.misc.this_device); + up(&ifs_sem); return 0; } diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h index b648cccda3ec..720bd18a5e91 100644 --- a/drivers/platform/x86/intel/ifs/ifs.h +++ b/drivers/platform/x86/intel/ifs/ifs.h @@ -117,5 +117,8 @@ static inline struct ifs_data *ifs_get_data(struct device *dev) void ifs_load_firmware(struct device *dev); int do_core_test(int cpu, struct device *dev); +const struct attribute_group **ifs_get_groups(void); + +extern struct semaphore ifs_sem; #endif diff --git a/drivers/platform/x86/intel/ifs/sysfs.c b/drivers/platform/x86/intel/ifs/sysfs.c new file mode 100644 index 000000000000..37d8380d6fa8 --- /dev/null +++ b/drivers/platform/x86/intel/ifs/sysfs.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2022 Intel Corporation. */ + +#include +#include +#include +#include +#include + +#include "ifs.h" + +/* + * Protects against simultaneous tests on multiple cores, or + * reloading can file while a test is in progress + */ +DEFINE_SEMAPHORE(ifs_sem); + +/* + * The sysfs interface to check additional details of last test + * cat /sys/devices/system/platform/ifs/details + */ +static ssize_t details_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ifs_data *ifsd = ifs_get_data(dev); + + return sysfs_emit(buf, "%#llx\n", ifsd->scan_details); +} + +static DEVICE_ATTR_RO(details); + +static const char * const status_msg[] = { + [SCAN_NOT_TESTED] = "untested", + [SCAN_TEST_PASS] = "pass", + [SCAN_TEST_FAIL] = "fail" +}; + +/* + * The sysfs interface to check the test status: + * To check the status of last test + * cat /sys/devices/platform/ifs/status + */ +static ssize_t status_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ifs_data *ifsd = ifs_get_data(dev); + + return sysfs_emit(buf, "%s\n", status_msg[ifsd->status]); +} + +static DEVICE_ATTR_RO(status); + +/* + * The sysfs interface for single core testing + * To start test, for example, cpu5 + * echo 5 > /sys/devices/platform/ifs/run_test + * To check the result: + * cat /sys/devices/platform/ifs/result + * The sibling core gets tested at the same time. + */ +static ssize_t run_test_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ifs_data *ifsd = ifs_get_data(dev); + unsigned int cpu; + int rc; + + rc = kstrtouint(buf, 0, &cpu); + if (rc < 0 || cpu >= nr_cpu_ids) + return -EINVAL; + + if (down_interruptible(&ifs_sem)) + return -EINTR; + + if (!ifsd->loaded) + rc = -EPERM; + else + rc = do_core_test(cpu, dev); + + up(&ifs_sem); + + return rc ? rc : count; +} + +static DEVICE_ATTR_WO(run_test); + +/* + * Reload the IFS image. When user wants to install new IFS image + */ +static ssize_t reload_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ifs_data *ifsd = ifs_get_data(dev); + bool res; + + + if (kstrtobool(buf, &res)) + return -EINVAL; + if (!res) + return count; + + if (down_interruptible(&ifs_sem)) + return -EINTR; + + ifs_load_firmware(dev); + + up(&ifs_sem); + + return ifsd->loaded ? count : -ENODEV; +} + +static DEVICE_ATTR_WO(reload); + +/* + * Display currently loaded IFS image version. + */ +static ssize_t image_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ifs_data *ifsd = ifs_get_data(dev); + + if (!ifsd->loaded) + return sysfs_emit(buf, "%s\n", "none"); + else + return sysfs_emit(buf, "%#x\n", ifsd->loaded_version); +} + +static DEVICE_ATTR_RO(image_version); + +/* global scan sysfs attributes */ +static struct attribute *plat_ifs_attrs[] = { + &dev_attr_details.attr, + &dev_attr_status.attr, + &dev_attr_run_test.attr, + &dev_attr_reload.attr, + &dev_attr_image_version.attr, + NULL +}; + +ATTRIBUTE_GROUPS(plat_ifs); + +const struct attribute_group **ifs_get_groups(void) +{ + return plat_ifs_groups; +} -- Gitee From dcc2e602241ecb637c41b8da5861394c05f3b59e Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 6 May 2022 15:54:08 -0700 Subject: [PATCH 10/14] trace: platform/x86/intel/ifs: Add trace point to track Intel IFS operations mainline inclusion from mainline-v5.19-rc1 commit 51af802fc05152e84727a4293ccaa7e7e1b64d7e category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=51af802fc05152e84727a4293ccaa7e7e1b64d7e Intel-SIG: commit 51af802fc051 ("trace: platform/x86/intel/ifs: Add trace point to track Intel IFS operations") ------------------------------------- trace: platform/x86/intel/ifs: Add trace point to track Intel IFS operations Add tracing support which may be useful for debugging systems that fail to complete In Field Scan tests. Acked-by: Steven Rostedt (Google) Reviewed-by: Dan Williams Signed-off-by: Tony Luck Acked-by: Hans de Goede Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20220506225410.1652287-11-tony.luck@intel.com Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- MAINTAINERS | 1 + drivers/platform/x86/intel/ifs/runtest.c | 5 +++ include/trace/events/intel_ifs.h | 41 ++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 include/trace/events/intel_ifs.h diff --git a/MAINTAINERS b/MAINTAINERS index 71cbeae822a6..68abd9a6709f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8972,6 +8972,7 @@ R: Ashok Raj R: Tony Luck S: Maintained F: drivers/platform/x86/intel/ifs +F: include/trace/events/intel_ifs.h INTEL INTEGRATED SENSOR HUB DRIVER M: Srinivas Pandruvada diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c index 7efcce35e0e9..b2ca2bb4501f 100644 --- a/drivers/platform/x86/intel/ifs/runtest.c +++ b/drivers/platform/x86/intel/ifs/runtest.c @@ -17,6 +17,9 @@ * core will update results of the test. */ +#define CREATE_TRACE_POINTS +#include + /* Max retries on the same chunk */ #define MAX_IFS_RETRIES 5 @@ -191,6 +194,8 @@ static void ifs_test_core(int cpu, struct device *dev) status.data = msrvals[1]; + trace_ifs_status(cpu, activate, status); + /* Some cases can be retried, give up for others */ if (!can_restart(status)) break; diff --git a/include/trace/events/intel_ifs.h b/include/trace/events/intel_ifs.h new file mode 100644 index 000000000000..d7353024016c --- /dev/null +++ b/include/trace/events/intel_ifs.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM intel_ifs + +#if !defined(_TRACE_IFS_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_IFS_H + +#include +#include + +TRACE_EVENT(ifs_status, + + TP_PROTO(int cpu, union ifs_scan activate, union ifs_status status), + + TP_ARGS(cpu, activate, status), + + TP_STRUCT__entry( + __field( u64, status ) + __field( int, cpu ) + __field( u8, start ) + __field( u8, stop ) + ), + + TP_fast_assign( + __entry->cpu = cpu; + __entry->start = activate.start; + __entry->stop = activate.stop; + __entry->status = status.data; + ), + + TP_printk("cpu: %d, start: %.2x, stop: %.2x, status: %llx", + __entry->cpu, + __entry->start, + __entry->stop, + __entry->status) +); + +#endif /* _TRACE_IFS_H */ + +/* This part must be outside protection */ +#include -- Gitee From 36bbda973ac71df5a02bdb772228d669693805e0 Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Fri, 6 May 2022 15:54:09 -0700 Subject: [PATCH 11/14] platform/x86/intel/ifs: add ABI documentation for IFS mainline inclusion from mainline-v5.19-rc1 commit 55b52633e16205663ab7d4c3168b9274eaa26400 category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=55b52633e16205663ab7d4c3168b9274eaa26400 Intel-SIG: commit 55b52633e162 ("platform/x86/intel/ifs: add ABI documentation for IFS") ------------------------------------- platform/x86/intel/ifs: add ABI documentation for IFS Add the sysfs attributes in ABI/testing for In-Field Scan. Reviewed-by: Dan Williams Signed-off-by: Jithu Joseph Co-developed-by: Tony Luck Signed-off-by: Tony Luck Acked-by: Hans de Goede Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20220506225410.1652287-12-tony.luck@intel.com Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- .../ABI/testing/sysfs-platform-intel-ifs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-platform-intel-ifs diff --git a/Documentation/ABI/testing/sysfs-platform-intel-ifs b/Documentation/ABI/testing/sysfs-platform-intel-ifs new file mode 100644 index 000000000000..486d6d2ff8a0 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-intel-ifs @@ -0,0 +1,39 @@ +What: /sys/devices/virtual/misc/intel_ifs_/run_test +Date: April 21 2022 +KernelVersion: 5.19 +Contact: "Jithu Joseph" +Description: Write to trigger IFS test for one online core. + Note that the test is per core. The cpu# can be + for any thread on the core. Running on one thread + completes the test for the core containing that thread. + Example: to test the core containing cpu5: echo 5 > + /sys/devices/platform/intel_ifs./run_test + +What: /sys/devices/virtual/misc/intel_ifs_/status +Date: April 21 2022 +KernelVersion: 5.19 +Contact: "Jithu Joseph" +Description: The status of the last test. It can be one of "pass", "fail" + or "untested". + +What: /sys/devices/virtual/misc/intel_ifs_/details +Date: April 21 2022 +KernelVersion: 5.19 +Contact: "Jithu Joseph" +Description: Additional information regarding the last test. The details file reports + the hex value of the SCAN_STATUS MSR. Note that the error_code field + may contain driver defined software code not defined in the Intel SDM. + +What: /sys/devices/virtual/misc/intel_ifs_/image_version +Date: April 21 2022 +KernelVersion: 5.19 +Contact: "Jithu Joseph" +Description: Version (hexadecimal) of loaded IFS binary image. If no scan image + is loaded reports "none". + +What: /sys/devices/virtual/misc/intel_ifs_/reload +Date: April 21 2022 +KernelVersion: 5.19 +Contact: "Jithu Joseph" +Description: Write "1" (or "y" or "Y") to reload the IFS image from + /lib/firmware/intel/ifs/ff-mm-ss.scan. -- Gitee From fda2db9842547a35ce13d4a005ee733880c20cc6 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 6 May 2022 15:54:10 -0700 Subject: [PATCH 12/14] Documentation: In-Field Scan mainline inclusion from mainline-v5.19-rc1 commit 34604d28916710070390036118fcd21217b0f597 category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=34604d28916710070390036118fcd21217b0f597 Intel-SIG: commit 34604d289167 ("Documentation: In-Field Scan") ------------------------------------- Documentation: In-Field Scan Add documentation for In-Field Scan (IFS). This documentation describes the basics of IFS, the loading IFS image, chunk authentication, running scan and how to check result via sysfs. The CORE_CAPABILITIES MSR enumerates whether IFS is supported. The full github location for distributing the IFS images is still being decided. So just a placeholder included for now in the documentation. Future CPUs will support more than one type of test. Plan for that now by using a "_0" suffix on the ABI directory names. Additional test types will use "_1", etc. Reviewed-by: Dan Williams Signed-off-by: Tony Luck Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/20220506225410.1652287-13-tony.luck@intel.com Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- Documentation/x86/ifs.rst | 2 + Documentation/x86/index.rst | 1 + drivers/platform/x86/intel/ifs/ifs.h | 110 +++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 Documentation/x86/ifs.rst diff --git a/Documentation/x86/ifs.rst b/Documentation/x86/ifs.rst new file mode 100644 index 000000000000..97abb696a680 --- /dev/null +++ b/Documentation/x86/ifs.rst @@ -0,0 +1,2 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. kernel-doc:: drivers/platform/x86/intel/ifs/ifs.h diff --git a/Documentation/x86/index.rst b/Documentation/x86/index.rst index b345cdbf5ad3..a397ad01ce0e 100644 --- a/Documentation/x86/index.rst +++ b/Documentation/x86/index.rst @@ -34,6 +34,7 @@ x86-specific Documentation usb-legacy-support i386/index x86_64/index + ifs sva sgx elf_auxvec diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h index 720bd18a5e91..73c8e91cf144 100644 --- a/drivers/platform/x86/intel/ifs/ifs.h +++ b/drivers/platform/x86/intel/ifs/ifs.h @@ -4,6 +4,116 @@ #ifndef _IFS_H_ #define _IFS_H_ +/** + * DOC: In-Field Scan + * + * ============= + * In-Field Scan + * ============= + * + * Introduction + * ------------ + * + * In Field Scan (IFS) is a hardware feature to run circuit level tests on + * a CPU core to detect problems that are not caught by parity or ECC checks. + * Future CPUs will support more than one type of test which will show up + * with a new platform-device instance-id, for now only .0 is exposed. + * + * + * IFS Image + * --------- + * + * Intel provides a firmware file containing the scan tests via + * github [#f1]_. Similar to microcode there is a separate file for each + * family-model-stepping. + * + * IFS Image Loading + * ----------------- + * + * The driver loads the tests into memory reserved BIOS local to each CPU + * socket in a two step process using writes to MSRs to first load the + * SHA hashes for the test. Then the tests themselves. Status MSRs provide + * feedback on the success/failure of these steps. When a new test file + * is installed it can be loaded by writing to the driver reload file:: + * + * # echo 1 > /sys/devices/virtual/misc/intel_ifs_0/reload + * + * Similar to microcode, the current version of the scan tests is stored + * in a fixed location: /lib/firmware/intel/ifs.0/family-model-stepping.scan + * + * Running tests + * ------------- + * + * Tests are run by the driver synchronizing execution of all threads on a + * core and then writing to the ACTIVATE_SCAN MSR on all threads. Instruction + * execution continues when: + * + * 1) All tests have completed. + * 2) Execution was interrupted. + * 3) A test detected a problem. + * + * Note that ALL THREADS ON THE CORE ARE EFFECTIVELY OFFLINE FOR THE + * DURATION OF THE TEST. This can be up to 200 milliseconds. If the system + * is running latency sensitive applications that cannot tolerate an + * interruption of this magnitude, the system administrator must arrange + * to migrate those applications to other cores before running a core test. + * It may also be necessary to redirect interrupts to other CPUs. + * + * In all cases reading the SCAN_STATUS MSR provides details on what + * happened. The driver makes the value of this MSR visible to applications + * via the "details" file (see below). Interrupted tests may be restarted. + * + * The IFS driver provides sysfs interfaces via /sys/devices/virtual/misc/intel_ifs_0/ + * to control execution: + * + * Test a specific core:: + * + * # echo > /sys/devices/virtual/misc/intel_ifs_0/run_test + * + * when HT is enabled any of the sibling cpu# can be specified to test + * its corresponding physical core. Since the tests are per physical core, + * the result of testing any thread is same. All siblings must be online + * to run a core test. It is only necessary to test one thread. + * + * For e.g. to test core corresponding to cpu5 + * + * # echo 5 > /sys/devices/virtual/misc/intel_ifs_0/run_test + * + * Results of the last test is provided in /sys:: + * + * $ cat /sys/devices/virtual/misc/intel_ifs_0/status + * pass + * + * Status can be one of pass, fail, untested + * + * Additional details of the last test is provided by the details file:: + * + * $ cat /sys/devices/virtual/misc/intel_ifs_0/details + * 0x8081 + * + * The details file reports the hex value of the SCAN_STATUS MSR. + * Hardware defined error codes are documented in volume 4 of the Intel + * Software Developer's Manual but the error_code field may contain one of + * the following driver defined software codes: + * + * +------+--------------------+ + * | 0xFD | Software timeout | + * +------+--------------------+ + * | 0xFE | Partial completion | + * +------+--------------------+ + * + * Driver design choices + * --------------------- + * + * 1) The ACTIVATE_SCAN MSR allows for running any consecutive subrange of + * available tests. But the driver always tries to run all tests and only + * uses the subrange feature to restart an interrupted test. + * + * 2) Hardware allows for some number of cores to be tested in parallel. + * The driver does not make use of this, it only tests one core at a time. + * + * .. [#f1] https://github.com/intel/TBD + */ #include #include -- Gitee From 0122f5626081382aae00f03c80967436a257d2d7 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 19 May 2022 16:57:15 +0200 Subject: [PATCH 13/14] platform/x86/intel/ifs: Add CPU_SUP_INTEL dependency mainline inclusion from mainline-v5.19-rc1 commit badb81a58b9e66ca8c15405476f5134e45b57dee category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit/?id=badb81a58b9e66ca8c15405476f5134e45b57dee Intel-SIG: commit badb81a58b9e ("platform/x86/intel/ifs: Add CPU_SUP_INTEL dependency") ------------------------------------- platform/x86/intel/ifs: Add CPU_SUP_INTEL dependency The driver is using functions from a compilation unit which is enabled by CONFIG_CPU_SUP_INTEL. Add that dependency to Kconfig explicitly otherwise: drivers/platform/x86/intel/ifs/load.o: in function `ifs_load_firmware': load.c:(.text+0x3b8): undefined reference to `intel_cpu_collect_info' Reported-by: Randy Dunlap Signed-off-by: Borislav Petkov Link: https://lore.kernel.org/r/YoZay8YR0zRGyVu+@zn.tnic Signed-off-by: Hans de Goede Signed-off-by: Aichun Shi --- drivers/platform/x86/intel/ifs/Kconfig | 2 +- drivers/platform/x86/intel/ifs/load.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/ifs/Kconfig b/drivers/platform/x86/intel/ifs/Kconfig index d84491cfb0db..7ce896434b8f 100644 --- a/drivers/platform/x86/intel/ifs/Kconfig +++ b/drivers/platform/x86/intel/ifs/Kconfig @@ -1,6 +1,6 @@ config INTEL_IFS tristate "Intel In Field Scan" - depends on X86 && 64BIT && SMP + depends on X86 && CPU_SUP_INTEL && 64BIT && SMP select INTEL_IFS_DEVICE help Enable support for the In Field Scan capability in select diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c index d056617ddc85..eed7a65ce1b4 100644 --- a/drivers/platform/x86/intel/ifs/load.c +++ b/drivers/platform/x86/intel/ifs/load.c @@ -174,6 +174,7 @@ static int ifs_sanity_check(struct device *dev, { unsigned long total_size, data_size; u32 sum, *mc; + int i; total_size = get_totalsize(mc_header); data_size = get_datasize(mc_header); @@ -190,7 +191,7 @@ static int ifs_sanity_check(struct device *dev, mc = (u32 *)mc_header; sum = 0; - for (int i = 0; i < total_size / sizeof(u32); i++) + for (i = 0; i < total_size / sizeof(u32); i++) sum += mc[i]; if (sum) { -- Gitee From 53c13478c34c44c99e35129156659edf16af4132 Mon Sep 17 00:00:00 2001 From: Aichun Shi Date: Thu, 8 Dec 2022 15:02:47 +0800 Subject: [PATCH 14/14] Enable Intel In Field Scan(IFS) as kernel module Intel inclusion category: feature feature: Intel In Filed Scan(IFS) bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I651S7 CVE: N/A Intel-SIG: openeuler_defconfig: Enable Intel In Field Scan(IFS) as kernel module -------------------------------------------- Enable Intel In Field Scan(IFS) as kernel module in openeuler_defconfig. Signed-off-by: Aichun Shi --- arch/x86/configs/openeuler_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig index b582e8c87587..9f4e4c344ec9 100644 --- a/arch/x86/configs/openeuler_defconfig +++ b/arch/x86/configs/openeuler_defconfig @@ -6504,6 +6504,7 @@ CONFIG_XEN_FRONT_PGDIR_SHBUF=m # CONFIG_GREYBUS is not set # CONFIG_STAGING is not set CONFIG_X86_PLATFORM_DEVICES=y +CONFIG_INTEL_IFS=m CONFIG_ACPI_WMI=m CONFIG_WMI_BMOF=m # CONFIG_ALIENWARE_WMI is not set -- Gitee