ia64/xen-unstable

changeset 17025:9541494c0945

x86 shadow: Move the shadow linear mapping for n-on-3-on-4 shadows so
that guest mappings of the bottom 4GB are not reflected in the monitor
pagetable. This ensures in particular that page 0 is not mapped,
allowing us to catch NULL dereferences in the hypervisor.

Signed-off-by: Tim Deegan <Tim.Deegan@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Feb 11 10:16:53 2008 +0000 (2008-02-11)
parents 49f87f3c2cb8
children ad064e48b6f2
files xen/arch/x86/mm/shadow/multi.c
line diff
     1.1 --- a/xen/arch/x86/mm/shadow/multi.c	Mon Feb 11 10:15:07 2008 +0000
     1.2 +++ b/xen/arch/x86/mm/shadow/multi.c	Mon Feb 11 10:16:53 2008 +0000
     1.3 @@ -1470,10 +1470,14 @@ void sh_install_xen_entries_in_l4(struct
     1.4          shadow_l4e_from_mfn(page_to_mfn(virt_to_page(d->arch.mm_perdomain_l3)),
     1.5                              __PAGE_HYPERVISOR);
     1.6  
     1.7 -    /* Linear mapping */
     1.8 +    /* Shadow linear mapping for 4-level shadows.  N.B. for 3-level
     1.9 +     * shadows on 64-bit xen, this linear mapping is later replaced by the
    1.10 +     * monitor pagetable structure, which is built in make_monitor_table
    1.11 +     * and maintained by sh_update_linear_entries. */
    1.12      sl4e[shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START)] =
    1.13          shadow_l4e_from_mfn(sl4mfn, __PAGE_HYPERVISOR);
    1.14  
    1.15 +    /* Self linear mapping.  */
    1.16      if ( shadow_mode_translate(v->domain) && !shadow_mode_external(v->domain) )
    1.17      {
    1.18          // linear tables may not be used with translated PV guests
    1.19 @@ -1745,7 +1749,7 @@ sh_make_monitor_table(struct vcpu *v)
    1.20      ASSERT(pagetable_get_pfn(v->arch.monitor_table) == 0);
    1.21      
    1.22      /* Guarantee we can get the memory we need */
    1.23 -    shadow_prealloc(d, SH_type_monitor_table, CONFIG_PAGING_LEVELS - 1);
    1.24 +    shadow_prealloc(d, SH_type_monitor_table, CONFIG_PAGING_LEVELS);
    1.25  
    1.26  #if CONFIG_PAGING_LEVELS == 4    
    1.27      {
    1.28 @@ -1755,22 +1759,34 @@ sh_make_monitor_table(struct vcpu *v)
    1.29          /* Remember the level of this table */
    1.30          mfn_to_page(m4mfn)->shadow_flags = 4;
    1.31  #if SHADOW_PAGING_LEVELS < 4
    1.32 -        // Install a monitor l3 table in slot 0 of the l4 table.
    1.33 -        // This is used for shadow linear maps.
    1.34          {
    1.35 -            mfn_t m3mfn; 
    1.36 +            mfn_t m3mfn, m2mfn;
    1.37              l4_pgentry_t *l4e;
    1.38 +            l3_pgentry_t *l3e;
    1.39 +            /* Install an l3 table and an l2 table that will hold the shadow 
    1.40 +             * linear map entries.  This overrides the linear map entry that 
    1.41 +             * was installed by sh_install_xen_entries_in_l4. */
    1.42 +            l4e = sh_map_domain_page(m4mfn);
    1.43 +
    1.44              m3mfn = shadow_alloc(d, SH_type_monitor_table, 0);
    1.45              mfn_to_page(m3mfn)->shadow_flags = 3;
    1.46 -            l4e = sh_map_domain_page(m4mfn);
    1.47 -            l4e[0] = l4e_from_pfn(mfn_x(m3mfn), __PAGE_HYPERVISOR);
    1.48 -            sh_unmap_domain_page(l4e);
    1.49 +            l4e[shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START)]
    1.50 +                = l4e_from_pfn(mfn_x(m3mfn), __PAGE_HYPERVISOR);
    1.51 +
    1.52 +            m2mfn = shadow_alloc(d, SH_type_monitor_table, 0);
    1.53 +            mfn_to_page(m2mfn)->shadow_flags = 2;
    1.54 +            l3e = sh_map_domain_page(m3mfn);
    1.55 +            l3e[0] = l3e_from_pfn(mfn_x(m2mfn), __PAGE_HYPERVISOR);
    1.56 +            sh_unmap_domain_page(l3e);
    1.57 +
    1.58              if ( is_pv_32on64_vcpu(v) )
    1.59              {
    1.60 -                // Install a monitor l2 table in slot 3 of the l3 table.
    1.61 -                // This is used for all Xen entries.
    1.62 -                mfn_t m2mfn;
    1.63 -                l3_pgentry_t *l3e;
    1.64 +                /* For 32-on-64 PV guests, we need to map the 32-bit Xen
    1.65 +                 * area into its usual VAs in the monitor tables */
    1.66 +                m3mfn = shadow_alloc(d, SH_type_monitor_table, 0);
    1.67 +                mfn_to_page(m3mfn)->shadow_flags = 3;
    1.68 +                l4e[0] = l4e_from_pfn(mfn_x(m3mfn), __PAGE_HYPERVISOR);
    1.69 +                
    1.70                  m2mfn = shadow_alloc(d, SH_type_monitor_table, 0);
    1.71                  mfn_to_page(m2mfn)->shadow_flags = 2;
    1.72                  l3e = sh_map_domain_page(m3mfn);
    1.73 @@ -1778,6 +1794,8 @@ sh_make_monitor_table(struct vcpu *v)
    1.74                  sh_install_xen_entries_in_l2h(v, m2mfn);
    1.75                  sh_unmap_domain_page(l3e);
    1.76              }
    1.77 +
    1.78 +            sh_unmap_domain_page(l4e);
    1.79          }
    1.80  #endif /* SHADOW_PAGING_LEVELS < 4 */
    1.81          return m4mfn;
    1.82 @@ -2181,21 +2199,34 @@ void sh_destroy_monitor_table(struct vcp
    1.83      ASSERT(mfn_to_shadow_page(mmfn)->type == SH_type_monitor_table);
    1.84  
    1.85  #if (CONFIG_PAGING_LEVELS == 4) && (SHADOW_PAGING_LEVELS != 4)
    1.86 -    /* Need to destroy the l3 monitor page in slot 0 too */
    1.87      {
    1.88          mfn_t m3mfn;
    1.89          l4_pgentry_t *l4e = sh_map_domain_page(mmfn);
    1.90 -        ASSERT(l4e_get_flags(l4e[0]) & _PAGE_PRESENT);
    1.91 -        m3mfn = _mfn(l4e_get_pfn(l4e[0]));
    1.92 +        l3_pgentry_t *l3e;
    1.93 +        int linear_slot = shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START);
    1.94 + 
    1.95 +        /* Need to destroy the l3 and l2 monitor pages used 
    1.96 +         * for the linear map */
    1.97 +        ASSERT(l4e_get_flags(l4e[linear_slot]) & _PAGE_PRESENT);
    1.98 +        m3mfn = _mfn(l4e_get_pfn(l4e[linear_slot]));
    1.99 +        l3e = sh_map_domain_page(m3mfn);
   1.100 +        ASSERT(l3e_get_flags(l3e[0]) & _PAGE_PRESENT);
   1.101 +        shadow_free(d, _mfn(l3e_get_pfn(l3e[0])));
   1.102 +        sh_unmap_domain_page(l3e);
   1.103 +        shadow_free(d, m3mfn);
   1.104 +
   1.105          if ( is_pv_32on64_vcpu(v) )
   1.106          {
   1.107 -            /* Need to destroy the l2 monitor page in slot 3 too */
   1.108 -            l3_pgentry_t *l3e = sh_map_domain_page(m3mfn);
   1.109 +            /* Need to destroy the l3 and l2 monitor pages that map the
   1.110 +             * Xen VAs at 3GB-4GB */
   1.111 +            ASSERT(l4e_get_flags(l4e[0]) & _PAGE_PRESENT);
   1.112 +            m3mfn = _mfn(l4e_get_pfn(l4e[0]));
   1.113 +            l3e = sh_map_domain_page(m3mfn);
   1.114              ASSERT(l3e_get_flags(l3e[3]) & _PAGE_PRESENT);
   1.115              shadow_free(d, _mfn(l3e_get_pfn(l3e[3])));
   1.116              sh_unmap_domain_page(l3e);
   1.117 +            shadow_free(d, m3mfn);
   1.118          }
   1.119 -        shadow_free(d, m3mfn);
   1.120          sh_unmap_domain_page(l4e);
   1.121      }
   1.122  #elif CONFIG_PAGING_LEVELS == 3
   1.123 @@ -3222,28 +3253,33 @@ sh_update_linear_entries(struct vcpu *v)
   1.124  
   1.125      if ( shadow_mode_external(d) )
   1.126      {
   1.127 -        /* Install copies of the shadow l3es into the monitor l3 table.
   1.128 -         * The monitor l3 table is hooked into slot 0 of the monitor
   1.129 -         * l4 table, so we use l3 linear indices 0 to 3 */
   1.130 +        /* Install copies of the shadow l3es into the monitor l2 table
   1.131 +         * that maps SH_LINEAR_PT_VIRT_START. */
   1.132          shadow_l3e_t *sl3e;
   1.133 -        l3_pgentry_t *ml3e;
   1.134 -        mfn_t l3mfn;
   1.135 +        l2_pgentry_t *ml2e;
   1.136          int i;
   1.137  
   1.138          /* Use linear mappings if we can; otherwise make new mappings */
   1.139 -        if ( v == current ) 
   1.140 -        {
   1.141 -            ml3e = __linear_l3_table;
   1.142 -            l3mfn = _mfn(l4e_get_pfn(__linear_l4_table[0]));
   1.143 -        }
   1.144 +        if ( v == current )
   1.145 +            ml2e = __linear_l2_table
   1.146 +                + l2_linear_offset(SH_LINEAR_PT_VIRT_START);
   1.147          else 
   1.148          {   
   1.149 +            mfn_t l3mfn, l2mfn;
   1.150              l4_pgentry_t *ml4e;
   1.151 +            l3_pgentry_t *ml3e;
   1.152 +            int linear_slot = shadow_l4_table_offset(SH_LINEAR_PT_VIRT_START);
   1.153              ml4e = sh_map_domain_page(pagetable_get_mfn(v->arch.monitor_table));
   1.154 -            ASSERT(l4e_get_flags(ml4e[0]) & _PAGE_PRESENT);
   1.155 -            l3mfn = _mfn(l4e_get_pfn(ml4e[0]));
   1.156 +
   1.157 +            ASSERT(l4e_get_flags(ml4e[linear_slot]) & _PAGE_PRESENT);
   1.158 +            l3mfn = _mfn(l4e_get_pfn(ml4e[linear_slot]));
   1.159              ml3e = sh_map_domain_page(l3mfn);
   1.160              sh_unmap_domain_page(ml4e);
   1.161 +
   1.162 +            ASSERT(l3e_get_flags(ml3e[0]) & _PAGE_PRESENT);
   1.163 +            l2mfn = _mfn(l3e_get_pfn(ml3e[0]));
   1.164 +            ml2e = sh_map_domain_page(l2mfn);
   1.165 +            sh_unmap_domain_page(ml3e);
   1.166          }
   1.167  
   1.168          /* Shadow l3 tables are made up by sh_update_cr3 */
   1.169 @@ -3251,15 +3287,15 @@ sh_update_linear_entries(struct vcpu *v)
   1.170  
   1.171          for ( i = 0; i < SHADOW_L3_PAGETABLE_ENTRIES; i++ )
   1.172          {
   1.173 -            ml3e[i] = 
   1.174 +            ml2e[i] = 
   1.175                  (shadow_l3e_get_flags(sl3e[i]) & _PAGE_PRESENT) 
   1.176 -                ? l3e_from_pfn(mfn_x(shadow_l3e_get_mfn(sl3e[i])), 
   1.177 +                ? l2e_from_pfn(mfn_x(shadow_l3e_get_mfn(sl3e[i])),
   1.178                                 __PAGE_HYPERVISOR) 
   1.179 -                : l3e_empty();
   1.180 +                : l2e_empty();
   1.181          }
   1.182  
   1.183          if ( v != current ) 
   1.184 -            sh_unmap_domain_page(ml3e);
   1.185 +            sh_unmap_domain_page(ml2e);
   1.186      }
   1.187      else
   1.188          domain_crash(d); /* XXX */