From 84f8baf80791b3432808c59fdb46b65b98f8bce0 Mon Sep 17 00:00:00 2001 From: Tim Deegan Date: Thu, 8 Sep 2011 15:13:06 +0100 Subject: x86/mm: adjust paging interface to return superpage sizes to the caller of paging_ga_to_gfn_cr3() Signed-off-by: Christoph Egger Signed-off-by: Tim Deegan Committed-by: Tim Deegan --- xen/arch/x86/mm/hap/guest_walk.c | 7 +++++-- xen/arch/x86/mm/hap/hap.c | 4 +++- xen/arch/x86/mm/hap/nested_hap.c | 2 +- xen/arch/x86/mm/hap/private.h | 6 +++--- xen/arch/x86/mm/p2m.c | 2 +- xen/include/asm-x86/guest_pt.h | 18 ++++++++++++++++++ xen/include/asm-x86/paging.h | 14 +++++++++----- 7 files changed, 40 insertions(+), 13 deletions(-) diff --git a/xen/arch/x86/mm/hap/guest_walk.c b/xen/arch/x86/mm/hap/guest_walk.c index 24ff59c196..78ae032195 100644 --- a/xen/arch/x86/mm/hap/guest_walk.c +++ b/xen/arch/x86/mm/hap/guest_walk.c @@ -43,12 +43,12 @@ unsigned long hap_gva_to_gfn(GUEST_PAGING_LEVELS)( struct vcpu *v, struct p2m_domain *p2m, unsigned long gva, uint32_t *pfec) { unsigned long cr3 = v->arch.hvm_vcpu.guest_cr[3]; - return hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)(v, p2m, cr3, gva, pfec); + return hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)(v, p2m, cr3, gva, pfec, NULL); } unsigned long hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)( struct vcpu *v, struct p2m_domain *p2m, unsigned long cr3, - paddr_t ga, uint32_t *pfec) + paddr_t ga, uint32_t *pfec, unsigned int *page_order) { uint32_t missing; mfn_t top_mfn; @@ -107,6 +107,9 @@ unsigned long hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)( return INVALID_GFN; } + if ( page_order ) + *page_order = guest_walk_to_page_order(&gw); + return gfn_x(gfn); } diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c index f90511ef04..9f6b990c2a 100644 --- a/xen/arch/x86/mm/hap/hap.c +++ b/xen/arch/x86/mm/hap/hap.c @@ -897,8 +897,10 @@ static unsigned long hap_gva_to_gfn_real_mode( static unsigned long hap_p2m_ga_to_gfn_real_mode( struct vcpu *v, struct p2m_domain *p2m, unsigned long cr3, - paddr_t ga, uint32_t *pfec) + paddr_t ga, uint32_t *pfec, unsigned int *page_order) { + if ( page_order ) + *page_order = PAGE_ORDER_4K; return (ga >> PAGE_SHIFT); } diff --git a/xen/arch/x86/mm/hap/nested_hap.c b/xen/arch/x86/mm/hap/nested_hap.c index 2bab9e71f2..d2c833f0f9 100644 --- a/xen/arch/x86/mm/hap/nested_hap.c +++ b/xen/arch/x86/mm/hap/nested_hap.c @@ -162,7 +162,7 @@ nestedhap_walk_L1_p2m(struct vcpu *v, paddr_t L2_gpa, paddr_t *L1_gpa) nested_cr3 = nhvm_vcpu_hostcr3(v); /* Walk the guest-supplied NPT table, just as if it were a pagetable */ - gfn = paging_ga_to_gfn_cr3(v, nested_cr3, L2_gpa, &pfec); + gfn = paging_ga_to_gfn_cr3(v, nested_cr3, L2_gpa, &pfec, NULL); if ( gfn == INVALID_GFN ) return NESTEDHVM_PAGEFAULT_INJECT; diff --git a/xen/arch/x86/mm/hap/private.h b/xen/arch/x86/mm/hap/private.h index 6dcd128838..b5c0b6aafd 100644 --- a/xen/arch/x86/mm/hap/private.h +++ b/xen/arch/x86/mm/hap/private.h @@ -40,12 +40,12 @@ unsigned long hap_gva_to_gfn_4_levels(struct vcpu *v, unsigned long hap_p2m_ga_to_gfn_2_levels(struct vcpu *v, struct p2m_domain *p2m, unsigned long cr3, - paddr_t ga, uint32_t *pfec); + paddr_t ga, uint32_t *pfec, unsigned int *page_order); unsigned long hap_p2m_ga_to_gfn_3_levels(struct vcpu *v, struct p2m_domain *p2m, unsigned long cr3, - paddr_t ga, uint32_t *pfec); + paddr_t ga, uint32_t *pfec, unsigned int *page_order); unsigned long hap_p2m_ga_to_gfn_4_levels(struct vcpu *v, struct p2m_domain *p2m, unsigned long cr3, - paddr_t ga, uint32_t *pfec); + paddr_t ga, uint32_t *pfec, unsigned int *page_order); #endif /* __HAP_PRIVATE_H__ */ diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index c3c8c87c37..c6cb98b2e5 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -1206,7 +1206,7 @@ unsigned long paging_gva_to_gfn(struct vcpu *v, /* translate l2 guest gfn into l1 guest gfn */ return hostmode->p2m_ga_to_gfn(v, hostp2m, ncr3, - gfn << PAGE_SHIFT, pfec); + gfn << PAGE_SHIFT, pfec, NULL); } return hostmode->gva_to_gfn(v, hostp2m, va, pfec); diff --git a/xen/include/asm-x86/guest_pt.h b/xen/include/asm-x86/guest_pt.h index e3dd07a8d7..9a3b949bf1 100644 --- a/xen/include/asm-x86/guest_pt.h +++ b/xen/include/asm-x86/guest_pt.h @@ -272,6 +272,24 @@ guest_walk_to_gpa(walk_t *gw) return guest_l1e_get_paddr(gw->l1e) + (gw->va & ~PAGE_MASK); } +/* Given a walk_t from a successful walk, return the page-order of the + * page or superpage that the virtual address is in. */ +static inline unsigned int +guest_walk_to_page_order(walk_t *gw) +{ + /* This is only valid for successful walks - otherwise the + * PSE bits might be invalid. */ + ASSERT(guest_l1e_get_flags(gw->l1e) & _PAGE_PRESENT); +#if GUEST_PAGING_LEVELS >= 3 + if ( guest_l3e_get_flags(gw->l3e) & _PAGE_PSE ) + return GUEST_L3_PAGETABLE_SHIFT - PAGE_SHIFT; +#endif + if ( guest_l2e_get_flags(gw->l2e) & _PAGE_PSE ) + return GUEST_L2_PAGETABLE_SHIFT - PAGE_SHIFT; + return GUEST_L1_PAGETABLE_SHIFT - PAGE_SHIFT; +} + + /* Walk the guest pagetables, after the manner of a hardware walker. * * Inputs: a vcpu, a virtual address, a walk_t to fill, a diff --git a/xen/include/asm-x86/paging.h b/xen/include/asm-x86/paging.h index 0a32fe2b4e..c432a973ed 100644 --- a/xen/include/asm-x86/paging.h +++ b/xen/include/asm-x86/paging.h @@ -115,7 +115,8 @@ struct paging_mode { unsigned long (*p2m_ga_to_gfn )(struct vcpu *v, struct p2m_domain *p2m, unsigned long cr3, - paddr_t ga, uint32_t *pfec); + paddr_t ga, uint32_t *pfec, + unsigned int *page_order); void (*update_cr3 )(struct vcpu *v, int do_locking); void (*update_paging_modes )(struct vcpu *v); void (*write_p2m_entry )(struct vcpu *v, unsigned long gfn, @@ -270,15 +271,18 @@ unsigned long paging_gva_to_gfn(struct vcpu *v, * to by nested HAP code, to walk the guest-supplied NPT tables as if * they were pagetables. * Use 'paddr_t' for the guest address so it won't overflow when - * guest or nested guest is in 32bit PAE mode. - */ + * l1 or l2 guest is in 32bit PAE mode. + * If the GFN returned is not INVALID_GFN, *page_order gives + * the size of the superpage (if any) it was found in. */ static inline unsigned long paging_ga_to_gfn_cr3(struct vcpu *v, unsigned long cr3, paddr_t ga, - uint32_t *pfec) + uint32_t *pfec, + unsigned int *page_order) { struct p2m_domain *p2m = v->domain->arch.p2m; - return paging_get_hostmode(v)->p2m_ga_to_gfn(v, p2m, cr3, ga, pfec); + return paging_get_hostmode(v)->p2m_ga_to_gfn(v, p2m, cr3, ga, pfec, + page_order); } /* Update all the things that are derived from the guest's CR3. -- cgit v1.2.3