debuggers.hg
changeset 3754: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
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 - 5.42 - /* Disallow everything but call gates. */ 5.43 - if ( (b & _SEGMENT_TYPE) != 0xc00 ) 5.44 - goto bad; 5.45 + /* Any code or data segment is okay. No base/limit checking. */ 5.46 + if ( (b & _SEGMENT_S) ) 5.47 + goto good; 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