Re: [PATCH 1/2] x86/mm/pat: Change pat_disable() to emulate PAT table

From: Toshi Kani
Date: Mon Mar 14 2016 - 22:18:54 EST


On Tue, 2016-03-15 at 01:29 +0100, Luis R. Rodriguez wrote:
> I like this approach more as it stuff more PAT setup on its own type
> of calls, but:
>
> On Sat, Mar 12, 2016 at 12:55:44PM +0100, Borislav Petkov wrote:
> > diff --git a/arch/x86/kernel/cpu/mtrr/main.c
> > b/arch/x86/kernel/cpu/mtrr/main.c
> > index 10f8d4796240..5c442b4bd52a 100644
> > --- a/arch/x86/kernel/cpu/mtrr/main.c
> > +++ b/arch/x86/kernel/cpu/mtrr/main.c
> > @@ -759,8 +761,11 @@ void __init mtrr_bp_init(void)
> > Â }
> > Â }
> > Â
> > - if (!mtrr_enabled())
> > + if (!__mtrr_enabled) {
> > Â pr_info("MTRR: Disabled\n");
> > + pat_disable("PAT disabled by MTRR");
> > + pat_setup();
> > + }
> > Â}
>
> This hunk would break PAT on Xen.

Can you try the attached patches? ÂThey apply on top of my original patch-
set. ÂWith this change, PAT code generally supports Xen, and the PAT init
code in Xen is now removed. ÂIf they look OK, I will reorganize the patch
series.

Thanks,
-ToshiFrom: Toshi Kani <toshi.kani@xxxxxxx>

Add support of PAT emulation that matches with the PAT MSR.

---
arch/x86/mm/pat.c | 73 +++++++++++++++++++++++++++++++----------------------
1 file changed, 43 insertions(+), 30 deletions(-)

diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 1ff8aa9..565a478 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -40,7 +40,7 @@
static bool boot_cpu_done;

static int __read_mostly __pat_enabled = IS_ENABLED(CONFIG_X86_PAT);
-static void pat_disable_init(void);
+static void pat_emu_init(void);

void pat_disable(const char *reason)
{
@@ -52,7 +52,7 @@ void pat_disable(const char *reason)
__pat_enabled = 0;
pr_info("x86/PAT: %s\n", reason);

- pat_disable_init();
+ pat_emu_init();
}

static int __init nopat(char *str)
@@ -239,40 +239,53 @@ static void pat_ap_init(u64 pat)
wrmsrl(MSR_IA32_CR_PAT, pat);
}

-static void pat_disable_init(void)
+static void pat_emu_init(void)
{
- u64 pat;
- static int disable_init_done;
+ u64 pat = 0;
+ static int emu_init_done;

- if (disable_init_done)
+ if (emu_init_done)
return;

- /*
- * No PAT. Emulate the PAT table that corresponds to the two
- * cache bits, PWT (Write Through) and PCD (Cache Disable). This
- * setup is the same as the BIOS default setup when the system
- * has PAT but the "nopat" boot option has been specified. This
- * emulated PAT table is used when MSR_IA32_CR_PAT returns 0.
- *
- * PTE encoding:
- *
- * PCD
- * |PWT PAT
- * || slot
- * 00 0 WB : _PAGE_CACHE_MODE_WB
- * 01 1 WT : _PAGE_CACHE_MODE_WT
- * 10 2 UC-: _PAGE_CACHE_MODE_UC_MINUS
- * 11 3 UC : _PAGE_CACHE_MODE_UC
- *
- * NOTE: When WC or WP is used, it is redirected to UC- per
- * the default setup in __cachemode2pte_tbl[].
- */
- pat = PAT(0, WB) | PAT(1, WT) | PAT(2, UC_MINUS) | PAT(3, UC) |
- PAT(4, WB) | PAT(5, WT) | PAT(6, UC_MINUS) | PAT(7, UC);
+ if (cpu_has_pat) {
+ /*
+ * CPU supports PAT. Initialize the PAT table to match with
+ * the PAT MSR value. This setup is used by "nopat" boot
+ * option, or by virtual machine environments which do not
+ * support MTRRs but support PAT.
+ *
+ * If the MSR returns 0, it is considered invalid and emulate
+ * as No PAT.
+ */
+ rdmsrl(MSR_IA32_CR_PAT, pat);
+ }
+
+ if (!pat) {
+ /*
+ * No PAT. Emulate the PAT table that corresponds to the two
+ * cache bits, PWT (Write Through) and PCD (Cache Disable).
+ * This setup is also the same as the BIOS default setup.
+ *
+ * PTE encoding:
+ *
+ * PCD
+ * |PWT PAT
+ * || slot
+ * 00 0 WB : _PAGE_CACHE_MODE_WB
+ * 01 1 WT : _PAGE_CACHE_MODE_WT
+ * 10 2 UC-: _PAGE_CACHE_MODE_UC_MINUS
+ * 11 3 UC : _PAGE_CACHE_MODE_UC
+ *
+ * NOTE: When WC or WP is used, it is redirected to UC- per
+ * the default setup in __cachemode2pte_tbl[].
+ */
+ pat = PAT(0, WB) | PAT(1, WT) | PAT(2, UC_MINUS) | PAT(3, UC) |
+ PAT(4, WB) | PAT(5, WT) | PAT(6, UC_MINUS) | PAT(7, UC);
+ }

pat_init_cache_modes(pat);

- disable_init_done = 1;
+ emu_init_done = 1;
}

void pat_init(void)
@@ -281,7 +294,7 @@ void pat_init(void)
struct cpuinfo_x86 *c = &boot_cpu_data;

if (!pat_enabled()) {
- pat_disable_init();
+ pat_emu_init();
return;
}

From: Toshi Kani <toshi.kani@xxxxxxx>

Delete the PAT table initialization code from Xen as this case
is now supported by PAT.

---
arch/x86/include/asm/mtrr.h | 2 +-
arch/x86/kernel/cpu/mtrr/main.c | 4 ++--
arch/x86/xen/enlighten.c | 9 ---------
3 files changed, 3 insertions(+), 12 deletions(-)

diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h
index a965e74..77420c3 100644
--- a/arch/x86/include/asm/mtrr.h
+++ b/arch/x86/include/asm/mtrr.h
@@ -86,7 +86,7 @@ static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
}
static inline void mtrr_bp_init(void)
{
- pat_disable("PAT disabled by MTRR");
+ pat_disable("PAT emulation");
}

#define mtrr_ap_init() do {} while (0)
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index d9e91f1..e10fba4 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -767,10 +767,10 @@ void __init mtrr_bp_init(void)

/*
* PAT initialization relies on MTRR's rendezvous handler.
- * Disable PAT until the handler can initialize both features
+ * Emulate PAT until the handler can initialize both features
* independently.
*/
- pat_disable("PAT disabled by MTRR");
+ pat_disable("PAT emulation");
}
}

diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index d09e4c9..c883f11 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -74,7 +74,6 @@
#include <asm/mach_traps.h>
#include <asm/mwait.h>
#include <asm/pci_x86.h>
-#include <asm/pat.h>
#include <asm/cpu.h>

#ifdef CONFIG_ACPI
@@ -1510,7 +1509,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
{
struct physdev_set_iopl set_iopl;
unsigned long initrd_start = 0;
- u64 pat;
int rc;

if (!xen_start_info)
@@ -1617,13 +1615,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
xen_start_info->nr_pages);
xen_reserve_special_pages();

- /*
- * Modify the cache mode translation tables to match Xen's PAT
- * configuration.
- */
- rdmsrl(MSR_IA32_CR_PAT, pat);
- pat_init_cache_modes(pat);
-
/* keep using Xen gdt for now; no urgent need to change it */

#ifdef CONFIG_X86_32