summaryrefslogtreecommitdiff
path: root/arch/x86/kernel/cpu/microcode
diff options
context:
space:
mode:
authorBorislav Petkov <bp@suse.de>2018-10-19 15:27:24 +0300
committerBorislav Petkov <bp@suse.de>2018-11-19 12:51:06 +0300
commitd430a305b7f8127d992e79e90b6fac00f99d23b3 (patch)
tree8872f7ac196b4072960203e75731295037364605 /arch/x86/kernel/cpu/microcode
parentc79570205ba6064bd756f531e6d9d0b498a191d6 (diff)
downloadlinux-d430a305b7f8127d992e79e90b6fac00f99d23b3.tar.xz
x86/microcode/AMD: Change verify_patch()'s return value
Have it return 0 on success, positive value when the current patch should be skipped and negative on error. Signed-off-by: Borislav Petkov <bp@suse.de> Cc: x86@kernel.org Link: https://lkml.kernel.org/r/20181107170218.7596-11-bp@alien8.de
Diffstat (limited to 'arch/x86/kernel/cpu/microcode')
-rw-r--r--arch/x86/kernel/cpu/microcode/amd.c91
1 files changed, 52 insertions, 39 deletions
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
index ebac82357639..79216cfb9f72 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -210,24 +210,32 @@ __verify_patch_size(u8 family, u32 sh_psize, unsigned int buf_size)
break;
}
- if (sh_psize > min_t(u32, buf_size, max_size)) {
- pr_err("patch size mismatch\n");
+ if (sh_psize > min_t(u32, buf_size, max_size))
return 0;
- }
return sh_psize;
}
-static unsigned int
-verify_patch(u8 family, const u8 *buf, unsigned int buf_size, bool early)
+/*
+ * Verify the patch in @buf.
+ *
+ * Returns:
+ * negative: on error
+ * positive: patch is not for this family, skip it
+ * 0: success
+ */
+static int
+verify_patch(u8 family, const u8 *buf, size_t buf_size, u32 *patch_size, bool early)
{
struct microcode_header_amd *mc_hdr;
+ unsigned int ret;
u32 sh_psize;
u16 proc_id;
u8 patch_fam;
if (!__verify_patch_section(buf, buf_size, &sh_psize, early))
- return 0;
+ return -1;
+
/*
* The section header length is not included in this indicated size
* but is present in the leftover file length so we need to subtract
@@ -243,23 +251,31 @@ verify_patch(u8 family, const u8 *buf, unsigned int buf_size, bool early)
if (!early)
pr_debug("Patch of size %u truncated.\n", sh_psize);
- return 0;
+ return -1;
}
- mc_hdr = (struct microcode_header_amd *)(buf + SECTION_HDR_SIZE);
- proc_id = mc_hdr->processor_rev_id;
+ ret = __verify_patch_size(family, sh_psize, buf_size);
+ if (!ret) {
+ if (!early)
+ pr_debug("Per-family patch size mismatch.\n");
+ return -1;
+ }
+
+ *patch_size = sh_psize;
+ mc_hdr = (struct microcode_header_amd *)(buf + SECTION_HDR_SIZE);
if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) {
if (!early)
pr_err("Patch-ID 0x%08x: chipset-specific code unsupported.\n", mc_hdr->patch_id);
- return 0;
+ return -1;
}
+ proc_id = mc_hdr->processor_rev_id;
patch_fam = 0xf + (proc_id >> 12);
if (patch_fam != family)
- return 0;
+ return 1;
- return __verify_patch_size(family, sh_psize, buf_size);
+ return 0;
}
/*
@@ -729,23 +745,17 @@ static void cleanup(void)
* driver cannot continue functioning normally. In such cases, we tear
* down everything we've used up so far and exit.
*/
-static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover)
+static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover,
+ unsigned int *patch_size)
{
struct microcode_header_amd *mc_hdr;
- unsigned int patch_size, crnt_size;
struct ucode_patch *patch;
u16 proc_id;
+ int ret;
- patch_size = verify_patch(family, fw, leftover, false);
- if (!patch_size) {
- pr_debug("Patch size mismatch.\n");
- return 1;
- }
-
- /* If initial rough pokes pass, we can start looking at the header. */
- crnt_size = patch_size + SECTION_HDR_SIZE;
- mc_hdr = (struct microcode_header_amd *)(fw + SECTION_HDR_SIZE);
- proc_id = mc_hdr->processor_rev_id;
+ ret = verify_patch(family, fw, leftover, patch_size, false);
+ if (ret)
+ return ret;
patch = kzalloc(sizeof(*patch), GFP_KERNEL);
if (!patch) {
@@ -753,13 +763,16 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover)
return -EINVAL;
}
- patch->data = kmemdup(fw + SECTION_HDR_SIZE, patch_size, GFP_KERNEL);
+ patch->data = kmemdup(fw + SECTION_HDR_SIZE, *patch_size, GFP_KERNEL);
if (!patch->data) {
pr_err("Patch data allocation failure.\n");
kfree(patch);
return -EINVAL;
}
+ mc_hdr = (struct microcode_header_amd *)(fw + SECTION_HDR_SIZE);
+ proc_id = mc_hdr->processor_rev_id;
+
INIT_LIST_HEAD(&patch->plist);
patch->patch_id = mc_hdr->patch_id;
patch->equiv_cpu = proc_id;
@@ -770,39 +783,39 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover)
/* ... and add to cache. */
update_cache(patch);
- return crnt_size;
+ return 0;
}
static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
size_t size)
{
- enum ucode_state ret = UCODE_ERROR;
- unsigned int leftover;
u8 *fw = (u8 *)data;
- int crnt_size = 0;
int offset;
offset = install_equiv_cpu_table(data);
if (offset < 0) {
pr_err("failed to create equivalent cpu table\n");
- return ret;
+ return UCODE_ERROR;
}
- fw += offset;
- leftover = size - offset;
+ fw += offset;
+ size -= offset;
if (*(u32 *)fw != UCODE_UCODE_TYPE) {
pr_err("invalid type field in container file section header\n");
free_equiv_cpu_table();
- return ret;
+ return UCODE_ERROR;
}
- while (leftover) {
- crnt_size = verify_and_add_patch(family, fw, leftover);
- if (crnt_size < 0)
- return ret;
+ while (size > 0) {
+ unsigned int crnt_size = 0;
+ int ret;
+
+ ret = verify_and_add_patch(family, fw, size, &crnt_size);
+ if (ret < 0)
+ return UCODE_ERROR;
- fw += crnt_size;
- leftover -= crnt_size;
+ fw += crnt_size + SECTION_HDR_SIZE;
+ size -= (crnt_size + SECTION_HDR_SIZE);
}
return UCODE_OK;