xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Thomas Leonard <talex5@gmail.com>
To: xen-devel@lists.xenproject.org
Cc: samuel.thibault@ens-lyon.org, Thomas Leonard <talex5@gmail.com>,
	stefano.stabellini@eu.citrix.com
Subject: [PATCH 3/4] mini-os: Initial commit to port minios to ARM
Date: Mon,  2 Jun 2014 18:49:56 +0100	[thread overview]
Message-ID: <1401731397-29842-4-git-send-email-talex5@gmail.com> (raw)
In-Reply-To: <1401731397-29842-1-git-send-email-talex5@gmail.com>

From: Karim Raslan <karim.allah.ahmed@gmail.com>

On ARM, Mini-OS will boot and display some output on the Xen emergency
console (only visible if Xen is compiled in debug mode). Tested with:

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

Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@gmail.com>
[talex5@gmail.com: made x86_64 support work again]
[talex5@gmail.com: split into multiple patches]
Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/ARM-TODO.txt                        |  19 +
 extras/mini-os/Config.mk                           |   2 +
 extras/mini-os/Makefile                            |  12 +
 extras/mini-os/arch/arm/Makefile                   |  33 ++
 extras/mini-os/arch/arm/arch.mk                    |   6 +
 extras/mini-os/arch/arm/arm32.S                    | 211 +++++++++++
 extras/mini-os/arch/arm/divsi3.S                   | 404 +++++++++++++++++++++
 extras/mini-os/arch/arm/events.c                   |  24 ++
 extras/mini-os/arch/arm/hypercalls32.S             |  88 +++++
 extras/mini-os/arch/arm/ldivmod.S                  |  67 ++++
 extras/mini-os/arch/arm/ldivmod_helper.c           |  66 ++++
 extras/mini-os/arch/arm/minios-arm32.lds           |  73 ++++
 extras/mini-os/arch/arm/mm.c                       |  44 +++
 extras/mini-os/arch/arm/qdivrem.c                  | 270 ++++++++++++++
 extras/mini-os/arch/arm/sched.c                    |  32 ++
 extras/mini-os/arch/arm/setup.c                    |  55 +++
 extras/mini-os/arch/arm/time.c                     | 232 ++++++++++++
 extras/mini-os/arch/arm/xenbus.c                   |  36 ++
 extras/mini-os/arch/x86/events.c                   |  28 ++
 extras/mini-os/arch/x86/setup.c                    |  44 ++-
 extras/mini-os/arch/x86/time.c                     |   4 +-
 extras/mini-os/arch/x86/x86_32.S                   |   2 +-
 extras/mini-os/arch/x86/x86_64.S                   |   2 +-
 extras/mini-os/arch/x86/xenbus.c                   |  10 +
 extras/mini-os/console/console.c                   |   2 +
 extras/mini-os/drivers/gic.c                       | 179 +++++++++
 extras/mini-os/events.c                            |  32 +-
 extras/mini-os/gntmap.c                            |   1 +
 extras/mini-os/gnttab.c                            |   1 +
 extras/mini-os/hypervisor.c                        |  20 +-
 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                    | 314 ++++++++++++++++
 extras/mini-os/include/arm/traps.h                 |  20 +
 extras/mini-os/include/console.h                   |   1 +
 extras/mini-os/include/hypervisor.h                |  19 +-
 extras/mini-os/include/mm.h                        |   2 +
 extras/mini-os/include/types.h                     |  73 +++-
 extras/mini-os/include/x86/arch_mm.h               |   2 +
 extras/mini-os/include/x86/os.h                    |  19 +-
 .../mini-os/include/x86/x86_64/hypercall-x86_64.h  |   1 +
 extras/mini-os/kernel.c                            |  78 ++--
 extras/mini-os/mm.c                                |   9 +-
 extras/mini-os/sched.c                             |   9 +-
 extras/mini-os/time.c                              |  12 +
 extras/mini-os/xenbus/xenbus.c                     |  18 +-
 49 files changed, 2758 insertions(+), 108 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/divsi3.S
 create mode 100644 extras/mini-os/arch/arm/events.c
 create mode 100644 extras/mini-os/arch/arm/hypercalls32.S
 create mode 100644 extras/mini-os/arch/arm/ldivmod.S
 create mode 100644 extras/mini-os/arch/arm/ldivmod_helper.c
 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/qdivrem.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/arch/arm/xenbus.c
 create mode 100644 extras/mini-os/arch/x86/events.c
 create mode 100644 extras/mini-os/arch/x86/xenbus.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/time.c

diff --git a/extras/mini-os/ARM-TODO.txt b/extras/mini-os/ARM-TODO.txt
new file mode 100644
index 0000000..57d531a
--- /dev/null
+++ b/extras/mini-os/ARM-TODO.txt
@@ -0,0 +1,19 @@
+* 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
+* remove start_info structure from the common code
+* make sure that wallclock is functioning properly
+* console support
+* 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 50d038b..0fd38a8 100644
--- a/extras/mini-os/Makefile
+++ b/extras/mini-os/Makefile
@@ -72,6 +72,11 @@ TARGET := mini-os
 # Subdirectories common to mini-os
 SUBDIRS := lib xenbus console
 
+ifeq ($(XEN_TARGET_ARCH),arm32)
+# ARM drivers
+src-y += drivers/gic.c
+endif
+
 src-$(CONFIG_BLKFRONT) += blkfront.c
 src-$(CONFIG_TPMFRONT) += tpmfront.c
 src-$(CONFIG_TPM_TIS) += tpm_tis.c
@@ -82,6 +87,7 @@ src-$(CONFIG_FBFRONT) += fbfront.c
 src-y += gntmap.c
 src-y += gnttab.c
 src-y += hypervisor.c
+src-y += time.c
 src-y += kernel.c
 src-y += lock.c
 src-y += main.c
@@ -92,7 +98,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
@@ -178,7 +186,11 @@ $(OBJ_DIR)/$(TARGET): links include/list.h $(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..d8ecc88
--- /dev/null
+++ b/extras/mini-os/arch/arm/Makefile
@@ -0,0 +1,33 @@
+#
+# x86 architecture specific makefiles.
+# It's is used for x86_32, x86_32y and x86_64
+#
+
+XEN_ROOT = $(CURDIR)/../../../..
+include $(XEN_ROOT)/Config.mk
+include ../../Config.mk
+
+# include arch.mk has to be before mini-os.mk!
+
+include arch.mk
+include ../../minios.mk
+
+# Sources here are all *.c *.S 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 divsi3.o ldivmod.o
+
+all: $(OBJ_DIR)/$(ARCH_LIB)
+
+# $(HEAD_ARCH_OBJ) is only build 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..d2e0946
--- /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__ #-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..2dd0f6c
--- /dev/null
+++ b/extras/mini-os/arch/arm/arm32.S
@@ -0,0 +1,211 @@
+#define PHYS_START (0x80008000)
+
+.section .text
+
+.globl _start
+_start:
+	@ zImage header
+.rept   8
+        mov     r0, r0
+.endr
+        b       1f
+        .word   0x016f2818      @ Magic numbers to help the loader
+        .word   _start		@ absolute load/run zImage address
+        .word   _end - _start   @ zImage size
+	@ end of zImage header
+
+1:
+#if FIXME
+@ core processor specific initialization
+	@ Initialize ACTLR core register
+	mrc p15, 0, <Rt>, c1, c0, 1
+	mcr p15, 0, <Rt>, c1, c0, 1
+#endif
+
+@ Save dtb pointer passed by the hypervisor
+	mov	r4, r2		@ save dtb pointer
+
+@ Build pagetables
+	bl	build_pagetables
+
+	ldr	r2, =page_dir
+	MCR	p15, 0, r2, c2, c0, 0	@ set ttbr0
+
+	@ Set access permission for domains
+	mov	r0, #0x3
+	MCR	p15, 0, r0, c3, c0, 0
+	isb
+	
+	ldr	r0, =mmu_switched
+
+	@ enable mmu / sctlr
+	mrc	p15, 0, r1, c1, c0, 0	@ read sctlr
+	orr	r1, r1, #0x1		@ enable mmu
+	@orr	r1, r1, #0x4		@ enable cache
+	orr	r1, r1, #0x02		@ enable barrier enable
+	@mcr	p15, 0, r1, c1, c0, 0	@ write sctlr
+	isb
+
+	@ jump to the virtual address now
+	mov	pc, r0
+
+@ If we're here, then we're very lucky
+mmu_switched:
+
+@ set VBAR = exception_vector_table
+	@ SCTLR.V = 0
+	adr	r0, exception_vector_table
+	mcr	p15, 0, r0, c12, c0, 0
+
+@ load stack
+	ldr	sp, =stack
+	add	sp, sp, #(4*4*1024)
+
+
+	mov	r0, r4		@ set r0 = dtb pointer
+	b	arch_init
+
+
+@ Populate the whole pagedir with 1MB section descriptors for now (1-1 mapping)
+build_pagetables:
+	ldr	r0, =(0x2 + (1 << 16) + (1<<19)) @ First section entry (sharable + NS ).
+	ldr	r1, =page_dir
+	add	r2, r1, #(4*4*1024) @ Limit
+
+1:
+	str	r0, [r1] @ write the section entry
+
+	add	r0, r0, #(1 << 20) @ next physical page.
+	add	r1, r1, #4 @ next pagedir entry
+	cmp	r1, r2
+	bne	1b
+
+	mov	pc, lr
+
+.pushsection .data
+.align 13
+.globl stack
+stack:
+	.fill (4*1024), 4, 0x0
+.align 13
+irqstack:
+	.fill (1024), 4, 0x0
+.globl shared_info_page
+.align 13
+shared_info_page:
+	.fill (1024), 4, 0x0
+.align	14
+page_dir:
+	.fill (4*1024), 4, 0x0
+
+.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
+	b	firq_handler @ firq
+
+irq_handler:
+firq_handler:
+	ldr	sp, =irqstack
+	add	sp, sp, #(4*1024)
+
+	@ Save registers
+	stmda	sp!, {r0 - r12}
+	stmda	sp!, {lr}
+
+	@ FIXME Find interrupt id and dispatch to the correct handler.
+	@ If event_irq
+	ldr	r0, IRQ_handler
+	cmp	r0, #0
+	beq	. @ If no IRQ handler was setup, just get stuck here!
+
+	adr	lr, 1f
+	mov	pc, r0
+1:
+	@bl	do_hypervisor_callback
+
+	@ Restore registers
+	ldmib	sp!, {lr}
+	ldmib	sp!, {r0 - r12}
+
+	@ Return from IRQ
+	subs	pc, lr, #4
+
+.globl IRQ_handler
+IRQ_handler:
+	.long	0x0
+
+
+.globl __arch_switch_threads
+@ r0 = &prev->sp & r1 = &(next->sp)
+__arch_switch_threads:
+	@ store sp, ip for prev thread
+	str	sp, [r0] @ sp
+	str	lr, [r0, #4] @ ip
+	str	fp, [sp, #-4] @ store fp on the stack
+	@ Load sp, ip for next thread
+	ldr	sp, [r1] @ sp
+	ldr	lr, [r1, #4] @ ip
+	ldr	fp, [sp, #-4] @ restore fp from the stack
+	mov	pc, lr
+
+#if 0
+pagetables_code:
+	bl	build_pagetables
+
+	ldr	r2, =(page_dir+PHYS_START)
+	MCR	p15, 0, r2, c2, c0, 0	@ set ttbr0
+
+	@ Set access permission for domains
+	mov	r0, #0x3
+	MCR	p15, 0, r0, c3, c0, 0
+
+	ldr	r0, =mmu_switched
+
+	@ enable mmu / sctlr
+	isb
+	MRC	p15, 0, r1, c1, c0, 0	@ read sctlr
+	orr	r1, r1, #0x1
+	MCR	p15, 0, r1, c1, c0, 0	@ write sctlr
+	MRC     p15, 0, r1, c0, c0, 0	@ read id reg
+
+	@ jump to the virtual address now
+	mov	pc, r0
+
+mmu_switched:
+	b	.
+
+build_pagetables:
+	ldr	r2, =(page_dir + PHYS_START)
+	ldr	r0, =(pagetable + PHYS_START + 1)
+	str	r0, [r2]
+
+	ldr	r2, =(pagetable + PHYS_START)
+	add	r1, r2, #1000
+
+	@ setup entry
+	ldr	r0, =(PHYS_START + 0x3)
+2:
+	str	r0, [r2], #4
+	add	r0, r0, #1 << 12
+	cmp	r2, r1
+	bne	2b
+	mov	pc, lr
+
+.pushsection .data
+.align	14
+page_dir:
+	.fill (1024), 4, 0x0
+pagetable:
+	.fill (1024*50), 4, 0x0
+.popsection
+#endif
diff --git a/extras/mini-os/arch/arm/divsi3.S b/extras/mini-os/arch/arm/divsi3.S
new file mode 100644
index 0000000..fa92233
--- /dev/null
+++ b/extras/mini-os/arch/arm/divsi3.S
@@ -0,0 +1,404 @@
+/*	$NetBSD: divsi3.S,v 1.4 2003/04/05 23:27:15 bjh21 Exp $	*/
+
+/*-
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define ENTRY_NP(symbol) \
+	.globl symbol;	\
+	symbol:
+
+#define END(symbol)
+
+/* 
+ * stack is aligned as there's a possibility of branching to L_overflow
+ * which makes a C call
+ */
+
+ENTRY_NP(__umodsi3)
+	stmfd	sp!, {lr}
+	sub	sp, sp, #4	/* align stack */
+	bl	.L_udivide
+	add	sp, sp, #4	/* unalign stack */
+	mov	r0, r1
+	ldmfd	sp!, {pc}
+END(__umodsi3)
+
+ENTRY_NP(__modsi3)
+	stmfd	sp!, {lr}
+	sub	sp, sp, #4	/* align stack */
+	bl	.L_divide
+	add	sp, sp, #4	/* unalign stack */
+	mov	r0, r1
+	ldmfd	sp!, {pc}
+
+.L_overflow:
+	/* XXX should cause a fatal error */
+	mvn	r0, #0
+	mov	pc, lr
+
+END(__modsi3)
+
+#ifdef __ARM_EABI__
+ENTRY_NP(__aeabi_uidiv)
+ENTRY_NP(__aeabi_uidivmod)
+#endif
+ENTRY_NP(__udivsi3)
+.L_udivide:				/* r0 = r0 / r1; r1 = r0 % r1 */
+	eor     r0, r1, r0 
+	eor     r1, r0, r1 
+	eor     r0, r1, r0 
+					/* r0 = r1 / r0; r1 = r1 % r0 */
+	cmp	r0, #1
+	bcc	.L_overflow
+	beq	.L_divide_l0
+	mov	ip, #0
+	movs	r1, r1
+	bpl	.L_divide_l1
+	orr	ip, ip, #0x20000000	/* ip bit 0x20000000 = -ve r1 */
+	movs	r1, r1, lsr #1
+	orrcs	ip, ip, #0x10000000	/* ip bit 0x10000000 = bit 0 of r1 */
+	b	.L_divide_l1
+
+.L_divide_l0:				/* r0 == 1 */
+	mov	r0, r1
+	mov	r1, #0
+	mov	pc, lr
+#ifdef __ARM_EABI__
+END(__aeabi_uidiv)
+END(__aeabi_uidivmod)
+#endif
+END(__udivsi3)
+
+#ifdef __ARM_EABI__
+ENTRY_NP(__aeabi_idiv)
+ENTRY_NP(__aeabi_idivmod)
+#endif
+ENTRY_NP(__divsi3)
+.L_divide:				/* r0 = r0 / r1; r1 = r0 % r1 */
+	eor     r0, r1, r0 
+	eor     r1, r0, r1 
+	eor     r0, r1, r0 
+					/* r0 = r1 / r0; r1 = r1 % r0 */
+	cmp	r0, #1
+	bcc	.L_overflow
+	beq	.L_divide_l0
+	ands	ip, r0, #0x80000000
+	rsbmi	r0, r0, #0
+	ands	r2, r1, #0x80000000
+	eor	ip, ip, r2
+	rsbmi	r1, r1, #0
+	orr	ip, r2, ip, lsr #1	/* ip bit 0x40000000 = -ve division */
+					/* ip bit 0x80000000 = -ve remainder */
+
+.L_divide_l1:
+	mov	r2, #1
+	mov	r3, #0
+
+	/*
+	 * If the highest bit of the dividend is set, we have to be
+	 * careful when shifting the divisor. Test this. 
+	 */
+	movs	r1,r1
+	bpl	.L_old_code
+
+	/*
+	 * At this point, the highest bit of r1 is known to be set.
+	 * We abuse this below in the tst instructions.
+	 */
+	tst	r1, r0 /*, lsl #0 */
+	bmi	.L_divide_b1
+	tst	r1, r0, lsl #1
+	bmi	.L_divide_b2
+	tst	r1, r0, lsl #2
+	bmi	.L_divide_b3
+	tst	r1, r0, lsl #3
+	bmi	.L_divide_b4
+	tst	r1, r0, lsl #4
+	bmi	.L_divide_b5
+	tst	r1, r0, lsl #5
+	bmi	.L_divide_b6
+	tst	r1, r0, lsl #6
+	bmi	.L_divide_b7
+	tst	r1, r0, lsl #7
+	bmi	.L_divide_b8
+	tst	r1, r0, lsl #8
+	bmi	.L_divide_b9
+	tst	r1, r0, lsl #9
+	bmi	.L_divide_b10
+	tst	r1, r0, lsl #10
+	bmi	.L_divide_b11
+	tst	r1, r0, lsl #11
+	bmi	.L_divide_b12
+	tst	r1, r0, lsl #12
+	bmi	.L_divide_b13
+	tst	r1, r0, lsl #13
+	bmi	.L_divide_b14
+	tst	r1, r0, lsl #14
+	bmi	.L_divide_b15
+	tst	r1, r0, lsl #15
+	bmi	.L_divide_b16
+	tst	r1, r0, lsl #16
+	bmi	.L_divide_b17
+	tst	r1, r0, lsl #17
+	bmi	.L_divide_b18
+	tst	r1, r0, lsl #18
+	bmi	.L_divide_b19
+	tst	r1, r0, lsl #19
+	bmi	.L_divide_b20
+	tst	r1, r0, lsl #20
+	bmi	.L_divide_b21
+	tst	r1, r0, lsl #21
+	bmi	.L_divide_b22
+	tst	r1, r0, lsl #22
+	bmi	.L_divide_b23
+	tst	r1, r0, lsl #23
+	bmi	.L_divide_b24
+	tst	r1, r0, lsl #24
+	bmi	.L_divide_b25
+	tst	r1, r0, lsl #25
+	bmi	.L_divide_b26
+	tst	r1, r0, lsl #26
+	bmi	.L_divide_b27
+	tst	r1, r0, lsl #27
+	bmi	.L_divide_b28
+	tst	r1, r0, lsl #28
+	bmi	.L_divide_b29
+	tst	r1, r0, lsl #29
+	bmi	.L_divide_b30
+	tst	r1, r0, lsl #30
+	bmi	.L_divide_b31
+/*
+ * instead of:
+ *	tst	r1, r0, lsl #31
+ *	bmi	.L_divide_b32
+ */
+	b	.L_divide_b32
+
+.L_old_code:
+	cmp	r1, r0
+	bcc	.L_divide_b0
+	cmp	r1, r0, lsl #1
+	bcc	.L_divide_b1
+	cmp	r1, r0, lsl #2
+	bcc	.L_divide_b2
+	cmp	r1, r0, lsl #3
+	bcc	.L_divide_b3
+	cmp	r1, r0, lsl #4
+	bcc	.L_divide_b4
+	cmp	r1, r0, lsl #5
+	bcc	.L_divide_b5
+	cmp	r1, r0, lsl #6
+	bcc	.L_divide_b6
+	cmp	r1, r0, lsl #7
+	bcc	.L_divide_b7
+	cmp	r1, r0, lsl #8
+	bcc	.L_divide_b8
+	cmp	r1, r0, lsl #9
+	bcc	.L_divide_b9
+	cmp	r1, r0, lsl #10
+	bcc	.L_divide_b10
+	cmp	r1, r0, lsl #11
+	bcc	.L_divide_b11
+	cmp	r1, r0, lsl #12
+	bcc	.L_divide_b12
+	cmp	r1, r0, lsl #13
+	bcc	.L_divide_b13
+	cmp	r1, r0, lsl #14
+	bcc	.L_divide_b14
+	cmp	r1, r0, lsl #15
+	bcc	.L_divide_b15
+	cmp	r1, r0, lsl #16
+	bcc	.L_divide_b16
+	cmp	r1, r0, lsl #17
+	bcc	.L_divide_b17
+	cmp	r1, r0, lsl #18
+	bcc	.L_divide_b18
+	cmp	r1, r0, lsl #19
+	bcc	.L_divide_b19
+	cmp	r1, r0, lsl #20
+	bcc	.L_divide_b20
+	cmp	r1, r0, lsl #21
+	bcc	.L_divide_b21
+	cmp	r1, r0, lsl #22
+	bcc	.L_divide_b22
+	cmp	r1, r0, lsl #23
+	bcc	.L_divide_b23
+	cmp	r1, r0, lsl #24
+	bcc	.L_divide_b24
+	cmp	r1, r0, lsl #25
+	bcc	.L_divide_b25
+	cmp	r1, r0, lsl #26
+	bcc	.L_divide_b26
+	cmp	r1, r0, lsl #27
+	bcc	.L_divide_b27
+	cmp	r1, r0, lsl #28
+	bcc	.L_divide_b28
+	cmp	r1, r0, lsl #29
+	bcc	.L_divide_b29
+	cmp	r1, r0, lsl #30
+	bcc	.L_divide_b30
+.L_divide_b32:
+	cmp	r1, r0, lsl #31
+	subhs	r1, r1,r0, lsl #31
+	addhs	r3, r3,r2, lsl #31
+.L_divide_b31:
+	cmp	r1, r0, lsl #30
+	subhs	r1, r1,r0, lsl #30
+	addhs	r3, r3,r2, lsl #30
+.L_divide_b30:
+	cmp	r1, r0, lsl #29
+	subhs	r1, r1,r0, lsl #29
+	addhs	r3, r3,r2, lsl #29
+.L_divide_b29:
+	cmp	r1, r0, lsl #28
+	subhs	r1, r1,r0, lsl #28
+	addhs	r3, r3,r2, lsl #28
+.L_divide_b28:
+	cmp	r1, r0, lsl #27
+	subhs	r1, r1,r0, lsl #27
+	addhs	r3, r3,r2, lsl #27
+.L_divide_b27:
+	cmp	r1, r0, lsl #26
+	subhs	r1, r1,r0, lsl #26
+	addhs	r3, r3,r2, lsl #26
+.L_divide_b26:
+	cmp	r1, r0, lsl #25
+	subhs	r1, r1,r0, lsl #25
+	addhs	r3, r3,r2, lsl #25
+.L_divide_b25:
+	cmp	r1, r0, lsl #24
+	subhs	r1, r1,r0, lsl #24
+	addhs	r3, r3,r2, lsl #24
+.L_divide_b24:
+	cmp	r1, r0, lsl #23
+	subhs	r1, r1,r0, lsl #23
+	addhs	r3, r3,r2, lsl #23
+.L_divide_b23:
+	cmp	r1, r0, lsl #22
+	subhs	r1, r1,r0, lsl #22
+	addhs	r3, r3,r2, lsl #22
+.L_divide_b22:
+	cmp	r1, r0, lsl #21
+	subhs	r1, r1,r0, lsl #21
+	addhs	r3, r3,r2, lsl #21
+.L_divide_b21:
+	cmp	r1, r0, lsl #20
+	subhs	r1, r1,r0, lsl #20
+	addhs	r3, r3,r2, lsl #20
+.L_divide_b20:
+	cmp	r1, r0, lsl #19
+	subhs	r1, r1,r0, lsl #19
+	addhs	r3, r3,r2, lsl #19
+.L_divide_b19:
+	cmp	r1, r0, lsl #18
+	subhs	r1, r1,r0, lsl #18
+	addhs	r3, r3,r2, lsl #18
+.L_divide_b18:
+	cmp	r1, r0, lsl #17
+	subhs	r1, r1,r0, lsl #17
+	addhs	r3, r3,r2, lsl #17
+.L_divide_b17:
+	cmp	r1, r0, lsl #16
+	subhs	r1, r1,r0, lsl #16
+	addhs	r3, r3,r2, lsl #16
+.L_divide_b16:
+	cmp	r1, r0, lsl #15
+	subhs	r1, r1,r0, lsl #15
+	addhs	r3, r3,r2, lsl #15
+.L_divide_b15:
+	cmp	r1, r0, lsl #14
+	subhs	r1, r1,r0, lsl #14
+	addhs	r3, r3,r2, lsl #14
+.L_divide_b14:
+	cmp	r1, r0, lsl #13
+	subhs	r1, r1,r0, lsl #13
+	addhs	r3, r3,r2, lsl #13
+.L_divide_b13:
+	cmp	r1, r0, lsl #12
+	subhs	r1, r1,r0, lsl #12
+	addhs	r3, r3,r2, lsl #12
+.L_divide_b12:
+	cmp	r1, r0, lsl #11
+	subhs	r1, r1,r0, lsl #11
+	addhs	r3, r3,r2, lsl #11
+.L_divide_b11:
+	cmp	r1, r0, lsl #10
+	subhs	r1, r1,r0, lsl #10
+	addhs	r3, r3,r2, lsl #10
+.L_divide_b10:
+	cmp	r1, r0, lsl #9
+	subhs	r1, r1,r0, lsl #9
+	addhs	r3, r3,r2, lsl #9
+.L_divide_b9:
+	cmp	r1, r0, lsl #8
+	subhs	r1, r1,r0, lsl #8
+	addhs	r3, r3,r2, lsl #8
+.L_divide_b8:
+	cmp	r1, r0, lsl #7
+	subhs	r1, r1,r0, lsl #7
+	addhs	r3, r3,r2, lsl #7
+.L_divide_b7:
+	cmp	r1, r0, lsl #6
+	subhs	r1, r1,r0, lsl #6
+	addhs	r3, r3,r2, lsl #6
+.L_divide_b6:
+	cmp	r1, r0, lsl #5
+	subhs	r1, r1,r0, lsl #5
+	addhs	r3, r3,r2, lsl #5
+.L_divide_b5:
+	cmp	r1, r0, lsl #4
+	subhs	r1, r1,r0, lsl #4
+	addhs	r3, r3,r2, lsl #4
+.L_divide_b4:
+	cmp	r1, r0, lsl #3
+	subhs	r1, r1,r0, lsl #3
+	addhs	r3, r3,r2, lsl #3
+.L_divide_b3:
+	cmp	r1, r0, lsl #2
+	subhs	r1, r1,r0, lsl #2
+	addhs	r3, r3,r2, lsl #2
+.L_divide_b2:
+	cmp	r1, r0, lsl #1
+	subhs	r1, r1,r0, lsl #1
+	addhs	r3, r3,r2, lsl #1
+.L_divide_b1:
+	cmp	r1, r0
+	subhs	r1, r1, r0
+	addhs	r3, r3, r2
+.L_divide_b0:
+
+	tst	ip, #0x20000000
+	bne	.L_udivide_l1
+	mov	r0, r3
+	cmp	ip, #0
+	rsbmi	r1, r1, #0
+	movs	ip, ip, lsl #1
+	bicmi	r0, r0, #0x80000000	/* Fix incase we divided 0x80000000 */
+	rsbmi	r0, r0, #0
+	mov	pc, lr
+
+.L_udivide_l1:
+	tst	ip, #0x10000000
+	mov	r1, r1, lsl #1
+	orrne	r1, r1, #1
+	mov	r3, r3, lsl #1
+	cmp	r1, r0
+	subhs	r1, r1, r0
+	addhs	r3, r3, r2
+	mov	r0, r3
+	mov	pc, lr
+END(__aeabi_idiv)
+END(__aeabi_idivmod)
+END(__divsi3)
+
diff --git a/extras/mini-os/arch/arm/events.c b/extras/mini-os/arch/arm/events.c
new file mode 100644
index 0000000..6e579e7
--- /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/ldivmod.S b/extras/mini-os/arch/arm/ldivmod.S
new file mode 100644
index 0000000..7529826
--- /dev/null
+++ b/extras/mini-os/arch/arm/ldivmod.S
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#define ENTRY_NP(symbol) \
+	.globl symbol;	\
+	symbol:
+
+#define END(symbol)
+
+/*
+ * These calculate:
+ * q = n / m 
+ * With a remainer r.
+ *
+ * They take n in {r0, r1} and m in {r2, r3} then pass them into the
+ * helper function. The hepler functions return q in {r0, r1} as
+ * required by the API spec however r is returned on the stack. The
+ * ABI required us to return r in {r2, r3}.
+ *
+ * We need to allocate 8 bytes on the stack to store r, the link
+ * register, and a pointer to the space where the helper function
+ * will write r to. After returning from the helper fuinction we load
+ * the old link register and r from the stack and return.
+ */
+ENTRY_NP(__aeabi_ldivmod)
+	sub	sp, sp, #8	/* Space for the remainder */
+	stmfd	sp!, {sp, lr}	/* Save a pointer to the above space and lr */
+	bl	__kern_ldivmod
+	ldr	lr, [sp, #4]	/* Restore lr */
+	add	sp, sp, #8	/* Move sp to the remainder value */
+	ldmfd	sp!, {r2, r3}	/* Load the remainder */
+	mov	pc, lr
+END(__aeabi_ldivmod)
+
+ENTRY_NP(__aeabi_uldivmod)
+	sub	sp, sp, #8	/* Space for the remainder */
+	stmfd	sp!, {sp, lr}	/* Save a pointer to the above space and lr */
+	bl	__qdivrem
+	ldr	lr, [sp, #4]	/* Restore lr */
+	add	sp, sp, #8	/* Move sp to the remainder value */
+	ldmfd	sp!, {r2, r3}	/* Load the remainder */
+	mov	pc, lr
+END(__aeabi_uldivmod)
diff --git a/extras/mini-os/arch/arm/ldivmod_helper.c b/extras/mini-os/arch/arm/ldivmod_helper.c
new file mode 100644
index 0000000..f4dde48
--- /dev/null
+++ b/extras/mini-os/arch/arm/ldivmod_helper.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <mini-os/types.h>
+
+u_quad_t __qdivrem(u_quad_t u, u_quad_t v, u_quad_t *rem);
+
+quad_t
+__divdi3(quad_t a, quad_t b)
+{
+        u_quad_t ua, ub, uq;
+        int neg;
+
+        if (a < 0)
+                ua = -(u_quad_t)a, neg = 1;
+        else
+                ua = a, neg = 0;
+        if (b < 0)
+                ub = -(u_quad_t)b, neg ^= 1;
+        else
+                ub = b;
+        uq = __qdivrem(ua, ub, (u_quad_t *)0);
+        return (neg ? -uq : uq);
+}
+
+/*
+ * Helper for __aeabi_ldivmod.
+ * TODO: __divdi3 calls __qdivrem. We should do the same and use the
+ * remainder value rather than re-calculating it.
+ */
+long long __kern_ldivmod(long long, long long, long long *);
+
+long long
+__kern_ldivmod(long long n, long long m, long long *rem)
+{
+	long long q;
+
+	q = __divdi3(n, m);	/* q = n / m */
+	*rem = n - m * q;
+
+	return q;
+}
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..7e7ff06
--- /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/qdivrem.c b/extras/mini-os/arch/arm/qdivrem.c
new file mode 100644
index 0000000..0ab5733
--- /dev/null
+++ b/extras/mini-os/arch/arm/qdivrem.c
@@ -0,0 +1,270 @@
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <mini-os/types.h>
+
+/*
+ * Multiprecision divide.  This algorithm is from Knuth vol. 2 (2nd ed),
+ * section 4.3.1, pp. 257--259.
+ */
+
+#define	B	(1 << HALF_BITS)	/* digit base */
+
+/* Combine two `digits' to make a single two-digit number. */
+#define	COMBINE(a, b) (((u_long)(a) << HALF_BITS) | (b))
+
+/* select a type for digits in base B: use unsigned short if they fit */
+#if ULONG_MAX == 0xffffffff && USHRT_MAX >= 0xffff
+typedef unsigned short digit;
+#else
+typedef u_long digit;
+#endif
+
+/*
+ * Shift p[0]..p[len] left `sh' bits, ignoring any bits that
+ * `fall out' the left (there never will be any such anyway).
+ * We may assume len >= 0.  NOTE THAT THIS WRITES len+1 DIGITS.
+ */
+static void
+__shl(register digit *p, register int len, register int sh)
+{
+	register int i;
+
+	for (i = 0; i < len; i++)
+		p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh));
+	p[i] = LHALF(p[i] << sh);
+}
+
+/*
+ * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v.
+ *
+ * We do this in base 2-sup-HALF_BITS, so that all intermediate products
+ * fit within u_long.  As a consequence, the maximum length dividend and
+ * divisor are 4 `digits' in this base (they are shorter if they have
+ * leading zeros).
+ */
+u_quad_t
+__qdivrem(u_quad_t uq, u_quad_t vq, u_quad_t *arq)
+{
+	union uu tmp;
+	digit *u, *v, *q;
+	register digit v1, v2;
+	u_long qhat, rhat, t;
+	int m, n, d, j, i;
+	digit uspace[5], vspace[5], qspace[5];
+
+	/*
+	 * Take care of special cases: divide by zero, and u < v.
+	 */
+	if (vq == 0) {
+		/* divide by zero. */
+		static volatile const unsigned int zero = 0;
+
+		tmp.ul[H] = tmp.ul[L] = 1 / zero;
+		if (arq)
+			*arq = uq;
+		return (tmp.q);
+	}
+	if (uq < vq) {
+		if (arq)
+			*arq = uq;
+		return (0);
+	}
+	u = &uspace[0];
+	v = &vspace[0];
+	q = &qspace[0];
+
+	/*
+	 * Break dividend and divisor into digits in base B, then
+	 * count leading zeros to determine m and n.  When done, we
+	 * will have:
+	 *	u = (u[1]u[2]...u[m+n]) sub B
+	 *	v = (v[1]v[2]...v[n]) sub B
+	 *	v[1] != 0
+	 *	1 < n <= 4 (if n = 1, we use a different division algorithm)
+	 *	m >= 0 (otherwise u < v, which we already checked)
+	 *	m + n = 4
+	 * and thus
+	 *	m = 4 - n <= 2
+	 */
+	tmp.uq = uq;
+	u[0] = 0;
+	u[1] = HHALF(tmp.ul[H]);
+	u[2] = LHALF(tmp.ul[H]);
+	u[3] = HHALF(tmp.ul[L]);
+	u[4] = LHALF(tmp.ul[L]);
+	tmp.uq = vq;
+	v[1] = HHALF(tmp.ul[H]);
+	v[2] = LHALF(tmp.ul[H]);
+	v[3] = HHALF(tmp.ul[L]);
+	v[4] = LHALF(tmp.ul[L]);
+	for (n = 4; v[1] == 0; v++) {
+		if (--n == 1) {
+			u_long rbj;	/* r*B+u[j] (not root boy jim) */
+			digit q1, q2, q3, q4;
+
+			/*
+			 * Change of plan, per exercise 16.
+			 *	r = 0;
+			 *	for j = 1..4:
+			 *		q[j] = floor((r*B + u[j]) / v),
+			 *		r = (r*B + u[j]) % v;
+			 * We unroll this completely here.
+			 */
+			t = v[2];	/* nonzero, by definition */
+			q1 = u[1] / t;
+			rbj = COMBINE(u[1] % t, u[2]);
+			q2 = rbj / t;
+			rbj = COMBINE(rbj % t, u[3]);
+			q3 = rbj / t;
+			rbj = COMBINE(rbj % t, u[4]);
+			q4 = rbj / t;
+			if (arq)
+				*arq = rbj % t;
+			tmp.ul[H] = COMBINE(q1, q2);
+			tmp.ul[L] = COMBINE(q3, q4);
+			return (tmp.q);
+		}
+	}
+
+	/*
+	 * By adjusting q once we determine m, we can guarantee that
+	 * there is a complete four-digit quotient at &qspace[1] when
+	 * we finally stop.
+	 */
+	for (m = 4 - n; u[1] == 0; u++)
+		m--;
+	for (i = 4 - m; --i >= 0;)
+		q[i] = 0;
+	q += 4 - m;
+
+	/*
+	 * Here we run Program D, translated from MIX to C and acquiring
+	 * a few minor changes.
+	 *
+	 * D1: choose multiplier 1 << d to ensure v[1] >= B/2.
+	 */
+	d = 0;
+	for (t = v[1]; t < B / 2; t <<= 1)
+		d++;
+	if (d > 0) {
+		__shl(&u[0], m + n, d);		/* u <<= d */
+		__shl(&v[1], n - 1, d);		/* v <<= d */
+	}
+	/*
+	 * D2: j = 0.
+	 */
+	j = 0;
+	v1 = v[1];	/* for D3 -- note that v[1..n] are constant */
+	v2 = v[2];	/* for D3 */
+	do {
+		register digit uj0, uj1, uj2;
+
+		/*
+		 * D3: Calculate qhat (\^q, in TeX notation).
+		 * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
+		 * let rhat = (u[j]*B + u[j+1]) mod v[1].
+		 * While rhat < B and v[2]*qhat > rhat*B+u[j+2],
+		 * decrement qhat and increase rhat correspondingly.
+		 * Note that if rhat >= B, v[2]*qhat < rhat*B.
+		 */
+		uj0 = u[j + 0];	/* for D3 only -- note that u[j+...] change */
+		uj1 = u[j + 1];	/* for D3 only */
+		uj2 = u[j + 2];	/* for D3 only */
+		if (uj0 == v1) {
+			qhat = B;
+			rhat = uj1;
+			goto qhat_too_big;
+		} else {
+			u_long nn = COMBINE(uj0, uj1);
+			qhat = nn / v1;
+			rhat = nn % v1;
+		}
+		while (v2 * qhat > COMBINE(rhat, uj2)) {
+	qhat_too_big:
+			qhat--;
+			if ((rhat += v1) >= B)
+				break;
+		}
+		/*
+		 * D4: Multiply and subtract.
+		 * The variable `t' holds any borrows across the loop.
+		 * We split this up so that we do not require v[0] = 0,
+		 * and to eliminate a final special case.
+		 */
+		for (t = 0, i = n; i > 0; i--) {
+			t = u[i + j] - v[i] * qhat - t;
+			u[i + j] = LHALF(t);
+			t = (B - HHALF(t)) & (B - 1);
+		}
+		t = u[j] - t;
+		u[j] = LHALF(t);
+		/*
+		 * D5: test remainder.
+		 * There is a borrow if and only if HHALF(t) is nonzero;
+		 * in that (rare) case, qhat was too large (by exactly 1).
+		 * Fix it by adding v[1..n] to u[j..j+n].
+		 */
+		if (HHALF(t)) {
+			qhat--;
+			for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
+				t += u[i + j] + v[i];
+				u[i + j] = LHALF(t);
+				t = HHALF(t);
+			}
+			u[j] = LHALF(u[j] + t);
+		}
+		q[j] = qhat;
+	} while (++j <= m);		/* D7: loop on j. */
+
+	/*
+	 * If caller wants the remainder, we have to calculate it as
+	 * u[m..m+n] >> d (this is at most n digits and thus fits in
+	 * u[m+1..m+n], but we may need more source digits).
+	 */
+	if (arq) {
+		if (d) {
+			for (i = m + n; i > m; --i)
+				u[i] = (u[i] >> d) |
+				    LHALF(u[i - 1] << (HALF_BITS - d));
+			u[i] = 0;
+		}
+		tmp.ul[H] = COMBINE(uspace[1], uspace[2]);
+		tmp.ul[L] = COMBINE(uspace[3], uspace[4]);
+		*arq = tmp.q;
+	}
+
+	tmp.ul[H] = COMBINE(qspace[1], qspace[2]);
+	tmp.ul[L] = COMBINE(qspace[3], qspace[4]);
+	return (tmp.q);
+}
diff --git a/extras/mini-os/arch/arm/sched.c b/extras/mini-os/arch/arm/sched.c
new file mode 100644
index 0000000..e490105
--- /dev/null
+++ b/extras/mini-os/arch/arm/sched.c
@@ -0,0 +1,32 @@
+#include <mini-os/sched.h>
+#include <mini-os/xmalloc.h>
+
+
+/* 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);
+
+    thread->sp = (unsigned long)thread->stack + STACK_SIZE;
+    /* Save pointer to the thread on the stack, used by current macro */
+    *((unsigned long *)thread->stack) = (unsigned long)thread;
+
+    thread->ip = (unsigned long) function;
+    /* FIXME thread->r0 = (unsigned long)data; */
+
+    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..f0b2f47
--- /dev/null
+++ b/extras/mini-os/arch/arm/setup.c
@@ -0,0 +1,55 @@
+#include <mini-os/os.h>
+#include <xen/xen.h>
+#include <xen/memory.h>
+#include <hypervisor.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.
+ */
+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];
+
+void start_kernel(void);
+
+/*
+ * 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;
+
+	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..6dba1fe
--- /dev/null
+++ b/extras/mini-os/arch/arm/time.c
@@ -0,0 +1,232 @@
+#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
+ *************************************************************************/
+
+/* 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;
+
+#define HANDLE_USEC_OVERFLOW(_tv)          \
+    do {                                   \
+        while ( (_tv)->tv_usec >= 1000000 ) \
+        {                                  \
+            (_tv)->tv_usec -= 1000000;      \
+            (_tv)->tv_sec++;                \
+        }                                  \
+    } while ( 0 )
+
+static inline int time_values_up_to_date(void)
+{
+	struct vcpu_time_info *src = &HYPERVISOR_shared_info->vcpu_info[0].time;
+
+	return (shadow.version == src->version);
+}
+
+
+/*
+ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
+ * yielding a 64-bit result.
+ */
+static inline uint64_t scale_delta(uint64_t delta, uint32_t mul_frac, int shift)
+{
+	BUG();
+	return 0;
+}
+
+
+static unsigned long get_nsec_offset(void)
+{
+	return 0;
+#if FIXME
+	uint64_t now, delta;
+	rdtscll(now);
+	delta = now - shadow.tsc_timestamp;
+	return scale_delta(delta, shadow.tsc_to_nsec_mul, shadow.tsc_shift);
+#endif
+}
+
+
+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;
+}
+
+
+
+
+/* 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)
+{
+	uint64_t time;
+	uint32_t local_time_version;
+
+	do {
+		local_time_version = shadow.version;
+		rmb();
+		time = shadow.system_timestamp + get_nsec_offset();
+        if (!time_values_up_to_date())
+			get_time_values_from_xen();
+		rmb();
+	} while (local_time_version != shadow.version);
+
+	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 block_domain(s_time_t until)
+{
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    ASSERT(irqs_disabled());
+    if(monotonic_clock() < until)
+    {
+        HYPERVISOR_set_timer_op(until);
+        HYPERVISOR_sched_op(SCHEDOP_block, 0);
+        local_irq_disable();
+    }
+}
+
+
+/*
+ * Just a dummy
+ */
+void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign)
+{
+	DEBUG("Timer kick\n");
+    get_time_values_from_xen();
+	update_wallclock();
+}
+
+#define VTIMER_TICK 0x10000000
+void increment_vtimer_compare(uint64_t inc) {
+	uint32_t x, y;
+	uint64_t value;
+	__asm__ __volatile__("mrrc p15, 1, %0, %1, c14\n"
+			"isb":"=r"(x), "=r"(y));
+
+	// CompareValue = Counter + VTIMER_TICK
+	value = (0xFFFFFFFFFFFFFFFFULL & x) | ((0xFFFFFFFFFFFFFFFFULL & y) << 32);
+	DEBUG("Counter: %llx(x=%x and y=%x)\n", value, x, y);
+	value += inc;
+	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));
+}
+
+static inline void enable_virtual_timer(void) {
+#if FIXME
+	uint32_t x, y;
+	uint64_t value;
+
+	__asm__ __volatile__("ldr %0, =0xffffffff\n"
+			"ldr %1, =0xffffffff\n"
+			"dsb\n"
+			"mcrr p15, 3, %0, %1, c14\n" /* set CompareValue to 0x0000ffff 0000ffff */
+			"isb\n"
+			"mov %0, #0x1\n"
+			"mcr p15, 0, %0, c14, c3, 1\n" /* Enable timer and unmask the output signal */
+			"isb":"=r"(x), "=r"(y));
+#else
+	increment_vtimer_compare(VTIMER_TICK);
+#endif
+}
+
+evtchn_port_t timer_port = -1;
+void arch_init_time(void)
+{
+	// FIXME: VIRQ_TIMER isn't supported under ARM, use ARM Generic Timer instead.
+    printk("Initialising timer interface\n");
+    timer_port = bind_virq(VIRQ_TIMER, (evtchn_handler_t)timer_handler, 0);
+    if(timer_port == -1)
+		BUG();
+    unmask_evtchn(timer_port);
+
+    enable_virtual_timer();
+}
+
+void arch_fini_time(void)
+{
+	if(timer_port != -1)
+	{
+		mask_evtchn(timer_port);
+		unbind_evtchn(timer_port);
+	}
+}
diff --git a/extras/mini-os/arch/arm/xenbus.c b/extras/mini-os/arch/arm/xenbus.c
new file mode 100644
index 0000000..76feabc
--- /dev/null
+++ b/extras/mini-os/arch/arm/xenbus.c
@@ -0,0 +1,36 @@
+#include <mini-os/os.h>
+#include <mini-os/mm.h>
+#include <xen/hvm/params.h>
+#include <xen/io/xs_wire.h>
+#include <mini-os/hypervisor.h>
+
+static inline 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;
+}
+
+void arch_init_xenbus(struct xenstore_domain_interface **xenstore_buf, uint32_t *store_evtchn) {
+	uint64_t value;
+	uint64_t xenstore_pfn;
+
+	if (hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &value))
+		BUG();
+
+	*store_evtchn = (int)value;
+
+	if(hvm_get_parameter(HVM_PARAM_STORE_PFN, &value))
+		BUG();
+	xenstore_pfn = (unsigned long)value;
+
+	*xenstore_buf = pfn_to_virt(xenstore_pfn);
+}
diff --git a/extras/mini-os/arch/x86/events.c b/extras/mini-os/arch/x86/events.c
new file mode 100644
index 0000000..87f8b77
--- /dev/null
+++ b/extras/mini-os/arch/x86/events.c
@@ -0,0 +1,28 @@
+#include <mini-os/os.h>
+#include <mini-os/mm.h>
+
+#if defined(__x86_64__)
+char irqstack[2 * STACK_SIZE];
+
+static struct pda
+{
+    int irqcount;       /* offset 0 (used in x86_64.S) */
+    char *irqstackptr;  /*        8 */
+} cpu0_pda;
+#endif
+
+void arch_init_events(void) {
+#if defined(__x86_64__)
+    asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0));
+    wrmsrl(0xc0000101, &cpu0_pda); /* 0xc0000101 is MSR_GS_BASE */
+    cpu0_pda.irqcount = -1;
+    cpu0_pda.irqstackptr = (void*) (((unsigned long)irqstack + 2 * STACK_SIZE)
+                                    & ~(STACK_SIZE - 1));
+#endif
+}
+
+void arch_fini_events(void) {
+#if defined(__x86_64__)
+    wrmsrl(0xc0000101, NULL); /* 0xc0000101 is MSR_GS_BASE */
+#endif
+}
diff --git a/extras/mini-os/arch/x86/setup.c b/extras/mini-os/arch/x86/setup.c
index 54046d3..6bb6d4b 100644
--- a/extras/mini-os/arch/x86/setup.c
+++ b/extras/mini-os/arch/x86/setup.c
@@ -28,6 +28,7 @@
 
 #include <mini-os/os.h>
 #include <mini-os/lib.h> /* for printk, memcpy */
+#include <xen/xen.h>
 
 /*
  * Shared page for communicating with the hypervisor.
@@ -87,14 +88,40 @@ static inline void sse_init(void) {
 #define sse_init()
 #endif
 
+
+void start_kernel(void);
+
+/*
+ * INITIAL C ENTRY POINT.
+ */
 void
 arch_init(start_info_t *si)
 {
+    static char hello[] = "Bootstrapping...\n";
+
+    (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(hello), hello);
+
+    trap_init();
+
+    /* print out some useful information  */
+    printk("Xen Minimal OS!\n");
+    printk("  start_info: %p(VA)\n", si);
+    printk("    nr_pages: 0x%lx\n", si->nr_pages);
+    printk("  shared_inf: 0x%08lx(MA)\n", si->shared_info);
+    printk("     pt_base: %p(VA)\n", (void *)si->pt_base);
+    printk("nr_pt_frames: 0x%lx\n", si->nr_pt_frames);
+    printk("    mfn_list: %p(VA)\n", (void *)si->mfn_list);
+    printk("   mod_start: 0x%lx(VA)\n", si->mod_start);
+    printk("     mod_len: %lu\n", si->mod_len);
+    printk("       flags: 0x%x\n", (unsigned int)si->flags);
+    printk("    cmd_line: %s\n",
+           si->cmd_line ? (const char *)si->cmd_line : "NULL");
+
 	/*Initialize floating point unit */
-        fpu_init();
+	fpu_init();
 
-        /* Initialize SSE */
-        sse_init();
+	/* Initialize SSE */
+	sse_init();
 
 	/* Copy the start_info struct to a globally-accessible area. */
 	/* WARN: don't do printk before here, it uses information from
@@ -118,12 +145,15 @@ arch_init(start_info_t *si)
 		(unsigned long)failsafe_callback, 0);
 #endif
 
-
+	start_kernel();
 }
 
 void
 arch_fini(void)
 {
+	/* Reset traps */
+	trap_fini();
+
 #ifdef __i386__
 	HYPERVISOR_set_callbacks(0, 0, 0, 0);
 #else
@@ -132,9 +162,7 @@ arch_fini(void)
 }
 
 void
-arch_print_info(void)
+arch_do_exit(void)
 {
-	printk("  stack:      %p-%p\n", stack, stack + sizeof(stack));
+	stack_walk();
 }
-
-
diff --git a/extras/mini-os/arch/x86/time.c b/extras/mini-os/arch/x86/time.c
index 2c8d033..c57ee55 100644
--- a/extras/mini-os/arch/x86/time.c
+++ b/extras/mini-os/arch/x86/time.c
@@ -223,14 +223,14 @@ static void timer_handler(evtchn_port_t ev, struct pt_regs *regs, void *ign)
 
 
 static evtchn_port_t port;
-void init_time(void)
+void arch_init_time(void)
 {
     printk("Initialising timer interface\n");
     port = bind_virq(VIRQ_TIMER, &timer_handler, NULL);
     unmask_evtchn(port);
 }
 
-void fini_time(void)
+void arch_fini_time(void)
 {
     /* Clear any pending timer */
     HYPERVISOR_set_timer_op(0);
diff --git a/extras/mini-os/arch/x86/x86_32.S b/extras/mini-os/arch/x86/x86_32.S
index fb3e30a..b9aa392 100644
--- a/extras/mini-os/arch/x86/x86_32.S
+++ b/extras/mini-os/arch/x86/x86_32.S
@@ -20,7 +20,7 @@ _start:
         lss stack_start,%esp
         andl $(~(__STACK_SIZE-1)), %esp
         push %esi 
-        call start_kernel
+        call arch_init
 
 stack_start:
 	.long stack+(2*__STACK_SIZE), __KERNEL_SS
diff --git a/extras/mini-os/arch/x86/x86_64.S b/extras/mini-os/arch/x86/x86_64.S
index f022eb3..df3469e 100644
--- a/extras/mini-os/arch/x86/x86_64.S
+++ b/extras/mini-os/arch/x86/x86_64.S
@@ -21,7 +21,7 @@ _start:
         movq stack_start(%rip),%rsp
         andq $(~(__STACK_SIZE-1)), %rsp
         movq %rsi,%rdi
-        call start_kernel
+        call arch_init
 
 stack_start:
         .quad stack+(2*__STACK_SIZE)
diff --git a/extras/mini-os/arch/x86/xenbus.c b/extras/mini-os/arch/x86/xenbus.c
new file mode 100644
index 0000000..5cda78d
--- /dev/null
+++ b/extras/mini-os/arch/x86/xenbus.c
@@ -0,0 +1,10 @@
+#include <mini-os/os.h>
+#include <mini-os/mm.h>
+#include <mini-os/xmalloc.h>
+#include <xen/xen.h>
+#include <xen/io/xs_wire.h>
+
+void arch_init_xenbus(struct xenstore_domain_interface **xenstore_buf, uint32_t *store_evtchn) {
+    *xenstore_buf = mfn_to_virt(start_info.store_mfn);
+    *store_evtchn = start_info.store_evtchn;
+}
diff --git a/extras/mini-os/console/console.c b/extras/mini-os/console/console.c
index 5538bd4..c08fea9 100644
--- a/extras/mini-os/console/console.c
+++ b/extras/mini-os/console/console.c
@@ -157,7 +157,9 @@ void xprintk(const char *fmt, ...)
 void init_console(void)
 {   
     printk("Initialising console ... ");
+#ifndef __arm__
     xencons_ring_init();    
+#endif
     console_initialised = 1;
     /* This is also required to notify the daemon */
     printk("done.\n");
diff --git a/extras/mini-os/drivers/gic.c b/extras/mini-os/drivers/gic.c
new file mode 100644
index 0000000..14301ae
--- /dev/null
+++ b/extras/mini-os/drivers/gic.c
@@ -0,0 +1,179 @@
+// 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
+#define VTIMER_TICK 0x6000000
+void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign);
+void increment_vtimer_compare(uint64_t inc);
+
+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);
+		increment_vtimer_compare(VTIMER_TICK);
+		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);
+	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 */);
+	gic_enable_interrupts(&gic);
+}
diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c
index 2da9b01..84a30a3 100644
--- a/extras/mini-os/events.c
+++ b/extras/mini-os/events.c
@@ -47,9 +47,11 @@ void unbind_all_ports(void)
 
     for ( i = 0; i < NR_EVS; i++ )
     {
+#ifndef __arm__
         if ( i == start_info.console.domU.evtchn ||
              i == start_info.store_evtchn)
             continue;
+#endif
 
         if ( test_and_clear_bit(i, bound_ports) )
         {
@@ -167,44 +169,30 @@ evtchn_port_t bind_pirq(uint32_t pirq, int will_share,
 	return op.port;
 }
 
-#if defined(__x86_64__)
-char irqstack[2 * STACK_SIZE];
-
-static struct pda
-{
-    int irqcount;       /* offset 0 (used in x86_64.S) */
-    char *irqstackptr;  /*        8 */
-} cpu0_pda;
-#endif
-
+void arch_init_events(void);
 /*
  * Initially all events are without a handler and disabled
  */
 void init_events(void)
 {
     int i;
-#if defined(__x86_64__)
-    asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0));
-    wrmsrl(0xc0000101, &cpu0_pda); /* 0xc0000101 is MSR_GS_BASE */
-    cpu0_pda.irqcount = -1;
-    cpu0_pda.irqstackptr = (void*) (((unsigned long)irqstack + 2 * STACK_SIZE)
-                                    & ~(STACK_SIZE - 1));
-#endif
+
     /* initialize event handler */
     for ( i = 0; i < NR_EVS; i++ )
 	{
         ev_actions[i].handler = default_handler;
         mask_evtchn(i);
     }
+
+    arch_init_events();
 }
 
+void arch_fini_events(void);
 void fini_events(void)
 {
     /* Dealloc all events */
     unbind_all_ports();
-#if defined(__x86_64__)
-    wrmsrl(0xc0000101, NULL); /* 0xc0000101 is MSR_GS_BASE */
-#endif
+    arch_fini_events();
 }
 
 void default_handler(evtchn_port_t port, struct pt_regs *regs, void *ignore)
@@ -262,7 +250,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__
     uint32_t sid;
     struct xen_flask_op op;
     op.cmd = FLASK_GET_PEER_SID;
@@ -277,6 +266,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/gntmap.c b/extras/mini-os/gntmap.c
index 7eb69be..abfbd29 100644
--- a/extras/mini-os/gntmap.c
+++ b/extras/mini-os/gntmap.c
@@ -37,6 +37,7 @@
 #include <xen/grant_table.h>
 #include <inttypes.h>
 #include <mini-os/gntmap.h>
+#include <mini-os/hypervisor.h>
 
 //#define GNTMAP_DEBUG
 #ifdef GNTMAP_DEBUG
diff --git a/extras/mini-os/gnttab.c b/extras/mini-os/gnttab.c
index 2f1b3d7..404d72c 100644
--- a/extras/mini-os/gnttab.c
+++ b/extras/mini-os/gnttab.c
@@ -19,6 +19,7 @@
 #include <mini-os/mm.h>
 #include <mini-os/gnttab.h>
 #include <mini-os/semaphore.h>
+#include <mini-os/hypervisor.h>
 
 #define NR_RESERVED_ENTRIES 8
 
diff --git a/extras/mini-os/hypervisor.c b/extras/mini-os/hypervisor.c
index b4688a0..9c79d5d 100644
--- a/extras/mini-os/hypervisor.c
+++ b/extras/mini-os/hypervisor.c
@@ -71,23 +71,6 @@ void do_hypervisor_callback(struct pt_regs *regs)
     in_callback = 0;
 }
 
-void force_evtchn_callback(void)
-{
-    int save;
-    vcpu_info_t *vcpu;
-    vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()];
-    save = vcpu->evtchn_upcall_mask;
-
-    while (vcpu->evtchn_upcall_pending) {
-        vcpu->evtchn_upcall_mask = 1;
-        barrier();
-        do_hypervisor_callback(NULL);
-        barrier();
-        vcpu->evtchn_upcall_mask = save;
-        barrier();
-    };
-}
-
 inline void mask_evtchn(uint32_t port)
 {
     shared_info_t *s = HYPERVISOR_shared_info;
@@ -110,8 +93,7 @@ inline void unmask_evtchn(uint32_t port)
               &vcpu_info->evtchn_pending_sel) )
     {
         vcpu_info->evtchn_upcall_pending = 1;
-        if ( !vcpu_info->evtchn_upcall_mask )
-            force_evtchn_callback();
+        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..9b2cc03
--- /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)          (0)
+#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..31d9071
--- /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..6677bc4
--- /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..0343946
--- /dev/null
+++ b/extras/mini-os/include/arm/hypercall-arm32.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ * hypercall-x86_64.h
+ * 
+ * Copied from XenLinux.
+ * 
+ * Copyright (c) 2002-2004, K A Fraser
+ * 
+ * 64-bit updates:
+ *   Benjamin Liu <benjamin.liu@intel.com>
+ *   Jun Nakajima <jun.nakajima@intel.com>
+ * 
+ * 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 };
+	return low_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..60e84f7
--- /dev/null
+++ b/extras/mini-os/include/arm/os.h
@@ -0,0 +1,314 @@
+#ifndef _OS_H_
+#define _OS_H_
+
+#ifndef __ASSEMBLY__
+
+#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;
+
+#if 0
+static inline void force_evtchn_callback(void)
+{
+    int save;
+    vcpu_info_t *vcpu;
+    vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()];
+    save = vcpu->evtchn_upcall_mask;
+
+    while (vcpu->evtchn_upcall_pending) {
+        vcpu->evtchn_upcall_mask = 1;
+        barrier();
+        do_hypervisor_callback(NULL);
+        barrier();
+        vcpu->evtchn_upcall_mask = save;
+        barrier();
+    };
+}
+#else
+#define force_evtchn_callback(void) do {} while(0)
+#endif
+
+// 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..b8ce784
--- /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/console.h b/extras/mini-os/include/console.h
index 3755b66..dade8fb 100644
--- a/extras/mini-os/include/console.h
+++ b/extras/mini-os/include/console.h
@@ -42,6 +42,7 @@
 #include <xen/grant_table.h>
 #include <xenbus.h>
 #include <xen/io/console.h>
+#include <xen/event_channel.h>
 #include <stdarg.h>
 
 struct consfront_dev {
diff --git a/extras/mini-os/include/hypervisor.h b/extras/mini-os/include/hypervisor.h
index a62cb78..ee288a0 100644
--- a/extras/mini-os/include/hypervisor.h
+++ b/extras/mini-os/include/hypervisor.h
@@ -13,16 +13,34 @@
 #define _HYPERVISOR_H_
 
 #include <mini-os/types.h>
+
 #include <xen/xen.h>
+
 #if defined(__i386__)
 #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
 #include <mini-os/traps.h>
 
+#ifdef __arm__
+struct start_info {
+    union {
+        struct {
+            xen_pfn_t mfn;
+            uint32_t  evtchn;
+        } domU;
+    } console;
+};
+typedef struct start_info start_info_t;
+#endif
+
 /*
  * a placeholder for the start of day information passed up from the hypervisor
  */
@@ -35,7 +53,6 @@ extern union start_info_union start_info_union;
 #define start_info (start_info_union.start_info)
 
 /* hypervisor.c */
-void force_evtchn_callback(void);
 void do_hypervisor_callback(struct pt_regs *regs);
 void mask_evtchn(uint32_t port);
 void unmask_evtchn(uint32_t port);
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..781144c 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
@@ -83,4 +83,65 @@ typedef intptr_t            ptrdiff_t;
 typedef long ssize_t;
 #endif
 
+#ifdef __arm__
+/*
+ * From
+ *	@(#)quad.h	8.1 (Berkeley) 6/4/93
+ */
+
+#ifdef __BIG_ENDIAN
+#define _QUAD_HIGHWORD 0
+#define _QUAD_LOWWORD 1
+#else /* __LITTLE_ENDIAN */
+#define _QUAD_HIGHWORD 1
+#define _QUAD_LOWWORD 0
+#endif
+
+/*
+ * Define high and low longwords.
+ */
+#define H               _QUAD_HIGHWORD
+#define L               _QUAD_LOWWORD
+
+/*
+ * Total number of bits in a quad_t and in the pieces that make it up.
+ * These are used for shifting, and also below for halfword extraction
+ * and assembly.
+ */
+#define CHAR_BIT        8               /* number of bits in a char */
+#define QUAD_BITS       (sizeof(s64) * CHAR_BIT)
+#define LONG_BITS       (sizeof(long) * CHAR_BIT)
+#define HALF_BITS       (sizeof(long) * CHAR_BIT / 2)
+
+#define B (1 << HALF_BITS) /* digit base */
+/*
+ * Extract high and low shortwords from longword, and move low shortword of
+ * longword to upper half of long, i.e., produce the upper longword of
+ * ((quad_t)(x) << (number_of_bits_in_long/2)).  (`x' must actually be u_long.)
+ *
+ * These are used in the multiply code, to split a longword into upper
+ * and lower halves, and to reassemble a product as a quad_t, shifted left
+ * (sizeof(long)*CHAR_BIT/2).
+ */
+#define HHALF(x)        ((x) >> HALF_BITS)
+#define LHALF(x)        ((x) & ((1 << HALF_BITS) - 1))
+#define LHUP(x)         ((x) << HALF_BITS)
+
+#define COMBINE(a, b) (((u_long)(a) << HALF_BITS) | (b))
+
+/*
+ * Depending on the desired operation, we view a `long long' (aka quad_t) in
+ * one or more of the following formats.
+ */
+union uu {
+    int64_t            q;              /* as a (signed) quad */
+    int64_t            uq;             /* as an unsigned quad */
+    long           sl[2];          /* as two signed longs */
+    unsigned long  ul[2];          /* as two unsigned longs */
+};
+
+/* select a type for digits in base B */
+typedef u_long digit;
+#endif
+
 #endif /* _TYPES_H_ */
diff --git a/extras/mini-os/include/x86/arch_mm.h b/extras/mini-os/include/x86/arch_mm.h
index 23cfca7..3b74cd7 100644
--- a/extras/mini-os/include/x86/arch_mm.h
+++ b/extras/mini-os/include/x86/arch_mm.h
@@ -25,6 +25,8 @@
 #ifndef _ARCH_MM_H_
 #define _ARCH_MM_H_
 
+extern char stack[];
+
 #ifndef __ASSEMBLY__
 #include <xen/xen.h>
 #if defined(__i386__)
diff --git a/extras/mini-os/include/x86/os.h b/extras/mini-os/include/x86/os.h
index f193865..8eea1be 100644
--- a/extras/mini-os/include/x86/os.h
+++ b/extras/mini-os/include/x86/os.h
@@ -64,8 +64,6 @@ extern shared_info_t *HYPERVISOR_shared_info;
 void trap_init(void);
 void trap_fini(void);
 
-void arch_init(start_info_t *si);
-void arch_print_info(void);
 void arch_fini(void);
 
 
@@ -162,6 +160,23 @@ do {									\
  */
 typedef struct { volatile int counter; } atomic_t;
 
+static inline void force_evtchn_callback(void)
+{
+    int save;
+    vcpu_info_t *vcpu;
+    vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()];
+    save = vcpu->evtchn_upcall_mask;
+
+    while (vcpu->evtchn_upcall_pending) {
+        vcpu->evtchn_upcall_mask = 1;
+        barrier();
+        do_hypervisor_callback(NULL);
+        barrier();
+        vcpu->evtchn_upcall_mask = save;
+        barrier();
+    };
+}
+
 
 /************************** i386 *******************************/
 #ifdef __INSIDE_MINIOS__
diff --git a/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h b/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h
index 7083763..4581574 100644
--- a/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h
+++ b/extras/mini-os/include/x86/x86_64/hypercall-x86_64.h
@@ -37,6 +37,7 @@
 #include <xen/xen.h>
 #include <xen/sched.h>
 #include <mini-os/mm.h>
+#include <arch_mm.h>
 
 #define __STR(x) #x
 #define STR(x) __STR(x)
diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
index 386be8f..de25921 100644
--- a/extras/mini-os/kernel.c
+++ b/extras/mini-os/kernel.c
@@ -27,7 +27,6 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include <mini-os/os.h>
 #include <mini-os/hypervisor.h>
 #include <mini-os/mm.h>
 #include <mini-os/events.h>
@@ -118,40 +117,14 @@ __attribute__((weak)) int app_main(start_info_t *si)
     return 0;
 }
 
-/*
- * INITIAL C ENTRY POINT.
- */
-void start_kernel(start_info_t *si)
-{
-    static char hello[] = "Bootstrapping...\n";
-
-    (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(hello), hello);
-
-    arch_init(si);
-
-    trap_init();
-
-    /* print out some useful information  */
-    printk("Xen Minimal OS!\n");
-    printk("  start_info: %p(VA)\n", si);
-    printk("    nr_pages: 0x%lx\n", si->nr_pages);
-    printk("  shared_inf: 0x%08lx(MA)\n", si->shared_info);
-    printk("     pt_base: %p(VA)\n", (void *)si->pt_base); 
-    printk("nr_pt_frames: 0x%lx\n", si->nr_pt_frames);
-    printk("    mfn_list: %p(VA)\n", (void *)si->mfn_list); 
-    printk("   mod_start: 0x%lx(VA)\n", si->mod_start);
-    printk("     mod_len: %lu\n", si->mod_len); 
-    printk("       flags: 0x%x\n", (unsigned int)si->flags);
-    printk("    cmd_line: %s\n",  
-           si->cmd_line ? (const char *)si->cmd_line : "NULL");
+void gic_init(void);
 
+void start_kernel(void)
+{
     /* Set up events. */
     init_events();
-    
-    /* ENABLE EVENT DELIVERY. This is disabled at start of day. */
-    __sti();
 
-    arch_print_info();
+    __sti();
 
     setup_xen_features();
 
@@ -161,24 +134,58 @@ void start_kernel(start_info_t *si)
     /* Init time and timers. */
     init_time();
 
+#ifndef __arm__
     /* Init the console driver. */
     init_console();
+#endif
 
     /* Init grant tables */
     init_gnttab();
-    
+
     /* Init scheduler. */
     init_sched();
  
     /* Init XenBus */
     init_xenbus();
 
+
 #ifdef CONFIG_XENBUS
     create_thread("shutdown", shutdown_thread, NULL);
 #endif
 
+#ifdef __arm__
+    gic_init();
+#endif
+
+//#define VTIMER_TEST
+#ifdef VTIMER_TEST
+    while(1){
+		int x, y, z;
+    	z = 0;
+    	// counter
+    	__asm__ __volatile__("mrrc p15, 1, %0, %1, c14;isb":"=r"(x), "=r"(y));
+    	printk("Counter: %x-%x\n", x, y);
+
+    	__asm__ __volatile__("mrrc p15, 3, %0, %1, c14;isb":"=r"(x), "=r"(y));
+    	printk("CompareValue: %x-%x\n", x, y);
+
+    	// TimerValue
+    	__asm__ __volatile__("mrc p15, 0, %0, c14, c3, 0;isb":"=r"(x));
+    	printk("TimerValue: %x\n", x);
+
+    	// control register
+    	__asm__ __volatile__("mrc p15, 0, %0, c14, c3, 1;isb":"=r"(x));
+    	printk("ControlRegister: %x\n", x);
+    	while(z++ < 0xfffff){}
+    }
+#endif
+
     /* Call (possibly overridden) app_main() */
+#if defined(__arm__) || defined(__aarch64__)
+    app_main(NULL);
+#else
     app_main(&start_info);
+#endif
 
     /* Everything initialised, start idle thread */
     run_idle_thread();
@@ -205,13 +212,12 @@ void stop_kernel(void)
     /* Reset events. */
     fini_events();
 
-    /* Reset traps */
-    trap_fini();
-
     /* Reset arch details */
     arch_fini();
 }
 
+void arch_do_exit(void);
+
 /*
  * do_exit: This is called whenever an IRET fails in entry.S.
  * This will generally be because an application has got itself into
@@ -222,7 +228,7 @@ void stop_kernel(void)
 void do_exit(void)
 {
     printk("Do_exit called!\n");
-    stack_walk();
+    arch_do_exit();
     for( ;; )
     {
         struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_crash };
diff --git a/extras/mini-os/mm.c b/extras/mini-os/mm.c
index d2d5264..ab76018 100644
--- a/extras/mini-os/mm.c
+++ b/extras/mini-os/mm.c
@@ -213,22 +213,26 @@ static void init_page_allocator(unsigned long min, unsigned long max)
     min = round_pgup  (min);
     max = round_pgdown(max);
 
+
     /* Allocate space for the allocation bitmap. */
-    bitmap_size  = (max+1) >> (PAGE_SHIFT+3);
+    bitmap_size  = (max - min + 1) >> (PAGE_SHIFT+3);
     bitmap_size  = round_pgup(bitmap_size);
     alloc_bitmap = (unsigned long *)to_virt(min);
     min         += bitmap_size;
     range        = max - min;
 
+
     /* All allocated by default. */
     memset(alloc_bitmap, ~0, bitmap_size);
     /* Free up the memory we've been given to play with. */
     map_free(PHYS_PFN(min), range>>PAGE_SHIFT);
 
+
     /* The buddy lists are addressed in high memory. */
     min = (unsigned long) to_virt(min);
     max = (unsigned long) to_virt(max);
 
+
     while ( range != 0 )
     {
         /*
@@ -238,7 +242,6 @@ static void init_page_allocator(unsigned long min, unsigned long max)
         for ( i = PAGE_SHIFT; (1UL<<(i+1)) <= range; i++ )
             if ( min & (1UL<<i) ) break;
 
-
         ch = (chunk_head_t *)min;
         min   += (1UL<<i);
         range -= (1UL<<i);
@@ -399,9 +402,7 @@ void *sbrk(ptrdiff_t increment)
 
 void init_mm(void)
 {
-
     unsigned long start_pfn, max_pfn;
-
     printk("MM: Init\n");
 
     arch_init_mm(&start_pfn, &max_pfn);
diff --git a/extras/mini-os/sched.c b/extras/mini-os/sched.c
index 174945e..a1cd3a9 100644
--- a/extras/mini-os/sched.c
+++ b/extras/mini-os/sched.c
@@ -100,15 +100,19 @@ void schedule(void)
         next = NULL;
         MINIOS_TAILQ_FOREACH_SAFE(thread, &thread_list, thread_list, tmp)
         {
+        	DEBUG("Checking thread : %s (runnable:%i)\n", thread->name, is_runnable(thread));
             if (!is_runnable(thread) && thread->wakeup_time != 0LL)
             {
-                if (thread->wakeup_time <= now)
+                if (thread->wakeup_time <= now) {
+                	DEBUG("Wake thread : %s\n", thread->name);
                     wake(thread);
+                }
                 else if (thread->wakeup_time < min_wakeup_time)
                     min_wakeup_time = thread->wakeup_time;
             }
             if(is_runnable(thread)) 
             {
+            	DEBUG("Thread (%s) is runnable, put it next\n", thread->name);
                 next = thread;
                 /* Put this thread on the end of the list */
                 MINIOS_TAILQ_REMOVE(&thread_list, thread, thread_list);
@@ -145,6 +149,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;
diff --git a/extras/mini-os/time.c b/extras/mini-os/time.c
new file mode 100644
index 0000000..4320241
--- /dev/null
+++ b/extras/mini-os/time.c
@@ -0,0 +1,12 @@
+void arch_init_time(void);
+void arch_fini_time(void);
+
+void init_time(void)
+{
+	arch_init_time();
+}
+
+void fini_time(void)
+{
+	arch_fini_time();
+}
diff --git a/extras/mini-os/xenbus/xenbus.c b/extras/mini-os/xenbus/xenbus.c
index 934f23b..8a99ee2 100644
--- a/extras/mini-os/xenbus/xenbus.c
+++ b/extras/mini-os/xenbus/xenbus.c
@@ -27,6 +27,7 @@
 #include <mini-os/wait.h>
 #include <xen/io/xs_wire.h>
 #include <mini-os/spinlock.h>
+#include <mini-os/hypervisor.h>
 #include <mini-os/xmalloc.h>
 
 #define min(x,y) ({                       \
@@ -43,6 +44,7 @@
 #endif
 
 static struct xenstore_domain_interface *xenstore_buf;
+static uint32_t store_evtchn;
 static DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
 DECLARE_WAIT_QUEUE_HEAD(xenbus_watch_queue);
 
@@ -325,20 +327,23 @@ static int allocate_xenbus_id(void)
     return o_probe;
 }
 
+void arch_init_xenbus(struct xenstore_domain_interface **xenstore_buf, uint32_t *store_evtchn);
+
 /* Initialise xenbus. */
 void init_xenbus(void)
 {
     int err;
     DEBUG("init_xenbus called.\n");
-    xenstore_buf = mfn_to_virt(start_info.store_mfn);
+
+    arch_init_xenbus(&xenstore_buf, &store_evtchn);
+
     create_thread("xenstore", xenbus_thread_func, NULL);
     DEBUG("buf at %p.\n", xenstore_buf);
-    err = bind_evtchn(start_info.store_evtchn,
+    err = bind_evtchn(store_evtchn,
 		      xenbus_evtchn_handler,
               NULL);
-    unmask_evtchn(start_info.store_evtchn);
-    printk("xenbus initialised on irq %d mfn %#lx\n",
-	   err, start_info.store_mfn);
+    unmask_evtchn(store_evtchn);
+    printk("xenbus initialised on event %d\n", err);
 }
 
 void fini_xenbus(void)
@@ -420,7 +425,7 @@ static void xb_write(int type, int req_id, xenbus_transaction_t trans_id,
     xenstore_buf->req_prod += len;
 
     /* Send evtchn to notify remote */
-    notify_remote_via_evtchn(start_info.store_evtchn);
+    notify_remote_via_evtchn(store_evtchn);
 }
 
 /* Send a mesasge to xenbus, in the same fashion as xb_write, and
@@ -445,6 +450,7 @@ xenbus_msg_reply(int type,
     remove_waiter(w, req_info[id].waitq);
     wake(current);
 
+    rmb();
     rep = req_info[id].reply;
     BUG_ON(rep->req_id != id);
     release_xenbus_id(id);
-- 
1.9.3

  parent reply	other threads:[~2014-06-02 17:51 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-06-02 17:49 [PATCH 0/4] mini-os: initial ARM support Thomas Leonard
2014-06-02 17:49 ` [PATCH 1/4] mini-os: Fixed shutdown thread Thomas Leonard
2014-06-03  0:51   ` Samuel Thibault
2014-06-03  9:01   ` Andrew Cooper
2014-06-02 17:49 ` [PATCH 2/4] mini-os: Tidied up code Thomas Leonard
2014-06-03  0:57   ` Samuel Thibault
2014-06-02 17:49 ` Thomas Leonard [this message]
2014-06-03  9:12   ` [PATCH 3/4] mini-os: Initial commit to port minios to ARM Julien Grall
2014-06-04 16:06     ` [PATCH 0/7] mini-os: Preparing for ARM support Thomas Leonard
2014-06-04 16:06       ` [PATCH 1/7] mini-os: Fixed shutdown thread Thomas Leonard
2014-06-04 16:06       ` [PATCH 2/7] mini-os: Tidied up code Thomas Leonard
2014-06-04 16:22         ` Andrew Cooper
2014-06-05 10:24           ` Anil Madhavapeddy
2014-06-04 16:06       ` [PATCH 3/7] mini-os: Moved events code under arch Thomas Leonard
2014-06-04 16:23         ` Julien Grall
2014-06-06 13:54           ` Ian Campbell
2014-06-06 13:57         ` Ian Campbell
2014-06-04 16:06       ` [PATCH 4/7] mini-os: Switched initial C entry point to arch_init Thomas Leonard
2014-06-06 14:05         ` Ian Campbell
2014-06-04 16:06       ` [PATCH 5/7] mini-os: Moved arch-specific xenbus code under arch Thomas Leonard
2014-06-05 14:00         ` Julien Grall
2014-06-06 14:07         ` Ian Campbell
2014-06-04 16:06       ` [PATCH 6/7] mini-os: Added rmb to xenbus code Thomas Leonard
2014-06-05 13:55         ` Julien Grall
2014-06-05 17:45           ` Thomas Leonard
2014-06-06  4:59             ` karim.allah.ahmed
2014-06-06 14:15               ` Ian Campbell
2014-06-06 15:10                 ` Samuel Thibault
2014-06-06 16:40                   ` Ian Campbell
2014-06-09 13:56                     ` Thomas Leonard
2014-06-09 14:04                       ` Thomas Leonard
2014-06-04 16:06       ` [PATCH 7/7] mini-os: Moved force_evtchn_callback to header Thomas Leonard
2014-06-06 14:17         ` Ian Campbell
2014-06-09 11:54           ` Thomas Leonard
2014-06-04 16:12       ` [PATCH 0/7] mini-os: Preparing for ARM support Andrew Cooper
2014-06-02 17:49 ` [PATCH 4/4] mini-os: Added FDT support on ARM Thomas Leonard
2014-06-06 13:51   ` Ian Campbell
2014-06-05 14:36 ` [PATCH 0/4] mini-os: initial ARM support Oleksandr Tyshchenko
2014-06-05 14:57   ` Samuel Thibault
2014-06-05 17:20     ` Oleksandr Tyshchenko
2014-06-05 17:31   ` Thomas Leonard
2014-06-05 18:07     ` Oleksandr Tyshchenko
2014-06-05 18:12       ` Thomas Leonard
2014-06-05 18:21         ` Oleksandr Tyshchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1401731397-29842-4-git-send-email-talex5@gmail.com \
    --to=talex5@gmail.com \
    --cc=samuel.thibault@ens-lyon.org \
    --cc=stefano.stabellini@eu.citrix.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).