[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH ARM v3 7/7] mini-os: initial ARM support



From: Karim Raslan <karim.allah.ahmed@xxxxxxxxx>

On ARM, Mini-OS will boot and display some output on the console.
Tested with:

make XEN_TARGET_ARCH=arm32 CROSS_COMPILE=arm-linux-gnueabihf- \
        CONFIG_TEST=y CONFIG_START_NETWORK=n CONFIG_BLKFRONT=n \
        CONFIG_NETFRONT=n CONFIG_FBFRONT=n CONFIG_KBDFRONT=n \
        CONFIG_CONSFRONT=n CONFIG_XC=n -j4

Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@xxxxxxxxx>
[talex5@xxxxxxxxx: made x86_64 support work again]
[talex5@xxxxxxxxx: split into multiple patches]
[talex5@xxxxxxxxx: re-enabled force_evtchn_callback]
[talex5@xxxxxxxxx: enable regular console]
[talex5@xxxxxxxxx: fixed initialisation code:
- Configure write-back caching in page table. This is needed for
  reliable hypercalls to Xen (thanks to Julien Grall).
- Use "client mode" for access control (domains are deprecated,
  according to ARM Cortex-A Series Programmerâs Guide version 4.0,
  section 9.6.4).
- Enable more SCTLR features (icache, branch prediction)]
[talex5@xxxxxxxxx: use Virtual Count register for monotonic time]
[talex5@xxxxxxxxx: fixed HYPERVISOR_shutdown]
[talex5@xxxxxxxxx: get xenstore details from hypervisor]
[talex5@xxxxxxxxx: use GCC implementation of division]
[talex5@xxxxxxxxx: include hypervisor.h from os.h, as on x86]
[talex5@xxxxxxxxx: cleaned up interrupt handlers and threading]
[talex5@xxxxxxxxx: call exit_thread when a thread returns]
[talex5@xxxxxxxxx: implemented block_domain for ARM]
[talex5@xxxxxxxxx: fixed hang when enabling interrupts]
Signed-off-by: Thomas Leonard <talex5@xxxxxxxxx>
---
 extras/mini-os/ARM-TODO.txt                  |  17 ++
 extras/mini-os/Config.mk                     |   2 +
 extras/mini-os/Makefile                      |  14 ++
 extras/mini-os/arch/arm/Makefile             |  32 +++
 extras/mini-os/arch/arm/arch.mk              |   6 +
 extras/mini-os/arch/arm/arm32.S              | 149 ++++++++++++++
 extras/mini-os/arch/arm/events.c             |  24 +++
 extras/mini-os/arch/arm/hypercalls32.S       |  88 ++++++++
 extras/mini-os/arch/arm/minios-arm32.lds     |  73 +++++++
 extras/mini-os/arch/arm/mm.c                 |  44 ++++
 extras/mini-os/arch/arm/sched.c              |  37 ++++
 extras/mini-os/arch/arm/setup.c              | 102 ++++++++++
 extras/mini-os/arch/arm/time.c               | 202 ++++++++++++++++++
 extras/mini-os/drivers/gic.c                 | 180 ++++++++++++++++
 extras/mini-os/events.c                      |   4 +-
 extras/mini-os/hypervisor.c                  |  10 +
 extras/mini-os/include/arm/arch_limits.h     |   9 +
 extras/mini-os/include/arm/arch_mm.h         |  37 ++++
 extras/mini-os/include/arm/arch_sched.h      |  22 ++
 extras/mini-os/include/arm/arch_spinlock.h   |  49 +++++
 extras/mini-os/include/arm/hypercall-arm32.h | 173 ++++++++++++++++
 extras/mini-os/include/arm/os.h              | 294 +++++++++++++++++++++++++++
 extras/mini-os/include/arm/traps.h           |  20 ++
 extras/mini-os/include/gic.h                 |   1 +
 extras/mini-os/include/hypervisor.h          |   4 +
 extras/mini-os/include/mm.h                  |   2 +
 extras/mini-os/include/types.h               |  12 +-
 extras/mini-os/kernel.c                      |   8 +
 extras/mini-os/sched.c                       |   3 +
 29 files changed, 1611 insertions(+), 7 deletions(-)
 create mode 100644 extras/mini-os/ARM-TODO.txt
 create mode 100755 extras/mini-os/arch/arm/Makefile
 create mode 100644 extras/mini-os/arch/arm/arch.mk
 create mode 100644 extras/mini-os/arch/arm/arm32.S
 create mode 100644 extras/mini-os/arch/arm/events.c
 create mode 100644 extras/mini-os/arch/arm/hypercalls32.S
 create mode 100755 extras/mini-os/arch/arm/minios-arm32.lds
 create mode 100644 extras/mini-os/arch/arm/mm.c
 create mode 100644 extras/mini-os/arch/arm/sched.c
 create mode 100644 extras/mini-os/arch/arm/setup.c
 create mode 100644 extras/mini-os/arch/arm/time.c
 create mode 100644 extras/mini-os/drivers/gic.c
 create mode 100644 extras/mini-os/include/arm/arch_limits.h
 create mode 100644 extras/mini-os/include/arm/arch_mm.h
 create mode 100644 extras/mini-os/include/arm/arch_sched.h
 create mode 100755 extras/mini-os/include/arm/arch_spinlock.h
 create mode 100644 extras/mini-os/include/arm/hypercall-arm32.h
 create mode 100644 extras/mini-os/include/arm/os.h
 create mode 100644 extras/mini-os/include/arm/traps.h
 create mode 100644 extras/mini-os/include/gic.h

diff --git a/extras/mini-os/ARM-TODO.txt b/extras/mini-os/ARM-TODO.txt
new file mode 100644
index 0000000..074a304
--- /dev/null
+++ b/extras/mini-os/ARM-TODO.txt
@@ -0,0 +1,17 @@
+* os.h bit manipulation, write optimized assembly code
+* support abort exception handling ( and others )
+* scheduling!
+* use proper memory types and enable caches (L1 and L2)
+* Use LDREX and STREX in xchg implementation ( code already there but it 
causes an abort, I think because of using strong-ordered memory with disabled 
L1 caches - something to do with the implementation of the monitor on cortex-a7 
)
+* gic request_irq implementation, currently all IRQs all hardcoded in gic irq 
handler.
+* use device tree instead of the currently hardcoded values
+* Add virtual memory support and make vstart = 0 ( use 4k descriptors instead 
of 1M descriptors )
+* sched
+* fini_gnttab
+* fini_time
+* bind_*
+* add multiple cpu support (?)
+* map_frames
+* clean up the code and remove redundent code between arm and x86
+* make sure that wallclock is functioning properly
+* evtchn_get_peercontext
diff --git a/extras/mini-os/Config.mk b/extras/mini-os/Config.mk
index d61877b..4ecde54 100644
--- a/extras/mini-os/Config.mk
+++ b/extras/mini-os/Config.mk
@@ -12,6 +12,8 @@ export XEN_INTERFACE_VERSION
 # If not x86 then use $(XEN_TARGET_ARCH)
 ifeq ($(findstring x86_,$(XEN_TARGET_ARCH)),x86_)
 TARGET_ARCH_FAM = x86
+else ifeq ($(findstring arm,$(XEN_TARGET_ARCH)),arm)
+TARGET_ARCH_FAM = arm
 else
 TARGET_ARCH_FAM = $(XEN_TARGET_ARCH)
 endif
diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile
index 5af40ad..1bfe354 100644
--- a/extras/mini-os/Makefile
+++ b/extras/mini-os/Makefile
@@ -76,6 +76,14 @@ TARGET := mini-os
 # Subdirectories common to mini-os
 SUBDIRS := lib xenbus console
 
+ifeq ($(XEN_TARGET_ARCH),arm32)
+# ARM drivers
+src-y += drivers/gic.c
+
+# Need libgcc.a for division helpers
+LDLIBS += `$(CC) -print-libgcc-file-name`
+endif
+
 src-$(CONFIG_BLKFRONT) += blkfront.c
 src-$(CONFIG_TPMFRONT) += tpmfront.c
 src-$(CONFIG_TPM_TIS) += tpm_tis.c
@@ -96,7 +104,9 @@ src-y += sched.c
 src-$(CONFIG_TEST) += test.c
 
 src-y += lib/ctype.c
+ifneq ($(XEN_TARGET_ARCH),arm32)
 src-y += lib/math.c
+endif
 src-y += lib/printf.c
 src-y += lib/stack_chk_fail.c
 src-y += lib/string.c
@@ -185,7 +195,11 @@ $(OBJ_DIR)/$(TARGET): $(OBJS) $(APP_O) arch_lib
        $(LD) -r $(LDFLAGS) $(HEAD_OBJ) $(APP_O) $(OBJS) $(LDARCHLIB) $(LDLIBS) 
-o $@.o
        $(OBJCOPY) -w -G $(GLOBAL_PREFIX)* -G _start $@.o $@.o
        $(LD) $(LDFLAGS) $(LDFLAGS_FINAL) $@.o $(EXTRA_OBJS) -o $@
+ifeq ($(XEN_TARGET_ARCH),arm32)
+       $(OBJCOPY) -O binary $@ $@.img
+else
        gzip -f -9 -c $@ >$@.gz
+endif
 
 .PHONY: clean arch_clean
 
diff --git a/extras/mini-os/arch/arm/Makefile b/extras/mini-os/arch/arm/Makefile
new file mode 100755
index 0000000..8b78651
--- /dev/null
+++ b/extras/mini-os/arch/arm/Makefile
@@ -0,0 +1,32 @@
+#
+# ARM architecture specific makefiles.
+#
+
+XEN_ROOT = $(CURDIR)/../../../..
+include $(XEN_ROOT)/Config.mk
+include ../../Config.mk
+
+# include arch.mk has to be before minios.mk!
+
+include arch.mk
+include ../../minios.mk
+
+# Sources here are all *.c (without $(XEN_TARGET_ARCH).S)
+# This is handled in $(HEAD_ARCH_OBJ)
+ARCH_SRCS := $(wildcard *.c)
+
+# The objects built from the sources.
+ARCH_OBJS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(ARCH_SRCS))
+
+ARCH_OBJS += hypercalls32.o
+
+all: $(OBJ_DIR)/$(ARCH_LIB)
+
+# $(HEAD_ARCH_OBJ) is only built here, needed on linking
+# in ../../Makefile.
+$(OBJ_DIR)/$(ARCH_LIB): $(ARCH_OBJS) $(OBJ_DIR)/$(HEAD_ARCH_OBJ)
+       $(AR) rv $(OBJ_DIR)/$(ARCH_LIB) $(ARCH_OBJS)
+
+clean:
+       rm -f $(OBJ_DIR)/$(ARCH_LIB) $(ARCH_OBJS) $(OBJ_DIR)/$(HEAD_ARCH_OBJ)
+
diff --git a/extras/mini-os/arch/arm/arch.mk b/extras/mini-os/arch/arm/arch.mk
new file mode 100644
index 0000000..80650fc
--- /dev/null
+++ b/extras/mini-os/arch/arm/arch.mk
@@ -0,0 +1,6 @@
+ifeq ($(XEN_TARGET_ARCH),arm32)
+ARCH_CFLAGS  := -march=armv7-a -marm -fms-extensions -D__arm__ 
-DXEN_HAVE_PV_GUEST_ENTRY #-DCPU_EXCLUSIVE_LDST
+EXTRA_INC += $(TARGET_ARCH_FAM)/$(XEN_TARGET_ARCH)
+EXTRA_SRC += arch/$(EXTRA_INC)
+endif
+
diff --git a/extras/mini-os/arch/arm/arm32.S b/extras/mini-os/arch/arm/arm32.S
new file mode 100644
index 0000000..f725295
--- /dev/null
+++ b/extras/mini-os/arch/arm/arm32.S
@@ -0,0 +1,149 @@
+#define PHYS_START (0x80008000)
+
+.section .text
+
+.globl _start
+_start:
+       @ zImage header
+.rept   8
+        mov     r0, r0
+.endr
+        b       reset
+        .word   0x016f2818      @ Magic numbers to help the loader
+        .word   _start         @ absolute load/run zImage address
+        .word   _end - _start   @ zImage size
+       @ end of zImage header
+
+@ Called at boot time. Sets up MMU, exception vectors and stack, and then 
calls C setup() function.
+@ => r2 -> DTB
+@ <= never returns
+reset:
+       @ Fill in the top-level translation table (at page_dir).
+       @ Populate the whole pagedir with 1MB section descriptors.
+       @ TEX[2:0] C B = 001 1 1 (outer and inner write-back, write-allocate)
+       ldr     r0, =(0x2 +             /* Section entry */ \
+                     0xc +             /* C B */ \
+                     (3 << 10) +       /* Read/write */ \
+                     (1 << 12) +       /* TEX */ \
+                     (1 << 16) +       /* Sharable */ \
+                     (1<<19))          /* Non-secure */
+       ldr     r1, =page_dir
+       add     r3, r1, #4*4*1024       @ Limit (4 GB address space, 4 byte 
entries)
+
+1:
+       str     r0, [r1],#4             @ write the section entry
+       add     r0, r0, #1 << 20        @ next physical page
+       cmp     r1, r3
+       bne     1b
+
+       @ Tell the system where our new table is located.
+       ldr     r3, =page_dir
+       mcr     p15, 0, r3, c2, c0, 0   @ set ttbr0
+
+       @ Set access permission for domains
+       @ Domains are deprecated, but we have to configure them anyway.
+       @ We mark every page as being domain 0 and set domain 0 to "client mode"
+       @ (client mode = use access flags in page table).
+       mov     r0, #1                  @ 1 = client
+       mcr     p15, 0, r0, c3, c0, 0   @ DACR
+
+       @ Invalidate TLB
+       mcr     p15, 0, r1, c8, c7, 0   @ TLBIALL
+
+       @ Enable MMU / SCTLR
+       mrc     p15, 0, r1, c1, c0, 0   @ SCTLR
+       orr     r1, r1, #0x7            @ (dcache, barriers, MMU)
+       orr     r1, r1, #3 << 11        @ (icache, branch prediction)
+       mcr     p15, 0, r1, c1, c0, 0   @ SCTLR
+       isb
+
+       @ Set VBAR -> exception_vector_table
+       @ SCTLR.V = 0
+       adr     r0, exception_vector_table
+       mcr     p15, 0, r0, c12, c0, 0
+
+       @ Initialise 16 KB stack
+       ldr     sp, =stack_end
+
+       mov     r0, r2                  @ C wants the DTB pointer in r0
+       b       arch_init
+
+.pushsection .data
+.align 14
+page_dir:
+       .fill (4*1024), 4, 0x0
+
+.align 12
+.globl shared_info_page
+shared_info_page:
+       .fill (1024), 4, 0x0
+
+.align 3
+.globl stack
+stack:
+       .fill (4*1024), 4, 0x0
+stack_end:
+
+.align 3
+irqstack:
+       .fill (1024), 4, 0x0
+irqstack_end:
+.popsection
+
+@ exception base address
+.align 5
+.globl exception_vector_table
+exception_vector_table:
+       b       . @ reset
+       b       . @ undefined instruction
+       b       . @ supervisor call
+       b       . @ prefetch call
+       b       . @ prefetch abort
+       b       . @ data abort //FIXME CLREX
+       b       irq_handler @ irq
+       .word 0xe7f000f0    @ abort on FIQ
+
+irq_handler:
+       ldr     sp, =irqstack_end
+       push    {r0 - r12, r14}
+
+       ldr     r0, IRQ_handler
+       cmp     r0, #0
+       .word   0x07f000f0    @ undeq - panic if no handler
+       blx     r0
+
+       @ Return from IRQ
+       pop     {r0 - r12, r14}
+       subs    pc, lr, #4
+
+.globl IRQ_handler
+IRQ_handler:
+       .long   0x0
+
+
+.globl __arch_switch_threads
+@ => r0 = prev->sp
+@    r1 = next->sp
+@ <= returns to next thread's saved return address
+__arch_switch_threads:
+       stmia   r0, {sp, lr}    @ Store current sp and ip to prev's struct 
thread
+       str     fp, [sp, #-4]   @ Store fp on the old stack
+
+       ldmia   r1, {sp, lr}    @ Load new sp, ip from next's struct thread
+       ldr     fp, [sp, #-4]   @ Restore fp from the stack
+
+       mov     pc, lr
+
+@ This is called if you try to divide by zero. For now, we make a supervisor 
call,
+@ which will make us halt.
+.globl raise
+raise:
+       svc     0
+
+.globl arm_start_thread
+arm_start_thread:
+       pop     {r0, r1}
+       @ r0 = user data
+       @ r1 -> thread's main function
+       ldr     lr, =exit_thread
+       bx      r1
diff --git a/extras/mini-os/arch/arm/events.c b/extras/mini-os/arch/arm/events.c
new file mode 100644
index 0000000..5fd637e
--- /dev/null
+++ b/extras/mini-os/arch/arm/events.c
@@ -0,0 +1,24 @@
+#include <mini-os/os.h>
+#include <mini-os/events.h>
+#include <mini-os/hypervisor.h>
+
+static void virq_debug(evtchn_port_t port, struct pt_regs *regs, void *params)
+{
+    printk("Received a virq_debug event\n");
+}
+
+evtchn_port_t debug_port = -1;
+void arch_init_events(void) {
+    debug_port = bind_virq(VIRQ_DEBUG, (evtchn_handler_t)virq_debug, 0);
+    if(debug_port == -1)
+        BUG();
+    unmask_evtchn(debug_port);
+}
+
+void arch_fini_events(void) {
+    if(debug_port != -1)
+    {
+        mask_evtchn(debug_port);
+        unbind_evtchn(debug_port);
+    }
+}
diff --git a/extras/mini-os/arch/arm/hypercalls32.S 
b/extras/mini-os/arch/arm/hypercalls32.S
new file mode 100644
index 0000000..e2f21c4
--- /dev/null
+++ b/extras/mini-os/arch/arm/hypercalls32.S
@@ -0,0 +1,88 @@
+#define __HYPERVISOR_set_trap_table        0
+#define __HYPERVISOR_mmu_update            1
+#define __HYPERVISOR_set_gdt               2
+#define __HYPERVISOR_stack_switch          3
+#define __HYPERVISOR_set_callbacks         4
+#define __HYPERVISOR_fpu_taskswitch        5
+#define __HYPERVISOR_sched_op_compat       6 /* compat since 0x00030101 */
+#define __HYPERVISOR_platform_op           7
+#define __HYPERVISOR_set_debugreg          8
+#define __HYPERVISOR_get_debugreg          9
+#define __HYPERVISOR_update_descriptor    10
+#define __HYPERVISOR_memory_op            12
+#define __HYPERVISOR_multicall            13
+#define __HYPERVISOR_update_va_mapping    14
+#define __HYPERVISOR_set_timer_op         15
+#define __HYPERVISOR_event_channel_op_compat 16 /* compat since 0x00030202 */
+#define __HYPERVISOR_xen_version          17
+#define __HYPERVISOR_console_io           18
+#define __HYPERVISOR_physdev_op_compat    19 /* compat since 0x00030202 */
+#define __HYPERVISOR_grant_table_op       20
+#define __HYPERVISOR_vm_assist            21
+#define __HYPERVISOR_update_va_mapping_otherdomain 22
+#define __HYPERVISOR_iret                 23 /* x86 only */
+#define __HYPERVISOR_vcpu_op              24
+#define __HYPERVISOR_set_segment_base     25 /* x86/64 only */
+#define __HYPERVISOR_mmuext_op            26
+#define __HYPERVISOR_xsm_op               27
+#define __HYPERVISOR_nmi_op               28
+#define __HYPERVISOR_sched_op             29
+#define __HYPERVISOR_callback_op          30
+#define __HYPERVISOR_xenoprof_op          31
+#define __HYPERVISOR_event_channel_op     32
+#define __HYPERVISOR_physdev_op           33
+#define __HYPERVISOR_hvm_op               34
+#define __HYPERVISOR_sysctl               35
+#define __HYPERVISOR_domctl               36
+#define __HYPERVISOR_kexec_op             37
+#define __HYPERVISOR_tmem_op              38
+#define __HYPERVISOR_xc_reserved_op       39 /* reserved for XenClient */
+
+
+
+#define __HVC(imm16) .long ((0xE1400070 | (((imm16) & 0xFFF0) << 4) | ((imm16) 
& 0x000F)) & 0xFFFFFFFF)
+
+#define XEN_IMM 0xEA1
+
+#define HYPERCALL_SIMPLE(hypercall)            \
+.globl HYPERVISOR_##hypercall;                 \
+.align 4,0x90;                                 \
+HYPERVISOR_##hypercall:                                \
+        mov r12, #__HYPERVISOR_##hypercall;    \
+        __HVC(XEN_IMM);                                \
+        mov pc, lr;
+
+#define _hypercall0 HYPERCALL_SIMPLE
+#define _hypercall1 HYPERCALL_SIMPLE
+#define _hypercall2 HYPERCALL_SIMPLE
+#define _hypercall3 HYPERCALL_SIMPLE
+#define _hypercall4 HYPERCALL_SIMPLE
+
+_hypercall1(set_trap_table);
+_hypercall4(mmu_update);
+_hypercall4(mmuext_op);
+_hypercall2(set_gdt);
+_hypercall2(stack_switch);
+_hypercall3(set_callbacks);
+_hypercall1(fpu_taskswitch);
+_hypercall2(sched_op);
+_hypercall1(set_timer_op);
+_hypercall2(set_debugreg);
+_hypercall1(get_debugreg);
+_hypercall2(update_descriptor);
+_hypercall2(memory_op);
+_hypercall2(multicall);
+_hypercall3(update_va_mapping);
+_hypercall2(event_channel_op);
+_hypercall2(xen_version);
+_hypercall3(console_io);
+_hypercall1(physdev_op);
+_hypercall3(grant_table_op);
+_hypercall4(update_va_mapping_otherdomain);
+_hypercall2(vm_assist);
+_hypercall3(vcpu_op);
+_hypercall2(set_segment_base);
+_hypercall2(nmi_op);
+_hypercall1(sysctl);
+_hypercall1(domctl);
+_hypercall2(hvm_op);
diff --git a/extras/mini-os/arch/arm/minios-arm32.lds 
b/extras/mini-os/arch/arm/minios-arm32.lds
new file mode 100755
index 0000000..793f0de
--- /dev/null
+++ b/extras/mini-os/arch/arm/minios-arm32.lds
@@ -0,0 +1,73 @@
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0x80008000;
+  _text = .;                   /* Text and read-only data */
+  .text : {
+       *(.text)
+       *(.gnu.warning)
+       } = 0x9090
+
+  _etext = .;                  /* End of text section */
+
+  .rodata : { *(.rodata) *(.rodata.*) }
+  . = ALIGN(4096);
+  _erodata = .;
+
+  /* newlib initialization functions */
+  . = ALIGN(32 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+
+  .ctors : {
+        __CTOR_LIST__ = .;
+        *(.ctors)
+       CONSTRUCTORS
+        LONG(0)
+        __CTOR_END__ = .;
+        }
+
+  .dtors : {
+        __DTOR_LIST__ = .;
+        *(.dtors)
+        LONG(0)
+        __DTOR_END__ = .;
+        }
+
+  .data : {                    /* Data */
+       *(.data)
+       }
+
+  _edata = .;                  /* End of data section */
+
+  __bss_start = .;             /* BSS */
+  .bss : {
+       *(.bss)
+        *(.app.bss)
+       }
+  _end = . ;
+
+  /* Sections to be discarded */
+  /DISCARD/ : {
+       *(.text.exit)
+       *(.data.exit)
+       *(.exitcall.exit)
+       }
+
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
diff --git a/extras/mini-os/arch/arm/mm.c b/extras/mini-os/arch/arm/mm.c
new file mode 100644
index 0000000..3e797c2
--- /dev/null
+++ b/extras/mini-os/arch/arm/mm.c
@@ -0,0 +1,44 @@
+#include <console.h>
+#include <arm/arch_mm.h>
+
+#define PHYS_START (0x80008000 + (1000 * 4 * 1024))
+#define PHYS_SIZE (40*1024*1024)
+
+static void build_pagetable(unsigned long *start_pfn, unsigned long *max_pfn)
+{
+    // FIXME Create small pages descriptors here instead of the 1M superpages 
created earlier.
+    return;
+}
+
+unsigned long allocate_ondemand(unsigned long n, unsigned long alignment)
+{
+    // FIXME
+    BUG();
+}
+
+void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p)
+{
+    printk("    _text: %p(VA)\n", &_text);
+    printk("    _etext: %p(VA)\n", &_etext);
+    printk("    _erodata: %p(VA)\n", &_erodata);
+    printk("    _edata: %p(VA)\n", &_edata);
+    printk("    stack start: %p(VA)\n", stack);
+    printk("    _end: %p(VA)\n", &_end);
+
+    // FIXME Get from dt!
+    *start_pfn_p = (((unsigned long)&_end) >> PAGE_SHIFT) + 1000;
+    *max_pfn_p = ((unsigned long)&_end + PHYS_SIZE) >> PAGE_SHIFT;
+
+    printk("    start_pfn: %lx\n", *start_pfn_p);
+    printk("    max_pfn: %lx\n", *max_pfn_p);
+
+    build_pagetable(start_pfn_p, max_pfn_p);
+}
+
+void arch_init_p2m(unsigned long max_pfn)
+{
+}
+
+void arch_init_demand_mapping_area(unsigned long cur_pfn)
+{
+}
diff --git a/extras/mini-os/arch/arm/sched.c b/extras/mini-os/arch/arm/sched.c
new file mode 100644
index 0000000..1306c1b
--- /dev/null
+++ b/extras/mini-os/arch/arm/sched.c
@@ -0,0 +1,37 @@
+#include <mini-os/sched.h>
+#include <mini-os/xmalloc.h>
+
+void arm_start_thread(void);
+
+/* Architecture specific setup of thread creation */
+struct thread* arch_create_thread(char *name, void (*function)(void *),
+                                  void *data)
+{
+    struct thread *thread;
+
+    thread = xmalloc(struct thread);
+    /* We can't use lazy allocation here since the trap handler runs on the 
stack */
+    thread->stack = (char *)alloc_pages(STACK_SIZE_PAGE_ORDER);
+    thread->name = name;
+    printk("Thread \"%s\": pointer: 0x%lx, stack: 0x%lx\n", name, thread,
+            thread->stack);
+
+    /* Save pointer to the thread on the stack, used by current macro */
+    *((unsigned long *)thread->stack) = (unsigned long)thread;
+
+    /* Push the details to pass to arm_start_thread onto the stack */
+    int *sp = (int *) (thread->stack + STACK_SIZE);
+    *(--sp) = (int) function;
+    *(--sp) = (int) data;
+    thread->sp = (unsigned long) sp;
+
+    thread->ip = (unsigned long) arm_start_thread;
+
+    return thread;
+}
+
+void run_idle_thread(void)
+{
+    __asm__ __volatile__ ("mov sp, %0; mov pc, %1"::"r"(idle_thread->sp), 
"r"(idle_thread->ip));
+    /* Never arrive here! */
+}
diff --git a/extras/mini-os/arch/arm/setup.c b/extras/mini-os/arch/arm/setup.c
new file mode 100644
index 0000000..3654cc5
--- /dev/null
+++ b/extras/mini-os/arch/arm/setup.c
@@ -0,0 +1,102 @@
+#include <mini-os/os.h>
+#include <mini-os/kernel.h>
+#include <xen/xen.h>
+#include <xen/memory.h>
+#include <xen/hvm/params.h>
+#include <arm/arch_mm.h>
+
+/*
+ * This structure contains start-of-day info, such as pagetable base pointer,
+ * address of the shared_info structure, and things like that.
+ * On x86, the hypervisor passes it to us. On ARM, we fill it in ourselves.
+ */
+union start_info_union start_info_union;
+
+/*
+ * Shared page for communicating with the hypervisor.
+ * Events flags go here, for example.
+ */
+shared_info_t *HYPERVISOR_shared_info;
+
+extern char shared_info_page[PAGE_SIZE];
+
+static int hvm_get_parameter(int idx, uint64_t *value)
+{
+    struct xen_hvm_param xhv;
+    int ret;
+
+    xhv.domid = DOMID_SELF;
+    xhv.index = idx;
+    ret = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv);
+    if (ret < 0) {
+        BUG();
+    }
+    *value = xhv.value;
+    return ret;
+}
+
+static void get_console(void)
+{
+    uint64_t v = -1;
+
+    hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
+    start_info.console.domU.evtchn = v;
+
+    hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v);
+    start_info.console.domU.mfn = v;
+
+    printk("Console is on port %d\n", start_info.console.domU.evtchn);
+    printk("Console ring is at mfn %x\n", start_info.console.domU.mfn);
+}
+
+void get_xenbus(void)
+{
+    uint64_t value;
+
+    if (hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &value))
+       BUG();
+
+    start_info.store_evtchn = (int)value;
+
+    if(hvm_get_parameter(HVM_PARAM_STORE_PFN, &value))
+       BUG();
+    start_info.store_mfn = (unsigned long)value;
+}
+
+/*
+ * INITIAL C ENTRY POINT.
+ */
+void arch_init(void *dtb_pointer)
+{
+    struct xen_add_to_physmap xatp;
+
+    memset(&__bss_start, 0, &_end - &__bss_start);
+
+    printk("dtb_pointer : %x\n", dtb_pointer);
+
+    /* Map shared_info page */
+    xatp.domid = DOMID_SELF;
+    xatp.idx = 0;
+    xatp.space = XENMAPSPACE_shared_info;
+    xatp.gpfn = virt_to_pfn(shared_info_page);
+    if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0)
+        BUG();
+    HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
+
+    /* Fill in start_info */
+    get_console();
+    get_xenbus();
+
+    start_kernel();
+}
+
+void
+arch_fini(void)
+{
+
+}
+
+void
+arch_do_exit(void)
+{
+}
diff --git a/extras/mini-os/arch/arm/time.c b/extras/mini-os/arch/arm/time.c
new file mode 100644
index 0000000..ff86873
--- /dev/null
+++ b/extras/mini-os/arch/arm/time.c
@@ -0,0 +1,202 @@
+#include <mini-os/os.h>
+#include <mini-os/hypervisor.h>
+#include <mini-os/events.h>
+#include <mini-os/traps.h>
+#include <mini-os/types.h>
+#include <mini-os/time.h>
+#include <mini-os/lib.h>
+
+//#define VTIMER_DEBUG
+#ifdef VTIMER_DEBUG
+#define DEBUG(_f, _a...) \
+    printk("MINI_OS(file=vtimer.c, line=%d) " _f , __LINE__, ## _a)
+#else
+#define DEBUG(_f, _a...)    ((void)0)
+#endif
+
+/************************************************************************
+ * Time functions
+ *************************************************************************/
+
+static uint64_t cntvct_at_init;
+static uint32_t counter_freq;
+
+/* Compute with 96 bit intermediate result: (a*b)/c */
+uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
+{
+    union {
+        uint64_t ll;
+        struct {
+            uint32_t low, high;
+        } l;
+    } u, res;
+    uint64_t rl, rh;
+
+    u.ll = a;
+    rl = (uint64_t)u.l.low * (uint64_t)b;
+    rh = (uint64_t)u.l.high * (uint64_t)b;
+    rh += (rl >> 32);
+    res.l.high = rh / c;
+    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
+    return res.ll;
+}
+
+static inline s_time_t ticks_to_ns(uint64_t ticks)
+{
+    return muldiv64(ticks, SECONDS(1), counter_freq);
+}
+
+static inline uint64_t ns_to_ticks(s_time_t ns)
+{
+    return muldiv64(ns, counter_freq, SECONDS(1));
+}
+
+/* These are peridically updated in shared_info, and then copied here. */
+struct shadow_time_info {
+    uint64_t tsc_timestamp;     /* TSC at last update of time vals.  */
+    uint64_t system_timestamp;  /* Time, in nanosecs, since boot.    */
+    uint32_t tsc_to_nsec_mul;
+    uint32_t tsc_to_usec_mul;
+    int tsc_shift;
+    uint32_t version;
+};
+static struct timespec shadow_ts;
+static uint32_t shadow_ts_version;
+
+static struct shadow_time_info shadow;
+
+static void get_time_values_from_xen(void)
+{
+    struct vcpu_time_info    *src = &HYPERVISOR_shared_info->vcpu_info[0].time;
+
+     do {
+        shadow.version = src->version;
+        rmb();
+        shadow.tsc_timestamp     = src->tsc_timestamp;
+        shadow.system_timestamp  = src->system_time;
+        shadow.tsc_to_nsec_mul   = src->tsc_to_system_mul;
+        shadow.tsc_shift         = src->tsc_shift;
+        rmb();
+    }
+    while ((src->version & 1) | (shadow.version ^ src->version));
+
+    shadow.tsc_to_usec_mul = shadow.tsc_to_nsec_mul / 1000;
+}
+
+static inline uint64_t read_virtual_count(void)
+{
+    uint32_t c_lo, c_hi;
+    __asm__ __volatile__("isb;mrrc p15, 1, %0, %1, c14":"=r"(c_lo), 
"=r"(c_hi));
+    return (((uint64_t) c_hi) << 32) + c_lo;
+}
+
+/* monotonic_clock(): returns # of nanoseconds passed since time_init()
+ *        Note: This function is required to return accurate
+ *        time even in the absence of multiple timer ticks.
+ */
+uint64_t monotonic_clock(void)
+{
+    s_time_t time = ticks_to_ns(read_virtual_count() - cntvct_at_init);
+    //printk("monotonic_clock: %llu (%llu)\n", time, NSEC_TO_SEC(time));
+    return time;
+}
+
+static void update_wallclock(void)
+{
+    shared_info_t *s = HYPERVISOR_shared_info;
+
+    do {
+        shadow_ts_version = s->wc_version;
+        rmb();
+        shadow_ts.tv_sec  = s->wc_sec;
+        shadow_ts.tv_nsec = s->wc_nsec;
+        rmb();
+    }
+    while ((s->wc_version & 1) | (shadow_ts_version ^ s->wc_version));
+}
+
+
+int gettimeofday(struct timeval *tv, void *tz)
+{
+    uint64_t nsec = monotonic_clock();
+    nsec += shadow_ts.tv_nsec;
+
+    tv->tv_sec = shadow_ts.tv_sec;
+    tv->tv_sec += NSEC_TO_SEC(nsec);
+    tv->tv_usec = NSEC_TO_USEC(nsec % 1000000000UL);
+
+    return 0;
+}
+
+void set_vtimer_compare(uint64_t value) {
+    uint32_t x, y;
+
+    DEBUG("New CompareValue : %llx\n", value);
+    x = 0xFFFFFFFFULL & value;
+    y = (value >> 32) & 0xFFFFFFFF;
+
+    __asm__ __volatile__("mcrr p15, 3, %0, %1, c14\n"
+            "isb"::"r"(x), "r"(y));
+
+    __asm__ __volatile__("mov %0, #0x1\n"
+            "mcr p15, 0, %0, c14, c3, 1\n" /* Enable timer and unmask the 
output signal */
+            "isb":"=r"(x));
+}
+
+void unset_vtimer_compare(void) {
+    uint32_t x;
+
+    __asm__ __volatile__("mov %0, #0x2\n"
+            "mcr p15, 0, %0, c14, c3, 1\n" /* Disable timer and mask the 
output signal */
+            "isb":"=r"(x));
+}
+
+void block_domain(s_time_t until)
+{
+    uint64_t until_count = ns_to_ticks(until) + cntvct_at_init;
+    ASSERT(irqs_disabled());
+    if (read_virtual_count() < until_count)
+    {
+        set_vtimer_compare(until_count);
+        //char buf[] = "sleep\n"; (void)HYPERVISOR_console_io(CONSOLEIO_write, 
strlen(buf), buf);
+        __asm__ __volatile__("wfi");
+        //char wake[] = "wake\n"; (void)HYPERVISOR_console_io(CONSOLEIO_write, 
strlen(wake), wake);
+        unset_vtimer_compare();
+
+        /* Give the IRQ handler a chance to handle whatever woke us up. */
+        local_irq_enable();
+        local_irq_disable();
+    }
+}
+
+void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign)
+{
+    DEBUG("Timer kick\n");
+    get_time_values_from_xen();
+    update_wallclock();
+}
+
+evtchn_port_t timer_port = -1;
+
+void init_time(void)
+{
+    printk("Initialising timer interface\n");
+
+    __asm__ __volatile__("mrc p15, 0, %0, c14, c0, 0":"=r"(counter_freq));
+    cntvct_at_init = read_virtual_count();
+    printk("Virtual Count register is %llx, freq = %d Hz\n", cntvct_at_init, 
counter_freq);
+
+    timer_port = bind_virq(VIRQ_TIMER, (evtchn_handler_t)timer_handler, 0);
+    if(timer_port == -1)
+        BUG();
+    unmask_evtchn(timer_port);
+}
+
+void fini_time(void)
+{
+    if(timer_port != -1)
+    {
+        mask_evtchn(timer_port);
+        unbind_evtchn(timer_port);
+    }
+}
diff --git a/extras/mini-os/drivers/gic.c b/extras/mini-os/drivers/gic.c
new file mode 100644
index 0000000..e931f01
--- /dev/null
+++ b/extras/mini-os/drivers/gic.c
@@ -0,0 +1,180 @@
+// ARM GIC implementation
+
+#include <mini-os/os.h>
+#include <mini-os/hypervisor.h>
+
+//#define VGIC_DEBUG
+#ifdef VGIC_DEBUG
+#define DEBUG(_f, _a...) \
+    DEBUG("MINI_OS(file=vgic.c, line=%d) " _f , __LINE__, ## _a)
+#else
+#define DEBUG(_f, _a...)    ((void)0)
+#endif
+
+extern unsigned long IRQ_handler;
+
+struct gic {
+    volatile char *gicd_base;
+    volatile char *gicc_base;
+};
+
+static struct gic gic;
+
+// Distributor Interface
+#define GICD_CTLR        0x0
+#define GICD_ISENABLER    0x100
+#define GICD_PRIORITY    0x400
+#define GICD_ITARGETSR    0x800
+#define GICD_ICFGR        0xC00
+
+// CPU Interface
+#define GICC_CTLR    0x0
+#define GICC_PMR    0x4
+#define GICC_IAR    0xc
+#define GICC_EOIR    0x10
+#define GICC_HPPIR    0x18
+
+#define gicd(gic, offset) ((gic)->gicd_base + (offset))
+#define gicc(gic, offset) ((gic)->gicc_base + (offset))
+
+#define REG(addr) ((uint32_t *)(addr))
+
+static inline uint32_t REG_READ32(volatile uint32_t *addr)
+{
+    uint32_t value;
+    __asm__ __volatile__("ldr %0, [%1]":"=&r"(value):"r"(addr));
+    rmb();
+    return value;
+}
+
+static inline void REG_WRITE32(volatile uint32_t *addr, unsigned int value)
+{
+    __asm__ __volatile__("str %0, [%1]"::"r"(value), "r"(addr));
+    wmb();
+}
+
+static void gic_set_priority(struct gic *gic, unsigned char irq_number, 
unsigned char priority)
+{
+    uint32_t value;
+    value = REG_READ32(REG(gicd(gic, GICD_PRIORITY)) + irq_number);
+    value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0'
+    value |= priority << (8 * (irq_number & 0x3)); // add our priority
+    REG_WRITE32(REG(gicd(gic, GICD_PRIORITY)) + irq_number, value);
+}
+
+static void gic_route_interrupt(struct gic *gic, unsigned char irq_number, 
unsigned char cpu_set)
+{
+    uint32_t value;
+    value = REG_READ32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number);
+    value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0'
+    value |= cpu_set << (8 * (irq_number & 0x3)); // add our priority
+    REG_WRITE32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number, value);
+}
+
+static void gic_enable_interrupt(struct gic *gic, unsigned char irq_number,
+        unsigned char cpu_set, unsigned char level_sensitive, unsigned char 
ppi)
+{
+    void *set_enable_reg;
+    void *cfg_reg;
+
+    // set priority
+    gic_set_priority(gic, irq_number, 0x0);
+
+    // set target cpus for this interrupt
+    gic_route_interrupt(gic, irq_number, cpu_set);
+
+    // set level/edge triggered
+    cfg_reg = (void *)gicd(gic, GICD_ICFGR);
+    level_sensitive ? clear_bit((irq_number * 2) + 1, cfg_reg) : 
set_bit((irq_number * 2) + 1, cfg_reg);
+    if(ppi)
+        clear_bit((irq_number * 2), cfg_reg);
+
+    wmb();
+
+    // enable forwarding interrupt from distributor to cpu interface
+    set_enable_reg = (void *)gicd(gic, GICD_ISENABLER);
+    set_bit(irq_number, set_enable_reg);
+    wmb();
+}
+
+static void gic_enable_interrupts(struct gic *gic)
+{
+    // Global enable forwarding interrupts from distributor to cpu interface
+    REG_WRITE32(REG(gicd(gic, GICD_CTLR)), 0x00000001);
+
+    // Global enable signalling of interrupt from the cpu interface
+    REG_WRITE32(REG(gicc(gic, GICC_CTLR)), 0x00000001);
+}
+
+static void gic_disable_interrupts(struct gic *gic)
+{
+    // Global disable signalling of interrupt from the cpu interface
+    REG_WRITE32(REG(gicc(gic, GICC_CTLR)), 0x00000000);
+
+    // Global disable forwarding interrupts from distributor to cpu interface
+    REG_WRITE32(REG(gicd(gic, GICD_CTLR)), 0x00000000);
+}
+
+static void gic_cpu_set_priority(struct gic *gic, char priority)
+{
+    REG_WRITE32(REG(gicc(gic, GICC_PMR)), priority & 0x000000FF);
+}
+
+static void gic_set_handler(unsigned long gic_handler) {
+    IRQ_handler = gic_handler;
+}
+
+static unsigned long gic_readiar(struct gic *gic) {
+    return REG_READ32(REG(gicc(gic, GICC_IAR))) & 0x000003FF; // Interrupt ID
+}
+
+static void gic_eoir(struct gic *gic, uint32_t irq) {
+    REG_WRITE32(REG(gicc(gic, GICC_EOIR)), irq & 0x000003FF);
+}
+
+//FIXME Get event_irq from dt
+#define EVENTS_IRQ 31
+#define VIRTUALTIMER_IRQ 27
+
+//FIXME Move to a header file
+void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign);
+
+static void gic_handler(void) {
+    unsigned int irq = gic_readiar(&gic);
+
+    DEBUG("IRQ received : %i\n", irq);
+    switch(irq) {
+    case EVENTS_IRQ:
+        do_hypervisor_callback(NULL);
+        break;
+    case VIRTUALTIMER_IRQ:
+        timer_handler(0, NULL, 0);
+        break;
+    default:
+        DEBUG("Unhandled irq\n");
+        break;
+    }
+
+    DEBUG("EIRQ\n");
+
+    gic_eoir(&gic, irq);
+}
+
+void gic_init(void) {
+    // FIXME Get from dt!
+    gic.gicd_base = (char *)0x2c001000ULL;
+    gic.gicc_base = (char *)0x2c002000ULL;
+    wmb();
+
+    gic_set_handler((unsigned long)gic_handler);
+
+    gic_disable_interrupts(&gic);
+    gic_cpu_set_priority(&gic, 0xff);
+
+       /* Must call gic_enable_interrupts before enabling individual 
interrupts, otherwise our IRQ handler
+        * gets called endlessly with spurious interrupts. */
+       gic_enable_interrupts(&gic);
+
+    gic_enable_interrupt(&gic, EVENTS_IRQ /* interrupt number */, 0x1 
/*cpu_set*/, 1 /*level_sensitive*/, 0 /* ppi */);
+    gic_enable_interrupt(&gic, VIRTUALTIMER_IRQ /* interrupt number */, 0x1 
/*cpu_set*/, 1 /*level_sensitive*/, 1 /* ppi */);
+}
diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c
index d60630b..79ba286 100644
--- a/extras/mini-os/events.c
+++ b/extras/mini-os/events.c
@@ -246,7 +246,8 @@ int evtchn_bind_interdomain(domid_t pal, evtchn_port_t 
remote_port,
 
 int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size)
 {
-    int rc;
+    int rc = 0;
+#ifndef __arm__                        /* TODO */
     uint32_t sid;
     struct xen_flask_op op;
     op.cmd = FLASK_GET_PEER_SID;
@@ -261,6 +262,7 @@ int evtchn_get_peercontext(evtchn_port_t local_port, char 
*ctx, int size)
     op.u.sid_context.size = size;
     set_xen_guest_handle(op.u.sid_context.context, ctx);
     rc = _hypercall1(int, xsm_op, &op);
+#endif
     return rc;
 }
 
diff --git a/extras/mini-os/hypervisor.c b/extras/mini-os/hypervisor.c
index b4688a0..2a12ec4 100644
--- a/extras/mini-os/hypervisor.c
+++ b/extras/mini-os/hypervisor.c
@@ -73,18 +73,26 @@ void do_hypervisor_callback(struct pt_regs *regs)
 
 void force_evtchn_callback(void)
 {
+#ifdef XEN_HAVE_PV_UPCALL_MASK
     int save;
+#endif
     vcpu_info_t *vcpu;
     vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()];
+#ifdef XEN_HAVE_PV_UPCALL_MASK
     save = vcpu->evtchn_upcall_mask;
+#endif
 
     while (vcpu->evtchn_upcall_pending) {
+#ifdef XEN_HAVE_PV_UPCALL_MASK
         vcpu->evtchn_upcall_mask = 1;
+#endif
         barrier();
         do_hypervisor_callback(NULL);
         barrier();
+#ifdef XEN_HAVE_PV_UPCALL_MASK
         vcpu->evtchn_upcall_mask = save;
         barrier();
+#endif
     };
 }
 
@@ -110,7 +118,9 @@ inline void unmask_evtchn(uint32_t port)
               &vcpu_info->evtchn_pending_sel) )
     {
         vcpu_info->evtchn_upcall_pending = 1;
+#ifdef XEN_HAVE_PV_UPCALL_MASK
         if ( !vcpu_info->evtchn_upcall_mask )
+#endif
             force_evtchn_callback();
     }
 }
diff --git a/extras/mini-os/include/arm/arch_limits.h 
b/extras/mini-os/include/arm/arch_limits.h
new file mode 100644
index 0000000..bae99e1
--- /dev/null
+++ b/extras/mini-os/include/arm/arch_limits.h
@@ -0,0 +1,9 @@
+#ifndef __ARCH_LIMITS_H__
+#define __ARCH_LIMITS_H__
+
+#include <mm.h>
+
+#define __STACK_SIZE_PAGE_ORDER  2
+#define __STACK_SIZE (4 * PAGE_SIZE)
+
+#endif
diff --git a/extras/mini-os/include/arm/arch_mm.h 
b/extras/mini-os/include/arm/arch_mm.h
new file mode 100644
index 0000000..5e3953b
--- /dev/null
+++ b/extras/mini-os/include/arm/arch_mm.h
@@ -0,0 +1,37 @@
+#ifndef _ARCH_MM_H_
+#define _ARCH_MM_H_
+
+extern char _text, _etext, _erodata, _edata, _end, __bss_start;
+extern char stack[];
+
+#define PAGE_SHIFT        12
+#define PAGE_SIZE        (1 << PAGE_SHIFT)
+#define PAGE_MASK       (~(PAGE_SIZE-1))
+
+#define L1_PAGETABLE_SHIFT      12
+
+#if 0
+#define VIRT_START                 ((unsigned long)&_text)
+#else
+#define VIRT_START                 ((unsigned long)0)
+#endif
+
+#define to_phys(x)                 ((unsigned long)(x)-VIRT_START)
+#define to_virt(x)                 ((void *)((unsigned long)(x)+VIRT_START))
+
+#define PFN_UP(x)    (((x) + PAGE_SIZE-1) >> L1_PAGETABLE_SHIFT)
+#define PFN_DOWN(x)    ((x) >> L1_PAGETABLE_SHIFT)
+#define PFN_PHYS(x)    ((uint64_t)(x) << L1_PAGETABLE_SHIFT)
+#define PHYS_PFN(x)    ((x) >> L1_PAGETABLE_SHIFT)
+
+#define virt_to_pfn(_virt)         (PFN_DOWN(to_phys(_virt)))
+#define virt_to_mfn(_virt)         (0)
+#define mach_to_virt(_mach)        (0)
+#define virt_to_mach(_virt)        (0)
+#define mfn_to_virt(_mfn)          (to_virt(PFN_PHYS(_mfn)))
+#define pfn_to_virt(_pfn)          (to_virt(PFN_PHYS(_pfn)))
+
+// FIXME
+#define map_frames(f, n) (NULL)
+
+#endif
diff --git a/extras/mini-os/include/arm/arch_sched.h 
b/extras/mini-os/include/arm/arch_sched.h
new file mode 100644
index 0000000..e2307ed
--- /dev/null
+++ b/extras/mini-os/include/arm/arch_sched.h
@@ -0,0 +1,22 @@
+
+#ifndef __ARCH_SCHED_H__
+#define __ARCH_SCHED_H__
+
+#include "arch_limits.h"
+
+static inline struct thread* get_current(void)
+{
+   struct thread **current;
+   unsigned long sp;
+   __asm__ __volatile__ ("mov %0, sp":"=r"(sp));
+    current = (void *)(unsigned long)(sp & ~(__STACK_SIZE-1));
+    return *current;
+}
+
+
+extern void __arch_switch_threads(unsigned long *prevctx, unsigned long 
*nextctx);
+
+#define arch_switch_threads(prev,next) __arch_switch_threads(&(prev)->sp, 
&(next)->sp)
+
+
+#endif /* __ARCH_SCHED_H__ */
diff --git a/extras/mini-os/include/arm/arch_spinlock.h 
b/extras/mini-os/include/arm/arch_spinlock.h
new file mode 100755
index 0000000..d57f150
--- /dev/null
+++ b/extras/mini-os/include/arm/arch_spinlock.h
@@ -0,0 +1,49 @@
+
+
+#ifndef __ARCH_ASM_SPINLOCK_H
+#define __ARCH_ASM_SPINLOCK_H
+
+#include "os.h"
+
+
+#define ARCH_SPIN_LOCK_UNLOCKED { 1 }
+
+/*
+ * Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+#define arch_spin_is_locked(x)    (*(volatile signed char *)(&(x)->slock) <= 0)
+#define arch_spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
+
+/*
+ * This works. Despite all the confusion.
+ * (except on PPro SMP or if we are using OOSTORE)
+ * (PPro errata 66, 92)
+ */
+
+static inline void _raw_spin_unlock(spinlock_t *lock)
+{
+    xchg(&lock->slock, 1);
+}
+
+static inline int _raw_spin_trylock(spinlock_t *lock)
+{
+    return xchg(&lock->slock, 0) != 0 ? 1 : 0;
+}
+
+static inline void _raw_spin_lock(spinlock_t *lock)
+{
+    volatile int was_locked;
+    do {
+        was_locked = xchg(&lock->slock, 0) == 0 ? 1 : 0;
+    } while(was_locked);
+}
+
+static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags)
+{
+}
+
+#endif
diff --git a/extras/mini-os/include/arm/hypercall-arm32.h 
b/extras/mini-os/include/arm/hypercall-arm32.h
new file mode 100644
index 0000000..0fc1c03
--- /dev/null
+++ b/extras/mini-os/include/arm/hypercall-arm32.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ * hypercall-arm32.h
+ * 
+ * Copied from XenLinux.
+ * 
+ * Copyright (c) 2002-2004, K A Fraser
+ * 
+ * 64-bit updates:
+ *   Benjamin Liu <benjamin.liu@xxxxxxxxx>
+ *   Jun Nakajima <jun.nakajima@xxxxxxxxx>
+ * 
+ * This file may be distributed separately from the Linux kernel, or
+ * incorporated into other software packages, subject to the following license:
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __HYPERCALL_ARM_H__
+#define __HYPERCALL_ARM_H__
+
+#include <xen/xen.h>
+#include <xen/sched.h>
+#include <mini-os/mm.h>
+
+inline int
+HYPERVISOR_mmu_update(
+    mmu_update_t *req, int count, int *success_count, domid_t domid);
+
+inline int
+HYPERVISOR_mmuext_op(
+    struct mmuext_op *op, int count, int *success_count, domid_t domid);
+
+inline int
+HYPERVISOR_set_gdt(
+    unsigned long *frame_list, int entries);
+
+inline int
+HYPERVISOR_stack_switch(
+    unsigned long ss, unsigned long esp);
+
+inline int
+HYPERVISOR_set_callbacks(
+    unsigned long event_address, unsigned long failsafe_address, 
+    unsigned long syscall_address);
+
+inline int
+HYPERVISOR_fpu_taskswitch(
+    int set);
+
+inline int
+HYPERVISOR_sched_op(
+    int cmd, void *arg);
+
+static inline int
+HYPERVISOR_shutdown(
+    unsigned int reason)
+{
+    struct sched_shutdown shutdown = { .reason = reason };
+       HYPERVISOR_sched_op(SCHEDOP_shutdown, &shutdown);
+}
+
+inline long
+HYPERVISOR_set_timer_op(
+    uint64_t timeout);
+
+inline int
+HYPERVISOR_set_debugreg(
+    int reg, unsigned long value);
+
+inline unsigned long
+HYPERVISOR_get_debugreg(
+    int reg);
+
+inline int
+HYPERVISOR_update_descriptor(
+    unsigned long ma, unsigned long word);
+
+inline int
+HYPERVISOR_memory_op(
+    unsigned int cmd, void *arg);
+
+inline int
+HYPERVISOR_multicall(
+    void *call_list, int nr_calls);
+
+inline int
+HYPERVISOR_update_va_mapping(
+    unsigned long va, pte_t new_val, unsigned long flags);
+
+inline int
+HYPERVISOR_event_channel_op(
+       int cmd, void *op);
+
+inline int
+HYPERVISOR_xen_version(
+    int cmd, void *arg);
+
+inline int
+HYPERVISOR_console_io(
+    int cmd, int count, char *str);
+
+inline int
+HYPERVISOR_physdev_op(
+    void *physdev_op);
+
+inline int
+HYPERVISOR_grant_table_op(
+    unsigned int cmd, void *uop, unsigned int count);
+
+inline int
+HYPERVISOR_update_va_mapping_otherdomain(
+    unsigned long va, pte_t new_val, unsigned long flags, domid_t domid);
+
+inline int
+HYPERVISOR_vm_assist(
+    unsigned int cmd, unsigned int type);
+
+inline int
+HYPERVISOR_vcpu_op(
+    int cmd, int vcpuid, void *extra_args);
+
+inline int
+HYPERVISOR_set_segment_base(
+    int reg, unsigned long value);
+
+inline int
+HYPERVISOR_suspend(
+    unsigned long srec);
+
+inline int
+HYPERVISOR_nmi_op(
+    unsigned long op,
+    unsigned long arg);
+
+inline int
+HYPERVISOR_sysctl(
+    unsigned long op);
+
+inline int
+HYPERVISOR_domctl(
+    unsigned long op);
+
+inline int
+HYPERVISOR_hvm_op(
+    unsigned long op, void *arg);
+
+#endif /* __HYPERCALL_X86_64_H__ */
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/extras/mini-os/include/arm/os.h b/extras/mini-os/include/arm/os.h
new file mode 100644
index 0000000..bacc4af
--- /dev/null
+++ b/extras/mini-os/include/arm/os.h
@@ -0,0 +1,294 @@
+#ifndef _OS_H_
+#define _OS_H_
+
+#ifndef __ASSEMBLY__
+
+#include <mini-os/hypervisor.h>
+#include <mini-os/types.h>
+#include <xen/xen.h>
+
+void arch_fini(void);
+
+#define BUG() while(1){}
+
+#define smp_processor_id() 0
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+extern shared_info_t *HYPERVISOR_shared_info;
+
+// disable interrupts
+static inline __cli(void) {
+    int x;
+    __asm__ __volatile__("mrs %0, cpsr;cpsid i":"=r"(x)::"memory");
+}
+
+// enable interrupts
+static inline __sti(void) {
+    int x;
+    __asm__ __volatile__("mrs %0, cpsr\n"
+                        "bic %0, %0, #0x80\n"
+                        "msr cpsr_c, %0"
+                        :"=r"(x)::"memory");
+}
+
+static inline int irqs_disabled() {
+    int x;
+    __asm__ __volatile__("mrs %0, cpsr\n":"=r"(x)::"memory");
+    return (x & 0x80);
+}
+
+#define local_irq_save(x) { \
+    __asm__ __volatile__("mrs %0, cpsr;cpsid i; and %0, %0, 
#0x80":"=r"(x)::"memory");    \
+}
+
+#define local_irq_restore(x) {    \
+    __asm__ __volatile__("msr cpsr_c, %0"::"r"(x):"memory");    \
+}
+
+#define local_save_flags(x)    { \
+        __asm__ __volatile__("mrs %0, cpsr; and %0, %0, 
0x80":"=r"(x)::"memory");    \
+}
+
+#define local_irq_disable()    __cli()
+#define local_irq_enable() __sti()
+
+#if defined(__arm__)
+#define mb() __asm__("dmb");
+#define rmb() __asm__("dmb");
+#define wmb() __asm__("dmb");
+#elif defined(__aarch64__)
+#define mb()
+#define rmb()
+#define wmb()
+#else
+#error undefined architecture
+#endif
+
+#define LOCK_PREFIX ""
+#define LOCK ""
+
+#define unlikely(x)  __builtin_expect((x),0)
+#define likely(x)  __builtin_expect((x),1)
+
+#define ADDR (*(volatile long *) addr)
+
+/************************** arm *******************************/
+#ifdef __INSIDE_MINIOS__
+#if defined (__arm__)
+#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned 
long)(v),(ptr),sizeof(*(ptr))))
+#define __xg(x) ((volatile long *)(x))
+
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int 
size)
+{
+    //TODO
+    unsigned volatile long y, tmp = 0;
+    switch(size){
+    case 1:
+#if CPU_EXCLUSIVE_LDST
+        __asm__ __volatile__("1:ldrexb %0, [%1]\n"
+            "strexb %3, %2, [%1]\n"
+            "cmp %3, #1\n"
+            "beq 1b\n\n"
+            "dmb\n":"=&r"(y):"r"(ptr), "r"(x), "r"(tmp):"memory");
+#else
+        y = (*(char *)ptr) & 0x000000ff;
+        *((char *)ptr) = (char)x;
+#endif
+        break;
+    case 2:
+#if CPU_EXCLUSIVE_LDST
+        __asm__ __volatile__("1:ldrexh %0, [%1]\n"
+            "strexh %3, %2, [%1]\n"
+            "cmp %3, #1\n"
+            "beq 1b\n\n"
+            "dmb\n":"=&r"(y):"r"(ptr), "r"(x), "r"(tmp):"memory");
+#else
+        y = (*(short *)ptr) & 0x0000ffff;
+        *((short *)ptr) = (short)x;
+#endif
+        break;
+    default: // 4
+#if CPU_EXCLUSIVE_LDST
+        __asm__ __volatile__("1:ldrex %0, [%1]\n"
+            "strex %3, %2, [%1]\n"
+            "cmp %3, #1\n"
+            "beq 1b\n\n"
+            "dmb\n":"=&r"(y):"r"(ptr), "r"(x), "r"(tmp):"memory");
+#else
+        y = (*(unsigned long *)ptr) & 0xffffffff;
+        *((unsigned long *)ptr) = x;
+#endif
+        break;
+    }
+    return y;
+}
+
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @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)
+{
+    //TODO
+    unsigned long *tmp = (unsigned long *)addr;
+
+    int x = tmp[nr >> 5] & (1 << (nr & 0x1f));
+    tmp[nr >> 5] &= ~(1 << (nr & 0x1f));
+    return x;
+}
+
+static __inline__ int test_and_set_bit(int nr, volatile void * addr)
+{
+    //TODO
+    unsigned long *tmp = (unsigned long *)addr;
+
+    int x = tmp[nr >> 5] & (1 << (nr & 0x1f));
+    tmp[nr >> 5] |= (1 << (nr & 0x1f));
+    return x;
+}
+
+static __inline__ int constant_test_bit(int nr, const volatile void * addr)
+{
+    //TODO
+    unsigned long *tmp = (unsigned long *)addr;
+    return tmp[nr >> 5] & (1 << (nr & 0x1f));
+}
+
+static __inline__ int variable_test_bit(int nr, volatile const void * addr)
+{
+    //TODO:
+    unsigned long *tmp = (unsigned long *)addr;
+    return tmp[nr >> 5] & (1 << (nr & 0x1f));
+}
+
+//TODO
+#define test_bit(nr,addr) (((unsigned long *)addr)[nr >> 5] & (1 << (nr & 
0x1f)))
+
+
+/**
+ * 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)
+{
+    //TODO:
+    unsigned long *tmp = (unsigned long *)addr;
+    tmp[nr >> 5] |= (1 << (nr & 0x1f));
+}
+
+/**
+ * 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)
+{
+    //TODO
+    unsigned long *tmp = (unsigned long *)addr;
+    tmp[nr >> 5] &= (unsigned long)~(1 << (nr & 0x1f));
+}
+
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static __inline__ unsigned long __ffs(unsigned long word)
+{
+    //TODO
+    int index = 0;
+    while(!(word & (1 << index++))){};
+
+    return index - 1;
+}
+
+//FIXME
+#define rdtscll(val) (val = 0)
+
+#define wrmsr(msr,val1,val2) (0)
+
+#define wrmsrl(msr,val) 
wrmsr(msr,(uint32_t)((uint64_t)(val)),((uint64_t)(val))>>32)
+
+
+#else /* ifdef __arm__ */
+#error "Unsupported architecture"
+#endif
+#endif /* ifdef __INSIDE_MINIOS */
+
+/********************* common arm32 and arm64  ****************************/
+struct __synch_xchg_dummy { unsigned long a[100]; };
+#define __synch_xg(x) ((struct __synch_xchg_dummy *)(x))
+
+#define synch_cmpxchg(ptr, old, new) (0)
+
+static inline unsigned long __synch_cmpxchg(volatile void *ptr,
+        unsigned long old,
+        unsigned long new, int size)
+{
+    //TODO:
+    //BUG();
+    return 0;
+}
+
+
+static __inline__ void synch_set_bit(int nr, volatile void * addr)
+{
+    //TODO:
+    set_bit(nr, addr);
+}
+
+static __inline__ void synch_clear_bit(int nr, volatile void * addr)
+{
+    //TODO:
+    clear_bit(nr, addr);
+}
+
+static __inline__ int synch_test_and_set_bit(int nr, volatile void * addr)
+{
+    //TODO:
+    return test_and_set_bit(nr, addr);
+}
+
+static __inline__ int synch_test_and_clear_bit(int nr, volatile void * addr)
+{
+    //TODO:
+    return test_and_clear_bit(nr, addr);
+}
+
+static __inline__ int synch_const_test_bit(int nr, const volatile void * addr)
+{
+    //TODO:
+    return const_test_bit(nr, addr);
+}
+
+static __inline__ int synch_var_test_bit(int nr, volatile void * addr)
+{
+    //TODO:
+    return var_test_bit(nr, addr);
+}
+
+#define synch_test_bit(nr,addr) test_bit(nr, addr)
+
+
+#undef ADDR
+
+#endif /* not assembly */
+
+#endif
diff --git a/extras/mini-os/include/arm/traps.h 
b/extras/mini-os/include/arm/traps.h
new file mode 100644
index 0000000..704df22
--- /dev/null
+++ b/extras/mini-os/include/arm/traps.h
@@ -0,0 +1,20 @@
+#ifndef _TRAPS_H_
+#define _TRAPS_H_
+
+struct pt_regs {
+    unsigned long r0;
+    unsigned long r1;
+    unsigned long r2;
+    unsigned long r3;
+    unsigned long r4;
+    unsigned long r5;
+    unsigned long r6;
+    unsigned long r7;
+    unsigned long r8;
+    unsigned long r9;
+    unsigned long r10;
+    unsigned long r11;
+    unsigned long r12;
+};
+
+#endif
diff --git a/extras/mini-os/include/gic.h b/extras/mini-os/include/gic.h
new file mode 100644
index 0000000..cead2e5
--- /dev/null
+++ b/extras/mini-os/include/gic.h
@@ -0,0 +1 @@
+void gic_init(void);
diff --git a/extras/mini-os/include/hypervisor.h 
b/extras/mini-os/include/hypervisor.h
index a62cb78..052f4f8 100644
--- a/extras/mini-os/include/hypervisor.h
+++ b/extras/mini-os/include/hypervisor.h
@@ -18,6 +18,10 @@
 #include <hypercall-x86_32.h>
 #elif defined(__x86_64__)
 #include <hypercall-x86_64.h>
+#elif defined(__arm__)
+#include <hypercall-arm32.h>
+#elif defined(__aarch64__)
+#include <hypercall-arm64.h>
 #else
 #error "Unsupported architecture"
 #endif
diff --git a/extras/mini-os/include/mm.h b/extras/mini-os/include/mm.h
index a94cd6d..644c7de 100644
--- a/extras/mini-os/include/mm.h
+++ b/extras/mini-os/include/mm.h
@@ -29,6 +29,8 @@
 #include <xen/arch-x86_32.h>
 #elif defined(__x86_64__)
 #include <xen/arch-x86_64.h>
+#elif defined(__arm__) || defined(__aarch64__)
+#include <xen/arch-arm.h>
 #else
 #error "Unsupported architecture"
 #endif
diff --git a/extras/mini-os/include/types.h b/extras/mini-os/include/types.h
index 6640ede..931e853 100644
--- a/extras/mini-os/include/types.h
+++ b/extras/mini-os/include/types.h
@@ -27,7 +27,7 @@ typedef unsigned char       u_char;
 typedef unsigned int        u_int;
 typedef unsigned long       u_long;
 #endif
-#ifdef __i386__
+#if defined(__i386__) || defined(__arm__)
 typedef long long           quad_t;
 typedef unsigned long long  u_quad_t;
 
@@ -40,7 +40,7 @@ typedef unsigned long       u_quad_t;
 typedef struct { unsigned long pte; } pte_t;
 #endif /* __i386__ || __x86_64__ */
 
-#ifdef __x86_64__
+#if defined(__x86_64__) || defined(__aarch64__)
 #define __pte(x) ((pte_t) { (x) } )
 #else
 #define __pte(x) ({ unsigned long long _x = (x);        \
@@ -51,10 +51,10 @@ typedef struct { unsigned long pte; } pte_t;
 #include <limits.h>
 #include <stdint.h>
 #else
-#ifdef __i386__
+#if defined(__i386__) || defined(__arm__)
 typedef unsigned int        uintptr_t;
 typedef int                 intptr_t;
-#elif defined(__x86_64__)
+#elif defined(__x86_64__) || defined(__aarch64__)
 typedef unsigned long       uintptr_t;
 typedef long                intptr_t;
 #endif /* __i386__ || __x86_64__ */
@@ -64,10 +64,10 @@ typedef unsigned short uint16_t;
 typedef   signed short int16_t;
 typedef unsigned int uint32_t;
 typedef   signed int int32_t;
-#ifdef __i386__
+#if defined(__i386__) || defined(__arm__)
 typedef   signed long long int64_t;
 typedef unsigned long long uint64_t;
-#elif defined(__x86_64__)
+#elif defined(__x86_64__) || defined(__aarch64__)
 typedef   signed long int64_t;
 typedef unsigned long uint64_t;
 #endif
diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
index b9ab0a2..cdf5928 100644
--- a/extras/mini-os/kernel.c
+++ b/extras/mini-os/kernel.c
@@ -46,6 +46,10 @@
 #include <xen/features.h>
 #include <xen/version.h>
 
+#ifdef __arm__
+#include <mini-os/gic.h>
+#endif
+
 uint8_t xen_features[XENFEAT_NR_SUBMAPS * 32];
 
 void setup_xen_features(void)
@@ -146,6 +150,10 @@ void start_kernel(void)
     create_thread("shutdown", shutdown_thread, NULL);
 #endif
 
+#ifdef __arm__
+    gic_init();
+#endif
+
     /* Call (possibly overridden) app_main() */
     app_main(&start_info);
 
diff --git a/extras/mini-os/sched.c b/extras/mini-os/sched.c
index 174945e..ed3f8c0 100644
--- a/extras/mini-os/sched.c
+++ b/extras/mini-os/sched.c
@@ -145,6 +145,9 @@ struct thread* create_thread(char *name, void 
(*function)(void *), void *data)
     unsigned long flags;
     /* Call architecture specific setup. */
     thread = arch_create_thread(name, function, data);
+    if(!thread)
+       BUG(); //For now, FIXME should just return NULL
+
     /* Not runable, not exited, not sleeping */
     thread->flags = 0;
     thread->wakeup_time = 0LL;
-- 
2.0.0


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.