--- /dev/null
+/******************************************************************************
+ * 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_ */
--- /dev/null
- /* 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);
++}
--- /dev/null
- 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) (®s->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);
+}