[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 |