>From 6f30ff305df4d36160641ad7232c39f58afc5c4a Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 28 Nov 2011 17:33:47 -0500 Subject: x86/paravirt/xen: Introduce pte_flags. We are providing a version of pte_flags where the processing under Xen goes couple of extra steps (if pat is enabled). The baremetal version looks quite identical to the pte_val one and the idea is to piggyback on the DEF_NATIVE/PTE_IDENT mechanism that pte_val uses for baremetal. Specifically we move the logical processing of "& PTE_FLAGS_MASK" out of the functions to minimize the amount of operations the paravirt operations have to do. This benefits us greatly as this way we don't have do that logical operations in the function: (native_pte_flags): pushq %rbp movq %rdi, %rax movabsq $-70368744173569, %rdx andq %rdx, %rax movq %rsp, %rbp popq %rbp ret but instead the paravirt function ends up being: pushq %rbp movq %rdi, %rax movq %rsp, %rbp popq %rbp ret and the logical "and" operation is done outside the call. This means that the only real operation that native_pte_flags is "movq %rdi, %rax" we can take advantage of the PTE_IDENT functionality introduced in patch: "x86/paravirt/xen: Optimize pte_flags by marking it as paravirt_ident_[32|64] type." Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/include/asm/paravirt.h | 5 +++++ arch/x86/include/asm/paravirt_types.h | 1 + arch/x86/include/asm/pgtable.h | 1 + arch/x86/include/asm/pgtable_types.h | 4 ++-- arch/x86/kernel/paravirt.c | 1 + arch/x86/xen/mmu.c | 13 +++++++++++++ 6 files changed, 23 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index a7d2db9..6533409 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -462,6 +462,11 @@ static inline void pmd_update_defer(struct mm_struct *mm, unsigned long addr, PVOP_VCALL3(pv_mmu_ops.pmd_update_defer, mm, addr, pmdp); } +static inline pteval_t pte_flags(pte_t pte) +{ + return pv_mmu_ops.pte_flags(pte) & PTE_FLAGS_MASK; +} + static inline pte_t __pte(pteval_t val) { pteval_t ret; diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index 8e8b9a4..86bce9d 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -288,6 +288,7 @@ struct pv_mmu_ops { void (*ptep_modify_prot_commit)(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte); + pteval_t (*pte_flags)(pte_t pte); struct paravirt_callee_save pte_val; struct paravirt_callee_save make_pte; diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 18601c8..eebf625 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -76,6 +76,7 @@ extern struct mm_struct *pgd_page_get_mm(struct page *page); #define __pmd(x) native_make_pmd(x) #endif +#define pte_flags(x) (native_pte_val(x) & PTE_FLAGS_MASK) #define pte_val(x) native_pte_val(x) #define __pte(x) native_make_pte(x) diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 013286a..4c957e8 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -270,9 +270,9 @@ static inline pteval_t native_pte_val(pte_t pte) return pte.pte; } -static inline pteval_t pte_flags(pte_t pte) +static inline pteval_t native_pte_flags(pte_t pte) { - return native_pte_val(pte) & PTE_FLAGS_MASK; + return pte.pte; } #define pgprot_val(x) ((x).pgprot) diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index d90272e..4780367 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -462,6 +462,7 @@ struct pv_mmu_ops pv_mmu_ops = { #endif #endif /* PAGETABLE_LEVELS >= 3 */ + .pte_flags = native_pte_flags, .pte_val = PTE_IDENT, .pgd_val = PTE_IDENT, diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 87f6673..5b79048 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -412,6 +412,16 @@ static pteval_t iomap_pte(pteval_t val) return val; } +static pteval_t xen_pte_flags(pte_t pte) +{ + pteval_t pteval = pte.pte; + + /* If this is a WC pte, convert back from Xen WC to Linux WC */ + if ((pteval & (_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)) == _PAGE_PAT) + pteval = (pteval & ~_PAGE_PAT) | _PAGE_PWT; + return pteval; +} + static pteval_t xen_pte_val(pte_t pte) { pteval_t pteval = pte.pte; @@ -1975,6 +1985,8 @@ static void __init xen_post_allocator_init(void) pv_mmu_ops.release_pud = xen_release_pud; #endif + if (!pat_enabled) + pv_mmu_ops.pte_flags = native_pte_flags; #ifdef CONFIG_X86_64 SetPagePinned(virt_to_page(level3_user_vsyscall)); #endif @@ -2023,6 +2035,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = { .ptep_modify_prot_start = __ptep_modify_prot_start, .ptep_modify_prot_commit = __ptep_modify_prot_commit, + .pte_flags = xen_pte_flags, .pte_val = PV_CALLEE_SAVE(xen_pte_val), .pgd_val = PV_CALLEE_SAVE(xen_pgd_val), -- 1.7.7.3