diff options
author | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-03-30 14:47:40 -0400 |
---|---|---|
committer | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-10-22 15:57:31 -0400 |
commit | 41f2e4771a4f1ba26c35438daf32917b9ef7858d (patch) | |
tree | 94a0af183907bc2f646bcde12072c960da987f65 /arch/x86/xen | |
parent | 2f7acb208523a3bf5f1830f01c29f7feda045169 (diff) |
xen: add support for PAT
Convert Linux PAT entries into Xen ones when constructing ptes. Linux
doesn't use _PAGE_PAT for ptes, so the only difference in the first 4
entries is that Linux uses _PAGE_PWT for WC, whereas Xen (and default)
use it for WT.
xen_pte_val does the inverse conversion.
We hard-code assumptions about Linux's current PAT layout, but a
warning on the wrmsr to MSR_IA32_CR_PAT should point out any problems.
If necessary we could go to a more general table-based conversion between
Linux and Xen PAT entries.
hugetlbfs poses a problem at the moment, the x86 architecture uses the
same flag for _PAGE_PAT and _PAGE_PSE, which changes meaning depending
on which pagetable level we're using. At the moment this should be OK
so long as nobody tries to do a pte_val on a hugetlbfs pte.
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Diffstat (limited to 'arch/x86/xen')
-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); |