[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH ARM v4 07/12] mini-os: initial ARM support
From: Karim Raslan <karim.allah.ahmed@xxxxxxxxx> On ARM, Mini-OS will boot and display some output on the console. Tested with: make XEN_TARGET_ARCH=arm32 CROSS_COMPILE=arm-linux-gnueabihf- \ CONFIG_TEST=y CONFIG_START_NETWORK=n CONFIG_BLKFRONT=n \ CONFIG_NETFRONT=n CONFIG_FBFRONT=n CONFIG_KBDFRONT=n \ CONFIG_CONSFRONT=n CONFIG_XC=n -j4 Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@xxxxxxxxx> [talex5@xxxxxxxxx: made x86_64 support work again] [talex5@xxxxxxxxx: split into multiple patches] [talex5@xxxxxxxxx: re-enabled force_evtchn_callback] [talex5@xxxxxxxxx: enable regular console] [talex5@xxxxxxxxx: fixed initialisation code: - Configure write-back caching in page table. This is needed for reliable hypercalls to Xen (thanks to Julien Grall). - Use "client mode" for access control (domains are deprecated, according to ARM Cortex-A Series Programmerâs Guide version 4.0, section 9.6.4). - Enable more SCTLR features (icache, branch prediction)] [talex5@xxxxxxxxx: use Virtual Count register for monotonic time] [talex5@xxxxxxxxx: fixed HYPERVISOR_shutdown] [talex5@xxxxxxxxx: get xenstore details from hypervisor] [talex5@xxxxxxxxx: use GCC implementation of division] [talex5@xxxxxxxxx: include hypervisor.h from os.h, as on x86] [talex5@xxxxxxxxx: cleaned up interrupt handlers and threading] [talex5@xxxxxxxxx: call exit_thread when a thread returns] [talex5@xxxxxxxxx: implemented block_domain for ARM] [talex5@xxxxxxxxx: fixed hang when enabling interrupts] [talex5@xxxxxxxxx: added -march=armv7-a to flags] [talex5@xxxxxxxxx: implemented bitops for ARM] [talex5@xxxxxxxxx: CLREX after handling IRQs] [talex5@xxxxxxxxx: unbind debug port at shutdown] [talex5@xxxxxxxxx: allow unaligned accesses] [talex5@xxxxxxxxx: added arch_endian.h for ARM] [talex5@xxxxxxxxx: fix zImage header for XSA-95] Signed-off-by: Thomas Leonard <talex5@xxxxxxxxx> --- extras/mini-os/ARM-TODO.txt | 12 ++ extras/mini-os/Config.mk | 2 + extras/mini-os/Makefile | 14 ++ extras/mini-os/arch/arm/Makefile | 32 ++++ extras/mini-os/arch/arm/arch.mk | 7 + extras/mini-os/arch/arm/arm32.S | 155 +++++++++++++++ extras/mini-os/arch/arm/events.c | 30 +++ extras/mini-os/arch/arm/hypercalls32.S | 88 +++++++++ extras/mini-os/arch/arm/minios-arm32.lds | 75 ++++++++ extras/mini-os/arch/arm/mm.c | 44 +++++ extras/mini-os/arch/arm/sched.c | 37 ++++ extras/mini-os/arch/arm/setup.c | 102 ++++++++++ extras/mini-os/arch/arm/time.c | 202 ++++++++++++++++++++ extras/mini-os/arch/x86/events.c | 4 + extras/mini-os/drivers/gic.c | 187 ++++++++++++++++++ extras/mini-os/events.c | 5 +- extras/mini-os/hypervisor.c | 12 +- extras/mini-os/include/arm/arch_endian.h | 7 + extras/mini-os/include/arm/arch_limits.h | 9 + extras/mini-os/include/arm/arch_mm.h | 37 ++++ extras/mini-os/include/arm/arch_sched.h | 22 +++ extras/mini-os/include/arm/arch_spinlock.h | 49 +++++ extras/mini-os/include/arm/arm32/arch_wordsize.h | 1 + extras/mini-os/include/arm/hypercall-arm32.h | 173 +++++++++++++++++ extras/mini-os/include/arm/os.h | 230 +++++++++++++++++++++++ extras/mini-os/include/arm/traps.h | 20 ++ extras/mini-os/include/events.h | 4 + extras/mini-os/include/gic.h | 1 + extras/mini-os/include/hypervisor.h | 4 + extras/mini-os/include/mm.h | 2 + extras/mini-os/include/types.h | 12 +- extras/mini-os/kernel.c | 8 + extras/mini-os/sched.c | 29 +-- 33 files changed, 1595 insertions(+), 21 deletions(-) create mode 100644 extras/mini-os/ARM-TODO.txt create mode 100755 extras/mini-os/arch/arm/Makefile create mode 100644 extras/mini-os/arch/arm/arch.mk create mode 100644 extras/mini-os/arch/arm/arm32.S create mode 100644 extras/mini-os/arch/arm/events.c create mode 100644 extras/mini-os/arch/arm/hypercalls32.S create mode 100755 extras/mini-os/arch/arm/minios-arm32.lds create mode 100644 extras/mini-os/arch/arm/mm.c create mode 100644 extras/mini-os/arch/arm/sched.c create mode 100644 extras/mini-os/arch/arm/setup.c create mode 100644 extras/mini-os/arch/arm/time.c create mode 100644 extras/mini-os/drivers/gic.c create mode 100644 extras/mini-os/include/arm/arch_endian.h create mode 100644 extras/mini-os/include/arm/arch_limits.h create mode 100644 extras/mini-os/include/arm/arch_mm.h create mode 100644 extras/mini-os/include/arm/arch_sched.h create mode 100755 extras/mini-os/include/arm/arch_spinlock.h create mode 100644 extras/mini-os/include/arm/arm32/arch_wordsize.h create mode 100644 extras/mini-os/include/arm/hypercall-arm32.h create mode 100644 extras/mini-os/include/arm/os.h create mode 100644 extras/mini-os/include/arm/traps.h create mode 100644 extras/mini-os/include/gic.h diff --git a/extras/mini-os/ARM-TODO.txt b/extras/mini-os/ARM-TODO.txt new file mode 100644 index 0000000..3d9be10 --- /dev/null +++ b/extras/mini-os/ARM-TODO.txt @@ -0,0 +1,12 @@ +* support abort exception handling ( and others ) +* scheduling! +* gic request_irq implementation, currently all IRQs all hardcoded in gic irq handler. +* use device tree instead of the currently hardcoded values +* Add virtual memory support and make vstart = 0 ( use 4k descriptors instead of 1M descriptors ) +* sched +* fini_gnttab +* bind_* +* add multiple cpu support (?) +* map_frames +* make sure that wallclock is functioning properly +* evtchn_get_peercontext diff --git a/extras/mini-os/Config.mk b/extras/mini-os/Config.mk index d61877b..4ecde54 100644 --- a/extras/mini-os/Config.mk +++ b/extras/mini-os/Config.mk @@ -12,6 +12,8 @@ export XEN_INTERFACE_VERSION # If not x86 then use $(XEN_TARGET_ARCH) ifeq ($(findstring x86_,$(XEN_TARGET_ARCH)),x86_) TARGET_ARCH_FAM = x86 +else ifeq ($(findstring arm,$(XEN_TARGET_ARCH)),arm) +TARGET_ARCH_FAM = arm else TARGET_ARCH_FAM = $(XEN_TARGET_ARCH) endif diff --git a/extras/mini-os/Makefile b/extras/mini-os/Makefile index 6d6537e..535ca68 100644 --- a/extras/mini-os/Makefile +++ b/extras/mini-os/Makefile @@ -77,6 +77,14 @@ TARGET := mini-os # Subdirectories common to mini-os SUBDIRS := lib xenbus console +ifeq ($(XEN_TARGET_ARCH),arm32) +# ARM drivers +src-y += drivers/gic.c + +# Need libgcc.a for division helpers +LDLIBS += `$(CC) -print-libgcc-file-name` +endif + src-$(CONFIG_BLKFRONT) += blkfront.c src-$(CONFIG_TPMFRONT) += tpmfront.c src-$(CONFIG_TPM_TIS) += tpm_tis.c @@ -97,7 +105,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 @@ -190,7 +200,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..4f953ec --- /dev/null +++ b/extras/mini-os/arch/arm/arm32.S @@ -0,0 +1,155 @@ +#define PHYS_START (0x80008000) + +.section .text + +.globl _start +_start: + @ zImage header +.rept 8 + mov r0, r0 +.endr + b reset + .word 0x016f2818 @ Magic numbers to help the loader + .word 0 @ zImage start address + .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 setup() function. +@ => r2 -> DTB +@ <= never returns +reset: + @ Fill in the top-level translation table (at page_dir). + @ Populate the whole pagedir with 1MB section descriptors. + @ TEX[2:0] C B = 001 1 1 (outer and inner write-back, write-allocate) + ldr r0, =(0x2 + /* Section entry */ \ + 0xc + /* C B */ \ + (3 << 10) + /* Read/write */ \ + (1 << 12) + /* TEX */ \ + (1 << 16) + /* Sharable */ \ + (1<<19)) /* Non-secure */ + ldr r1, =page_dir + add r3, r1, #4*4*1024 @ Limit (4 GB address space, 4 byte entries) + +1: + str r0, [r1],#4 @ write the section entry + add r0, r0, #1 << 20 @ next physical page + cmp r1, r3 + bne 1b + + @ Tell the system where our new table is located. + ldr r3, =page_dir + mcr p15, 0, r3, c2, c0, 0 @ set ttbr0 + + @ Set access permission for domains + @ Domains are deprecated, but we have to configure them anyway. + @ We mark every page as being domain 0 and set domain 0 to "client mode" + @ (client mode = use access flags in page table). + mov r0, #1 @ 1 = client + mcr p15, 0, r0, c3, c0, 0 @ DACR + + @ Invalidate TLB + mcr p15, 0, r1, c8, c7, 0 @ TLBIALL + + @ Enable MMU / SCTLR + mrc p15, 0, r1, c1, c0, 0 @ SCTLR + orr r1, r1, #0x5 @ (dcache, MMU) + orr r1, r1, #3 << 11 @ (icache, branch prediction) + mcr p15, 0, r1, c1, c0, 0 @ SCTLR + isb + + @ Set VBAR -> exception_vector_table + @ SCTLR.V = 0 + adr r0, exception_vector_table + mcr p15, 0, r0, c12, c0, 0 + + @ Initialise 16 KB stack + ldr sp, =stack_end + + mov r0, r2 @ C wants the DTB pointer in r0 + b arch_init + +.pushsection .data +.align 14 +page_dir: + .fill (4*1024), 4, 0x0 + +.align 12 +.globl shared_info_page +shared_info_page: + .fill (1024), 4, 0x0 + +.align 3 +.globl stack +stack: + .fill (4*1024), 4, 0x0 +stack_end: + +.align 3 +irqstack: + .fill (1024), 4, 0x0 +irqstack_end: +.popsection + +@ exception base address +.align 5 +.globl exception_vector_table +@ 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 + + @ 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/hypercalls32.S b/extras/mini-os/arch/arm/hypercalls32.S new file mode 100644 index 0000000..e2f21c4 --- /dev/null +++ b/extras/mini-os/arch/arm/hypercalls32.S @@ -0,0 +1,88 @@ +#define __HYPERVISOR_set_trap_table 0 +#define __HYPERVISOR_mmu_update 1 +#define __HYPERVISOR_set_gdt 2 +#define __HYPERVISOR_stack_switch 3 +#define __HYPERVISOR_set_callbacks 4 +#define __HYPERVISOR_fpu_taskswitch 5 +#define __HYPERVISOR_sched_op_compat 6 /* compat since 0x00030101 */ +#define __HYPERVISOR_platform_op 7 +#define __HYPERVISOR_set_debugreg 8 +#define __HYPERVISOR_get_debugreg 9 +#define __HYPERVISOR_update_descriptor 10 +#define __HYPERVISOR_memory_op 12 +#define __HYPERVISOR_multicall 13 +#define __HYPERVISOR_update_va_mapping 14 +#define __HYPERVISOR_set_timer_op 15 +#define __HYPERVISOR_event_channel_op_compat 16 /* compat since 0x00030202 */ +#define __HYPERVISOR_xen_version 17 +#define __HYPERVISOR_console_io 18 +#define __HYPERVISOR_physdev_op_compat 19 /* compat since 0x00030202 */ +#define __HYPERVISOR_grant_table_op 20 +#define __HYPERVISOR_vm_assist 21 +#define __HYPERVISOR_update_va_mapping_otherdomain 22 +#define __HYPERVISOR_iret 23 /* x86 only */ +#define __HYPERVISOR_vcpu_op 24 +#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ +#define __HYPERVISOR_mmuext_op 26 +#define __HYPERVISOR_xsm_op 27 +#define __HYPERVISOR_nmi_op 28 +#define __HYPERVISOR_sched_op 29 +#define __HYPERVISOR_callback_op 30 +#define __HYPERVISOR_xenoprof_op 31 +#define __HYPERVISOR_event_channel_op 32 +#define __HYPERVISOR_physdev_op 33 +#define __HYPERVISOR_hvm_op 34 +#define __HYPERVISOR_sysctl 35 +#define __HYPERVISOR_domctl 36 +#define __HYPERVISOR_kexec_op 37 +#define __HYPERVISOR_tmem_op 38 +#define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */ + + + +#define __HVC(imm16) .long ((0xE1400070 | (((imm16) & 0xFFF0) << 4) | ((imm16) & 0x000F)) & 0xFFFFFFFF) + +#define XEN_IMM 0xEA1 + +#define HYPERCALL_SIMPLE(hypercall) \ +.globl HYPERVISOR_##hypercall; \ +.align 4,0x90; \ +HYPERVISOR_##hypercall: \ + mov r12, #__HYPERVISOR_##hypercall; \ + __HVC(XEN_IMM); \ + mov pc, lr; + +#define _hypercall0 HYPERCALL_SIMPLE +#define _hypercall1 HYPERCALL_SIMPLE +#define _hypercall2 HYPERCALL_SIMPLE +#define _hypercall3 HYPERCALL_SIMPLE +#define _hypercall4 HYPERCALL_SIMPLE + +_hypercall1(set_trap_table); +_hypercall4(mmu_update); +_hypercall4(mmuext_op); +_hypercall2(set_gdt); +_hypercall2(stack_switch); +_hypercall3(set_callbacks); +_hypercall1(fpu_taskswitch); +_hypercall2(sched_op); +_hypercall1(set_timer_op); +_hypercall2(set_debugreg); +_hypercall1(get_debugreg); +_hypercall2(update_descriptor); +_hypercall2(memory_op); +_hypercall2(multicall); +_hypercall3(update_va_mapping); +_hypercall2(event_channel_op); +_hypercall2(xen_version); +_hypercall3(console_io); +_hypercall1(physdev_op); +_hypercall3(grant_table_op); +_hypercall4(update_va_mapping_otherdomain); +_hypercall2(vm_assist); +_hypercall3(vcpu_op); +_hypercall2(set_segment_base); +_hypercall2(nmi_op); +_hypercall1(sysctl); +_hypercall1(domctl); +_hypercall2(hvm_op); diff --git a/extras/mini-os/arch/arm/minios-arm32.lds b/extras/mini-os/arch/arm/minios-arm32.lds new file mode 100755 index 0000000..0d58395 --- /dev/null +++ b/extras/mini-os/arch/arm/minios-arm32.lds @@ -0,0 +1,75 @@ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x80008000; + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.gnu.warning) + } = 0x9090 + + _etext = .; /* End of text section */ + + .rodata : { *(.rodata) *(.rodata.*) } + . = ALIGN(4096); + _erodata = .; + + /* newlib initialization functions */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + + .ctors : { + __CTOR_LIST__ = .; + *(.ctors) + CONSTRUCTORS + LONG(0) + __CTOR_END__ = .; + } + + .dtors : { + __DTOR_LIST__ = .; + *(.dtors) + LONG(0) + __DTOR_END__ = .; + } + + .data : { /* Data */ + *(.data) + } + + _edata = .; /* End of data section */ + + /* 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..bb6aa0e --- /dev/null +++ b/extras/mini-os/arch/arm/mm.c @@ -0,0 +1,44 @@ +#include <console.h> +#include <arch_mm.h> + +#define PHYS_START (0x80008000 + (1000 * 4 * 1024)) +#define PHYS_SIZE (40*1024*1024) + +static void build_pagetable(unsigned long *start_pfn, unsigned long *max_pfn) +{ + // FIXME Create small pages descriptors here instead of the 1M superpages created earlier. + return; +} + +unsigned long allocate_ondemand(unsigned long n, unsigned long alignment) +{ + // FIXME + BUG(); +} + +void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p) +{ + printk(" _text: %p(VA)\n", &_text); + printk(" _etext: %p(VA)\n", &_etext); + printk(" _erodata: %p(VA)\n", &_erodata); + printk(" _edata: %p(VA)\n", &_edata); + printk(" stack start: %p(VA)\n", stack); + printk(" _end: %p(VA)\n", &_end); + + // FIXME Get from dt! + *start_pfn_p = (((unsigned long)&_end) >> PAGE_SHIFT) + 1000; + *max_pfn_p = ((unsigned long)&_end + PHYS_SIZE) >> PAGE_SHIFT; + + printk(" start_pfn: %lx\n", *start_pfn_p); + printk(" max_pfn: %lx\n", *max_pfn_p); + + build_pagetable(start_pfn_p, max_pfn_p); +} + +void arch_init_p2m(unsigned long max_pfn) +{ +} + +void arch_init_demand_mapping_area(unsigned long cur_pfn) +{ +} diff --git a/extras/mini-os/arch/arm/sched.c b/extras/mini-os/arch/arm/sched.c new file mode 100644 index 0000000..1306c1b --- /dev/null +++ b/extras/mini-os/arch/arm/sched.c @@ -0,0 +1,37 @@ +#include <mini-os/sched.h> +#include <mini-os/xmalloc.h> + +void arm_start_thread(void); + +/* Architecture specific setup of thread creation */ +struct thread* arch_create_thread(char *name, void (*function)(void *), + void *data) +{ + struct thread *thread; + + thread = xmalloc(struct thread); + /* We can't use lazy allocation here since the trap handler runs on the stack */ + thread->stack = (char *)alloc_pages(STACK_SIZE_PAGE_ORDER); + thread->name = name; + printk("Thread \"%s\": pointer: 0x%lx, stack: 0x%lx\n", name, thread, + thread->stack); + + /* Save pointer to the thread on the stack, used by current macro */ + *((unsigned long *)thread->stack) = (unsigned long)thread; + + /* Push the details to pass to arm_start_thread onto the stack */ + int *sp = (int *) (thread->stack + STACK_SIZE); + *(--sp) = (int) function; + *(--sp) = (int) data; + thread->sp = (unsigned long) sp; + + thread->ip = (unsigned long) arm_start_thread; + + return thread; +} + +void run_idle_thread(void) +{ + __asm__ __volatile__ ("mov sp, %0; mov pc, %1"::"r"(idle_thread->sp), "r"(idle_thread->ip)); + /* Never arrive here! */ +} diff --git a/extras/mini-os/arch/arm/setup.c b/extras/mini-os/arch/arm/setup.c new file mode 100644 index 0000000..3499b37 --- /dev/null +++ b/extras/mini-os/arch/arm/setup.c @@ -0,0 +1,102 @@ +#include <mini-os/os.h> +#include <mini-os/kernel.h> +#include <xen/xen.h> +#include <xen/memory.h> +#include <xen/hvm/params.h> +#include <arch_mm.h> + +/* + * This structure contains start-of-day info, such as pagetable base pointer, + * address of the shared_info structure, and things like that. + * On x86, the hypervisor passes it to us. On ARM, we fill it in ourselves. + */ +union start_info_union start_info_union; + +/* + * Shared page for communicating with the hypervisor. + * Events flags go here, for example. + */ +shared_info_t *HYPERVISOR_shared_info; + +extern char shared_info_page[PAGE_SIZE]; + +static int hvm_get_parameter(int idx, uint64_t *value) +{ + struct xen_hvm_param xhv; + int ret; + + xhv.domid = DOMID_SELF; + xhv.index = idx; + ret = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv); + if (ret < 0) { + BUG(); + } + *value = xhv.value; + return ret; +} + +static void get_console(void) +{ + uint64_t v = -1; + + hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); + start_info.console.domU.evtchn = v; + + hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); + start_info.console.domU.mfn = v; + + printk("Console is on port %d\n", start_info.console.domU.evtchn); + printk("Console ring is at mfn %x\n", start_info.console.domU.mfn); +} + +void get_xenbus(void) +{ + uint64_t value; + + if (hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &value)) + BUG(); + + start_info.store_evtchn = (int)value; + + if(hvm_get_parameter(HVM_PARAM_STORE_PFN, &value)) + BUG(); + start_info.store_mfn = (unsigned long)value; +} + +/* + * INITIAL C ENTRY POINT. + */ +void arch_init(void *dtb_pointer) +{ + struct xen_add_to_physmap xatp; + + memset(&__bss_start, 0, &_end - &__bss_start); + + printk("dtb_pointer : %x\n", dtb_pointer); + + /* Map shared_info page */ + xatp.domid = DOMID_SELF; + xatp.idx = 0; + xatp.space = XENMAPSPACE_shared_info; + xatp.gpfn = virt_to_pfn(shared_info_page); + if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0) + BUG(); + HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; + + /* Fill in start_info */ + get_console(); + get_xenbus(); + + start_kernel(); +} + +void +arch_fini(void) +{ + +} + +void +arch_do_exit(void) +{ +} diff --git a/extras/mini-os/arch/arm/time.c b/extras/mini-os/arch/arm/time.c new file mode 100644 index 0000000..7c0cce5 --- /dev/null +++ b/extras/mini-os/arch/arm/time.c @@ -0,0 +1,202 @@ +#include <mini-os/os.h> +#include <mini-os/hypervisor.h> +#include <mini-os/events.h> +#include <mini-os/traps.h> +#include <mini-os/types.h> +#include <mini-os/time.h> +#include <mini-os/lib.h> + +//#define VTIMER_DEBUG +#ifdef VTIMER_DEBUG +#define DEBUG(_f, _a...) \ + printk("MINI_OS(file=vtimer.c, line=%d) " _f , __LINE__, ## _a) +#else +#define DEBUG(_f, _a...) ((void)0) +#endif + +/************************************************************************ + * Time functions + *************************************************************************/ + +static uint64_t cntvct_at_init; +static uint32_t counter_freq; + +/* Compute with 96 bit intermediate result: (a*b)/c */ +uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) +{ + union { + uint64_t ll; + struct { + uint32_t low, high; + } l; + } u, res; + uint64_t rl, rh; + + u.ll = a; + rl = (uint64_t)u.l.low * (uint64_t)b; + rh = (uint64_t)u.l.high * (uint64_t)b; + rh += (rl >> 32); + res.l.high = rh / c; + res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; + return res.ll; +} + +static inline s_time_t ticks_to_ns(uint64_t ticks) +{ + return muldiv64(ticks, SECONDS(1), counter_freq); +} + +static inline uint64_t ns_to_ticks(s_time_t ns) +{ + return muldiv64(ns, counter_freq, SECONDS(1)); +} + +/* These are peridically updated in shared_info, and then copied here. */ +struct shadow_time_info { + uint64_t tsc_timestamp; /* TSC at last update of time vals. */ + uint64_t system_timestamp; /* Time, in nanosecs, since boot. */ + uint32_t tsc_to_nsec_mul; + uint32_t tsc_to_usec_mul; + int tsc_shift; + uint32_t version; +}; +static struct timespec shadow_ts; +static uint32_t shadow_ts_version; + +static struct shadow_time_info shadow; + +static void get_time_values_from_xen(void) +{ + struct vcpu_time_info *src = &HYPERVISOR_shared_info->vcpu_info[0].time; + + do { + shadow.version = src->version; + rmb(); + shadow.tsc_timestamp = src->tsc_timestamp; + shadow.system_timestamp = src->system_time; + shadow.tsc_to_nsec_mul = src->tsc_to_system_mul; + shadow.tsc_shift = src->tsc_shift; + rmb(); + } + while ((src->version & 1) | (shadow.version ^ src->version)); + + shadow.tsc_to_usec_mul = shadow.tsc_to_nsec_mul / 1000; +} + +static inline uint64_t read_virtual_count(void) +{ + uint32_t c_lo, c_hi; + __asm__ __volatile__("isb;mrrc p15, 1, %0, %1, c14":"=r"(c_lo), "=r"(c_hi)); + return (((uint64_t) c_hi) << 32) + c_lo; +} + +/* monotonic_clock(): returns # of nanoseconds passed since time_init() + * Note: This function is required to return accurate + * time even in the absence of multiple timer ticks. + */ +uint64_t monotonic_clock(void) +{ + s_time_t time = ticks_to_ns(read_virtual_count() - cntvct_at_init); + //printk("monotonic_clock: %llu (%llu)\n", time, NSEC_TO_SEC(time)); + return time; +} + +static void update_wallclock(void) +{ + shared_info_t *s = HYPERVISOR_shared_info; + + do { + shadow_ts_version = s->wc_version; + rmb(); + shadow_ts.tv_sec = s->wc_sec; + shadow_ts.tv_nsec = s->wc_nsec; + rmb(); + } + while ((s->wc_version & 1) | (shadow_ts_version ^ s->wc_version)); +} + + +int gettimeofday(struct timeval *tv, void *tz) +{ + uint64_t nsec = monotonic_clock(); + nsec += shadow_ts.tv_nsec; + + tv->tv_sec = shadow_ts.tv_sec; + tv->tv_sec += NSEC_TO_SEC(nsec); + tv->tv_usec = NSEC_TO_USEC(nsec % 1000000000UL); + + return 0; +} + +void set_vtimer_compare(uint64_t value) { + uint32_t x, y; + + DEBUG("New CompareValue : %llx\n", value); + x = 0xFFFFFFFFULL & value; + y = (value >> 32) & 0xFFFFFFFF; + + __asm__ __volatile__("mcrr p15, 3, %0, %1, c14\n" + "isb"::"r"(x), "r"(y)); + + __asm__ __volatile__("mov %0, #0x1\n" + "mcr p15, 0, %0, c14, c3, 1\n" /* Enable timer and unmask the output signal */ + "isb":"=r"(x)); +} + +void unset_vtimer_compare(void) { + uint32_t x; + + __asm__ __volatile__("mov %0, #0x2\n" + "mcr p15, 0, %0, c14, c3, 1\n" /* Disable timer and mask the output signal */ + "isb":"=r"(x)); +} + +void block_domain(s_time_t until) +{ + uint64_t until_count = ns_to_ticks(until) + cntvct_at_init; + ASSERT(irqs_disabled()); + if (read_virtual_count() < until_count) + { + set_vtimer_compare(until_count); + //char buf[] = "sleep\n"; (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(buf), buf); + __asm__ __volatile__("wfi"); + //char wake[] = "wake\n"; (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(wake), wake); + unset_vtimer_compare(); + + /* Give the IRQ handler a chance to handle whatever woke us up. */ + local_irq_enable(); + local_irq_disable(); + } +} + +void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign) +{ + DEBUG("Timer kick\n"); + get_time_values_from_xen(); + update_wallclock(); +} + +evtchn_port_t timer_port = -1; + +void init_time(void) +{ + printk("Initialising timer interface\n"); + + __asm__ __volatile__("mrc p15, 0, %0, c14, c0, 0":"=r"(counter_freq)); + cntvct_at_init = read_virtual_count(); + printk("Virtual Count register is %llx, freq = %d Hz\n", cntvct_at_init, counter_freq); + + timer_port = bind_virq(VIRQ_TIMER, (evtchn_handler_t)timer_handler, 0); + if (timer_port == -1) + BUG(); + unmask_evtchn(timer_port); +} + +void fini_time(void) +{ + if (timer_port != -1) + { + mask_evtchn(timer_port); + unbind_evtchn(timer_port); + } +} diff --git a/extras/mini-os/arch/x86/events.c b/extras/mini-os/arch/x86/events.c index e420a98..5198cf3 100644 --- a/extras/mini-os/arch/x86/events.c +++ b/extras/mini-os/arch/x86/events.c @@ -23,6 +23,10 @@ void arch_init_events(void) #endif } +void arch_unbind_ports(void) +{ +} + void arch_fini_events(void) { #if defined(__x86_64__) diff --git a/extras/mini-os/drivers/gic.c b/extras/mini-os/drivers/gic.c new file mode 100644 index 0000000..3141830 --- /dev/null +++ b/extras/mini-os/drivers/gic.c @@ -0,0 +1,187 @@ +// ARM GIC implementation + +#include <mini-os/os.h> +#include <mini-os/hypervisor.h> + +//#define VGIC_DEBUG +#ifdef VGIC_DEBUG +#define DEBUG(_f, _a...) \ + DEBUG("MINI_OS(file=vgic.c, line=%d) " _f , __LINE__, ## _a) +#else +#define DEBUG(_f, _a...) ((void)0) +#endif + +extern 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_PRIORITY 0x400 +#define GICD_ITARGETSR 0x800 +#define GICD_ICFGR 0xC00 + +// CPU Interface +#define GICC_CTLR 0x0 +#define GICC_PMR 0x4 +#define GICC_IAR 0xc +#define GICC_EOIR 0x10 +#define GICC_HPPIR 0x18 + +#define gicd(gic, offset) ((gic)->gicd_base + (offset)) +#define gicc(gic, offset) ((gic)->gicc_base + (offset)) + +#define REG(addr) ((uint32_t *)(addr)) + +static inline uint32_t REG_READ32(volatile uint32_t *addr) +{ + uint32_t value; + __asm__ __volatile__("ldr %0, [%1]":"=&r"(value):"r"(addr)); + rmb(); + return value; +} + +static inline void REG_WRITE32(volatile uint32_t *addr, unsigned int value) +{ + __asm__ __volatile__("str %0, [%1]"::"r"(value), "r"(addr)); + wmb(); +} + +static void gic_set_priority(struct gic *gic, unsigned char irq_number, unsigned char priority) +{ + uint32_t value; + value = REG_READ32(REG(gicd(gic, GICD_PRIORITY)) + irq_number); + value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0' + value |= priority << (8 * (irq_number & 0x3)); // add our priority + REG_WRITE32(REG(gicd(gic, GICD_PRIORITY)) + irq_number, value); +} + +static void gic_route_interrupt(struct gic *gic, unsigned char irq_number, unsigned char cpu_set) +{ + uint32_t value; + value = REG_READ32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number); + value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0' + value |= cpu_set << (8 * (irq_number & 0x3)); // add our priority + REG_WRITE32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number, value); +} + +/* 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) +{ + uint32_t *tmp = (uint32_t *)base; + tmp[nr >> 5] &= (unsigned long)~(1 << (nr & 0x1f)); +} + +static __inline__ void set_bit_non_atomic(int nr, volatile void *base) +{ + uint32_t *tmp = (uint32_t *)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, unsigned char irq_number, + unsigned char cpu_set, unsigned char level_sensitive, unsigned char ppi) +{ + void *set_enable_reg; + void *cfg_reg; + + // set priority + gic_set_priority(gic, irq_number, 0x0); + + // set target cpus for this interrupt + gic_route_interrupt(gic, irq_number, cpu_set); + + // set level/edge triggered + cfg_reg = (void *)gicd(gic, GICD_ICFGR); + level_sensitive ? clear_bit_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) { + // FIXME Get from dt! + gic.gicd_base = (char *)0x2c001000ULL; + gic.gicc_base = (char *)0x2c002000ULL; + 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/events.c b/extras/mini-os/events.c index 3c92d82..780c74a 100644 --- a/extras/mini-os/events.c +++ b/extras/mini-os/events.c @@ -179,6 +179,7 @@ void init_events(void) void fini_events(void) { /* Dealloc all events */ + arch_unbind_ports(); unbind_all_ports(); arch_fini_events(); } @@ -238,7 +239,8 @@ int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port, int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size) { - int rc; + int rc = 0; +#ifndef __arm__ /* TODO */ uint32_t sid; struct xen_flask_op op; op.cmd = FLASK_GET_PEER_SID; @@ -253,6 +255,7 @@ int evtchn_get_peercontext(evtchn_port_t local_port, char *ctx, int size) op.u.sid_context.size = size; set_xen_guest_handle(op.u.sid_context.context, ctx); rc = _hypercall1(int, xsm_op, &op); +#endif return rc; } diff --git a/extras/mini-os/hypervisor.c b/extras/mini-os/hypervisor.c index b4688a0..1b61d9b 100644 --- a/extras/mini-os/hypervisor.c +++ b/extras/mini-os/hypervisor.c @@ -64,7 +64,7 @@ void do_hypervisor_callback(struct pt_regs *regs) l2 &= ~(1UL << l2i); port = (l1i * (sizeof(unsigned long) * 8)) + l2i; - do_event(port, regs); + do_event(port, regs); } } @@ -73,18 +73,26 @@ void do_hypervisor_callback(struct pt_regs *regs) void force_evtchn_callback(void) { +#ifdef XEN_HAVE_PV_UPCALL_MASK int save; +#endif vcpu_info_t *vcpu; vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; +#ifdef XEN_HAVE_PV_UPCALL_MASK save = vcpu->evtchn_upcall_mask; +#endif while (vcpu->evtchn_upcall_pending) { +#ifdef XEN_HAVE_PV_UPCALL_MASK vcpu->evtchn_upcall_mask = 1; +#endif barrier(); do_hypervisor_callback(NULL); barrier(); +#ifdef XEN_HAVE_PV_UPCALL_MASK vcpu->evtchn_upcall_mask = save; barrier(); +#endif }; } @@ -110,7 +118,9 @@ inline void unmask_evtchn(uint32_t port) &vcpu_info->evtchn_pending_sel) ) { vcpu_info->evtchn_upcall_pending = 1; +#ifdef XEN_HAVE_PV_UPCALL_MASK if ( !vcpu_info->evtchn_upcall_mask ) +#endif force_evtchn_callback(); } } diff --git a/extras/mini-os/include/arm/arch_endian.h b/extras/mini-os/include/arm/arch_endian.h new file mode 100644 index 0000000..0771683 --- /dev/null +++ b/extras/mini-os/include/arm/arch_endian.h @@ -0,0 +1,7 @@ +#ifndef ARCH_ENDIAN_H +#error "Do not include arch_endian by itself, include endian.h" +#else + +#define __BYTE_ORDER __LITTLE_ENDIAN + +#endif diff --git a/extras/mini-os/include/arm/arch_limits.h b/extras/mini-os/include/arm/arch_limits.h new file mode 100644 index 0000000..bae99e1 --- /dev/null +++ b/extras/mini-os/include/arm/arch_limits.h @@ -0,0 +1,9 @@ +#ifndef __ARCH_LIMITS_H__ +#define __ARCH_LIMITS_H__ + +#include <mm.h> + +#define __STACK_SIZE_PAGE_ORDER 2 +#define __STACK_SIZE (4 * PAGE_SIZE) + +#endif diff --git a/extras/mini-os/include/arm/arch_mm.h b/extras/mini-os/include/arm/arch_mm.h new file mode 100644 index 0000000..be14ada --- /dev/null +++ b/extras/mini-os/include/arm/arch_mm.h @@ -0,0 +1,37 @@ +#ifndef _ARCH_MM_H_ +#define _ARCH_MM_H_ + +extern char _text, _etext, _erodata, _edata, _end, __bss_start; +extern char stack[]; + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#define L1_PAGETABLE_SHIFT 12 + +#if 0 +#define VIRT_START ((unsigned long)&_text) +#else +#define VIRT_START ((unsigned long)0) +#endif + +#define to_phys(x) ((unsigned long)(x)-VIRT_START) +#define to_virt(x) ((void *)((unsigned long)(x)+VIRT_START)) + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> L1_PAGETABLE_SHIFT) +#define PFN_DOWN(x) ((x) >> L1_PAGETABLE_SHIFT) +#define PFN_PHYS(x) ((uint64_t)(x) << L1_PAGETABLE_SHIFT) +#define PHYS_PFN(x) ((x) >> L1_PAGETABLE_SHIFT) + +#define virt_to_pfn(_virt) (PFN_DOWN(to_phys(_virt))) +#define virt_to_mfn(_virt) (PFN_DOWN(to_phys(_virt))) +#define mach_to_virt(_mach) (_mach) +#define virt_to_mach(_virt) (_virt) +#define mfn_to_virt(_mfn) (to_virt(PFN_PHYS(_mfn))) +#define pfn_to_virt(_pfn) (to_virt(PFN_PHYS(_pfn))) + +// FIXME +#define map_frames(f, n) (NULL) + +#endif diff --git a/extras/mini-os/include/arm/arch_sched.h b/extras/mini-os/include/arm/arch_sched.h new file mode 100644 index 0000000..e2307ed --- /dev/null +++ b/extras/mini-os/include/arm/arch_sched.h @@ -0,0 +1,22 @@ + +#ifndef __ARCH_SCHED_H__ +#define __ARCH_SCHED_H__ + +#include "arch_limits.h" + +static inline struct thread* get_current(void) +{ + struct thread **current; + unsigned long sp; + __asm__ __volatile__ ("mov %0, sp":"=r"(sp)); + current = (void *)(unsigned long)(sp & ~(__STACK_SIZE-1)); + return *current; +} + + +extern void __arch_switch_threads(unsigned long *prevctx, unsigned long *nextctx); + +#define arch_switch_threads(prev,next) __arch_switch_threads(&(prev)->sp, &(next)->sp) + + +#endif /* __ARCH_SCHED_H__ */ diff --git a/extras/mini-os/include/arm/arch_spinlock.h b/extras/mini-os/include/arm/arch_spinlock.h new file mode 100755 index 0000000..d57f150 --- /dev/null +++ b/extras/mini-os/include/arm/arch_spinlock.h @@ -0,0 +1,49 @@ + + +#ifndef __ARCH_ASM_SPINLOCK_H +#define __ARCH_ASM_SPINLOCK_H + +#include "os.h" + + +#define ARCH_SPIN_LOCK_UNLOCKED { 1 } + +/* + * Simple spin lock operations. There are two variants, one clears IRQ's + * on the local processor, one does not. + * + * We make no fairness assumptions. They have a cost. + */ + +#define arch_spin_is_locked(x) (*(volatile signed char *)(&(x)->slock) <= 0) +#define arch_spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x)) + +/* + * This works. Despite all the confusion. + * (except on PPro SMP or if we are using OOSTORE) + * (PPro errata 66, 92) + */ + +static inline void _raw_spin_unlock(spinlock_t *lock) +{ + xchg(&lock->slock, 1); +} + +static inline int _raw_spin_trylock(spinlock_t *lock) +{ + return xchg(&lock->slock, 0) != 0 ? 1 : 0; +} + +static inline void _raw_spin_lock(spinlock_t *lock) +{ + volatile int was_locked; + do { + was_locked = xchg(&lock->slock, 0) == 0 ? 1 : 0; + } while(was_locked); +} + +static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags) +{ +} + +#endif diff --git a/extras/mini-os/include/arm/arm32/arch_wordsize.h b/extras/mini-os/include/arm/arm32/arch_wordsize.h new file mode 100644 index 0000000..b47eee9 --- /dev/null +++ b/extras/mini-os/include/arm/arm32/arch_wordsize.h @@ -0,0 +1 @@ +#define __WORDSIZE 32 diff --git a/extras/mini-os/include/arm/hypercall-arm32.h b/extras/mini-os/include/arm/hypercall-arm32.h new file mode 100644 index 0000000..0fc1c03 --- /dev/null +++ b/extras/mini-os/include/arm/hypercall-arm32.h @@ -0,0 +1,173 @@ +/****************************************************************************** + * hypercall-arm32.h + * + * Copied from XenLinux. + * + * Copyright (c) 2002-2004, K A Fraser + * + * 64-bit updates: + * Benjamin Liu <benjamin.liu@xxxxxxxxx> + * Jun Nakajima <jun.nakajima@xxxxxxxxx> + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __HYPERCALL_ARM_H__ +#define __HYPERCALL_ARM_H__ + +#include <xen/xen.h> +#include <xen/sched.h> +#include <mini-os/mm.h> + +inline int +HYPERVISOR_mmu_update( + mmu_update_t *req, int count, int *success_count, domid_t domid); + +inline int +HYPERVISOR_mmuext_op( + struct mmuext_op *op, int count, int *success_count, domid_t domid); + +inline int +HYPERVISOR_set_gdt( + unsigned long *frame_list, int entries); + +inline int +HYPERVISOR_stack_switch( + unsigned long ss, unsigned long esp); + +inline int +HYPERVISOR_set_callbacks( + unsigned long event_address, unsigned long failsafe_address, + unsigned long syscall_address); + +inline int +HYPERVISOR_fpu_taskswitch( + int set); + +inline int +HYPERVISOR_sched_op( + int cmd, void *arg); + +static inline int +HYPERVISOR_shutdown( + unsigned int reason) +{ + struct sched_shutdown shutdown = { .reason = reason }; + HYPERVISOR_sched_op(SCHEDOP_shutdown, &shutdown); +} + +inline long +HYPERVISOR_set_timer_op( + uint64_t timeout); + +inline int +HYPERVISOR_set_debugreg( + int reg, unsigned long value); + +inline unsigned long +HYPERVISOR_get_debugreg( + int reg); + +inline int +HYPERVISOR_update_descriptor( + unsigned long ma, unsigned long word); + +inline int +HYPERVISOR_memory_op( + unsigned int cmd, void *arg); + +inline int +HYPERVISOR_multicall( + void *call_list, int nr_calls); + +inline int +HYPERVISOR_update_va_mapping( + unsigned long va, pte_t new_val, unsigned long flags); + +inline int +HYPERVISOR_event_channel_op( + int cmd, void *op); + +inline int +HYPERVISOR_xen_version( + int cmd, void *arg); + +inline int +HYPERVISOR_console_io( + int cmd, int count, char *str); + +inline int +HYPERVISOR_physdev_op( + void *physdev_op); + +inline int +HYPERVISOR_grant_table_op( + unsigned int cmd, void *uop, unsigned int count); + +inline int +HYPERVISOR_update_va_mapping_otherdomain( + unsigned long va, pte_t new_val, unsigned long flags, domid_t domid); + +inline int +HYPERVISOR_vm_assist( + unsigned int cmd, unsigned int type); + +inline int +HYPERVISOR_vcpu_op( + int cmd, int vcpuid, void *extra_args); + +inline int +HYPERVISOR_set_segment_base( + int reg, unsigned long value); + +inline int +HYPERVISOR_suspend( + unsigned long srec); + +inline int +HYPERVISOR_nmi_op( + unsigned long op, + unsigned long arg); + +inline int +HYPERVISOR_sysctl( + unsigned long op); + +inline int +HYPERVISOR_domctl( + unsigned long op); + +inline int +HYPERVISOR_hvm_op( + unsigned long op, void *arg); + +#endif /* __HYPERCALL_X86_64_H__ */ + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/extras/mini-os/include/arm/os.h b/extras/mini-os/include/arm/os.h new file mode 100644 index 0000000..21e9276 --- /dev/null +++ b/extras/mini-os/include/arm/os.h @@ -0,0 +1,230 @@ +#ifndef _OS_H_ +#define _OS_H_ + +#ifndef __ASSEMBLY__ + +#include <mini-os/hypervisor.h> +#include <mini-os/types.h> +#include <xen/xen.h> + +void arch_fini(void); +void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign); + +#define BUG() while(1){} + +#define smp_processor_id() 0 + +#define barrier() __asm__ __volatile__("": : :"memory") + +extern shared_info_t *HYPERVISOR_shared_info; + +// disable interrupts +static inline __cli(void) { + int x; + __asm__ __volatile__("mrs %0, cpsr;cpsid i":"=r"(x)::"memory"); +} + +// enable interrupts +static inline __sti(void) { + int x; + __asm__ __volatile__("mrs %0, cpsr\n" + "bic %0, %0, #0x80\n" + "msr cpsr_c, %0" + :"=r"(x)::"memory"); +} + +static inline int irqs_disabled() { + int x; + __asm__ __volatile__("mrs %0, cpsr\n":"=r"(x)::"memory"); + return (x & 0x80); +} + +#define local_irq_save(x) { \ + __asm__ __volatile__("mrs %0, cpsr;cpsid i; and %0, %0, #0x80":"=r"(x)::"memory"); \ +} + +#define local_irq_restore(x) { \ + __asm__ __volatile__("msr cpsr_c, %0"::"r"(x):"memory"); \ +} + +#define local_save_flags(x) { \ + __asm__ __volatile__("mrs %0, cpsr; and %0, %0, 0x80":"=r"(x)::"memory"); \ +} + +#define local_irq_disable() __cli() +#define local_irq_enable() __sti() + +#if defined(__arm__) +#define mb() __asm__("dmb"); +#define rmb() __asm__("dmb"); +#define wmb() __asm__("dmb"); +#elif defined(__aarch64__) +#define mb() +#define rmb() +#define wmb() +#else +#error undefined architecture +#endif + +#define unlikely(x) __builtin_expect((x),0) +#define likely(x) __builtin_expect((x),1) + +/************************** arm *******************************/ +#ifdef __INSIDE_MINIOS__ +#if defined (__arm__) +#define xchg(ptr,v) __atomic_exchange_n(ptr, v, __ATOMIC_SEQ_CST) + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + * + * This operation is atomic. + * If you need a memory barrier, use synch_test_and_clear_bit instead. + */ +static __inline__ int test_and_clear_bit(int nr, volatile void * addr) +{ + uint8_t *byte = ((uint8_t *)addr) + (nr >> 3); + uint8_t bit = 1 << (nr & 7); + uint8_t orig; + + orig = __atomic_fetch_and(byte, ~bit, __ATOMIC_RELAXED); + + return (orig & bit) != 0; +} + +/** + * Atomically set a bit and return the old value. + * Similar to test_and_clear_bit. + */ +static __inline__ int test_and_set_bit(int nr, volatile void *base) +{ + uint8_t *byte = ((uint8_t *)base) + (nr >> 3); + uint8_t bit = 1 << (nr & 7); + uint8_t orig; + + orig = __atomic_fetch_or(byte, bit, __ATOMIC_RELAXED); + + return (orig & bit) != 0; +} + +/** + * Test whether a bit is set. */ +static __inline__ int test_bit(int nr, const volatile unsigned long *addr) +{ + const uint8_t *ptr = (const uint8_t *) addr; + return ((1 << (nr & 7)) & (ptr[nr >> 3])) != 0; +} + +/** + * Atomically set a bit in memory (like test_and_set_bit but discards result). + */ +static __inline__ void set_bit(int nr, volatile unsigned long *addr) +{ + test_and_set_bit(nr, addr); +} + +/** + * Atomically clear a bit in memory (like test_and_clear_bit but discards result). + */ +static __inline__ void clear_bit(int nr, volatile unsigned long *addr) +{ + test_and_clear_bit(nr, addr); +} + +/** + * __ffs - find first (lowest) set bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +static __inline__ unsigned long __ffs(unsigned long word) +{ + int clz; + + /* xxxxx10000 = word + * xxxxx01111 = word - 1 + * 0000011111 = word ^ (word - 1) + * 4 = 31 - clz(word ^ (word - 1)) + */ + + __asm__ ( + "sub r0, %[word], #1\n" + "eor r0, r0, %[word]\n" + "clz %[clz], r0\n": + /* Outputs: */ + [clz] "=r"(clz): + /* Inputs: */ + [word] "r"(word): + /* Clobbers: */ + "r0"); + + return 31 - clz; +} + +#else /* ifdef __arm__ */ +#error "Unsupported architecture" +#endif +#endif /* ifdef __INSIDE_MINIOS */ + +/********************* common arm32 and arm64 ****************************/ + +/* If *ptr == old, then store new there (and return new). + * Otherwise, return the old value. + * Atomic. */ +#define synch_cmpxchg(ptr, old, new) \ +({ __typeof__(*ptr) stored = old; \ + __atomic_compare_exchange_n(ptr, &stored, new, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? new : old; \ +}) + +/* As test_and_clear_bit, but using __ATOMIC_SEQ_CST */ +static __inline__ int synch_test_and_clear_bit(int nr, volatile void *addr) +{ + uint8_t *byte = ((uint8_t *)addr) + (nr >> 3); + uint8_t bit = 1 << (nr & 7); + uint8_t orig; + + orig = __atomic_fetch_and(byte, ~bit, __ATOMIC_SEQ_CST); + + return (orig & bit) != 0; +} + +/* As test_and_set_bit, but using __ATOMIC_SEQ_CST */ +static __inline__ int synch_test_and_set_bit(int nr, volatile void *base) +{ + uint8_t *byte = ((uint8_t *)base) + (nr >> 3); + uint8_t bit = 1 << (nr & 7); + uint8_t orig; + + orig = __atomic_fetch_or(byte, bit, __ATOMIC_SEQ_CST); + + return (orig & bit) != 0; +} + +/* As set_bit, but using __ATOMIC_SEQ_CST */ +static __inline__ void synch_set_bit(int nr, volatile void *addr) +{ + synch_test_and_set_bit(nr, addr); +} + +/* As clear_bit, but using __ATOMIC_SEQ_CST */ +static __inline__ void synch_clear_bit(int nr, volatile void *addr) +{ + synch_test_and_clear_bit(nr, addr); +} + +/* As test_bit, but with a following memory barrier. */ +static __inline__ int synch_test_bit(int nr, volatile void *addr) +{ + int result; + result = test_bit(nr, addr); + barrier(); + return result; +} + +#endif /* not assembly */ + +#endif diff --git a/extras/mini-os/include/arm/traps.h b/extras/mini-os/include/arm/traps.h new file mode 100644 index 0000000..704df22 --- /dev/null +++ b/extras/mini-os/include/arm/traps.h @@ -0,0 +1,20 @@ +#ifndef _TRAPS_H_ +#define _TRAPS_H_ + +struct pt_regs { + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long r11; + unsigned long r12; +}; + +#endif diff --git a/extras/mini-os/include/events.h b/extras/mini-os/include/events.h index 0452d21..f571b06 100644 --- a/extras/mini-os/include/events.h +++ b/extras/mini-os/include/events.h @@ -26,6 +26,10 @@ typedef void (*evtchn_handler_t)(evtchn_port_t, struct pt_regs *, void *); /* prototypes */ void arch_init_events(void); + +/* Called by fini_events. Close any arch-specific ports (e.g. debug ports) */ +void arch_unbind_ports(void); + void arch_fini_events(void); int do_event(evtchn_port_t port, struct pt_regs *regs); diff --git a/extras/mini-os/include/gic.h b/extras/mini-os/include/gic.h new file mode 100644 index 0000000..cead2e5 --- /dev/null +++ b/extras/mini-os/include/gic.h @@ -0,0 +1 @@ +void gic_init(void); diff --git a/extras/mini-os/include/hypervisor.h b/extras/mini-os/include/hypervisor.h index a62cb78..052f4f8 100644 --- a/extras/mini-os/include/hypervisor.h +++ b/extras/mini-os/include/hypervisor.h @@ -18,6 +18,10 @@ #include <hypercall-x86_32.h> #elif defined(__x86_64__) #include <hypercall-x86_64.h> +#elif defined(__arm__) +#include <hypercall-arm32.h> +#elif defined(__aarch64__) +#include <hypercall-arm64.h> #else #error "Unsupported architecture" #endif diff --git a/extras/mini-os/include/mm.h b/extras/mini-os/include/mm.h index a94cd6d..644c7de 100644 --- a/extras/mini-os/include/mm.h +++ b/extras/mini-os/include/mm.h @@ -29,6 +29,8 @@ #include <xen/arch-x86_32.h> #elif defined(__x86_64__) #include <xen/arch-x86_64.h> +#elif defined(__arm__) || defined(__aarch64__) +#include <xen/arch-arm.h> #else #error "Unsupported architecture" #endif diff --git a/extras/mini-os/include/types.h b/extras/mini-os/include/types.h index de356e8..f79ff8c 100644 --- a/extras/mini-os/include/types.h +++ b/extras/mini-os/include/types.h @@ -27,7 +27,7 @@ typedef unsigned char u_char; typedef unsigned int u_int; typedef unsigned long u_long; #endif -#ifdef __i386__ +#if defined(__i386__) || defined(__arm__) typedef long long quad_t; typedef unsigned long long u_quad_t; @@ -40,7 +40,7 @@ typedef unsigned long u_quad_t; typedef struct { unsigned long pte; } pte_t; #endif /* __i386__ || __x86_64__ */ -#ifdef __x86_64__ +#if defined(__x86_64__) || defined(__aarch64__) #define __pte(x) ((pte_t) { (x) } ) #else #define __pte(x) ({ unsigned long long _x = (x); \ @@ -51,10 +51,10 @@ typedef struct { unsigned long pte; } pte_t; #include <limits.h> #include <stdint.h> #else -#ifdef __i386__ +#if defined(__i386__) || defined(__arm__) typedef unsigned int uintptr_t; typedef int intptr_t; -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__aarch64__) typedef unsigned long uintptr_t; typedef long intptr_t; #endif /* __i386__ || __x86_64__ */ @@ -64,10 +64,10 @@ typedef unsigned short uint16_t; typedef signed short int16_t; typedef unsigned int uint32_t; typedef signed int int32_t; -#ifdef __i386__ +#if defined(__i386__) || defined(__arm__) typedef signed long long int64_t; typedef unsigned long long uint64_t; -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__aarch64__) typedef signed long int64_t; typedef unsigned long uint64_t; #endif diff --git a/extras/mini-os/kernel.c b/extras/mini-os/kernel.c index 9a30550..7b2b8fc 100644 --- a/extras/mini-os/kernel.c +++ b/extras/mini-os/kernel.c @@ -47,6 +47,10 @@ #include <xen/features.h> #include <xen/version.h> +#ifdef __arm__ +#include <mini-os/gic.h> +#endif + uint8_t xen_features[XENFEAT_NR_SUBMAPS * 32]; void setup_xen_features(void) @@ -147,6 +151,10 @@ void start_kernel(void) create_thread("shutdown", shutdown_thread, NULL); #endif +#ifdef __arm__ + gic_init(); +#endif + /* Call (possibly overridden) app_main() */ app_main(&start_info); diff --git a/extras/mini-os/sched.c b/extras/mini-os/sched.c index 174945e..b99d7dc 100644 --- a/extras/mini-os/sched.c +++ b/extras/mini-os/sched.c @@ -145,6 +145,9 @@ struct thread* create_thread(char *name, void (*function)(void *), void *data) unsigned long flags; /* Call architecture specific setup. */ thread = arch_create_thread(name, function, data); + if(!thread) + BUG(); //For now, FIXME should just return NULL + /* Not runable, not exited, not sleeping */ thread->flags = 0; thread->wakeup_time = 0LL; @@ -165,28 +168,28 @@ struct _reent *__getreent(void) struct _reent *_reent; if (!threads_started) - _reent = _impure_ptr; + _reent = _impure_ptr; else if (in_callback) - _reent = &callback_reent; + _reent = &callback_reent; else - _reent = &get_current()->reent; + _reent = &get_current()->reent; #ifndef NDEBUG #if defined(__x86_64__) || defined(__x86__) { #ifdef __x86_64__ - register unsigned long sp asm ("rsp"); + register unsigned long sp asm ("rsp"); #else - register unsigned long sp asm ("esp"); + register unsigned long sp asm ("esp"); #endif - if ((sp & (STACK_SIZE-1)) < STACK_SIZE / 16) { - static int overflowing; - if (!overflowing) { - overflowing = 1; - printk("stack overflow\n"); - BUG(); - } - } + if ((sp & (STACK_SIZE-1)) < STACK_SIZE / 16) { + static int overflowing; + if (!overflowing) { + overflowing = 1; + printk("stack overflow\n"); + BUG(); + } + } } #endif #else -- 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 |