bitkeeper revision 1.485 (3f81b19fL5Y4lVlRaEpJI9r_IZlDcw)
authoriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Mon, 6 Oct 2003 18:17:03 +0000 (18:17 +0000)
committeriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Mon, 6 Oct 2003 18:17:03 +0000 (18:17 +0000)
Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno/users/rn212/xeno.mini
into labyrinth.cl.cam.ac.uk:/auto/anfs/scratch/labyrinth/iap10/xeno-clone/xeno.bk

1  2 
extras/mini-os/h/os.h
extras/mini-os/kernel.c
extras/mini-os/traps.c

index 2645bea9549f0b8cacc3b4adb4959d8423311348,0000000000000000000000000000000000000000..9578b8f5b4481eaae378a60d22ae35adef6c6f4b
mode 100644,000000..100644
--- /dev/null
@@@ -1,270 -1,0 +1,274 @@@
 +/******************************************************************************
 + * os.h
 + * 
 + * random collection of macros and definition
 + */
 +
 +#ifndef _OS_H_
 +#define _OS_H_
 +
 +
 +#define NULL 0
 +
 +/*
 + * These are the segment descriptors provided for us by the hypervisor.
 + * For now, these are hardwired -- guest OSes cannot update the GDT
 + * or LDT.
 + * 
 + * It shouldn't be hard to support descriptor-table frobbing -- let me 
 + * know if the BSD or XP ports require flexibility here.
 + */
 +
 +
 +/*
 + * these are also defined in hypervisor-if.h but can't be pulled in as
 + * they are used in start of day assembly. Need to clean up the .h files
 + * a bit more...
 + */
 +
 +#ifndef FLAT_RING1_CS
 +#define FLAT_RING1_CS         0x0819
 +#define FLAT_RING1_DS         0x0821
 +#define FLAT_RING3_CS         0x082b
 +#define FLAT_RING3_DS         0x0833
 +#endif
 +
 +#define __KERNEL_CS        FLAT_RING1_CS
 +#define __KERNEL_DS        FLAT_RING1_DS
 +
 +/* Everything below this point is not included by assembler (.S) files. */
 +#ifndef __ASSEMBLY__
 +
 +#include <types.h>
 +#include <hypervisor-ifs/hypervisor-if.h>
 +
 +
 +/* this struct defines the way the registers are stored on the 
 +   stack during an exception or interrupt. */
 +struct pt_regs {
 +      long ebx;
 +      long ecx;
 +      long edx;
 +      long esi;
 +      long edi;
 +      long ebp;
 +      long eax;
 +      int  xds;
 +      int  xes;
 +      long orig_eax;
 +      long eip;
 +      int  xcs;
 +      long eflags;
 +      long esp;
 +      int  xss;
 +};
 +
++/* some function prototypes */
++void trap_init(void);
++void dump_regs(struct pt_regs *regs);
++
 +
 +/*
 + * STI/CLI equivalents. These basically set and clear the virtual
 + * event_enable flag in teh shared_info structure. Note that when
 + * the enable bit is set, there may be pending events to be handled.
 + * We may therefore call into do_hypervisor_callback() directly.
 + */
 +#define unlikely(x)  __builtin_expect((x),0)
 +#define __save_flags(x)                                                       \
 +do {                                                                          \
 +    (x) = test_bit(EVENTS_MASTER_ENABLE_BIT,                                  \
 +                   &HYPERVISOR_shared_info->events_mask);                     \
 +    barrier();                                                                \
 +} while (0)
 +
 +#define __restore_flags(x)                                                    \
 +do {                                                                          \
 +    shared_info_t *_shared = HYPERVISOR_shared_info;                          \
 +    if (x) set_bit(EVENTS_MASTER_ENABLE_BIT, &_shared->events_mask);          \
 +    barrier();                                                                \
 +    if ( unlikely(_shared->events) && (x) ) do_hypervisor_callback(NULL);     \
 +} while (0)
 +
 +#define __cli()                                                               \
 +do {                                                                          \
 +    clear_bit(EVENTS_MASTER_ENABLE_BIT, &HYPERVISOR_shared_info->events_mask);\
 +    barrier();                                                                \
 +} while (0)
 +
 +#define __sti()                                                               \
 +do {                                                                          \
 +    shared_info_t *_shared = HYPERVISOR_shared_info;                          \
 +    set_bit(EVENTS_MASTER_ENABLE_BIT, &_shared->events_mask);                 \
 +    barrier();                                                                \
 +    if ( unlikely(_shared->events) ) do_hypervisor_callback(NULL);            \
 +} while (0)
 +#define cli() __cli()
 +#define sti() __sti()
 +#define save_flags(x) __save_flags(x)
 +#define restore_flags(x) __restore_flags(x)
 +#define save_and_cli(x) __save_and_cli(x)
 +#define save_and_sti(x) __save_and_sti(x)
 +
 +
 +
 +/* This is a barrier for the compiler only, NOT the processor! */
 +#define barrier() __asm__ __volatile__("": : :"memory")
 +
 +#define LOCK_PREFIX ""
 +#define LOCK ""
 +#define ADDR (*(volatile long *) addr)
 +/*
 + * Make sure gcc doesn't try to be clever and move things around
 + * on us. We need to use _exactly_ the address the user gave us,
 + * not some alias that contains the same information.
 + */
 +typedef struct { volatile int counter; } atomic_t;
 +
 +
 +/*
 + * This XCHG macro is straight from Linux. It is gross.
 + */
 +#define xchg(ptr,v) \
 +        ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
 +struct __xchg_dummy { unsigned long a[100]; };
 +#define __xg(x) ((struct __xchg_dummy *)(x))
 +static inline unsigned long __xchg(unsigned long x, volatile void * ptr,
 +                                   int size)
 +{
 +    switch (size) {
 +    case 1:
 +        __asm__ __volatile__("xchgb %b0,%1"
 +                             :"=q" (x)
 +                             :"m" (*__xg(ptr)), "0" (x)
 +                             :"memory");
 +        break;
 +    case 2:
 +        __asm__ __volatile__("xchgw %w0,%1"
 +                             :"=r" (x)
 +                             :"m" (*__xg(ptr)), "0" (x)
 +                             :"memory");
 +        break;
 +    case 4:
 +        __asm__ __volatile__("xchgl %0,%1"
 +                             :"=r" (x)
 +                             :"m" (*__xg(ptr)), "0" (x)
 +                             :"memory");
 +        break;
 +    }
 +    return x;
 +}
 +
 +/**
 + * test_and_clear_bit - Clear a bit and return its old value
 + * @nr: Bit to set
 + * @addr: Address to count from
 + *
 + * This operation is atomic and cannot be reordered.  
 + * It also implies a memory barrier.
 + */
 +static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
 +{
 +        int oldbit;
 +
 +        __asm__ __volatile__( LOCK_PREFIX
 +                "btrl %2,%1\n\tsbbl %0,%0"
 +                :"=r" (oldbit),"=m" (ADDR)
 +                :"Ir" (nr) : "memory");
 +        return oldbit;
 +}
 +
 +static __inline__ int constant_test_bit(int nr, const volatile void * addr)
 +{
 +    return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
 +}
 +
 +static __inline__ int variable_test_bit(int nr, volatile void * addr)
 +{
 +    int oldbit;
 +    
 +    __asm__ __volatile__(
 +        "btl %2,%1\n\tsbbl %0,%0"
 +        :"=r" (oldbit)
 +        :"m" (ADDR),"Ir" (nr));
 +    return oldbit;
 +}
 +
 +#define test_bit(nr,addr) \
 +(__builtin_constant_p(nr) ? \
 + constant_test_bit((nr),(addr)) : \
 + variable_test_bit((nr),(addr)))
 +
 +
 +/**
 + * set_bit - Atomically set a bit in memory
 + * @nr: the bit to set
 + * @addr: the address to start counting from
 + *
 + * This function is atomic and may not be reordered.  See __set_bit()
 + * if you do not require the atomic guarantees.
 + * Note that @nr may be almost arbitrarily large; this function is not
 + * restricted to acting on a single-word quantity.
 + */
 +static __inline__ void set_bit(int nr, volatile void * addr)
 +{
 +        __asm__ __volatile__( LOCK_PREFIX
 +                "btsl %1,%0"
 +                :"=m" (ADDR)
 +                :"Ir" (nr));
 +}
 +
 +/**
 + * clear_bit - Clears a bit in memory
 + * @nr: Bit to clear
 + * @addr: Address to start counting from
 + *
 + * clear_bit() is atomic and may not be reordered.  However, it does
 + * not contain a memory barrier, so if it is used for locking purposes,
 + * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
 + * in order to ensure changes are visible on other processors.
 + */
 +static __inline__ void clear_bit(int nr, volatile void * addr)
 +{
 +        __asm__ __volatile__( LOCK_PREFIX
 +                "btrl %1,%0"
 +                :"=m" (ADDR)
 +                :"Ir" (nr));
 +}
 +
 +/**
 + * atomic_inc - increment atomic variable
 + * @v: pointer of type atomic_t
 + * 
 + * Atomically increments @v by 1.  Note that the guaranteed
 + * useful range of an atomic_t is only 24 bits.
 + */ 
 +static __inline__ void atomic_inc(atomic_t *v)
 +{
 +        __asm__ __volatile__(
 +                LOCK "incl %0"
 +                :"=m" (v->counter)
 +                :"m" (v->counter));
 +}
 +
 +
 +/* useful hypervisor macros */
 +
 +struct desc_struct {
 +        unsigned long a,b;
 +};
 +extern struct desc_struct default_ldt[];
 +
 +#define asmlinkage        __attribute__((regparm(0)))
 +
 +/*
 + * some random linux macros
 + */
 +
 +#define rdtscll(val) \
 +     __asm__ __volatile__("rdtsc" : "=A" (val))
 +
 +
 +#endif /* !__ASSEMBLY__ */
 +
 +#endif /* _OS_H_ */
index 6486fac119357354c8aab16b60b13a9f5a27c324,0000000000000000000000000000000000000000..196d8612c3f3014bef32860c9ced354f850cd95b
mode 100644,000000..100644
--- /dev/null
@@@ -1,126 -1,0 +1,136 @@@
- /* default exit event handler */
 +/******************************************************************************
 + * kernel.c
 + * 
 + * Assorted crap goes here, including the initial C entry point, jumped at
 + * from head.S.
 + */
 +
 +#include <os.h>
 +#include <hypervisor.h>
 +#include <mm.h>
 +#include <events.h>
 +#include <time.h>
 +#include <types.h>
 +#include <lib.h>
 +
 +/*
 + * Shared page for communicating with the hypervisor.
 + * Events flags go here, for example.
 + */
 +shared_info_t *HYPERVISOR_shared_info;
 +
 +/*
 + * This structure contains start-of-day info, such as pagetable base pointer,
 + * address of the shared_info structure, and things like that.
 + */
 +union start_info_union start_info_union;
 +
 +/*
 + * Just allocate the kernel stack here. SS:ESP is set up to point here
 + * in head.S.
 + */
 +char stack[8192];
 +
 +
 +/* Assembler interface fns in entry.S. */
 +void hypervisor_callback(void);
 +void failsafe_callback(void);
 +
- extern void trap_init(void);
++/* default event handlers */
 +static void exit_handler(int ev, struct pt_regs *regs);
++static void debug_handler(int ev, struct pt_regs *regs);
 +
 +
 +/*
 + * INITIAL C ENTRY POINT.
 + */
 +void start_kernel(start_info_t *si)
 +{
 +    int i;
 +
 +    /* Copy the start_info struct to a globally-accessible area. */
 +    memcpy(&start_info, si, sizeof(*si));
 +
 +    /* Grab the shared_info pointer and put it in a safe place. */
 +    HYPERVISOR_shared_info = start_info.shared_info;
 +
 +    /* Set up event and failsafe callback addresses. */
 +    HYPERVISOR_set_callbacks(
 +        __KERNEL_CS, (unsigned long)hypervisor_callback,
 +        __KERNEL_CS, (unsigned long)failsafe_callback);
 +
 +
 +    trap_init();
 +
 +
 +    /* ENABLE EVENT DELIVERY. This is disabled at start of day. */
 +    __sti();
 +    
 +    /* print out some useful information  */
 +    printk("Xeno Minimal OS!\n");
 +    printk("start_info:   %p\n",  si);
 +    printk("  nr_pages:   %lu",   si->nr_pages);
 +    printk("  shared_inf: %p\n",  si->shared_info);
 +    printk("  pt_base:    %p",    (void *)si->pt_base); 
 +    printk("  mod_start:  0x%lx\n", si->mod_start);
 +    printk("  mod_len:    %lu\n", si->mod_len); 
 +    printk("  net_rings: ");
 +    for (i = 0; i < MAX_DOMAIN_VIFS; i++) {
 +        printk(" %lx", si->net_rings[i]);
 +    }; printk("\n");
 +    printk("  blk_ring:   0x%lx\n", si->blk_ring);
 +    printk("  dom_id:     %d\n",  si->dom_id);
 +    printk("  flags:      0x%lx\n", si->flags);
 +    printk("  cmd_line:   %s\n",  si->cmd_line ? (const char *)si->cmd_line : "NULL");
 +
 +
 +    /*
 +     * If used for porting another OS, start here to figure out your
 +     * guest os entry point. Otherwise continue below...
 +     */
 +
 +    /* init memory management */
 +    init_mm();
 +
 +    /* set up events */
 +    init_events();
 +
 +    /* install some handlers */
 +    add_ev_action(EV_DIE, &exit_handler);
 +    enable_ev_action(EV_DIE);
 +    enable_hypervisor_event(EV_DIE);
 +
++    add_ev_action(EV_DEBUG, &debug_handler);
++    enable_ev_action(EV_DEBUG);
++    enable_hypervisor_event(EV_DEBUG);
++
 +    /* init time and timers */
 +    init_time();
 +
 +    /* do nothing */
 +    for ( ; ; ) HYPERVISOR_yield();
 +}
 +
 +
 +/*
 + * do_exit: This is called whenever an IRET fails in entry.S.
 + * This will generally be because an application has got itself into
 + * a really bad state (probably a bad CS or SS). It must be killed.
 + * Of course, minimal OS doesn't have applications :-)
 + */
 +
 +void do_exit(void)
 +{
 +    printk("do_exit called!\n");
 +    for ( ;; ) ;
 +}
 +static void exit_handler(int ev, struct pt_regs *regs) {
 +    do_exit();
 +}
 +
++/*
++ * a debug handler to print out some state from the guest
++ */
++static void debug_handler(int ev, struct pt_regs *regs) {
++    dump_regs(regs);
++}
index 6352559c0f2447dabf19a6a619fa9b203eef8f5a,0000000000000000000000000000000000000000..8dec10c5811c01ce4374b38f13e6139a8929a28e
mode 100644,000000..100644
--- /dev/null
@@@ -1,231 -1,0 +1,258 @@@
- void dump_regs(struct pt_regs *regs) {
-   printk("Register dump:");
-   printk("ebx: \t 0x%lx",      regs->ebx);
-   printk("ecx: \t 0x%lx",      regs->ecx);
-   printk("edx: \t 0x%lx",      regs->edx);
-   printk("esi: \t 0x%lx",      regs->esi);
-   printk("edi: \t 0x%lx",      regs->edi);
-   printk("ebp: \t 0x%lx",      regs->ebp);
-   printk("eax: \t 0x%lx",      regs->eax);
-   printk("xds: \t 0x%x",      regs->xds);
-   printk("xes: \t 0x%x",      regs->xes);
-   printk("orig_eax: \t 0x%lx", regs->orig_eax);
-   printk("eip: \t 0x%lx",      regs->eip);
-   printk("xcs: \t 0x%x",      regs->xcs);
-   printk("eflags: \t 0x%lx",   regs->eflags);
-   printk("esp: \t 0x%lx",      regs->esp);
-   printk("xss: \t 0x%x",      regs->xss);
- };
 +
 +#include <os.h>
 +#include <hypervisor.h>
++#include <mm.h>
 +#include <lib.h>
 +
 +/*
 + * These are assembler stubs in entry.S.
 + * They are the actual entry points for virtual exceptions.
 + */
 +void divide_error(void);
 +void debug(void);
 +void int3(void);
 +void overflow(void);
 +void bounds(void);
 +void invalid_op(void);
 +void device_not_available(void);
 +void double_fault(void);
 +void coprocessor_segment_overrun(void);
 +void invalid_TSS(void);
 +void segment_not_present(void);
 +void stack_segment(void);
 +void general_protection(void);
 +void page_fault(void);
 +void coprocessor_error(void);
 +void simd_coprocessor_error(void);
 +void alignment_check(void);
 +void spurious_interrupt_bug(void);
 +void machine_check(void);
 +
 +
 +extern void do_exit(void);
 +
 +int kstack_depth_to_print = 24;
++#define THREAD_SIZE (2*PAGE_SIZE)
 +
 +static inline int kernel_text_address(unsigned long addr)
 +{
 +    return ( (addr >> 20) > 0x800 && (addr >> 20) < 0x804 );
 +}
 +
 +void show_trace(unsigned long * stack)
 +{
 +    int i;
 +    unsigned long addr;
 +
 +    if (!stack)
 +        stack = (unsigned long*)&stack;
 +
 +    printk("Call Trace: ");
 +    i = 1;
 +    while (((long) stack & (4095)) != 0) {
 +        addr = *stack++;
 +        if (kernel_text_address(addr)) {
 +            printf("0x%lx", addr);
 +            i++;
 +        }
 +    }
 +    printk("\n");
 +}
 +
++void show_stack(unsigned long * esp)
++{
++      unsigned long *stack;
++      int i;
++
++      if(esp==NULL)
++              esp=(unsigned long*)&esp;
++
++      stack = esp;
++      for(i=0; i < kstack_depth_to_print; i++) {
++              if (((long) stack & (THREAD_SIZE-1)) == 0)
++                      break;
++              printk("%08lx ", *stack++);
++      }
++      printk("\n");
++      show_trace(esp);
++}
++
++void dump_regs(struct pt_regs *regs)
++{
++      int in_kernel = 1;
++      unsigned long esp;
++      unsigned short ss;
++
++      esp = (unsigned long) (&regs->esp);
++      ss = __KERNEL_DS;
++      if (regs->xcs & 2) {
++              in_kernel = 0;
++              esp = regs->esp;
++              ss = regs->xss & 0xffff;
++      }
++      printf("EIP:    %04x:[<%08lx>]\n",
++             0xffff & regs->xcs, regs->eip);
++      printf("EFLAGS: %08lx\n",regs->eflags);
++      printf("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
++              regs->eax, regs->ebx, regs->ecx, regs->edx);
++      printf("esi: %08lx   edi: %08lx   ebp: %08lx   esp: %08lx\n",
++              regs->esi, regs->edi, regs->ebp, esp);
++      printf("ds: %04x   es: %04x   ss: %04x\n",
++              regs->xds & 0xffff, regs->xes & 0xffff, ss);
++      printf("\n");
++}     
++
 +
 +static inline void dump_code(unsigned eip)
 +{
 +  unsigned *ptr = (unsigned *)eip;
 +  int x;
 +
 +  printk("Bytes at eip:\n");
 +  for (x = -4; x < 5; x++)
 +      printf("%x", ptr[x]);
 +}
 +
 +
 +/*
 + * C handlers here have their parameter-list constructed by the
 + * assembler stubs above. Each one gets a pointer to a list
 + * of register values (to be restored at end of exception).
 + * Some will also receive an error code -- this is the code that
 + * was generated by the processor for the underlying real exception. 
 + * 
 + * Note that the page-fault exception is special. It also receives
 + * the faulting linear address. Normally this would be found in
 + * register CR2, but that is not accessible in a virtualised OS.
 + */
 +
 +static void inline do_trap(int trapnr, char *str,
 +                         struct pt_regs * regs, long error_code)
 +{
 +  printk("FATAL:  Unhandled Trap (see mini-os:traps.c)");
 +  printf("%d %s", trapnr, str);
 +  dump_regs(regs);
 +  show_trace((void *)regs->esp);
 +  dump_code(regs->eip);
 +
 +  do_exit();
 +}
 +
 +#define DO_ERROR(trapnr, str, name) \
 +void do_##name(struct pt_regs * regs, long error_code) \
 +{ \
 +      do_trap(trapnr, str, regs, error_code); \
 +}
 +
 +#define DO_ERROR_INFO(trapnr, str, name, sicode, siaddr) \
 +void do_##name(struct pt_regs * regs, long error_code) \
 +{ \
 +      do_trap(trapnr, str, regs, error_code); \
 +}
 +
 +DO_ERROR_INFO( 0, "divide error", divide_error, FPE_INTDIV, regs->eip)
 +DO_ERROR( 3, "int3", int3)
 +DO_ERROR( 4, "overflow", overflow)
 +DO_ERROR( 5, "bounds", bounds)
 +DO_ERROR_INFO( 6, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
 +DO_ERROR( 7, "device not available", device_not_available)
 +DO_ERROR( 8, "double fault", double_fault)
 +DO_ERROR( 9, "coprocessor segment overrun", coprocessor_segment_overrun)
 +DO_ERROR(10, "invalid TSS", invalid_TSS)
 +DO_ERROR(11, "segment not present", segment_not_present)
 +DO_ERROR(12, "stack segment", stack_segment)
 +DO_ERROR_INFO(17, "alignment check", alignment_check, BUS_ADRALN, 0)
 +DO_ERROR(18, "machine check", machine_check)
 +
 +void do_page_fault(struct pt_regs * regs, long error_code,
 +                   unsigned long address)
 +{
 +    printk("Page fault\n");
 +    printk("Address: 0x%lx", address);
 +    printk("Error Code: 0x%lx", error_code);
 +    printk("eip: \t 0x%lx", regs->eip);
 +    do_exit();
 +}
 +
 +void do_general_protection(struct pt_regs * regs, long error_code)
 +{
 +
 +  HYPERVISOR_shared_info->events_mask = 0;
 +  printk("GPF\n");
 +  printk("Error Code: 0x%lx", error_code);
 +  dump_regs(regs);
 +  dump_code(regs->eip);
 +  do_exit();
 +}
 +
 +
 +void do_debug(struct pt_regs * regs, long error_code)
 +{
 +    printk("Debug exception\n");
 +#define TF_MASK 0x100
 +    regs->eflags &= ~TF_MASK;
 +    dump_regs(regs);
 +    do_exit();
 +}
 +
 +
 +
 +void do_coprocessor_error(struct pt_regs * regs, long error_code)
 +{
 +    printk("Copro error\n");
 +    dump_regs(regs);
 +    dump_code(regs->eip);
 +    do_exit();
 +}
 +
 +void simd_math_error(void *eip)
 +{
 +    printk("SIMD error\n");
 +}
 +
 +void do_simd_coprocessor_error(struct pt_regs * regs,
 +                                        long error_code)
 +{
 +    printk("SIMD copro error\n");
 +}
 +
 +void do_spurious_interrupt_bug(struct pt_regs * regs,
 +                                        long error_code)
 +{
 +}
 +
 +/*
 + * Submit a virtual IDT to teh hypervisor. This consists of tuples
 + * (interrupt vector, privilege ring, CS:EIP of handler).
 + * The 'privilege ring' field specifies the least-privileged ring that
 + * can trap to that vector using a software-interrupt instruction (INT).
 + */
 +static trap_info_t trap_table[] = {
 +    {  0, 0, __KERNEL_CS, (unsigned long)divide_error                },
 +    {  1, 0, __KERNEL_CS, (unsigned long)debug                       },
 +    {  3, 3, __KERNEL_CS, (unsigned long)int3                        },
 +    {  4, 3, __KERNEL_CS, (unsigned long)overflow                    },
 +    {  5, 3, __KERNEL_CS, (unsigned long)bounds                      },
 +    {  6, 0, __KERNEL_CS, (unsigned long)invalid_op                  },
 +    {  7, 0, __KERNEL_CS, (unsigned long)device_not_available        },
 +    {  8, 0, __KERNEL_CS, (unsigned long)double_fault                },
 +    {  9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun },
 +    { 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS                 },
 +    { 11, 0, __KERNEL_CS, (unsigned long)segment_not_present         },
 +    { 12, 0, __KERNEL_CS, (unsigned long)stack_segment               },
 +    { 13, 0, __KERNEL_CS, (unsigned long)general_protection          },
 +    { 14, 0, __KERNEL_CS, (unsigned long)page_fault                  },
 +    { 15, 0, __KERNEL_CS, (unsigned long)spurious_interrupt_bug      },
 +    { 16, 0, __KERNEL_CS, (unsigned long)coprocessor_error           },
 +    { 17, 0, __KERNEL_CS, (unsigned long)alignment_check             },
 +    { 18, 0, __KERNEL_CS, (unsigned long)machine_check               },
 +    { 19, 0, __KERNEL_CS, (unsigned long)simd_coprocessor_error      },
 +    {  0, 0,           0, 0                           }
 +};
 +    
 +
 +
 +void trap_init(void)
 +{
 +    HYPERVISOR_set_trap_table(trap_table);    
 +}