diff options
| -rw-r--r-- | arch/x86/xen/enlighten.c | 5 | ||||
| -rw-r--r-- | arch/x86/xen/mmu.c | 53 | ||||
| -rw-r--r-- | arch/x86/xen/xen-ops.h | 2 |
3 files changed, 57 insertions, 3 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index d8873014b5ed..b860e576ed0c 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
| @@ -829,6 +829,11 @@ static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) | |||
| 829 | Xen console noise. */ | 829 | Xen console noise. */ |
| 830 | break; | 830 | break; |
| 831 | 831 | ||
| 832 | case MSR_IA32_CR_PAT: | ||
| 833 | if (smp_processor_id() == 0) | ||
| 834 | xen_set_pat(((u64)high << 32) | low); | ||
| 835 | break; | ||
| 836 | |||
| 832 | default: | 837 | default: |
| 833 | ret = native_write_msr_safe(msr, low, high); | 838 | ret = native_write_msr_safe(msr, low, high); |
| 834 | } | 839 | } |
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index b2371671b11c..67b41017f7b8 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
| @@ -55,6 +55,7 @@ | |||
| 55 | #include <asm/e820.h> | 55 | #include <asm/e820.h> |
| 56 | #include <asm/linkage.h> | 56 | #include <asm/linkage.h> |
| 57 | #include <asm/page.h> | 57 | #include <asm/page.h> |
| 58 | #include <asm/pat.h> | ||
| 58 | 59 | ||
| 59 | #include <asm/xen/hypercall.h> | 60 | #include <asm/xen/hypercall.h> |
| 60 | #include <asm/xen/hypervisor.h> | 61 | #include <asm/xen/hypervisor.h> |
| @@ -780,10 +781,18 @@ static pteval_t iomap_pte(pteval_t val) | |||
| 780 | 781 | ||
| 781 | pteval_t xen_pte_val(pte_t pte) | 782 | pteval_t xen_pte_val(pte_t pte) |
| 782 | { | 783 | { |
| 783 | if (xen_initial_domain() && (pte.pte & _PAGE_IOMAP)) | 784 | pteval_t pteval = pte.pte; |
| 784 | return pte.pte; | ||
| 785 | 785 | ||
| 786 | return pte_mfn_to_pfn(pte.pte); | 786 | /* If this is a WC pte, convert back from Xen WC to Linux WC */ |
| 787 | if ((pteval & (_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)) == _PAGE_PAT) { | ||
| 788 | WARN_ON(!pat_enabled); | ||
| 789 | pteval = (pteval & ~_PAGE_PAT) | _PAGE_PWT; | ||
| 790 | } | ||
| 791 | |||
| 792 | if (xen_initial_domain() && (pteval & _PAGE_IOMAP)) | ||
| 793 | return pteval; | ||
| 794 | |||
| 795 | return pte_mfn_to_pfn(pteval); | ||
| 787 | } | 796 | } |
| 788 | PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val); | 797 | PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val); |
| 789 | 798 | ||
| @@ -793,10 +802,48 @@ pgdval_t xen_pgd_val(pgd_t pgd) | |||
| 793 | } | 802 | } |
| 794 | PV_CALLEE_SAVE_REGS_THUNK(xen_pgd_val); | 803 | PV_CALLEE_SAVE_REGS_THUNK(xen_pgd_val); |
| 795 | 804 | ||
| 805 | /* | ||
| 806 | * Xen's PAT setup is part of its ABI, though I assume entries 6 & 7 | ||
| 807 | * are reserved for now, to correspond to the Intel-reserved PAT | ||
| 808 | * types. | ||
| 809 | * | ||
| 810 | * We expect Linux's PAT set as follows: | ||
| 811 | * | ||
| 812 | * Idx PTE flags Linux Xen Default | ||
| 813 | * 0 WB WB WB | ||
| 814 | * 1 PWT WC WT WT | ||
| 815 | * 2 PCD UC- UC- UC- | ||
| 816 | * 3 PCD PWT UC UC UC | ||
| 817 | * 4 PAT WB WC WB | ||
| 818 | * 5 PAT PWT WC WP WT | ||
| 819 | * 6 PAT PCD UC- UC UC- | ||
| 820 | * 7 PAT PCD PWT UC UC UC | ||
| 821 | */ | ||
| 822 | |||
| 823 | void xen_set_pat(u64 pat) | ||
| 824 | { | ||
| 825 | /* We expect Linux to use a PAT setting of | ||
| 826 | * UC UC- WC WB (ignoring the PAT flag) */ | ||
| 827 | WARN_ON(pat != 0x0007010600070106ull); | ||
| 828 | } | ||
| 829 | |||
| 796 | pte_t xen_make_pte(pteval_t pte) | 830 | pte_t xen_make_pte(pteval_t pte) |
| 797 | { | 831 | { |
| 798 | phys_addr_t addr = (pte & PTE_PFN_MASK); | 832 | phys_addr_t addr = (pte & PTE_PFN_MASK); |
| 799 | 833 | ||
| 834 | /* If Linux is trying to set a WC pte, then map to the Xen WC. | ||
| 835 | * If _PAGE_PAT is set, then it probably means it is really | ||
| 836 | * _PAGE_PSE, so avoid fiddling with the PAT mapping and hope | ||
| 837 | * things work out OK... | ||
| 838 | * | ||
| 839 | * (We should never see kernel mappings with _PAGE_PSE set, | ||
| 840 | * but we could see hugetlbfs mappings, I think.). | ||
| 841 | */ | ||
| 842 | if (pat_enabled && !WARN_ON(pte & _PAGE_PAT)) { | ||
| 843 | if ((pte & (_PAGE_PCD | _PAGE_PWT)) == _PAGE_PWT) | ||
| 844 | pte = (pte & ~(_PAGE_PCD | _PAGE_PWT)) | _PAGE_PAT; | ||
| 845 | } | ||
| 846 | |||
| 800 | /* | 847 | /* |
| 801 | * Unprivileged domains are allowed to do IOMAPpings for | 848 | * Unprivileged domains are allowed to do IOMAPpings for |
| 802 | * PCI passthrough, but not map ISA space. The ISA | 849 | * PCI passthrough, but not map ISA space. The ISA |
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index d505e98e03f8..64044747348e 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h | |||
| @@ -32,6 +32,8 @@ void xen_ident_map_ISA(void); | |||
| 32 | void xen_reserve_top(void); | 32 | void xen_reserve_top(void); |
| 33 | extern unsigned long xen_max_p2m_pfn; | 33 | extern unsigned long xen_max_p2m_pfn; |
| 34 | 34 | ||
| 35 | void xen_set_pat(u64); | ||
| 36 | |||
| 35 | char * __init xen_memory_setup(void); | 37 | char * __init xen_memory_setup(void); |
| 36 | void __init xen_arch_setup(void); | 38 | void __init xen_arch_setup(void); |
| 37 | void __init xen_init_IRQ(void); | 39 | void __init xen_init_IRQ(void); |
