ia64/xen-unstable

changeset 14226:d5ca4c37b3c5

x86/64: Save/restore user pagetable pointer for x86/64 PV guests.
Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir@xensource.com>
date Fri Mar 02 22:57:27 2007 +0000 (2007-03-02)
parents 87087954247a
children 29d4bca7a503
files tools/libxc/xc_linux_restore.c tools/libxc/xc_linux_save.c xen/arch/x86/domain.c xen/arch/x86/domctl.c xen/include/public/arch-x86/xen.h
line diff
     1.1 --- a/tools/libxc/xc_linux_restore.c	Fri Mar 02 16:57:24 2007 +0000
     1.2 +++ b/tools/libxc/xc_linux_restore.c	Fri Mar 02 22:57:27 2007 +0000
     1.3 @@ -19,7 +19,7 @@ static unsigned long max_mfn;
     1.4  /* virtual starting address of the hypervisor */
     1.5  static unsigned long hvirt_start;
     1.6  
     1.7 -/* #levels of page tables used by the currrent guest */
     1.8 +/* #levels of page tables used by the current guest */
     1.9  static unsigned int pt_levels;
    1.10  
    1.11  /* total number of pages used by the current guest */
    1.12 @@ -857,6 +857,28 @@ int xc_linux_restore(int xc_handle, int 
    1.13  
    1.14          ctxt.ctrlreg[3] = xen_pfn_to_cr3(p2m[pfn]);
    1.15  
    1.16 +        /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */
    1.17 +        if ( (pt_levels == 4) && ctxt.ctrlreg[1] )
    1.18 +        {
    1.19 +            pfn = xen_cr3_to_pfn(ctxt.ctrlreg[1]);
    1.20 +
    1.21 +            if (pfn >= max_pfn) {
    1.22 +                ERROR("User PT base is bad: pfn=%lu max_pfn=%lu type=%08lx",
    1.23 +                      pfn, max_pfn, pfn_type[pfn]);
    1.24 +                goto out;
    1.25 +            }
    1.26 +
    1.27 +            if ( (pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) !=
    1.28 +                 ((unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT) ) {
    1.29 +                ERROR("User PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx",
    1.30 +                      pfn, max_pfn, pfn_type[pfn],
    1.31 +                      (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
    1.32 +                goto out;
    1.33 +            }
    1.34 +
    1.35 +            ctxt.ctrlreg[1] = xen_pfn_to_cr3(p2m[pfn]);
    1.36 +        }
    1.37 +
    1.38          domctl.cmd = XEN_DOMCTL_setvcpucontext;
    1.39          domctl.domain = (domid_t)dom;
    1.40          domctl.u.vcpucontext.vcpu = i;
     2.1 --- a/tools/libxc/xc_linux_save.c	Fri Mar 02 16:57:24 2007 +0000
     2.2 +++ b/tools/libxc/xc_linux_save.c	Fri Mar 02 22:57:27 2007 +0000
     2.3 @@ -34,7 +34,7 @@ static unsigned long max_mfn;
     2.4  /* virtual starting address of the hypervisor */
     2.5  static unsigned long hvirt_start;
     2.6  
     2.7 -/* #levels of page tables used by the currrent guest */
     2.8 +/* #levels of page tables used by the current guest */
     2.9  static unsigned int pt_levels;
    2.10  
    2.11  /* total number of pages used by the current guest */
    2.12 @@ -491,7 +491,7 @@ static int canonicalize_pagetable(unsign
    2.13      ** reserved hypervisor mappings. This depends on the current
    2.14      ** page table type as well as the number of paging levels.
    2.15      */
    2.16 -    xen_start = xen_end = pte_last = PAGE_SIZE / ((pt_levels == 2)? 4 : 8);
    2.17 +    xen_start = xen_end = pte_last = PAGE_SIZE / ((pt_levels == 2) ? 4 : 8);
    2.18  
    2.19      if (pt_levels == 2 && type == XEN_DOMCTL_PFINFO_L2TAB)
    2.20          xen_start = (hvirt_start >> L2_PAGETABLE_SHIFT);
    2.21 @@ -1279,6 +1279,18 @@ int xc_linux_save(int xc_handle, int io_
    2.22          ctxt.ctrlreg[3] = 
    2.23              xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[3])));
    2.24  
    2.25 +        /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */
    2.26 +        if ( (pt_levels == 4) && ctxt.ctrlreg[1] )
    2.27 +        {
    2.28 +            if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[1])) ) {
    2.29 +                ERROR("PT base is not in range of pseudophys map");
    2.30 +                goto out;
    2.31 +            }
    2.32 +            /* Least-significant bit means 'valid PFN'. */
    2.33 +            ctxt.ctrlreg[1] = 1 |
    2.34 +                xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[1])));
    2.35 +        }
    2.36 +
    2.37          if (!write_exact(io_fd, &ctxt, sizeof(ctxt))) {
    2.38              ERROR("Error when writing to state file (1) (errno %d)", errno);
    2.39              goto out;
     3.1 --- a/xen/arch/x86/domain.c	Fri Mar 02 16:57:24 2007 +0000
     3.2 +++ b/xen/arch/x86/domain.c	Fri Mar 02 22:57:27 2007 +0000
     3.3 @@ -641,6 +641,31 @@ int arch_set_info_guest(
     3.4              }
     3.5  
     3.6              v->arch.guest_table = pagetable_from_pfn(cr3_pfn);
     3.7 +
     3.8 +#ifdef __x86_64__
     3.9 +            if ( c.nat->ctrlreg[1] )
    3.10 +            {
    3.11 +                cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c.nat->ctrlreg[1]));
    3.12 +
    3.13 +                if ( !mfn_valid(cr3_pfn) ||
    3.14 +                     (paging_mode_refcounts(d)
    3.15 +                      ? !get_page(mfn_to_page(cr3_pfn), d)
    3.16 +                      : !get_page_and_type(mfn_to_page(cr3_pfn), d,
    3.17 +                                           PGT_base_page_table)) )
    3.18 +                {
    3.19 +                    cr3_pfn = pagetable_get_pfn(v->arch.guest_table);
    3.20 +                    v->arch.guest_table = pagetable_null();
    3.21 +                    if ( paging_mode_refcounts(d) )
    3.22 +                        put_page(mfn_to_page(cr3_pfn));
    3.23 +                    else
    3.24 +                        put_page_and_type(mfn_to_page(cr3_pfn));
    3.25 +                    destroy_gdt(v);
    3.26 +                    return -EINVAL;
    3.27 +                }
    3.28 +
    3.29 +                v->arch.guest_table_user = pagetable_from_pfn(cr3_pfn);
    3.30 +            }
    3.31 +#endif
    3.32          }
    3.33  #ifdef CONFIG_COMPAT
    3.34          else
     4.1 --- a/xen/arch/x86/domctl.c	Fri Mar 02 16:57:24 2007 +0000
     4.2 +++ b/xen/arch/x86/domctl.c	Fri Mar 02 22:57:27 2007 +0000
     4.3 @@ -470,8 +470,15 @@ void arch_get_info_guest(struct vcpu *v,
     4.4          c(user_regs.eflags |= v->arch.iopl << 12);
     4.5  
     4.6          if ( !IS_COMPAT(v->domain) )
     4.7 +        {
     4.8              c.nat->ctrlreg[3] = xen_pfn_to_cr3(
     4.9                  pagetable_get_pfn(v->arch.guest_table));
    4.10 +#ifdef __x86_64__
    4.11 +            if ( !pagetable_is_null(v->arch.guest_table_user) )
    4.12 +                c.nat->ctrlreg[1] = xen_pfn_to_cr3(
    4.13 +                    pagetable_get_pfn(v->arch.guest_table_user));
    4.14 +#endif
    4.15 +        }
    4.16  #ifdef CONFIG_COMPAT
    4.17          else
    4.18          {
     5.1 --- a/xen/include/public/arch-x86/xen.h	Fri Mar 02 16:57:24 2007 +0000
     5.2 +++ b/xen/include/public/arch-x86/xen.h	Fri Mar 02 22:57:27 2007 +0000
     5.3 @@ -132,6 +132,7 @@ struct vcpu_guest_context {
     5.4      unsigned long ldt_base, ldt_ents;       /* LDT (linear address, # ents) */
     5.5      unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
     5.6      unsigned long kernel_ss, kernel_sp;     /* Virtual TSS (only SS1/SP1)   */
     5.7 +    /* NB. User pagetable on x86/64 is placed in ctrlreg[1]. */
     5.8      unsigned long ctrlreg[8];               /* CR0-CR7 (control registers)  */
     5.9      unsigned long debugreg[8];              /* DB0-DB7 (debug registers)    */
    5.10  #ifdef __i386__