ia64/xen-unstable

changeset 3716:23e7cf28ddb3

bitkeeper revision 1.1159.212.126 (42089d5esMXb54hvuQX14wvXnCm18w)

Various hypercall fixes for x86_64.
Main todos: 1. mmu_updates/update_va_mapping hypercalls.
2. map perdomain_pt into Xen address space.
3. exception/interrupt callbacks to guest OS.
4. user-space ring 3 vs. guest-OS ring 3.
Signed-off-by: keir.fraser@cl.cam.ac.uk
author kaf24@scramble.cl.cam.ac.uk
date Tue Feb 08 11:07:10 2005 +0000 (2005-02-08)
parents a95bb5c8b8be
children ea98f0bb6510 456195c4774c f504382b179f
files xen/arch/x86/memory.c xen/arch/x86/traps.c xen/arch/x86/x86_32/mm.c xen/arch/x86/x86_64/entry.S xen/arch/x86/x86_64/mm.c xen/include/asm-x86/mm.h xen/include/asm-x86/multicall.h
line diff
     1.1 --- a/xen/arch/x86/memory.c	Tue Feb 08 03:15:03 2005 +0000
     1.2 +++ b/xen/arch/x86/memory.c	Tue Feb 08 11:07:10 2005 +0000
     1.3 @@ -249,11 +249,13 @@ static inline void invalidate_shadow_ldt
     1.4  
     1.5  static int alloc_segdesc_page(struct pfn_info *page)
     1.6  {
     1.7 -    unsigned long *descs = map_domain_mem((page-frame_table) << PAGE_SHIFT);
     1.8 +    struct desc_struct *descs;
     1.9      int i;
    1.10  
    1.11 +    descs = map_domain_mem((page-frame_table) << PAGE_SHIFT);
    1.12 +
    1.13      for ( i = 0; i < 512; i++ )
    1.14 -        if ( unlikely(!check_descriptor(&descs[i*2])) )
    1.15 +        if ( unlikely(!check_descriptor(&descs[i])) )
    1.16              goto fail;
    1.17  
    1.18      unmap_domain_mem(descs);
    1.19 @@ -1652,6 +1654,182 @@ int do_update_va_mapping_otherdomain(uns
    1.20  
    1.21  
    1.22  /*************************
    1.23 + * Descriptor Tables
    1.24 + */
    1.25 +
    1.26 +void destroy_gdt(struct exec_domain *ed)
    1.27 +{
    1.28 +    int i;
    1.29 +    unsigned long pfn;
    1.30 +
    1.31 +    for ( i = 0; i < 16; i++ )
    1.32 +    {
    1.33 +        if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
    1.34 +            put_page_and_type(&frame_table[pfn]);
    1.35 +        ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
    1.36 +    }
    1.37 +}
    1.38 +
    1.39 +
    1.40 +long set_gdt(struct exec_domain *ed, 
    1.41 +             unsigned long *frames,
    1.42 +             unsigned int entries)
    1.43 +{
    1.44 +    struct domain *d = ed->domain;
    1.45 +    /* NB. There are 512 8-byte entries per GDT page. */
    1.46 +    int i = 0, nr_pages = (entries + 511) / 512;
    1.47 +    struct desc_struct *vgdt;
    1.48 +    unsigned long pfn;
    1.49 +
    1.50 +    /* Check the first page in the new GDT. */
    1.51 +    if ( (pfn = frames[0]) >= max_page )
    1.52 +        goto fail;
    1.53 +
    1.54 +    /* The first page is special because Xen owns a range of entries in it. */
    1.55 +    if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
    1.56 +    {
    1.57 +        /* GDT checks failed: try zapping the Xen reserved entries. */
    1.58 +        if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
    1.59 +            goto fail;
    1.60 +        vgdt = map_domain_mem(pfn << PAGE_SHIFT);
    1.61 +        memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
    1.62 +               NR_RESERVED_GDT_ENTRIES*8);
    1.63 +        unmap_domain_mem(vgdt);
    1.64 +        put_page_and_type(&frame_table[pfn]);
    1.65 +
    1.66 +        /* Okay, we zapped the entries. Now try the GDT checks again. */
    1.67 +        if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
    1.68 +            goto fail;
    1.69 +    }
    1.70 +
    1.71 +    /* Check the remaining pages in the new GDT. */
    1.72 +    for ( i = 1; i < nr_pages; i++ )
    1.73 +        if ( ((pfn = frames[i]) >= max_page) ||
    1.74 +             !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
    1.75 +            goto fail;
    1.76 +
    1.77 +    /* Copy reserved GDT entries to the new GDT. */
    1.78 +    vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
    1.79 +    memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY, 
    1.80 +           gdt_table + FIRST_RESERVED_GDT_ENTRY, 
    1.81 +           NR_RESERVED_GDT_ENTRIES*8);
    1.82 +    unmap_domain_mem(vgdt);
    1.83 +
    1.84 +    /* Tear down the old GDT. */
    1.85 +    destroy_gdt(ed);
    1.86 +
    1.87 +    /* Install the new GDT. */
    1.88 +    for ( i = 0; i < nr_pages; i++ )
    1.89 +        ed->arch.perdomain_ptes[i] =
    1.90 +            mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
    1.91 +
    1.92 +    SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
    1.93 +    SET_GDT_ENTRIES(ed, entries);
    1.94 +
    1.95 +    return 0;
    1.96 +
    1.97 + fail:
    1.98 +    while ( i-- > 0 )
    1.99 +        put_page_and_type(&frame_table[frames[i]]);
   1.100 +    return -EINVAL;
   1.101 +}
   1.102 +
   1.103 +
   1.104 +long do_set_gdt(unsigned long *frame_list, unsigned int entries)
   1.105 +{
   1.106 +    int nr_pages = (entries + 511) / 512;
   1.107 +    unsigned long frames[16];
   1.108 +    long ret;
   1.109 +
   1.110 +    if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) ) 
   1.111 +        return -EINVAL;
   1.112 +    
   1.113 +    if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
   1.114 +        return -EFAULT;
   1.115 +
   1.116 +    LOCK_BIGLOCK(current->domain);
   1.117 +
   1.118 +    if ( (ret = set_gdt(current, frames, entries)) == 0 )
   1.119 +    {
   1.120 +        local_flush_tlb();
   1.121 +        __asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
   1.122 +    }
   1.123 +
   1.124 +    UNLOCK_BIGLOCK(current->domain);
   1.125 +
   1.126 +    return ret;
   1.127 +}
   1.128 +
   1.129 +
   1.130 +long do_update_descriptor(
   1.131 +    unsigned long pa, unsigned long word1, unsigned long word2)
   1.132 +{
   1.133 +    unsigned long pfn = pa >> PAGE_SHIFT;
   1.134 +    struct desc_struct *gdt_pent, d;
   1.135 +    struct pfn_info *page;
   1.136 +    struct exec_domain *ed;
   1.137 +    long ret = -EINVAL;
   1.138 +
   1.139 +    d.a = (u32)word1;
   1.140 +    d.b = (u32)word2;
   1.141 +
   1.142 +    LOCK_BIGLOCK(current->domain);
   1.143 +
   1.144 +    if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(&d) ) {
   1.145 +        UNLOCK_BIGLOCK(current->domain);
   1.146 +        return -EINVAL;
   1.147 +    }
   1.148 +
   1.149 +    page = &frame_table[pfn];
   1.150 +    if ( unlikely(!get_page(page, current->domain)) ) {
   1.151 +        UNLOCK_BIGLOCK(current->domain);
   1.152 +        return -EINVAL;
   1.153 +    }
   1.154 +
   1.155 +    /* Check if the given frame is in use in an unsafe context. */
   1.156 +    switch ( page->u.inuse.type_info & PGT_type_mask )
   1.157 +    {
   1.158 +    case PGT_gdt_page:
   1.159 +        /* Disallow updates of Xen-reserved descriptors in the current GDT. */
   1.160 +        for_each_exec_domain(current->domain, ed) {
   1.161 +            if ( (l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[0]) == pfn) &&
   1.162 +                 (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
   1.163 +                 (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
   1.164 +                goto out;
   1.165 +        }
   1.166 +        if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
   1.167 +            goto out;
   1.168 +        break;
   1.169 +    case PGT_ldt_page:
   1.170 +        if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
   1.171 +            goto out;
   1.172 +        break;
   1.173 +    default:
   1.174 +        if ( unlikely(!get_page_type(page, PGT_writable_page)) )
   1.175 +            goto out;
   1.176 +        break;
   1.177 +    }
   1.178 +
   1.179 +    /* All is good so make the update. */
   1.180 +    gdt_pent = map_domain_mem(pa);
   1.181 +    memcpy(gdt_pent, &d, 8);
   1.182 +    unmap_domain_mem(gdt_pent);
   1.183 +
   1.184 +    put_page_type(page);
   1.185 +
   1.186 +    ret = 0; /* success */
   1.187 +
   1.188 + out:
   1.189 +    put_page(page);
   1.190 +
   1.191 +    UNLOCK_BIGLOCK(current->domain);
   1.192 +
   1.193 +    return ret;
   1.194 +}
   1.195 +
   1.196 +
   1.197 +
   1.198 +/*************************
   1.199   * Writable Pagetables
   1.200   */
   1.201  
     2.1 --- a/xen/arch/x86/traps.c	Tue Feb 08 03:15:03 2005 +0000
     2.2 +++ b/xen/arch/x86/traps.c	Tue Feb 08 11:07:10 2005 +0000
     2.3 @@ -149,6 +149,11 @@ static inline int do_trap(int trapnr, ch
     2.4      if ( !GUEST_FAULT(regs) )
     2.5          goto xen_fault;
     2.6  
     2.7 +#ifndef NDEBUG
     2.8 +    if ( (ed->arch.traps[trapnr].address == 0) && (ed->domain->id == 0) )
     2.9 +        goto xen_fault;
    2.10 +#endif
    2.11 +
    2.12      ti = current->arch.traps + trapnr;
    2.13      tb->flags = TBF_EXCEPTION;
    2.14      tb->cs    = ti->cs;
    2.15 @@ -314,6 +319,11 @@ asmlinkage int do_page_fault(struct xen_
    2.16      if ( !GUEST_FAULT(regs) )
    2.17          goto xen_fault;
    2.18  
    2.19 +#ifndef NDEBUG
    2.20 +    if ( (ed->arch.traps[TRAP_page_fault].address == 0) && (d->id == 0) )
    2.21 +        goto xen_fault;
    2.22 +#endif
    2.23 +
    2.24      propagate_page_fault(addr, regs->error_code);
    2.25      return 0; 
    2.26  
    2.27 @@ -523,6 +533,12 @@ asmlinkage int do_general_protection(str
    2.28          return 0;
    2.29  #endif
    2.30  
    2.31 +#ifndef NDEBUG
    2.32 +    if ( (ed->arch.traps[TRAP_gp_fault].address == 0) &&
    2.33 +         (ed->domain->id == 0) )
    2.34 +        goto gp_in_kernel;
    2.35 +#endif
    2.36 +
    2.37      /* Pass on GPF as is. */
    2.38      ti = current->arch.traps + 13;
    2.39      tb->flags      = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
    2.40 @@ -838,6 +854,13 @@ long do_fpu_taskswitch(void)
    2.41  }
    2.42  
    2.43  
    2.44 +#if defined(__i386__)
    2.45 +#define DB_VALID_ADDR(_a) \
    2.46 +    ((_a) <= (PAGE_OFFSET - 4))
    2.47 +#elif defined(__x86_64__)
    2.48 +#define DB_VALID_ADDR(_a) \
    2.49 +    ((_a) >= HYPERVISOR_VIRT_END) || ((_a) <= (HYPERVISOR_VIRT_START-8))
    2.50 +#endif
    2.51  long set_debugreg(struct exec_domain *p, int reg, unsigned long value)
    2.52  {
    2.53      int i;
    2.54 @@ -845,22 +868,22 @@ long set_debugreg(struct exec_domain *p,
    2.55      switch ( reg )
    2.56      {
    2.57      case 0: 
    2.58 -        if ( value > (PAGE_OFFSET-4) ) return -EPERM;
    2.59 +        if ( !DB_VALID_ADDR(value) ) return -EPERM;
    2.60          if ( p == current ) 
    2.61              __asm__ ( "mov %0, %%db0" : : "r" (value) );
    2.62          break;
    2.63      case 1: 
    2.64 -        if ( value > (PAGE_OFFSET-4) ) return -EPERM;
    2.65 +        if ( !DB_VALID_ADDR(value) ) return -EPERM;
    2.66          if ( p == current ) 
    2.67              __asm__ ( "mov %0, %%db1" : : "r" (value) );
    2.68          break;
    2.69      case 2: 
    2.70 -        if ( value > (PAGE_OFFSET-4) ) return -EPERM;
    2.71 +        if ( !DB_VALID_ADDR(value) ) return -EPERM;
    2.72          if ( p == current ) 
    2.73              __asm__ ( "mov %0, %%db2" : : "r" (value) );
    2.74          break;
    2.75      case 3:
    2.76 -        if ( value > (PAGE_OFFSET-4) ) return -EPERM;
    2.77 +        if ( !DB_VALID_ADDR(value) ) return -EPERM;
    2.78          if ( p == current ) 
    2.79              __asm__ ( "mov %0, %%db3" : : "r" (value) );
    2.80          break;
     3.1 --- a/xen/arch/x86/x86_32/mm.c	Tue Feb 08 03:15:03 2005 +0000
     3.2 +++ b/xen/arch/x86/x86_32/mm.c	Tue Feb 08 11:07:10 2005 +0000
     3.3 @@ -212,9 +212,10 @@ long do_stack_switch(unsigned long ss, u
     3.4  
     3.5  
     3.6  /* Returns TRUE if given descriptor is valid for GDT or LDT. */
     3.7 -int check_descriptor(unsigned long *d)
     3.8 +int check_descriptor(struct desc_struct *d)
     3.9  {
    3.10 -    unsigned long base, limit, a = d[0], b = d[1];
    3.11 +    unsigned long base, limit;
    3.12 +    u32 a = d->a, b = d->b;
    3.13  
    3.14      /* A not-present descriptor will always fault, so is safe. */
    3.15      if ( !(b & _SEGMENT_P) ) 
    3.16 @@ -298,8 +299,8 @@ int check_descriptor(unsigned long *d)
    3.17              if ( !(b & _SEGMENT_G) )
    3.18                  goto bad; /* too dangerous; too hard to work out... */
    3.19              limit = (limit >> 12) - 1;
    3.20 -            d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
    3.21 -            d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
    3.22 +            d->a &= ~0x0ffff; d->a |= limit & 0x0ffff;
    3.23 +            d->b &= ~0xf0000; d->b |= limit & 0xf0000;
    3.24          }
    3.25      }
    3.26  
    3.27 @@ -310,175 +311,6 @@ int check_descriptor(unsigned long *d)
    3.28  }
    3.29  
    3.30  
    3.31 -void destroy_gdt(struct exec_domain *ed)
    3.32 -{
    3.33 -    int i;
    3.34 -    unsigned long pfn;
    3.35 -
    3.36 -    for ( i = 0; i < 16; i++ )
    3.37 -    {
    3.38 -        if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
    3.39 -            put_page_and_type(&frame_table[pfn]);
    3.40 -        ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
    3.41 -    }
    3.42 -}
    3.43 -
    3.44 -
    3.45 -long set_gdt(struct exec_domain *ed, 
    3.46 -             unsigned long *frames,
    3.47 -             unsigned int entries)
    3.48 -{
    3.49 -    struct domain *d = ed->domain;
    3.50 -    /* NB. There are 512 8-byte entries per GDT page. */
    3.51 -    int i = 0, nr_pages = (entries + 511) / 512;
    3.52 -    struct desc_struct *vgdt;
    3.53 -    unsigned long pfn;
    3.54 -
    3.55 -    /* Check the first page in the new GDT. */
    3.56 -    if ( (pfn = frames[0]) >= max_page )
    3.57 -        goto fail;
    3.58 -
    3.59 -    /* The first page is special because Xen owns a range of entries in it. */
    3.60 -    if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
    3.61 -    {
    3.62 -        /* GDT checks failed: try zapping the Xen reserved entries. */
    3.63 -        if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
    3.64 -            goto fail;
    3.65 -        vgdt = map_domain_mem(pfn << PAGE_SHIFT);
    3.66 -        memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
    3.67 -               NR_RESERVED_GDT_ENTRIES*8);
    3.68 -        unmap_domain_mem(vgdt);
    3.69 -        put_page_and_type(&frame_table[pfn]);
    3.70 -
    3.71 -        /* Okay, we zapped the entries. Now try the GDT checks again. */
    3.72 -        if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
    3.73 -            goto fail;
    3.74 -    }
    3.75 -
    3.76 -    /* Check the remaining pages in the new GDT. */
    3.77 -    for ( i = 1; i < nr_pages; i++ )
    3.78 -        if ( ((pfn = frames[i]) >= max_page) ||
    3.79 -             !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
    3.80 -            goto fail;
    3.81 -
    3.82 -    /* Copy reserved GDT entries to the new GDT. */
    3.83 -    vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
    3.84 -    memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY, 
    3.85 -           gdt_table + FIRST_RESERVED_GDT_ENTRY, 
    3.86 -           NR_RESERVED_GDT_ENTRIES*8);
    3.87 -    unmap_domain_mem(vgdt);
    3.88 -
    3.89 -    /* Tear down the old GDT. */
    3.90 -    destroy_gdt(ed);
    3.91 -
    3.92 -    /* Install the new GDT. */
    3.93 -    for ( i = 0; i < nr_pages; i++ )
    3.94 -        ed->arch.perdomain_ptes[i] =
    3.95 -            mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
    3.96 -
    3.97 -    SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
    3.98 -    SET_GDT_ENTRIES(ed, entries);
    3.99 -
   3.100 -    return 0;
   3.101 -
   3.102 - fail:
   3.103 -    while ( i-- > 0 )
   3.104 -        put_page_and_type(&frame_table[frames[i]]);
   3.105 -    return -EINVAL;
   3.106 -}
   3.107 -
   3.108 -
   3.109 -long do_set_gdt(unsigned long *frame_list, unsigned int entries)
   3.110 -{
   3.111 -    int nr_pages = (entries + 511) / 512;
   3.112 -    unsigned long frames[16];
   3.113 -    long ret;
   3.114 -
   3.115 -    if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) ) 
   3.116 -        return -EINVAL;
   3.117 -    
   3.118 -    if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
   3.119 -        return -EFAULT;
   3.120 -
   3.121 -    LOCK_BIGLOCK(current->domain);
   3.122 -
   3.123 -    if ( (ret = set_gdt(current, frames, entries)) == 0 )
   3.124 -    {
   3.125 -        local_flush_tlb();
   3.126 -        __asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
   3.127 -    }
   3.128 -
   3.129 -    UNLOCK_BIGLOCK(current->domain);
   3.130 -
   3.131 -    return ret;
   3.132 -}
   3.133 -
   3.134 -
   3.135 -long do_update_descriptor(
   3.136 -    unsigned long pa, unsigned long word1, unsigned long word2)
   3.137 -{
   3.138 -    unsigned long *gdt_pent, pfn = pa >> PAGE_SHIFT, d[2];
   3.139 -    struct pfn_info *page;
   3.140 -    struct exec_domain *ed;
   3.141 -    long ret = -EINVAL;
   3.142 -
   3.143 -    d[0] = word1;
   3.144 -    d[1] = word2;
   3.145 -
   3.146 -    LOCK_BIGLOCK(current->domain);
   3.147 -
   3.148 -    if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(d) ) {
   3.149 -        UNLOCK_BIGLOCK(current->domain);
   3.150 -        return -EINVAL;
   3.151 -    }
   3.152 -
   3.153 -    page = &frame_table[pfn];
   3.154 -    if ( unlikely(!get_page(page, current->domain)) ) {
   3.155 -        UNLOCK_BIGLOCK(current->domain);
   3.156 -        return -EINVAL;
   3.157 -    }
   3.158 -
   3.159 -    /* Check if the given frame is in use in an unsafe context. */
   3.160 -    switch ( page->u.inuse.type_info & PGT_type_mask )
   3.161 -    {
   3.162 -    case PGT_gdt_page:
   3.163 -        /* Disallow updates of Xen-reserved descriptors in the current GDT. */
   3.164 -        for_each_exec_domain(current->domain, ed) {
   3.165 -            if ( (l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[0]) == pfn) &&
   3.166 -                 (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
   3.167 -                 (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
   3.168 -                goto out;
   3.169 -        }
   3.170 -        if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
   3.171 -            goto out;
   3.172 -        break;
   3.173 -    case PGT_ldt_page:
   3.174 -        if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
   3.175 -            goto out;
   3.176 -        break;
   3.177 -    default:
   3.178 -        if ( unlikely(!get_page_type(page, PGT_writable_page)) )
   3.179 -            goto out;
   3.180 -        break;
   3.181 -    }
   3.182 -
   3.183 -    /* All is good so make the update. */
   3.184 -    gdt_pent = map_domain_mem(pa);
   3.185 -    memcpy(gdt_pent, d, 8);
   3.186 -    unmap_domain_mem(gdt_pent);
   3.187 -
   3.188 -    put_page_type(page);
   3.189 -
   3.190 -    ret = 0; /* success */
   3.191 -
   3.192 - out:
   3.193 -    put_page(page);
   3.194 -
   3.195 -    UNLOCK_BIGLOCK(current->domain);
   3.196 -
   3.197 -    return ret;
   3.198 -}
   3.199 -
   3.200  #ifdef MEMORY_GUARD
   3.201  
   3.202  void *memguard_init(void *heap_start)
     4.1 --- a/xen/arch/x86/x86_64/entry.S	Tue Feb 08 03:15:03 2005 +0000
     4.2 +++ b/xen/arch/x86/x86_64/entry.S	Tue Feb 08 11:07:10 2005 +0000
     4.3 @@ -28,8 +28,8 @@ ENTRY(hypercall)
     4.4          SAVE_ALL
     4.5          movq  %r10,%rcx
     4.6          andq  $(NR_hypercalls-1),%rax
     4.7 -        leaq  SYMBOL_NAME(hypercall_table)(%rip),%rcx
     4.8 -        callq *(%rcx,%rax,8)
     4.9 +        leaq  SYMBOL_NAME(hypercall_table)(%rip),%rbx
    4.10 +        callq *(%rbx,%rax,8)
    4.11          RESTORE_ALL
    4.12          addq  $8,%rsp
    4.13          popq  %rcx
    4.14 @@ -147,7 +147,7 @@ ENTRY(nmi)
    4.15          SAVE_ALL
    4.16          inb   $0x61,%al
    4.17          movl  %eax,%esi # reason
    4.18 -        movl  %esp,%edi # regs
    4.19 +        movq  %rsp,%rdi # regs
    4.20          call  SYMBOL_NAME(do_nmi)
    4.21  	jmp   restore_all_xen
    4.22  
     5.1 --- a/xen/arch/x86/x86_64/mm.c	Tue Feb 08 03:15:03 2005 +0000
     5.2 +++ b/xen/arch/x86/x86_64/mm.c	Tue Feb 08 11:07:10 2005 +0000
     5.3 @@ -240,99 +240,38 @@ long do_stack_switch(unsigned long ss, u
     5.4  
     5.5  
     5.6  /* Returns TRUE if given descriptor is valid for GDT or LDT. */
     5.7 -int check_descriptor(unsigned long *d)
     5.8 +int check_descriptor(struct desc_struct *d)
     5.9  {
    5.10 -    unsigned long base, limit, a = d[0], b = d[1];
    5.11 +    u32 a = d->a, b = d->b;
    5.12  
    5.13      /* A not-present descriptor will always fault, so is safe. */
    5.14      if ( !(b & _SEGMENT_P) ) 
    5.15          goto good;
    5.16  
    5.17 -    /*
    5.18 -     * We don't allow a DPL of zero. There is no legitimate reason for 
    5.19 -     * specifying DPL==0, and it gets rather dangerous if we also accept call 
    5.20 -     * gates (consider a call gate pointing at another guestos descriptor with 
    5.21 -     * DPL 0 -- this would get the OS ring-0 privileges).
    5.22 -     */
    5.23 -    if ( (b & _SEGMENT_DPL) == 0 )
    5.24 +    /* The guest can only safely be executed in ring 3. */
    5.25 +    if ( (b & _SEGMENT_DPL) != 3 )
    5.26          goto bad;
    5.27  
    5.28 -    if ( !(b & _SEGMENT_S) )
    5.29 -    {
    5.30 -        /*
    5.31 -         * System segment:
    5.32 -         *  1. Don't allow interrupt or trap gates as they belong in the IDT.
    5.33 -         *  2. Don't allow TSS descriptors or task gates as we don't
    5.34 -         *     virtualise x86 tasks.
    5.35 -         *  3. Don't allow LDT descriptors because they're unnecessary and
    5.36 -         *     I'm uneasy about allowing an LDT page to contain LDT
    5.37 -         *     descriptors. In any case, Xen automatically creates the
    5.38 -         *     required descriptor when reloading the LDT register.
    5.39 -         *  4. We allow call gates but they must not jump to a private segment.
    5.40 -         */
    5.41 +    /* Any code or data segment is okay. No base/limit checking. */
    5.42 +    if ( (b & _SEGMENT_S) )
    5.43 +        goto good;
    5.44  
    5.45 -        /* Disallow everything but call gates. */
    5.46 -        if ( (b & _SEGMENT_TYPE) != 0xc00 )
    5.47 -            goto bad;
    5.48 -
    5.49 -#if 0
    5.50 -        /* Can't allow far jump to a Xen-private segment. */
    5.51 -        if ( !VALID_CODESEL(a>>16) )
    5.52 -            goto bad;
    5.53 -#endif
    5.54 +    /* Invalid type 0 is harmless. It is used for 2nd half of a call gate. */
    5.55 +    if ( (b & _SEGMENT_TYPE) == 0x000 )
    5.56 +        goto good;
    5.57  
    5.58 -        /* Reserved bits must be zero. */
    5.59 -        if ( (b & 0xe0) != 0 )
    5.60 -            goto bad;
    5.61 -        
    5.62 -        /* No base/limit check is needed for a call gate. */
    5.63 -        goto good;
    5.64 -    }
    5.65 -    
    5.66 -    /* Check that base is at least a page away from Xen-private area. */
    5.67 -    base  = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
    5.68 -    if ( base >= (PAGE_OFFSET - PAGE_SIZE) )
    5.69 +    /* Everything but a call gate is discarded here. */
    5.70 +    if ( (b & _SEGMENT_TYPE) != 0xc00 )
    5.71          goto bad;
    5.72  
    5.73 -    /* Check and truncate the limit if necessary. */
    5.74 -    limit = (b&0xf0000) | (a&0xffff);
    5.75 -    limit++; /* We add one because limit is inclusive. */
    5.76 -    if ( (b & _SEGMENT_G) )
    5.77 -        limit <<= 12;
    5.78 +    /* Can't allow far jump to a Xen-private segment. */
    5.79 +    if ( !VALID_CODESEL(a>>16) )
    5.80 +        goto bad;
    5.81  
    5.82 -    if ( (b & (_SEGMENT_CODE | _SEGMENT_EC)) == _SEGMENT_EC )
    5.83 -    {
    5.84 -        /*
    5.85 -         * Grows-down limit check. 
    5.86 -         * NB. limit == 0xFFFFF provides no access      (if G=1).
    5.87 -         *     limit == 0x00000 provides 4GB-4kB access (if G=1).
    5.88 -         */
    5.89 -        if ( (base + limit) > base )
    5.90 -        {
    5.91 -            limit = -(base & PAGE_MASK);
    5.92 -            goto truncate;
    5.93 -        }
    5.94 -    }
    5.95 -    else
    5.96 -    {
    5.97 -        /*
    5.98 -         * Grows-up limit check.
    5.99 -         * NB. limit == 0xFFFFF provides 4GB access (if G=1).
   5.100 -         *     limit == 0x00000 provides 4kB access (if G=1).
   5.101 -         */
   5.102 -        if ( ((base + limit) <= base) || 
   5.103 -             ((base + limit) > PAGE_OFFSET) )
   5.104 -        {
   5.105 -            limit = PAGE_OFFSET - base;
   5.106 -        truncate:
   5.107 -            if ( !(b & _SEGMENT_G) )
   5.108 -                goto bad; /* too dangerous; too hard to work out... */
   5.109 -            limit = (limit >> 12) - 1;
   5.110 -            d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
   5.111 -            d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
   5.112 -        }
   5.113 -    }
   5.114 -
   5.115 +    /* Reserved bits must be zero. */
   5.116 +    if ( (b & 0xe0) != 0 )
   5.117 +        goto bad;
   5.118 +        
   5.119   good:
   5.120      return 1;
   5.121   bad:
   5.122 @@ -340,159 +279,6 @@ int check_descriptor(unsigned long *d)
   5.123  }
   5.124  
   5.125  
   5.126 -void destroy_gdt(struct exec_domain *ed)
   5.127 -{
   5.128 -    int i;
   5.129 -    unsigned long pfn;
   5.130 -
   5.131 -    for ( i = 0; i < 16; i++ )
   5.132 -    {
   5.133 -        if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
   5.134 -            put_page_and_type(&frame_table[pfn]);
   5.135 -        ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
   5.136 -    }
   5.137 -}
   5.138 -
   5.139 -
   5.140 -long set_gdt(struct exec_domain *ed, 
   5.141 -             unsigned long *frames,
   5.142 -             unsigned int entries)
   5.143 -{
   5.144 -    struct domain *d = ed->domain;
   5.145 -    /* NB. There are 512 8-byte entries per GDT page. */
   5.146 -    int i = 0, nr_pages = (entries + 511) / 512;
   5.147 -    struct desc_struct *vgdt;
   5.148 -    unsigned long pfn;
   5.149 -
   5.150 -    /* Check the first page in the new GDT. */
   5.151 -    if ( (pfn = frames[0]) >= max_page )
   5.152 -        goto fail;
   5.153 -
   5.154 -    /* The first page is special because Xen owns a range of entries in it. */
   5.155 -    if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
   5.156 -    {
   5.157 -        /* GDT checks failed: try zapping the Xen reserved entries. */
   5.158 -        if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
   5.159 -            goto fail;
   5.160 -        vgdt = map_domain_mem(pfn << PAGE_SHIFT);
   5.161 -        memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
   5.162 -               NR_RESERVED_GDT_ENTRIES*8);
   5.163 -        unmap_domain_mem(vgdt);
   5.164 -        put_page_and_type(&frame_table[pfn]);
   5.165 -
   5.166 -        /* Okay, we zapped the entries. Now try the GDT checks again. */
   5.167 -        if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
   5.168 -            goto fail;
   5.169 -    }
   5.170 -
   5.171 -    /* Check the remaining pages in the new GDT. */
   5.172 -    for ( i = 1; i < nr_pages; i++ )
   5.173 -        if ( ((pfn = frames[i]) >= max_page) ||
   5.174 -             !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
   5.175 -            goto fail;
   5.176 -
   5.177 -    /* Copy reserved GDT entries to the new GDT. */
   5.178 -    vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
   5.179 -    memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY, 
   5.180 -           gdt_table + FIRST_RESERVED_GDT_ENTRY, 
   5.181 -           NR_RESERVED_GDT_ENTRIES*8);
   5.182 -    unmap_domain_mem(vgdt);
   5.183 -
   5.184 -    /* Tear down the old GDT. */
   5.185 -    destroy_gdt(ed);
   5.186 -
   5.187 -    /* Install the new GDT. */
   5.188 -    for ( i = 0; i < nr_pages; i++ )
   5.189 -        ed->arch.perdomain_ptes[i] =
   5.190 -            mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
   5.191 -
   5.192 -    SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
   5.193 -    SET_GDT_ENTRIES(ed, entries);
   5.194 -
   5.195 -    return 0;
   5.196 -
   5.197 - fail:
   5.198 -    while ( i-- > 0 )
   5.199 -        put_page_and_type(&frame_table[frames[i]]);
   5.200 -    return -EINVAL;
   5.201 -}
   5.202 -
   5.203 -
   5.204 -long do_set_gdt(unsigned long *frame_list, unsigned int entries)
   5.205 -{
   5.206 -    int nr_pages = (entries + 511) / 512;
   5.207 -    unsigned long frames[16];
   5.208 -    long ret;
   5.209 -
   5.210 -    if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) ) 
   5.211 -        return -EINVAL;
   5.212 -    
   5.213 -    if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
   5.214 -        return -EFAULT;
   5.215 -
   5.216 -    if ( (ret = set_gdt(current, frames, entries)) == 0 )
   5.217 -    {
   5.218 -        local_flush_tlb();
   5.219 -        __asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
   5.220 -    }
   5.221 -
   5.222 -    return ret;
   5.223 -}
   5.224 -
   5.225 -
   5.226 -long do_update_descriptor(
   5.227 -    unsigned long pa, unsigned long word1, unsigned long word2)
   5.228 -{
   5.229 -    unsigned long *gdt_pent, pfn = pa >> PAGE_SHIFT, d[2];
   5.230 -    struct pfn_info *page;
   5.231 -    long ret = -EINVAL;
   5.232 -
   5.233 -    d[0] = word1;
   5.234 -    d[1] = word2;
   5.235 -
   5.236 -    if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(d) )
   5.237 -        return -EINVAL;
   5.238 -
   5.239 -    page = &frame_table[pfn];
   5.240 -    if ( unlikely(!get_page(page, current->domain)) )
   5.241 -        return -EINVAL;
   5.242 -
   5.243 -    /* Check if the given frame is in use in an unsafe context. */
   5.244 -    switch ( page->u.inuse.type_info & PGT_type_mask )
   5.245 -    {
   5.246 -    case PGT_gdt_page:
   5.247 -        /* Disallow updates of Xen-reserved descriptors in the current GDT. */
   5.248 -        if ( (l1_pgentry_to_pagenr(current->arch.perdomain_ptes[0]) == pfn) &&
   5.249 -             (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
   5.250 -             (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
   5.251 -            goto out;
   5.252 -        if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
   5.253 -            goto out;
   5.254 -        break;
   5.255 -    case PGT_ldt_page:
   5.256 -        if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
   5.257 -            goto out;
   5.258 -        break;
   5.259 -    default:
   5.260 -        if ( unlikely(!get_page_type(page, PGT_writable_page)) )
   5.261 -            goto out;
   5.262 -        break;
   5.263 -    }
   5.264 -
   5.265 -    /* All is good so make the update. */
   5.266 -    gdt_pent = map_domain_mem(pa);
   5.267 -    memcpy(gdt_pent, d, 8);
   5.268 -    unmap_domain_mem(gdt_pent);
   5.269 -
   5.270 -    put_page_type(page);
   5.271 -
   5.272 -    ret = 0; /* success */
   5.273 -
   5.274 - out:
   5.275 -    put_page(page);
   5.276 -    return ret;
   5.277 -}
   5.278 -
   5.279  #ifdef MEMORY_GUARD
   5.280  
   5.281  #define ALLOC_PT(_level) \
     6.1 --- a/xen/include/asm-x86/mm.h	Tue Feb 08 03:15:03 2005 +0000
     6.2 +++ b/xen/include/asm-x86/mm.h	Tue Feb 08 11:07:10 2005 +0000
     6.3 @@ -219,7 +219,7 @@ static inline int get_page_and_type(stru
     6.4      ASSERT(((_p)->count_info & PGC_count_mask) != 0);          \
     6.5      ASSERT(page_get_owner(_p) == (_d))
     6.6  
     6.7 -int check_descriptor(unsigned long *d);
     6.8 +int check_descriptor(struct desc_struct *d);
     6.9  
    6.10  /*
    6.11   * Use currently-executing domain's pagetables on the specified CPUs.
     7.1 --- a/xen/include/asm-x86/multicall.h	Tue Feb 08 03:15:03 2005 +0000
     7.2 +++ b/xen/include/asm-x86/multicall.h	Tue Feb 08 11:07:10 2005 +0000
     7.3 @@ -9,7 +9,23 @@
     7.4  
     7.5  #ifdef __x86_64__
     7.6  
     7.7 -#define do_multicall_call(_call) BUG()
     7.8 +#define do_multicall_call(_call)                         \
     7.9 +    do {                                                 \
    7.10 +        __asm__ __volatile__ (                           \
    7.11 +            "movq  "STR(MULTICALL_op)"(%0),%%rax; "      \
    7.12 +            "andq  $("STR(NR_hypercalls)"-1),%%rax; "    \
    7.13 +            "leaq  "STR(hypercall_table)"(%%rip),%%rdi; "\
    7.14 +            "leaq  (%%rdi,%%rax,8),%%rax; "              \
    7.15 +            "movq  "STR(MULTICALL_arg0)"(%0),%%rdi; "    \
    7.16 +            "movq  "STR(MULTICALL_arg1)"(%0),%%rsi; "    \
    7.17 +            "movq  "STR(MULTICALL_arg2)"(%0),%%rdx; "    \
    7.18 +            "movq  "STR(MULTICALL_arg3)"(%0),%%rcx; "    \
    7.19 +            "movq  "STR(MULTICALL_arg4)"(%0),%%r8; "     \
    7.20 +            "callq *(%%rax); "                           \
    7.21 +            "movq  %%rax,"STR(MULTICALL_result)"(%0); "  \
    7.22 +            : : "b" (_call)                              \
    7.23 +            : "rax", "rdi", "rsi", "rdx", "rcx", "r8" ); \
    7.24 +    } while ( 0 )
    7.25  
    7.26  #else
    7.27