From: Toshi Kani 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; }