]> xenbits.xensource.com Git - xen.git/commitdiff
bitkeeper revision 1.1159.187.66 (41bf1718JfLUlcF63YjP4sfqtgAPWA)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 14 Dec 2004 16:38:48 +0000 (16:38 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 14 Dec 2004 16:38:48 +0000 (16:38 +0000)
Some more x86/64 progress...

17 files changed:
.rootkeys
xen/arch/x86/boot/x86_64.S
xen/arch/x86/domain.c
xen/arch/x86/traps.c
xen/arch/x86/x86_32/entry.S
xen/arch/x86/x86_64/asm-offsets.c [new file with mode: 0644]
xen/arch/x86/x86_64/mm.c [new file with mode: 0644]
xen/arch/x86/x86_64/xen.lds
xen/include/asm-x86/asm_defns.h [new file with mode: 0644]
xen/include/asm-x86/irq.h
xen/include/asm-x86/multicall.h
xen/include/asm-x86/processor.h
xen/include/asm-x86/uaccess.h
xen/include/asm-x86/x86_32/asm_defns.h
xen/include/asm-x86/x86_32/uaccess.h
xen/include/asm-x86/x86_64/asm_defns.h [new file with mode: 0644]
xen/include/asm-x86/x86_64/uaccess.h

index b8615ff886645644879cbd25776961fbd3110e3b..2d0c24586c881c94e882d0e777c08e799d848d2e 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 40f92331jfOlE7MfKwpdkEb1CEf23g xen/arch/x86/x86_32/seg_fixup.c
 3ddb79bc4nTpGQOe6_-MbyZzkhlhFQ xen/arch/x86/x86_32/usercopy.c
 3ddb79bcOMCu9-5mKpjIh5d0qqBDPg xen/arch/x86/x86_32/xen.lds
+41bf1717Ty3hwN3E9swdu8QfnvGqww xen/arch/x86/x86_64/asm-offsets.c
 40e96d3aLDI-nViMuYneD7VKYlZrVg xen/arch/x86/x86_64/entry.S
+41bf1717XhPz_dNT5OKSjgmbFuWBuA xen/arch/x86/x86_64/mm.c
 40e96d3ahBTZqbTViInnq0lM03vs7A xen/arch/x86/x86_64/usercopy.c
 40e96d3akN3Hu_J5Bk-WXD8OGscrYQ xen/arch/x86/x86_64/xen.lds
 3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile
 40715b2dWe0tDhx9LkLXzTQkvD49RA xen/include/asm-x86/acpi.h
 3ddb79c3l4IiQtf6MS2jIzcd-hJS8g xen/include/asm-x86/apic.h
 3ddb79c3QJYWr8LLGdonLbWmNb9pQQ xen/include/asm-x86/apicdef.h
+41bf17171g_hhz2k4B-fN9LQlODDjQ xen/include/asm-x86/asm_defns.h
 3ddb79c3OiG9eTsi9Dy3F_OkuRAzKA xen/include/asm-x86/atomic.h
 3ddb79c3rM-Ote0Xn6Ytg8Y6YqAG-A xen/include/asm-x86/bitops.h
 3ddb79c3KhTI0F_Iw_hRL9QEyOVK-g xen/include/asm-x86/cache.h
 3ddb79c3mbqEM7QQr3zVq7NiBNhouA xen/include/asm-x86/x86_32/regs.h
 3e7f358aG11EvMI9VJ4_9hD4LUO7rQ xen/include/asm-x86/x86_32/string.h
 3ddb79c3M2n1ROZH6xk3HbyN4CPDqg xen/include/asm-x86/x86_32/uaccess.h
+41bf1717bML6GxpclTWJabiaO5W5vg xen/include/asm-x86/x86_64/asm_defns.h
 404f1b9ceJeGVaPNIENm2FkK0AgEOQ xen/include/asm-x86/x86_64/current.h
 404f1b9fl6AQ_a-T1TDK3fuwTPXmHw xen/include/asm-x86/x86_64/desc.h
 404f1badfXZJZ2sU8sh9PS2EZvd19Q xen/include/asm-x86/x86_64/ldt.h
index b16cde876204100e845ae8fc5dfe37ba6ef725e5..a8253a4ce1adf74204138ed7cc5d88e4a70e7776 100644 (file)
@@ -257,29 +257,22 @@ copy_to_user:
 set_intr_gate:
 die:
 machine_to_phys_mapping:
-.globl copy_from_user, show_registers, __set_fixmap, do_iopl, check_descriptor
+.globl copy_from_user, show_registers, do_iopl
 copy_from_user: 
 show_registers: 
-__set_fixmap: 
 do_iopl: 
-check_descriptor:
-.globl set_gdt, idt_table, copy_user_generic, memcmp, idt_tables, new_thread
-set_gdt:
+.globl idt_table, copy_user_generic, memcmp, idt_tables, new_thread
 idt_table:
 copy_user_generic:
 memcmp:
 idt_tables:
 new_thread:
-.globl switch_to, __get_user_1, paging_init, trap_init
+.globl switch_to, __get_user_1, __get_user_4, __get_user_8, trap_init
 switch_to:
 __get_user_1:
-paging_init:
-trap_init: 
-.globl __get_user_8, zap_low_mappings, set_debugreg,synchronise_pagetables
+__get_user_4:
 __get_user_8:
-zap_low_mappings:
+trap_init: 
+.globl set_debugreg
 set_debugreg:
-synchronise_pagetables:
-.globl destroy_gdt
-destroy_gdt:    
         
index 1881afa3fd42cd7c4d48721f5d2bfb9bf00f1580..964062cb89a426437f6337c8901a20b362f4bae9 100644 (file)
@@ -427,6 +427,8 @@ long do_iopl(domid_t domain, unsigned int new_io_pl)
     return 0;
 }
 
+#endif
+
 unsigned long hypercall_create_continuation(
     unsigned int op, unsigned int nr_args, ...)
 {
@@ -448,11 +450,15 @@ unsigned long hypercall_create_continuation(
     else
     {
         ec       = get_execution_context();
+#if defined(__i386__)
         ec->eax  = op;
         ec->eip -= 2;  /* re-execute 'int 0x82' */
         
         for ( i = 0, preg = &ec->ebx; i < nr_args; i++, preg++ )
             *preg = va_arg(args, unsigned long);
+#else
+        preg = NULL; /* XXX x86/64 */
+#endif
     }
 
     va_end(args);
@@ -460,9 +466,6 @@ unsigned long hypercall_create_continuation(
     return op;
 }
 
-#endif
-
-
 static void relinquish_list(struct domain *d, struct list_head *list)
 {
     struct list_head *ent;
index 842de24582d532e57cef05fd9c621af168b1f1f7..6837a143d3d6055efad813581f24c34b5b00d4de 100644 (file)
@@ -981,4 +981,10 @@ unsigned long do_get_debugreg(int reg)
     return current->thread.debugreg[reg];
 }
 
+#else
+
+asmlinkage void fatal_trap(int trapnr, struct xen_regs *regs)
+{
+}
+
 #endif /* __i386__ */
index a3ed040538c7107ed9f34cecbb41156343bc07d6..d3df231fbb91ea1f35463baba8b32b748749d806 100644 (file)
@@ -56,7 +56,7 @@
 #include <xen/config.h>
 #include <xen/errno.h>
 #include <xen/softirq.h>
-#include <asm/x86_32/asm_defns.h>
+#include <asm/asm_defns.h>
 #include <public/xen.h>
 
 #define GET_CURRENT(reg)   \
diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c
new file mode 100644 (file)
index 0000000..2e6c3b3
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed
+ * to extract and format the required data.
+ */
+
+#include <xen/sched.h>
+
+#define DEFINE(_sym, _val) \
+    __asm__ __volatile__ ( "\n->" #_sym " %0 " #_val : : "i" (_val) )
+#define BLANK() \
+    __asm__ __volatile__ ( "\n->" : : )
+#define OFFSET(_sym, _str, _mem) \
+    DEFINE(_sym, offsetof(_str, _mem));
+
+void __dummy__(void)
+{
+    OFFSET(XREGS_r15, struct xen_regs, r15);
+    OFFSET(XREGS_r14, struct xen_regs, r14);
+    OFFSET(XREGS_r13, struct xen_regs, r13);
+    OFFSET(XREGS_r12, struct xen_regs, r12);
+    OFFSET(XREGS_rbp, struct xen_regs, rbp);
+    OFFSET(XREGS_rbx, struct xen_regs, rbx);
+    OFFSET(XREGS_r11, struct xen_regs, r11);
+    OFFSET(XREGS_r10, struct xen_regs, r10);
+    OFFSET(XREGS_r9, struct xen_regs, r9);
+    OFFSET(XREGS_r8, struct xen_regs, r8);
+    OFFSET(XREGS_rax, struct xen_regs, rax);
+    OFFSET(XREGS_rcx, struct xen_regs, rcx);
+    OFFSET(XREGS_rdx, struct xen_regs, rdx);
+    OFFSET(XREGS_rsi, struct xen_regs, rsi);
+    OFFSET(XREGS_rdi, struct xen_regs, rdi);
+    OFFSET(XREGS_orig_rax, struct xen_regs, orig_rax);
+    OFFSET(XREGS_rip, struct xen_regs, rip);
+    OFFSET(XREGS_cs, struct xen_regs, cs);
+    OFFSET(XREGS_eflags, struct xen_regs, eflags);
+    OFFSET(XREGS_rsp, struct xen_regs, rsp);
+    OFFSET(XREGS_ss, struct xen_regs, ss);
+    BLANK();
+
+    OFFSET(DOMAIN_processor, struct domain, processor);
+    OFFSET(DOMAIN_shared_info, struct domain, shared_info);
+    OFFSET(DOMAIN_event_sel, struct domain, thread.event_selector);
+    OFFSET(DOMAIN_event_addr, struct domain, thread.event_address);
+    OFFSET(DOMAIN_failsafe_sel, struct domain, thread.failsafe_selector);
+    OFFSET(DOMAIN_failsafe_addr, struct domain, thread.failsafe_address);
+    OFFSET(DOMAIN_trap_bounce, struct domain, thread.trap_bounce);
+    OFFSET(DOMAIN_thread_flags, struct domain, thread.flags);
+    BLANK();
+
+    OFFSET(SHINFO_upcall_pending, shared_info_t, 
+           vcpu_data[0].evtchn_upcall_pending);
+    OFFSET(SHINFO_upcall_mask, shared_info_t, 
+           vcpu_data[0].evtchn_upcall_mask);
+    BLANK();
+
+    OFFSET(TRAPBOUNCE_error_code, struct trap_bounce, error_code);
+    OFFSET(TRAPBOUNCE_cr2, struct trap_bounce, cr2);
+    OFFSET(TRAPBOUNCE_flags, struct trap_bounce, flags);
+    OFFSET(TRAPBOUNCE_cs, struct trap_bounce, cs);
+    OFFSET(TRAPBOUNCE_eip, struct trap_bounce, eip);
+    BLANK();
+
+    OFFSET(MULTICALL_op, multicall_entry_t, op);
+    OFFSET(MULTICALL_arg0, multicall_entry_t, args[0]);
+    OFFSET(MULTICALL_arg1, multicall_entry_t, args[1]);
+    OFFSET(MULTICALL_arg2, multicall_entry_t, args[2]);
+    OFFSET(MULTICALL_arg3, multicall_entry_t, args[3]);
+    OFFSET(MULTICALL_arg4, multicall_entry_t, args[4]);
+    OFFSET(MULTICALL_result, multicall_entry_t, args[5]);
+}
diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c
new file mode 100644 (file)
index 0000000..c7bcb17
--- /dev/null
@@ -0,0 +1,455 @@
+/******************************************************************************
+ * arch/x86/x86_64/mm.c
+ * 
+ * Modifications to Linux original are copyright (c) 2004, K A Fraser
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <xen/config.h>
+#include <xen/lib.h>
+#include <xen/init.h>
+#include <xen/mm.h>
+#include <asm/page.h>
+#include <asm/flushtlb.h>
+#include <asm/fixmap.h>
+#include <asm/domain_page.h>
+
+static inline void set_pte_phys(unsigned long vaddr,
+                                l1_pgentry_t entry)
+{
+    l4_pgentry_t *l4ent;
+    l3_pgentry_t *l3ent;
+    l2_pgentry_t *l2ent;
+    l1_pgentry_t *l1ent;
+
+    l4ent = &idle_pg_table[l4_table_offset(vaddr)];
+    l3ent = l4_pgentry_to_l3(*l4ent) + l3_table_offset(vaddr);
+    l2ent = l3_pgentry_to_l2(*l3ent) + l2_table_offset(vaddr);
+    l1ent = l2_pgentry_to_l1(*l2ent) + l1_table_offset(vaddr);
+    *l1ent = entry;
+
+    /* It's enough to flush this one mapping. */
+    __flush_tlb_one(vaddr);
+}
+
+
+void __set_fixmap(enum fixed_addresses idx, 
+                  l1_pgentry_t entry)
+{
+    unsigned long address = fix_to_virt(idx);
+
+    if ( likely(idx < __end_of_fixed_addresses) )
+        set_pte_phys(address, entry);
+    else
+        printk("Invalid __set_fixmap\n");
+}
+
+
+void __init paging_init(void)
+{
+    void *ioremap_pt;
+    int i;
+
+    /* Create page table for ioremap(). */
+    ioremap_pt = (void *)alloc_xenheap_page();
+    clear_page(ioremap_pt);
+    idle_pg_table[IOREMAP_VIRT_START >> L2_PAGETABLE_SHIFT] = 
+        mk_l2_pgentry(__pa(ioremap_pt) | __PAGE_HYPERVISOR);
+
+    /* Create read-only mapping of MPT for guest-OS use. */
+    idle_pg_table[RO_MPT_VIRT_START >> L2_PAGETABLE_SHIFT] =
+        mk_l2_pgentry(l2_pgentry_val(
+            idle_pg_table[RDWR_MPT_VIRT_START >> L2_PAGETABLE_SHIFT]) & 
+                      ~_PAGE_RW);
+
+    /* Set up mapping cache for domain pages. */
+    mapcache = (unsigned long *)alloc_xenheap_page();
+    clear_page(mapcache);
+    idle_pg_table[MAPCACHE_VIRT_START >> L2_PAGETABLE_SHIFT] =
+        mk_l2_pgentry(__pa(mapcache) | __PAGE_HYPERVISOR);
+
+    /* Set up linear page table mapping. */
+    idle_pg_table[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
+        mk_l2_pgentry(__pa(idle_pg_table) | __PAGE_HYPERVISOR);
+
+}
+
+void __init zap_low_mappings(void)
+{
+    idle_pg_table[0] = 0;
+}
+
+
+/*
+ * Allows shooting down of borrowed page-table use on specific CPUs.
+ * Specifically, we borrow page tables when running the idle domain.
+ */
+static void __synchronise_pagetables(void *mask)
+{
+    struct domain *d = current;
+    if ( ((unsigned long)mask & (1<<d->processor)) && is_idle_task(d) )
+        write_ptbase(&d->mm);
+}
+void synchronise_pagetables(unsigned long cpu_mask)
+{
+    __synchronise_pagetables((void *)cpu_mask);
+    smp_call_function(__synchronise_pagetables, (void *)cpu_mask, 1, 1);
+}
+
+long do_stack_switch(unsigned long ss, unsigned long esp)
+{
+    int nr = smp_processor_id();
+    struct tss_struct *t = &init_tss[nr];
+
+    /* We need to do this check as we load and use SS on guest's behalf. */
+    if ( (ss & 3) == 0 )
+        return -EPERM;
+
+    current->thread.guestos_ss = ss;
+    current->thread.guestos_sp = esp;
+    t->ss1  = ss;
+    t->esp1 = esp;
+
+    return 0;
+}
+
+
+/* Returns TRUE if given descriptor is valid for GDT or LDT. */
+int check_descriptor(unsigned long *d)
+{
+    unsigned long base, limit, a = d[0], b = d[1];
+
+    /* A not-present descriptor will always fault, so is safe. */
+    if ( !(b & _SEGMENT_P) ) 
+        goto good;
+
+    /*
+     * We don't allow a DPL of zero. There is no legitimate reason for 
+     * specifying DPL==0, and it gets rather dangerous if we also accept call 
+     * gates (consider a call gate pointing at another guestos descriptor with 
+     * DPL 0 -- this would get the OS ring-0 privileges).
+     */
+    if ( (b & _SEGMENT_DPL) == 0 )
+        goto bad;
+
+    if ( !(b & _SEGMENT_S) )
+    {
+        /*
+         * System segment:
+         *  1. Don't allow interrupt or trap gates as they belong in the IDT.
+         *  2. Don't allow TSS descriptors or task gates as we don't
+         *     virtualise x86 tasks.
+         *  3. Don't allow LDT descriptors because they're unnecessary and
+         *     I'm uneasy about allowing an LDT page to contain LDT
+         *     descriptors. In any case, Xen automatically creates the
+         *     required descriptor when reloading the LDT register.
+         *  4. We allow call gates but they must not jump to a private segment.
+         */
+
+        /* Disallow everything but call gates. */
+        if ( (b & _SEGMENT_TYPE) != 0xc00 )
+            goto bad;
+
+        /* Can't allow far jump to a Xen-private segment. */
+        if ( !VALID_CODESEL(a>>16) )
+            goto bad;
+
+        /* Reserved bits must be zero. */
+        if ( (b & 0xe0) != 0 )
+            goto bad;
+        
+        /* No base/limit check is needed for a call gate. */
+        goto good;
+    }
+    
+    /* Check that base is at least a page away from Xen-private area. */
+    base  = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
+    if ( base >= (PAGE_OFFSET - PAGE_SIZE) )
+        goto bad;
+
+    /* Check and truncate the limit if necessary. */
+    limit = (b&0xf0000) | (a&0xffff);
+    limit++; /* We add one because limit is inclusive. */
+    if ( (b & _SEGMENT_G) )
+        limit <<= 12;
+
+    if ( (b & (_SEGMENT_CODE | _SEGMENT_EC)) == _SEGMENT_EC )
+    {
+        /*
+         * Grows-down limit check. 
+         * NB. limit == 0xFFFFF provides no access      (if G=1).
+         *     limit == 0x00000 provides 4GB-4kB access (if G=1).
+         */
+        if ( (base + limit) > base )
+        {
+            limit = -(base & PAGE_MASK);
+            goto truncate;
+        }
+    }
+    else
+    {
+        /*
+         * Grows-up limit check.
+         * NB. limit == 0xFFFFF provides 4GB access (if G=1).
+         *     limit == 0x00000 provides 4kB access (if G=1).
+         */
+        if ( ((base + limit) <= base) || 
+             ((base + limit) > PAGE_OFFSET) )
+        {
+            limit = PAGE_OFFSET - base;
+        truncate:
+            if ( !(b & _SEGMENT_G) )
+                goto bad; /* too dangerous; too hard to work out... */
+            limit = (limit >> 12) - 1;
+            d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
+            d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
+        }
+    }
+
+ good:
+    return 1;
+ bad:
+    return 0;
+}
+
+
+void destroy_gdt(struct domain *d)
+{
+    int i;
+    unsigned long pfn;
+
+    for ( i = 0; i < 16; i++ )
+    {
+        if ( (pfn = l1_pgentry_to_pagenr(d->mm.perdomain_pt[i])) != 0 )
+            put_page_and_type(&frame_table[pfn]);
+        d->mm.perdomain_pt[i] = mk_l1_pgentry(0);
+    }
+}
+
+
+long set_gdt(struct domain *d, 
+             unsigned long *frames,
+             unsigned int entries)
+{
+    /* NB. There are 512 8-byte entries per GDT page. */
+    int i = 0, nr_pages = (entries + 511) / 512;
+    struct desc_struct *vgdt;
+    unsigned long pfn;
+
+    /* Check the first page in the new GDT. */
+    if ( (pfn = frames[0]) >= max_page )
+        goto fail;
+
+    /* The first page is special because Xen owns a range of entries in it. */
+    if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
+    {
+        /* GDT checks failed: try zapping the Xen reserved entries. */
+        if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
+            goto fail;
+        vgdt = map_domain_mem(pfn << PAGE_SHIFT);
+        memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
+               NR_RESERVED_GDT_ENTRIES*8);
+        unmap_domain_mem(vgdt);
+        put_page_and_type(&frame_table[pfn]);
+
+        /* Okay, we zapped the entries. Now try the GDT checks again. */
+        if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
+            goto fail;
+    }
+
+    /* Check the remaining pages in the new GDT. */
+    for ( i = 1; i < nr_pages; i++ )
+        if ( ((pfn = frames[i]) >= max_page) ||
+             !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
+            goto fail;
+
+    /* Copy reserved GDT entries to the new GDT. */
+    vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
+    memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY, 
+           gdt_table + FIRST_RESERVED_GDT_ENTRY, 
+           NR_RESERVED_GDT_ENTRIES*8);
+    unmap_domain_mem(vgdt);
+
+    /* Tear down the old GDT. */
+    destroy_gdt(d);
+
+    /* Install the new GDT. */
+    for ( i = 0; i < nr_pages; i++ )
+        d->mm.perdomain_pt[i] =
+            mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+
+    SET_GDT_ADDRESS(d, GDT_VIRT_START);
+    SET_GDT_ENTRIES(d, entries);
+
+    return 0;
+
+ fail:
+    while ( i-- > 0 )
+        put_page_and_type(&frame_table[frames[i]]);
+    return -EINVAL;
+}
+
+
+long do_set_gdt(unsigned long *frame_list, unsigned int entries)
+{
+    int nr_pages = (entries + 511) / 512;
+    unsigned long frames[16];
+    long ret;
+
+    if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) ) 
+        return -EINVAL;
+    
+    if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
+        return -EFAULT;
+
+    if ( (ret = set_gdt(current, frames, entries)) == 0 )
+    {
+        local_flush_tlb();
+        __asm__ __volatile__ ("lgdt %0" : "=m" (*current->mm.gdt));
+    }
+
+    return ret;
+}
+
+
+long do_update_descriptor(
+    unsigned long pa, unsigned long word1, unsigned long word2)
+{
+    unsigned long *gdt_pent, pfn = pa >> PAGE_SHIFT, d[2];
+    struct pfn_info *page;
+    long ret = -EINVAL;
+
+    d[0] = word1;
+    d[1] = word2;
+
+    if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(d) )
+        return -EINVAL;
+
+    page = &frame_table[pfn];
+    if ( unlikely(!get_page(page, current)) )
+        return -EINVAL;
+
+    /* Check if the given frame is in use in an unsafe context. */
+    switch ( page->u.inuse.type_info & PGT_type_mask )
+    {
+    case PGT_gdt_page:
+        /* Disallow updates of Xen-reserved descriptors in the current GDT. */
+        if ( (l1_pgentry_to_pagenr(current->mm.perdomain_pt[0]) == pfn) &&
+             (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
+             (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
+            goto out;
+        if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
+            goto out;
+        break;
+    case PGT_ldt_page:
+        if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
+            goto out;
+        break;
+    default:
+        if ( unlikely(!get_page_type(page, PGT_writable_page)) )
+            goto out;
+        break;
+    }
+
+    /* All is good so make the update. */
+    gdt_pent = map_domain_mem(pa);
+    memcpy(gdt_pent, d, 8);
+    unmap_domain_mem(gdt_pent);
+
+    put_page_type(page);
+
+    ret = 0; /* success */
+
+ out:
+    put_page(page);
+    return ret;
+}
+
+#ifdef MEMORY_GUARD
+
+void *memguard_init(void *heap_start)
+{
+    l1_pgentry_t *l1;
+    int i, j;
+
+    /* Round the allocation pointer up to a page boundary. */
+    heap_start = (void *)(((unsigned long)heap_start + (PAGE_SIZE-1)) & 
+                          PAGE_MASK);
+
+    /* Memory guarding is incompatible with super pages. */
+    for ( i = 0; i < (xenheap_phys_end >> L2_PAGETABLE_SHIFT); i++ )
+    {
+        l1 = (l1_pgentry_t *)heap_start;
+        heap_start = (void *)((unsigned long)heap_start + PAGE_SIZE);
+        for ( j = 0; j < ENTRIES_PER_L1_PAGETABLE; j++ )
+            l1[j] = mk_l1_pgentry((i << L2_PAGETABLE_SHIFT) |
+                                   (j << L1_PAGETABLE_SHIFT) | 
+                                  __PAGE_HYPERVISOR);
+        idle_pg_table[i] = idle_pg_table[i + l2_table_offset(PAGE_OFFSET)] =
+            mk_l2_pgentry(virt_to_phys(l1) | __PAGE_HYPERVISOR);
+    }
+
+    return heap_start;
+}
+
+static void __memguard_change_range(void *p, unsigned long l, int guard)
+{
+    l1_pgentry_t *l1;
+    l2_pgentry_t *l2;
+    unsigned long _p = (unsigned long)p;
+    unsigned long _l = (unsigned long)l;
+
+    /* Ensure we are dealing with a page-aligned whole number of pages. */
+    ASSERT((_p&PAGE_MASK) != 0);
+    ASSERT((_l&PAGE_MASK) != 0);
+    ASSERT((_p&~PAGE_MASK) == 0);
+    ASSERT((_l&~PAGE_MASK) == 0);
+
+    while ( _l != 0 )
+    {
+        l2  = &idle_pg_table[l2_table_offset(_p)];
+        l1  = l2_pgentry_to_l1(*l2) + l1_table_offset(_p);
+        if ( guard )
+            *l1 = mk_l1_pgentry(l1_pgentry_val(*l1) & ~_PAGE_PRESENT);
+        else
+            *l1 = mk_l1_pgentry(l1_pgentry_val(*l1) | _PAGE_PRESENT);
+        _p += PAGE_SIZE;
+        _l -= PAGE_SIZE;
+    }
+}
+
+void memguard_guard_range(void *p, unsigned long l)
+{
+    __memguard_change_range(p, l, 1);
+    local_flush_tlb();
+}
+
+void memguard_unguard_range(void *p, unsigned long l)
+{
+    __memguard_change_range(p, l, 0);
+}
+
+int memguard_is_guarded(void *p)
+{
+    l1_pgentry_t *l1;
+    l2_pgentry_t *l2;
+    unsigned long _p = (unsigned long)p;
+    l2  = &idle_pg_table[l2_table_offset(_p)];
+    l1  = l2_pgentry_to_l1(*l2) + l1_table_offset(_p);
+    return !(l1_pgentry_val(*l1) & _PAGE_PRESENT);
+}
+
+#endif
index 4763fdf55ae827696464ed804f6560ee799dfe05..8a6b3a27ac699cd3ca09d89a5a0d10c2560975ba 100644 (file)
@@ -28,6 +28,11 @@ SECTIONS
   __ex_table : { *(__ex_table) } :text
   __stop___ex_table = .;
 
+  . = ALIGN(16);                /* Pre-exception table */
+  __start___pre_ex_table = .;
+  __pre_ex_table : { *(__pre_ex_table) } :text
+  __stop___pre_ex_table = .;
+
   __start___ksymtab = .;       /* Kernel symbol table */
   __ksymtab : { *(__ksymtab) } :text
   __stop___ksymtab = .;
diff --git a/xen/include/asm-x86/asm_defns.h b/xen/include/asm-x86/asm_defns.h
new file mode 100644 (file)
index 0000000..0fb3e44
--- /dev/null
@@ -0,0 +1,18 @@
+
+#ifndef __X86_ASM_DEFNS_H__
+#define __X86_ASM_DEFNS_H__
+
+/* NB. Auto-generated from arch/.../asm-offsets.c */
+#include <asm/asm-offsets.h>
+#include <asm/processor.h>
+
+#define __STR(x) #x
+#define STR(x) __STR(x)
+
+#ifdef __x86_64__
+#include <asm/x86_64/asm_defns.h>
+#else
+#include <asm/x86_32/asm_defns.h>
+#endif
+
+#endif /* __X86_ASM_DEFNS_H__ */
index b07fef7809156867aca2116d3b22ddbd1d4f6cf1..27792826598d5773d5048596df10483cd0e8c3cc 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <xen/config.h>
 #include <asm/atomic.h>
-#include <asm/x86_32/asm_defns.h>
+#include <asm/asm_defns.h>
 
 extern void disable_irq(unsigned int);
 extern void disable_irq_nosync(unsigned int);
index e1a7770354de0b86548845e400d107ae1aecb6b7..d03ac9ffb14841cae67ddd378521d4af612bc488 100644 (file)
@@ -5,7 +5,13 @@
 #ifndef __ASM_X86_MULTICALL_H__
 #define __ASM_X86_MULTICALL_H__
 
-#include <asm-x86/x86_32/asm_defns.h>
+#include <asm/asm_defns.h>
+
+#ifdef __x86_64__
+
+#define do_multicall_call(_call) BUG()
+
+#else
 
 #define do_multicall_call(_call)                       \
     do {                                               \
@@ -23,4 +29,6 @@
             : : "b" (_call) : "eax", "ecx", "edx" );   \
     } while ( 0 )
 
+#endif
+
 #endif /* __ASM_X86_MULTICALL_H__ */
index 6d3cf3036a5bed22eab3f6a1ba5d60f9d62247b7..ae5b13b7d1a3900112e0565364e068ab65c92372 100644 (file)
@@ -254,18 +254,18 @@ static inline unsigned int cpuid_edx(unsigned int op)
 })
 
 #define write_cr0(x) \
-       __asm__("mov"__OS" %0,%%cr0": :"r" (x));
+       __asm__("mov"__OS" %0,%%cr0": :"r" ((unsigned long)x));
 
 #define read_cr4() ({ \
-       unsigned int __dummy; \
+       unsigned long __dummy; \
        __asm__( \
-               "movl %%cr4,%0\n\t" \
+               "mov"__OS" %%cr4,%0\n\t" \
                :"=r" (__dummy)); \
        __dummy; \
 })
 
 #define write_cr4(x) \
-       __asm__("movl %0,%%cr4": :"r" (x));
+       __asm__("mov"__OS" %0,%%cr4": :"r" ((unsigned long)x));
 
 /*
  * Save the cr4 feature set we're using (ie
@@ -290,7 +290,7 @@ static inline void clear_in_cr4 (unsigned long mask)
     mmu_cr4_features &= ~mask;
     __asm__("mov"__OS" %%cr4,%%"__OP"ax\n\t"
             "and"__OS" %0,%%"__OP"ax\n\t"
-            "movl"__OS" %%"__OP"ax,%%cr4\n"
+            "mov"__OS" %%"__OP"ax,%%cr4\n"
             : : "irg" (~mask)
             :"ax");
 }
index 52a8b25c56c06c63ab4d445bb92619ecbc677b93..46c02ecef4910906b5fc723079dac2825a08945f 100644 (file)
@@ -1,6 +1,32 @@
 
+#ifndef __X86_UACCESS_H__
+#define __X86_UACCESS_H__
+
 #ifdef __x86_64__
 #include <asm/x86_64/uaccess.h>
 #else
 #include <asm/x86_32/uaccess.h>
 #endif
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry
+{
+       unsigned long insn, fixup;
+};
+
+extern unsigned long search_exception_table(unsigned long);
+extern void sort_exception_tables(void);
+
+#endif /* __X86_UACCESS_H__ */
index 8231bb2dec0974abba974a9fc47425f6226e56ca..e11ea349646a3f7f78a974ddf4a08e9eebe01b20 100644 (file)
@@ -1,12 +1,5 @@
-#ifndef __ASM_DEFNS_H__
-#define __ASM_DEFNS_H__
-
-/* NB. Auto-generated from arch/.../asm-offsets.c */
-#include <asm/asm-offsets.h>
-#include <asm/processor.h>
-
-#define __STR(x) #x
-#define STR(x) __STR(x)
+#ifndef __X86_32_ASM_DEFNS_H__
+#define __X86_32_ASM_DEFNS_H__
 
 /* Maybe auto-generate the following two cases (quoted vs. unquoted). */
 #ifndef __ASSEMBLY__
@@ -85,4 +78,4 @@
 
 #endif
 
-#endif /* __ASM_DEFNS_H__ */
+#endif /* __X86_32_ASM_DEFNS_H__ */
index 650492d59eee32cbd62d0e8486e3946385b7dd3d..b202a1a12b9eee26572f06999545beafae49972a 100644 (file)
@@ -69,27 +69,6 @@ extern struct movsl_mask {
 #define array_access_ok(type,addr,count,size) \
     (likely(count < (~0UL/size)) && access_ok(type,addr,count*size))
 
-/*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue.  No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
- *
- * All the routines below use bits of fixup code that are out of line
- * with the main instruction path.  This means when everything is well,
- * we don't even have to jump over them.  Further, they do not intrude
- * on our cache or tlb entries.
- */
-
-struct exception_table_entry
-{
-       unsigned long insn, fixup;
-};
-
-extern unsigned long search_exception_table(unsigned long);
-extern void sort_exception_tables(void);
-
 /**
  * get_user: - Get a simple variable from user space.
  * @x:   Variable to store result.
diff --git a/xen/include/asm-x86/x86_64/asm_defns.h b/xen/include/asm-x86/x86_64/asm_defns.h
new file mode 100644 (file)
index 0000000..fa0b978
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __X86_64_ASM_DEFNS_H__
+#define __X86_64_ASM_DEFNS_H__
+
+#define SAVE_ALL(_r) ""
+
+#endif /* __X86_64_ASM_DEFNS_H__ */
index be49ff870bd4268a6ac2b895aec7dd3d052e5897..f965c87d321e0774c75e1d5d51dc329a5ac3bbcf 100644 (file)
 
 #define access_ok(type, addr, size) (__range_not_ok(addr,size) == 0)
 
+#define array_access_ok(type,addr,count,size)                    \
+    (likely(sizeof(count) <= 4) /* disallow 64-bit counts */ &&  \
+     access_ok(type,addr,count*size))
+
 extern inline int verify_area(int type, const void __user * addr, unsigned long size)
 {
        return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
 
-
-/*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue.  No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
- *
- * All the routines below use bits of fixup code that are out of line
- * with the main instruction path.  This means when everything is well,
- * we don't even have to jump over them.  Further, they do not intrude
- * on our cache or tlb entries.
- */
-
-struct exception_table_entry
-{
-       unsigned long insn, fixup;
-};
-
-
 /*
  * These are the main single-value transfer routines.  They automatically
  * use the right size if we just have the right pointer type.