nestedhvm: fix write access fault on ro mapping
PATCH 1/1 nestedhvm: fix write access fault on ro mapping
Fix write access fault when host npt is mapped read-only. In this case let the host handle the #NPF.
Apply host p2mt to hap-on-hap pagetable entry. This fixes the l2 guest graphic display refresh problem.
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
xen/arch/x86/hvm/hvm.c +2 -0
@@ -1291,6 +1291,8 @@ int hvm_hap_nested_page_fault(unsigned lif ( !handle_mmio () )hvm_inject_hw_exception (TRAP_gp_fault,0 );return 1 ; +case NESTEDHVM_PAGEFAULT_READONLY : +break ; } }
xen/arch/x86/mm/hap/nested_hap.c +18 -8
@@ -141,23 +141,28 @@ nestedhap_fix_p2m(struct vcpu *v, struct*/ static int nestedhap_walk_L0_p2m (struct p2m_domain *p2m,paddr_t L1_gpa,paddr_t *L0_gpa, -unsigned int *page_order) +p2m_type_t *p2mt, +unsigned int *page_order, +bool_t access_r,bool_t access_w,bool_t access_x) {mfn_t mfn; -p2m_type_t p2mt;p2m_access_t p2ma;int rc;/* walk L0 P2M table */ - mfn =get_gfn_type_access (p2m, L1_gpa >>PAGE_SHIFT , &p2mt, &p2ma, + mfn =get_gfn_type_access (p2m, L1_gpa >>PAGE_SHIFT , p2mt, &p2ma,0 , page_order); rc =NESTEDHVM_PAGEFAULT_MMIO ; -if (p2m_is_mmio (p2mt) ) +if (p2m_is_mmio (*p2mt) ) + goto out; + + rc =NESTEDHVM_PAGEFAULT_READONLY ; +if ( access_w &&p2m_is_readonly (*p2mt) ) goto out; rc =NESTEDHVM_PAGEFAULT_ERROR ; -if (p2m_is_paging (p2mt) ||p2m_is_shared (p2mt) || !p2m_is_ram (p2mt) ) +if (p2m_is_paging (*p2mt) ||p2m_is_shared (*p2mt) || !p2m_is_ram (*p2mt) ) goto out; rc =NESTEDHVM_PAGEFAULT_ERROR ;
@@ -215,6 +220,7 @@ nestedhvm_hap_nested_page_fault(struct vstruct domain *d = v->domain;struct p2m_domain *p2m, *nested_p2m;unsigned int page_order_21, page_order_10, page_order_20; +p2m_type_t p2mt_10; p2m =p2m_get_hostp2m (d);/* L0 p2m */ nested_p2m =p2m_get_nestedp2m (v,nhvm_vcpu_hostcr3 (v));
@@ -237,7 +243,9 @@ nestedhvm_hap_nested_page_fault(struct v }/* ==> we have to walk L0 P2M */ - rv =nestedhap_walk_L0_p2m (p2m, L1_gpa, &L0_gpa, &page_order_10); + rv =nestedhap_walk_L0_p2m (p2m, L1_gpa, &L0_gpa, + &p2mt_10, &page_order_10, + access_r, access_w, access_x);/* let upper level caller to handle these two cases */ switch (rv) {
@@ -249,6 +257,8 @@ nestedhvm_hap_nested_page_fault(struct vbreak ;case NESTEDHVM_PAGEFAULT_MMIO :return rv; +case NESTEDHVM_PAGEFAULT_READONLY : +return rv;default :BUG ();break ;
@@ -258,8 +268,8 @@ nestedhvm_hap_nested_page_fault(struct v/* fix p2m_get_pagetable(nested_p2m) */ nestedhap_fix_p2m (v, nested_p2m, L2_gpa, L0_gpa, page_order_20, - p2m_ram_rw, - p2m_access_rwx/* FIXME: Should use same permission as l1 guest */ ); + p2mt_10, + p2m_access_rwx/* FIXME: Should use minimum permission. */ );return NESTEDHVM_PAGEFAULT_DONE ; }
xen/include/asm-x86/hvm/nestedhvm.h +5 -4
@@ -47,10 +47,11 @@ bool_t nestedhvm_vcpu_in_guestmode(strucvcpu_nestedhvm (v).nv_guestmode =0 /* Nested paging */ -#define NESTEDHVM_PAGEFAULT_DONE 0 -#define NESTEDHVM_PAGEFAULT_INJECT 1 -#define NESTEDHVM_PAGEFAULT_ERROR 2 -#define NESTEDHVM_PAGEFAULT_MMIO 3 +#define NESTEDHVM_PAGEFAULT_DONE 0 +#define NESTEDHVM_PAGEFAULT_INJECT 1 +#define NESTEDHVM_PAGEFAULT_ERROR 2 +#define NESTEDHVM_PAGEFAULT_MMIO 3 +#define NESTEDHVM_PAGEFAULT_READONLY 4int nestedhvm_hap_nested_page_fault (struct vcpu *v,paddr_t L2_gpa,bool_t access_r,bool_t access_w,bool_t access_x);
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel
Quoted 10 lines · Christoph Egger
Fix write access fault when host npt is mapped read-only. In this case let the host handle the #NPF.
Apply host p2mt to hap-on-hap pagetable entry. This fixes the l2 guest graphic display refresh problem.diff -r
ae0e96e156f3xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/hvm.c int hvm_hap_nested_page_fault(unsigned l · line 1295
Quoted 5 lines
xen/arch/x86/hvm/hvm.c +2
-0@@ -1291,6 +1291,8 @@ int hvm_hap_nested_page_fault(unsigned lif ( !handle_mmio () )hvm_inject_hw_exception (TRAP_gp_fault,0 );return 1 ; +case NESTEDHVM_PAGEFAULT_READONLY : +break ;
Don't we have to translate the faulting PA into an L1 address before letting the rest of this fault handler run? It explicitly operates on the hostp2m.
If we do that, we should probably do it for NESTEDHVM_PAGEFAULT_ERROR, rather than special-casing READONLY. That way any other automatically-fixed types (like the p2m_access magic) will be covered too.
Cheers,
Tim.
Quoted 21 lines · Tim Deegan
Quoted 10 lines · Christoph Egger
Fix write access fault when host npt is mapped read-only. In this case let the host handle the #NPF.
Apply host p2mt to hap-on-hap pagetable entry. This fixes the l2 guest graphic display refresh problem.diff -r
ae0e96e156f3xen/arch/x86/hvm/hvm.cxen/arch/x86/hvm/hvm.c int hvm_hap_nested_page_fault(unsigned l · line 1295
Quoted 5 lines
xen/arch/x86/hvm/hvm.c +2
-0@@ -1291,6 +1291,8 @@ int hvm_hap_nested_page_fault(unsigned lif ( !handle_mmio () )hvm_inject_hw_exception (TRAP_gp_fault,0 );return 1 ; +case NESTEDHVM_PAGEFAULT_READONLY : +break ;Don't we have to translate the faulting PA into an L1 address before letting the rest of this fault handler run? It explicitly operates on the hostp2m.
Quoted 4 lines
If we do that, we should probably do it for
NESTEDHVM_PAGEFAULT_ERROR, rather than special-casing READONLY. That way any other automatically-fixed types (like thep2m_accessmagic) will be covered too.
How do you differentiate if the error happened from walking l1 npt or host npt ?
In the first case it isn't possible to provide l1 address.
Christoph
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
Quoted 11 lines · Christoph Egger
Quoted 11 lines
xen/arch/x86/hvm/hvm.c int hvm_hap_nested_page_fault(unsigned l · line 1295
Quoted 6 lines
xen/arch/x86/hvm/hvm.c +2
-0@@ -1291,6 +1291,8 @@ int hvm_hap_nested_page_fault(unsigned lif ( !handle_mmio () )hvm_inject_hw_exception (TRAP_gp_fault,0 );return 1 ; +case NESTEDHVM_PAGEFAULT_READONLY : +break ;Don't we have to translate the faulting PA into an L1 address before letting the rest of this fault handler run? It explicitly operates on the hostp2m.
Quoted 8 lines
Quoted 4 lines
If we do that, we should probably do it for
NESTEDHVM_PAGEFAULT_ERROR, rather than special-casing READONLY. That way any other automatically-fixed types (like thep2m_accessmagic) will be covered too.How do you differentiate if the error happened from walking l1 npt or host npt ?
In the first case it isn't possible to provide l1 address.
It must be _possible_; after all we managed to detect the error. :) In any case it's definitely wrong to carry on with this handler with the wrong address in hand. So I wonder why this patch actually works for you. Does replacing the 'break' above with 'return 1' also fix the problem?
In the short term, do you only care about pages that are read-only for log-dirty tracking? For the L1 walk, that should be handled by the PT walker's own calls to paging_mark_dirty(), and the nested-p2m handler could potentially take care of the other case by calling paging_mark_dirty() (for writes!) before calling nestedhap_walk_L0_p2m().
Tim.
Quoted 21 lines · Tim Deegan
Quoted 11 lines · Christoph Egger
Quoted 11 lines
Review int hvm_hap_nested_page_fault(unsigned l · line 1295
Quoted 6 lines
(quoted diff) +2
-0@@ -1291,6 +1291,8 @@ int hvm_hap_nested_page_fault(unsigned l if ( !handle_mmio() ) hvm_inject_hw_exception(TRAP_gp_fault, 0); return 1; + case NESTEDHVM_PAGEFAULT_READONLY: + break;Don't we have to translate the faulting PA into an L1 address before letting the rest of this fault handler run? It explicitly operates on the hostp2m.
Quoted 8 lines
Quoted 4 lines
If we do that, we should probably do it for
NESTEDHVM_PAGEFAULT_ERROR, rather than special-casing READONLY. That way any other automatically-fixed types (like thep2m_accessmagic) will be covered too.How do you differentiate if the error happened from walking l1 npt or host npt ?
In the first case it isn't possible to provide l1 address.
Quoted 5 lines
It must be _possible_; after all we managed to detect the error. :) In any case it's definitely wrong to carry on with this handler with the wrong address in hand. So I wonder why this patch actually works for you. Does replacing the 'break' above with 'return 1' also fix the problem?
No. Two things have to happen:
1. Calling paging_mark_dirty() and
2. using the same p2mt from the hostp2m in the nestedp2m.
Quoted 7 lines
In the short term, do you only care about pages that are read-only for log-dirty tracking? For the L1 walk, that should be handled by the PT walker's own calls to
paging_mark_dirty(), and the nested-p2m handler could potentially take care of the other case by callingpaging_mark_dirty()(for writes!) before callingnestedhap_walk_L0_p2m().
Ok, I consider this as a performance improvement rather a bugfix.
New version is attached.
Christoph
Signature · 6 lines
---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632
xen/arch/x86/hvm/hvm.c +8 -2
@@ -1278,12 +1278,14 @@ int hvm_hap_nested_page_fault(unsigned l* into l1 guest if not fixable. The algorithm is * the same as for shadow paging. */ - rv =nestedhvm_hap_nested_page_fault (v, gpa, + rv =nestedhvm_hap_nested_page_fault (v, &gpa, access_r, access_w, access_x);switch (rv) {case NESTEDHVM_PAGEFAULT_DONE :return 1 ; -case NESTEDHVM_PAGEFAULT_ERROR : +case NESTEDHVM_PAGEFAULT_L1_ERROR : +/* An error occured while translating gpa from +* l2 guest address to l1 guest address. */ return 0 ;case NESTEDHVM_PAGEFAULT_INJECT :return -1 ;
@@ -1291,6 +1293,10 @@ int hvm_hap_nested_page_fault(unsigned lif ( !handle_mmio () )hvm_inject_hw_exception (TRAP_gp_fault,0 );return 1 ; +case NESTEDHVM_PAGEFAULT_L0_ERROR : +/* gpa is now translated to l1 guest address, update gfn. */ + gfn = gpa >>PAGE_SHIFT ; +break ; } }
xen/arch/x86/mm/hap/nested_hap.c +22 -15
@@ -141,26 +141,29 @@ nestedhap_fix_p2m(struct vcpu *v, struct*/ static int nestedhap_walk_L0_p2m (struct p2m_domain *p2m,paddr_t L1_gpa,paddr_t *L0_gpa, -unsigned int *page_order) +p2m_type_t *p2mt, +unsigned int *page_order, +bool_t access_r,bool_t access_w,bool_t access_x) {mfn_t mfn; -p2m_type_t p2mt;p2m_access_t p2ma;int rc;/* walk L0 P2M table */ - mfn =get_gfn_type_access (p2m, L1_gpa >>PAGE_SHIFT , &p2mt, &p2ma, + mfn =get_gfn_type_access (p2m, L1_gpa >>PAGE_SHIFT , p2mt, &p2ma,0 , page_order); rc =NESTEDHVM_PAGEFAULT_MMIO ; -if (p2m_is_mmio (p2mt) ) +if (p2m_is_mmio (*p2mt) ) goto out; - rc =NESTEDHVM_PAGEFAULT_ERROR ; -if (p2m_is_paging (p2mt) ||p2m_is_shared (p2mt) || !p2m_is_ram (p2mt) ) + rc =NESTEDHVM_PAGEFAULT_L0_ERROR ; +if ( access_w &&p2m_is_readonly (*p2mt) ) goto out; - rc =NESTEDHVM_PAGEFAULT_ERROR ; +if (p2m_is_paging (*p2mt) ||p2m_is_shared (*p2mt) || !p2m_is_ram (*p2mt) ) + goto out; +if ( !mfn_valid (mfn) ) goto out;
@@ -207,7 +210,7 @@ nestedhap_walk_L1_p2m(struct vcpu *v, pa* Returns: */ int -nestedhvm_hap_nested_page_fault (struct vcpu *v,paddr_t L2_gpa, +nestedhvm_hap_nested_page_fault (struct vcpu *v,paddr_t *L2_gpa,bool_t access_r,bool_t access_w,bool_t access_x) {int rv;
@@ -215,19 +218,20 @@ nestedhvm_hap_nested_page_fault(struct vstruct domain *d = v->domain;struct p2m_domain *p2m, *nested_p2m;unsigned int page_order_21, page_order_10, page_order_20; +p2m_type_t p2mt_10; p2m =p2m_get_hostp2m (d);/* L0 p2m */ nested_p2m =p2m_get_nestedp2m (v,nhvm_vcpu_hostcr3 (v));/* walk the L1 P2M table */ - rv =nestedhap_walk_L1_p2m (v, L2_gpa, &L1_gpa, &page_order_21, + rv =nestedhap_walk_L1_p2m (v, *L2_gpa, &L1_gpa, &page_order_21, access_r, access_w, access_x);/* let caller to handle these two cases */ switch (rv) {case NESTEDHVM_PAGEFAULT_INJECT :return rv; -case NESTEDHVM_PAGEFAULT_ERROR : +case NESTEDHVM_PAGEFAULT_L1_ERROR :return rv;case NESTEDHVM_PAGEFAULT_DONE :break ;
@@ -237,13 +241,16 @@ nestedhvm_hap_nested_page_fault(struct v }/* ==> we have to walk L0 P2M */ - rv =nestedhap_walk_L0_p2m (p2m, L1_gpa, &L0_gpa, &page_order_10); + rv =nestedhap_walk_L0_p2m (p2m, L1_gpa, &L0_gpa, + &p2mt_10, &page_order_10, + access_r, access_w, access_x);/* let upper level caller to handle these two cases */ switch (rv) {case NESTEDHVM_PAGEFAULT_INJECT :return rv; -case NESTEDHVM_PAGEFAULT_ERROR : +case NESTEDHVM_PAGEFAULT_L0_ERROR : + *L2_gpa = L1_gpa;return rv;case NESTEDHVM_PAGEFAULT_DONE :break ;
@@ -257,9 +264,9 @@ nestedhvm_hap_nested_page_fault(struct v page_order_20 =min (page_order_21, page_order_10);/* fix p2m_get_pagetable(nested_p2m) */ -nestedhap_fix_p2m (v, nested_p2m, L2_gpa, L0_gpa, page_order_20, - p2m_ram_rw, - p2m_access_rwx/* FIXME: Should use same permission as l1 guest */ ); +nestedhap_fix_p2m (v, nested_p2m, *L2_gpa, L0_gpa, page_order_20, + p2mt_10, + p2m_access_rwx/* FIXME: Should use minimum permission. */ );return NESTEDHVM_PAGEFAULT_DONE ; }
xen/include/asm-x86/hvm/nestedhvm.h +6 -5
@@ -47,11 +47,12 @@ bool_t nestedhvm_vcpu_in_guestmode(strucvcpu_nestedhvm (v).nv_guestmode =0 /* Nested paging */ -#define NESTEDHVM_PAGEFAULT_DONE 0 -#define NESTEDHVM_PAGEFAULT_INJECT 1 -#define NESTEDHVM_PAGEFAULT_ERROR 2 -#define NESTEDHVM_PAGEFAULT_MMIO 3 -int nestedhvm_hap_nested_page_fault (struct vcpu *v,paddr_t L2_gpa, +#define NESTEDHVM_PAGEFAULT_DONE 0 +#define NESTEDHVM_PAGEFAULT_INJECT 1 +#define NESTEDHVM_PAGEFAULT_L1_ERROR 2 +#define NESTEDHVM_PAGEFAULT_L0_ERROR 3 +#define NESTEDHVM_PAGEFAULT_MMIO 4 +int nestedhvm_hap_nested_page_fault (struct vcpu *v,paddr_t *L2_gpa,bool_t access_r,bool_t access_w,bool_t access_x);/* IO permission map */
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel
Tim Deegan
AppliedQuoted 19 lines · Christoph Egger
Quoted 5 lines
It must be _possible_; after all we managed to detect the error. :) In any case it's definitely wrong to carry on with this handler with the wrong address in hand. So I wonder why this patch actually works for you. Does replacing the 'break' above with 'return 1' also fix the problem?
No. Two things have to happen:
1. Calling
paging_mark_dirty()and
2. using the same p2mt from the hostp2m in the nestedp2m.Quoted 7 lines
In the short term, do you only care about pages that are read-only for log-dirty tracking? For the L1 walk, that should be handled by the PT walker's own calls to
paging_mark_dirty(), and the nested-p2m handler could potentially take care of the other case by callingpaging_mark_dirty()(for writes!) before callingnestedhap_walk_L0_p2m().
Quoted 3 lines
Ok, I consider this as a performance improvement rather a bugfix.
New version is attached.
Applied, thanks.
Tim.