2022-04-07 21:21:23

by Joseph, Jithu

[permalink] [raw]
Subject: [PATCH v2 00/10] Introduce In Field Scan driver

Note to Maintainers:
Requesting x86 Maintainers to take a look at patch1 as it
touches arch/x86 portion of the kernel.

Patch 2/10 - Adds Documentation. Requesting Documentation maintainer to review it.

Requesting Greg KH to review the sysfs changes added by patch8 (note that in
this revision we no longer touch /sys/devices/system/cpu as in previous version
and limit ourselves to only /sys/devices/platform/intel_ifs)

Patch10 - adds tracing support, requesting Steven Rostedt to review that.

Rest of the patches adds the IFS platform driver, requesting Platform driver maintainers
to review them.

This is the v2 version incorporating the review feedback from the RFC version [1]

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.
See References section to understand more about CPU core errors and how
and when they are encountered.

Intel will provide a firmware file containing the scan tests. Similar to
microcode there is a separate file for each family-model-stepping. The
tests in the file are divided into some number of "chunks" that can be
run individually.

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.

Tests are run by 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

In all cases reading the SCAN_STATUS MSR provides details on what
happened. Interrupted tests may be restarted.

The IFS driver provides interfaces from /sys to control execution:

/sys/devices/platform/intel_ifs/run_test
Writing <cpu#> to this file will trigger a scan on that core
e.g echo 5 > sys/devices/platform/intel_ifs/run_test will trigger
scan on the core containing cpu5

Results of the tests are also provided in /sys:

/sys/devices/platform/intel_ifs/status
Status (pass/fail/untested) for the last test

/sys/devices/platform/intel_ifs/details
Hex value of the SCAN_STATUS MSR for the most recent test.
Note that the error_code field may contain driver
defined software code not defined in the Intel SDM.

Driver design choices:

1) The ACTIVATE_SCAN MSR allows for running any consecutive subrange or
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.

References
Links to a few articles, papers, presentation [2] [3] [4] [5] which
talk about cpu core errors encountered in the wild which could be
relevant to this work.

[1] https://lore.kernel.org/lkml/[email protected]/
[2] https://sigops.org/s/conferences/hotos/2021/papers/hotos21-s01-hochschild.pdf
[3] https://www.youtube.com/watch?v=QMF3rqhjYuM
[4] https://engineering.fb.com/2021/02/23/data-infrastructure/silent-data-corruption/
[5] https://www.theregister.com/2021/06/04/google_chip_flaws/

Changes since RFC:
- Renamed collect_cpu_info_early() - >cpu_collect_info_early() (Patch 1; GregKH)
- Refactored collect_cpu_info_early(), cpu_signatures_match() from
microcode specific file to intel-generic file (Patch 1; Borislav Petkov)
- Keep the same platform driver object through-out the life-time of
the driver (patch 4; Dan Wiliiams)
- Replace platform_device_register_simple() with platform_device_alloc/add()
so that sysfs files are available instantateously (patch 4; Dan Wiliiams)
- Move IFS binary loading to driver_probe context from module_init
context (patch4; Dan Wiliiams)
- Remove the version check during scan image load so as to allow user
to move to any IFS binary (Patch 4)
- Replace pr_* macros with dev_* macros (Patches 3-9; Dan Wiliiams)
- Replace percpu kthreads with work_queue worker threads (Patch 7; Dan Wiliiams)
- Remove hotplug callbacks which are no longer required due to above
change (Patch 7; Dan Wiliiams)
- Remove percpu ifs_state data structure as it is no longer needed (Patch 7)
- Refactored test logic into a separate runtest.c file (Patch 7, Tony Luck)
- Moved sysfs interface from /sys/devices/system/cpu/ifs and
/sys/devices/system/cpu/cpu#/ifs to /sys/devices/platform/intel_ifs
- Done away with global/percpu testing interfaces. To trigger a test,
there is a single run_test file which takes cpu_number as input.
This hugely reduces the number of sysfs file needed. Userspace can iterate
over all the cpus to achevie global testing (Patch8; Dan Wiliiams)
- Remove the reload sysfs interface for IFS binary loading. Since binary loading
is done from the probe context, reloading can be acheieved using driver
bind sysfs interface (Patch 8; Dan Williams)
- Updated the Documentation/ ABI files to reflect the sysfs changes
- Change trace event structure field ordering (patch 10; Steven Rostedt)
- misc changes
- adding enum type for ifs_status_err_code
- replace sprintf with sysfs_emit in sysfs.c

Jithu Joseph (8):
x86/microcode/intel: expose collect_cpu_info_early() for IFS
platform/x86/intel/ifs: Add driver for In-Field Scan
platform/x86/intel/ifs: Load IFS Image
platform/x86/intel/ifs: Check IFS Image sanity
platform/x86/intel/ifs: Authenticate and copy to secured memory
platform/x86/intel/ifs: Add scan test support
platform/x86/intel/ifs: Add IFS sysfs interface
platform/x86/intel/ifs: add ABI documentation for IFS

Tony Luck (2):
Documentation: In-Field Scan
trace: platform/x86/intel/ifs: Add trace point to track Intel IFS
operations

.../ABI/testing/sysfs-platform-intel-ifs | 54 ++++
Documentation/x86/ifs.rst | 114 +++++++
Documentation/x86/index.rst | 1 +
MAINTAINERS | 7 +
arch/x86/include/asm/microcode_intel.h | 4 +
arch/x86/kernel/cpu/intel.c | 47 +++
arch/x86/kernel/cpu/microcode/intel.c | 55 +---
drivers/platform/x86/intel/Kconfig | 1 +
drivers/platform/x86/intel/Makefile | 1 +
drivers/platform/x86/intel/ifs/Kconfig | 9 +
drivers/platform/x86/intel/ifs/Makefile | 3 +
drivers/platform/x86/intel/ifs/core.c | 121 +++++++
drivers/platform/x86/intel/ifs/ifs.h | 137 ++++++++
drivers/platform/x86/intel/ifs/load.c | 285 +++++++++++++++++
drivers/platform/x86/intel/ifs/runtest.c | 300 ++++++++++++++++++
drivers/platform/x86/intel/ifs/sysfs.c | 139 ++++++++
include/trace/events/intel_ifs.h | 38 +++
17 files changed, 1266 insertions(+), 50 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-platform-intel-ifs
create mode 100644 Documentation/x86/ifs.rst
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
create mode 100644 drivers/platform/x86/intel/ifs/ifs.h
create mode 100644 drivers/platform/x86/intel/ifs/load.c
create mode 100644 drivers/platform/x86/intel/ifs/runtest.c
create mode 100644 drivers/platform/x86/intel/ifs/sysfs.c
create mode 100644 include/trace/events/intel_ifs.h

--
2.17.1


2022-04-07 21:21:54

by Joseph, Jithu

[permalink] [raw]
Subject: [PATCH v2 04/10] platform/x86/intel/ifs: Load IFS Image

IFS uses a scan image format that shares the same header as
microcode updates and deployment approach for these images mirrors
that of microcode update. Specifically, enable images to be deployed
relative to a static symlink in /lib/firmware and then load
into kernel memory via request_firmware().

The image is specific to a processor family, model and stepping.
IFS requires that a test image be loaded before any ifs test is
initiated. Load the image that matches processor signature.
The IFS image is signed by Intel.

The IFS image file follows a similar naming convention as used for
Intel CPU microcode files. The file must be located in the firmware
directory where the microcode files are placed and named as {family/model
/stepping}.scan as below:

/lib/firmware/intel/ifs/{ff-mm-ss}.scan

Reviewed-by: Tony Luck <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
---
drivers/platform/x86/intel/ifs/Makefile | 2 +-
drivers/platform/x86/intel/ifs/core.c | 62 ++++++++++++++++++++
drivers/platform/x86/intel/ifs/ifs.h | 15 +++++
drivers/platform/x86/intel/ifs/load.c | 76 +++++++++++++++++++++++++
4 files changed, 154 insertions(+), 1 deletion(-)
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 c44305dff542..b69d026ca9da 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 87956623208f..716f333a064b 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -2,10 +2,14 @@
/* Copyright(c) 2022 Intel Corporation. */

#include <linux/module.h>
+#include <linux/platform_device.h>
#include <asm/cpu_device_id.h>

#include "ifs.h"

+struct platform_device *ifs_pdev;
+struct ifs_binary ifs_binary;
+
#define X86_MATCH(model) \
X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \
INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, NULL)
@@ -17,10 +21,39 @@ static const struct x86_cpu_id ifs_cpu_ids[] __initconst = {

MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids);

+static int ifs_probe(struct platform_device *pdev)
+{
+ /* Load IFS binary to BIOS reserved memory area */
+ if (load_ifs_binary()) {
+ ifs_binary.loaded = false;
+ dev_err(&ifs_pdev->dev, "Failed to Load IFS binary. Try reloading.\n");
+ return -EPERM;
+ }
+ ifs_binary.loaded = true;
+ return 0;
+}
+
+static int ifs_remove(struct platform_device *pdev)
+{
+ ifs_binary.loaded = false;
+ ifs_binary.loaded_version = 0;
+ /* No OS managed memory to free */
+ return 0;
+}
+
+static struct platform_driver ifs_driver = {
+ .probe = ifs_probe,
+ .remove = ifs_remove,
+ .driver = {
+ .name = "intel_ifs",
+ },
+};
+
static int __init ifs_init(void)
{
const struct x86_cpu_id *m;
u64 ia32_core_caps;
+ int ret;

/* ifs capability check */
m = x86_match_cpu(ifs_cpu_ids);
@@ -31,11 +64,40 @@ static int __init ifs_init(void)
if (!(ia32_core_caps & MSR_IA32_CORE_CAPS_INTEGRITY))
return -ENODEV;

+ ifs_binary.loaded = false;
+
+ ret = platform_driver_register(&ifs_driver);
+ if (ret) {
+ pr_err("intel_ifs: platform driver register failed\n");
+ return ret;
+ }
+
+ ifs_pdev = platform_device_alloc("intel_ifs", -1);
+ if (!ifs_pdev) {
+ pr_err("intel_ifs: platform device allocation failed\n");
+ ret = -ENOMEM;
+ goto drv_unreg;
+ }
+
+ ret = platform_device_add(ifs_pdev);
+ if (ret) {
+ pr_err("intel_ifs: platform device add failed\n");
+ platform_device_put(ifs_pdev);
+ goto drv_unreg;
+ }
+
return 0;
+
+drv_unreg:
+ platform_driver_unregister(&ifs_driver);
+ return ret;
+
}

static void __exit ifs_exit(void)
{
+ platform_device_unregister(ifs_pdev);
+ platform_driver_unregister(&ifs_driver);
}

MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
index bb25a4cd3af6..e1c9c16cbadb 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -8,4 +8,19 @@
#define MSR_IA32_CORE_CAPS_INTEGRITY_BIT 2
#define MSR_IA32_CORE_CAPS_INTEGRITY BIT(MSR_IA32_CORE_CAPS_INTEGRITY_BIT)

+#define IFS_BLOB_REV_ERR_INJ BIT(30)
+#define IFS_BLOB_REV_DEBUG BIT(31)
+/**
+ * struct ifs_binary - attributes related to test binary
+ * @loaded_version: stores the currently loaded ifs image version.
+ * @loaded: If a valid test binary has been loaded into the memory
+ */
+struct ifs_binary {
+ int loaded_version;
+ bool loaded;
+};
+
+int load_ifs_binary(void);
+extern struct platform_device *ifs_pdev;
+extern struct ifs_binary ifs_binary;
#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..a1be4d6558a1
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/load.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. */
+
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include "ifs.h"
+static const char *ifs_path = "intel/ifs/";
+
+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 const struct firmware *load_binary(const char *path)
+{
+ const struct firmware *fw;
+ int err;
+
+ err = request_firmware_direct(&fw, path, &ifs_pdev->dev);
+ if (err) {
+ dev_err(&ifs_pdev->dev, "ifs file %s load failed\n", path);
+ goto out;
+ }
+
+out:
+
+ return fw;
+}
+
+static void check_binary_flags(struct ifs_header *new_image_ptr)
+{
+ if (new_image_ptr->blob_revision & IFS_BLOB_REV_DEBUG)
+ dev_warn(&ifs_pdev->dev, "Debug flag is set in the binary loaded\n");
+ if (new_image_ptr->blob_revision & IFS_BLOB_REV_ERR_INJ)
+ dev_warn(&ifs_pdev->dev, "Error Injection flag is set in the binary loaded\n");
+}
+
+/*
+ * 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}.
+ */
+int load_ifs_binary(void)
+{
+ const struct firmware *scan_fw;
+ char scan_path[256];
+ int ret;
+
+ snprintf(scan_path, sizeof(scan_path), "%s%02x-%02x-%02x.scan", ifs_path,
+ boot_cpu_data.x86, boot_cpu_data.x86_model, boot_cpu_data.x86_stepping);
+
+ scan_fw = load_binary(scan_path);
+ if (!scan_fw)
+ return -ENOENT;
+
+ ifs_header_ptr = (struct ifs_header *)scan_fw->data;
+ ifs_hash_ptr = (u64)(ifs_header_ptr + 1);
+
+ check_binary_flags(ifs_header_ptr);
+ release_firmware(scan_fw);
+
+ return ret;
+}
--
2.17.1

2022-04-07 21:21:58

by Joseph, Jithu

[permalink] [raw]
Subject: [PATCH v2 09/10] platform/x86/intel/ifs: add ABI documentation for IFS

Add the sysfs attributes in ABI/testing for In-Field Scan.

Reviewed-by: Tony Luck <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
---
.../ABI/testing/sysfs-platform-intel-ifs | 54 +++++++++++++++++++
1 file changed, 54 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..54dc6cd75484
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-intel-ifs
@@ -0,0 +1,54 @@
+What: /sys/devices/platform/intel_ifs/run_test
+Date: April 07, 2022
+KernelVersion: 5.19.0
+Contact: "Jithu Joseph" <[email protected]>
+Description: echo <cpu#> to trigger ifs test for all online cores.
+ For e.g to test cpu5 do echo 5 > /sys/devices/platform/intel_ifs/run_test
+
+What: /sys/devices/platform/intel_ifs/status
+Date: April 07, 2022
+KernelVersion: 5.19.0
+Contact: "Jithu Joseph" <[email protected]>
+Description: The status of the last test. It can be one of "pass", "fail"
+ or "untested".
+
+What: /sys/devices/system/cpu/cpu#/ifs/details
+Date: April 07, 2022
+KernelVersion: 5.19.0
+Contact: "Jithu Joseph" <[email protected]>
+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/platform/intel_ifs/image_version
+Date: April 07, 2022
+KernelVersion: 5.19.0
+Contact: "Jithu Joseph" <[email protected]>
+Description: Version of loaded IFS binary image.
+
+What: /sys/bus/platform/drivers/intel_ifs/bind
+Date: April 07, 2022
+KernelVersion: 5.19.0
+Contact: "Jithu Joseph" <[email protected]>
+Description: echo "intel_ifs" to reload IFS image.
+
+What: /sys/module/intel_ifs/parameters/noirq
+Date: April 07, 2022
+KernelVersion: 5.19.0
+Contact: "Jithu Joseph" <[email protected]>
+Description: IFS tunable parameter that user can modify before
+ the scan run if they wish to override default value.
+
+ When set, system interrupts are not allowed to interrupt an IFS. The
+ default state for this parameter is set.
+
+What: /sys/module/intel_ifs/parameters/retry
+Date: April 07, 2022
+KernelVersion: 5.19.0
+Contact: "Jithu Joseph" <[email protected]>
+Description: IFS tunable parameter that user can modify before scan run
+ if they wish to override default value.
+
+ Maximum retry counter when the test is not executed due to an
+ event such as interrupt. The default value is 5, it can be set to any
+ value from 1 to 20.
--
2.17.1

2022-04-07 21:22:06

by Joseph, Jithu

[permalink] [raw]
Subject: [PATCH v2 07/10] 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,
worker threads for each sibling cpus(belonging to that core) are
queued to execute the scan test function in the Workqueue context.

All the siblings rendezvous before the test execution. The scan
results are same for all siblings.

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: Tony Luck <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
---
drivers/platform/x86/intel/ifs/Makefile | 2 +-
drivers/platform/x86/intel/ifs/core.c | 14 ++
drivers/platform/x86/intel/ifs/ifs.h | 76 ++++++
drivers/platform/x86/intel/ifs/runtest.c | 295 +++++++++++++++++++++++
4 files changed, 386 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 b69d026ca9da..d5905e5d2de8 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/core.c b/drivers/platform/x86/intel/ifs/core.c
index 716f333a064b..95847e00038b 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -9,6 +9,9 @@

struct platform_device *ifs_pdev;
struct ifs_binary ifs_binary;
+struct ifs_test ifs_test;
+
+struct workqueue_struct *ifs_wq;

#define X86_MATCH(model) \
X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \
@@ -86,6 +89,15 @@ static int __init ifs_init(void)
goto drv_unreg;
}

+ /* Flags are to keep all the sibling cpu worker threads (of a core) in close sync */
+ ifs_wq = alloc_workqueue("intel_ifs", (WQ_HIGHPRI | WQ_CPU_INTENSIVE), 1);
+ if (!ifs_wq) {
+ dev_err(&ifs_pdev->dev, "Failed to create work queue\n");
+ platform_device_unregister(ifs_pdev);
+ ret = -ENOMEM;
+ goto drv_unreg;
+ }
+ init_completion(&ifs_test.test_thread_done);
return 0;

drv_unreg:
@@ -96,6 +108,8 @@ static int __init ifs_init(void)

static void __exit ifs_exit(void)
{
+ flush_workqueue(ifs_wq);
+ destroy_workqueue(ifs_wq);
platform_device_unregister(ifs_pdev);
platform_driver_unregister(&ifs_driver);
}
diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
index 4d12f8e71c67..93cc1af4aea0 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -14,6 +14,13 @@
#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
+#define SPINUNIT 100
+#define THREAD_WAIT 5

/* MSR_SCAN_HASHES_STATUS bit fields */
union ifs_scan_hashes_status {
@@ -41,6 +48,53 @@ union ifs_chunks_auth_status {
};
};

+/* MSR_ACTIVATE_SCAN bit fields */
+union ifs_scan {
+ u64 data;
+ struct {
+ u64 start :8;
+ u64 stop :8;
+ u64 rsvd :16;
+ u64 delay :31;
+ u64 sigmce :1;
+ };
+};
+
+/* MSR_SCAN_STATUS bit fields */
+union ifs_status {
+ u64 data;
+ struct {
+ u64 chunk_num :8;
+ u64 chunk_stop_index :8;
+ u64 rsvd1 :16;
+ u64 error_code :8;
+ u64 rsvd2 :22;
+ u64 control_error :1;
+ u64 signature_error :1;
+ };
+};
+
+enum ifs_status_err_code {
+ IFS_NO_ERROR = 0,
+ IFS_OTHER_THREAD_COULD_NOT_JOIN,
+ IFS_INTERRUPTED_BEFORE_RENDEZVOUS,
+ IFS_POWER_MGMT_INADEQUATE_FOR_SCAN,
+ IFS_INVALID_CHUNK_RANGE,
+ IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS,
+ IFS_CORE_NOT_CAPABLE_CURRENTLY,
+ IFS_UNASSIGNED_ERROR_CODE,
+ IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT,
+ IFS_INTERRUPTED_DURING_EXECUTION,
+};
+
+/*
+ * 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_binary - attributes related to test binary
* @loaded_version: stores the currently loaded ifs image version.
@@ -53,7 +107,29 @@ struct ifs_binary {
bool loaded;
};

+/**
+ * struct ifs_test - various parameters pertaining to a test
+ * @status: it holds simple status pass/fail/untested
+ * @cpu_sibl_ct: number of h/w sibling threads for the test cpu
+ * @siblings_in: sibling count for joining rendezvous
+ * @siblings_out: sibling count for exiting rendezvous
+ * @scan_details: opaque scan status code from h/w
+ * @test_thread_done: set when scan are done for all siblings threads
+ */
+struct ifs_test {
+ int status;
+ int cpu_sibl_ct;
+ atomic_t siblings_in;
+ atomic_t siblings_out;
+ u64 scan_details;
+ struct completion test_thread_done;
+};
+
int load_ifs_binary(void);
+int do_core_test(int cpu);
extern struct platform_device *ifs_pdev;
extern struct ifs_binary ifs_binary;
+extern struct ifs_test ifs_test;
+extern struct workqueue_struct *ifs_wq;
+extern bool ifs_disabled;
#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..f9c98d84183f
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/runtest.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. */
+
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/nmi.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "ifs.h"
+
+bool ifs_disabled;
+
+static int ifs_retry_set(const char *val, const struct kernel_param *kp);
+static const struct kernel_param_ops ifs_retry_ops = {
+ .set = ifs_retry_set,
+ .get = param_get_int,
+};
+
+static int retry = 5;
+module_param_cb(retry, &ifs_retry_ops, &retry, 0644);
+
+MODULE_PARM_DESC(retry, "Maximum retry count when the test is not executed");
+
+static bool noirq = 1;
+module_param(noirq, bool, 0644);
+MODULE_PARM_DESC(noirq, "Option to enable/disable interrupt during test");
+
+static int ifs_retry_set(const char *val, const struct kernel_param *kp)
+{
+ int var = 0;
+
+ if (kstrtoint(val, 0, &var)) {
+ dev_warn(&ifs_pdev->dev, "unable to parse retry\n");
+ return -EINVAL;
+ }
+
+ /* validate retry value for sanity */
+ if (var < 1 || var > 20) {
+ dev_warn(&ifs_pdev->dev, "retry parameter should be between 1 and 20\n");
+ return -EINVAL;
+ }
+
+ return param_set_int(val, kp);
+}
+
+static unsigned long msec_to_tsc(unsigned long msec)
+{
+ return tsc_khz * 1000 * msec / MSEC_PER_SEC;
+}
+
+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(int cpu, union ifs_status status)
+{
+ if (status.error_code < ARRAY_SIZE(scan_test_status))
+ dev_info(&ifs_pdev->dev, "CPU(s) %*pbl: SCAN operation did not start. %s\n",
+ cpumask_pr_args(topology_sibling_cpumask(cpu)),
+ scan_test_status[status.error_code]);
+ else if (status.error_code == IFS_SW_TIMEOUT)
+ dev_info(&ifs_pdev->dev, "CPU(s) %*pbl: software timeout during scan\n",
+ cpumask_pr_args(topology_sibling_cpumask(cpu)));
+ else if (status.error_code == IFS_SW_PARTIAL_COMPLETION)
+ dev_info(&ifs_pdev->dev, "CPU(s) %*pbl: %s\n",
+ cpumask_pr_args(topology_sibling_cpumask(cpu)),
+ "Not all scan chunks were executed. Maximum forward progress retries exceeded");
+ else
+ dev_info(&ifs_pdev->dev, "CPU(s) %*pbl: SCAN unknown status %llx\n",
+ cpumask_pr_args(topology_sibling_cpumask(cpu)), status.data);
+}
+
+static void message_fail(int cpu, union ifs_status status)
+{
+ if (status.control_error) {
+ dev_err(&ifs_pdev->dev, "CPU(s) %*pbl: scan failed. %s\n",
+ cpumask_pr_args(topology_sibling_cpumask(cpu)),
+ "Suggest reload scan file: # echo 1 > /sys/devices/platform/intel_ifs/reload");
+ }
+ if (status.signature_error) {
+ dev_err(&ifs_pdev->dev, "CPU(s) %*pbl: test signature incorrect. %s\n",
+ cpumask_pr_args(topology_sibling_cpumask(cpu)),
+ "Retry once to check if problem is transient");
+ }
+}
+
+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;
+}
+
+static bool wait_for_siblings(atomic_t *t, long long timeout)
+{
+ atomic_inc(t);
+ while (atomic_read(t) < ifs_test.cpu_sibl_ct) {
+ if (timeout < SPINUNIT) {
+ dev_err(&ifs_pdev->dev,
+ "Timeout while waiting for CPUs rendezvous, remaining: %d\n",
+ ifs_test.cpu_sibl_ct - atomic_read(t));
+ return false;
+ }
+
+ ndelay(SPINUNIT);
+ timeout -= SPINUNIT;
+
+ touch_nmi_watchdog();
+ }
+
+ return true;
+}
+
+/*
+ * When a Scan test (for a particular core) is triggered by the user, worker threads
+ * for each sibling cpus(belonging to that core) are queued to execute this function in
+ * the Workqueue (ifs_wq) context.
+ * Wait for the sibling thread to join before the execution.
+ * Execute the scan test by running wrmsr(MSR_ACTIVATE_SCAN).
+ */
+static void ifs_work_func(struct work_struct *work)
+{
+ int cpu = smp_processor_id();
+ union ifs_scan activate;
+ union ifs_status status;
+ unsigned long timeout;
+ int retries;
+ u32 first;
+
+ activate.rsvd = 0;
+ activate.delay = msec_to_tsc(THREAD_WAIT);
+ activate.sigmce = 0;
+
+ /*
+ * Need to get (and keep) the threads on this core executing close together
+ * so that the writes to MSR_ACTIVATE_SCAN below will succeed in entering
+ * IFS test mode on this core. Interrupts on each thread are expected to be
+ * brief. But preemption would be a problem.
+ */
+ preempt_disable();
+
+ /* wait for the sibling threads to join */
+ first = cpumask_first(topology_sibling_cpumask(cpu));
+ if (!wait_for_siblings(&ifs_test.siblings_in, NSEC_PER_SEC)) {
+ preempt_enable();
+ dev_err(&ifs_pdev->dev, "cpu %d sibling did not join rendezvous\n", cpu);
+ goto out;
+ }
+
+ activate.start = 0;
+ activate.stop = ifs_binary.valid_chunks - 1;
+ timeout = jiffies + HZ / 2;
+ retries = retry;
+
+ while (activate.start <= activate.stop) {
+ if (time_after(jiffies, timeout)) {
+ status.error_code = IFS_SW_TIMEOUT;
+ break;
+ }
+
+ if (noirq)
+ local_irq_disable();
+ /* scan start */
+ wrmsrl(MSR_ACTIVATE_SCAN, activate.data);
+
+ if (noirq)
+ local_irq_enable();
+
+ /*
+ * All logical CPUs on this core are now running IFS test. When it completes
+ * execution or is interrupted, the following RDMSR gets the scan status.
+ */
+
+ rdmsrl(MSR_SCAN_STATUS, status.data);
+
+ /* 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 = retry;
+ activate.start = status.chunk_num;
+ }
+ }
+
+ preempt_enable();
+
+ if (cpu == first) {
+ /* Update status for this core */
+ ifs_test.scan_details = status.data;
+
+ if (status.control_error || status.signature_error) {
+ ifs_test.status = SCAN_TEST_FAIL;
+ message_fail(cpu, status);
+ } else if (status.error_code) {
+ ifs_test.status = SCAN_NOT_TESTED;
+ message_not_tested(cpu, status);
+ } else {
+ ifs_test.status = SCAN_TEST_PASS;
+ }
+ }
+
+ if (!wait_for_siblings(&ifs_test.siblings_out, NSEC_PER_SEC))
+ dev_err(&ifs_pdev->dev, "cpu %d sibling did not exit rendezvous\n", cpu);
+
+out:
+ if (cpu == first)
+ complete(&ifs_test.test_thread_done);
+}
+
+/*
+ * 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 work_struct *local_work;
+ int sibling;
+ int ret = 0;
+ int i = 0;
+
+ cpu_hotplug_disable();
+ if (!cpu_online(cpu)) {
+ dev_info(&ifs_pdev->dev, "cannot test on the offline cpu %d\n", cpu);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ reinit_completion(&ifs_test.test_thread_done);
+ atomic_set(&ifs_test.siblings_in, 0);
+ atomic_set(&ifs_test.siblings_out, 0);
+
+ ifs_test.cpu_sibl_ct = cpumask_weight(topology_sibling_cpumask(cpu));
+ local_work = kcalloc(ifs_test.cpu_sibl_ct, sizeof(struct work_struct), GFP_NOWAIT);
+ if (!local_work) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for_each_cpu(sibling, topology_sibling_cpumask(cpu)) {
+ INIT_WORK(&local_work[i], ifs_work_func);
+ queue_work_on(sibling, ifs_wq, &local_work[i]);
+ i++;
+ }
+
+ if (wait_for_completion_timeout(&ifs_test.test_thread_done, HZ) == 0) {
+ dev_err(&ifs_pdev->dev,
+ "cpu %d Core locked up during IFS test? IFS disabled\n", cpu);
+ ifs_disabled = true;
+ }
+
+ kfree(local_work);
+out:
+ cpu_hotplug_enable();
+ return ret;
+}
--
2.17.1

2022-04-07 21:23:01

by Joseph, Jithu

[permalink] [raw]
Subject: [PATCH v2 05/10] 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: Tony Luck <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
---
drivers/platform/x86/intel/ifs/load.c | 67 +++++++++++++++++++++++++++
1 file changed, 67 insertions(+)

diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c
index a1be4d6558a1..8f2735775f5b 100644
--- a/drivers/platform/x86/intel/ifs/load.c
+++ b/drivers/platform/x86/intel/ifs/load.c
@@ -3,6 +3,7 @@

#include <linux/firmware.h>
#include <linux/platform_device.h>
+#include <asm/microcode_intel.h>

#include "ifs.h"
static const char *ifs_path = "intel/ifs/";
@@ -24,6 +25,67 @@ struct ifs_header {
#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 int ifs_sanity_check(void *mc)
+{
+ struct microcode_header_intel *mc_header = mc;
+ unsigned long total_size, data_size;
+ u32 sum, i;
+
+ 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(&ifs_pdev->dev, "bad ifs data file size.\n");
+ return -EINVAL;
+ }
+
+ if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
+ dev_err(&ifs_pdev->dev, "invalid/unknown ifs update format.\n");
+ return -EINVAL;
+ }
+
+ sum = 0;
+ i = total_size / sizeof(u32);
+ while (i--)
+ sum += ((u32 *)mc)[i];
+
+ if (sum) {
+ dev_err(&ifs_pdev->dev, "bad ifs data checksum, aborting.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static bool find_ifs_matching_signature(struct ucode_cpu_info *uci, void *mc)
+{
+ struct microcode_header_intel *shdr;
+ unsigned int mc_size;
+
+ shdr = (struct microcode_header_intel *)mc;
+ mc_size = get_totalsize(shdr);
+
+ if (!mc_size || ifs_sanity_check(shdr) < 0) {
+ dev_err(&ifs_pdev->dev, "ifs sanity check failure\n");
+ return false;
+ }
+
+ if (!cpu_signatures_match(uci->cpu_sig.sig, uci->cpu_sig.pf, shdr->sig, shdr->pf)) {
+ dev_err(&ifs_pdev->dev, "ifs signature, pf not matching\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool ifs_image_sanity_check(void *data)
+{
+ struct ucode_cpu_info uci;
+
+ cpu_collect_info_early(&uci);
+
+ return find_ifs_matching_signature(&uci, data);
+}

static const struct firmware *load_binary(const char *path)
{
@@ -36,6 +98,11 @@ static const struct firmware *load_binary(const char *path)
goto out;
}

+ if (!ifs_image_sanity_check((void *)fw->data)) {
+ dev_err(&ifs_pdev->dev, "ifs header sanity check failed\n");
+ release_firmware(fw);
+ fw = NULL;
+ }
out:

return fw;
--
2.17.1

2022-04-07 21:23:13

by Joseph, Jithu

[permalink] [raw]
Subject: [PATCH v2 08/10] 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: Tony Luck <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
---
drivers/platform/x86/intel/ifs/Makefile | 2 +-
drivers/platform/x86/intel/ifs/core.c | 1 +
drivers/platform/x86/intel/ifs/ifs.h | 2 +
drivers/platform/x86/intel/ifs/sysfs.c | 139 ++++++++++++++++++++++++
4 files changed, 143 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 d5905e5d2de8..93745fcdf652 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 95847e00038b..85442953d0f5 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -82,6 +82,7 @@ static int __init ifs_init(void)
goto drv_unreg;
}

+ ifs_sysfs_add();
ret = platform_device_add(ifs_pdev);
if (ret) {
pr_err("intel_ifs: platform device add failed\n");
diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
index 93cc1af4aea0..3200d9de4436 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -127,6 +127,8 @@ struct ifs_test {

int load_ifs_binary(void);
int do_core_test(int cpu);
+void ifs_sysfs_add(void);
+
extern struct platform_device *ifs_pdev;
extern struct ifs_binary ifs_binary;
extern struct ifs_test ifs_test;
diff --git a/drivers/platform/x86/intel/ifs/sysfs.c b/drivers/platform/x86/intel/ifs/sysfs.c
new file mode 100644
index 000000000000..f6decebbeae9
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/sysfs.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. */
+
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/semaphore.h>
+#include <linux/slab.h>
+
+#include "ifs.h"
+
+static 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)
+{
+ int ret;
+
+ if (down_trylock(&ifs_sem))
+ return -EBUSY;
+
+ ret = sysfs_emit(buf, "%#llx\n", ifs_test.scan_details);
+ up(&ifs_sem);
+
+ return ret;
+}
+
+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)
+{
+ int ret;
+
+ if (down_trylock(&ifs_sem))
+ return -EBUSY;
+
+ ret = sysfs_emit(buf, "%s\n", status_msg[ifs_test.status]);
+
+ up(&ifs_sem);
+
+ return ret;
+}
+
+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)
+{
+ unsigned int cpu;
+ int ret = count;
+ int rc;
+
+ if (!ifs_binary.loaded) {
+ dev_info(&ifs_pdev->dev, "Load scan binary using driver bind interface\n");
+ return -EPERM;
+ }
+
+ if (ifs_disabled)
+ return -ENXIO;
+
+ rc = kstrtouint(buf, 0, &cpu);
+ if (rc < 0 || cpu >= nr_cpu_ids)
+ return -EINVAL;
+
+ if (down_trylock(&ifs_sem))
+ return -EBUSY;
+
+ rc = do_core_test(cpu);
+ if (rc)
+ ret = rc;
+
+ up(&ifs_sem);
+
+ return ret;
+}
+
+static DEVICE_ATTR_WO(run_test);
+
+/*
+ * Currently loaded IFS image version.
+ */
+static ssize_t image_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "%#x\n", ifs_binary.loaded_version);
+}
+
+static DEVICE_ATTR_RO(image_version);
+
+/* global scan sysfs attributes */
+static struct attribute *plat_ifs_attrs[] = {
+ &dev_attr_image_version.attr,
+ &dev_attr_run_test.attr,
+ &dev_attr_status.attr,
+ &dev_attr_details.attr,
+ NULL
+};
+
+static const struct attribute_group plat_ifs_attr_group = {
+ .attrs = plat_ifs_attrs,
+};
+
+static const struct attribute_group *plat_ifs_groups[] = {
+ &plat_ifs_attr_group,
+ NULL
+};
+
+void ifs_sysfs_add(void)
+{
+ ifs_pdev->dev.groups = plat_ifs_groups;
+}
--
2.17.1

2022-04-07 21:23:17

by Joseph, Jithu

[permalink] [raw]
Subject: [PATCH v2 10/10] trace: platform/x86/intel/ifs: Add trace point to track Intel IFS operations

From: Tony Luck <[email protected]>

Add tracing support which may be useful for debugging systems that fail to complete
In Field Scan tests.

Signed-off-by: Tony Luck <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
---
drivers/platform/x86/intel/ifs/runtest.c | 5 ++++
include/trace/events/intel_ifs.h | 38 ++++++++++++++++++++++++
2 files changed, 43 insertions(+)
create mode 100644 include/trace/events/intel_ifs.h

diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c
index f9c98d84183f..b9fac2ac7107 100644
--- a/drivers/platform/x86/intel/ifs/runtest.c
+++ b/drivers/platform/x86/intel/ifs/runtest.c
@@ -10,6 +10,9 @@

#include "ifs.h"

+#define CREATE_TRACE_POINTS
+#include <trace/events/intel_ifs.h>
+
bool ifs_disabled;

static int ifs_retry_set(const char *val, const struct kernel_param *kp);
@@ -204,6 +207,8 @@ static void ifs_work_func(struct work_struct *work)

rdmsrl(MSR_SCAN_STATUS, status.data);

+ trace_ifs_status(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..0611f370cb37
--- /dev/null
+++ b/include/trace/events/intel_ifs.h
@@ -0,0 +1,38 @@
+/* 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 <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(ifs_status,
+
+ TP_PROTO(union ifs_scan activate, union ifs_status status),
+
+ TP_ARGS(activate, status),
+
+ TP_STRUCT__entry(
+ __field( u64, status )
+ __field( u8, start )
+ __field( u8, stop )
+ ),
+
+ TP_fast_assign(
+ __entry->start = activate.start;
+ __entry->stop = activate.stop;
+ __entry->status = status.data;
+ ),
+
+ TP_printk("start: %.2x, stop: %.2x, status: %llx",
+ __entry->start,
+ __entry->stop,
+ __entry->status)
+);
+
+#endif /* _TRACE_IFS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
2.17.1

2022-04-08 05:34:47

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH v2 08/10] platform/x86/intel/ifs: Add IFS sysfs interface

On Thu, Apr 07, 2022 at 12:13:45PM -0700, Jithu Joseph wrote:
> 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: Tony Luck <[email protected]>
> Signed-off-by: Jithu Joseph <[email protected]>
> ---
> drivers/platform/x86/intel/ifs/Makefile | 2 +-
> drivers/platform/x86/intel/ifs/core.c | 1 +
> drivers/platform/x86/intel/ifs/ifs.h | 2 +
> drivers/platform/x86/intel/ifs/sysfs.c | 139 ++++++++++++++++++++++++
> 4 files changed, 143 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 d5905e5d2de8..93745fcdf652 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 95847e00038b..85442953d0f5 100644
> --- a/drivers/platform/x86/intel/ifs/core.c
> +++ b/drivers/platform/x86/intel/ifs/core.c
> @@ -82,6 +82,7 @@ static int __init ifs_init(void)
> goto drv_unreg;
> }
>
> + ifs_sysfs_add();
> ret = platform_device_add(ifs_pdev);
> if (ret) {
> pr_err("intel_ifs: platform device add failed\n");
> diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
> index 93cc1af4aea0..3200d9de4436 100644
> --- a/drivers/platform/x86/intel/ifs/ifs.h
> +++ b/drivers/platform/x86/intel/ifs/ifs.h
> @@ -127,6 +127,8 @@ struct ifs_test {
>
> int load_ifs_binary(void);
> int do_core_test(int cpu);
> +void ifs_sysfs_add(void);
> +
> extern struct platform_device *ifs_pdev;
> extern struct ifs_binary ifs_binary;
> extern struct ifs_test ifs_test;
> diff --git a/drivers/platform/x86/intel/ifs/sysfs.c b/drivers/platform/x86/intel/ifs/sysfs.c
> new file mode 100644
> index 000000000000..f6decebbeae9
> --- /dev/null
> +++ b/drivers/platform/x86/intel/ifs/sysfs.c
> @@ -0,0 +1,139 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright(c) 2022 Intel Corporation. */
> +
> +#include <linux/cpu.h>
> +#include <linux/delay.h>
> +#include <linux/fs.h>
> +#include <linux/platform_device.h>
> +#include <linux/semaphore.h>
> +#include <linux/slab.h>
> +
> +#include "ifs.h"
> +
> +static 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)
> +{
> + int ret;
> +
> + if (down_trylock(&ifs_sem))
> + return -EBUSY;

Why do you care about locking here at all?

> +
> + ret = sysfs_emit(buf, "%#llx\n", ifs_test.scan_details);
> + up(&ifs_sem);

What are you protecting? The value can change right after the lock is
released, so who cares?

> +
> + return ret;
> +}
> +
> +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)
> +{
> + int ret;
> +
> + if (down_trylock(&ifs_sem))
> + return -EBUSY;
> +
> + ret = sysfs_emit(buf, "%s\n", status_msg[ifs_test.status]);
> +
> + up(&ifs_sem);
> +
> + return ret;
> +}
> +
> +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)
> +{
> + unsigned int cpu;
> + int ret = count;
> + int rc;
> +
> + if (!ifs_binary.loaded) {
> + dev_info(&ifs_pdev->dev, "Load scan binary using driver bind interface\n");

Do not allow userspace to spam kernel logs for no reason :(

sysfs files are not "help files" in the kernel.

> + return -EPERM;
> + }
> +
> + if (ifs_disabled)
> + return -ENXIO;
> +
> + rc = kstrtouint(buf, 0, &cpu);
> + if (rc < 0 || cpu >= nr_cpu_ids)
> + return -EINVAL;
> +
> + if (down_trylock(&ifs_sem))
> + return -EBUSY;
> +
> + rc = do_core_test(cpu);
> + if (rc)
> + ret = rc;
> +
> + up(&ifs_sem);
> +
> + return ret;
> +}
> +
> +static DEVICE_ATTR_WO(run_test);
> +
> +/*
> + * Currently loaded IFS image version.
> + */
> +static ssize_t image_version_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + return sysfs_emit(buf, "%#x\n", ifs_binary.loaded_version);
> +}
> +
> +static DEVICE_ATTR_RO(image_version);
> +
> +/* global scan sysfs attributes */
> +static struct attribute *plat_ifs_attrs[] = {
> + &dev_attr_image_version.attr,
> + &dev_attr_run_test.attr,
> + &dev_attr_status.attr,
> + &dev_attr_details.attr,
> + NULL
> +};
> +
> +static const struct attribute_group plat_ifs_attr_group = {
> + .attrs = plat_ifs_attrs,
> +};
> +
> +static const struct attribute_group *plat_ifs_groups[] = {
> + &plat_ifs_attr_group,
> + NULL
> +};
> +
> +void ifs_sysfs_add(void)
> +{
> + ifs_pdev->dev.groups = plat_ifs_groups;

Why do you have a single global structure?

{sigh}


2022-04-08 05:35:47

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH v2 09/10] platform/x86/intel/ifs: add ABI documentation for IFS

On Thu, Apr 07, 2022 at 12:13:46PM -0700, Jithu Joseph wrote:
> Add the sysfs attributes in ABI/testing for In-Field Scan.
>
> Reviewed-by: Tony Luck <[email protected]>
> Signed-off-by: Jithu Joseph <[email protected]>
> ---
> .../ABI/testing/sysfs-platform-intel-ifs | 54 +++++++++++++++++++
> 1 file changed, 54 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..54dc6cd75484
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-platform-intel-ifs
> @@ -0,0 +1,54 @@
> +What: /sys/devices/platform/intel_ifs/run_test
> +Date: April 07, 2022
> +KernelVersion: 5.19.0

No need for ".0"

> +Contact: "Jithu Joseph" <[email protected]>
> +Description: echo <cpu#> to trigger ifs test for all online cores.
> + For e.g to test cpu5 do echo 5 > /sys/devices/platform/intel_ifs/run_test

So core numbers are different than cpu numbers here? How are users
going to map them?

> +
> +What: /sys/devices/platform/intel_ifs/status
> +Date: April 07, 2022
> +KernelVersion: 5.19.0
> +Contact: "Jithu Joseph" <[email protected]>
> +Description: The status of the last test. It can be one of "pass", "fail"
> + or "untested".
> +
> +What: /sys/devices/system/cpu/cpu#/ifs/details
> +Date: April 07, 2022
> +KernelVersion: 5.19.0
> +Contact: "Jithu Joseph" <[email protected]>
> +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/platform/intel_ifs/image_version
> +Date: April 07, 2022
> +KernelVersion: 5.19.0
> +Contact: "Jithu Joseph" <[email protected]>
> +Description: Version of loaded IFS binary image.

In what format?

> +
> +What: /sys/bus/platform/drivers/intel_ifs/bind
> +Date: April 07, 2022
> +KernelVersion: 5.19.0
> +Contact: "Jithu Joseph" <[email protected]>
> +Description: echo "intel_ifs" to reload IFS image.

Huh? Why are you using a common sysfs file for this type of attribute?
Please do not do so, make it "reload" or something like that.

> +
> +What: /sys/module/intel_ifs/parameters/noirq
> +Date: April 07, 2022
> +KernelVersion: 5.19.0
> +Contact: "Jithu Joseph" <[email protected]>
> +Description: IFS tunable parameter that user can modify before
> + the scan run if they wish to override default value.

And where are those parameters documented? What are valid values here?

> + When set, system interrupts are not allowed to interrupt an IFS. The
> + default state for this parameter is set.

set to what?

> +
> +What: /sys/module/intel_ifs/parameters/retry
> +Date: April 07, 2022
> +KernelVersion: 5.19.0
> +Contact: "Jithu Joseph" <[email protected]>
> +Description: IFS tunable parameter that user can modify before scan run
> + if they wish to override default value.
> +
> + Maximum retry counter when the test is not executed due to an
> + event such as interrupt. The default value is 5, it can be set to any
> + value from 1 to 20.

Why would anyone ever want to change this value? Why doesn't it "just
work" without needing anything tuned?

thanks,

greg k-h

2022-04-08 05:36:22

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH v2 04/10] platform/x86/intel/ifs: Load IFS Image

On Thu, Apr 07, 2022 at 12:13:41PM -0700, Jithu Joseph wrote:
> IFS uses a scan image format that shares the same header as
> microcode updates and deployment approach for these images mirrors
> that of microcode update. Specifically, enable images to be deployed
> relative to a static symlink in /lib/firmware and then load
> into kernel memory via request_firmware().
>
> The image is specific to a processor family, model and stepping.
> IFS requires that a test image be loaded before any ifs test is
> initiated. Load the image that matches processor signature.
> The IFS image is signed by Intel.
>
> The IFS image file follows a similar naming convention as used for
> Intel CPU microcode files. The file must be located in the firmware
> directory where the microcode files are placed and named as {family/model
> /stepping}.scan as below:
>
> /lib/firmware/intel/ifs/{ff-mm-ss}.scan

Is the firmware already submitted to the linux-firmware project for
inclusion there?

If not, where should a user get it from?

thanks,

greg k-h

2022-04-08 05:38:12

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH v2 04/10] platform/x86/intel/ifs: Load IFS Image

On Thu, Apr 07, 2022 at 12:13:41PM -0700, Jithu Joseph wrote:
> IFS uses a scan image format that shares the same header as
> microcode updates and deployment approach for these images mirrors
> that of microcode update. Specifically, enable images to be deployed
> relative to a static symlink in /lib/firmware and then load
> into kernel memory via request_firmware().
>
> The image is specific to a processor family, model and stepping.
> IFS requires that a test image be loaded before any ifs test is
> initiated. Load the image that matches processor signature.
> The IFS image is signed by Intel.
>
> The IFS image file follows a similar naming convention as used for
> Intel CPU microcode files. The file must be located in the firmware
> directory where the microcode files are placed and named as {family/model
> /stepping}.scan as below:
>
> /lib/firmware/intel/ifs/{ff-mm-ss}.scan
>
> Reviewed-by: Tony Luck <[email protected]>
> Signed-off-by: Jithu Joseph <[email protected]>
> ---
> drivers/platform/x86/intel/ifs/Makefile | 2 +-
> drivers/platform/x86/intel/ifs/core.c | 62 ++++++++++++++++++++
> drivers/platform/x86/intel/ifs/ifs.h | 15 +++++
> drivers/platform/x86/intel/ifs/load.c | 76 +++++++++++++++++++++++++
> 4 files changed, 154 insertions(+), 1 deletion(-)
> 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 c44305dff542..b69d026ca9da 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 87956623208f..716f333a064b 100644
> --- a/drivers/platform/x86/intel/ifs/core.c
> +++ b/drivers/platform/x86/intel/ifs/core.c
> @@ -2,10 +2,14 @@
> /* Copyright(c) 2022 Intel Corporation. */
>
> #include <linux/module.h>
> +#include <linux/platform_device.h>
> #include <asm/cpu_device_id.h>
>
> #include "ifs.h"
>
> +struct platform_device *ifs_pdev;
> +struct ifs_binary ifs_binary;

Please no static memory. Use the driver model properly which does not
want you to do this at all.

You should not need this at all. If you do, something is wrong as you
are tying the lifecycle of the memory to the code, not to the device.

{sigh}

greg k-h

2022-04-19 20:56:29

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v3 00/11] Introduce In Field Scan driver

Longer description of what this does, and why it is useful in the v2 cover
letter here:
https://lore.kernel.org/all/[email protected]/

But the TL;DR version is this driver loads scan test files that can
check whether silicon in a CPU core is still running correctly. It
is expected that these tests would be run several times per day to
catch problems as silicon ages.

I'm posting this update because I missed many major issues when I added
my review tag. So I have a moral obligation to fix up the things that
I missed.

Changes since V2:

Dan Williams (offline):
----------------------
1) Provided the clue to split into a tiny driver that enumerates and
registers the device. Then the IFS driver can attach to that an behave
much more like a normal driver (original idea from Andy Lutomirski,
used for pmem/nvdimms)

2 .. many) Lots more pointers, tips, and general good guidance to make both
the code and commit comments better and easier to understand.

Boris:
-----
1) Add "intel_" prefixes to the two functions moving to wider scope.

Done.

2) Move the declarations from <asm/microcode_intel.h> to <asm/cpu.h>

Done.

3) intel_cpu_signatures_match() is small enough to be "inline".

Done.

Greg:
----
1) Is the firmware already submitted to the linux-firmware project for
inclusion there?
If not, where should a user get it from?

The scan files will be distributed by Intel on Github in much the
same way that microcode is distributed today.

2) > +struct ifs_binary ifs_binary;

Please no static memory. Use the driver model properly which does not
want you to do this at all.

You should not need this at all. If you do, something is wrong as you
are tying the lifecycle of the memory to the code, not to the device.

Moved this (and ifs_test) to dynamic allocation using devm_kzalloc()
and attaching the resulting pointer to the device with dev_set_drvdata().

3) > +static ssize_t details_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + int ret;
> +
> + if (down_trylock(&ifs_sem))
> + return -EBUSY;

Why do you care about locking here at all?

> +
> + ret = sysfs_emit(buf, "%#llx\n", ifs_test.scan_details);
> + up(&ifs_sem);

What are you protecting? The value can change right after the lock is
released, so who cares?

Removed locking from status and details show() functions. Running a test
is synchronous. So:
# echo 3 > run_test
# cat status
# cat details
will give the results of the core 3 test as expected. It is up to the user
to not do dumb things like reading status/details from another process in
parallel with running tests.

4) > + if (!ifs_binary.loaded) {
> + dev_info(&ifs_pdev->dev, "Load scan binary using driver bind interface\n");

Do not allow userspace to spam kernel logs for no reason :(

sysfs files are not "help files" in the kernel.

Spam removed.

5) > +void ifs_sysfs_add(void)
> +{
> + ifs_pdev->dev.groups = plat_ifs_groups;

Why do you have a single global structure?

All instances of the driver for different tests can use the same files
and functions. They use "struct ifs_data *ifsd = dev_get_drvdata(dev);"
to operate on the correct driver instance.

6) > +KernelVersion: 5.19.0

No need for ".0"

Removed.

7) > + For e.g to test cpu5 do echo 5 > /sys/devices/platform/intel_ifs/run_test

So core numbers are different than cpu numbers here? How are users
going to map them?

Added some extra text here to say that tests are per core, but any thread
on the core can be used to run the test. Should I also point people at
/sys/devices/system/cpu/cpu#/topology/thread_siblings_list? It seems
easy for users to get a list of cores with a script like:
$ cores=$(cat /sys/devices/system/cpu/cpu*/topology/thread_siblings_list | sed -e 's/,.*//' | sort -n | uniq)

8) > +Description: Version of loaded IFS binary image.

In what format?

Added "(hexadecimal)". Also added code (and Docs) to print "none" if the load
of the scan file failed.

9) > +Description: echo "intel_ifs" to reload IFS image.

Huh? Why are you using a common sysfs file for this type of attribute?
Please do not do so, make it "reload" or something like that.

Ok. Added a "reload" file like microcode. (Though using driver bind/unbind
also works).

10) > +Description: IFS tunable parameter that user can modify before
> + the scan run if they wish to override default value.

And where are those parameters documented? What are valid values here?

Dropped both the "noirq" and "retry" parameters. I think they now have sane
defaults. If Jithu/Ashok have a good use case, they can send a patch to add
them back.

-Tony


Jithu Joseph (7):
x86/microcode/intel: Expose collect_cpu_info_early() for IFS
platform/x86/intel/ifs: Read IFS firmware image
platform/x86/intel/ifs: Check IFS Image sanity
platform/x86/intel/ifs: Authenticate and copy to secured memory
platform/x86/intel/ifs: Add scan test support
platform/x86/intel/ifs: Add IFS sysfs interface
platform/x86/intel/ifs: add ABI documentation for IFS

Tony Luck (4):
Documentation: In-Field Scan
platform/x86/intel/ifs: Create device for Intel IFS (In Field Scan)
platform/x86/intel/ifs: Add stub driver for In-Field Scan
trace: platform/x86/intel/ifs: Add trace point to track Intel IFS
operations

.../ABI/testing/sysfs-platform-intel-ifs | 39 ++
Documentation/x86/ifs.rst | 101 ++++++
Documentation/x86/index.rst | 1 +
MAINTAINERS | 8 +
arch/x86/include/asm/cpu.h | 18 +
arch/x86/kernel/cpu/intel.c | 32 ++
arch/x86/kernel/cpu/microcode/intel.c | 59 +---
drivers/platform/x86/intel/Kconfig | 1 +
drivers/platform/x86/intel/Makefile | 1 +
drivers/platform/x86/intel/ifs/Kconfig | 16 +
drivers/platform/x86/intel/ifs/Makefile | 5 +
drivers/platform/x86/intel/ifs/core.c | 74 ++++
drivers/platform/x86/intel/ifs/ifs.h | 103 ++++++
.../platform/x86/intel/ifs/intel_ifs_device.c | 50 +++
drivers/platform/x86/intel/ifs/load.c | 265 ++++++++++++++
drivers/platform/x86/intel/ifs/runtest.c | 333 ++++++++++++++++++
drivers/platform/x86/intel/ifs/sysfs.c | 151 ++++++++
include/trace/events/intel_ifs.h | 38 ++
18 files changed, 1243 insertions(+), 52 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-platform-intel-ifs
create mode 100644 Documentation/x86/ifs.rst
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
create mode 100644 drivers/platform/x86/intel/ifs/ifs.h
create mode 100644 drivers/platform/x86/intel/ifs/intel_ifs_device.c
create mode 100644 drivers/platform/x86/intel/ifs/load.c
create mode 100644 drivers/platform/x86/intel/ifs/runtest.c
create mode 100644 drivers/platform/x86/intel/ifs/sysfs.c
create mode 100644 include/trace/events/intel_ifs.h


base-commit: b2d229d4ddb17db541098b83524d901257e93845
--
2.35.1

2022-04-20 12:56:28

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v3 04/11] 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.

[1]: https://www.youtube.com/watch?v=QMF3rqhjYuM

Kconfig for this driver selects CONFIG_INTEL_IFS_DEVICE so the base
kernel will be built with code to create the device to which this driver
will attach.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Tony Luck <[email protected]>

---
Not using module_platform_driver() for this simple stub because
later patches need to add init()/exit() functions.
---
drivers/platform/x86/intel/ifs/Kconfig | 14 ++++++++++++
drivers/platform/x86/intel/ifs/Makefile | 4 ++++
drivers/platform/x86/intel/ifs/core.c | 29 +++++++++++++++++++++++++
3 files changed, 47 insertions(+)
create mode 100644 drivers/platform/x86/intel/ifs/core.c

diff --git a/drivers/platform/x86/intel/ifs/Kconfig b/drivers/platform/x86/intel/ifs/Kconfig
index 51325b699563..0aa5ecc5ef42 100644
--- a/drivers/platform/x86/intel/ifs/Kconfig
+++ b/drivers/platform/x86/intel/ifs/Kconfig
@@ -1,2 +1,16 @@
config INTEL_IFS_DEVICE
bool
+
+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
+ driver 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
index 12c2f5ce9925..bf8adc57892c 100644
--- a/drivers/platform/x86/intel/ifs/Makefile
+++ b/drivers/platform/x86/intel/ifs/Makefile
@@ -1 +1,5 @@
obj-$(CONFIG_INTEL_IFS_DEVICE) += intel_ifs_device.o
+
+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..eb34b877dac0
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+static struct platform_driver intel_ifs_driver = {
+ .driver = {
+ .name = "intel_ifs",
+ },
+};
+
+static int __init ifs_init(void)
+{
+ return platform_driver_register(&intel_ifs_driver);
+}
+
+static void __exit ifs_exit(void)
+{
+ platform_driver_unregister(&intel_ifs_driver);
+}
+
+module_init(ifs_init);
+module_exit(ifs_exit);
+
+MODULE_ALIAS("platform:intel_ifs*");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel In Field Scan (IFS) driver");
--
2.35.1

2022-04-20 19:56:20

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v3 01/11] x86/microcode/intel: Expose collect_cpu_info_early() for IFS

From: Jithu Joseph <[email protected]>

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.

Rename collect_cpu_info_early() to intel_cpu_collect_info_early() and
EXPORT_SYMBOL_GPL() it. Add declaration to x86 <asm/cpu.h>

Make cpu_signatures_match() an inline function in x86 <asm/cpu.h>,
and also give it an "intel_" prefix.

No functional change intended.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
arch/x86/include/asm/cpu.h | 18 ++++++++
arch/x86/kernel/cpu/intel.c | 32 +++++++++++++++
arch/x86/kernel/cpu/microcode/intel.c | 59 ++++-----------------------
3 files changed, 57 insertions(+), 52 deletions(-)

diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index 86e5e4e26fcb..c245b2196657 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -76,4 +76,22 @@ static inline void init_ia32_feat_ctl(struct cpuinfo_x86 *c) {}

extern __noendbr void cet_disable(void);

+struct ucode_cpu_info;
+
+int intel_cpu_collect_info_early(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 f7a5370a9b3b..bb717cd847b4 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_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;
+}
+EXPORT_SYMBOL_GPL(intel_cpu_collect_info_early);
+
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 d28a9f8f3fec..5184bd06416c 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_early(&uci);

sig = uci.cpu_sig.sig;
pf = uci.cpu_sig.pf;
@@ -502,7 +457,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_early(&uci);
print_ucode_info(&uci, current_mc_date);
delay_ucode_info = 0;
}
@@ -604,7 +559,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_early(&uci);

scan_microcode(cp.data, cp.size, &uci, true);

@@ -637,7 +592,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_early(uci);

return scan_microcode(cp.data, cp.size, uci, false);
}
@@ -712,7 +667,7 @@ void reload_ucode_intel(void)
struct microcode_intel *p;
struct ucode_cpu_info uci;

- collect_cpu_info_early(&uci);
+ intel_cpu_collect_info_early(&uci);

p = find_patch(&uci);
if (!p)
--
2.35.1

2022-04-21 13:10:31

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v3 03/11] platform/x86/intel/ifs: Create device for Intel IFS (In Field Scan)

The initial implementation of IFS is model specific. Enumeration is
via a combination of family-model-stepping and a check for a bit in the
CORE_CAPABILITIES MSR.

Linux has handled this lack of enumeration before with a code stub to
create a device. See arch/x86/kernel/pmem.c. Use the same approach
here.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
MAINTAINERS | 7 +++
drivers/platform/x86/intel/Kconfig | 1 +
drivers/platform/x86/intel/Makefile | 1 +
drivers/platform/x86/intel/ifs/Kconfig | 2 +
drivers/platform/x86/intel/ifs/Makefile | 1 +
.../platform/x86/intel/ifs/intel_ifs_device.c | 50 +++++++++++++++++++
6 files changed, 62 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/intel_ifs_device.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 40fa1955ca3f..9e372a960fa5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9861,6 +9861,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) DRIVER
+M: Jithu Joseph <[email protected]>
+R: Ashok Raj <[email protected]>
+R: Tony Luck <[email protected]>
+S: Maintained
+F: drivers/platform/x86/intel/ifs
+
INTEL INTEGRATED SENSOR HUB DRIVER
M: Srinivas Pandruvada <[email protected]>
M: Jiri Kosina <[email protected]>
diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig
index 1f01a8a23c57..794968bda115 100644
--- a/drivers/platform/x86/intel/Kconfig
+++ b/drivers/platform/x86/intel/Kconfig
@@ -4,6 +4,7 @@
#

source "drivers/platform/x86/intel/atomisp2/Kconfig"
+source "drivers/platform/x86/intel/ifs/Kconfig"
source "drivers/platform/x86/intel/int1092/Kconfig"
source "drivers/platform/x86/intel/int3472/Kconfig"
source "drivers/platform/x86/intel/pmc/Kconfig"
diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile
index c61bc3e97121..10285d0fd16a 100644
--- a/drivers/platform/x86/intel/Makefile
+++ b/drivers/platform/x86/intel/Makefile
@@ -5,6 +5,7 @@
#

obj-$(CONFIG_INTEL_ATOMISP2_PDX86) += atomisp2/
+obj-y += ifs/
obj-$(CONFIG_INTEL_SAR_INT1092) += int1092/
obj-$(CONFIG_INTEL_SKL_INT3472) += int3472/
obj-$(CONFIG_INTEL_PMC_CORE) += pmc/
diff --git a/drivers/platform/x86/intel/ifs/Kconfig b/drivers/platform/x86/intel/ifs/Kconfig
new file mode 100644
index 000000000000..51325b699563
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/Kconfig
@@ -0,0 +1,2 @@
+config INTEL_IFS_DEVICE
+ bool
diff --git a/drivers/platform/x86/intel/ifs/Makefile b/drivers/platform/x86/intel/ifs/Makefile
new file mode 100644
index 000000000000..12c2f5ce9925
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_INTEL_IFS_DEVICE) += intel_ifs_device.o
diff --git a/drivers/platform/x86/intel/ifs/intel_ifs_device.c b/drivers/platform/x86/intel/ifs/intel_ifs_device.c
new file mode 100644
index 000000000000..64a143871d72
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/intel_ifs_device.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2022 Intel Corporation. */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <asm/cpu_device_id.h>
+
+#define MSR_IA32_CORE_CAPS_INTEGRITY_BIT 2
+#define MSR_IA32_CORE_CAPS_INTEGRITY BIT(MSR_IA32_CORE_CAPS_INTEGRITY_BIT)
+
+#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),
+ {}
+};
+
+static __init int register_ifs_device(void)
+{
+ struct platform_device *pdev;
+ const struct x86_cpu_id *m;
+ u64 ia32_core_caps;
+
+ m = x86_match_cpu(ifs_cpu_ids);
+ if (!m)
+ return -ENODEV;
+
+ if (rdmsrl_safe(MSR_IA32_CORE_CAPS, &ia32_core_caps))
+ return -ENODEV;
+
+ if (ia32_core_caps & MSR_IA32_CORE_CAPS_INTEGRITY) {
+ pdev = platform_device_alloc("intel_ifs", 0);
+ if (pdev) {
+ if (platform_device_add(pdev))
+ platform_device_put(pdev);
+ }
+ }
+
+ /*
+ * Failure here will be visible by a missing device
+ * in sysfs. Returning an error code would not make
+ * that any easier to diagnose. Would also complicate
+ * future implementations that may support a subset of
+ * the types of tests.
+ */
+ return 0;
+}
+device_initcall(register_ifs_device);
--
2.35.1

2022-04-21 14:39:16

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v3 10/11] 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.

Reviewed-by: Dan Williams <[email protected]
Signed-off-by: Tony Luck <[email protected]>
---
MAINTAINERS | 1 +
drivers/platform/x86/intel/ifs/runtest.c | 5 ++++
include/trace/events/intel_ifs.h | 38 ++++++++++++++++++++++++
3 files changed, 44 insertions(+)
create mode 100644 include/trace/events/intel_ifs.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 9e372a960fa5..b488ff628a43 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9867,6 +9867,7 @@ R: Ashok Raj <[email protected]>
R: Tony Luck <[email protected]>
S: Maintained
F: drivers/platform/x86/intel/ifs
+F: include/trace/events/intel_ifs.h

INTEL INTEGRATED SENSOR HUB DRIVER
M: Srinivas Pandruvada <[email protected]>
diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c
index 246eff250563..c6fa9385dda0 100644
--- a/drivers/platform/x86/intel/ifs/runtest.c
+++ b/drivers/platform/x86/intel/ifs/runtest.c
@@ -24,6 +24,9 @@ static atomic_t siblings_out;
static int cpu_sibl_ct;
static bool scan_enabled = true;

+#define CREATE_TRACE_POINTS
+#include <trace/events/intel_ifs.h>
+
struct ifs_work {
struct work_struct w;
struct device *dev;
@@ -217,6 +220,8 @@ static void ifs_work_func(struct work_struct *work)

rdmsrl(MSR_SCAN_STATUS, status.data);

+ trace_ifs_status(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..0611f370cb37
--- /dev/null
+++ b/include/trace/events/intel_ifs.h
@@ -0,0 +1,38 @@
+/* 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 <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(ifs_status,
+
+ TP_PROTO(union ifs_scan activate, union ifs_status status),
+
+ TP_ARGS(activate, status),
+
+ TP_STRUCT__entry(
+ __field( u64, status )
+ __field( u8, start )
+ __field( u8, stop )
+ ),
+
+ TP_fast_assign(
+ __entry->start = activate.start;
+ __entry->stop = activate.stop;
+ __entry->status = status.data;
+ ),
+
+ TP_printk("start: %.2x, stop: %.2x, status: %llx",
+ __entry->start,
+ __entry->stop,
+ __entry->status)
+);
+
+#endif /* _TRACE_IFS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
2.35.1

2022-04-22 02:00:21

by Steven Rostedt

[permalink] [raw]
Subject: Re: [PATCH v3 10/11] trace: platform/x86/intel/ifs: Add trace point to track Intel IFS operations

On Tue, 19 Apr 2022 09:38:58 -0700
Tony Luck <[email protected]> wrote:

> +TRACE_EVENT(ifs_status,
> +
> + TP_PROTO(union ifs_scan activate, union ifs_status status),

Really, you want to pass the structure in by value, so that we have two
copies? One to get to this function and then one to write to the ring
buffer?

-- Steve


> +
> + TP_ARGS(activate, status),
> +
> + TP_STRUCT__entry(
> + __field( u64, status )
> + __field( u8, start )
> + __field( u8, stop )
> + ),
> +
> + TP_fast_assign(
> + __entry->start = activate.start;
> + __entry->stop = activate.stop;
> + __entry->status = status.data;
> + ),
> +
> + TP_printk("start: %.2x, stop: %.2x, status: %llx",
> + __entry->start,
> + __entry->stop,
> + __entry->status)
> +);
> +
> +#endif /* _TRACE_IFS_H */

2022-04-22 11:59:53

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v3 02/11] 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
as well as tunable parameters.

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 <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
Documentation/x86/ifs.rst | 101 ++++++++++++++++++++++++++++++++++++
Documentation/x86/index.rst | 1 +
2 files changed, 102 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..62f3c07d433a
--- /dev/null
+++ b/Documentation/x86/ifs.rst
@@ -0,0 +1,101 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============
+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/bus/platform/drivers/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.
+
+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/platform/intel_ifs.0/
+to control execution:
+
+Test a specific core::
+
+ # echo <cpu#> > /sys/devices/platform/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. It is only necessary to test one
+thread.
+
+For e.g. to test core corresponding to cpu5
+
+ # echo 5 > /sys/devices/platform/intel_ifs.0/run_test
+
+Results of the last test is provided in /sys::
+
+ $ cat /sys/devices/platform/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/platform/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
diff --git a/Documentation/x86/index.rst b/Documentation/x86/index.rst
index 91b2fa456618..9d8e8a73d57b 100644
--- a/Documentation/x86/index.rst
+++ b/Documentation/x86/index.rst
@@ -35,6 +35,7 @@ x86-specific Documentation
usb-legacy-support
i386/index
x86_64/index
+ ifs
sva
sgx
features
--
2.35.1

2022-04-22 17:07:51

by Dan Williams

[permalink] [raw]
Subject: Re: [PATCH v3 03/11] platform/x86/intel/ifs: Create device for Intel IFS (In Field Scan)

On Tue, Apr 19, 2022 at 11:09 AM Dan Williams <[email protected]> wrote:
>
> On Tue, Apr 19, 2022 at 9:48 AM Greg KH <[email protected]> wrote:
> >
> > On Tue, Apr 19, 2022 at 09:38:51AM -0700, Tony Luck wrote:
> > > The initial implementation of IFS is model specific. Enumeration is
> > > via a combination of family-model-stepping and a check for a bit in the
> > > CORE_CAPABILITIES MSR.
> > >
> > > Linux has handled this lack of enumeration before with a code stub to
> > > create a device. See arch/x86/kernel/pmem.c. Use the same approach
> > > here.
> >
> > Ick, why? Why not just create a simple virtual device and use that? Do
> > you really want to bind a driver to this? Or do you already "know" the
> > only driver that you have will bind to this?
>
> With the realization that there may be multiple instances of an
> IFS-like capability going forward, and that ideally those capabilities
> would move away from a CPU capability bit to an ACPI description, then
> it seemed to me that a simulated platform_device for this is a
> reasonable fit. I.e. when / if an ACPI _HID is assigned for this
> capability the same platform_driver can be reused for those instances.

Turns out the ACPI enumeration for this may not materialize, so this
can indeed move to a simple / driver-less device.

2022-04-22 17:43:36

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v3 07/11] platform/x86/intel/ifs: Authenticate and copy to secured memory

From: Jithu Joseph <[email protected]>

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
also 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.

The ifs hash copy and authentication only needs to be done on the first
logical cpu of each socket.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
drivers/platform/x86/intel/ifs/ifs.h | 33 ++++++
drivers/platform/x86/intel/ifs/load.c | 165 ++++++++++++++++++++++++++
2 files changed, 198 insertions(+)

diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
index dacc8b6ce159..c51e285fc7ba 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -4,14 +4,47 @@
#ifndef _IFS_H_
#define _IFS_H_

+#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
* @loaded_version: stores the currently loaded ifs image version.
* @loaded: If a valid test binary has been loaded into the memory
+ * @valid_chunks: number of chunks which could be validated.
*/
struct ifs_data {
int loaded_version;
bool loaded;
+ int valid_chunks;
};

int load_ifs_binary(struct device *dev);
diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c
index b05d9055c391..04072ed84071 100644
--- a/drivers/platform/x86/intel/ifs/load.c
+++ b/drivers/platform/x86/intel/ifs/load.c
@@ -3,10 +3,169 @@

#include <linux/firmware.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <asm/cpu.h>
#include <asm/microcode_intel.h>

+#include "ifs.h"
+
static const char *ifs_path = "intel/ifs/";
+static bool ifs_loading_error; /* error occurred during ifs hashes/chunk authentication.*/
+
+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 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(void *arg)
+{
+ union ifs_scan_hashes_status hashes_status;
+ union ifs_chunks_auth_status chunk_status;
+ int i, num_chunks, chunk_size;
+ struct device *dev = arg;
+ struct ifs_data *ifsd;
+ u64 linear_addr, base;
+ u32 err_code;
+
+ ifsd = dev_get_drvdata(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) {
+ ifs_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);
+ return;
+ }
+ dev_err(dev, "Hash copy error : %s", scan_hash_status[err_code]);
+ return;
+ }
+
+ /* 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) {
+ ifs_loading_error = true;
+ if (err_code >= ARRAY_SIZE(scan_authentication_status)) {
+ dev_err(dev,
+ "invalid error code 0x%x for authentication\n", err_code);
+ return;
+ }
+ dev_err(dev, "Chunk authentication error %s\n",
+ scan_authentication_status[err_code]);
+ return;
+ }
+ }
+}
+
+/*
+ * 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 = dev_get_drvdata(dev);
+ bool *package_authenticated;
+ 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;
+ ifs_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;
+ package_authenticated[curr_pkg] = 1;
+ ret = smp_call_function_single(cpu, copy_hashes_authenticate_chunks,
+ dev, 1);
+ if (ret || ifs_loading_error) {
+ ret = ifs_loading_error ? -ENOMEM : ret;
+ goto out;
+ }
+ }
+
+out:
+ cpus_read_unlock();
+ kfree(package_authenticated);
+
+ return ret;
+}

static int ifs_sanity_check(struct device *dev, void *mc)
{
@@ -92,8 +251,14 @@ int load_ifs_binary(struct device *dev)
if (!ifs_image_sanity_check(dev, (void *)fw->data)) {
dev_err(dev, "ifs header sanity check failed\n");
ret = -ENOENT;
+ 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);

return ret;
--
2.35.1

2022-04-22 17:52:41

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH v3 03/11] platform/x86/intel/ifs: Create device for Intel IFS (In Field Scan)

On Tue, Apr 19, 2022 at 03:28:26PM -0700, Dan Williams wrote:
> On Tue, Apr 19, 2022 at 11:09 AM Dan Williams <[email protected]> wrote:
> >
> > On Tue, Apr 19, 2022 at 9:48 AM Greg KH <[email protected]> wrote:
> > >
> > > On Tue, Apr 19, 2022 at 09:38:51AM -0700, Tony Luck wrote:
> > > > The initial implementation of IFS is model specific. Enumeration is
> > > > via a combination of family-model-stepping and a check for a bit in the
> > > > CORE_CAPABILITIES MSR.
> > > >
> > > > Linux has handled this lack of enumeration before with a code stub to
> > > > create a device. See arch/x86/kernel/pmem.c. Use the same approach
> > > > here.
> > >
> > > Ick, why? Why not just create a simple virtual device and use that? Do
> > > you really want to bind a driver to this? Or do you already "know" the
> > > only driver that you have will bind to this?
> >
> > With the realization that there may be multiple instances of an
> > IFS-like capability going forward, and that ideally those capabilities
> > would move away from a CPU capability bit to an ACPI description, then
> > it seemed to me that a simulated platform_device for this is a
> > reasonable fit. I.e. when / if an ACPI _HID is assigned for this
> > capability the same platform_driver can be reused for those instances.
>
> Turns out the ACPI enumeration for this may not materialize, so this
> can indeed move to a simple / driver-less device.

Hey, see, doing extra work now was not a good idea :)

2022-04-22 18:04:08

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v3 11/11] platform/x86/intel/ifs: add ABI documentation for IFS

From: Jithu Joseph <[email protected]>

Add the sysfs attributes in ABI/testing for In-Field Scan.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
.../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..7a753c9f2dd7
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-intel-ifs
@@ -0,0 +1,39 @@
+What: /sys/devices/platform/intel_ifs.<N>/run_test
+Date: April 13, 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: Write <cpu#> 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.<N>/run_test
+
+What: /sys/devices/platform/intel_ifs.<N>/status
+Date: April 13, 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: The status of the last test. It can be one of "pass", "fail"
+ or "untested".
+
+What: /sys/devices/system/cpu/cpu#/ifs.<N>/details
+Date: April 13, 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+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/platform/intel_ifs.<N>/image_version
+Date: April 13, 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: Version (hexadecimal) of loaded IFS binary image. If no scan image
+ is loaded reports "none".
+
+What: /sys/bus/platform/drivers/intel_ifs.<N>/reload
+Date: April 13, 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: Write "1" > reload to reload IFS image from
+ /lib/firmware/intel/ifs/ff-mm-ss.scan.
--
2.35.1

2022-04-22 19:06:45

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH v3 03/11] platform/x86/intel/ifs: Create device for Intel IFS (In Field Scan)

On Wed, Apr 20, 2022 at 06:08:20PM +0000, Luck, Tony wrote:
> >> Or is it ok for them all to sit at the top level of /sys/devices/virtual?
> >
> > How many do you have?
> >
> > And why is a directory needed for just one tiny driver type?
>
> One today. Two tomorrow (internally ... next gen CPU).
>
> Three eventually (That's how many are on the roadmap that I can see).

Then just use a misc device, it's simple and saves you a ton of code.

2022-04-22 20:13:37

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v3 06/11] platform/x86/intel/ifs: Check IFS Image sanity

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
drivers/platform/x86/intel/ifs/load.c | 69 +++++++++++++++++++++++++++
1 file changed, 69 insertions(+)

diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c
index fa6c64707a73..b05d9055c391 100644
--- a/drivers/platform/x86/intel/ifs/load.c
+++ b/drivers/platform/x86/intel/ifs/load.c
@@ -3,9 +3,73 @@

#include <linux/firmware.h>
#include <linux/platform_device.h>
+#include <asm/cpu.h>
+#include <asm/microcode_intel.h>

static const char *ifs_path = "intel/ifs/";

+static int ifs_sanity_check(struct device *dev, void *mc)
+{
+ struct microcode_header_intel *mc_header = mc;
+ unsigned long total_size, data_size;
+ u32 sum, i;
+
+ 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;
+ }
+
+ sum = 0;
+ i = total_size / sizeof(u32);
+ while (i--)
+ sum += ((u32 *)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, void *mc)
+{
+ struct microcode_header_intel *shdr;
+ unsigned int mc_size;
+
+ shdr = (struct microcode_header_intel *)mc;
+ 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, void *data)
+{
+ struct ucode_cpu_info uci;
+
+ intel_cpu_collect_info_early(&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}.
@@ -25,6 +89,11 @@ int load_ifs_binary(struct device *dev)
return ret;
}

+ if (!ifs_image_sanity_check(dev, (void *)fw->data)) {
+ dev_err(dev, "ifs header sanity check failed\n");
+ ret = -ENOENT;
+ }
+
release_firmware(fw);

return ret;
--
2.35.1

2022-04-22 20:18:07

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v3 08/11] platform/x86/intel/ifs: Add scan test support

From: Jithu Joseph <[email protected]>

In a core, the scan engine is shared between sibling cpus.

When a Scan test (for a particular core) is triggered by the user,
worker threads for each sibling cpus(belonging to that core) are
queued to execute the scan test function in the Workqueue context.

All the siblings rendezvous before the test execution. The scan
results are same for all siblings.

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
drivers/platform/x86/intel/ifs/Makefile | 2 +-
drivers/platform/x86/intel/ifs/core.c | 15 +-
drivers/platform/x86/intel/ifs/ifs.h | 48 ++++
drivers/platform/x86/intel/ifs/runtest.c | 321 +++++++++++++++++++++++
4 files changed, 384 insertions(+), 2 deletions(-)
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 eab0cc81f38e..7de27361b479 100644
--- a/drivers/platform/x86/intel/ifs/Makefile
+++ b/drivers/platform/x86/intel/ifs/Makefile
@@ -2,4 +2,4 @@ obj-$(CONFIG_INTEL_IFS_DEVICE) += intel_ifs_device.o

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/core.c b/drivers/platform/x86/intel/ifs/core.c
index 139449f11a64..0dc4cdda35ff 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -35,11 +35,24 @@ static struct platform_driver intel_ifs_driver = {

static int __init ifs_init(void)
{
- return platform_driver_register(&intel_ifs_driver);
+ int ret;
+
+ ret = platform_driver_register(&intel_ifs_driver);
+ if (ret)
+ return ret;
+
+ ret = ifs_setup_wq();
+ if (ret) {
+ platform_driver_unregister(&intel_ifs_driver);
+ return ret;
+ }
+
+ return 0;
}

static void __exit ifs_exit(void)
{
+ ifs_destroy_wq();
platform_driver_unregister(&intel_ifs_driver);
}

diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
index c51e285fc7ba..f5e3636d709f 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -8,6 +8,13 @@
#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
+#define SPINUNIT 100
+#define THREAD_WAIT 5

/* MSR_SCAN_HASHES_STATUS bit fields */
union ifs_scan_hashes_status {
@@ -35,18 +42,59 @@ 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
* @loaded_version: stores the currently loaded ifs image version.
* @loaded: If a valid test binary has been loaded into the memory
* @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 loaded_version;
bool loaded;
int valid_chunks;
+ int status;
+ u64 scan_details;
};

int load_ifs_binary(struct device *dev);
+int ifs_setup_wq(void);
+void ifs_destroy_wq(void);
+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..7793a01f7b94
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/runtest.c
@@ -0,0 +1,321 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. */
+
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/nmi.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "ifs.h"
+
+static struct workqueue_struct *ifs_wq;
+static struct completion test_thread_done;
+static atomic_t siblings_in;
+static atomic_t siblings_out;
+static int cpu_sibl_ct;
+static bool scan_enabled = true;
+
+struct ifs_work {
+ struct work_struct w;
+ struct device *dev;
+};
+
+/* Max retries on the same chunk */
+#define MAX_IFS_RETRIES 5
+
+static unsigned long msec_to_tsc(unsigned long msec)
+{
+ return tsc_khz * 1000 * msec / MSEC_PER_SEC;
+}
+
+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(topology_sibling_cpumask(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(topology_sibling_cpumask(cpu)));
+ else if (status.error_code == IFS_SW_PARTIAL_COMPLETION)
+ dev_info(dev, "CPU(s) %*pbl: %s\n",
+ cpumask_pr_args(topology_sibling_cpumask(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(topology_sibling_cpumask(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(topology_sibling_cpumask(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(topology_sibling_cpumask(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;
+}
+
+static bool wait_for_siblings(struct device *dev, struct ifs_data *ifsd, atomic_t *t, long long timeout)
+{
+ atomic_inc(t);
+ while (atomic_read(t) < cpu_sibl_ct) {
+ if (timeout < SPINUNIT) {
+ dev_err(dev,
+ "Timeout while waiting for CPUs rendezvous, remaining: %d\n",
+ cpu_sibl_ct - atomic_read(t));
+ return false;
+ }
+
+ ndelay(SPINUNIT);
+ timeout -= SPINUNIT;
+
+ touch_nmi_watchdog();
+ }
+
+ return true;
+}
+
+/*
+ * When a Scan test (for a particular core) is triggered by the user, worker threads
+ * for each sibling cpus(belonging to that core) are queued to execute this function in
+ * the Workqueue (ifs_wq) context.
+ * Wait for the sibling thread to join before the execution.
+ * Execute the scan test by running wrmsr(MSR_ACTIVATE_SCAN).
+ */
+static void ifs_work_func(struct work_struct *work)
+{
+ struct ifs_work *local_work = container_of(work, struct ifs_work, w);
+ int cpu = smp_processor_id();
+ union ifs_scan activate;
+ union ifs_status status;
+ unsigned long timeout;
+ struct ifs_data *ifsd;
+ struct device *dev;
+ int retries;
+ u32 first;
+
+ dev = local_work->dev;
+ ifsd = dev_get_drvdata(dev);
+
+ activate.rsvd = 0;
+ activate.delay = msec_to_tsc(THREAD_WAIT);
+ activate.sigmce = 0;
+
+ /*
+ * Need to get (and keep) the threads on this core executing close together
+ * so that the writes to MSR_ACTIVATE_SCAN below will succeed in entering
+ * IFS test mode on this core. Interrupts on each thread are expected to be
+ * brief. But preemption would be a problem.
+ */
+ preempt_disable();
+
+ /* wait for the sibling threads to join */
+ first = cpumask_first(topology_sibling_cpumask(cpu));
+ if (!wait_for_siblings(dev, ifsd, &siblings_in, NSEC_PER_SEC)) {
+ preempt_enable();
+ dev_err(dev, "cpu %d sibling did not join rendezvous\n", cpu);
+ goto out;
+ }
+
+ 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;
+ }
+
+ local_irq_disable();
+ wrmsrl(MSR_ACTIVATE_SCAN, activate.data);
+ local_irq_enable();
+
+ /*
+ * All logical CPUs on this core are now running IFS test. When it completes
+ * execution or is interrupted, the following RDMSR gets the scan status.
+ */
+
+ rdmsrl(MSR_SCAN_STATUS, status.data);
+
+ /* 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;
+ }
+ }
+
+ preempt_enable();
+
+ if (cpu == first) {
+ /* 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;
+ }
+ }
+
+ if (!wait_for_siblings(dev, ifsd, &siblings_out, NSEC_PER_SEC))
+ dev_err(dev, "cpu %d sibling did not exit rendezvous\n", cpu);
+
+out:
+ if (cpu == first)
+ complete(&test_thread_done);
+}
+
+/*
+ * 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)
+{
+ struct ifs_work *local_work;
+ int sibling;
+ int ret = 0;
+ int i = 0;
+
+ if (!scan_enabled)
+ return -ENXIO;
+
+ cpu_hotplug_disable();
+ if (!cpu_online(cpu)) {
+ dev_info(dev, "cannot test on the offline cpu %d\n", cpu);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ reinit_completion(&test_thread_done);
+ atomic_set(&siblings_in, 0);
+ atomic_set(&siblings_out, 0);
+
+ cpu_sibl_ct = cpumask_weight(topology_sibling_cpumask(cpu));
+ local_work = kcalloc(cpu_sibl_ct, sizeof(*local_work), GFP_NOWAIT);
+ if (!local_work) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for_each_cpu(sibling, topology_sibling_cpumask(cpu)) {
+ local_work[i].dev = dev;
+ INIT_WORK(&local_work[i].w, ifs_work_func);
+ queue_work_on(sibling, ifs_wq, &local_work[i].w);
+ i++;
+ }
+
+ if (wait_for_completion_timeout(&test_thread_done, HZ) == 0) {
+ dev_err(dev, "cpu %d Core locked up during IFS test? IFS disabled\n", cpu);
+ scan_enabled = false;
+ }
+
+ kfree(local_work);
+out:
+ cpu_hotplug_enable();
+ return ret;
+}
+
+int ifs_setup_wq(void)
+{
+ /* Flags are to keep all the sibling cpu worker threads (of a core) in close sync */
+ ifs_wq = alloc_workqueue("intel_ifs", (WQ_HIGHPRI | WQ_CPU_INTENSIVE), 1);
+ if (!ifs_wq)
+ return -ENOMEM;
+
+ init_completion(&test_thread_done);
+
+ return 0;
+}
+
+void ifs_destroy_wq(void)
+{
+ destroy_workqueue(ifs_wq);
+}
--
2.35.1

2022-04-22 20:25:19

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v3 09/11] platform/x86/intel/ifs: Add IFS sysfs interface

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
drivers/platform/x86/intel/ifs/Makefile | 2 +-
drivers/platform/x86/intel/ifs/core.c | 9 ++
drivers/platform/x86/intel/ifs/ifs.h | 3 +
drivers/platform/x86/intel/ifs/runtest.c | 7 ++
drivers/platform/x86/intel/ifs/sysfs.c | 151 +++++++++++++++++++++++
5 files changed, 171 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 7de27361b479..dbbe0bf66987 100644
--- a/drivers/platform/x86/intel/ifs/Makefile
+++ b/drivers/platform/x86/intel/ifs/Makefile
@@ -2,4 +2,4 @@ obj-$(CONFIG_INTEL_IFS_DEVICE) += intel_ifs_device.o

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 0dc4cdda35ff..f56cde0cdfd6 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -3,6 +3,7 @@

#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/semaphore.h>

#include "ifs.h"

@@ -26,10 +27,18 @@ static int ifs_probe(struct platform_device *pdev)
return 0;
}

+/*
+ * Note there is no need for a ->remove() call back. There isn't an
+ * "unload" operation to remove the scan binary from the BIOS reserved
+ * area. Also ".dev_groups" removal order will guarantee that any in
+ * flight tests have completed.
+ */
+
static struct platform_driver intel_ifs_driver = {
.probe = ifs_probe,
.driver = {
.name = "intel_ifs",
+ .dev_groups = plat_ifs_groups,
},
};

diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
index f5e3636d709f..4e6662f2d2f8 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -97,4 +97,7 @@ int ifs_setup_wq(void);
void ifs_destroy_wq(void);
int do_core_test(int cpu, struct device *dev);

+extern const struct attribute_group *plat_ifs_groups[];
+extern struct semaphore ifs_sem;
+
#endif
diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c
index 7793a01f7b94..246eff250563 100644
--- a/drivers/platform/x86/intel/ifs/runtest.c
+++ b/drivers/platform/x86/intel/ifs/runtest.c
@@ -10,6 +10,13 @@

#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 and indicate
+ * completion.
+ */
static struct workqueue_struct *ifs_wq;
static struct completion test_thread_done;
static atomic_t siblings_in;
diff --git a/drivers/platform/x86/intel/ifs/sysfs.c b/drivers/platform/x86/intel/ifs/sysfs.c
new file mode 100644
index 000000000000..41db2a12fbc8
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/sysfs.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. */
+
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/semaphore.h>
+#include <linux/slab.h>
+
+#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 = dev_get_drvdata(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 = dev_get_drvdata(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 = dev_get_drvdata(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 = dev_get_drvdata(dev);
+ int rc;
+
+ if (!sysfs_streq(buf, "1"))
+ return -EINVAL;
+
+ if (down_interruptible(&ifs_sem))
+ return -EINTR;
+
+ rc = load_ifs_binary(dev);
+
+ ifsd->loaded = (rc == 0);
+
+ up(&ifs_sem);
+
+ return rc ? rc : count;
+}
+
+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 = dev_get_drvdata(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
+};
+
+static const struct attribute_group plat_ifs_attr_group = {
+ .attrs = plat_ifs_attrs,
+};
+
+const struct attribute_group *plat_ifs_groups[] = {
+ &plat_ifs_attr_group,
+ NULL
+};
--
2.35.1

2022-04-22 21:23:20

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v3 05/11] platform/x86/intel/ifs: Read IFS firmware image

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
drivers/platform/x86/intel/ifs/Makefile | 2 +-
drivers/platform/x86/intel/ifs/core.c | 23 ++++++++++++++++++
drivers/platform/x86/intel/ifs/ifs.h | 19 +++++++++++++++
drivers/platform/x86/intel/ifs/load.c | 31 +++++++++++++++++++++++++
4 files changed, 74 insertions(+), 1 deletion(-)
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 bf8adc57892c..eab0cc81f38e 100644
--- a/drivers/platform/x86/intel/ifs/Makefile
+++ b/drivers/platform/x86/intel/ifs/Makefile
@@ -2,4 +2,4 @@ obj-$(CONFIG_INTEL_IFS_DEVICE) += intel_ifs_device.o

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 eb34b877dac0..139449f11a64 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -4,7 +4,30 @@
#include <linux/module.h>
#include <linux/platform_device.h>

+#include "ifs.h"
+
+static int ifs_probe(struct platform_device *pdev)
+{
+ struct ifs_data *ifsd;
+
+ ifsd = devm_kzalloc(&pdev->dev, sizeof(*ifsd), GFP_KERNEL);
+ if (!ifsd)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, ifsd);
+
+ switch (pdev->id) {
+ case 0:
+ /* Load IFS binary to BIOS reserved memory area */
+ ifsd->loaded = !load_ifs_binary(&pdev->dev);
+ break;
+ }
+
+ return 0;
+}
+
static struct platform_driver intel_ifs_driver = {
+ .probe = ifs_probe,
.driver = {
.name = "intel_ifs",
},
diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
new file mode 100644
index 000000000000..dacc8b6ce159
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright(c) 2022 Intel Corporation. */
+
+#ifndef _IFS_H_
+#define _IFS_H_
+
+/**
+ * struct ifs_data - attributes related to intel IFS driver
+ * @loaded_version: stores the currently loaded ifs image version.
+ * @loaded: If a valid test binary has been loaded into the memory
+ */
+struct ifs_data {
+ int loaded_version;
+ bool loaded;
+};
+
+int load_ifs_binary(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..fa6c64707a73
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/load.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. */
+
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+static const char *ifs_path = "intel/ifs/";
+
+/*
+ * 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}.
+ */
+int load_ifs_binary(struct device *dev)
+{
+ const struct firmware *fw;
+ char scan_path[256];
+ int ret;
+
+ snprintf(scan_path, sizeof(scan_path), "%s%02x-%02x-%02x.scan", ifs_path,
+ 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 ret;
+ }
+
+ release_firmware(fw);
+
+ return ret;
+}
--
2.35.1

2022-04-22 21:47:04

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH v3 02/11] Documentation: In-Field Scan

On Tue, Apr 19, 2022 at 09:38:50AM -0700, Tony Luck wrote:
> 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
> as well as tunable parameters.
>
> 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 <[email protected]>
> Signed-off-by: Tony Luck <[email protected]>
> ---
> Documentation/x86/ifs.rst | 101 ++++++++++++++++++++++++++++++++++++
> Documentation/x86/index.rst | 1 +
> 2 files changed, 102 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..62f3c07d433a
> --- /dev/null
> +++ b/Documentation/x86/ifs.rst
> @@ -0,0 +1,101 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +=============
> +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/bus/platform/drivers/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.
> +
> +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/platform/intel_ifs.0/
> +to control execution:
> +
> +Test a specific core::
> +
> + # echo <cpu#> > /sys/devices/platform/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. It is only necessary to test one
> +thread.
> +
> +For e.g. to test core corresponding to cpu5
> +
> + # echo 5 > /sys/devices/platform/intel_ifs.0/run_test
> +
> +Results of the last test is provided in /sys::
> +
> + $ cat /sys/devices/platform/intel_ifs.0/status
> + pass

sysfs documentation belongs in Documentation/ABI/

And why not just include this whole thing in the driver itself and suck
the documentation out of that? No need to have a separate file.

thanks,

greg k-h

2022-04-22 22:23:12

by Luck, Tony

[permalink] [raw]
Subject: RE: [PATCH v3 10/11] trace: platform/x86/intel/ifs: Add trace point to track Intel IFS operations

>> +TRACE_EVENT(ifs_status,
>> +
>> + TP_PROTO(union ifs_scan activate, union ifs_status status),
>
> Really, you want to pass the structure in by value, so that we have two
> copies? One to get to this function and then one to write to the ring
> buffer?

These "structures" are just bitfield helpers for a u64 that is passed into
WRMSR (in the case of activate) and received back from RDMSR in
the case of status.

So this is really just a pair of u64 arguments, with the compiler handling
the bit field extractions into the ring buffer.

Here are the definitions:

union ifs_scan {
u64 data;
struct {
u32 start :8;
u32 stop :8;
u32 rsvd :16;
u32 delay :31;
u32 sigmce :1;
};
};

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

Would it be better to do the bit extractions of the start/stop fields first?

-Tony


2022-04-22 22:40:11

by Dan Williams

[permalink] [raw]
Subject: Re: [PATCH v3 02/11] Documentation: In-Field Scan

On Tue, Apr 19, 2022 at 9:48 AM Greg KH <[email protected]> wrote:
>
> On Tue, Apr 19, 2022 at 09:38:50AM -0700, Tony Luck wrote:
> > 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
> > as well as tunable parameters.
> >
> > 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 <[email protected]>
> > Signed-off-by: Tony Luck <[email protected]>
> > ---
> > Documentation/x86/ifs.rst | 101 ++++++++++++++++++++++++++++++++++++
> > Documentation/x86/index.rst | 1 +
> > 2 files changed, 102 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..62f3c07d433a
> > --- /dev/null
> > +++ b/Documentation/x86/ifs.rst
> > @@ -0,0 +1,101 @@
> > +.. SPDX-License-Identifier: GPL-2.0
> > +
> > +=============
> > +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/bus/platform/drivers/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.
> > +
> > +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/platform/intel_ifs.0/
> > +to control execution:
> > +
> > +Test a specific core::
> > +
> > + # echo <cpu#> > /sys/devices/platform/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. It is only necessary to test one
> > +thread.
> > +
> > +For e.g. to test core corresponding to cpu5
> > +
> > + # echo 5 > /sys/devices/platform/intel_ifs.0/run_test
> > +
> > +Results of the last test is provided in /sys::
> > +
> > + $ cat /sys/devices/platform/intel_ifs.0/status
> > + pass
>
> sysfs documentation belongs in Documentation/ABI/
>
> And why not just include this whole thing in the driver itself and suck
> the documentation out of that? No need to have a separate file.

At a minimum a separate file is needed to house the
---
.. kernel-doc:: $source_file
:doc: $header
---
...statements, but ok, I'll recommend that going forward to
de-emphasize shipping content directly from Documentation/ when it can
be ingested from "DOC:" source. I had been assuming DOC: blocks in the
code were more for augmenting kernel-doc on driver internal ABIs and
not longer theory of operation documentation that is an awkward fit
for Documentation/ABI/.

2022-04-22 22:41:18

by Steven Rostedt

[permalink] [raw]
Subject: Re: [PATCH v3 10/11] trace: platform/x86/intel/ifs: Add trace point to track Intel IFS operations

On Thu, 21 Apr 2022 04:26:39 +0000
"Luck, Tony" <[email protected]> wrote:

> >> +TRACE_EVENT(ifs_status,
> >> +
> >> + TP_PROTO(union ifs_scan activate, union ifs_status status),
> >
> > Really, you want to pass the structure in by value, so that we have two
> > copies? One to get to this function and then one to write to the ring
> > buffer?
>
> These "structures" are just bitfield helpers for a u64 that is passed into
> WRMSR (in the case of activate) and received back from RDMSR in
> the case of status.
>
> So this is really just a pair of u64 arguments, with the compiler handling
> the bit field extractions into the ring buffer.

I was just wondering if passing by reference would be better, but as you
stated, they are just two u64 arguments.

>
> Here are the definitions:
>
> union ifs_scan {
> u64 data;
> struct {
> u32 start :8;
> u32 stop :8;
> u32 rsvd :16;
> u32 delay :31;
> u32 sigmce :1;
> };
> };
>
> 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;
> };
> };
>
> Would it be better to do the bit extractions of the start/stop fields first?

No, I'm just paranoid about passing structures / unions in by value and not
reference. If you are fine with this, then I'm OK too.

-- Steve

2022-04-22 23:08:58

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v4 00/10] Introduce In Field Scan driver

TL;DR this driver loads scan test files that can check whether silicon
in a CPU core is still running correctly. It is expected that these tests
would be run several times per day to catch problems as silicon ages.

Changes since v3:

Thomas Gleixner:
----------------
1) intel_collect_cpu_info_early() ... function name doesn't make sense
in context of this driver

True: Dropped the "_early" suffix from the name.

Greg Kroah-Hartman:
-------------------
1) "Ick, why?" and "pmem.c should not be used as a good example of anything"
and "Why not just use a misc device?"

Now using a misc device.

2) "So even if everything fails, you succeed?"

This was w.r.t. the "pmem"-like driver, which is completely gone in
v4. New driver succeeds if any of the test-types enumerate as present
on the system. Fails with -ENODEV if no test types found.

3) "sysfs documentation belongs in Documentation/ABI/"

See patch 10 of this series.

4) "And why not just include this whole thing in the driver itself and suck
the documentation out of that? No need to have a separate file."

Dropped Documentation/x86/ifs.rst from v4. People should be able to
figure out how to use it from the ABI docs for the sysfs files. If
that turns out to be wrong, we can revisit.

5) "int load_ifs_binary(struct device *dev)
Shouldn't all of your global symbols start with "ifs_"? Your other ones
seem to, what went wrong here?
Also, how about "ifs_load_firmware()" makes more sense."

Changed name to ifs_load_firmware()

6) "static bool ifs_image_sanity_check(struct device *dev, void *data)
u8 *data?" and
"if (!ifs_image_sanity_check(dev, (void *)fw->data)) {
It's not a void pointer, it's a pointer to u8. Why cast it away?"

Changed the top of that call stack to cast to "(struct microcode_header_intel *)
which is what the lower level functions all want.

7) "if (!sysfs_streq(buf, "1"))
kstrtobool()?

Changed from sysfs_streq() to kstrtobool()

8) "ATTRIBUTE_GROUPS()?"

Now using this macro.

Steven Rostedt:
---------------
1) "TP_PROTO(union ifs_scan activate, union ifs_status status),

Really, you want to pass the structure in by value, so that we have two
copies? One to get to this function and then one to write to the ring
buffer?"

Discussion on list resolved because these "pass by value" objects are
just wrappers around a u64. Passing pointers wouldn't make any real
difference. No code change.

Jithu Joseph (7):
x86/microcode/intel: Expose collect_cpu_info_early() for IFS
platform/x86/intel/ifs: Read IFS firmware image
platform/x86/intel/ifs: Check IFS Image sanity
platform/x86/intel/ifs: Authenticate and copy to secured memory
platform/x86/intel/ifs: Add scan test support
platform/x86/intel/ifs: Add IFS sysfs interface
platform/x86/intel/ifs: add ABI documentation for IFS

Tony Luck (3):
x86/msr-index: Define INTEGRITY_CAPABILITIES MSR
platform/x86/intel/ifs: Add stub driver for In-Field Scan
trace: platform/x86/intel/ifs: Add trace point to track Intel IFS
operations

.../ABI/testing/sysfs-platform-intel-ifs | 39 ++
MAINTAINERS | 8 +
arch/x86/include/asm/cpu.h | 18 +
arch/x86/include/asm/msr-index.h | 7 +
arch/x86/kernel/cpu/intel.c | 32 ++
arch/x86/kernel/cpu/microcode/intel.c | 59 +---
drivers/platform/x86/intel/Kconfig | 1 +
drivers/platform/x86/intel/Makefile | 1 +
drivers/platform/x86/intel/ifs/Kconfig | 13 +
drivers/platform/x86/intel/ifs/Makefile | 3 +
drivers/platform/x86/intel/ifs/core.c | 97 +++++
drivers/platform/x86/intel/ifs/ifs.h | 123 +++++++
drivers/platform/x86/intel/ifs/load.c | 262 ++++++++++++++
drivers/platform/x86/intel/ifs/runtest.c | 332 ++++++++++++++++++
drivers/platform/x86/intel/ifs/sysfs.c | 147 ++++++++
include/trace/events/intel_ifs.h | 38 ++
16 files changed, 1128 insertions(+), 52 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-platform-intel-ifs
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
create mode 100644 drivers/platform/x86/intel/ifs/ifs.h
create mode 100644 drivers/platform/x86/intel/ifs/load.c
create mode 100644 drivers/platform/x86/intel/ifs/runtest.c
create mode 100644 drivers/platform/x86/intel/ifs/sysfs.c
create mode 100644 include/trace/events/intel_ifs.h


base-commit: b2d229d4ddb17db541098b83524d901257e93845
--
2.35.1

2022-04-22 23:09:16

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v4 07/10] platform/x86/intel/ifs: Add scan test support

From: Jithu Joseph <[email protected]>

In a core, the scan engine is shared between sibling cpus.

When a Scan test (for a particular core) is triggered by the user,
worker threads for each sibling cpus(belonging to that core) are
queued to execute the scan test function in the Workqueue context.

All the siblings rendezvous before the test execution. The scan
results are same for all siblings.

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
drivers/platform/x86/intel/ifs/Makefile | 2 +-
drivers/platform/x86/intel/ifs/core.c | 7 +
drivers/platform/x86/intel/ifs/ifs.h | 48 ++++
drivers/platform/x86/intel/ifs/runtest.c | 327 +++++++++++++++++++++++
4 files changed, 383 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/core.c b/drivers/platform/x86/intel/ifs/core.c
index ed4ded6755b2..fa4a6b13c1e2 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -57,6 +57,9 @@ static int __init ifs_init(void)
if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval))
return -ENODEV;

+ if (ifs_setup_wq())
+ return -ENOMEM;
+
for (i = 0; i < IFS_NUMTESTS; i++) {
if (!(msrval & BIT(ifs_devices[i].data.integrity_cap_bit)))
continue;
@@ -67,6 +70,9 @@ static int __init ifs_init(void)
}
}

+ if (!ndevices)
+ ifs_destroy_wq();
+
return ndevices ? 0 : -ENODEV;
}

@@ -77,6 +83,7 @@ static void __exit ifs_exit(void)
for (i = 0; i < IFS_NUMTESTS; i++)
if (ifs_devices[i].misc.this_device)
misc_deregister(&ifs_devices[i].misc);
+ ifs_destroy_wq();
}

module_init(ifs_init);
diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
index a9e73346cd28..1df796227ace 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -11,6 +11,13 @@
#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
+#define SPINUNIT 100
+#define THREAD_WAIT 5

/* MSR_SCAN_HASHES_STATUS bit fields */
union ifs_scan_hashes_status {
@@ -38,6 +45,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 +86,8 @@ union ifs_chunks_auth_status {
* @loaded: If a valid test binary has been loaded into the memory
* @loading_error: Error occured 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 +95,8 @@ struct ifs_data {
bool loaded;
bool loading_error;
int valid_chunks;
+ int status;
+ u64 scan_details;
};

struct ifs_device {
@@ -68,5 +113,8 @@ static inline struct ifs_data *ifs_get_data(struct device *dev)
}

void ifs_load_firmware(struct device *dev);
+int ifs_setup_wq(void);
+void ifs_destroy_wq(void);
+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..c30cc9c95b4f
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/runtest.c
@@ -0,0 +1,327 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. */
+
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/nmi.h>
+#include <linux/slab.h>
+
+#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 and indicate
+ * completion.
+ */
+static struct workqueue_struct *ifs_wq;
+static struct completion test_thread_done;
+static atomic_t siblings_in;
+static atomic_t siblings_out;
+static int cpu_sibl_ct;
+static bool scan_enabled = true;
+
+struct ifs_work {
+ struct work_struct w;
+ struct device *dev;
+};
+
+/* Max retries on the same chunk */
+#define MAX_IFS_RETRIES 5
+
+static unsigned long msec_to_tsc(unsigned long msec)
+{
+ return tsc_khz * 1000 * msec / MSEC_PER_SEC;
+}
+
+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(topology_sibling_cpumask(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(topology_sibling_cpumask(cpu)));
+ else if (status.error_code == IFS_SW_PARTIAL_COMPLETION)
+ dev_info(dev, "CPU(s) %*pbl: %s\n",
+ cpumask_pr_args(topology_sibling_cpumask(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(topology_sibling_cpumask(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(topology_sibling_cpumask(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(topology_sibling_cpumask(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;
+}
+
+static bool wait_for_siblings(struct device *dev, struct ifs_data *ifsd, atomic_t *t, long long timeout)
+{
+ atomic_inc(t);
+ while (atomic_read(t) < cpu_sibl_ct) {
+ if (timeout < SPINUNIT) {
+ dev_err(dev,
+ "Timeout while waiting for CPUs rendezvous, remaining: %d\n",
+ cpu_sibl_ct - atomic_read(t));
+ return false;
+ }
+
+ ndelay(SPINUNIT);
+ timeout -= SPINUNIT;
+
+ touch_nmi_watchdog();
+ }
+
+ return true;
+}
+
+/*
+ * When a Scan test (for a particular core) is triggered by the user, worker threads
+ * for each sibling cpus(belonging to that core) are queued to execute this function in
+ * the Workqueue (ifs_wq) context.
+ * Wait for the sibling thread to join before the execution.
+ * Execute the scan test by running wrmsr(MSR_ACTIVATE_SCAN).
+ */
+static void ifs_work_func(struct work_struct *work)
+{
+ struct ifs_work *local_work = container_of(work, struct ifs_work, w);
+ int cpu = smp_processor_id();
+ union ifs_scan activate;
+ union ifs_status status;
+ unsigned long timeout;
+ struct ifs_data *ifsd;
+ struct device *dev;
+ int retries;
+ u32 first;
+
+ dev = local_work->dev;
+ ifsd = ifs_get_data(dev);
+
+ activate.rsvd = 0;
+ activate.delay = msec_to_tsc(THREAD_WAIT);
+ activate.sigmce = 0;
+
+ /*
+ * Need to get (and keep) the threads on this core executing close together
+ * so that the writes to MSR_ACTIVATE_SCAN below will succeed in entering
+ * IFS test mode on this core. Interrupts on each thread are expected to be
+ * brief. But preemption would be a problem.
+ */
+ preempt_disable();
+
+ /* wait for the sibling threads to join */
+ first = cpumask_first(topology_sibling_cpumask(cpu));
+ if (!wait_for_siblings(dev, ifsd, &siblings_in, NSEC_PER_SEC)) {
+ preempt_enable();
+ dev_err(dev, "cpu %d sibling did not join rendezvous\n", cpu);
+ goto out;
+ }
+
+ 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;
+ }
+
+ local_irq_disable();
+ wrmsrl(MSR_ACTIVATE_SCAN, activate.data);
+ local_irq_enable();
+
+ /*
+ * All logical CPUs on this core are now running IFS test. When it completes
+ * execution or is interrupted, the following RDMSR gets the scan status.
+ */
+
+ rdmsrl(MSR_SCAN_STATUS, status.data);
+
+ /* 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;
+ }
+ }
+
+ preempt_enable();
+
+ if (cpu == first) {
+ /* 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;
+ }
+ }
+
+ if (!wait_for_siblings(dev, ifsd, &siblings_out, NSEC_PER_SEC))
+ dev_err(dev, "cpu %d sibling did not exit rendezvous\n", cpu);
+
+out:
+ if (cpu == first)
+ complete(&test_thread_done);
+}
+
+/*
+ * 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)
+{
+ struct ifs_work *local_work;
+ int sibling;
+ int ret = 0;
+ int i = 0;
+
+ if (!scan_enabled)
+ return -ENXIO;
+
+ cpu_hotplug_disable();
+ if (!cpu_online(cpu)) {
+ dev_info(dev, "cannot test on the offline cpu %d\n", cpu);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ reinit_completion(&test_thread_done);
+ atomic_set(&siblings_in, 0);
+ atomic_set(&siblings_out, 0);
+
+ cpu_sibl_ct = cpumask_weight(topology_sibling_cpumask(cpu));
+ local_work = kcalloc(cpu_sibl_ct, sizeof(*local_work), GFP_NOWAIT);
+ if (!local_work) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for_each_cpu(sibling, topology_sibling_cpumask(cpu)) {
+ local_work[i].dev = dev;
+ INIT_WORK(&local_work[i].w, ifs_work_func);
+ queue_work_on(sibling, ifs_wq, &local_work[i].w);
+ i++;
+ }
+
+ if (wait_for_completion_timeout(&test_thread_done, HZ) == 0) {
+ dev_err(dev, "cpu %d Core locked up during IFS test? IFS disabled\n", cpu);
+ scan_enabled = false;
+ }
+
+ kfree(local_work);
+out:
+ cpu_hotplug_enable();
+ return ret;
+}
+
+int ifs_setup_wq(void)
+{
+ /* Flags are to keep all the sibling cpu worker threads (of a core) in close sync */
+ ifs_wq = alloc_workqueue("intel_ifs", (WQ_HIGHPRI | WQ_CPU_INTENSIVE), 1);
+ if (!ifs_wq)
+ return -ENOMEM;
+
+ init_completion(&test_thread_done);
+
+ return 0;
+}
+
+void ifs_destroy_wq(void)
+{
+ destroy_workqueue(ifs_wq);
+}
--
2.35.1

2022-04-22 23:09:27

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v4 06/10] platform/x86/intel/ifs: Authenticate and copy to secured memory

From: Jithu Joseph <[email protected]>

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
also 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.

The ifs hash copy and authentication only needs to be done on the first
logical cpu of each socket.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
drivers/platform/x86/intel/ifs/ifs.h | 47 +++++++
drivers/platform/x86/intel/ifs/load.c | 170 +++++++++++++++++++++++++-
2 files changed, 215 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
index 9a0f8e2077e2..a9e73346cd28 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -7,12 +7,51 @@
#include <linux/device.h>
#include <linux/miscdevice.h>

+#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_device {
@@ -20,6 +59,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 aece78d1c757..46a9b78aa195 100644
--- a/drivers/platform/x86/intel/ifs/load.c
+++ b/drivers/platform/x86/intel/ifs/load.c
@@ -3,10 +3,166 @@

#include <linux/firmware.h>
#include <asm/cpu.h>
+#include <linux/slab.h>
#include <asm/microcode_intel.h>

#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 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(void *arg)
+{
+ union ifs_scan_hashes_status hashes_status;
+ union ifs_chunks_auth_status chunk_status;
+ int i, num_chunks, chunk_size;
+ struct device *dev = arg;
+ 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);
+ return;
+ }
+ dev_err(dev, "Hash copy error : %s", scan_hash_status[err_code]);
+ return;
+ }
+
+ /* 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);
+ return;
+ }
+ dev_err(dev, "Chunk authentication error %s\n",
+ scan_authentication_status[err_code]);
+ return;
+ }
+ }
+}
+
+/*
+ * 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;
+ 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;
+ package_authenticated[curr_pkg] = 1;
+ ret = smp_call_function_single(cpu, copy_hashes_authenticate_chunks,
+ dev, 1);
+ if (ret || ifsd->loading_error) {
+ ret = ifsd->loading_error ? -ENOMEM : ret;
+ goto out;
+ }
+ }
+
+out:
+ cpus_read_unlock();
+ kfree(package_authenticated);
+
+ return ret;
+}
+
static int ifs_sanity_check(struct device *dev,
const struct microcode_header_intel *mc_header)
{
@@ -76,6 +232,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;
@@ -86,11 +243,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);
}
--
2.35.1

2022-04-22 23:09:31

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v4 01/10] x86/microcode/intel: Expose collect_cpu_info_early() for IFS

From: Jithu Joseph <[email protected]>

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 <asm/cpu.h>

Make cpu_signatures_match() an inline function in x86 <asm/cpu.h>,
and also give it an "intel_" prefix.

No functional change intended.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
arch/x86/include/asm/cpu.h | 18 ++++++++
arch/x86/kernel/cpu/intel.c | 32 +++++++++++++++
arch/x86/kernel/cpu/microcode/intel.c | 59 ++++-----------------------
3 files changed, 57 insertions(+), 52 deletions(-)

diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index 86e5e4e26fcb..990167357c34 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -76,4 +76,22 @@ static inline void init_ia32_feat_ctl(struct cpuinfo_x86 *c) {}

extern __noendbr void cet_disable(void);

+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 f7a5370a9b3b..94779146275d 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 d28a9f8f3fec..025c8f0cd948 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;
@@ -502,7 +457,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;
}
@@ -604,7 +559,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);

@@ -637,7 +592,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);
}
@@ -712,7 +667,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)
--
2.35.1

2022-04-22 23:09:44

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v4 05/10] platform/x86/intel/ifs: Check IFS Image sanity

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
drivers/platform/x86/intel/ifs/load.c | 68 +++++++++++++++++++++++++++
1 file changed, 68 insertions(+)

diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c
index 9fb71d38c819..aece78d1c757 100644
--- a/drivers/platform/x86/intel/ifs/load.c
+++ b/drivers/platform/x86/intel/ifs/load.c
@@ -2,9 +2,74 @@
/* Copyright(c) 2022 Intel Corporation. */

#include <linux/firmware.h>
+#include <asm/cpu.h>
+#include <asm/microcode_intel.h>

#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, i;
+ u8 *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 = (u8 *)mc_header;
+ sum = 0;
+ i = total_size / sizeof(u32);
+ while (i--)
+ sum += ((u32 *)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 +89,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);
}
--
2.35.1

2022-04-22 23:10:38

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v4 09/10] 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.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
MAINTAINERS | 1 +
drivers/platform/x86/intel/ifs/runtest.c | 5 ++++
include/trace/events/intel_ifs.h | 38 ++++++++++++++++++++++++
3 files changed, 44 insertions(+)
create mode 100644 include/trace/events/intel_ifs.h

diff --git a/MAINTAINERS b/MAINTAINERS
index d2ee63193ab3..abcf9b895ea8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9867,6 +9867,7 @@ R: Ashok Raj <[email protected]>
R: Tony Luck <[email protected]>
S: Maintained
F: drivers/platform/x86/intel/ifs
+F: include/trace/events/intel_ifs.h

INTEL INTEGRATED SENSOR HUB DRIVER
M: Srinivas Pandruvada <[email protected]>
diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c
index c30cc9c95b4f..d6cb5d9e44c2 100644
--- a/drivers/platform/x86/intel/ifs/runtest.c
+++ b/drivers/platform/x86/intel/ifs/runtest.c
@@ -23,6 +23,9 @@ static atomic_t siblings_out;
static int cpu_sibl_ct;
static bool scan_enabled = true;

+#define CREATE_TRACE_POINTS
+#include <trace/events/intel_ifs.h>
+
struct ifs_work {
struct work_struct w;
struct device *dev;
@@ -216,6 +219,8 @@ static void ifs_work_func(struct work_struct *work)

rdmsrl(MSR_SCAN_STATUS, status.data);

+ trace_ifs_status(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..0611f370cb37
--- /dev/null
+++ b/include/trace/events/intel_ifs.h
@@ -0,0 +1,38 @@
+/* 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 <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(ifs_status,
+
+ TP_PROTO(union ifs_scan activate, union ifs_status status),
+
+ TP_ARGS(activate, status),
+
+ TP_STRUCT__entry(
+ __field( u64, status )
+ __field( u8, start )
+ __field( u8, stop )
+ ),
+
+ TP_fast_assign(
+ __entry->start = activate.start;
+ __entry->stop = activate.stop;
+ __entry->status = status.data;
+ ),
+
+ TP_printk("start: %.2x, stop: %.2x, status: %llx",
+ __entry->start,
+ __entry->stop,
+ __entry->status)
+);
+
+#endif /* _TRACE_IFS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
2.35.1

2022-04-22 23:10:44

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v4 10/10] platform/x86/intel/ifs: add ABI documentation for IFS

From: Jithu Joseph <[email protected]>

Add the sysfs attributes in ABI/testing for In-Field Scan.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
.../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_<N>/run_test
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: Write <cpu#> 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.<N>/run_test
+
+What: /sys/devices/virtual/misc/intel_ifs_<N>/status
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: The status of the last test. It can be one of "pass", "fail"
+ or "untested".
+
+What: /sys/devices/virtual/misc/intel_ifs_<N>/details
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+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_<N>/image_version
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: Version (hexadecimal) of loaded IFS binary image. If no scan image
+ is loaded reports "none".
+
+What: /sys/devices/virtual/misc/intel_ifs_<N>/reload
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: Write "1" (or "y" or "Y") to reload the IFS image from
+ /lib/firmware/intel/ifs/ff-mm-ss.scan.
--
2.35.1

2022-04-22 23:11:43

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v4 02/10] 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 <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
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 ee15311b6be1..c3dc7ae32f1f 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -76,6 +76,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)

@@ -154,6 +156,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
--
2.35.1

2022-04-22 23:11:59

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v4 08/10] platform/x86/intel/ifs: Add IFS sysfs interface

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
drivers/platform/x86/intel/ifs/Makefile | 2 +-
drivers/platform/x86/intel/ifs/core.c | 4 +
drivers/platform/x86/intel/ifs/ifs.h | 3 +
drivers/platform/x86/intel/ifs/sysfs.c | 147 ++++++++++++++++++++++++
4 files changed, 155 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 fa4a6b13c1e2..317ed3225307 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -3,6 +3,7 @@

#include <linux/module.h>
#include <linux/kdev_t.h>
+#include <linux/semaphore.h>

#include <asm/cpu_device_id.h>

@@ -64,9 +65,12 @@ static int __init ifs_init(void)
if (!(msrval & BIT(ifs_devices[i].data.integrity_cap_bit)))
continue;

+ ifs_devices[i].misc.groups = ifs_get_groups();
if (!misc_register(&ifs_devices[i].misc)) {
ndevices++;
+ down(&ifs_sem);
ifs_load_firmware(ifs_devices[i].misc.this_device);
+ up(&ifs_sem);
}
}

diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
index 1df796227ace..2ba03b21e2f8 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -116,5 +116,8 @@ void ifs_load_firmware(struct device *dev);
int ifs_setup_wq(void);
void ifs_destroy_wq(void);
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..8f3b0fb5a423
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/sysfs.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. */
+
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/semaphore.h>
+#include <linux/slab.h>
+
+#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)
+{
+ 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 count;
+}
+
+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;
+}
--
2.35.1

2022-04-22 23:11:59

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v4 04/10] platform/x86/intel/ifs: Read IFS firmware image

From: Jithu Joseph <[email protected]>

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.

Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
drivers/platform/x86/intel/ifs/Makefile | 2 +-
drivers/platform/x86/intel/ifs/core.c | 36 ++++++++++++++++++++++++-
drivers/platform/x86/intel/ifs/ifs.h | 25 +++++++++++++++++
drivers/platform/x86/intel/ifs/load.c | 28 +++++++++++++++++++
4 files changed, 89 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 5713e6ee90f0..ed4ded6755b2 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -6,6 +6,8 @@

#include <asm/cpu_device_id.h>

+#include "ifs.h"
+
enum test_types {
IFS_SAF,
};
@@ -20,10 +22,27 @@ static const struct x86_cpu_id ifs_cpu_ids[] __initconst = {
};
MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids);

+static struct ifs_device ifs_devices[] = {
+ [IFS_SAF] = {
+ .data = {
+ .integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
+ },
+ .misc = {
+ .name = "intel_ifs_0",
+ .nodename = "intel_ifs/0",
+ .minor = MISC_DYNAMIC_MINOR,
+ },
+ },
+};
+
+#define IFS_NUMTESTS ARRAY_SIZE(ifs_devices)
+
static int __init ifs_init(void)
{
const struct x86_cpu_id *m;
+ int ndevices = 0;
u64 msrval;
+ int i;

m = x86_match_cpu(ifs_cpu_ids);
if (!m)
@@ -38,11 +57,26 @@ static int __init ifs_init(void)
if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval))
return -ENODEV;

- return 0;
+ for (i = 0; i < IFS_NUMTESTS; i++) {
+ if (!(msrval & BIT(ifs_devices[i].data.integrity_cap_bit)))
+ continue;
+
+ if (!misc_register(&ifs_devices[i].misc)) {
+ ndevices++;
+ ifs_load_firmware(ifs_devices[i].misc.this_device);
+ }
+ }
+
+ return ndevices ? 0 : -ENODEV;
}

static void __exit ifs_exit(void)
{
+ int i;
+
+ for (i = 0; i < IFS_NUMTESTS; i++)
+ if (ifs_devices[i].misc.this_device)
+ misc_deregister(&ifs_devices[i].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..9a0f8e2077e2
--- /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 <linux/device.h>
+#include <linux/miscdevice.h>
+
+/**
+ * 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 <linux/firmware.h>
+
+#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);
+}
--
2.35.1

2022-04-22 23:13:03

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v4 03/10] 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 <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
MAINTAINERS | 7 ++++
drivers/platform/x86/intel/Kconfig | 1 +
drivers/platform/x86/intel/Makefile | 1 +
drivers/platform/x86/intel/ifs/Kconfig | 13 +++++++
drivers/platform/x86/intel/ifs/Makefile | 3 ++
drivers/platform/x86/intel/ifs/core.c | 52 +++++++++++++++++++++++++
6 files changed, 77 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 40fa1955ca3f..d2ee63193ab3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9861,6 +9861,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 <[email protected]>
+R: Ashok Raj <[email protected]>
+R: Tony Luck <[email protected]>
+S: Maintained
+F: drivers/platform/x86/intel/ifs
+
INTEL INTEGRATED SENSOR HUB DRIVER
M: Srinivas Pandruvada <[email protected]>
M: Jiri Kosina <[email protected]>
diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig
index 1f01a8a23c57..794968bda115 100644
--- a/drivers/platform/x86/intel/Kconfig
+++ b/drivers/platform/x86/intel/Kconfig
@@ -4,6 +4,7 @@
#

source "drivers/platform/x86/intel/atomisp2/Kconfig"
+source "drivers/platform/x86/intel/ifs/Kconfig"
source "drivers/platform/x86/intel/int1092/Kconfig"
source "drivers/platform/x86/intel/int3472/Kconfig"
source "drivers/platform/x86/intel/pmc/Kconfig"
diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile
index c61bc3e97121..717933dd0cfd 100644
--- a/drivers/platform/x86/intel/Makefile
+++ b/drivers/platform/x86/intel/Makefile
@@ -5,6 +5,7 @@
#

obj-$(CONFIG_INTEL_ATOMISP2_PDX86) += atomisp2/
+obj-$(CONFIG_INTEL_IFS) += ifs/
obj-$(CONFIG_INTEL_SAR_INT1092) += int1092/
obj-$(CONFIG_INTEL_SKL_INT3472) += int3472/
obj-$(CONFIG_INTEL_PMC_CORE) += pmc/
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..5713e6ee90f0
--- /dev/null
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. */
+
+#include <linux/module.h>
+#include <linux/kdev_t.h>
+
+#include <asm/cpu_device_id.h>
+
+enum test_types {
+ IFS_SAF,
+};
+
+#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");
--
2.35.1

2022-04-25 16:02:03

by Steven Rostedt

[permalink] [raw]
Subject: Re: [PATCH v4 09/10] trace: platform/x86/intel/ifs: Add trace point to track Intel IFS operations

On Fri, 22 Apr 2022 13:02:18 -0700
Tony Luck <[email protected]> wrote:

> Add tracing support which may be useful for debugging systems that fail to complete
> In Field Scan tests.
>
> Reviewed-by: Dan Williams <[email protected]>
> Signed-off-by: Tony Luck <[email protected]>
> ---
> MAINTAINERS | 1 +
> drivers/platform/x86/intel/ifs/runtest.c | 5 ++++
> include/trace/events/intel_ifs.h | 38 ++++++++++++++++++++++++

From the tracing POV:

Acked-by: Steven Rostedt (Google) <[email protected]>

-- Steve

2022-04-25 23:57:25

by Luck, Tony

[permalink] [raw]
Subject: RE: [PATCH v4 09/10] 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.
> >
> > Reviewed-by: Dan Williams <[email protected]>
> > Signed-off-by: Tony Luck <[email protected]>
> > ---
> > MAINTAINERS | 1 +
> > drivers/platform/x86/intel/ifs/runtest.c | 5 ++++
> > include/trace/events/intel_ifs.h | 38 ++++++++++++++++++++++++
>
> From the tracing POV:
>
> Acked-by: Steven Rostedt (Google) <[email protected]>

Question for the future of this driver. There are a couple more scan tools coming
in the future. The interface is similar:

WRMSR to start a scan
RDMSR to get the results

For this first one, I made the trace code do some user friendly decoding of the
WRMSR value to just show the two interesting fields (start & stop).

The future scan modes will have different fields.

I see two paths:

1) Create a new user friendly trace point for each new scan mode.
2) Just provide a generic one that dumps both the 64-bit WRMSR and RDMSR values.

Q: Are trace points "expensive" in some way ... so better to just have one than three?
Or are the cheap enough that decoding for the user is an OK thing?

Thanks

-Tony


2022-04-26 07:01:50

by Steven Rostedt

[permalink] [raw]
Subject: Re: [PATCH v4 09/10] trace: platform/x86/intel/ifs: Add trace point to track Intel IFS operations

On Mon, 25 Apr 2022 16:49:35 +0000
"Luck, Tony" <[email protected]> wrote:

> I see two paths:
>
> 1) Create a new user friendly trace point for each new scan mode.
> 2) Just provide a generic one that dumps both the 64-bit WRMSR and RDMSR values.
>
> Q: Are trace points "expensive" in some way ... so better to just have one than three?
> Or are the cheap enough that decoding for the user is an OK thing?

Yes, they are expensive as each TRACE_EVENT() can add a few KB of text and
data. But you can add a DECLARE_EVENT_CLASS() and then add "printk"
differences that are less memory heavy.

See DEFINE_EVENT_PRINT().

-- Steve

2022-04-26 17:15:42

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH v4 04/10] platform/x86/intel/ifs: Read IFS firmware image

On Fri, Apr 22, 2022 at 01:02:13PM -0700, Tony Luck wrote:
> From: Jithu Joseph <[email protected]>
>
> 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.
>
> Signed-off-by: Jithu Joseph <[email protected]>
> Co-developed-by: Tony Luck <[email protected]>
> Signed-off-by: Tony Luck <[email protected]>
> ---
> drivers/platform/x86/intel/ifs/Makefile | 2 +-
> drivers/platform/x86/intel/ifs/core.c | 36 ++++++++++++++++++++++++-
> drivers/platform/x86/intel/ifs/ifs.h | 25 +++++++++++++++++
> drivers/platform/x86/intel/ifs/load.c | 28 +++++++++++++++++++
> 4 files changed, 89 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 5713e6ee90f0..ed4ded6755b2 100644
> --- a/drivers/platform/x86/intel/ifs/core.c
> +++ b/drivers/platform/x86/intel/ifs/core.c
> @@ -6,6 +6,8 @@
>
> #include <asm/cpu_device_id.h>
>
> +#include "ifs.h"
> +
> enum test_types {
> IFS_SAF,
> };
> @@ -20,10 +22,27 @@ static const struct x86_cpu_id ifs_cpu_ids[] __initconst = {
> };
> MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids);
>
> +static struct ifs_device ifs_devices[] = {
> + [IFS_SAF] = {
> + .data = {
> + .integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
> + },
> + .misc = {
> + .name = "intel_ifs_0",
> + .nodename = "intel_ifs/0",
> + .minor = MISC_DYNAMIC_MINOR,
> + },
> + },
> +};
> +
> +#define IFS_NUMTESTS ARRAY_SIZE(ifs_devices)

Cute way to do this, but I don't see you ever have any more devices
added to this list in this series. Did I miss them?

If not, why all the overhead and complexity involved here for just a
single misc device?

thanks,

greg k-h

2022-04-27 03:34:07

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH v4 04/10] platform/x86/intel/ifs: Read IFS firmware image

On Tue, Apr 26, 2022 at 09:12:37AM -0700, Luck, Tony wrote:
> On Tue, Apr 26, 2022 at 12:45:40PM +0200, Greg KH wrote:
> > On Fri, Apr 22, 2022 at 01:02:13PM -0700, Tony Luck wrote:
> > > drivers/platform/x86/intel/ifs/Makefile | 2 +-
> > > drivers/platform/x86/intel/ifs/core.c | 36 ++++++++++++++++++++++++-
> > > drivers/platform/x86/intel/ifs/ifs.h | 25 +++++++++++++++++
> > > drivers/platform/x86/intel/ifs/load.c | 28 +++++++++++++++++++
>
> You haven't commented on the source tree location. With the change
> to use misc_register() this isn't a "platform" device anymore.
>
> Should I move to "drivers/misc/"? Or is there some better spot that
> preseves the detail that this is an x86/intel driver in the path?

There's misc_register() users all over the tree, no need for it to be in
drivers/misc/ at all, especially if this really is a platform device as
this one is. It's fine here.

> > > +static struct ifs_device ifs_devices[] = {
> > > + [IFS_SAF] = {
> > > + .data = {
> > > + .integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
> > > + },
> > > + .misc = {
> > > + .name = "intel_ifs_0",
> > > + .nodename = "intel_ifs/0",
> > > + .minor = MISC_DYNAMIC_MINOR,
> > > + },
> > > + },
> > > +};
> > > +
> > > +#define IFS_NUMTESTS ARRAY_SIZE(ifs_devices)
> >
> > Cute way to do this, but I don't see you ever have any more devices
> > added to this list in this series. Did I miss them?
>
> That's in part 11/10 ... I have hardware, so I'm pretty sure that this
> is a real thing. Just not ready to post until Intel announces the
> details of the new test type.

Let's not over-engineer for anything we can not review today please.

> > If not, why all the overhead and complexity involved here for just a
> > single misc device?
>
> It didn't seem like a lot of complexity here. It makes the changes to
> this file to add an extra test trivial (just a new name in the "enum"
> and a new initializer in ifs_devices[]).
>
> Obviously some more code in load.c and runtest.c to handle the new
> test type.
>
> If it really is too much now, I can rip it out from this submission
> and add it back when the second test is ready for public view.

Please do, thanks.

greg k-h

2022-04-27 09:30:32

by Luck, Tony

[permalink] [raw]
Subject: Re: [PATCH v4 04/10] platform/x86/intel/ifs: Read IFS firmware image

On Tue, Apr 26, 2022 at 06:36:46PM +0200, Greg KH wrote:
> On Tue, Apr 26, 2022 at 09:12:37AM -0700, Luck, Tony wrote:
> > If it really is too much now, I can rip it out from this submission
> > and add it back when the second test is ready for public view.
>
> Please do, thanks.

Hmmm ... maybe there were more bits than I thought.

1 file changed, 19 insertions(+), 36 deletions(-)

core.c is now down to just 80 lines ... so that was a significant
fraction of the file.

Net change below (I'll thread it back into the patch series before reposting).

Any other comments on the series?

-Tony



diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c
index 317ed3225307..489b77645b5e 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -9,10 +9,6 @@

#include "ifs.h"

-enum test_types {
- IFS_SAF,
-};
-
#define X86_MATCH(model) \
X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \
INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, NULL)
@@ -23,27 +19,21 @@ static const struct x86_cpu_id ifs_cpu_ids[] __initconst = {
};
MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids);

-static struct ifs_device ifs_devices[] = {
- [IFS_SAF] = {
- .data = {
- .integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
- },
- .misc = {
- .name = "intel_ifs_0",
- .nodename = "intel_ifs/0",
- .minor = MISC_DYNAMIC_MINOR,
- },
+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,
},
};

-#define IFS_NUMTESTS ARRAY_SIZE(ifs_devices)
-
static int __init ifs_init(void)
{
const struct x86_cpu_id *m;
- int ndevices = 0;
u64 msrval;
- int i;

m = x86_match_cpu(ifs_cpu_ids);
if (!m)
@@ -61,32 +51,25 @@ static int __init ifs_init(void)
if (ifs_setup_wq())
return -ENOMEM;

- for (i = 0; i < IFS_NUMTESTS; i++) {
- if (!(msrval & BIT(ifs_devices[i].data.integrity_cap_bit)))
- continue;
-
- ifs_devices[i].misc.groups = ifs_get_groups();
- if (!misc_register(&ifs_devices[i].misc)) {
- ndevices++;
- down(&ifs_sem);
- ifs_load_firmware(ifs_devices[i].misc.this_device);
- up(&ifs_sem);
- }
- }
+ ifs_device.misc.groups = ifs_get_groups();

- if (!ndevices)
+ 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);
+ } else {
ifs_destroy_wq();
+ return -ENODEV;
+ }

- return ndevices ? 0 : -ENODEV;
+ return 0;
}

static void __exit ifs_exit(void)
{
- int i;

- for (i = 0; i < IFS_NUMTESTS; i++)
- if (ifs_devices[i].misc.this_device)
- misc_deregister(&ifs_devices[i].misc);
+ misc_deregister(&ifs_device.misc);
ifs_destroy_wq();
}

--
2.35.1

2022-04-27 10:04:07

by Steven Rostedt

[permalink] [raw]
Subject: Re: [PATCH v4 09/10] trace: platform/x86/intel/ifs: Add trace point to track Intel IFS operations

On Tue, 26 Apr 2022 16:53:13 -0700
"Luck, Tony" <[email protected]> wrote:
>
> I looked at the examples in samples/trace_events/trace-events-sample.h
> and tried to use this. But I'm doing something wrong because the
> compiler barfs on something defined but not used.
>
> Maybe my problem is the TP_printk() in the DECLARE_EVENT_CLASS() that
> is over-ridden by DEFINE_EVENT_PRINT(). I wasn't at all sure what to
> put here ... or how to use the base tracepoint that doesn't have the
> printk() over-ridden.

Yeah, that could be confusing.

Basically, TRACE_EVENT() is simply defined as:

DECLARE_EVENT_CLASS()
DEFINE_EVENT();

So technically you could create the class and event with the same name,
and then you could create a second event on top of that. But I usually
suggest people explicitly specify the DECLARE_EVENT_CLASS() and
DEFINE_EVENT().

I would not do this until you have more than one event. The what you
would do is create one event where the print matches the
DECLARE_EVENT_CLASS() TP_printk(), and have that event defined with
just DEFINE_EVENT(). Then create other events with the
DEFINE_EVENT_PRINT().

>
> I think I need my class to just save both the u64 values to the trace
> buffer. Then the different trace points will extract the bits they want
> and print in a user friendly way. While this increases space used in
> the trace buffer, these events are not crazy high frequency. Usually
> one or two events per core with a gap 30 minutes or more between tests.
>
> In my ".c" file the tracepoint looks like this using the name from
> DEFINE_EVENT_PRINT(), and now passing the full u64 values:
>
> trace_ifs_status_saf(activate.data, status.data);
>
> and my #include file looks like this:
>
> ----------------------------------------------
> /* 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 <linux/ktime.h>
> #include <linux/tracepoint.h>
>
> DECLARE_EVENT_CLASS(ifs_status,
>
> TP_PROTO(u64 activate, u64 status),
>
> TP_ARGS(activate, status),
>
> TP_STRUCT__entry(
> __field( u64, activate )
> __field( u64, status )
> ),
>
> TP_fast_assign(
> __entry->activate = activate;
> __entry->status = status;
> ),
>
> TP_printk("activate: %llx status: %llx",
> __entry->activate,
> __entry->status)
> );
>
> DEFINE_EVENT_PRINT(ifs_status, ifs_status_saf,
> TP_PROTO(u64 activate, u64 status),
> TP_ARGS(activate, status),
> TP_printk("start: %.2x, stop: %.2x, status: %llx",
> ((union ifs_scan *)&(__entry->activate))->start,
> ((union ifs_scan *)&(__entry->activate))->stop,
> __entry->status)
> );
>
> #endif /* _TRACE_IFS_H */
>
> /* This part must be outside protection */
> #include <trace/define_trace.h>
> -----------------------------------------------------
>
> GCC messages:
>
>
> CC [M] drivers/platform/x86/intel/ifs/runtest.o
> In file included from /home/agluck/GIT/mywork/include/trace/define_trace.h:102,
> from /home/agluck/GIT/mywork/include/trace/events/intel_ifs.h:44,
> from /home/agluck/GIT/mywork/drivers/platform/x86/intel/ifs/runtest.c:27:
> /home/agluck/GIT/mywork/include/trace/trace_events.h:426:13: warning: ‘print_fmt_ifs_status’ defined but not used [-Wunused-variable]
> 426 | static char print_fmt_##call[] = print; \
> | ^~~~~~~~~~
> /home/agluck/GIT/mywork/include/trace/events/intel_ifs.h:11:1: note: in expansion of macro ‘DECLARE_EVENT_CLASS’
> 11 | DECLARE_EVENT_CLASS(ifs_status,
> | ^~~~~~~~~~~~~~~~~~~
> In file included from /home/agluck/GIT/mywork/include/trace/define_trace.h:102,
> from /home/agluck/GIT/mywork/include/trace/events/intel_ifs.h:44,
> from /home/agluck/GIT/mywork/drivers/platform/x86/intel/ifs/runtest.c:27:
> /home/agluck/GIT/mywork/include/trace/trace_events.h:207:37: warning: ‘trace_event_type_funcs_ifs_status’ defined but not used [-Wunused-variable]
> 207 | static struct trace_event_functions trace_event_type_funcs_##call = { \
> | ^~~~~~~~~~~~~~~~~~~~~~~
> /home/agluck/GIT/mywork/include/trace/events/intel_ifs.h:11:1: note: in expansion of macro ‘DECLARE_EVENT_CLASS’
> 11 | DECLARE_EVENT_CLASS(ifs_status,
> | ^~~~~~~~~~~~~~~~~~~
> make[1]: Leaving directory '/home/agluck/GIT/mywork/build/ifsv5-rc1'
>

Yeah, because you don't have more than one event, so the
DEFINE_EVENT_PRINT() does not make sense. You still need one
DEFINE_EVENT() otherwise, you will get that static function not used
warning.

-- Steve

2022-04-27 11:20:15

by Luck, Tony

[permalink] [raw]
Subject: Re: [PATCH v4 09/10] trace: platform/x86/intel/ifs: Add trace point to track Intel IFS operations

On Mon, Apr 25, 2022 at 09:49:28PM -0400, Steven Rostedt wrote:
> On Mon, 25 Apr 2022 16:49:35 +0000
> "Luck, Tony" <[email protected]> wrote:
>
> > I see two paths:
> >
> > 1) Create a new user friendly trace point for each new scan mode.
> > 2) Just provide a generic one that dumps both the 64-bit WRMSR and RDMSR values.
> >
> > Q: Are trace points "expensive" in some way ... so better to just have one than three?
> > Or are the cheap enough that decoding for the user is an OK thing?
>
> Yes, they are expensive as each TRACE_EVENT() can add a few KB of text and
> data. But you can add a DECLARE_EVENT_CLASS() and then add "printk"
> differences that are less memory heavy.
>
> See DEFINE_EVENT_PRINT().

I looked at the examples in samples/trace_events/trace-events-sample.h
and tried to use this. But I'm doing something wrong because the
compiler barfs on something defined but not used.

Maybe my problem is the TP_printk() in the DECLARE_EVENT_CLASS() that
is over-ridden by DEFINE_EVENT_PRINT(). I wasn't at all sure what to
put here ... or how to use the base tracepoint that doesn't have the
printk() over-ridden.

I think I need my class to just save both the u64 values to the trace
buffer. Then the different trace points will extract the bits they want
and print in a user friendly way. While this increases space used in
the trace buffer, these events are not crazy high frequency. Usually
one or two events per core with a gap 30 minutes or more between tests.

In my ".c" file the tracepoint looks like this using the name from
DEFINE_EVENT_PRINT(), and now passing the full u64 values:

trace_ifs_status_saf(activate.data, status.data);

and my #include file looks like this:

----------------------------------------------
/* 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 <linux/ktime.h>
#include <linux/tracepoint.h>

DECLARE_EVENT_CLASS(ifs_status,

TP_PROTO(u64 activate, u64 status),

TP_ARGS(activate, status),

TP_STRUCT__entry(
__field( u64, activate )
__field( u64, status )
),

TP_fast_assign(
__entry->activate = activate;
__entry->status = status;
),

TP_printk("activate: %llx status: %llx",
__entry->activate,
__entry->status)
);

DEFINE_EVENT_PRINT(ifs_status, ifs_status_saf,
TP_PROTO(u64 activate, u64 status),
TP_ARGS(activate, status),
TP_printk("start: %.2x, stop: %.2x, status: %llx",
((union ifs_scan *)&(__entry->activate))->start,
((union ifs_scan *)&(__entry->activate))->stop,
__entry->status)
);

#endif /* _TRACE_IFS_H */

/* This part must be outside protection */
#include <trace/define_trace.h>
-----------------------------------------------------

GCC messages:


CC [M] drivers/platform/x86/intel/ifs/runtest.o
In file included from /home/agluck/GIT/mywork/include/trace/define_trace.h:102,
from /home/agluck/GIT/mywork/include/trace/events/intel_ifs.h:44,
from /home/agluck/GIT/mywork/drivers/platform/x86/intel/ifs/runtest.c:27:
/home/agluck/GIT/mywork/include/trace/trace_events.h:426:13: warning: ‘print_fmt_ifs_status’ defined but not used [-Wunused-variable]
426 | static char print_fmt_##call[] = print; \
| ^~~~~~~~~~
/home/agluck/GIT/mywork/include/trace/events/intel_ifs.h:11:1: note: in expansion of macro ‘DECLARE_EVENT_CLASS’
11 | DECLARE_EVENT_CLASS(ifs_status,
| ^~~~~~~~~~~~~~~~~~~
In file included from /home/agluck/GIT/mywork/include/trace/define_trace.h:102,
from /home/agluck/GIT/mywork/include/trace/events/intel_ifs.h:44,
from /home/agluck/GIT/mywork/drivers/platform/x86/intel/ifs/runtest.c:27:
/home/agluck/GIT/mywork/include/trace/trace_events.h:207:37: warning: ‘trace_event_type_funcs_ifs_status’ defined but not used [-Wunused-variable]
207 | static struct trace_event_functions trace_event_type_funcs_##call = { \
| ^~~~~~~~~~~~~~~~~~~~~~~
/home/agluck/GIT/mywork/include/trace/events/intel_ifs.h:11:1: note: in expansion of macro ‘DECLARE_EVENT_CLASS’
11 | DECLARE_EVENT_CLASS(ifs_status,
| ^~~~~~~~~~~~~~~~~~~
make[1]: Leaving directory '/home/agluck/GIT/mywork/build/ifsv5-rc1'

-Tony

2022-04-27 11:26:22

by Luck, Tony

[permalink] [raw]
Subject: Re: [PATCH v4 04/10] platform/x86/intel/ifs: Read IFS firmware image

On Tue, Apr 26, 2022 at 12:45:40PM +0200, Greg KH wrote:
> On Fri, Apr 22, 2022 at 01:02:13PM -0700, Tony Luck wrote:
> > drivers/platform/x86/intel/ifs/Makefile | 2 +-
> > drivers/platform/x86/intel/ifs/core.c | 36 ++++++++++++++++++++++++-
> > drivers/platform/x86/intel/ifs/ifs.h | 25 +++++++++++++++++
> > drivers/platform/x86/intel/ifs/load.c | 28 +++++++++++++++++++

You haven't commented on the source tree location. With the change
to use misc_register() this isn't a "platform" device anymore.

Should I move to "drivers/misc/"? Or is there some better spot that
preseves the detail that this is an x86/intel driver in the path?

> > +static struct ifs_device ifs_devices[] = {
> > + [IFS_SAF] = {
> > + .data = {
> > + .integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
> > + },
> > + .misc = {
> > + .name = "intel_ifs_0",
> > + .nodename = "intel_ifs/0",
> > + .minor = MISC_DYNAMIC_MINOR,
> > + },
> > + },
> > +};
> > +
> > +#define IFS_NUMTESTS ARRAY_SIZE(ifs_devices)
>
> Cute way to do this, but I don't see you ever have any more devices
> added to this list in this series. Did I miss them?

That's in part 11/10 ... I have hardware, so I'm pretty sure that this
is a real thing. Just not ready to post until Intel announces the
details of the new test type.

> If not, why all the overhead and complexity involved here for just a
> single misc device?

It didn't seem like a lot of complexity here. It makes the changes to
this file to add an extra test trivial (just a new name in the "enum"
and a new initializer in ifs_devices[]).

Obviously some more code in load.c and runtest.c to handle the new
test type.

If it really is too much now, I can rip it out from this submission
and add it back when the second test is ready for public view.

-Tony

2022-04-30 14:06:14

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v5 00/10] Introduce In Field Scan driver

Hopefully this is close enough to done to begin discussion on which
maintainer tree will take this series.

Choices:
1) Hans/Mark take it into the platform-drivers tree
Needs an Ack from x86 maintainers on parts 1 & 2
2) X86 maintainers take it into TIP
Needs Ack from Hans/Mark on parts 2-10

TL;DR this driver loads scan test files that can check whether silicon
in a CPU core is still running correctly. It is expected that these tests
would be run several times per day to catch problems as silicon ages.

Changes since v4:

Greg Kroah-Hartman
------------------
"Cute way to do this, but I don't see you ever have any more devices
added to this list in this series."

Removed the enum, arrays, loops, and count of test types discovered.
Now just check for enumeration of the single test type that is being
deployed on Sapphire Rapids.


Jithu Joseph (7):
x86/microcode/intel: Expose collect_cpu_info_early() for IFS
platform/x86/intel/ifs: Read IFS firmware image
platform/x86/intel/ifs: Check IFS Image sanity
platform/x86/intel/ifs: Authenticate and copy to secured memory
platform/x86/intel/ifs: Add scan test support
platform/x86/intel/ifs: Add IFS sysfs interface
platform/x86/intel/ifs: add ABI documentation for IFS

Tony Luck (3):
x86/msr-index: Define INTEGRITY_CAPABILITIES MSR
platform/x86/intel/ifs: Add stub driver for In-Field Scan
trace: platform/x86/intel/ifs: Add trace point to track Intel IFS
operations

.../ABI/testing/sysfs-platform-intel-ifs | 39 ++
MAINTAINERS | 8 +
arch/x86/include/asm/cpu.h | 18 +
arch/x86/include/asm/msr-index.h | 7 +
arch/x86/kernel/cpu/intel.c | 32 ++
arch/x86/kernel/cpu/microcode/intel.c | 59 +---
drivers/platform/x86/intel/Kconfig | 1 +
drivers/platform/x86/intel/Makefile | 1 +
drivers/platform/x86/intel/ifs/Kconfig | 13 +
drivers/platform/x86/intel/ifs/Makefile | 3 +
drivers/platform/x86/intel/ifs/core.c | 80 +++++
drivers/platform/x86/intel/ifs/ifs.h | 123 +++++++
drivers/platform/x86/intel/ifs/load.c | 262 ++++++++++++++
drivers/platform/x86/intel/ifs/runtest.c | 332 ++++++++++++++++++
drivers/platform/x86/intel/ifs/sysfs.c | 147 ++++++++
include/trace/events/intel_ifs.h | 38 ++
16 files changed, 1111 insertions(+), 52 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-platform-intel-ifs
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
create mode 100644 drivers/platform/x86/intel/ifs/ifs.h
create mode 100644 drivers/platform/x86/intel/ifs/load.c
create mode 100644 drivers/platform/x86/intel/ifs/runtest.c
create mode 100644 drivers/platform/x86/intel/ifs/sysfs.c
create mode 100644 include/trace/events/intel_ifs.h


base-commit: af2d861d4cd2a4da5137f795ee3509e6f944a25b
--
2.35.1

2022-05-01 20:26:50

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v5 04/10] platform/x86/intel/ifs: Read IFS firmware image

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
drivers/platform/x86/intel/ifs/Makefile | 2 +-
drivers/platform/x86/intel/ifs/core.c | 21 +++++++++++++++++++
drivers/platform/x86/intel/ifs/ifs.h | 25 ++++++++++++++++++++++
drivers/platform/x86/intel/ifs/load.c | 28 +++++++++++++++++++++++++
4 files changed, 75 insertions(+), 1 deletion(-)
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..d4a54ff47447 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -6,6 +6,8 @@

#include <asm/cpu_device_id.h>

+#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,19 @@ static int __init ifs_init(void)
if (rdmsrl_safe(MSR_INTEGRITY_CAPS, &msrval))
return -ENODEV;

+ if ((msrval & BIT(ifs_device.data.integrity_cap_bit)) &&
+ !misc_register(&ifs_device.misc)) {
+ ifs_load_firmware(ifs_device.misc.this_device);
+ } else {
+ return -ENODEV;
+ }
+
return 0;
}

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..9a0f8e2077e2
--- /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 <linux/device.h>
+#include <linux/miscdevice.h>
+
+/**
+ * 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 <linux/firmware.h>
+
+#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);
+}
--
2.35.1

2022-05-02 23:52:32

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v5 00/10] Introduce In Field Scan driver

Hi,

On 4/28/22 17:38, Tony Luck wrote:
> Hopefully this is close enough to done to begin discussion on which
> maintainer tree will take this series.
>
> Choices:
> 1) Hans/Mark take it into the platform-drivers tree
> Needs an Ack from x86 maintainers on parts 1 & 2
> 2) X86 maintainers take it into TIP
> Needs Ack from Hans/Mark on parts 2-10

I've taken a quick look at the entire series and it looks good to me.

I'm fine with this entire series getting merged through the TIP
tree, here is my ack for merging the drivers/platform/x86 bits
through the TIP tree:

Acked-by: Hans de Goede <[email protected]>

Regards,

Hans






>
> TL;DR this driver loads scan test files that can check whether silicon
> in a CPU core is still running correctly. It is expected that these tests
> would be run several times per day to catch problems as silicon ages.
>
> Changes since v4:
>
> Greg Kroah-Hartman
> ------------------
> "Cute way to do this, but I don't see you ever have any more devices
> added to this list in this series."
>
> Removed the enum, arrays, loops, and count of test types discovered.
> Now just check for enumeration of the single test type that is being
> deployed on Sapphire Rapids.
>
>
> Jithu Joseph (7):
> x86/microcode/intel: Expose collect_cpu_info_early() for IFS
> platform/x86/intel/ifs: Read IFS firmware image
> platform/x86/intel/ifs: Check IFS Image sanity
> platform/x86/intel/ifs: Authenticate and copy to secured memory
> platform/x86/intel/ifs: Add scan test support
> platform/x86/intel/ifs: Add IFS sysfs interface
> platform/x86/intel/ifs: add ABI documentation for IFS
>
> Tony Luck (3):
> x86/msr-index: Define INTEGRITY_CAPABILITIES MSR
> platform/x86/intel/ifs: Add stub driver for In-Field Scan
> trace: platform/x86/intel/ifs: Add trace point to track Intel IFS
> operations
>
> .../ABI/testing/sysfs-platform-intel-ifs | 39 ++
> MAINTAINERS | 8 +
> arch/x86/include/asm/cpu.h | 18 +
> arch/x86/include/asm/msr-index.h | 7 +
> arch/x86/kernel/cpu/intel.c | 32 ++
> arch/x86/kernel/cpu/microcode/intel.c | 59 +---
> drivers/platform/x86/intel/Kconfig | 1 +
> drivers/platform/x86/intel/Makefile | 1 +
> drivers/platform/x86/intel/ifs/Kconfig | 13 +
> drivers/platform/x86/intel/ifs/Makefile | 3 +
> drivers/platform/x86/intel/ifs/core.c | 80 +++++
> drivers/platform/x86/intel/ifs/ifs.h | 123 +++++++
> drivers/platform/x86/intel/ifs/load.c | 262 ++++++++++++++
> drivers/platform/x86/intel/ifs/runtest.c | 332 ++++++++++++++++++
> drivers/platform/x86/intel/ifs/sysfs.c | 147 ++++++++
> include/trace/events/intel_ifs.h | 38 ++
> 16 files changed, 1111 insertions(+), 52 deletions(-)
> create mode 100644 Documentation/ABI/testing/sysfs-platform-intel-ifs
> 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
> create mode 100644 drivers/platform/x86/intel/ifs/ifs.h
> create mode 100644 drivers/platform/x86/intel/ifs/load.c
> create mode 100644 drivers/platform/x86/intel/ifs/runtest.c
> create mode 100644 drivers/platform/x86/intel/ifs/sysfs.c
> create mode 100644 include/trace/events/intel_ifs.h
>
>
> base-commit: af2d861d4cd2a4da5137f795ee3509e6f944a25b

2022-05-03 00:16:15

by Luck, Tony

[permalink] [raw]
Subject: RE: [PATCH v5 00/10] Introduce In Field Scan driver

> I've taken a quick look at the entire series and it looks good to me.
>
> I'm fine with this entire series getting merged through the TIP
> tree, here is my ack for merging the drivers/platform/x86 bits
> through the TIP tree:
>
> Acked-by: Hans de Goede <[email protected]>


Hans,

Thanks for looking, and double thanks for the "Ack".

-Tony

2022-05-03 16:24:02

by Luck, Tony

[permalink] [raw]
Subject: RE: [PATCH v5 00/10] Introduce In Field Scan driver

> Hmm, so looking at the diffstat - the majority of that is
> drivers/platform/x86/ so I guess your tree would be better suited for
> it...

Can you check that I fixed the issues in part 01/10 that you reported in v3 of this
series and give an Ack to Hans?

-Tony

2022-05-03 17:56:01

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH v5 00/10] Introduce In Field Scan driver

On Mon, May 02, 2022 at 05:15:39PM +0200, Hans de Goede wrote:
> I'm fine with this entire series getting merged through the TIP
> tree,

Hmm, so looking at the diffstat - the majority of that is
drivers/platform/x86/ so I guess your tree would be better suited for
it...

Thx.

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette

2022-05-03 22:51:56

by Luck, Tony

[permalink] [raw]
Subject: RE: [PATCH v5 00/10] Introduce In Field Scan driver

> Can you check that I fixed the issues in part 01/10 that you reported in v3 of this
> series and give an Ack to Hans?

Oops ... reading e-mail out of order ... I see that you already gave the Ack. Thanks!

-Tony

2022-05-05 12:43:09

by Luck, Tony

[permalink] [raw]
Subject: RE: [PATCH v5 04/10] platform/x86/intel/ifs: Read IFS firmware image

>> + ret = request_firmware_direct(&fw, scan_path, dev);
>> + if (ret) {
>> + dev_err(dev, "ifs file %s load failed\n", scan_path);
>> + return;
>
> Why is this not returning an error to the caller?

There are three call sequences that lead here:

1) CONFIG_INTEL_IFS=y
At boot this is pretty much guaranteed to fail (unless some crazy person includes the
scan file in the initramfs). In this case there isn't a useful caller to return the code to.
In this case the driver init routine must ignore any error to make sure the sysfs reload
file is present to load the scan file once the file system is available.

2) CONFIG_INTEL_IFS=m module load time
Same code path as built-in ... so must ignore a failed load here too (unless there is a
way to distinguish the built-in vs. module execution environment).

3) echo 1 > reload
Hmmm. Some older revision did return an error ... but I seem to have factored it out
during cleanups. Limited to standard -E???? error codes. The reload_store() function
can just check whether the load succeeded by looking at ifsd->loaded instead of a
return value from ifs_load_firmware()

So, I will fix case 3. But probably by checking ifsd->loaded rather than by adding a return
code to this function.

-Tony

2022-05-05 15:55:09

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH v5 04/10] platform/x86/intel/ifs: Read IFS firmware image

On Thu, Apr 28 2022 at 08:38, Tony Luck wrote:
> +/*
> + * 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;

Why is this not returning an error to the caller?

Thanks,

tglx

2022-05-06 19:06:04

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v6 00/11] Introduce In Field Scan driver

TL;DR this driver loads scan test files that can check whether silicon
in a CPU core is still running correctly. It is expected that these tests
would be run several times per day to catch problems as silicon ages.

Changes since v5:

Added various Reviewed tags. If anyone wants to take one or more
back in the light of changes listed below, please speak up.

Thomas Gleixner
---------------
03 "So checking for Intel Fam6 ANYMODEL and X86_FEATURE_CORE_CAPABILITIES is
sufficient, no?"

Longer explanation in earlier e-mail ... but the family/model/stepping
check is needed. No change.

04 "Why is ifs_load_firmware() not returning an error to the caller?"

In most cases the return isn't useful. But this did prompt a change
to make sure "echo 1 > reload" does give an error if the load fails.

05 "The above struct is nicely tabular. Can we have that here too please?"

Added <TAB>s to ifs_data structure to make it equally pretty.

06 "Setting the authenticated indicator _before_ actually doing the
authentication is just wrong. It does not matter in this case, but it's
still making my eyes bleed."

Moved indicator to after success has been checked.

06 "Why has this to be a smp function call? Just because it's conveniant?
This is nothing urgent and no hotpath, so this really can use
queue_work_on()."

Even simpler is schedule_work_on() [since other changes mean that
the driver no longer allocates a work queue.


07 "Waiting for a second with preemption disabled? Seriously?"
"Plus another half a second with preemption disabled. That's just insane."
"That local_irq_disable() solves what?"
"Why cpu_hotplug_disable()? Why is cpus_read_lock() not sufficient here?"
"Why does this need GFP_NOWAIT?"
"I put that into the wishful thinking realm"
"The real question is why you try to rendevouz CPUs via work queues."
"pseudo-code to use stomp_machine()"

PeterZ contributed a neatly tailored for this usage "stop_core_cpuslocked()"
function that works beautifully. See part 0003 of this new series. That
meant all of the code that triggered the above comments has gone.

Tony Luck
---------
Noticed unnecessary casts from u8 to u32 in the checksum calculation
in load.c. Fixed.

Changed the tracepoint to include the CPU number of the core being
tested (the tracepoint otherwise just tells you which CPU is executing
the driver code and executing "stop_core_cpuslocked()" to do the actual
work on the target CPUs.

Dropped the msec_to_tsc() function that was used to initialize
activate.delay. Just use a #define of 100000 cycles (two orders
of magnitude bigger than I saw for the slew between the two threads
executing the "stop_core_cpuslocked()" target function ... but not
too insane so if the threads do not sync, we give up quickly).



Jithu Joseph (7):
x86/microcode/intel: Expose collect_cpu_info_early() for IFS
platform/x86/intel/ifs: Read IFS firmware image
platform/x86/intel/ifs: Check IFS Image sanity
platform/x86/intel/ifs: Authenticate and copy to secured memory
platform/x86/intel/ifs: Add scan test support
platform/x86/intel/ifs: Add IFS sysfs interface
platform/x86/intel/ifs: add ABI documentation for IFS

Peter Zijlstra (1):
stop_machine: Add stop_core_cpuslocked() for per-core operations

Tony Luck (3):
x86/msr-index: Define INTEGRITY_CAPABILITIES MSR
platform/x86/intel/ifs: Add stub driver for In-Field Scan
trace: platform/x86/intel/ifs: Add trace point to track Intel IFS
operations

.../ABI/testing/sysfs-platform-intel-ifs | 39 +++
MAINTAINERS | 8 +
arch/x86/include/asm/cpu.h | 18 ++
arch/x86/include/asm/msr-index.h | 7 +
arch/x86/kernel/cpu/intel.c | 32 +++
arch/x86/kernel/cpu/microcode/intel.c | 59 +---
drivers/platform/x86/intel/Kconfig | 1 +
drivers/platform/x86/intel/Makefile | 1 +
drivers/platform/x86/intel/ifs/Kconfig | 13 +
drivers/platform/x86/intel/ifs/Makefile | 3 +
drivers/platform/x86/intel/ifs/core.c | 74 +++++
drivers/platform/x86/intel/ifs/ifs.h | 124 ++++++++
drivers/platform/x86/intel/ifs/load.c | 266 ++++++++++++++++++
drivers/platform/x86/intel/ifs/runtest.c | 255 +++++++++++++++++
drivers/platform/x86/intel/ifs/sysfs.c | 149 ++++++++++
include/linux/stop_machine.h | 16 ++
include/trace/events/intel_ifs.h | 41 +++
kernel/stop_machine.c | 19 ++
18 files changed, 1073 insertions(+), 52 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-platform-intel-ifs
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
create mode 100644 drivers/platform/x86/intel/ifs/ifs.h
create mode 100644 drivers/platform/x86/intel/ifs/load.c
create mode 100644 drivers/platform/x86/intel/ifs/runtest.c
create mode 100644 drivers/platform/x86/intel/ifs/sysfs.c
create mode 100644 include/trace/events/intel_ifs.h


base-commit: 672c0c5173427e6b3e2a9bbb7be51ceeec78093a
--
2.35.1


2022-05-06 21:56:50

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v5 00/10] Introduce In Field Scan driver

Hi,

On 5/6/22 17:53, Luck, Tony wrote:
>> I'll give it some more time for review for v6 and then pick up v6
>> (or v7 if review leads to more changes).
>
> Hans,
>
> Thomas has found one substantive problem, and a few minor things (so far ... he
> still seems to be working through v6).

Ok.

> So there will be a v7. Likely early next week. Is that OK?

That is fine.

> Do you still take patches after -rc6?

If the patches are send soon (1-2 days) after rc6 I can still take them.

Regards,

Hans


2022-05-08 06:21:47

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v6 11/11] platform/x86/intel/ifs: add ABI documentation for IFS

From: Jithu Joseph <[email protected]>

Add the sysfs attributes in ABI/testing for In-Field Scan.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
.../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_<N>/run_test
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: Write <cpu#> 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.<N>/run_test
+
+What: /sys/devices/virtual/misc/intel_ifs_<N>/status
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: The status of the last test. It can be one of "pass", "fail"
+ or "untested".
+
+What: /sys/devices/virtual/misc/intel_ifs_<N>/details
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+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_<N>/image_version
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: Version (hexadecimal) of loaded IFS binary image. If no scan image
+ is loaded reports "none".
+
+What: /sys/devices/virtual/misc/intel_ifs_<N>/reload
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: Write "1" (or "y" or "Y") to reload the IFS image from
+ /lib/firmware/intel/ifs/ff-mm-ss.scan.
--
2.35.1


2022-05-08 18:10:12

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v6 10/11] 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) <[email protected]>
Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
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 bb0c4ff25942..6864fa039974 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9868,6 +9868,7 @@ R: Ashok Raj <[email protected]>
R: Tony Luck <[email protected]>
S: Maintained
F: drivers/platform/x86/intel/ifs
+F: include/trace/events/intel_ifs.h

INTEL INTEGRATED SENSOR HUB DRIVER
M: Srinivas Pandruvada <[email protected]>
diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c
index fd3f5f3f31e5..cd25817ceda0 100644
--- a/drivers/platform/x86/intel/ifs/runtest.c
+++ b/drivers/platform/x86/intel/ifs/runtest.c
@@ -19,6 +19,9 @@
struct workqueue_struct *ifs_wq;
static bool scan_enabled = true;

+#define CREATE_TRACE_POINTS
+#include <trace/events/intel_ifs.h>
+
/* 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 <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+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 <trace/define_trace.h>
--
2.35.1


2022-05-09 02:12:23

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v6 05/11] platform/x86/intel/ifs: Read IFS firmware image

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
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 <asm/cpu_device_id.h>

+#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..47e5f8344fd8
--- /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 <linux/device.h>
+#include <linux/miscdevice.h>
+
+/**
+ * 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 <linux/firmware.h>
+
+#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);
+}
--
2.35.1


2022-05-09 02:28:52

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v6 03/11] stop_machine: Add stop_core_cpuslocked() for per-core operations

From: Peter Zijlstra <[email protected]>

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 <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
---
include/linux/stop_machine.h | 16 ++++++++++++++++
kernel/stop_machine.c | 19 +++++++++++++++++++
2 files changed, 35 insertions(+)

diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h
index 46fb3ebdd16e..ea7a74ea7389 100644
--- a/include/linux/stop_machine.h
+++ b/include/linux/stop_machine.h
@@ -124,6 +124,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 cbc30271ea4d..579761729836 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -633,6 +633,25 @@ int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus)
}
EXPORT_SYMBOL_GPL(stop_machine);

+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);
+
/**
* stop_machine_from_inactive_cpu - stop_machine() from inactive CPU
* @fn: the function to run
--
2.35.1


2022-05-09 02:49:59

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v6 04/11] 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 <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
MAINTAINERS | 7 ++++
drivers/platform/x86/intel/Kconfig | 1 +
drivers/platform/x86/intel/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, 73 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 edc96cdb85e8..bb0c4ff25942 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9862,6 +9862,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 <[email protected]>
+R: Ashok Raj <[email protected]>
+R: Tony Luck <[email protected]>
+S: Maintained
+F: drivers/platform/x86/intel/ifs
+
INTEL INTEGRATED SENSOR HUB DRIVER
M: Srinivas Pandruvada <[email protected]>
M: Jiri Kosina <[email protected]>
diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig
index 1f01a8a23c57..794968bda115 100644
--- a/drivers/platform/x86/intel/Kconfig
+++ b/drivers/platform/x86/intel/Kconfig
@@ -4,6 +4,7 @@
#

source "drivers/platform/x86/intel/atomisp2/Kconfig"
+source "drivers/platform/x86/intel/ifs/Kconfig"
source "drivers/platform/x86/intel/int1092/Kconfig"
source "drivers/platform/x86/intel/int3472/Kconfig"
source "drivers/platform/x86/intel/pmc/Kconfig"
diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile
index c61bc3e97121..717933dd0cfd 100644
--- a/drivers/platform/x86/intel/Makefile
+++ b/drivers/platform/x86/intel/Makefile
@@ -5,6 +5,7 @@
#

obj-$(CONFIG_INTEL_ATOMISP2_PDX86) += atomisp2/
+obj-$(CONFIG_INTEL_IFS) += ifs/
obj-$(CONFIG_INTEL_SAR_INT1092) += int1092/
obj-$(CONFIG_INTEL_SKL_INT3472) += int3472/
obj-$(CONFIG_INTEL_PMC_CORE) += pmc/
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 <linux/module.h>
+#include <linux/kdev_t.h>
+
+#include <asm/cpu_device_id.h>
+
+#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");
--
2.35.1


2022-05-09 02:58:31

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v6 01/11] x86/microcode/intel: Expose collect_cpu_info_early() for IFS

From: Jithu Joseph <[email protected]>

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 <asm/cpu.h>

Make cpu_signatures_match() an inline function in x86 <asm/cpu.h>,
and also give it an "intel_" prefix.

No functional change intended.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Reviewed-by: Thomas Gleixner <[email protected]>
Acked-by: Borislav Petkov <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
arch/x86/include/asm/cpu.h | 18 ++++++++
arch/x86/kernel/cpu/intel.c | 32 +++++++++++++++
arch/x86/kernel/cpu/microcode/intel.c | 59 ++++-----------------------
3 files changed, 57 insertions(+), 52 deletions(-)

diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index 86e5e4e26fcb..990167357c34 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -76,4 +76,22 @@ static inline void init_ia32_feat_ctl(struct cpuinfo_x86 *c) {}

extern __noendbr void cet_disable(void);

+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 f7a5370a9b3b..94779146275d 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 d28a9f8f3fec..025c8f0cd948 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;
@@ -502,7 +457,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;
}
@@ -604,7 +559,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);

@@ -637,7 +592,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);
}
@@ -712,7 +667,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)
--
2.35.1


2022-05-09 03:24:57

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v7 00/12] Introduce In Field Scan driver

TL;DR this driver loads scan test files that can check whether silicon
in a CPU core is still running correctly. It is expected that these tests
would be run several times per day to catch problems as silicon ages.

Changes since v6

Thomas Gleixner
---------------
"struct workqueue_struct *ifs_wq; Seems to be unused."

True. Deleted.

"static bool oscan_enabled = true; What changes this?"

Code that cleared it deleted. Drop this too.

"Please add curly brackets as these are not one-line statements"

Added

cpumask_first(topology_sibling_cpumask(cpu)); Shouldn't that be cpu_smt_mask()?"

Changed (and several other places)

"take up to 200 milliseconds before it retires. 200ms per test chunk?"

Updated comment to note that 200ms is for all chunks.

"Documentation lost in the intertubes"

Dredged up the version from v3 series and changed:
1) Fixed pathnames now this is a virtual misc device instead of platform
device
2) Put all the text into a "/** DOC:" comment section in ifs.h with just
a "kernel-doc:: drivers/platform/x86/intel/ifs/ifs.h" in the ifs.rst
file under Documentation/x86.
3) Added a "big fat warning" (in all CAPS) pointing out that a core test
can take up to 200 milliseconds. So admins must take extra steps if they
are running latency sensitive workloads.
4) Added note that all HT threads of a core must be online to run a
test.

Tony Luck
---------
Off-by-one on retries check (#define set to 5, but tried 6 times). Fixed
Fixed kerneldoc description of "integrity_cap_bit" (was missing a ":")

Jithu Joseph (7):
x86/microcode/intel: Expose collect_cpu_info_early() for IFS
platform/x86/intel/ifs: Read IFS firmware image
platform/x86/intel/ifs: Check IFS Image sanity
platform/x86/intel/ifs: Authenticate and copy to secured memory
platform/x86/intel/ifs: Add scan test support
platform/x86/intel/ifs: Add IFS sysfs interface
platform/x86/intel/ifs: add ABI documentation for IFS

Peter Zijlstra (1):
stop_machine: Add stop_core_cpuslocked() for per-core operations

Tony Luck (4):
x86/msr-index: Define INTEGRITY_CAPABILITIES MSR
platform/x86/intel/ifs: Add stub driver for In-Field Scan
trace: platform/x86/intel/ifs: Add trace point to track Intel IFS
operations
Documentation: In-Field Scan

.../ABI/testing/sysfs-platform-intel-ifs | 39 +++
Documentation/x86/ifs.rst | 2 +
Documentation/x86/index.rst | 1 +
MAINTAINERS | 8 +
arch/x86/include/asm/cpu.h | 18 ++
arch/x86/include/asm/msr-index.h | 7 +
arch/x86/kernel/cpu/intel.c | 32 +++
arch/x86/kernel/cpu/microcode/intel.c | 59 +---
drivers/platform/x86/intel/Kconfig | 1 +
drivers/platform/x86/intel/Makefile | 1 +
drivers/platform/x86/intel/ifs/Kconfig | 13 +
drivers/platform/x86/intel/ifs/Makefile | 3 +
drivers/platform/x86/intel/ifs/core.c | 73 +++++
drivers/platform/x86/intel/ifs/ifs.h | 234 +++++++++++++++
drivers/platform/x86/intel/ifs/load.c | 266 ++++++++++++++++++
drivers/platform/x86/intel/ifs/runtest.c | 252 +++++++++++++++++
drivers/platform/x86/intel/ifs/sysfs.c | 149 ++++++++++
include/linux/stop_machine.h | 16 ++
include/trace/events/intel_ifs.h | 41 +++
kernel/stop_machine.c | 19 ++
20 files changed, 1182 insertions(+), 52 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-platform-intel-ifs
create mode 100644 Documentation/x86/ifs.rst
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
create mode 100644 drivers/platform/x86/intel/ifs/ifs.h
create mode 100644 drivers/platform/x86/intel/ifs/load.c
create mode 100644 drivers/platform/x86/intel/ifs/runtest.c
create mode 100644 drivers/platform/x86/intel/ifs/sysfs.c
create mode 100644 include/trace/events/intel_ifs.h


base-commit: 672c0c5173427e6b3e2a9bbb7be51ceeec78093a
--
2.35.1


2022-05-09 03:37:34

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH v6 03/11] stop_machine: Add stop_core_cpuslocked() for per-core operations

On Thu, May 05 2022 at 18:40, Tony Luck wrote:
> From: Peter Zijlstra <[email protected]>
>
> 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 <[email protected]>
> Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
> Signed-off-by: Tony Luck <[email protected]>

Reviewed-by: Thomas Gleixner <[email protected]>

2022-05-09 03:50:02

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v7 04/12] 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 <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
Reviewed-by: Thomas Gleixner <[email protected]>
---
MAINTAINERS | 7 ++++
drivers/platform/x86/intel/Kconfig | 1 +
drivers/platform/x86/intel/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, 73 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 edc96cdb85e8..bb0c4ff25942 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9862,6 +9862,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 <[email protected]>
+R: Ashok Raj <[email protected]>
+R: Tony Luck <[email protected]>
+S: Maintained
+F: drivers/platform/x86/intel/ifs
+
INTEL INTEGRATED SENSOR HUB DRIVER
M: Srinivas Pandruvada <[email protected]>
M: Jiri Kosina <[email protected]>
diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig
index 1f01a8a23c57..794968bda115 100644
--- a/drivers/platform/x86/intel/Kconfig
+++ b/drivers/platform/x86/intel/Kconfig
@@ -4,6 +4,7 @@
#

source "drivers/platform/x86/intel/atomisp2/Kconfig"
+source "drivers/platform/x86/intel/ifs/Kconfig"
source "drivers/platform/x86/intel/int1092/Kconfig"
source "drivers/platform/x86/intel/int3472/Kconfig"
source "drivers/platform/x86/intel/pmc/Kconfig"
diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile
index c61bc3e97121..717933dd0cfd 100644
--- a/drivers/platform/x86/intel/Makefile
+++ b/drivers/platform/x86/intel/Makefile
@@ -5,6 +5,7 @@
#

obj-$(CONFIG_INTEL_ATOMISP2_PDX86) += atomisp2/
+obj-$(CONFIG_INTEL_IFS) += ifs/
obj-$(CONFIG_INTEL_SAR_INT1092) += int1092/
obj-$(CONFIG_INTEL_SKL_INT3472) += int3472/
obj-$(CONFIG_INTEL_PMC_CORE) += pmc/
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 <linux/module.h>
+#include <linux/kdev_t.h>
+
+#include <asm/cpu_device_id.h>
+
+#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");
--
2.35.1


2022-05-09 04:53:32

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v6 09/11] platform/x86/intel/ifs: Add IFS sysfs interface

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
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 <linux/module.h>
#include <linux/kdev_t.h>
+#include <linux/semaphore.h>

#include <asm/cpu_device_id.h>

@@ -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 7435a5582df3..6606214773bc 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 <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/semaphore.h>
+#include <linux/slab.h>
+
+#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;
+}
--
2.35.1


2022-05-09 04:54:12

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v6 07/11] platform/x86/intel/ifs: Authenticate and copy to secured memory

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
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 47e5f8344fd8..1a606c999b12 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -7,12 +7,56 @@
#include <linux/device.h>
#include <linux/miscdevice.h>

+#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 <linux/firmware.h>
#include <asm/cpu.h>
+#include <linux/slab.h>
#include <asm/microcode_intel.h>

#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);
}
--
2.35.1


2022-05-09 05:52:29

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v7 02/12] 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 <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
Reviewed-by: Thomas Gleixner <[email protected]>
---
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 ee15311b6be1..c3dc7ae32f1f 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -76,6 +76,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)

@@ -154,6 +156,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
--
2.35.1


2022-05-09 06:02:54

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v7 01/12] x86/microcode/intel: Expose collect_cpu_info_early() for IFS

From: Jithu Joseph <[email protected]>

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 <asm/cpu.h>

Make cpu_signatures_match() an inline function in x86 <asm/cpu.h>,
and also give it an "intel_" prefix.

No functional change intended.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Reviewed-by: Thomas Gleixner <[email protected]>
Acked-by: Borislav Petkov <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
arch/x86/include/asm/cpu.h | 18 ++++++++
arch/x86/kernel/cpu/intel.c | 32 +++++++++++++++
arch/x86/kernel/cpu/microcode/intel.c | 59 ++++-----------------------
3 files changed, 57 insertions(+), 52 deletions(-)

diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index 86e5e4e26fcb..990167357c34 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -76,4 +76,22 @@ static inline void init_ia32_feat_ctl(struct cpuinfo_x86 *c) {}

extern __noendbr void cet_disable(void);

+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 f7a5370a9b3b..94779146275d 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 d28a9f8f3fec..025c8f0cd948 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;
@@ -502,7 +457,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;
}
@@ -604,7 +559,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);

@@ -637,7 +592,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);
}
@@ -712,7 +667,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)
--
2.35.1


2022-05-09 06:31:00

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v7 11/12] platform/x86/intel/ifs: add ABI documentation for IFS

From: Jithu Joseph <[email protected]>

Add the sysfs attributes in ABI/testing for In-Field Scan.

Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
.../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_<N>/run_test
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: Write <cpu#> 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.<N>/run_test
+
+What: /sys/devices/virtual/misc/intel_ifs_<N>/status
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: The status of the last test. It can be one of "pass", "fail"
+ or "untested".
+
+What: /sys/devices/virtual/misc/intel_ifs_<N>/details
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+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_<N>/image_version
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: Version (hexadecimal) of loaded IFS binary image. If no scan image
+ is loaded reports "none".
+
+What: /sys/devices/virtual/misc/intel_ifs_<N>/reload
+Date: April 21 2022
+KernelVersion: 5.19
+Contact: "Jithu Joseph" <[email protected]>
+Description: Write "1" (or "y" or "Y") to reload the IFS image from
+ /lib/firmware/intel/ifs/ff-mm-ss.scan.
--
2.35.1


2022-05-09 07:24:23

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v6 06/11] platform/x86/intel/ifs: Check IFS Image sanity

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
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 <linux/firmware.h>
+#include <asm/cpu.h>
+#include <asm/microcode_intel.h>

#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);
}
--
2.35.1


2022-05-09 07:48:39

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v7 08/12] platform/x86/intel/ifs: Add scan test support

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
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 <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/nmi.h>
+#include <linux/slab.h>
+#include <linux/stop_machine.h>
+
+#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;
+}
--
2.35.1


2022-05-09 08:02:18

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v7 06/12] platform/x86/intel/ifs: Check IFS Image sanity

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
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 <linux/firmware.h>
+#include <asm/cpu.h>
+#include <asm/microcode_intel.h>

#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);
}
--
2.35.1


2022-05-09 08:09:33

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v7 05/12] platform/x86/intel/ifs: Read IFS firmware image

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
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 <asm/cpu_device_id.h>

+#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 <linux/device.h>
+#include <linux/miscdevice.h>
+
+/**
+ * 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 <linux/firmware.h>
+
+#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);
+}
--
2.35.1


2022-05-09 09:12:08

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v7 09/12] platform/x86/intel/ifs: Add IFS sysfs interface

From: Jithu Joseph <[email protected]>

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 <[email protected]>
Signed-off-by: Jithu Joseph <[email protected]>
Co-developed-by: Tony Luck <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
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 <linux/module.h>
#include <linux/kdev_t.h>
+#include <linux/semaphore.h>

#include <asm/cpu_device_id.h>

@@ -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 <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/semaphore.h>
+#include <linux/slab.h>
+
+#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;
+}
--
2.35.1


2022-05-09 09:23:11

by Luck, Tony

[permalink] [raw]
Subject: RE: [PATCH v5 00/10] Introduce In Field Scan driver

> I'll give it some more time for review for v6 and then pick up v6
> (or v7 if review leads to more changes).

Hans,

Thomas has found one substantive problem, and a few minor things (so far ... he
still seems to be working through v6).

So there will be a v7. Likely early next week. Is that OK? Do you still take patches after -rc6?

-Tony

2022-05-09 09:49:11

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v5 00/10] Introduce In Field Scan driver

Hi,

On 5/3/22 17:32, Borislav Petkov wrote:
> On Mon, May 02, 2022 at 05:15:39PM +0200, Hans de Goede wrote:
>> I'm fine with this entire series getting merged through the TIP
>> tree,
>
> Hmm, so looking at the diffstat - the majority of that is
> drivers/platform/x86/ so I guess your tree would be better suited for
> it...

Ok, that also works for me and I see that the few arch/x86 already have
Ack-s / Reviewed-by-s from you / tglx .

I'll give it some more time for review for v6 and then pick up v6
(or v7 if review leads to more changes).

Regards,

Hans


2022-05-09 11:24:17

by Luck, Tony

[permalink] [raw]
Subject: [PATCH v7 10/12] 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) <[email protected]>
Reviewed-by: Dan Williams <[email protected]>
Signed-off-by: Tony Luck <[email protected]>
Acked-by: Hans de Goede <[email protected]>
Reviewed-off-by: Greg Kroah-Hartman <[email protected]>
---
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 bb0c4ff25942..6864fa039974 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9868,6 +9868,7 @@ R: Ashok Raj <[email protected]>
R: Tony Luck <[email protected]>
S: Maintained
F: drivers/platform/x86/intel/ifs
+F: include/trace/events/intel_ifs.h

INTEL INTEGRATED SENSOR HUB DRIVER
M: Srinivas Pandruvada <[email protected]>
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 <trace/events/intel_ifs.h>
+
/* 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 <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+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 <trace/define_trace.h>
--
2.35.1


2022-05-09 12:37:04

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH v7 05/12] platform/x86/intel/ifs: Read IFS firmware image

On Fri, May 06 2022 at 15:54, Tony Luck wrote:
> Reviewed-by: Dan Williams <[email protected]>
> Signed-off-by: Jithu Joseph <[email protected]>
> Co-developed-by: Tony Luck <[email protected]>
> Signed-off-by: Tony Luck <[email protected]>
> Acked-by: Hans de Goede <[email protected]>
> Reviewed-off-by: Greg Kroah-Hartman <[email protected]>

Reviewed-by: Thomas Gleixner <[email protected]>

2022-05-09 12:37:27

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH v7 06/12] platform/x86/intel/ifs: Check IFS Image sanity

On Fri, May 06 2022 at 15:54, Tony Luck wrote:
> Reviewed-by: Dan Williams <[email protected]>
> Signed-off-by: Jithu Joseph <[email protected]>
> Co-developed-by: Tony Luck <[email protected]>
> Signed-off-by: Tony Luck <[email protected]>
> Acked-by: Hans de Goede <[email protected]>
> Reviewed-off-by: Greg Kroah-Hartman <[email protected]>

Reviewed-by: Thomas Gleixner <[email protected]>

2022-05-09 12:37:48

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH v7 08/12] platform/x86/intel/ifs: Add scan test support

On Fri, May 06 2022 at 15:54, Tony Luck wrote:
> From: Jithu Joseph <[email protected]>
>
> 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 <[email protected]>
> Signed-off-by: Jithu Joseph <[email protected]>
> Co-developed-by: Tony Luck <[email protected]>
> Signed-off-by: Tony Luck <[email protected]>
> Acked-by: Hans de Goede <[email protected]>
> Reviewed-off-by: Greg Kroah-Hartman <[email protected]>

Reviewed-by: Thomas Gleixner <[email protected]>

2022-05-09 12:38:03

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH v7 09/12] platform/x86/intel/ifs: Add IFS sysfs interface

On Fri, May 06 2022 at 15:54, Tony Luck wrote:
> 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 <[email protected]>
> Signed-off-by: Jithu Joseph <[email protected]>
> Co-developed-by: Tony Luck <[email protected]>
> Signed-off-by: Tony Luck <[email protected]>
> Acked-by: Hans de Goede <[email protected]>
> Reviewed-off-by: Greg Kroah-Hartman <[email protected]>

Reviewed-by: Thomas Gleixner <[email protected]>

2022-05-09 16:38:50

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH v7 06/12] platform/x86/intel/ifs: Check IFS Image sanity

On Fri, May 06, 2022 at 03:54:04PM -0700, Tony Luck wrote:
> From: Jithu Joseph <[email protected]>
>
> 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.

Is the checksum the only protection against people loading arbitrary IFS
images or are those things signed or encrypted, just like the microcode?

I'd hope they pass the same checks as microcode, when they get loaded,
considering the similarity of how they're handled...

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette

2022-05-09 17:01:07

by Luck, Tony

[permalink] [raw]
Subject: RE: [PATCH v7 06/12] platform/x86/intel/ifs: Check IFS Image sanity

> Is the checksum the only protection against people loading arbitrary IFS
> images or are those things signed or encrypted, just like the microcode?
>
> I'd hope they pass the same checks as microcode, when they get loaded,
> considering the similarity of how they're handled...

The checksum is just a "did this file get corrupted check". The file contains
SHA256 checksums for each of the chunks. These checksums are digitally
signed. Checking of these is done by microcode when the file is loaded into
BIOS reserved memory (where it is inaccessible to OS and I/O).

-Tony

2022-05-09 17:06:49

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH v7 06/12] platform/x86/intel/ifs: Check IFS Image sanity

On Mon, May 09, 2022 at 04:51:56PM +0000, Luck, Tony wrote:
> The checksum is just a "did this file get corrupted check". The file contains
> SHA256 checksums for each of the chunks. These checksums are digitally
> signed. Checking of these is done by microcode when the file is loaded into
> BIOS reserved memory (where it is inaccessible to OS and I/O).

That sounds like something I was hoping to hear, good. :-)

Thx.

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette

2022-05-09 17:13:00

by Luck, Tony

[permalink] [raw]
Subject: RE: [PATCH v5 00/10] Introduce In Field Scan driver

>> Do you still take patches after -rc6?
>
> If the patches are send soon (1-2 days) after rc6 I can still take them.

Hans,

V7 was posted Friday. It survived my weekend testing, and another round of tglx scrutiny (ending with
his "Reviewed-by" on the latter parts of the series.

Let me know if there is anything else you need to get them applied.

Thanks

-Tony

2022-05-09 18:19:18

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v5 00/10] Introduce In Field Scan driver

Hi,

On 5/9/22 19:05, Luck, Tony wrote:
>>> Do you still take patches after -rc6?
>>
>> If the patches are send soon (1-2 days) after rc6 I can still take them.
>
> Hans,
>
> V7 was posted Friday. It survived my weekend testing, and another round of tglx scrutiny (ending with
> his "Reviewed-by" on the latter parts of the series.
>
> Let me know if there is anything else you need to get them applied.

From my side everything looks good. I plan to merge this
into my review-hans (*) branch coming Wednesday.

Regards,

Hans



*) And then from there move it to for-next once the build bots
have had a chance to play with it



2022-05-13 05:34:48

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v7 00/12] Introduce In Field Scan driver

Hi,

On 5/7/22 00:53, Tony Luck wrote:
> TL;DR this driver loads scan test files that can check whether silicon
> in a CPU core is still running correctly. It is expected that these tests
> would be run several times per day to catch problems as silicon ages.

Thank you for your patch-series, I've applied the series to my
review-hans branch:
https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git/log/?h=review-hans

Note it will show up in my review-hans branch once I've pushed my
local branch there, which might take a while.

Once I've run some tests on this branch the patches there will be
added to the platform-drivers-x86/for-next branch and eventually
will be included in the pdx86 pull-request to Linus for the next
merge-window.

Regards,

Hans




>
> Changes since v6
>
> Thomas Gleixner
> ---------------
> "struct workqueue_struct *ifs_wq; Seems to be unused."
>
> True. Deleted.
>
> "static bool oscan_enabled = true; What changes this?"
>
> Code that cleared it deleted. Drop this too.
>
> "Please add curly brackets as these are not one-line statements"
>
> Added
>
> cpumask_first(topology_sibling_cpumask(cpu)); Shouldn't that be cpu_smt_mask()?"
>
> Changed (and several other places)
>
> "take up to 200 milliseconds before it retires. 200ms per test chunk?"
>
> Updated comment to note that 200ms is for all chunks.
>
> "Documentation lost in the intertubes"
>
> Dredged up the version from v3 series and changed:
> 1) Fixed pathnames now this is a virtual misc device instead of platform
> device
> 2) Put all the text into a "/** DOC:" comment section in ifs.h with just
> a "kernel-doc:: drivers/platform/x86/intel/ifs/ifs.h" in the ifs.rst
> file under Documentation/x86.
> 3) Added a "big fat warning" (in all CAPS) pointing out that a core test
> can take up to 200 milliseconds. So admins must take extra steps if they
> are running latency sensitive workloads.
> 4) Added note that all HT threads of a core must be online to run a
> test.
>
> Tony Luck
> ---------
> Off-by-one on retries check (#define set to 5, but tried 6 times). Fixed
> Fixed kerneldoc description of "integrity_cap_bit" (was missing a ":")
>
> Jithu Joseph (7):
> x86/microcode/intel: Expose collect_cpu_info_early() for IFS
> platform/x86/intel/ifs: Read IFS firmware image
> platform/x86/intel/ifs: Check IFS Image sanity
> platform/x86/intel/ifs: Authenticate and copy to secured memory
> platform/x86/intel/ifs: Add scan test support
> platform/x86/intel/ifs: Add IFS sysfs interface
> platform/x86/intel/ifs: add ABI documentation for IFS
>
> Peter Zijlstra (1):
> stop_machine: Add stop_core_cpuslocked() for per-core operations
>
> Tony Luck (4):
> x86/msr-index: Define INTEGRITY_CAPABILITIES MSR
> platform/x86/intel/ifs: Add stub driver for In-Field Scan
> trace: platform/x86/intel/ifs: Add trace point to track Intel IFS
> operations
> Documentation: In-Field Scan
>
> .../ABI/testing/sysfs-platform-intel-ifs | 39 +++
> Documentation/x86/ifs.rst | 2 +
> Documentation/x86/index.rst | 1 +
> MAINTAINERS | 8 +
> arch/x86/include/asm/cpu.h | 18 ++
> arch/x86/include/asm/msr-index.h | 7 +
> arch/x86/kernel/cpu/intel.c | 32 +++
> arch/x86/kernel/cpu/microcode/intel.c | 59 +---
> drivers/platform/x86/intel/Kconfig | 1 +
> drivers/platform/x86/intel/Makefile | 1 +
> drivers/platform/x86/intel/ifs/Kconfig | 13 +
> drivers/platform/x86/intel/ifs/Makefile | 3 +
> drivers/platform/x86/intel/ifs/core.c | 73 +++++
> drivers/platform/x86/intel/ifs/ifs.h | 234 +++++++++++++++
> drivers/platform/x86/intel/ifs/load.c | 266 ++++++++++++++++++
> drivers/platform/x86/intel/ifs/runtest.c | 252 +++++++++++++++++
> drivers/platform/x86/intel/ifs/sysfs.c | 149 ++++++++++
> include/linux/stop_machine.h | 16 ++
> include/trace/events/intel_ifs.h | 41 +++
> kernel/stop_machine.c | 19 ++
> 20 files changed, 1182 insertions(+), 52 deletions(-)
> create mode 100644 Documentation/ABI/testing/sysfs-platform-intel-ifs
> create mode 100644 Documentation/x86/ifs.rst
> 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
> create mode 100644 drivers/platform/x86/intel/ifs/ifs.h
> create mode 100644 drivers/platform/x86/intel/ifs/load.c
> create mode 100644 drivers/platform/x86/intel/ifs/runtest.c
> create mode 100644 drivers/platform/x86/intel/ifs/sysfs.c
> create mode 100644 include/trace/events/intel_ifs.h
>
>
> base-commit: 672c0c5173427e6b3e2a9bbb7be51ceeec78093a