Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions drivers/platform/x86/intel/ifs/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@

#include "ifs.h"

#define X86_MATCH(model) \
#define X86_MATCH(model, array_gen) \
X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \
INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, NULL)
INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, array_gen)

static const struct x86_cpu_id ifs_cpu_ids[] __initconst = {
X86_MATCH(SAPPHIRERAPIDS_X),
X86_MATCH(EMERALDRAPIDS_X),
X86_MATCH(SAPPHIRERAPIDS_X, ARRAY_GEN0),
X86_MATCH(EMERALDRAPIDS_X, ARRAY_GEN0),
X86_MATCH(GRANITERAPIDS_X, ARRAY_GEN0),
X86_MATCH(GRANITERAPIDS_D, ARRAY_GEN0),
X86_MATCH(ATOM_CRESTMONT_X, ARRAY_GEN1),
{}
};
MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids);
Expand Down Expand Up @@ -97,6 +100,7 @@ static int __init ifs_init(void)
continue;
ifs_devices[i].rw_data.generation = FIELD_GET(MSR_INTEGRITY_CAPS_SAF_GEN_MASK,
msrval);
ifs_devices[i].rw_data.array_gen = (u32)m->driver_data;
ret = misc_register(&ifs_devices[i].misc);
if (ret)
goto err_exit;
Expand Down
34 changes: 34 additions & 0 deletions drivers/platform/x86/intel/ifs/ifs.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,20 @@
#define MSR_CHUNKS_AUTHENTICATION_STATUS 0x000002c5
#define MSR_ACTIVATE_SCAN 0x000002c6
#define MSR_SCAN_STATUS 0x000002c7
#define MSR_ARRAY_TRIGGER 0x000002d6
#define MSR_ARRAY_STATUS 0x000002d7
#define MSR_SAF_CTRL 0x000004f0

#define SCAN_NOT_TESTED 0
#define SCAN_TEST_PASS 1
#define SCAN_TEST_FAIL 2

#define IFS_TYPE_SAF 0
#define IFS_TYPE_ARRAY_BIST 1

#define ARRAY_GEN0 0
#define ARRAY_GEN1 1

/* MSR_SCAN_HASHES_STATUS bit fields */
union ifs_scan_hashes_status {
u64 data;
Expand All @@ -158,6 +165,19 @@ union ifs_scan_hashes_status {
};
};

union ifs_scan_hashes_status_gen2 {
u64 data;
struct {
u16 chunk_size;
u16 num_chunks;
u32 error_code :8;
u32 chunks_in_stride :9;
u32 rsvd :2;
u32 max_core_limit :12;
u32 valid :1;
};
};

/* MSR_CHUNKS_AUTH_STATUS bit fields */
union ifs_chunks_auth_status {
u64 data;
Expand All @@ -170,6 +190,16 @@ union ifs_chunks_auth_status {
};
};

union ifs_chunks_auth_status_gen2 {
u64 data;
struct {
u16 valid_chunks;
u16 total_chunks;
u32 error_code :8;
u32 rsvd2 :24;
};
};

/* MSR_ACTIVATE_SCAN bit fields */
union ifs_scan {
u64 data;
Expand Down Expand Up @@ -246,6 +276,8 @@ struct ifs_test_caps {
* @scan_details: opaque scan status code from h/w
* @cur_batch: number indicating the currently loaded test file
* @generation: IFS test generation enumerated by hardware
* @chunk_size: size of a test chunk
* @array_gen: test generation of array test
*/
struct ifs_data {
int loaded_version;
Expand All @@ -256,6 +288,8 @@ struct ifs_data {
u64 scan_details;
u32 cur_batch;
u32 generation;
u32 chunk_size;
u32 array_gen;
};

struct ifs_work {
Expand Down
150 changes: 136 additions & 14 deletions drivers/platform/x86/intel/ifs/load.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/* Copyright(c) 2022 Intel Corporation. */

#include <linux/firmware.h>
#include <linux/sizes.h>
#include <asm/cpu.h>
#include <asm/microcode.h>

Expand All @@ -26,6 +27,11 @@ union meta_data {

#define IFS_HEADER_SIZE (sizeof(struct microcode_header_intel))
#define META_TYPE_IFS 1
#define INVALIDATE_STRIDE 0x1UL
#define IFS_GEN_STRIDE_AWARE 2
#define AUTH_INTERRUPTED_ERROR 5
#define IFS_AUTH_RETRY_CT 10

static struct microcode_header_intel *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 */
Expand All @@ -44,7 +50,10 @@ static const char * const scan_hash_status[] = {
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"
[2] = "Chunk authentication error. The hash of chunk did not match expected value",
[3] = "Reserved",
[4] = "Chunk outside the current stride",
[5] = "Authentication flow interrupted",
};

#define MC_HEADER_META_TYPE_END (0)
Expand Down Expand Up @@ -80,6 +89,23 @@ static struct metadata_header *find_meta_data(void *ucode, unsigned int meta_typ
return NULL;
}

static void hashcopy_err_message(struct device *dev, u32 err_code)
{
if (err_code >= ARRAY_SIZE(scan_hash_status))
dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code);
else
dev_err(dev, "Hash copy error : %s\n", scan_hash_status[err_code]);
}

static void auth_err_message(struct device *dev, u32 err_code)
{
if (err_code >= ARRAY_SIZE(scan_authentication_status))
dev_err(dev, "invalid error code 0x%x for authentication\n", err_code);
else
dev_err(dev, "Chunk authentication error : %s\n",
scan_authentication_status[err_code]);
}

/*
* To copy scan hashes and authenticate test chunks, the initiating cpu must point
* to the EDX:EAX to the test image in linear address.
Expand Down Expand Up @@ -109,11 +135,7 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work)

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]);
hashcopy_err_message(dev, err_code);
goto done;
}

Expand All @@ -133,20 +155,110 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work)

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]);
auth_err_message(dev, err_code);
goto done;
}
}
done:
complete(&ifs_done);
}

static int get_num_chunks(int gen, union ifs_scan_hashes_status_gen2 status)
{
return gen >= IFS_GEN_STRIDE_AWARE ? status.chunks_in_stride : status.num_chunks;
}

static bool need_copy_scan_hashes(struct ifs_data *ifsd)
{
return !ifsd->loaded ||
ifsd->generation < IFS_GEN_STRIDE_AWARE ||
ifsd->loaded_version != ifs_header_ptr->rev;
}

static int copy_hashes_authenticate_chunks_gen2(struct device *dev)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Possible uninitialized use of chunk_status in copy_hashes_authenticate_chunks_gen2.

If num_chunks is zero, chunk_status may remain uninitialized. Please add explicit handling for the zero-chunk case.

{
union ifs_scan_hashes_status_gen2 hashes_status;
union ifs_chunks_auth_status_gen2 chunk_status;
u32 err_code, valid_chunks, total_chunks;
int i, num_chunks, chunk_size;
union meta_data *ifs_meta;
int starting_chunk_nr;
struct ifs_data *ifsd;
u64 linear_addr, base;
u64 chunk_table[2];
int retry_count;

ifsd = ifs_get_data(dev);

if (need_copy_scan_hashes(ifsd)) {
wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr);
rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data);

/* enumerate the scan image information */
chunk_size = hashes_status.chunk_size * SZ_1K;
err_code = hashes_status.error_code;

num_chunks = get_num_chunks(ifsd->generation, hashes_status);

if (!hashes_status.valid) {
hashcopy_err_message(dev, err_code);
return -EIO;
}
ifsd->loaded_version = ifs_header_ptr->rev;
ifsd->chunk_size = chunk_size;
} else {
num_chunks = ifsd->valid_chunks;
chunk_size = ifsd->chunk_size;
}

if (ifsd->generation >= IFS_GEN_STRIDE_AWARE) {
wrmsrl(MSR_SAF_CTRL, INVALIDATE_STRIDE);
rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
if (chunk_status.valid_chunks != 0) {
dev_err(dev, "Couldn't invalidate installed stride - %d\n",
chunk_status.valid_chunks);
return -EIO;
}
}

base = ifs_test_image_ptr;
ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS);
starting_chunk_nr = ifs_meta->starting_chunk;

/* scan data authentication and copy chunks to secured memory */
for (i = 0; i < num_chunks; i++) {
retry_count = IFS_AUTH_RETRY_CT;
linear_addr = base + i * chunk_size;

chunk_table[0] = starting_chunk_nr + i;
chunk_table[1] = linear_addr;
do {
wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, (u64)chunk_table);
rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
err_code = chunk_status.error_code;
} while (err_code == AUTH_INTERRUPTED_ERROR && --retry_count);

if (err_code) {
ifsd->loading_error = true;
auth_err_message(dev, err_code);
return -EIO;
}
}

valid_chunks = chunk_status.valid_chunks;
total_chunks = chunk_status.total_chunks;

if (valid_chunks != total_chunks) {
ifsd->loading_error = true;
dev_err(dev, "Couldn't authenticate all the chunks. Authenticated %d total %d.\n",
valid_chunks, total_chunks);
return -EIO;
}
ifsd->valid_chunks = valid_chunks;

return 0;
}

static int validate_ifs_metadata(struct device *dev)
{
struct ifs_data *ifsd = ifs_get_data(dev);
Expand Down Expand Up @@ -179,6 +291,13 @@ static int validate_ifs_metadata(struct device *dev)
return ret;
}

if (ifs_meta->chunks_per_stride &&
(ifs_meta->starting_chunk % ifs_meta->chunks_per_stride != 0)) {
dev_warn(dev, "Starting chunk num %u not a multiple of chunks_per_stride %u\n",
ifs_meta->starting_chunk, ifs_meta->chunks_per_stride);
return ret;
}

return 0;
}

Expand All @@ -199,7 +318,9 @@ static int scan_chunks_sanity_check(struct device *dev)
return ret;

ifsd->loading_error = false;
ifsd->loaded_version = ifs_header_ptr->rev;

if (ifsd->generation > 0)
return copy_hashes_authenticate_chunks_gen2(dev);
Copy link

Copilot AI Jun 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The assignment of ifsd->loaded_version occurs in two separate code paths (one in copy_hashes_authenticate_chunks_gen2 and again after cpus_read_unlock). Consider consolidating this update to ensure consistent firmware version tracking across all branches.

Suggested change
return copy_hashes_authenticate_chunks_gen2(dev);
ret = copy_hashes_authenticate_chunks_gen2(dev);
goto update_version;

Copilot uses AI. Check for mistakes.

/* copy the scan hash and authenticate per package */
cpus_read_lock();
Expand All @@ -219,6 +340,7 @@ static int scan_chunks_sanity_check(struct device *dev)
ifs_pkg_auth[curr_pkg] = 1;
}
ret = 0;
ifsd->loaded_version = ifs_header_ptr->rev;
out:
cpus_read_unlock();

Expand Down
Loading
Loading