From: Borislav Petkov <bp@alien8.de>
To: "Raj, Ashok" <ashok.raj@intel.com>
Cc: Mihai Carabas <mihai.carabas@oracle.com>,
Boris Ostrovsky <boris.ostrovsky@oracle.com>,
"H. Peter Anvin" <hpa@zytor.com>, Ingo Molnar <mingo@redhat.com>,
Jon Grimm <Jon.Grimm@amd.com>,
kanth.ghatraju@oracle.com, konrad.wilk@oracle.com,
patrick.colp@oracle.com, Thomas Gleixner <tglx@linutronix.de>,
Tom Lendacky <thomas.lendacky@amd.com>, x86-ml <x86@kernel.org>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] x86/microcode: Add an option to reload microcode even if revision is unchanged
Date: Tue, 3 Sep 2019 18:46:30 +0200 [thread overview]
Message-ID: <20190903164630.GF11641@zn.tnic> (raw)
In-Reply-To: <20190829130213.GA23510@araj-mobl1.jf.intel.com>
On Thu, Aug 29, 2019 at 06:02:14AM -0700, Raj, Ashok wrote:
> > As I've said before, I don't like the churn in this version and how it
> > turns out. I'll have a look at how to do this cleanly when I get some
> > free cycles.
Ok, here's an untested rough version. It is doing a couple of things in
one go, including cleanups, which I'll eventually separate out but it
should suffice for now to show the intent: namely, reload the microcode
revision which late loading has loaded already in the past. See, pls, if
that suffices for your microcoders' needs.
Thx.
---
diff --git a/Documentation/x86/microcode.rst b/Documentation/x86/microcode.rst
index a320d37982ed..4b2b9c350cea 100644
--- a/Documentation/x86/microcode.rst
+++ b/Documentation/x86/microcode.rst
@@ -110,6 +110,17 @@ The loading mechanism looks for microcode blobs in
/lib/firmware/{intel-ucode,amd-ucode}. The default distro installation
packages already put them there.
+Normally, microcode will be updated only if the current revision's
+number is smaller than the new one.
+
+Reload of the current revision can be done by doing::
+
+ # echo 2 > /sys/devices/system/cpu/microcode/reload
+
+as root. This is meant to have a quicker turnaround when testing
+microcode patches and will taint the kernel so do not use it if you
+don't know what you're doing.
+
Builtin microcode
=================
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
index 2b7cc5397f80..3e53ce875e55 100644
--- a/arch/x86/include/asm/microcode.h
+++ b/arch/x86/include/asm/microcode.h
@@ -35,19 +35,24 @@ struct microcode_ops {
enum ucode_state (*request_microcode_user) (int cpu,
const void __user *buf, size_t size);
- enum ucode_state (*request_microcode_fw) (int cpu, struct device *,
+ enum ucode_state (*request_microcode_fw)(int cpu, struct device *dev,
bool refresh_fw);
- void (*microcode_fini_cpu) (int cpu);
+ void (*microcode_fini_cpu)(int cpu);
/*
* The generic 'microcode_core' part guarantees that
- * the callbacks below run on a target cpu when they
+ * the callbacks below run on a target CPU when they
* are being called.
- * See also the "Synchronization" section in microcode_core.c.
+ * See also the "Synchronization" section in microcode/core.c.
*/
- enum ucode_state (*apply_microcode) (int cpu);
+ enum ucode_state (*apply_microcode)(unsigned int cpu);
int (*collect_cpu_info) (int cpu, struct cpu_signature *csig);
+
+ /*
+ * Attempt to reapply microcode without any checking whatsoever.
+ */
+ enum ucode_state (*apply_microcode_nocheck)(unsigned int cpu);
};
struct ucode_cpu_info {
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
index a0e52bd00ecc..e9e2bd9e5d4d 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -666,7 +666,7 @@ static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
return 0;
}
-static enum ucode_state apply_microcode_amd(int cpu)
+static enum ucode_state apply_microcode_amd(unsigned int cpu)
{
struct cpuinfo_x86 *c = &cpu_data(cpu);
struct microcode_amd *mc_amd;
@@ -675,7 +675,8 @@ static enum ucode_state apply_microcode_amd(int cpu)
enum ucode_state ret;
u32 rev, dummy;
- BUG_ON(raw_smp_processor_id() != cpu);
+ if (WARN_ON(raw_smp_processor_id() != cpu))
+ return UCODE_ERROR;
uci = ucode_cpu_info + cpu;
@@ -716,6 +717,28 @@ static enum ucode_state apply_microcode_amd(int cpu)
return ret;
}
+static enum ucode_state apply_microcode_nocheck_amd(unsigned int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ struct microcode_amd *mc;
+
+ if (WARN_ON(raw_smp_processor_id() != cpu))
+ return UCODE_ERROR;
+
+ if (!uci->mc)
+ return UCODE_NFOUND;
+
+ mc = uci->mc;
+
+ if (__apply_microcode_amd(mc)) {
+ pr_err("CPU%d: update failed for patch_level=0x%08x\n",
+ cpu, mc->hdr.patch_id);
+ return UCODE_ERROR;
+ }
+
+ return UCODE_OK;
+}
+
static size_t install_equiv_cpu_table(const u8 *buf, size_t buf_size)
{
u32 equiv_tbl_len;
@@ -933,11 +956,12 @@ static void microcode_fini_cpu_amd(int cpu)
}
static struct microcode_ops microcode_amd_ops = {
- .request_microcode_user = request_microcode_user,
- .request_microcode_fw = request_microcode_amd,
- .collect_cpu_info = collect_cpu_info_amd,
- .apply_microcode = apply_microcode_amd,
- .microcode_fini_cpu = microcode_fini_cpu_amd,
+ .request_microcode_user = request_microcode_user,
+ .request_microcode_fw = request_microcode_amd,
+ .collect_cpu_info = collect_cpu_info_amd,
+ .apply_microcode = apply_microcode_amd,
+ .apply_microcode_nocheck = apply_microcode_nocheck_amd,
+ .microcode_fini_cpu = microcode_fini_cpu_amd,
};
struct microcode_ops * __init init_amd_microcode(void)
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 7019d4b2df0c..345deaf55119 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -42,6 +42,8 @@
#define DRIVER_VERSION "2.2"
+typedef void (*apply_fn_t)(void *arg);
+
static struct microcode_ops *microcode_ops;
static bool dis_ucode_ldr = true;
@@ -379,6 +381,13 @@ static void apply_microcode_local(void *arg)
*err = microcode_ops->apply_microcode(smp_processor_id());
}
+static void apply_microcode_nocheck(void *arg)
+{
+ enum ucode_state *err = arg;
+
+ *err = microcode_ops->apply_microcode_nocheck(smp_processor_id());
+}
+
static int apply_microcode_on_target(int cpu)
{
enum ucode_state err;
@@ -550,6 +559,7 @@ static int __wait_for_cpus(atomic_t *t, long long timeout)
*/
static int __reload_late(void *info)
{
+ apply_fn_t ap_func = (apply_fn_t)(info);
int cpu = smp_processor_id();
enum ucode_state err;
int ret = 0;
@@ -569,7 +579,7 @@ static int __reload_late(void *info)
* below.
*/
if (cpumask_first(topology_sibling_cpumask(cpu)) == cpu)
- apply_microcode_local(&err);
+ ap_func(&err);
else
goto wait_for_siblings;
@@ -591,7 +601,7 @@ static int __reload_late(void *info)
* revision.
*/
if (cpumask_first(topology_sibling_cpumask(cpu)) != cpu)
- apply_microcode_local(&err);
+ ap_func(&err);
return ret;
}
@@ -600,14 +610,14 @@ static int __reload_late(void *info)
* Reload microcode late on all CPUs. Wait for a sec until they
* all gather together.
*/
-static int microcode_reload_late(void)
+static int microcode_reload_late(apply_fn_t apply_func)
{
int ret;
atomic_set(&late_cpus_in, 0);
atomic_set(&late_cpus_out, 0);
- ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask);
+ ret = stop_machine_cpuslocked(__reload_late, apply_func, cpu_online_mask);
if (ret > 0)
microcode_check();
@@ -629,8 +639,12 @@ static ssize_t reload_store(struct device *dev,
if (ret)
return ret;
- if (val != 1)
+ if (val == 2) {
+ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
+ return microcode_reload_late(apply_microcode_nocheck);
+ } else if (val != 1) {
return size;
+ }
tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev, true);
if (tmp_ret != UCODE_NEW)
@@ -643,7 +657,7 @@ static ssize_t reload_store(struct device *dev,
goto put;
mutex_lock(µcode_mutex);
- ret = microcode_reload_late();
+ ret = microcode_reload_late(apply_microcode_local);
mutex_unlock(µcode_mutex);
put:
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index 6a99535d7f37..4cc438833f3f 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -787,7 +787,7 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
return 0;
}
-static enum ucode_state apply_microcode_intel(int cpu)
+static enum ucode_state apply_microcode_intel(unsigned int cpu)
{
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
struct cpuinfo_x86 *c = &cpu_data(cpu);
@@ -859,6 +859,31 @@ static enum ucode_state apply_microcode_intel(int cpu)
return ret;
}
+static enum ucode_state apply_microcode_nocheck_intel(unsigned int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ struct microcode_intel *mc;
+
+ if (WARN_ON(raw_smp_processor_id() != cpu))
+ return UCODE_ERROR;
+
+ if (!uci->mc)
+ return UCODE_NFOUND;
+
+ mc = uci->mc;
+
+ /*
+ * Writeback and invalidate caches before updating microcode to avoid
+ * internal issues depending on what the microcode is updating.
+ */
+ native_wbinvd();
+
+ /* write microcode via MSR 0x79 */
+ wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
+
+ return UCODE_OK;
+}
+
static enum ucode_state generic_load_microcode(int cpu, struct iov_iter *iter)
{
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -1014,10 +1039,11 @@ request_microcode_user(int cpu, const void __user *buf, size_t size)
}
static struct microcode_ops microcode_intel_ops = {
- .request_microcode_user = request_microcode_user,
- .request_microcode_fw = request_microcode_fw,
- .collect_cpu_info = collect_cpu_info,
- .apply_microcode = apply_microcode_intel,
+ .request_microcode_user = request_microcode_user,
+ .request_microcode_fw = request_microcode_fw,
+ .collect_cpu_info = collect_cpu_info,
+ .apply_microcode = apply_microcode_intel,
+ .apply_microcode_nocheck = apply_microcode_nocheck_intel,
};
static int __init calc_llc_size_per_core(struct cpuinfo_x86 *c)
--
Regards/Gruss,
Boris.
Good mailing practices for 400: avoid top-posting and trim the reply.
next prev parent reply other threads:[~2019-09-03 16:46 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-08-29 5:33 [PATCH] x86/microcode: Add an option to reload microcode even if revision is unchanged Ashok Raj
2019-08-29 5:38 ` Raj, Ashok
2019-08-29 6:09 ` Borislav Petkov
2019-08-29 13:02 ` Raj, Ashok
2019-09-03 16:46 ` Borislav Petkov [this message]
2019-09-04 22:06 ` Boris Ostrovsky
2019-09-04 22:12 ` Boris Petkov
2019-09-05 0:21 ` Raj, Ashok
2019-09-05 7:20 ` Borislav Petkov
2019-09-05 10:51 ` Thomas Gleixner
2019-09-05 19:40 ` Raj, Ashok
2019-09-05 19:49 ` Borislav Petkov
2019-09-05 20:20 ` Raj, Ashok
2019-09-05 21:22 ` Thomas Gleixner
2019-09-05 22:27 ` Raj, Ashok
2019-09-06 7:46 ` Borislav Petkov
2019-09-06 12:51 ` Thomas Gleixner
2019-09-06 14:40 ` Johannes Erdfelt
2019-09-06 15:16 ` Borislav Petkov
2019-09-06 15:46 ` Johannes Erdfelt
2019-09-06 16:17 ` Borislav Petkov
2019-09-06 16:43 ` Konrad Rzeszutek Wilk
2019-09-06 17:10 ` Borislav Petkov
2019-09-06 16:52 ` Johannes Erdfelt
2019-09-06 17:17 ` Borislav Petkov
2019-09-06 21:16 ` Thomas Gleixner
2019-09-07 0:33 ` Raj, Ashok
2019-09-07 10:37 ` Thomas Gleixner
2019-09-16 10:36 ` Thomas Gleixner
2019-09-17 0:31 ` Raj, Ashok
2019-09-17 6:37 ` Thomas Gleixner
2019-09-17 6:46 ` Borislav Petkov
2019-09-17 14:29 ` Raj, Ashok
2019-09-19 19:48 ` Mihai Carabas
2019-09-06 16:55 ` Raj, Ashok
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190903164630.GF11641@zn.tnic \
--to=bp@alien8.de \
--cc=Jon.Grimm@amd.com \
--cc=ashok.raj@intel.com \
--cc=boris.ostrovsky@oracle.com \
--cc=hpa@zytor.com \
--cc=kanth.ghatraju@oracle.com \
--cc=konrad.wilk@oracle.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mihai.carabas@oracle.com \
--cc=mingo@redhat.com \
--cc=patrick.colp@oracle.com \
--cc=tglx@linutronix.de \
--cc=thomas.lendacky@amd.com \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.