[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH ARM v3 7/7] 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] Signed-off-by: Thomas Leonard <talex5@xxxxxxxxx> --- extras/mini-os/ARM-TODO.txt | 17 ++ 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 | 6 + extras/mini-os/arch/arm/arm32.S | 149 ++++++++++++++ extras/mini-os/arch/arm/events.c | 24 +++ extras/mini-os/arch/arm/hypercalls32.S | 88 ++++++++ extras/mini-os/arch/arm/minios-arm32.lds | 73 +++++++ 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/drivers/gic.c | 180 ++++++++++++++++ extras/mini-os/events.c | 4 +- extras/mini-os/hypervisor.c | 10 + extras/mini-os/include/arm/arch_limits.h | 9 + extras/mini-os/include/arm/arch_mm.h | 37 ++++ extras/mini-os/include/arm/arch_sched.h | 22 ++ extras/mini-os/include/arm/arch_spinlock.h | 49 +++++ extras/mini-os/include/arm/hypercall-arm32.h | 173 ++++++++++++++++ extras/mini-os/include/arm/os.h | 294 +++++++++++++++++++++++++++ extras/mini-os/include/arm/traps.h | 20 ++ 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 | 3 + 29 files changed, 1611 insertions(+), 7 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_limits.h create mode 100644 extras/mini-os/include/arm/arch_mm.h create mode 100644 extras/mini-os/include/arm/arch_sched.h create mode 100755 extras/mini-os/include/arm/arch_spinlock.h create mode 100644 extras/mini-os/include/arm/hypercall-arm32.h create mode 100644 extras/mini-os/include/arm/os.h create mode 100644 extras/mini-os/include/arm/traps.h create mode 100644 extras/mini-os/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..074a304 --- /dev/null +++ b/extras/mini-os/ARM-TODO.txt @@ -0,0 +1,17 @@ +* os.h bit manipulation, write optimized assembly code +* support abort exception handling ( and others ) +* scheduling! +* use proper memory types and enable caches (L1 and L2) +* Use LDREX and STREX in xchg implementation ( code already there but it causes an abort, I think because of using strong-ordered memory with disabled L1 caches - something to do with the implementation of the monitor on cortex-a7 ) +* gic request_irq implementation, currently all IRQs all hardcoded in gic irq handler. +* use device tree instead of the currently hardcoded values +* Add virtual memory support and make vstart = 0 ( use 4k descriptors instead of 1M descriptors ) +* sched +* fini_gnttab +* fini_time +* bind_* +* add multiple cpu support (?) +* map_frames +* clean up the code and remove redundent code between arm and x86 +* 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 5af40ad..1bfe354 100644 --- a/extras/mini-os/Makefile +++ b/extras/mini-os/Makefile @@ -76,6 +76,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 @@ -96,7 +104,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 @@ -185,7 +195,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..80650fc --- /dev/null +++ b/extras/mini-os/arch/arm/arch.mk @@ -0,0 +1,6 @@ +ifeq ($(XEN_TARGET_ARCH),arm32) +ARCH_CFLAGS := -march=armv7-a -marm -fms-extensions -D__arm__ -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..f725295 --- /dev/null +++ b/extras/mini-os/arch/arm/arm32.S @@ -0,0 +1,149 @@ +#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 _start @ absolute load/run zImage address + .word _end - _start @ zImage size + @ 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, #0x7 @ (dcache, barriers, 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 +exception_vector_table: + b . @ reset + b . @ undefined instruction + b . @ supervisor call + b . @ prefetch call + b . @ prefetch abort + b . @ data abort //FIXME CLREX + b irq_handler @ irq + .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} + 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..5fd637e --- /dev/null +++ b/extras/mini-os/arch/arm/events.c @@ -0,0 +1,24 @@ +#include <mini-os/os.h> +#include <mini-os/events.h> +#include <mini-os/hypervisor.h> + +static void virq_debug(evtchn_port_t port, struct pt_regs *regs, void *params) +{ + printk("Received a virq_debug event\n"); +} + +evtchn_port_t debug_port = -1; +void arch_init_events(void) { + debug_port = bind_virq(VIRQ_DEBUG, (evtchn_handler_t)virq_debug, 0); + if(debug_port == -1) + BUG(); + unmask_evtchn(debug_port); +} + +void arch_fini_events(void) { + if(debug_port != -1) + { + mask_evtchn(debug_port); + unbind_evtchn(debug_port); + } +} diff --git a/extras/mini-os/arch/arm/hypercalls32.S b/extras/mini-os/arch/arm/hypercalls32.S new file mode 100644 index 0000000..e2f21c4 --- /dev/null +++ b/extras/mini-os/arch/arm/hypercalls32.S @@ -0,0 +1,88 @@ +#define __HYPERVISOR_set_trap_table 0 +#define __HYPERVISOR_mmu_update 1 +#define __HYPERVISOR_set_gdt 2 +#define __HYPERVISOR_stack_switch 3 +#define __HYPERVISOR_set_callbacks 4 +#define __HYPERVISOR_fpu_taskswitch 5 +#define __HYPERVISOR_sched_op_compat 6 /* compat since 0x00030101 */ +#define __HYPERVISOR_platform_op 7 +#define __HYPERVISOR_set_debugreg 8 +#define __HYPERVISOR_get_debugreg 9 +#define __HYPERVISOR_update_descriptor 10 +#define __HYPERVISOR_memory_op 12 +#define __HYPERVISOR_multicall 13 +#define __HYPERVISOR_update_va_mapping 14 +#define __HYPERVISOR_set_timer_op 15 +#define __HYPERVISOR_event_channel_op_compat 16 /* compat since 0x00030202 */ +#define __HYPERVISOR_xen_version 17 +#define __HYPERVISOR_console_io 18 +#define __HYPERVISOR_physdev_op_compat 19 /* compat since 0x00030202 */ +#define __HYPERVISOR_grant_table_op 20 +#define __HYPERVISOR_vm_assist 21 +#define __HYPERVISOR_update_va_mapping_otherdomain 22 +#define __HYPERVISOR_iret 23 /* x86 only */ +#define __HYPERVISOR_vcpu_op 24 +#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ +#define __HYPERVISOR_mmuext_op 26 +#define __HYPERVISOR_xsm_op 27 +#define __HYPERVISOR_nmi_op 28 +#define __HYPERVISOR_sched_op 29 +#define __HYPERVISOR_callback_op 30 +#define __HYPERVISOR_xenoprof_op 31 +#define __HYPERVISOR_event_channel_op 32 +#define __HYPERVISOR_physdev_op 33 +#define __HYPERVISOR_hvm_op 34 +#define __HYPERVISOR_sysctl 35 +#define __HYPERVISOR_domctl 36 +#define __HYPERVISOR_kexec_op 37 +#define __HYPERVISOR_tmem_op 38 +#define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */ + + + +#define __HVC(imm16) .long ((0xE1400070 | (((imm16) & 0xFFF0) << 4) | ((imm16) & 0x000F)) & 0xFFFFFFFF) + +#define XEN_IMM 0xEA1 + +#define HYPERCALL_SIMPLE(hypercall) \ +.globl HYPERVISOR_##hypercall; \ +.align 4,0x90; \ +HYPERVISOR_##hypercall: \ + mov r12, #__HYPERVISOR_##hypercall; \ + __HVC(XEN_IMM); \ + mov pc, lr; + +#define _hypercall0 HYPERCALL_SIMPLE +#define _hypercall1 HYPERCALL_SIMPLE +#define _hypercall2 HYPERCALL_SIMPLE +#define _hypercall3 HYPERCALL_SIMPLE +#define _hypercall4 HYPERCALL_SIMPLE + +_hypercall1(set_trap_table); +_hypercall4(mmu_update); +_hypercall4(mmuext_op); +_hypercall2(set_gdt); +_hypercall2(stack_switch); +_hypercall3(set_callbacks); +_hypercall1(fpu_taskswitch); +_hypercall2(sched_op); +_hypercall1(set_timer_op); +_hypercall2(set_debugreg); +_hypercall1(get_debugreg); +_hypercall2(update_descriptor); +_hypercall2(memory_op); +_hypercall2(multicall); +_hypercall3(update_va_mapping); +_hypercall2(event_channel_op); +_hypercall2(xen_version); +_hypercall3(console_io); +_hypercall1(physdev_op); +_hypercall3(grant_table_op); +_hypercall4(update_va_mapping_otherdomain); +_hypercall2(vm_assist); +_hypercall3(vcpu_op); +_hypercall2(set_segment_base); +_hypercall2(nmi_op); +_hypercall1(sysctl); +_hypercall1(domctl); +_hypercall2(hvm_op); diff --git a/extras/mini-os/arch/arm/minios-arm32.lds b/extras/mini-os/arch/arm/minios-arm32.lds new file mode 100755 index 0000000..793f0de --- /dev/null +++ b/extras/mini-os/arch/arm/minios-arm32.lds @@ -0,0 +1,73 @@ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x80008000; + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.gnu.warning) + } = 0x9090 + + _etext = .; /* End of text section */ + + .rodata : { *(.rodata) *(.rodata.*) } + . = ALIGN(4096); + _erodata = .; + + /* newlib initialization functions */ + . = ALIGN(32 / 8); + PROVIDE (__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE (__fini_array_end = .); + + .ctors : { + __CTOR_LIST__ = .; + *(.ctors) + CONSTRUCTORS + LONG(0) + __CTOR_END__ = .; + } + + .dtors : { + __DTOR_LIST__ = .; + *(.dtors) + LONG(0) + __DTOR_END__ = .; + } + + .data : { /* Data */ + *(.data) + } + + _edata = .; /* End of data section */ + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + *(.app.bss) + } + _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff --git a/extras/mini-os/arch/arm/mm.c b/extras/mini-os/arch/arm/mm.c new file mode 100644 index 0000000..3e797c2 --- /dev/null +++ b/extras/mini-os/arch/arm/mm.c @@ -0,0 +1,44 @@ +#include <console.h> +#include <arm/arch_mm.h> + +#define PHYS_START (0x80008000 + (1000 * 4 * 1024)) +#define PHYS_SIZE (40*1024*1024) + +static void build_pagetable(unsigned long *start_pfn, unsigned long *max_pfn) +{ + // FIXME Create small pages descriptors here instead of the 1M superpages created earlier. + return; +} + +unsigned long allocate_ondemand(unsigned long n, unsigned long alignment) +{ + // FIXME + BUG(); +} + +void arch_init_mm(unsigned long* start_pfn_p, unsigned long* max_pfn_p) +{ + printk(" _text: %p(VA)\n", &_text); + printk(" _etext: %p(VA)\n", &_etext); + printk(" _erodata: %p(VA)\n", &_erodata); + printk(" _edata: %p(VA)\n", &_edata); + printk(" stack start: %p(VA)\n", stack); + printk(" _end: %p(VA)\n", &_end); + + // FIXME Get from dt! + *start_pfn_p = (((unsigned long)&_end) >> PAGE_SHIFT) + 1000; + *max_pfn_p = ((unsigned long)&_end + PHYS_SIZE) >> PAGE_SHIFT; + + printk(" start_pfn: %lx\n", *start_pfn_p); + printk(" max_pfn: %lx\n", *max_pfn_p); + + build_pagetable(start_pfn_p, max_pfn_p); +} + +void arch_init_p2m(unsigned long max_pfn) +{ +} + +void arch_init_demand_mapping_area(unsigned long cur_pfn) +{ +} diff --git a/extras/mini-os/arch/arm/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..3654cc5 --- /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 <arm/arch_mm.h> + +/* + * This structure contains start-of-day info, such as pagetable base pointer, + * address of the shared_info structure, and things like that. + * 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..ff86873 --- /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/drivers/gic.c b/extras/mini-os/drivers/gic.c new file mode 100644 index 0000000..e931f01 --- /dev/null +++ b/extras/mini-os/drivers/gic.c @@ -0,0 +1,180 @@ +// ARM GIC implementation + +#include <mini-os/os.h> +#include <mini-os/hypervisor.h> + +//#define VGIC_DEBUG +#ifdef VGIC_DEBUG +#define DEBUG(_f, _a...) \ + DEBUG("MINI_OS(file=vgic.c, line=%d) " _f , __LINE__, ## _a) +#else +#define DEBUG(_f, _a...) ((void)0) +#endif + +extern unsigned long IRQ_handler; + +struct gic { + volatile char *gicd_base; + volatile char *gicc_base; +}; + +static struct gic gic; + +// Distributor Interface +#define GICD_CTLR 0x0 +#define GICD_ISENABLER 0x100 +#define GICD_PRIORITY 0x400 +#define GICD_ITARGETSR 0x800 +#define GICD_ICFGR 0xC00 + +// CPU Interface +#define GICC_CTLR 0x0 +#define GICC_PMR 0x4 +#define GICC_IAR 0xc +#define GICC_EOIR 0x10 +#define GICC_HPPIR 0x18 + +#define gicd(gic, offset) ((gic)->gicd_base + (offset)) +#define gicc(gic, offset) ((gic)->gicc_base + (offset)) + +#define REG(addr) ((uint32_t *)(addr)) + +static inline uint32_t REG_READ32(volatile uint32_t *addr) +{ + uint32_t value; + __asm__ __volatile__("ldr %0, [%1]":"=&r"(value):"r"(addr)); + rmb(); + return value; +} + +static inline void REG_WRITE32(volatile uint32_t *addr, unsigned int value) +{ + __asm__ __volatile__("str %0, [%1]"::"r"(value), "r"(addr)); + wmb(); +} + +static void gic_set_priority(struct gic *gic, unsigned char irq_number, unsigned char priority) +{ + uint32_t value; + value = REG_READ32(REG(gicd(gic, GICD_PRIORITY)) + irq_number); + value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0' + value |= priority << (8 * (irq_number & 0x3)); // add our priority + REG_WRITE32(REG(gicd(gic, GICD_PRIORITY)) + irq_number, value); +} + +static void gic_route_interrupt(struct gic *gic, unsigned char irq_number, unsigned char cpu_set) +{ + uint32_t value; + value = REG_READ32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number); + value &= ~(0xff << (8 * (irq_number & 0x3))); // set priority to '0' + value |= cpu_set << (8 * (irq_number & 0x3)); // add our priority + REG_WRITE32(REG(gicd(gic, GICD_ITARGETSR)) + irq_number, value); +} + +static void gic_enable_interrupt(struct gic *gic, unsigned char irq_number, + unsigned char cpu_set, unsigned char level_sensitive, unsigned char ppi) +{ + void *set_enable_reg; + void *cfg_reg; + + // set priority + gic_set_priority(gic, irq_number, 0x0); + + // set target cpus for this interrupt + gic_route_interrupt(gic, irq_number, cpu_set); + + // set level/edge triggered + cfg_reg = (void *)gicd(gic, GICD_ICFGR); + level_sensitive ? clear_bit((irq_number * 2) + 1, cfg_reg) : set_bit((irq_number * 2) + 1, cfg_reg); + if(ppi) + clear_bit((irq_number * 2), cfg_reg); + + wmb(); + + // enable forwarding interrupt from distributor to cpu interface + set_enable_reg = (void *)gicd(gic, GICD_ISENABLER); + set_bit(irq_number, set_enable_reg); + wmb(); +} + +static void gic_enable_interrupts(struct gic *gic) +{ + // Global enable forwarding interrupts from distributor to cpu interface + REG_WRITE32(REG(gicd(gic, GICD_CTLR)), 0x00000001); + + // Global enable signalling of interrupt from the cpu interface + REG_WRITE32(REG(gicc(gic, GICC_CTLR)), 0x00000001); +} + +static void gic_disable_interrupts(struct gic *gic) +{ + // Global disable signalling of interrupt from the cpu interface + REG_WRITE32(REG(gicc(gic, GICC_CTLR)), 0x00000000); + + // Global disable forwarding interrupts from distributor to cpu interface + REG_WRITE32(REG(gicd(gic, GICD_CTLR)), 0x00000000); +} + +static void gic_cpu_set_priority(struct gic *gic, char priority) +{ + REG_WRITE32(REG(gicc(gic, GICC_PMR)), priority & 0x000000FF); +} + +static void gic_set_handler(unsigned long gic_handler) { + IRQ_handler = gic_handler; +} + +static unsigned long gic_readiar(struct gic *gic) { + return REG_READ32(REG(gicc(gic, GICC_IAR))) & 0x000003FF; // Interrupt ID +} + +static void gic_eoir(struct gic *gic, uint32_t irq) { + REG_WRITE32(REG(gicc(gic, GICC_EOIR)), irq & 0x000003FF); +} + +//FIXME Get event_irq from dt +#define EVENTS_IRQ 31 +#define VIRTUALTIMER_IRQ 27 + +//FIXME Move to a header file +void timer_handler(evtchn_port_t port, struct pt_regs *regs, void *ign); + +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(); + + gic_set_handler((unsigned long)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 d60630b..79ba286 100644 --- a/extras/mini-os/events.c +++ b/extras/mini-os/events.c @@ -246,7 +246,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; @@ -261,6 +262,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..2a12ec4 100644 --- a/extras/mini-os/hypervisor.c +++ b/extras/mini-os/hypervisor.c @@ -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_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..5e3953b --- /dev/null +++ b/extras/mini-os/include/arm/arch_mm.h @@ -0,0 +1,37 @@ +#ifndef _ARCH_MM_H_ +#define _ARCH_MM_H_ + +extern char _text, _etext, _erodata, _edata, _end, __bss_start; +extern char stack[]; + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#define L1_PAGETABLE_SHIFT 12 + +#if 0 +#define VIRT_START ((unsigned long)&_text) +#else +#define VIRT_START ((unsigned long)0) +#endif + +#define to_phys(x) ((unsigned long)(x)-VIRT_START) +#define to_virt(x) ((void *)((unsigned long)(x)+VIRT_START)) + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> L1_PAGETABLE_SHIFT) +#define PFN_DOWN(x) ((x) >> L1_PAGETABLE_SHIFT) +#define PFN_PHYS(x) ((uint64_t)(x) << L1_PAGETABLE_SHIFT) +#define PHYS_PFN(x) ((x) >> L1_PAGETABLE_SHIFT) + +#define virt_to_pfn(_virt) (PFN_DOWN(to_phys(_virt))) +#define virt_to_mfn(_virt) (0) +#define mach_to_virt(_mach) (0) +#define virt_to_mach(_virt) (0) +#define mfn_to_virt(_mfn) (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/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..bacc4af --- /dev/null +++ b/extras/mini-os/include/arm/os.h @@ -0,0 +1,294 @@ +#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); + +#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 LOCK_PREFIX "" +#define LOCK "" + +#define unlikely(x) __builtin_expect((x),0) +#define likely(x) __builtin_expect((x),1) + +#define ADDR (*(volatile long *) addr) + +/************************** arm *******************************/ +#ifdef __INSIDE_MINIOS__ +#if defined (__arm__) +#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr)))) +#define __xg(x) ((volatile long *)(x)) + +static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +{ + //TODO + unsigned volatile long y, tmp = 0; + switch(size){ + case 1: +#if CPU_EXCLUSIVE_LDST + __asm__ __volatile__("1:ldrexb %0, [%1]\n" + "strexb %3, %2, [%1]\n" + "cmp %3, #1\n" + "beq 1b\n\n" + "dmb\n":"=&r"(y):"r"(ptr), "r"(x), "r"(tmp):"memory"); +#else + y = (*(char *)ptr) & 0x000000ff; + *((char *)ptr) = (char)x; +#endif + break; + case 2: +#if CPU_EXCLUSIVE_LDST + __asm__ __volatile__("1:ldrexh %0, [%1]\n" + "strexh %3, %2, [%1]\n" + "cmp %3, #1\n" + "beq 1b\n\n" + "dmb\n":"=&r"(y):"r"(ptr), "r"(x), "r"(tmp):"memory"); +#else + y = (*(short *)ptr) & 0x0000ffff; + *((short *)ptr) = (short)x; +#endif + break; + default: // 4 +#if CPU_EXCLUSIVE_LDST + __asm__ __volatile__("1:ldrex %0, [%1]\n" + "strex %3, %2, [%1]\n" + "cmp %3, #1\n" + "beq 1b\n\n" + "dmb\n":"=&r"(y):"r"(ptr), "r"(x), "r"(tmp):"memory"); +#else + y = (*(unsigned long *)ptr) & 0xffffffff; + *((unsigned long *)ptr) = x; +#endif + break; + } + return y; +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is atomic and cannot be reordered. + * It also implies a memory barrier. + */ +static __inline__ int test_and_clear_bit(int nr, volatile void * addr) +{ + //TODO + unsigned long *tmp = (unsigned long *)addr; + + int x = tmp[nr >> 5] & (1 << (nr & 0x1f)); + tmp[nr >> 5] &= ~(1 << (nr & 0x1f)); + return x; +} + +static __inline__ int test_and_set_bit(int nr, volatile void * addr) +{ + //TODO + unsigned long *tmp = (unsigned long *)addr; + + int x = tmp[nr >> 5] & (1 << (nr & 0x1f)); + tmp[nr >> 5] |= (1 << (nr & 0x1f)); + return x; +} + +static __inline__ int constant_test_bit(int nr, const volatile void * addr) +{ + //TODO + unsigned long *tmp = (unsigned long *)addr; + return tmp[nr >> 5] & (1 << (nr & 0x1f)); +} + +static __inline__ int variable_test_bit(int nr, volatile const void * addr) +{ + //TODO: + unsigned long *tmp = (unsigned long *)addr; + return tmp[nr >> 5] & (1 << (nr & 0x1f)); +} + +//TODO +#define test_bit(nr,addr) (((unsigned long *)addr)[nr >> 5] & (1 << (nr & 0x1f))) + + +/** + * set_bit - Atomically set a bit in memory + * @nr: the bit to set + * @addr: the address to start counting from + * + * This function is atomic and may not be reordered. See __set_bit() + * if you do not require the atomic guarantees. + * Note that @nr may be almost arbitrarily large; this function is not + * restricted to acting on a single-word quantity. + */ +static __inline__ void set_bit(int nr, volatile void * addr) +{ + //TODO: + unsigned long *tmp = (unsigned long *)addr; + tmp[nr >> 5] |= (1 << (nr & 0x1f)); +} + +/** + * clear_bit - Clears a bit in memory + * @nr: Bit to clear + * @addr: Address to start counting from + * + * clear_bit() is atomic and may not be reordered. However, it does + * not contain a memory barrier, so if it is used for locking purposes, + * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() + * in order to ensure changes are visible on other processors. + */ +static __inline__ void clear_bit(int nr, volatile void * addr) +{ + //TODO + unsigned long *tmp = (unsigned long *)addr; + tmp[nr >> 5] &= (unsigned long)~(1 << (nr & 0x1f)); +} + +/** + * __ffs - find first bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +static __inline__ unsigned long __ffs(unsigned long word) +{ + //TODO + int index = 0; + while(!(word & (1 << index++))){}; + + return index - 1; +} + +//FIXME +#define rdtscll(val) (val = 0) + +#define wrmsr(msr,val1,val2) (0) + +#define wrmsrl(msr,val) wrmsr(msr,(uint32_t)((uint64_t)(val)),((uint64_t)(val))>>32) + + +#else /* ifdef __arm__ */ +#error "Unsupported architecture" +#endif +#endif /* ifdef __INSIDE_MINIOS */ + +/********************* common arm32 and arm64 ****************************/ +struct __synch_xchg_dummy { unsigned long a[100]; }; +#define __synch_xg(x) ((struct __synch_xchg_dummy *)(x)) + +#define synch_cmpxchg(ptr, old, new) (0) + +static inline unsigned long __synch_cmpxchg(volatile void *ptr, + unsigned long old, + unsigned long new, int size) +{ + //TODO: + //BUG(); + return 0; +} + + +static __inline__ void synch_set_bit(int nr, volatile void * addr) +{ + //TODO: + set_bit(nr, addr); +} + +static __inline__ void synch_clear_bit(int nr, volatile void * addr) +{ + //TODO: + clear_bit(nr, addr); +} + +static __inline__ int synch_test_and_set_bit(int nr, volatile void * addr) +{ + //TODO: + return test_and_set_bit(nr, addr); +} + +static __inline__ int synch_test_and_clear_bit(int nr, volatile void * addr) +{ + //TODO: + return test_and_clear_bit(nr, addr); +} + +static __inline__ int synch_const_test_bit(int nr, const volatile void * addr) +{ + //TODO: + return const_test_bit(nr, addr); +} + +static __inline__ int synch_var_test_bit(int nr, volatile void * addr) +{ + //TODO: + return var_test_bit(nr, addr); +} + +#define synch_test_bit(nr,addr) test_bit(nr, addr) + + +#undef ADDR + +#endif /* not assembly */ + +#endif diff --git a/extras/mini-os/include/arm/traps.h b/extras/mini-os/include/arm/traps.h new file mode 100644 index 0000000..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/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 6640ede..931e853 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 b9ab0a2..cdf5928 100644 --- a/extras/mini-os/kernel.c +++ b/extras/mini-os/kernel.c @@ -46,6 +46,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) @@ -146,6 +150,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..ed3f8c0 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; -- 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 |