ia64/xen-unstable

changeset 18795:48879ca58848

x86: Use the shadow-code PT walker from the HAP functions

Replace the guts of the HAP pagetable walker with a call to the
newly-commonified walker from the shadow code. This reduces
duplication, and gives HAP guests proper access control and A/D-bit
setting for memory accesses from the emulator

Signed-off-by: Tim Deegan <Tim.Deegan@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Nov 13 13:03:16 2008 +0000 (2008-11-13)
parents 7fb33d15dc9b
children d44ad6db638c
files xen/arch/x86/mm/hap/guest_walk.c xen/arch/x86/mm/hap/private.h xen/arch/x86/mm/page-guest32.h
line diff
     1.1 --- a/xen/arch/x86/mm/hap/guest_walk.c	Thu Nov 13 13:02:08 2008 +0000
     1.2 +++ b/xen/arch/x86/mm/hap/guest_walk.c	Thu Nov 13 13:03:16 2008 +0000
     1.3 @@ -19,25 +19,58 @@
     1.4   * Place - Suite 330, Boston, MA 02111-1307 USA.
     1.5   */
     1.6  
     1.7 +
     1.8 +#include <xen/domain_page.h>
     1.9 +#include <xen/paging.h>
    1.10  #include <xen/config.h>
    1.11 -#include <xen/types.h>
    1.12 -#include <xen/mm.h>
    1.13 -#include <xen/domain_page.h>
    1.14 -#include <asm/page.h>
    1.15 -#include <xen/event.h>
    1.16  #include <xen/sched.h>
    1.17 -#include <asm/hvm/svm/vmcb.h>
    1.18 -#include <asm/domain.h>
    1.19 -#include <asm/paging.h>
    1.20 -#include <asm/p2m.h>
    1.21 -#include <asm/hap.h>
    1.22 -
    1.23 -#include "private.h"
    1.24  
    1.25  #define _hap_gva_to_gfn(levels) hap_gva_to_gfn_##levels##level
    1.26  #define hap_gva_to_gfn(levels) _hap_gva_to_gfn(levels)
    1.27  
    1.28 -#if GUEST_PAGING_LEVELS > CONFIG_PAGING_LEVELS
    1.29 +#if GUEST_PAGING_LEVELS <= CONFIG_PAGING_LEVELS
    1.30 +
    1.31 +#include <asm/guest_pt.h>
    1.32 +
    1.33 +unsigned long hap_gva_to_gfn(GUEST_PAGING_LEVELS)(
    1.34 +    struct vcpu *v, unsigned long gva, uint32_t *pfec)
    1.35 +{
    1.36 +    unsigned long cr3;
    1.37 +    uint32_t missing;
    1.38 +    mfn_t top_mfn;
    1.39 +    void *top_map;
    1.40 +    p2m_type_t p2mt;
    1.41 +    walk_t gw;
    1.42 +
    1.43 +    /* Get the top-level table's MFN */
    1.44 +    cr3 = v->arch.hvm_vcpu.guest_cr[3];
    1.45 +    top_mfn = gfn_to_mfn(v->domain, _gfn(cr3 >> PAGE_SHIFT), &p2mt);
    1.46 +    if ( !p2m_is_ram(p2mt) )
    1.47 +    {
    1.48 +        pfec[0] &= ~PFEC_page_present;
    1.49 +        return INVALID_GFN;
    1.50 +    }
    1.51 +
    1.52 +    /* Map the top-level table and call the tree-walker */
    1.53 +    ASSERT(mfn_valid(mfn_x(top_mfn)));
    1.54 +    top_map = map_domain_page(mfn_x(top_mfn));
    1.55 +#if GUEST_PAGING_LEVELS == 3
    1.56 +    top_map += (cr3 & ~(PAGE_MASK | 31));
    1.57 +#endif
    1.58 +    missing = guest_walk_tables(v, gva, &gw, pfec[0], top_mfn, top_map);
    1.59 +    unmap_domain_page(top_map);
    1.60 +
    1.61 +    /* Interpret the answer */
    1.62 +    if ( missing == 0 ) 
    1.63 +        return gfn_x(guest_l1e_get_gfn(gw.l1e));
    1.64 +    
    1.65 +    if ( missing & _PAGE_PRESENT )
    1.66 +        pfec[0] &= ~PFEC_page_present;
    1.67 +    
    1.68 +    return INVALID_GFN;
    1.69 +}
    1.70 +
    1.71 +#else
    1.72  
    1.73  unsigned long hap_gva_to_gfn(GUEST_PAGING_LEVELS)(
    1.74      struct vcpu *v, unsigned long gva, uint32_t *pfec)
    1.75 @@ -48,130 +81,8 @@ unsigned long hap_gva_to_gfn(GUEST_PAGIN
    1.76      return INVALID_GFN;
    1.77  }
    1.78  
    1.79 -#else
    1.80 -
    1.81 -#if GUEST_PAGING_LEVELS == 2
    1.82 -#include "../page-guest32.h"
    1.83 -#define l1_pgentry_t l1_pgentry_32_t
    1.84 -#define l2_pgentry_t l2_pgentry_32_t
    1.85 -#undef l2e_get_flags
    1.86 -#define l2e_get_flags(x) l2e_get_flags_32(x)
    1.87 -#undef l1e_get_flags
    1.88 -#define l1e_get_flags(x) l1e_get_flags_32(x)
    1.89 -#endif
    1.90 -
    1.91 -unsigned long hap_gva_to_gfn(GUEST_PAGING_LEVELS)(
    1.92 -    struct vcpu *v, unsigned long gva, uint32_t *pfec)
    1.93 -{
    1.94 -    unsigned long gcr3 = v->arch.hvm_vcpu.guest_cr[3];
    1.95 -    int mode = GUEST_PAGING_LEVELS;
    1.96 -    int lev, index;
    1.97 -    paddr_t gpa = 0;
    1.98 -    unsigned long gpfn, mfn;
    1.99 -    p2m_type_t p2mt;
   1.100 -    int success = 1;
   1.101 -
   1.102 -    l1_pgentry_t *l1e;
   1.103 -    l2_pgentry_t *l2e;
   1.104 -#if GUEST_PAGING_LEVELS >= 3
   1.105 -    l3_pgentry_t *l3e;
   1.106 -#endif
   1.107 -#if GUEST_PAGING_LEVELS >= 4
   1.108 -    l4_pgentry_t *l4e;
   1.109 -#endif
   1.110 -
   1.111 -    gpfn = (gcr3 >> PAGE_SHIFT);
   1.112 -    for ( lev = mode; lev >= 1; lev-- )
   1.113 -    {
   1.114 -        mfn = mfn_x(gfn_to_mfn(v->domain, gpfn, &p2mt));
   1.115 -        if ( !p2m_is_ram(p2mt) )
   1.116 -        {
   1.117 -            HAP_PRINTK("bad pfn=0x%lx from gva=0x%lx at lev%d\n", gpfn, gva,
   1.118 -                       lev);
   1.119 -            success = 0;
   1.120 -            break;
   1.121 -        }
   1.122 -        ASSERT(mfn_valid(mfn));
   1.123 -
   1.124 -        index = (gva >> PT_SHIFT[mode][lev]) & (PT_ENTRIES[mode][lev]-1);
   1.125 -
   1.126 -#if GUEST_PAGING_LEVELS >= 4
   1.127 -        if ( lev == 4 )
   1.128 -        {
   1.129 -            l4e = map_domain_page(mfn);
   1.130 -            if ( !(l4e_get_flags(l4e[index]) & _PAGE_PRESENT) )
   1.131 -            {
   1.132 -                HAP_PRINTK("Level 4 entry not present at index = %d\n", index);
   1.133 -                success = 0;
   1.134 -            }
   1.135 -            gpfn = l4e_get_pfn(l4e[index]);
   1.136 -            unmap_domain_page(l4e);
   1.137 -        }
   1.138  #endif
   1.139  
   1.140 -#if GUEST_PAGING_LEVELS >= 3
   1.141 -        if ( lev == 3 )
   1.142 -        {
   1.143 -            l3e = map_domain_page(mfn);
   1.144 -#if GUEST_PAGING_LEVELS == 3
   1.145 -            index += ((gcr3 >> 5) & 127) * 4;
   1.146 -#endif
   1.147 -            if ( !(l3e_get_flags(l3e[index]) & _PAGE_PRESENT) )
   1.148 -            {
   1.149 -                HAP_PRINTK("Level 3 entry not present at index = %d\n", index);
   1.150 -                success = 0;
   1.151 -            }
   1.152 -            gpfn = l3e_get_pfn(l3e[index]);
   1.153 -            unmap_domain_page(l3e);
   1.154 -        }
   1.155 -#endif
   1.156 -
   1.157 -        if ( lev == 2 )
   1.158 -        {
   1.159 -            l2e = map_domain_page(mfn);
   1.160 -            if ( !(l2e_get_flags(l2e[index]) & _PAGE_PRESENT) )
   1.161 -            {
   1.162 -                HAP_PRINTK("Level 2 entry not present at index = %d\n", index);
   1.163 -                success = 0;
   1.164 -            }
   1.165 -
   1.166 -            if ( l2e_get_flags(l2e[index]) & _PAGE_PSE )
   1.167 -            {
   1.168 -                paddr_t mask = ((paddr_t)1 << PT_SHIFT[mode][2]) - 1;
   1.169 -                HAP_PRINTK("guest page table is PSE\n");
   1.170 -                gpa = (l2e_get_intpte(l2e[index]) & ~mask) + (gva & mask);
   1.171 -                unmap_domain_page(l2e);
   1.172 -                break; /* last level page table, jump out from here */
   1.173 -            }
   1.174 -
   1.175 -            gpfn = l2e_get_pfn(l2e[index]);
   1.176 -            unmap_domain_page(l2e);
   1.177 -        }
   1.178 -
   1.179 -        if ( lev == 1 )
   1.180 -        {
   1.181 -            l1e = map_domain_page(mfn);
   1.182 -            if ( !(l1e_get_flags(l1e[index]) & _PAGE_PRESENT) )
   1.183 -            {
   1.184 -                HAP_PRINTK("Level 1 entry not present at index = %d\n", index);
   1.185 -                success = 0;
   1.186 -            }
   1.187 -            gpfn = l1e_get_pfn(l1e[index]);
   1.188 -            gpa = (l1e_get_intpte(l1e[index]) & PAGE_MASK) + (gva &~PAGE_MASK);
   1.189 -            unmap_domain_page(l1e);
   1.190 -        }
   1.191 -
   1.192 -        if ( success != 1 ) /* error happened, jump out */
   1.193 -            break;
   1.194 -    }
   1.195 -
   1.196 -    gpa &= PADDR_MASK;
   1.197 -    HAP_PRINTK("success = %d, gva = %lx, gpa = %lx\n", success, gva, gpa);
   1.198 -
   1.199 -    return (!success ? INVALID_GFN : ((paddr_t)gpa >> PAGE_SHIFT));
   1.200 -}
   1.201 -
   1.202 -#endif
   1.203  
   1.204  /*
   1.205   * Local variables:
     2.1 --- a/xen/arch/x86/mm/hap/private.h	Thu Nov 13 13:02:08 2008 +0000
     2.2 +++ b/xen/arch/x86/mm/hap/private.h	Thu Nov 13 13:03:16 2008 +0000
     2.3 @@ -20,9 +20,6 @@
     2.4  #ifndef __HAP_PRIVATE_H__
     2.5  #define __HAP_PRIVATE_H__
     2.6  
     2.7 -#include <asm/flushtlb.h>
     2.8 -#include <asm/hvm/support.h>
     2.9 -
    2.10  /********************************************/
    2.11  /*          GUEST TRANSLATION FUNCS         */
    2.12  /********************************************/
    2.13 @@ -33,36 +30,5 @@ unsigned long hap_gva_to_gfn_3level(stru
    2.14  unsigned long hap_gva_to_gfn_4level(struct vcpu *v, unsigned long gva,
    2.15                                      uint32_t *pfec);
    2.16  
    2.17 -/********************************************/
    2.18 -/*            MISC DEFINITIONS              */
    2.19 -/********************************************/
    2.20 -
    2.21 -/* PT_SHIFT describes the amount by which a virtual address is shifted right 
    2.22 - * to right justify the portion to be used for indexing into a page 
    2.23 - * table, given the guest memory model (i.e. number of levels) and the level 
    2.24 - * of the page table being accessed. The idea is from Virtual Iron's code.
    2.25 - */
    2.26 -static const int PT_SHIFT[][5] =
    2.27 -  {   /*     ------  level ------           nr_levels  */
    2.28 -    /*         1     2     3     4                   */
    2.29 -    {    0,    0,    0,    0,    0},   /* 0 not used */
    2.30 -    {    0,    0,    0,    0,    0},   /* 1 not used */
    2.31 -    {    0,   12,   22,    0,    0},   /* 2  */
    2.32 -    {    0,   12,   21,   30,    0},   /* 3  */
    2.33 -    {    0,   12,   21,   30,   39}    /* 4  */
    2.34 -  };
    2.35 -
    2.36 -/* PT_ENTRIES describes the number of entries in a page table, given the 
    2.37 - * memory model (i.e. number of levels) and the level of the page table 
    2.38 - * being considered. This idea from Virtual Iron's shadow code*/
    2.39 -static const int PT_ENTRIES[][5] =
    2.40 -  {   /*     ------  level ------           nr_levels  */
    2.41 -    /*         1     2     3     4                   */
    2.42 -    {    0,    0,    0,    0,    0},   /* 0 not used */
    2.43 -    {    0,    0,    0,    0,    0},   /* 1 not used */
    2.44 -    {    0, 1024, 1024,    0,    0},   /* 2  */
    2.45 -    {    0,  512,  512,    4,    0},   /* 3  */
    2.46 -    {    0,  512,  512,  512,  512}    /* 4  */
    2.47 -  };
    2.48  
    2.49  #endif /* __SVM_NPT_H__ */
     3.1 --- a/xen/arch/x86/mm/page-guest32.h	Thu Nov 13 13:02:08 2008 +0000
     3.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.3 @@ -1,100 +0,0 @@
     3.4 -
     3.5 -#ifndef __X86_PAGE_GUEST_H__
     3.6 -#define __X86_PAGE_GUEST_H__
     3.7 -
     3.8 -#ifndef __ASSEMBLY__
     3.9 -# include <asm/types.h>
    3.10 -#endif
    3.11 -
    3.12 -#define PAGETABLE_ORDER_32         10
    3.13 -#define L1_PAGETABLE_ENTRIES_32    (1<<PAGETABLE_ORDER_32)
    3.14 -#define L2_PAGETABLE_ENTRIES_32    (1<<PAGETABLE_ORDER_32)
    3.15 -#define ROOT_PAGETABLE_ENTRIES_32  L2_PAGETABLE_ENTRIES_32
    3.16 -
    3.17 -
    3.18 -#define L1_PAGETABLE_SHIFT_32 12
    3.19 -#define L2_PAGETABLE_SHIFT_32 22
    3.20 -
    3.21 -/* Extract flags into 12-bit integer, or turn 12-bit flags into a pte mask. */
    3.22 -
    3.23 -#ifndef __ASSEMBLY__
    3.24 -
    3.25 -typedef u32 intpte_32_t;
    3.26 -
    3.27 -typedef struct { intpte_32_t l1; } l1_pgentry_32_t;
    3.28 -typedef struct { intpte_32_t l2; } l2_pgentry_32_t;
    3.29 -typedef l2_pgentry_t root_pgentry_32_t;
    3.30 -#endif
    3.31 -
    3.32 -#define get_pte_flags_32(x) ((u32)(x) & 0xFFF)
    3.33 -#define put_pte_flags_32(x) ((intpte_32_t)(x))
    3.34 -
    3.35 -/* Get pte access flags (unsigned int). */
    3.36 -#define l1e_get_flags_32(x)           (get_pte_flags_32((x).l1))
    3.37 -#define l2e_get_flags_32(x)           (get_pte_flags_32((x).l2))
    3.38 -
    3.39 -#define l1e_get_paddr_32(x)           \
    3.40 -    ((paddr_t)(((x).l1 & (PADDR_MASK&PAGE_MASK))))
    3.41 -#define l2e_get_paddr_32(x)           \
    3.42 -    ((paddr_t)(((x).l2 & (PADDR_MASK&PAGE_MASK))))
    3.43 -
    3.44 -/* Construct an empty pte. */
    3.45 -#define l1e_empty_32()                ((l1_pgentry_32_t) { 0 })
    3.46 -#define l2e_empty_32()                ((l2_pgentry_32_t) { 0 })
    3.47 -
    3.48 -/* Construct a pte from a pfn and access flags. */
    3.49 -#define l1e_from_pfn_32(pfn, flags)   \
    3.50 -    ((l1_pgentry_32_t) { ((intpte_32_t)(pfn) << PAGE_SHIFT) | put_pte_flags_32(flags) })
    3.51 -#define l2e_from_pfn_32(pfn, flags)   \
    3.52 -    ((l2_pgentry_32_t) { ((intpte_32_t)(pfn) << PAGE_SHIFT) | put_pte_flags_32(flags) })
    3.53 -
    3.54 -/* Construct a pte from a physical address and access flags. */
    3.55 -#ifndef __ASSEMBLY__
    3.56 -static inline l1_pgentry_32_t l1e_from_paddr_32(paddr_t pa, unsigned int flags)
    3.57 -{
    3.58 -    ASSERT((pa & ~(PADDR_MASK & PAGE_MASK)) == 0);
    3.59 -    return (l1_pgentry_32_t) { pa | put_pte_flags_32(flags) };
    3.60 -}
    3.61 -static inline l2_pgentry_32_t l2e_from_paddr_32(paddr_t pa, unsigned int flags)
    3.62 -{
    3.63 -    ASSERT((pa & ~(PADDR_MASK & PAGE_MASK)) == 0);
    3.64 -    return (l2_pgentry_32_t) { pa | put_pte_flags_32(flags) };
    3.65 -}
    3.66 -#endif /* !__ASSEMBLY__ */
    3.67 -
    3.68 -
    3.69 -/* Construct a pte from a page pointer and access flags. */
    3.70 -#define l1e_from_page_32(page, flags) (l1e_from_pfn_32(page_to_mfn(page),(flags)))
    3.71 -#define l2e_from_page_32(page, flags) (l2e_from_pfn_32(page_to_mfn(page),(flags)))
    3.72 -
    3.73 -/* Add extra flags to an existing pte. */
    3.74 -#define l1e_add_flags_32(x, flags)    ((x).l1 |= put_pte_flags_32(flags))
    3.75 -#define l2e_add_flags_32(x, flags)    ((x).l2 |= put_pte_flags_32(flags))
    3.76 -
    3.77 -/* Remove flags from an existing pte. */
    3.78 -#define l1e_remove_flags_32(x, flags) ((x).l1 &= ~put_pte_flags_32(flags))
    3.79 -#define l2e_remove_flags_32(x, flags) ((x).l2 &= ~put_pte_flags_32(flags))
    3.80 -
    3.81 -/* Check if a pte's page mapping or significant access flags have changed. */
    3.82 -#define l1e_has_changed_32(x,y,flags) \
    3.83 -    ( !!(((x).l1 ^ (y).l1) & ((PADDR_MASK&PAGE_MASK)|put_pte_flags_32(flags))) )
    3.84 -#define l2e_has_changed_32(x,y,flags) \
    3.85 -    ( !!(((x).l2 ^ (y).l2) & ((PADDR_MASK&PAGE_MASK)|put_pte_flags_32(flags))) )
    3.86 -
    3.87 -/* Given a virtual address, get an entry offset into a page table. */
    3.88 -#define l1_table_offset_32(a)         \
    3.89 -    (((a) >> L1_PAGETABLE_SHIFT_32) & (L1_PAGETABLE_ENTRIES_32 - 1))
    3.90 -#define l2_table_offset_32(a)         \
    3.91 -    (((a) >> L2_PAGETABLE_SHIFT_32) & (L2_PAGETABLE_ENTRIES_32 - 1))
    3.92 -
    3.93 -#endif /* __X86_PAGE_GUEST_H__ */
    3.94 -
    3.95 -/*
    3.96 - * Local variables:
    3.97 - * mode: C
    3.98 - * c-set-style: "BSD"
    3.99 - * c-basic-offset: 4
   3.100 - * tab-width: 4
   3.101 - * indent-tabs-mode: nil
   3.102 - * End:
   3.103 - */