All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Leonard <talex5@gmail.com>
To: xen-devel@lists.xenproject.org
Cc: Thomas Leonard <talex5@gmail.com>,
	Dave.Scott@eu.citrix.com, anil@recoil.org,
	stefano.stabellini@eu.citrix.com, samuel.thibault@ens-lyon.org
Subject: [PATCH ARM v5 19/20] mini-os: initial ARM support
Date: Thu, 26 Jun 2014 12:28:36 +0100	[thread overview]
Message-ID: <1403782117-15125-20-git-send-email-talex5@gmail.com> (raw)
In-Reply-To: <1403782117-15125-1-git-send-email-talex5@gmail.com>

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

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

Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@gmail.com>
[talex5@gmail.com: made x86_64 support work again]
[talex5@gmail.com: split into multiple patches]
[talex5@gmail.com: re-enabled force_evtchn_callback]
[talex5@gmail.com: enable regular console]
[talex5@gmail.com: fixed initialisation code:
- Configure write-back caching in page table. This is needed for
  reliable hypercalls to Xen (thanks to Julien Grall).
- Use "client mode" for access control (domains are deprecated,
  according to ARM Cortex-A Series Programmer’s Guide version 4.0,
  section 9.6.4).
- Enable more SCTLR features (icache, branch prediction)]
[talex5@gmail.com: use Virtual Count register for monotonic time]
[talex5@gmail.com: fixed HYPERVISOR_shutdown]
[talex5@gmail.com: get xenstore details from hypervisor]
[talex5@gmail.com: use GCC implementation of division]
[talex5@gmail.com: cleaned up interrupt handlers and threading]
[talex5@gmail.com: call exit_thread when a thread returns]
[talex5@gmail.com: implemented block_domain for ARM]
[talex5@gmail.com: fixed hang when enabling interrupts]
[talex5@gmail.com: added -march=armv7-a to flags]
[talex5@gmail.com: CLREX after handling IRQs]
[talex5@gmail.com: unbind debug port at shutdown]
[talex5@gmail.com: allow unaligned accesses]
[talex5@gmail.com: fix zImage header for XSA-95]
[talex5@gmail.com: get RAM base and size from the FDT]
[talex5@gmail.com: get GIC addresses from FDT]
[talex5@gmail.com: added ARM grant table initialisation]
[talex5@gmail.com: added missing copyright header to hypercalls32.S]
[talex5@gmail.com: moved GIC driver to arm directory]
[talex5@gmail.com: fixes suggested by Julien Grall:
- Removed unnecessary isb.
- Renamed GICD_PRIORITY to GICD_IPRIORITYR.
- Change IRQ number type from unsigned char to int.
- Added volatile to {set,clear}_bit_non_atomic.
- Fixed some comments.
- Check compatible properties in DTB.]
[talex5@gmail.com: made image relocatable]
[talex5@gmail.com: added mfn_to_pfn and pfn_to_mfn]
Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
 extras/mini-os/ARM-TODO.txt              |   6 +
 extras/mini-os/Config.mk                 |   2 +
 extras/mini-os/Makefile                  |   9 ++
 extras/mini-os/arch/arm/Makefile         |  32 ++++
 extras/mini-os/arch/arm/arch.mk          |   7 +
 extras/mini-os/arch/arm/arm32.S          | 266 +++++++++++++++++++++++++++++++
 extras/mini-os/arch/arm/events.c         |  30 ++++
 extras/mini-os/arch/arm/gic.c            | 222 ++++++++++++++++++++++++++
 extras/mini-os/arch/arm/hypercalls32.S   |  75 +++++++++
 extras/mini-os/arch/arm/minios-arm32.lds |  75 +++++++++
 extras/mini-os/arch/arm/mm.c             | 134 ++++++++++++++++
 extras/mini-os/arch/arm/sched.c          |  37 +++++
 extras/mini-os/arch/arm/setup.c          | 116 ++++++++++++++
 extras/mini-os/arch/arm/time.c           | 202 +++++++++++++++++++++++
 extras/mini-os/kernel.c                  |   2 +-
 15 files changed, 1214 insertions(+), 1 deletion(-)
 create mode 100644 extras/mini-os/ARM-TODO.txt
 create mode 100755 extras/mini-os/arch/arm/Makefile
 create mode 100644 extras/mini-os/arch/arm/arch.mk
 create mode 100644 extras/mini-os/arch/arm/arm32.S
 create mode 100644 extras/mini-os/arch/arm/events.c
 create mode 100644 extras/mini-os/arch/arm/gic.c
 create mode 100644 extras/mini-os/arch/arm/hypercalls32.S
 create mode 100755 extras/mini-os/arch/arm/minios-arm32.lds
 create mode 100644 extras/mini-os/arch/arm/mm.c
 create mode 100644 extras/mini-os/arch/arm/sched.c
 create mode 100644 extras/mini-os/arch/arm/setup.c
 create mode 100644 extras/mini-os/arch/arm/time.c

diff --git a/extras/mini-os/ARM-TODO.txt b/extras/mini-os/ARM-TODO.txt
new file mode 100644
index 0000000..c85ee5b
--- /dev/null
+++ b/extras/mini-os/ARM-TODO.txt
@@ -0,0 +1,6 @@
+* support abort exception handling ( and others )
+* gic request_irq implementation, currently all IRQs all hardcoded in gic irq handler.
+* bind_*
+* add multiple cpu support (?)
+* map_frames
+* make sure that wallclock is functioning properly
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 931cd05..01d8af0 100644
--- a/extras/mini-os/Makefile
+++ b/extras/mini-os/Makefile
@@ -78,6 +78,9 @@ TARGET := mini-os
 SUBDIRS := lib xenbus console
 
 ifeq ($(XEN_TARGET_ARCH),arm32)
+# Need libgcc.a for division helpers
+LDLIBS += `$(CC) -print-libgcc-file-name`
+
 # Device tree support
 SUBDIRS += lib/fdt
 src-y += lib/fdt/fdt.c
@@ -109,7 +112,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
@@ -203,7 +208,11 @@ $(OBJ_DIR)/$(TARGET): $(OBJS) $(APP_O) arch_lib
 	$(LD) -r $(LDFLAGS) $(HEAD_OBJ) $(APP_O) $(OBJS) $(LDARCHLIB) $(LDLIBS) -o $@.o
 	$(OBJCOPY) -w -G $(GLOBAL_PREFIX)* -G _start $@.o $@.o
 	$(LD) $(LDFLAGS) $(LDFLAGS_FINAL) $@.o $(EXTRA_OBJS) -o $@
+ifeq ($(XEN_TARGET_ARCH),arm32)
+	$(OBJCOPY) -O binary $@ $@.img
+else
 	gzip -f -9 -c $@ >$@.gz
+endif
 
 .PHONY: clean arch_clean
 
diff --git a/extras/mini-os/arch/arm/Makefile b/extras/mini-os/arch/arm/Makefile
new file mode 100755
index 0000000..8b78651
--- /dev/null
+++ b/extras/mini-os/arch/arm/Makefile
@@ -0,0 +1,32 @@
+#
+# ARM architecture specific makefiles.
+#
+
+XEN_ROOT = $(CURDIR)/../../../..
+include $(XEN_ROOT)/Config.mk
+include ../../Config.mk
+
+# include arch.mk has to be before minios.mk!
+
+include arch.mk
+include ../../minios.mk
+
+# Sources here are all *.c (without $(XEN_TARGET_ARCH).S)
+# This is handled in $(HEAD_ARCH_OBJ)
+ARCH_SRCS := $(wildcard *.c)
+
+# The objects built from the sources.
+ARCH_OBJS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(ARCH_SRCS))
+
+ARCH_OBJS += hypercalls32.o
+
+all: $(OBJ_DIR)/$(ARCH_LIB)
+
+# $(HEAD_ARCH_OBJ) is only built here, needed on linking
+# in ../../Makefile.
+$(OBJ_DIR)/$(ARCH_LIB): $(ARCH_OBJS) $(OBJ_DIR)/$(HEAD_ARCH_OBJ)
+	$(AR) rv $(OBJ_DIR)/$(ARCH_LIB) $(ARCH_OBJS)
+
+clean:
+	rm -f $(OBJ_DIR)/$(ARCH_LIB) $(ARCH_OBJS) $(OBJ_DIR)/$(HEAD_ARCH_OBJ)
+
diff --git a/extras/mini-os/arch/arm/arch.mk b/extras/mini-os/arch/arm/arch.mk
new file mode 100644
index 0000000..ab20d99
--- /dev/null
+++ b/extras/mini-os/arch/arm/arch.mk
@@ -0,0 +1,7 @@
+ifeq ($(XEN_TARGET_ARCH),arm32)
+DEF_ASFLAGS += -march=armv7-a
+ARCH_CFLAGS  := -march=armv7-a -marm -fms-extensions -D__arm__ -DXEN_HAVE_PV_GUEST_ENTRY #-DCPU_EXCLUSIVE_LDST
+EXTRA_INC += $(TARGET_ARCH_FAM)/$(XEN_TARGET_ARCH)
+EXTRA_SRC += arch/$(EXTRA_INC)
+endif
+
diff --git a/extras/mini-os/arch/arm/arm32.S b/extras/mini-os/arch/arm/arm32.S
new file mode 100644
index 0000000..de74ed9
--- /dev/null
+++ b/extras/mini-os/arch/arm/arm32.S
@@ -0,0 +1,266 @@
+@ Virtual address of the start of RAM (any value will do, but it must be
+@ section-aligned). Update the lds script if changed.
+#define VIRT_BASE 0x400000
+
+@ Offset of the kernel within the RAM. This is a zImage convention which we
+@ rely on.
+#define ZIMAGE_KERNEL_OFFSET 0x8000
+
+@ Desired virtual address of _start. Must match value in .lds file.
+#define VIRT_START (VIRT_BASE + ZIMAGE_KERNEL_OFFSET)
+
+.section .text
+
+.globl _start
+_start:
+	@ zImage header
+.rept   8
+        mov     r0, r0
+.endr
+        b       reset
+        .word   0x016f2818      @ Magic numbers to help the loader
+        .word   0		@ zImage start address (0 = relocatable)
+        .word   _edata - _start @ zImage end address (excludes bss section)
+	@ end of zImage header
+
+@ Called at boot time. Sets up MMU, exception vectors and stack, and then calls C arch_init() function.
+@ => r2 -> DTB
+@ <= never returns
+@ Note: this boot code needs to be within the first (1MB - ZIMAGE_KERNEL_OFFSET) of _start.
+reset:
+	@ Problem: the C code wants to be at a known address (VIRT_BASE), but Xen might
+	@ load us anywhere. We initialise the MMU (mapping virtual to physical @ addresses)
+	@ so everything ends up where the code expects it to be.
+	@
+	@ We calculate the offet between where the linker thought _start would be and where
+	@ it actually is and initialise the page tables to have that offset for every page.
+	@
+	@ When we turn on the MMU, we're still executing at the old address. We don't want
+	@ the code to disappear from under us. So we have to do the mapping in stages:
+	@
+	@ 1. set up a mapping to our current page from both its current and desired addresses
+	@ 2. enable the MMU
+	@ 3. jump to the new address
+	@ 4. remap all the other pages with the calculated offset
+
+	adr	r1, _start		@ r1 = physical address of _start
+	ldr	r3, =VIRT_START		@ r3 = (desired) virtual address of _start
+	sub 	r9, r1, r3		@ r9 = (physical - virtual) offset
+
+	ldr	r7, =page_dir		@ r7 = (desired) virtual addr of page_dir
+	add	r1, r7, r9		@ r1 = physical addr of page_dir
+
+	@ Tell the system where our page table is located.
+	mcr	p15, 0, r1, c2, c0, 0	@ set ttbr0 = r1
+
+	@ Set access permission for domains.
+	@ Domains are deprecated, but we have to configure them anyway.
+	@ We mark every page as being domain 0 and set domain 0 to "client mode"
+	@ (client mode = use access flags in page table).
+	mov	r0, #1			@ 1 = client
+	mcr	p15, 0, r0, c3, c0, 0	@ DACR
+
+	@ Template (flags) for a 1 MB page-table entry.
+	@ TEX[2:0] C B = 001 1 1 (outer and inner write-back, write-allocate)
+	ldr	r8, =(0x2 +  		/* Section entry */ \
+		      0xc +  		/* C B */ \
+		      (3 << 10) + 	/* Read/write */ \
+		      (1 << 12) +	/* TEX */ \
+		      (1 << 16) +	/* Sharable */ \
+		      (1<<19))		/* Non-secure */
+	@ r8 = template page table entry
+
+	@ Add two entries for the current physical section, at the old and new
+	@ addresses.
+	@ It's OK if they're the same. It's even OK if the new section overlaps
+	@ the physical address of the page table, since the MMU is still turned off.
+	mov	r0, pc, lsr#20
+	mov	r0, r0, lsl#20		@ r0 = physical address of this code's section start
+	orr	r3, r0, r8		@ r3 = table entry for this section
+	str	r3, [r1, #VIRT_BASE >> 18] @ map desired virtual section to this code
+	str	r3, [r1, r0, lsr#18]	@ map current section to this code too
+
+	@ Map the section containing the page table to its desired address, if possible.
+	@ We need to make sure the desired virtual section doesn't match the old address of the
+	@ code, since that needs to remain valid briefly after the MMU is turned on.
+	mov	r3, r1, lsr#20		@ r3 = physical section number containing page table
+	rsb	r4, r9, r3, lsl#20	@ r4 = desired virtual address of page table's section
+	orr	r3, r8, r3, lsl#20	@ r3 = table entry for page table
+	cmp	r4, r0			@ is r4 where we're executing from?
+	movne	r5, r4			@ use it if not
+	addeq	r5, r4, #1<<20		@ else use next section instead
+	str	r3, [r1, r5, lsr#18]	@ add section entry for page table itself
+	@ r5 = temporary virtual address of page table section
+
+	@ Invalidate TLB
+	mcr	p15, 0, r1, c8, c7, 0	@ TLBIALL
+
+	@ Enable MMU / SCTLR
+	@ We leave caches off for now because we're going to be changing the
+	@ TLB a lot and this avoids having to flush the caches each time.
+	mrc	p15, 0, r1, c1, c0, 0	@ SCTLR
+	orr	r1, r1, #0x1		@ Enable MMU
+	mcr	p15, 0, r1, c1, c0, 0	@ SCTLR
+	isb
+
+	adr	r1, stage2		@ Physical address of stage2
+	sub	r1, r1, r9		@ Virtual address of stage2
+	bx	r1
+
+@ Called once the MMU is enabled. The boot code and the page table are mapped,
+@ but nothing else is yet.
+@
+@ => r2 -> dtb (physical)
+@    r3 = page table entry for page table itself
+@    r4 = desired virtual address of page table's section
+@    r5 = temporary virtual address of page table's section
+@    r7 = desired virtual address of page table
+@    r8 = section entry template (flags)
+@    r9 = desired physical - virtual offset
+@    pc -> somewhere in newly-mapped virtual code section
+stage2:
+	@ Remap page table to its final location, now it can't clash with our
+	@ execution address.
+	sub	r5, r5,	r4		@ r5 = difference between desired and actual
+	add	r5, r5, r7		@ r5 = temporary virtual address of page_dir
+	str	r3, [r5, r4, lsr#18]	@ map page table section at desired address
+
+	@ Invalidate TLB
+	mcr	p15, 0, r1, c8, c7, 0	@ TLBIALL
+	isb
+
+	@ The new mapping has now taken effect:
+	@ r7 -> page_dir
+
+	@ Fill in the whole top-level translation table (at page_dir).
+	@ Populate the whole pagedir with 1MB section descriptors.
+
+	mov	r1, r7			@ r1 -> first section entry
+	add	r3, r1, #4*4*1024	@ limit (4 GB address space, 4 byte entries)
+	orr	r0, r8, r9		@ r0 = entry mapping section zero to start of physical RAM
+1:
+	str	r0, [r1],#4		@ write the section entry
+	add	r0, r0, #1 << 20 	@ next physical page (wraps)
+	cmp	r1, r3
+	bne	1b
+
+	@ Invalidate TLB
+	mcr	p15, 0, r1, c8, c7, 0	@ TLBIALL
+	isb
+
+	@ At this point, everything is mapped to its final location.
+	@ It's now safe to turn on caching.
+	ldr	r0, =(3 << 11) + 4	@ icache, branch prediction, dcache
+	mrc	p15, 0, r1, c1, c0, 0	@ SCTLR
+	orr	r1, r1, r0
+	mcr	p15, 0, r1, c1, c0, 0	@ SCTLR
+
+	@ Set VBAR -> exception_vector_table
+	@ SCTLR.V = 0
+	adr	r0, exception_vector_table
+	mcr	p15, 0, r0, c12, c0, 0
+
+	@ Initialise 16 KB stack
+	ldr	sp, =stack_end
+
+	@ Store virtual -> physical offset for C code
+	ldr	r0, =physical_address_offset
+	str	r9, [r0]
+
+	sub	r0, r2, r9		@ r0 -> device tree (virtual address)
+
+	b	arch_init
+
+.pushsection .data
+_data:
+.align	14
+.globl page_dir
+@ Each word maps one 1MB virtual section to a physical section
+page_dir:
+	.fill (4*1024), 4, 0x0
+
+.align 12
+.globl shared_info_page
+shared_info_page:
+	.fill (1024), 4, 0x0
+
+.align 3
+.globl stack
+stack:
+	.fill (4*1024), 4, 0x0
+stack_end:
+
+.align 3
+irqstack:
+	.fill (1024), 4, 0x0
+irqstack_end:
+
+.globl physical_address_offset
+physical_address_offset:
+	.long 	0
+
+.popsection
+
+@ exception base address
+.align 5
+.globl exception_vector_table
+@ Note: remember to call CLREX if returning from an exception:
+@ "The architecture enables the local monitor to treat any exclusive store as
+@  matching a previous LDREX address. For this reason, use of the CLREX
+@  instruction to clear an existing tag is required on context switches."
+@ -- ARM Cortex-A Series Programmer’s Guide (Version: 4.0)
+exception_vector_table:
+	b	. @ reset
+	b	. @ undefined instruction
+	b	. @ supervisor call
+	b	. @ prefetch call
+	b	. @ prefetch abort
+	b	. @ data abort
+	b	irq_handler @ irq
+	.word 0xe7f000f0    @ abort on FIQ
+
+irq_handler:
+	ldr	sp, =irqstack_end
+	push	{r0 - r12, r14}
+
+	ldr	r0, IRQ_handler
+	cmp	r0, #0
+	.word	0x07f000f0    	@ undeq - panic if no handler
+	blx	r0		@ call handler
+
+	@ Return from IRQ
+	pop	{r0 - r12, r14}
+	clrex
+	subs	pc, lr, #4
+
+.globl IRQ_handler
+IRQ_handler:
+	.long	0x0
+
+
+.globl __arch_switch_threads
+@ => r0 = &prev->sp
+@    r1 = &next->sp
+@ <= returns to next thread's saved return address
+__arch_switch_threads:
+	stmia	r0, {sp, lr}	@ Store current sp and ip to prev's struct thread
+	str	fp, [sp, #-4]	@ Store fp on the old stack
+
+	ldmia	r1, {sp, lr}	@ Load new sp, ip from next's struct thread
+	ldr	fp, [sp, #-4]	@ Restore fp from the stack
+
+	mov	pc, lr
+
+@ This is called if you try to divide by zero. For now, we make a supervisor call,
+@ which will make us halt.
+.globl raise
+raise:
+	svc	0
+
+.globl arm_start_thread
+arm_start_thread:
+	pop	{r0, r1}
+	@ r0 = user data
+	@ r1 -> thread's main function
+	ldr	lr, =exit_thread
+	bx	r1
diff --git a/extras/mini-os/arch/arm/events.c b/extras/mini-os/arch/arm/events.c
new file mode 100644
index 0000000..517e763
--- /dev/null
+++ b/extras/mini-os/arch/arm/events.c
@@ -0,0 +1,30 @@
+#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_unbind_ports(void)
+{
+    if(debug_port != -1)
+    {
+        mask_evtchn(debug_port);
+        unbind_evtchn(debug_port);
+    }
+}
+
+void arch_fini_events(void)
+{
+}
diff --git a/extras/mini-os/arch/arm/gic.c b/extras/mini-os/arch/arm/gic.c
new file mode 100644
index 0000000..5641eb0
--- /dev/null
+++ b/extras/mini-os/arch/arm/gic.c
@@ -0,0 +1,222 @@
+// ARM GIC implementation
+
+#include <mini-os/os.h>
+#include <mini-os/hypervisor.h>
+#include <libfdt.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 void (*IRQ_handler)(void);
+
+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_IPRIORITYR   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, int irq_number, unsigned char priority)
+{
+    uint32_t value;
+    uint32_t *addr = REG(gicd(gic, GICD_IPRIORITYR)) + (irq_number >> 2);
+    value = REG_READ32(addr);
+    value &= ~(0xff << (8 * (irq_number & 0x3))); // clear old priority
+    value |= priority << (8 * (irq_number & 0x3)); // set new priority
+    REG_WRITE32(addr, value);
+}
+
+static void gic_route_interrupt(struct gic *gic, int irq_number, unsigned char cpu_set)
+{
+    uint32_t value;
+    uint32_t *addr = REG(gicd(gic, GICD_ITARGETSR)) + (irq_number >> 2);
+    value = REG_READ32(addr);
+    value &= ~(0xff << (8 * (irq_number & 0x3))); // clear old target
+    value |= cpu_set << (8 * (irq_number & 0x3)); // set new target
+    REG_WRITE32(addr, value);
+}
+
+/* When accessing the GIC registers, we can't use LDREX/STREX because it's not regular memory. */
+static __inline__ void clear_bit_non_atomic(int nr, volatile void *base)
+{
+    volatile uint32_t *tmp = base;
+    tmp[nr >> 5] &= (unsigned long)~(1 << (nr & 0x1f));
+}
+
+static __inline__ void set_bit_non_atomic(int nr, volatile void *base)
+{
+    volatile uint32_t *tmp = base;
+    tmp[nr >> 5] |= (1 << (nr & 0x1f));
+}
+
+/* Note: not thread safe (but we only support one CPU for now anyway) */
+static void gic_enable_interrupt(struct gic *gic, int 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_non_atomic((irq_number * 2) + 1, cfg_reg) : set_bit_non_atomic((irq_number * 2) + 1, cfg_reg);
+    if(ppi)
+        clear_bit_non_atomic((irq_number * 2), cfg_reg);
+
+    wmb();
+
+    // enable forwarding interrupt from distributor to cpu interface
+    set_enable_reg = (void *)gicd(gic, GICD_ISENABLER);
+    set_bit_non_atomic(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 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
+
+static void gic_handler(void) {
+    unsigned int irq = gic_readiar(&gic);
+
+    DEBUG("IRQ received : %i\n", irq);
+    switch(irq) {
+    case EVENTS_IRQ:
+        do_hypervisor_callback(NULL);
+        break;
+    case VIRTUALTIMER_IRQ:
+        timer_handler(0, NULL, 0);
+        break;
+    default:
+        DEBUG("Unhandled irq\n");
+        break;
+    }
+
+    DEBUG("EIRQ\n");
+
+    gic_eoir(&gic, irq);
+}
+
+void gic_init(void) {
+    gic.gicd_base = NULL;
+    int node = 0;
+    int depth = 0;
+    for (;;)
+    {
+        node = fdt_next_node(device_tree, node, &depth);
+        if (node <= 0 || depth < 0)
+            break;
+
+        if (fdt_getprop(device_tree, node, "interrupt-controller", NULL)) {
+            int len = 0;
+
+            if (fdt_node_check_compatible(device_tree, node, "arm,cortex-a15-gic") &&
+                fdt_node_check_compatible(device_tree, node, "arm,cortex-a9-gic") &&
+                fdt_node_check_compatible(device_tree, node, "arm,cortex-a7-gic")) {
+                printk("Skipping incompatible interrupt-controller node\n");
+                continue;
+            }
+
+            const uint64_t *reg = fdt_getprop(device_tree, node, "reg", &len);
+            if (reg == NULL || len != 32) {
+                /* TODO: support other formats */
+                printk("Bad 'reg' property: %p %d\n", reg, len);
+                continue;
+            }
+            gic.gicd_base = to_virt((long) fdt64_to_cpu(reg[0]));
+            gic.gicc_base = to_virt((long) fdt64_to_cpu(reg[2]));
+            printk("Found GIC: gicd_base = %p, gicc_base = %p\n", gic.gicd_base, gic.gicc_base);
+            break;
+        }
+    }
+    if (!gic.gicd_base) {
+        printk("GIC not found!\n");
+        BUG();
+    }
+    wmb();
+
+    IRQ_handler = gic_handler;
+
+    gic_disable_interrupts(&gic);
+    gic_cpu_set_priority(&gic, 0xff);
+
+    /* Must call gic_enable_interrupts before enabling individual interrupts, otherwise our IRQ handler
+     * gets called endlessly with spurious interrupts. */
+    gic_enable_interrupts(&gic);
+
+    gic_enable_interrupt(&gic, EVENTS_IRQ /* interrupt number */, 0x1 /*cpu_set*/, 1 /*level_sensitive*/, 0 /* ppi */);
+    gic_enable_interrupt(&gic, VIRTUALTIMER_IRQ /* interrupt number */, 0x1 /*cpu_set*/, 1 /*level_sensitive*/, 1 /* ppi */);
+}
diff --git a/extras/mini-os/arch/arm/hypercalls32.S b/extras/mini-os/arch/arm/hypercalls32.S
new file mode 100644
index 0000000..0d7662d
--- /dev/null
+++ b/extras/mini-os/arch/arm/hypercalls32.S
@@ -0,0 +1,75 @@
+/******************************************************************************
+ * hypercall.S
+ *
+ * Xen hypercall wrappers
+ *
+ * Stefano Stabellini <stefano.stabellini@eu.citrix.com>, Citrix, 2012
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when 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.
+ */
+
+#define __HYPERVISOR_memory_op            12
+#define __HYPERVISOR_xen_version          17
+#define __HYPERVISOR_console_io           18
+#define __HYPERVISOR_grant_table_op       20
+#define __HYPERVISOR_vcpu_op              24
+#define __HYPERVISOR_xsm_op               27
+#define __HYPERVISOR_sched_op             29
+#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 __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
+
+_hypercall2(sched_op);
+_hypercall2(memory_op);
+_hypercall2(event_channel_op);
+_hypercall2(xen_version);
+_hypercall3(console_io);
+_hypercall1(physdev_op);
+_hypercall3(grant_table_op);
+_hypercall3(vcpu_op);
+_hypercall1(sysctl);
+_hypercall1(domctl);
+_hypercall2(hvm_op);
+_hypercall1(xsm_op);
diff --git a/extras/mini-os/arch/arm/minios-arm32.lds b/extras/mini-os/arch/arm/minios-arm32.lds
new file mode 100755
index 0000000..b18ca55
--- /dev/null
+++ b/extras/mini-os/arch/arm/minios-arm32.lds
@@ -0,0 +1,75 @@
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0x408000;
+  _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 */
+
+  /* Nothing after here is included in the zImage's size */
+
+  __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..5e38a88
--- /dev/null
+++ b/extras/mini-os/arch/arm/mm.c
@@ -0,0 +1,134 @@
+#include <console.h>
+#include <xen/memory.h>
+#include <arch_mm.h>
+#include <mini-os/hypervisor.h>
+#include <libfdt.h>
+#include <lib.h>
+
+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)
+{
+    int memory;
+    int prop_len = 0;
+    const uint64_t *regs;
+
+    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);
+
+    if (fdt_num_mem_rsv(device_tree) != 0)
+        printk("WARNING: reserved memory not supported!\n");
+
+    memory = fdt_node_offset_by_prop_value(device_tree, -1, "device_type", "memory", sizeof("memory"));
+    if (memory < 0) {
+        printk("No memory found in FDT!\n");
+        BUG();
+    }
+
+    /* Xen will always provide us at least one bank of memory.
+     * Mini-OS will use the first bank for the time-being. */
+    regs = fdt_getprop(device_tree, memory, "reg", &prop_len);
+    if (regs == NULL || prop_len != 16) {
+        /* TODO: support other formats */
+        printk("Bad 'reg' property: %p %d\n", regs, prop_len);
+        BUG();
+    }
+
+    unsigned int end = (unsigned int) &_end;
+    unsigned int mem_base = fdt64_to_cpu(regs[0]);
+    unsigned int mem_size = fdt64_to_cpu(regs[1]);
+    printk("Found memory at %p (len 0x%x)\n", mem_base, mem_size);
+
+    BUG_ON(to_virt(mem_base) > (void *) &_text);          /* Our image isn't in our RAM! */
+    *start_pfn_p = PFN_UP(to_phys(end));
+    int heap_len = mem_size - (PFN_PHYS(*start_pfn_p) - mem_base);
+    *max_pfn_p = *start_pfn_p + PFN_DOWN(heap_len);
+
+    printk("Using pages %d to %d as free space for heap.\n", *start_pfn_p, *max_pfn_p);
+
+    /* The device tree is probably in memory that we're about to hand over to the page
+     * allocator, so move it to the end and reserve that space.
+     */
+    int fdt_size = fdt_totalsize(device_tree);
+    void *new_device_tree = to_virt(((*max_pfn_p << PAGE_SHIFT) - fdt_size) & PAGE_MASK);
+    if (new_device_tree != device_tree) {
+        memmove(new_device_tree, device_tree, fdt_size);
+    }
+    device_tree = new_device_tree;
+    *max_pfn_p = to_phys(new_device_tree) >> PAGE_SHIFT;
+}
+
+void arch_init_p2m(unsigned long max_pfn)
+{
+}
+
+void arch_init_demand_mapping_area(unsigned long cur_pfn)
+{
+}
+
+/* Get Xen's suggested physical page assignments for the grant table. */
+static unsigned long get_gnttab_base(void)
+{
+    int hypervisor;
+    int len = 0;
+    const uint64_t *regs;
+    unsigned int gnttab_base;
+
+    hypervisor = fdt_node_offset_by_compatible(device_tree, -1, "xen,xen");
+    BUG_ON(hypervisor < 0);
+
+    regs = fdt_getprop(device_tree, hypervisor, "reg", &len);
+    if (regs == NULL || len != 16) {
+        /* TODO: support other formats */
+        printk("Bad 'reg' property: %p %d\n", regs, len);
+        BUG();
+    }
+
+    gnttab_base = fdt64_to_cpu(regs[0]);
+
+    printk("FDT suggests grant table base %lx\n", gnttab_base);
+
+    return gnttab_base;
+}
+
+grant_entry_t *arch_init_gnttab(int nr_grant_frames)
+{
+    struct xen_add_to_physmap xatp;
+    struct gnttab_setup_table setup;
+    xen_pfn_t frames[nr_grant_frames];
+    unsigned long gnttab_table;
+    int i, rc;
+
+    gnttab_table = get_gnttab_base();
+
+    for (i = 0; i < nr_grant_frames; i++)
+    {
+        xatp.domid = DOMID_SELF;
+        xatp.size = 0;      /* Seems to be unused */
+        xatp.space = XENMAPSPACE_grant_table;
+        xatp.idx = i;
+        xatp.gpfn = (gnttab_table >> PAGE_SHIFT) + i;
+        rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp);
+        BUG_ON(rc != 0);
+    }
+
+    setup.dom = DOMID_SELF;
+    setup.nr_frames = nr_grant_frames;
+    set_xen_guest_handle(setup.frame_list, frames);
+    HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
+    if (setup.status != 0)
+    {
+        printk("GNTTABOP_setup_table failed; status = %d\n", setup.status);
+        BUG();
+    }
+
+    return to_virt(gnttab_table);
+}
diff --git a/extras/mini-os/arch/arm/sched.c b/extras/mini-os/arch/arm/sched.c
new file mode 100644
index 0000000..1306c1b
--- /dev/null
+++ b/extras/mini-os/arch/arm/sched.c
@@ -0,0 +1,37 @@
+#include <mini-os/sched.h>
+#include <mini-os/xmalloc.h>
+
+void arm_start_thread(void);
+
+/* Architecture specific setup of thread creation */
+struct thread* arch_create_thread(char *name, void (*function)(void *),
+                                  void *data)
+{
+    struct thread *thread;
+
+    thread = xmalloc(struct thread);
+    /* We can't use lazy allocation here since the trap handler runs on the stack */
+    thread->stack = (char *)alloc_pages(STACK_SIZE_PAGE_ORDER);
+    thread->name = name;
+    printk("Thread \"%s\": pointer: 0x%lx, stack: 0x%lx\n", name, thread,
+            thread->stack);
+
+    /* Save pointer to the thread on the stack, used by current macro */
+    *((unsigned long *)thread->stack) = (unsigned long)thread;
+
+    /* Push the details to pass to arm_start_thread onto the stack */
+    int *sp = (int *) (thread->stack + STACK_SIZE);
+    *(--sp) = (int) function;
+    *(--sp) = (int) data;
+    thread->sp = (unsigned long) sp;
+
+    thread->ip = (unsigned long) arm_start_thread;
+
+    return thread;
+}
+
+void run_idle_thread(void)
+{
+    __asm__ __volatile__ ("mov sp, %0; mov pc, %1"::"r"(idle_thread->sp), "r"(idle_thread->ip));
+    /* Never arrive here! */
+}
diff --git a/extras/mini-os/arch/arm/setup.c b/extras/mini-os/arch/arm/setup.c
new file mode 100644
index 0000000..721e59f
--- /dev/null
+++ b/extras/mini-os/arch/arm/setup.c
@@ -0,0 +1,116 @@
+#include <mini-os/os.h>
+#include <mini-os/kernel.h>
+#include <mini-os/gic.h>
+#include <xen/xen.h>
+#include <xen/memory.h>
+#include <xen/hvm/params.h>
+#include <arch_mm.h>
+#include <libfdt.h>
+
+/*
+ * This structure contains start-of-day info, such as pagetable base pointer,
+ * address of the shared_info structure, and things like that.
+ * On x86, the hypervisor passes it to us. On ARM, we fill it in ourselves.
+ */
+union start_info_union start_info_union;
+
+/*
+ * Shared page for communicating with the hypervisor.
+ * Events flags go here, for example.
+ */
+shared_info_t *HYPERVISOR_shared_info;
+
+extern char shared_info_page[PAGE_SIZE];
+
+void *device_tree;
+
+static int hvm_get_parameter(int idx, uint64_t *value)
+{
+    struct xen_hvm_param xhv;
+    int ret;
+
+    xhv.domid = DOMID_SELF;
+    xhv.index = idx;
+    ret = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv);
+    if (ret < 0) {
+        BUG();
+    }
+    *value = xhv.value;
+    return ret;
+}
+
+static void get_console(void)
+{
+    uint64_t v = -1;
+
+    hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
+    start_info.console.domU.evtchn = v;
+
+    hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v);
+    start_info.console.domU.mfn = v;
+
+    printk("Console is on port %d\n", start_info.console.domU.evtchn);
+    printk("Console ring is at mfn %x\n", start_info.console.domU.mfn);
+}
+
+void get_xenbus(void)
+{
+    uint64_t value;
+
+    if (hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &value))
+        BUG();
+
+    start_info.store_evtchn = (int)value;
+
+    if(hvm_get_parameter(HVM_PARAM_STORE_PFN, &value))
+        BUG();
+    start_info.store_mfn = (unsigned long)value;
+}
+
+/*
+ * INITIAL C ENTRY POINT.
+ */
+void arch_init(void *dtb_pointer)
+{
+    struct xen_add_to_physmap xatp;
+    int r;
+
+    memset(&__bss_start, 0, &_end - &__bss_start);
+
+    xprintk("Virtual -> physical offset = %x\n", physical_address_offset);
+
+    xprintk("Checking DTB at %x...\n", dtb_pointer);
+
+    if ((r = fdt_check_header(dtb_pointer))) {
+        xprintk("Invalid DTB from Xen: %s\n", fdt_strerror(r));
+        BUG();
+    }
+    device_tree = dtb_pointer;
+
+    /* Map shared_info page */
+    xatp.domid = DOMID_SELF;
+    xatp.idx = 0;
+    xatp.space = XENMAPSPACE_shared_info;
+    xatp.gpfn = virt_to_pfn(shared_info_page);
+    if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0)
+        BUG();
+    HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
+
+    /* Fill in start_info */
+    get_console();
+    get_xenbus();
+
+    gic_init();
+
+    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..a522aa9
--- /dev/null
+++ b/extras/mini-os/arch/arm/time.c
@@ -0,0 +1,202 @@
+#include <mini-os/os.h>
+#include <mini-os/hypervisor.h>
+#include <mini-os/events.h>
+#include <mini-os/traps.h>
+#include <mini-os/types.h>
+#include <mini-os/time.h>
+#include <mini-os/lib.h>
+
+//#define VTIMER_DEBUG
+#ifdef VTIMER_DEBUG
+#define DEBUG(_f, _a...) \
+    printk("MINI_OS(file=vtimer.c, line=%d) " _f , __LINE__, ## _a)
+#else
+#define DEBUG(_f, _a...)    ((void)0)
+#endif
+
+/************************************************************************
+ * Time functions
+ *************************************************************************/
+
+static uint64_t cntvct_at_init;
+static uint32_t counter_freq;
+
+/* Compute with 96 bit intermediate result: (a*b)/c */
+uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
+{
+    union {
+        uint64_t ll;
+        struct {
+            uint32_t low, high;
+        } l;
+    } u, res;
+    uint64_t rl, rh;
+
+    u.ll = a;
+    rl = (uint64_t)u.l.low * (uint64_t)b;
+    rh = (uint64_t)u.l.high * (uint64_t)b;
+    rh += (rl >> 32);
+    res.l.high = rh / c;
+    res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
+    return res.ll;
+}
+
+static inline s_time_t ticks_to_ns(uint64_t ticks)
+{
+    return muldiv64(ticks, SECONDS(1), counter_freq);
+}
+
+static inline uint64_t ns_to_ticks(s_time_t ns)
+{
+    return muldiv64(ns, counter_freq, SECONDS(1));
+}
+
+/* These are peridically updated in shared_info, and then copied here. */
+struct shadow_time_info {
+    uint64_t tsc_timestamp;     /* TSC at last update of time vals.  */
+    uint64_t system_timestamp;  /* Time, in nanosecs, since boot.    */
+    uint32_t tsc_to_nsec_mul;
+    uint32_t tsc_to_usec_mul;
+    int tsc_shift;
+    uint32_t version;
+};
+static struct timespec shadow_ts;
+static uint32_t shadow_ts_version;
+
+static struct shadow_time_info shadow;
+
+static void get_time_values_from_xen(void)
+{
+    struct vcpu_time_info    *src = &HYPERVISOR_shared_info->vcpu_info[0].time;
+
+     do {
+        shadow.version = src->version;
+        rmb();
+        shadow.tsc_timestamp     = src->tsc_timestamp;
+        shadow.system_timestamp  = src->system_time;
+        shadow.tsc_to_nsec_mul   = src->tsc_to_system_mul;
+        shadow.tsc_shift         = src->tsc_shift;
+        rmb();
+    }
+    while ((src->version & 1) | (shadow.version ^ src->version));
+
+    shadow.tsc_to_usec_mul = shadow.tsc_to_nsec_mul / 1000;
+}
+
+static inline uint64_t read_virtual_count(void)
+{
+    uint32_t c_lo, c_hi;
+    __asm__ __volatile__("isb;mrrc p15, 1, %0, %1, c14":"=r"(c_lo), "=r"(c_hi));
+    return (((uint64_t) c_hi) << 32) + c_lo;
+}
+
+/* monotonic_clock(): returns # of nanoseconds passed since time_init()
+ *        Note: This function is required to return accurate
+ *        time even in the absence of multiple timer ticks.
+ */
+uint64_t monotonic_clock(void)
+{
+    s_time_t time = ticks_to_ns(read_virtual_count() - cntvct_at_init);
+    //printk("monotonic_clock: %llu (%llu)\n", time, NSEC_TO_SEC(time));
+    return time;
+}
+
+static void update_wallclock(void)
+{
+    shared_info_t *s = HYPERVISOR_shared_info;
+
+    do {
+        shadow_ts_version = s->wc_version;
+        rmb();
+        shadow_ts.tv_sec  = s->wc_sec;
+        shadow_ts.tv_nsec = s->wc_nsec;
+        rmb();
+    }
+    while ((s->wc_version & 1) | (shadow_ts_version ^ s->wc_version));
+}
+
+
+int gettimeofday(struct timeval *tv, void *tz)
+{
+    uint64_t nsec = monotonic_clock();
+    nsec += shadow_ts.tv_nsec;
+
+    tv->tv_sec = shadow_ts.tv_sec;
+    tv->tv_sec += NSEC_TO_SEC(nsec);
+    tv->tv_usec = NSEC_TO_USEC(nsec % 1000000000UL);
+
+    return 0;
+}
+
+void set_vtimer_compare(uint64_t value) {
+    uint32_t x, y;
+
+    DEBUG("New CompareValue : %llx\n", value);
+    x = 0xFFFFFFFFULL & value;
+    y = (value >> 32) & 0xFFFFFFFF;
+
+    __asm__ __volatile__("mcrr p15, 3, %0, %1, c14"
+            ::"r"(x), "r"(y));
+
+    __asm__ __volatile__("mov %0, #0x1\n"
+            "mcr p15, 0, %0, c14, c3, 1\n" /* Enable timer and unmask the output signal */
+            "isb":"=r"(x));
+}
+
+void unset_vtimer_compare(void) {
+    uint32_t x;
+
+    __asm__ __volatile__("mov %0, #0x2\n"
+            "mcr p15, 0, %0, c14, c3, 1\n" /* Disable timer and mask the output signal */
+            "isb":"=r"(x));
+}
+
+void block_domain(s_time_t until)
+{
+    uint64_t until_count = ns_to_ticks(until) + cntvct_at_init;
+    ASSERT(irqs_disabled());
+    if (read_virtual_count() < until_count)
+    {
+        set_vtimer_compare(until_count);
+        //char buf[] = "sleep\n"; (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(buf), buf);
+        __asm__ __volatile__("wfi");
+        //char wake[] = "wake\n"; (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(wake), wake);
+        unset_vtimer_compare();
+
+        /* Give the IRQ handler a chance to handle whatever woke us up. */
+        local_irq_enable();
+        local_irq_disable();
+    }
+}
+
+void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign)
+{
+    DEBUG("Timer kick\n");
+    get_time_values_from_xen();
+    update_wallclock();
+}
+
+evtchn_port_t timer_port = -1;
+
+void init_time(void)
+{
+    printk("Initialising timer interface\n");
+
+    __asm__ __volatile__("mrc p15, 0, %0, c14, c0, 0":"=r"(counter_freq));
+    cntvct_at_init = read_virtual_count();
+    printk("Virtual Count register is %llx, freq = %d Hz\n", cntvct_at_init, counter_freq);
+
+    timer_port = bind_virq(VIRQ_TIMER, (evtchn_handler_t)timer_handler, 0);
+    if (timer_port == -1)
+        BUG();
+    unmask_evtchn(timer_port);
+}
+
+void fini_time(void)
+{
+    if (timer_port != -1)
+    {
+        mask_evtchn(timer_port);
+        unbind_evtchn(timer_port);
+    }
+}
diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c
index 9a30550..437e5b4 100644
--- a/extras/mini-os/kernel.c
+++ b/extras/mini-os/kernel.c
@@ -121,7 +121,7 @@ void start_kernel(void)
     init_events();
 
     /* ENABLE EVENT DELIVERY. This is disabled at start of day. */
-    __sti();
+    local_irq_enable();
 
     setup_xen_features();
 
-- 
2.0.0


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

  parent reply	other threads:[~2014-06-26 11:29 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-06-26 11:28 [PATCH ARM v5 00/20] mini-os: initial ARM support Thomas Leonard
2014-06-26 11:28 ` [PATCH ARM v5 01/20] mini-os: build fixes Thomas Leonard
2014-06-26 11:28 ` [PATCH ARM v5 02/20] mini-os: fixed shutdown thread Thomas Leonard
2014-06-26 11:28 ` [PATCH ARM v5 03/20] mini-os: fixed format string error in unbind_evtchn Thomas Leonard
2014-06-26 11:28 ` [PATCH ARM v5 04/20] mini-os: use unbind_evtchn in unbind_all_ports Thomas Leonard
2014-06-26 11:28 ` [PATCH ARM v5 05/20] mini-os: made off_t type signed Thomas Leonard
2014-06-26 11:28 ` [PATCH ARM v5 06/20] mini-os: switched initial C entry point to arch_init Thomas Leonard
2014-06-26 11:28 ` [PATCH ARM v5 07/20] mini-os: whitespace Thomas Leonard
2014-06-26 11:35   ` Samuel Thibault
2014-06-26 11:28 ` [PATCH ARM v5 08/20] mini-os: added arch_init_gnttab Thomas Leonard
2014-06-26 11:36   ` Samuel Thibault
2014-06-26 11:28 ` [PATCH ARM v5 09/20] mini-os: don't require XEN_HAVE_PV_UPCALL_MASK Thomas Leonard
2014-06-26 11:37   ` Samuel Thibault
2014-06-26 11:28 ` [PATCH ARM v5 10/20] mini-os: add missing casts to MM printk Thomas Leonard
2014-06-26 11:37   ` Samuel Thibault
2014-06-26 11:28 ` [PATCH ARM v5 11/20] mini-os: added HYPERVISOR_xsm_op Thomas Leonard
2014-06-26 11:38   ` Samuel Thibault
2014-06-27 13:13     ` Ian Campbell
2014-06-27 13:56       ` Thomas Leonard
2014-06-27 15:43         ` Thomas Leonard
2014-06-27 15:50           ` Samuel Thibault
2014-06-27 16:47         ` Ian Campbell
2014-06-26 11:28 ` [PATCH ARM v5 12/20] mini-os: added arch_unbind_ports Thomas Leonard
2014-06-26 11:38   ` Samuel Thibault
2014-06-26 11:28 ` [PATCH ARM v5 13/20] mini-os: moved __pte to x86 Thomas Leonard
2014-06-26 11:39   ` Samuel Thibault
2014-06-26 11:28 ` [PATCH ARM v5 14/20] mini-os: moved unlikely/likely macros to new compiler.h Thomas Leonard
2014-06-26 11:40   ` Samuel Thibault
2014-06-26 11:28 ` [PATCH ARM v5 15/20] mini-os: enable test_xenbus again Thomas Leonard
2014-06-26 11:40   ` Samuel Thibault
2014-06-27 11:05   ` Ian Campbell
2014-06-27 12:48     ` Thomas Leonard
2014-06-27 12:54       ` Ian Campbell
2014-06-26 11:28 ` [PATCH ARM v5 16/20] mini-os: use irqs_disabled() helper in schedule Thomas Leonard
2014-06-26 11:42   ` Samuel Thibault
2014-06-26 11:28 ` [PATCH ARM v5 17/20] mini-os: headers for ARM Thomas Leonard
2014-06-26 16:26   ` Julien Grall
2014-06-27 13:02     ` Thomas Leonard
2014-06-27 13:11       ` Ian Campbell
2014-06-26 11:28 ` [PATCH ARM v5 18/20] mini-os: import libfdt Thomas Leonard
2014-06-28 12:01   ` Julien Grall
2014-06-28 12:27     ` Thomas Leonard
2014-06-28 15:14       ` Julien Grall
2014-06-28 16:35         ` Anil Madhavapeddy
2014-06-28 16:45           ` Julien Grall
2014-06-26 11:28 ` Thomas Leonard [this message]
2014-06-28 18:31   ` [PATCH ARM v5 19/20] mini-os: initial ARM support Julien Grall
2014-06-30 19:12     ` Thomas Leonard
2014-06-30 21:08       ` Julien Grall
2014-07-02  8:41         ` Ian Campbell
2014-07-02  8:23       ` Ian Campbell
2014-07-02  9:22         ` karim.allah.ahmed
2014-06-26 11:28 ` [PATCH ARM v5 20/20] mini-os: arm: show registers, stack and exception vector on fault Thomas Leonard
2014-06-27 13:34 ` [PATCH ARM v5 00/20] mini-os: initial ARM support Ian Campbell

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=1403782117-15125-20-git-send-email-talex5@gmail.com \
    --to=talex5@gmail.com \
    --cc=Dave.Scott@eu.citrix.com \
    --cc=anil@recoil.org \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.