|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH ARM v5 19/20] mini-os: initial ARM support
On ARM, Mini-OS will boot and display some output on the console.
Tested with:
make XEN_TARGET_ARCH=arm32 CROSS_COMPILE=arm-linux-gnueabihf- \
CONFIG_TEST=y CONFIG_START_NETWORK=n CONFIG_BLKFRONT=n \
CONFIG_NETFRONT=n CONFIG_FBFRONT=n CONFIG_KBDFRONT=n \
CONFIG_CONSFRONT=n CONFIG_XC=n -j4
Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@xxxxxxxxx>
[talex5@xxxxxxxxx: made x86_64 support work again]
[talex5@xxxxxxxxx: split into multiple patches]
[talex5@xxxxxxxxx: re-enabled force_evtchn_callback]
[talex5@xxxxxxxxx: enable regular console]
[talex5@xxxxxxxxx: fixed initialisation code:
- Configure write-back caching in page table. This is needed for
reliable hypercalls to Xen (thanks to Julien Grall).
- Use "client mode" for access control (domains are deprecated,
according to ARM Cortex-A Series Programmerâs Guide version 4.0,
section 9.6.4).
- Enable more SCTLR features (icache, branch prediction)]
[talex5@xxxxxxxxx: use Virtual Count register for monotonic time]
[talex5@xxxxxxxxx: fixed HYPERVISOR_shutdown]
[talex5@xxxxxxxxx: get xenstore details from hypervisor]
[talex5@xxxxxxxxx: use GCC implementation of division]
[talex5@xxxxxxxxx: cleaned up interrupt handlers and threading]
[talex5@xxxxxxxxx: call exit_thread when a thread returns]
[talex5@xxxxxxxxx: implemented block_domain for ARM]
[talex5@xxxxxxxxx: fixed hang when enabling interrupts]
[talex5@xxxxxxxxx: added -march=armv7-a to flags]
[talex5@xxxxxxxxx: CLREX after handling IRQs]
[talex5@xxxxxxxxx: unbind debug port at shutdown]
[talex5@xxxxxxxxx: allow unaligned accesses]
[talex5@xxxxxxxxx: fix zImage header for XSA-95]
[talex5@xxxxxxxxx: get RAM base and size from the FDT]
[talex5@xxxxxxxxx: get GIC addresses from FDT]
[talex5@xxxxxxxxx: added ARM grant table initialisation]
[talex5@xxxxxxxxx: added missing copyright header to hypercalls32.S]
[talex5@xxxxxxxxx: moved GIC driver to arm directory]
[talex5@xxxxxxxxx: 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@xxxxxxxxx: made image relocatable]
[talex5@xxxxxxxxx: added mfn_to_pfn and pfn_to_mfn]
Signed-off-by: Thomas Leonard <talex5@xxxxxxxxx>
---
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@xxxxxxxxxxxxx>, 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@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |