diff --git a/.gitignore b/.gitignore index 5e458a3a..dcacdf3b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ *.pyc *.pyo *.swp -/arch/x86/*.lds +/arch/*/*.lds /cscope.* /dist/ /docs/autogenerated/ diff --git a/INSTALL b/INSTALL index ed19623b..296a0f01 100644 --- a/INSTALL +++ b/INSTALL @@ -2,6 +2,24 @@ Xen Test Framework Build requirements: - GNU Make >= 3.81 +For x86: - GNU compatible compiler, capable of: -std=gnu99 -m64 and -m32 +For arm64/arm32: +-when cross-compiling: + - GNU compatible cross-compiler toolchain for Aarch64/Aarch32 +-when building natively: + - GNU compatible toolchain for Aarch64/Aarch32 + +To build XTF: +-for x86: + $ make +-for arm64 natively: + $ make ARCH=arm64 +-for arm64 when cross compiling: + $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- +-for arm32 natively: + $ make ARCH=arm32 +-for arm32 when cross compiling: + $ make ARCH=arm32 CROSS_COMPILE=arm-linux-gnueabi- diff --git a/Makefile b/Makefile index 91959573..35e8b301 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ MAKEFLAGS += -rR ROOT := $(abspath $(CURDIR)) -export ROOT # $(xtfdir) defaults to $(ROOT) so development and testing can be done # straight out of the working tree. @@ -19,7 +18,16 @@ endif xtftestdir := $(xtfdir)/tests -export DESTDIR xtfdir xtftestdir +# Supported architectures +SUPPORTED_ARCH := x86 arm64 arm32 +# Default architecture +ARCH ?= x86 +# Check if specified architecture is supported +ifeq ($(filter $(ARCH),$(SUPPORTED_ARCH)),) +$(error Architecture '$(ARCH)' not supported) +endif + +export ROOT DESTDIR ARCH xtfdir xtftestdir ifeq ($(LLVM),) # GCC toolchain CC := $(CROSS_COMPILE)gcc @@ -50,9 +58,16 @@ PYTHON ?= $(PYTHON_INTERPRETER) export CC LD CPP INSTALL INSTALL_DATA INSTALL_DIR INSTALL_PROGRAM OBJCOPY PYTHON +# Some tests are architecture specific. In this case we can have a list of tests +# supported by a given architecture in $(ROOT)/build/$(ARCH)/arch-tests.mk +-include $(ROOT)/build/$(ARCH)/arch-tests.mk + +# By default enable all the tests +TESTS ?= $(wildcard tests/*) + .PHONY: all all: - @set -e; for D in $(wildcard tests/*); do \ + @set -e; for D in $(TESTS); do \ [ ! -e $$D/Makefile ] && continue; \ $(MAKE) -C $$D build; \ done @@ -61,7 +76,7 @@ all: install: @$(INSTALL_DIR) $(DESTDIR)$(xtfdir) $(INSTALL_PROGRAM) xtf-runner $(DESTDIR)$(xtfdir) - @set -e; for D in $(wildcard tests/*); do \ + @set -e; for D in $(TESTS); do \ [ ! -e $$D/Makefile ] && continue; \ $(MAKE) -C $$D install; \ done diff --git a/README b/README index 20d91270..7ae54cda 100644 --- a/README +++ b/README @@ -9,12 +9,19 @@ Tests for more generic areas are build multiple times into different microkernels, to test the same functionality from different types of virtual machine. +Currently there are 3 architectures available: x86, arm64 and arm32 although +only x86 is truly supported. Initial support for arm64 is added allowing to run +hello-world test. Support for arm32 allows to run startup code. +This creates a base for future implementation. + ## The framework consists of: * PV and HVM, 32 and 64 bit entry points * Hypercall interface * PV console driver (output) * Common reporting framework +* Initial support for arm64 (hello-world test running) +* Initial support for arm32 (startup code running) ## TODO List: diff --git a/arch/arm/arm32/head.S b/arch/arm/arm32/head.S new file mode 100644 index 00000000..219e6444 --- /dev/null +++ b/arch/arm/arm32/head.S @@ -0,0 +1,35 @@ +#include + +#define ZIMAGE_MAGIC_NUMBER 0x016f2818 + +.arm + +/* + * Common register usage for assembly boot code + * + * r10 - DTB physical address (boot CPU only) + * r9 - Offset between PA and VA ( PA - VA) + */ +ENTRY(_start) + /* 8 NOPs that make the compressed kernel bootable on legacy ARM systems */ +.rept 8 + mov r0, r0 +.endr + b startup + /* Magic number used to identify this is an ARM Linux zImage */ + .word ZIMAGE_MAGIC_NUMBER + /* The address the zImage starts at (0 = relocatable) */ + .word 0 + /* The address the zImage ends at */ + .word (_end - _start) +startup: + /* Save DTB pointer */ + mov r10, r2 + + /* Calculate where we are */ + ldr r0, =_start /* r0 := vaddr(_start) */ + adr r8, _start /* r8 := paddr(_start) */ + sub r9, r8, r0 /* r9 := phys-offset */ + + /* Start an infinite loop */ +1: b 1b diff --git a/arch/arm/arm32/hypercall.S b/arch/arm/arm32/hypercall.S new file mode 100644 index 00000000..05c79a46 --- /dev/null +++ b/arch/arm/arm32/hypercall.S @@ -0,0 +1,45 @@ +#include +#include + +#define __HVC(imm16) .long \ + ((0xE1400070 | (((imm16) & 0xFFF0) << 4) | ((imm16) & 0x000F)) & 0xFFFFFFFF) + +#define HYPERCALL_SIMPLE(hypercall) \ +ENTRY(hypercall_##hypercall) \ + mov r12, #__HYPERVISOR_##hypercall; \ + __HVC(XEN_HYPERCALL_TAG); \ + mov pc ,lr; \ +ENDFUNC(hypercall_##hypercall) + +#define HYPERCALL0 HYPERCALL_SIMPLE +#define HYPERCALL1 HYPERCALL_SIMPLE +#define HYPERCALL2 HYPERCALL_SIMPLE +#define HYPERCALL3 HYPERCALL_SIMPLE +#define HYPERCALL4 HYPERCALL_SIMPLE + +#define HYPERCALL5(hypercall) \ +ENTRY(hypercall_##hypercall) \ + stmdb sp!, {r4}; \ + ldr r4, [sp, #4]; \ + mov r12, #__HYPERVISOR_##hypercall; \ + __HVC(XEN_HYPERCALL_TAG); \ + ldm sp!, {r4}; \ + mov pc ,lr; \ +ENDFUNC(hypercall_##hypercall) + +.text + +HYPERCALL2(xen_version); +HYPERCALL3(console_io); +HYPERCALL3(grant_table_op); +HYPERCALL2(sched_op); +HYPERCALL2(event_channel_op); +HYPERCALL2(hvm_op); +HYPERCALL2(memory_op); +HYPERCALL2(physdev_op); +HYPERCALL3(vcpu_op); +HYPERCALL1(tmem_op); +HYPERCALL2(multicall); +HYPERCALL2(vm_assist); +HYPERCALL1(sysctl); +HYPERCALL1(domctl); diff --git a/arch/arm/arm64/cache.S b/arch/arm/arm64/cache.S new file mode 100644 index 00000000..8e6fa91e --- /dev/null +++ b/arch/arm/arm64/cache.S @@ -0,0 +1,26 @@ +#include + +/* + * flush_dcache_range(start, end) + * - x0(start) - start address of a region + * - x1(end) - end address of a region + * Clobbers: x2, x3, x4 + */ +ENTRY(flush_dcache_range) + /* Do not modify x0 */ + mov x4, x0 + /* Get the minimum D-cache line size */ + mrs x3, ctr_el0 + ubfm x3, x3, #16, #19 + mov x2, #4 + lsl x2, x2, x3 + sub x3, x2, #1 + bic x4, x4, x3 + /* Clean and invalidate D-cache line */ +1: dc civac, x4 + add x4, x4, x2 + cmp x4, x1 + b.lo 1b + dsb sy + ret +ENDFUNC(flush_dcache_range) diff --git a/arch/arm/arm64/head.S b/arch/arm/arm64/head.S new file mode 100644 index 00000000..85ae0e60 --- /dev/null +++ b/arch/arm/arm64/head.S @@ -0,0 +1,448 @@ +#include +#include +#include +#include + +/* Necessary for older compilers */ +lr .req x30 + +/* 1 if BE, 0 if LE */ +#define HEAD_FLAG_ENDIANNESS 0 +#define HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2) +#define HEAD_FLAG_PHYS_BASE 1 +#define HEAD_FLAGS ((HEAD_FLAG_ENDIANNESS << 0) | \ + (HEAD_FLAG_PAGE_SIZE << 1) | \ + (HEAD_FLAG_PHYS_BASE << 3)) + +/* Include console driver */ +#ifdef CONFIG_PL011_EARLY_PRINTK +#include "pl011.inc" +#else +#include "hvc.inc" +#endif + +/* + * Print a string to the console + * console_puts is a driver specific function to print a string. + * Address of a string is stored in x0. + */ +#define PRINT(s) \ + adr x0, 98f; \ + console_puts; \ +.pushsection .rodata.str, "aMS", %progbits, 1; \ +98: .asciz s; \ +.popsection + +.section ".bss.page_aligned" +.p2align PAGE_SHIFT + +stack_start: + .space STACK_SIZE +stack_end: + +.text + b _start /* branch to kernel start, magic */ + .long 0 /* Executable code */ + .quad 0x0 /* Image load offset from start of RAM */ + .quad _end - _start /* Effective Image size */ + .quad HEAD_FLAGS /* Informative flags, little-endian */ + .quad 0 /* reserved */ + .quad 0 /* reserved */ + .quad 0 /* reserved */ + .byte 0x41 /* Magic number, "ARM\x64" */ + .byte 0x52 + .byte 0x4d + .byte 0x64 + .long 0 /* reserved */ + + +/* Load a physical address of \sym to \xb */ +.macro load_paddr xb, sym + ldr \xb, =\sym + add \xb, \xb, x21 +.endm + +/* + * Common register usage for assembly boot code + * + * x20 - DTB physical address (boot CPU only) + * x21 - Offset between PA and VA ( PA - VA) + * x30 - lr + */ +ENTRY(_start) + /* Disable all IRQs */ + msr daifset, #0xf + + /* Save DTB pointer */ + mov x20, x0 + + /* Disable MMU */ + bl _mmu_disable + + /* Calculate where we are */ + ldr x22, =_start /* x22 := vaddr(_start) */ + adr x21, _start /* x21 := paddr(_start) */ + sub x21, x21, x22 /* x21 := phys-offset */ + + bl console_init + + PRINT("- XTF booting -\n") + + PRINT("- Setup CPU -\n") + bl _cpu_setup + + /* Load the vector table */ + ldr x2, =vector_table + msr vbar_el1, x2 + +#ifdef CONFIG_MMU + /* + * TTBR0_EL1 - identity mapping + * TTBR1_EL1 - page tables + */ + PRINT("- Setup page tables -\n") + bl _setup_page_tables + bl _setup_identity_mapping + + PRINT("- Enable MMU -\n") + bl _mmu_enable + + /* Jump to the runtime VA */ + ldr x0, =mmu_enabled + br x0 + +mmu_enabled: + bl _setup_fixmap +#ifdef CONFIG_PL011_EARLY_PRINTK + /* From now on use a virtual address to access the UART */ + ldr x23, =PL011_EARLY_VA +#endif + + /* + * Remove identity mapping. + * By setting bit EPD0 we are disabling page table walk using TTBR0_EL1. + */ + mrs x0, tcr_el1 + add x0, x0, #TCR_EPD0 + msr tcr_el1, x0 +#endif /* CONFIG_MMU */ + + PRINT("- Zero BSS -\n") + ldr x0, =__start_bss + ldr x1, =__end_bss + + bl flush_dcache_range +1: str xzr, [x0], #8 + cmp x0, x1 + b.lo 1b + + /* Load BSS start address again as x0 has been modified in the upper loop */ + ldr x0, =__start_bss + bl flush_dcache_range + + PRINT("- Setup stack -\n") + ldr x1, =stack_end + mov sp, x1 + + /* Save boot arguments */ + ldr x0, =boot_data + stp x21, x20, [x0] + + PRINT("- Jump to C world-\n") + b xtf_main +ENDFUNC(_start) + +ENTRY(_mmu_disable) + dsb sy + + /* Turn off D-cache and MMU */ + mrs x2, sctlr_el1 + bic x2, x2, #SCTLR_M + bic x2, x2, #SCTLR_C + msr sctlr_el1, x2 + isb + + ret +ENDFUNC(_mmu_disable) + +ENTRY(_cpu_setup) + dsb sy + + /* Set up memory attribute type tables */ + ldr x0, =MAIRVAL + msr mair_el1, x0 + + /* Set up TCR_EL1 register */ + ldr x0, =TCRVAL + mrs x1, ID_AA64MMFR0_EL1 + /* Set TCR_EL1.IPS to ID_AA64MMFR0_EL1.PARange */ + bfi x0, x1, #32, #3 + msr tcr_el1, x0 + isb + + ret +ENDFUNC(_cpu_setup) + +#ifdef CONFIG_MMU +ENTRY(_mmu_enable) + dsb sy + + /* Turn on D-cache and MMU */ + mrs x2, sctlr_el1 + orr x2, x2, #SCTLR_M + orr x2, x2, #SCTLR_C + msr sctlr_el1, x2 + isb + + ret +ENDFUNC(_mmu_enable) + +ENTRY(_setup_page_tables) + ldr x0, =_text + ldr x1, =_end + load_paddr x3, l2_bpgtable + load_paddr x4, l1_bpgtable + + /* L1 table -> L2 table */ + /* Find page table index */ + lsr x2, x0, #L1_TABLE_SHIFT + and x2, x2, #TABLE_ADDR_MASK + + /* Create page descriptor */ + ldr x5, =DESC_PAGE_TABLE + lsr x6, x3, #PAGE_SHIFT + orr x5, x5, x6, lsl #PAGE_SHIFT + + /* Store the entry */ + str x5, [x4, x2, lsl #3] + + /* Set TTBR1_EL1 */ + msr ttbr1_el1, x4 + dsb sy + + /* L2 table -> 2M blocks */ + /* Find page table index */ +1: lsr x2, x0, #L2_TABLE_SHIFT + and x2, x2, #TABLE_ADDR_MASK + + /* Create block descriptor */ + add x7, x0, x21 + lsr x7, x7, #PAGE_SHIFT + ldr x5, =DESC_PAGE_BLOCK + orr x5, x5, x7, lsl #PAGE_SHIFT + + /* Store the entry */ + str x5, [x3, x2, lsl #3] + + add x0, x0, #L2_TABLE_SIZE + cmp x1, x0 + b.gt 1b + + ret +ENDFUNC(_setup_page_tables) + +ENTRY(_setup_identity_mapping) + load_paddr x0, l1_idmap + load_paddr x1, _text + + /* Find the index */ + lsr x2, x1, #L1_TABLE_SHIFT + and x2, x2, #TABLE_ADDR_MASK + + /* Create block descriptor */ + ldr x3, =DESC_PAGE_BLOCK + lsr x4, x1, #PAGE_SHIFT + orr x3, x3, x4, lsl #PAGE_SHIFT + + /* Store the entry */ + str x3, [x0, x2, lsl #3] + + /* Set TTBR0_EL1 */ + msr ttbr0_el1, x0 + isb + + ret +ENDFUNC(_setup_identity_mapping) + +ENTRY(_setup_fixmap) + ldr x0, =FIXMAP_ADDR(0) + load_paddr x1, fix_pgtable + load_paddr x2, l2_bpgtable + + /* L2 table -> L3 table(fixmap) */ + /* Find page table index */ + lsr x3, x0, #L2_TABLE_SHIFT + and x3, x3, #TABLE_ADDR_MASK + + /* Create page descriptor */ + ldr x4, =DESC_PAGE_TABLE + lsr x5, x1, #PAGE_SHIFT + orr x4, x4, x5, lsl #PAGE_SHIFT + + /* Store the entry */ + str x4, [x2, x3, lsl #3] + +#ifdef CONFIG_PL011_UART + /* Map UART address in fixmap table */ + /* Find page table index */ + lsr x3, x0, #L3_TABLE_SHIFT + and x3, x3, #TABLE_ADDR_MASK + + /* Create page descriptor */ + ldr x5, =CONFIG_PL011_ADDRESS + ldr x4, =DESC_PAGE_TABLE_DEV + lsr x5, x5, #PAGE_SHIFT + orr x4, x4, x5, lsl #PAGE_SHIFT + + /* Store the entry */ + str x4, [x1, x3, lsl #3] +#endif /* CONFIG_PL011_UART */ + + dsb nshst + + ret +ENDFUNC(_setup_fixmap) +#endif /* CONFIG_MMU */ + +ENTRY(console_init) +#ifdef CONFIG_PL011_EARLY_PRINTK + ldr x23, =CONFIG_PL011_ADDRESS + pl011_uart_init x23, 0 + PRINT("- Early printk using PL011 UART -\n") +#else + PRINT("- Early printk using Xen debug console -\n") +#endif + ret +ENDFUNC(console_init) + +/* Save state */ +.macro entry_trap + sub sp, sp, #(272 - 240) /* offset: spsr_el1 - lr */ + stp x28, x29, [sp, #-16]! + stp x26, x27, [sp, #-16]! + stp x24, x25, [sp, #-16]! + stp x22, x23, [sp, #-16]! + stp x20, x21, [sp, #-16]! + stp x18, x19, [sp, #-16]! + stp x16, x17, [sp, #-16]! + stp x14, x15, [sp, #-16]! + stp x12, x13, [sp, #-16]! + stp x10, x11, [sp, #-16]! + stp x8, x9, [sp, #-16]! + stp x6, x7, [sp, #-16]! + stp x4, x5, [sp, #-16]! + stp x2, x3, [sp, #-16]! + stp x0, x1, [sp, #-16]! + + add x21, sp, #272 /* offset: spsr_el1 */ + stp lr, x21, [sp, #240] /* offset: lr */ + mrs x21, elr_el1 + mrs x22, spsr_el1 + stp x21, x22, [sp, #256] /* offset: pc */ +.endm + +/* Restore state */ +.macro exit_trap + ldp x21, x22, [sp, #256] /* offset: pc */ + ldp x0, x1, [sp], #16 + ldp x2, x3, [sp], #16 + ldp x4, x5, [sp], #16 + ldp x6, x7, [sp], #16 + ldp x8, x9, [sp], #16 + + msr elr_el1, x21 /* set up the return data */ + msr spsr_el1, x22 + + ldp x10, x11, [sp], #16 + ldp x12, x13, [sp], #16 + ldp x14, x15, [sp], #16 + ldp x16, x17, [sp], #16 + ldp x18, x19, [sp], #16 + ldp x20, x21, [sp], #16 + ldp x22, x23, [sp], #16 + ldp x24, x25, [sp], #16 + ldp x26, x27, [sp], #16 + ldp x28, x29, [sp], #16 + + ldr lr, [sp], #32 /* offset: spsr_el1 - lr */ + eret +.endm + +/* Bad abort numbers */ +#define BAD_SYNC 0 +#define BAD_IRQ 1 +#define BAD_FIQ 2 +#define BAD_ERROR 3 + +.macro invalid, reason + mov x0, sp + mov x1, #\reason + b do_bad_mode +.endm + +el0_error_invalid: + invalid BAD_ERROR +ENDFUNC(el0_error_invalid) + +el1_sync_invalid: + invalid BAD_SYNC +ENDFUNC(el1_sync_invalid) + +el1_irq_invalid: + invalid BAD_IRQ +ENDFUNC(el1_irq_invalid) + +el1_fiq_invalid: + invalid BAD_FIQ +ENDFUNC(el1_fiq_invalid) + +el1_error_invalid: + invalid BAD_ERROR +ENDFUNC(el1_error_invalid) + +/* SYNC exception handler */ + .align 6 +el1_sync: + entry_trap + mov x0, sp + bl do_trap_sync + exit_trap +ENDFUNC(el1_sync) + +/* IRQ exception handler */ + .align 6 +el1_irq: + entry_trap + mov x0, sp + bl do_trap_irq + exit_trap +ENDFUNC(el1_irq) + +/* Exception vectors */ +.macro ventry label + .align 7 + b \label +.endm + + .align 11 +ENTRY(vector_table) + ventry el1_sync_invalid /* Synchronous EL1t */ + ventry el1_irq_invalid /* IRQ EL1t */ + ventry el1_fiq_invalid /* FIQ EL1t */ + ventry el1_error_invalid /* Error EL1t */ + + ventry el1_sync /* Synchronous EL1h */ + ventry el1_irq /* IRQ EL1h */ + ventry el1_fiq_invalid /* FIQ EL1h */ + ventry el1_error_invalid /* Error EL1h */ + + ventry el0_error_invalid /* Synchronous 64-bit EL0 */ + ventry el0_error_invalid /* IRQ 64-bit EL0 */ + ventry el0_error_invalid /* FIQ 64-bit EL0 */ + ventry el0_error_invalid /* Error 64-bit EL0 */ + + ventry el0_error_invalid /* Synchronous 32-bit EL0 */ + ventry el0_error_invalid /* IRQ 32-bit EL0 */ + ventry el0_error_invalid /* FIQ 32-bit EL0 */ + ventry el0_error_invalid /* Error 32-bit EL0 */ +ENDFUNC(vector_table) diff --git a/arch/arm/arm64/hvc.inc b/arch/arm/arm64/hvc.inc new file mode 100644 index 00000000..ac7aa3e7 --- /dev/null +++ b/arch/arm/arm64/hvc.inc @@ -0,0 +1,14 @@ +/* + * Print a string using Xen debug console + * Clobbers: x0, x1, x2, x3, x16 + */ +.macro console_puts + mov x2, x0 + mov x1, #0 +97: ldrb w3, [x2, x1] + add x1, x1, #1 + cbnz w3, 97b + mov x0, #CONSOLEIO_write + mov x16, #__HYPERVISOR_console_io + hvc #XEN_HYPERCALL_TAG +.endm diff --git a/arch/arm/arm64/hypercall.S b/arch/arm/arm64/hypercall.S new file mode 100644 index 00000000..8013c0a9 --- /dev/null +++ b/arch/arm/arm64/hypercall.S @@ -0,0 +1,33 @@ +#include +#include + +#define HYPERCALL_SIMPLE(hypercall) \ +ENTRY(hypercall_##hypercall) \ + mov x16, #__HYPERVISOR_##hypercall; \ + hvc XEN_HYPERCALL_TAG; \ + ret; \ +ENDFUNC(hypercall_##hypercall) + +#define HYPERCALL0 HYPERCALL_SIMPLE +#define HYPERCALL1 HYPERCALL_SIMPLE +#define HYPERCALL2 HYPERCALL_SIMPLE +#define HYPERCALL3 HYPERCALL_SIMPLE +#define HYPERCALL4 HYPERCALL_SIMPLE +#define HYPERCALL5 HYPERCALL_SIMPLE + +.text + +HYPERCALL2(xen_version); +HYPERCALL3(console_io); +HYPERCALL3(grant_table_op); +HYPERCALL2(sched_op); +HYPERCALL2(event_channel_op); +HYPERCALL2(hvm_op); +HYPERCALL2(memory_op); +HYPERCALL2(physdev_op); +HYPERCALL3(vcpu_op); +HYPERCALL1(tmem_op); +HYPERCALL2(multicall); +HYPERCALL2(vm_assist); +HYPERCALL1(sysctl); +HYPERCALL1(domctl); diff --git a/arch/arm/arm64/pl011.inc b/arch/arm/arm64/pl011.inc new file mode 100644 index 00000000..0fa34406 --- /dev/null +++ b/arch/arm/arm64/pl011.inc @@ -0,0 +1,50 @@ +#include + +/* + * PL011 UART initialization + * xb: register which contains the UART base address + * c: scratch register number + */ +.macro pl011_uart_init xb, c + mov x\c, #PL011_WLEN_8 + str w\c, [\xb, #PL011_UARTLCR] + ldr x\c, =(PL011_TX_ENABLE | PL011_ENABLE) + str w\c, [\xb, #PL011_UARTCR] +.endm + +/* + * PL011 UART wait UART to be ready to transmit + * xb: register which contains the UART base address + * c: scratch register number + */ +.macro pl011_uart_ready xb, c +80: ldrh w\c, [\xb, #PL011_UARTFR] + tst w\c, #PL011_FR_BUSY /* Check BUSY bit */ + b.ne 80b /* Wait for the UART to be ready */ +.endm + +/* + * PL011 UART transmit character + * xb: register which contains the UART base address + * wt: register which contains the character to transmit + */ +.macro pl011_uart_transmit xb, wt + strb \wt, [\xb] +.endm + +/* + * PL011 UART transmit string + * Clobbers: x1 + */ +.macro console_puts +81: + pl011_uart_ready x23, 1 + ldrb w1, [x0], #1 + cbz w1, 82f + pl011_uart_transmit x23, w1 + b 81b +82: + /* Send carriage return at the end */ + mov w1, 0x0D + pl011_uart_transmit x23, w1 +.endm diff --git a/arch/arm/decode.c b/arch/arm/decode.c new file mode 100644 index 00000000..9a9b132a --- /dev/null +++ b/arch/arm/decode.c @@ -0,0 +1,24 @@ +/** + * @file arch/arm/decode.c + * + * Helper routines for decoding arm architectural state. + */ +#include +#include + +bool arch_fmt_pointer( + char **str_ptr, char *end, const char **fmt_ptr, const void *arg, + int width, int precision, unsigned int flags) +{ + return false; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/arm32/regs.h b/arch/arm/include/arch/arm32/regs.h new file mode 100644 index 00000000..f371bc76 --- /dev/null +++ b/arch/arm/include/arch/arm32/regs.h @@ -0,0 +1,71 @@ +/** + * @file arch/arm/include/arch/arm32/regs.h + * + * arm32 CPU user registers. + */ +#ifndef XTF_ARM32_REGS_H +#define XTF_ARM32_REGS_H + +#include + +#ifndef __ASSEMBLY__ +struct cpu_regs +{ + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + union { + uint32_t r11; + uint32_t fp; + }; + uint32_t r12; + uint32_t sp; + + union { + uint32_t lr; + uint32_t lr_usr; + }; + + union { + uint32_t pc, pc32; + }; + + uint32_t cpsr; + uint32_t hsr; + + uint32_t sp_usr; + + uint32_t sp_irq, lr_irq; + uint32_t sp_svc, lr_svc; + uint32_t sp_abt, lr_abt; + uint32_t sp_und, lr_und; + + uint32_t r8_fiq, r9_fiq, r10_fiq, r11_fiq, r12_fiq; + uint32_t sp_fiq, lr_fiq; + + uint32_t spsr_svc, spsr_abt, spsr_und, spsr_irq, spsr_fiq; + + /* The stack should be 8-byte aligned */ + uint32_t pad1; +}; +#endif /* __ASSEMBLY__ */ + +#endif /* XTF_ARM32_REGS_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/arm32/system.h b/arch/arm/include/arch/arm32/system.h new file mode 100644 index 00000000..82c12d64 --- /dev/null +++ b/arch/arm/include/arch/arm32/system.h @@ -0,0 +1,20 @@ +/** + * @file arch/arm/include/arch/arm32/system.h + */ +#ifndef XTF_ARM32_SYSTEM_H +#define XTF_ARM32_SYSTEM_H + +#define local_irq_disable() asm volatile ( "cpsid i\n" : : : "cc" ) +#define local_irq_enable() asm volatile ( "cpsie i\n" : : : "cc" ) + +#endif /* XTF_ARM32_SYSTEM_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/arm64/regs.h b/arch/arm/include/arch/arm64/regs.h new file mode 100644 index 00000000..4f2216e2 --- /dev/null +++ b/arch/arm/include/arch/arm64/regs.h @@ -0,0 +1,100 @@ +/** + * @file arch/arm/include/arch/arm64/regs.h + * + * arm64 CPU user registers. + */ +#ifndef XTF_ARM64_REGS_H +#define XTF_ARM64_REGS_H + +#include + +#ifndef __ASSEMBLY__ +/* Anonymous union includes both 32- and 64-bit names (e.g., r0/x0). */ +#define __DECL_REG(n64, n32) union { \ + uint64_t n64; \ + uint32_t n32; \ +} + +struct cpu_regs +{ + /* + * The mapping AArch64 <-> AArch32 is based on D1.20.1 in ARM DDI + * 0487A.d. + * + * AArch64 AArch32 + */ + __DECL_REG(x0, r0); + __DECL_REG(x1, r1); + __DECL_REG(x2, r2); + __DECL_REG(x3, r3); + __DECL_REG(x4, r4); + __DECL_REG(x5, r5); + __DECL_REG(x6, r6); + __DECL_REG(x7, r7); + __DECL_REG(x8, r8); + __DECL_REG(x9, r9); + __DECL_REG(x10, r10); + __DECL_REG(x11 , r11); + __DECL_REG(x12, r12); + + __DECL_REG(x13, sp_usr); + __DECL_REG(x14, lr_usr); + + __DECL_REG(x15, __unused_sp_hyp); + + __DECL_REG(x16, lr_irq); + __DECL_REG(x17, sp_irq); + + __DECL_REG(x18, lr_svc); + __DECL_REG(x19, sp_svc); + + __DECL_REG(x20, lr_abt); + __DECL_REG(x21, sp_abt); + + __DECL_REG(x22, lr_und); + __DECL_REG(x23, sp_und); + + __DECL_REG(x24, r8_fiq); + __DECL_REG(x25, r9_fiq); + __DECL_REG(x26, r10_fiq); + __DECL_REG(x27, r11_fiq); + __DECL_REG(x28, r12_fiq); + __DECL_REG(/* x29 */ fp, /* r13_fiq */ sp_fiq); + + __DECL_REG(/* x30 */ lr, /* r14_fiq */ lr_fiq); + + uint64_t sp; + + /* Return address and mode */ + __DECL_REG(pc, pc32); + uint64_t cpsr; + uint64_t hsr; + + /* The kernel frame should be 16-byte aligned. */ + uint64_t pad0; + + union { + uint64_t spsr_el1; /* AArch64 */ + uint64_t spsr_svc; /* AArch32 */ + }; + + /* AArch32 guests only */ + uint32_t spsr_fiq, spsr_irq, spsr_und, spsr_abt; + + /* AArch64 guests only */ + uint64_t sp_el0; + uint64_t sp_el1, elr_el1; +}; +#endif /* __ASSEMBLY__ */ + +#endif /* XTF_ARM64_REGS_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/arm64/system.h b/arch/arm/include/arch/arm64/system.h new file mode 100644 index 00000000..e758ca98 --- /dev/null +++ b/arch/arm/include/arch/arm64/system.h @@ -0,0 +1,20 @@ +/** + * @file arch/arm/include/arch/arm64/system.h + */ +#ifndef XTF_ARM64_SYSTEM_H +#define XTF_ARM64_SYSTEM_H + +#define local_irq_disable() asm volatile ( "msr daifset, #2\n" ::: "memory" ) +#define local_irq_enable() asm volatile ( "msr daifclr, #2\n" ::: "memory" ) + +#endif /* XTF_ARM64_SYSTEM_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/asm_macros.h b/arch/arm/include/arch/asm_macros.h new file mode 100644 index 00000000..39e1d163 --- /dev/null +++ b/arch/arm/include/arch/asm_macros.h @@ -0,0 +1,21 @@ +/** + * @file arch/arm/include/arch/asm_macros.h + * + * Macros for use in arm assembly files. + */ +#ifndef XTF_ARM_ASM_MACROS_H +#define XTF_ARM_ASM_MACROS_H + +#define ALIGN .align 2 + +#endif /* XTF_ARM_ASM_MACROS_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/barrier.h b/arch/arm/include/arch/barrier.h new file mode 100644 index 00000000..b84c922b --- /dev/null +++ b/arch/arm/include/arch/barrier.h @@ -0,0 +1,41 @@ +/** + * @file arch/arm/include/arch/barrier.h + * + * arm memory barriers. + */ +#ifndef XTF_ARM_BARRIER_H +#define XTF_ARM_BARRIER_H + +#include + +#define isb() __asm__ __volatile__ ("isb" : : : "memory") +#define dsb(scope) __asm__ __volatile__ ("dsb " #scope : : : "memory") +#define dmb(scope) __asm__ __volatile__ ("dmb " #scope : : : "memory") + +#define mb() dsb(sy) +#ifdef CONFIG_ARM_64 +#define rmb() dsb(ld) +#else +#define rmb() dsb(sy) +#endif +#define wmb() dsb(st) + +#define smp_mb() dmb(ish) +#ifdef CONFIG_ARM_64 +#define smp_rmb() dmb(ishld) +#else +#define smp_rmb() dmb(ish) +#endif +#define smp_wmb() dmb(ishst) + +#endif /* XTF_ARM_BARRIER_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/bitops.h b/arch/arm/include/arch/bitops.h new file mode 100644 index 00000000..524b9f7c --- /dev/null +++ b/arch/arm/include/arch/bitops.h @@ -0,0 +1,45 @@ +/** + * @file arch/arm/include/arch/bitops.h + * + * Low level bit operations. + */ +#ifndef XTF_ARM_BITOPS_H +#define XTF_ARM_BITOPS_H + +#include + +static inline bool test_bit(unsigned int bit, const void *addr) +{ + UNIMPLEMENTED(); + return false; +} + +static inline bool test_and_set_bit(unsigned int bit, volatile void *addr) +{ + UNIMPLEMENTED(); + return false; +} + +static inline bool test_and_change_bit(unsigned int bit, volatile void *addr) +{ + UNIMPLEMENTED(); + return false; +} + +static inline bool test_and_clear_bit(unsigned int bit, volatile void *addr) +{ + UNIMPLEMENTED(); + return false; +} + +#endif /* XTF_ARM_BITOPS_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/config.h b/arch/arm/include/arch/config.h new file mode 100644 index 00000000..69e583ff --- /dev/null +++ b/arch/arm/include/arch/config.h @@ -0,0 +1,55 @@ +/** + * @file arch/arm/include/arch/config.h + * + * A Linux-style configuration list. + */ +#ifndef XTF_ARM_CONFIG_H +#define XTF_ARM_CONFIG_H + +#include + +#if defined(CONFIG_ENV_64le) +#define CONFIG_ARM_64 1 +#define CONFIG_64BIT 1 +#define CONFIG_LE 1 +#define ENVIRONMENT_DESCRIPTION "ARM64 LE" +#elif defined(CONFIG_ENV_mmu64le) +#define CONFIG_ARM_64 1 +#define CONFIG_64BIT 1 +#define CONFIG_LE 1 +#define CONFIG_MMU 1 +#define ENVIRONMENT_DESCRIPTION "ARM64 LE MMU" +#elif defined(CONFIG_ENV_32le) +#define CONFIG_ARM_32 1 +#define CONFIG_32BIT 1 +#define CONFIG_LE 1 +#define ENVIRONMENT_DESCRIPTION "ARM32 LE" +#else +#error "Bad environment" +#endif + +/* + * On MMU less system, when using XTF as dom0 we need to know the load address + * as it may differ depending on the target. Allow specifying the load address + * on the command line when invoking make using: + * CONFIG_LOAD_ADDRESS=
+ */ +#if defined(CONFIG_LOAD_ADDRESS) && !defined(CONFIG_MMU) +#define XTF_VIRT_START CONFIG_LOAD_ADDRESS +#elif defined(CONFIG_MMU) +#define XTF_VIRT_START VA_START +#else +#define XTF_VIRT_START 0x40000000 +#endif + +#endif /* XTF_ARM_CONFIG_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/desc.h b/arch/arm/include/arch/desc.h new file mode 100644 index 00000000..f4ea8b31 --- /dev/null +++ b/arch/arm/include/arch/desc.h @@ -0,0 +1,16 @@ +/** + * @file arch/arm/include/arch/desc.h + */ +#ifndef XTF_ARM_DESC_H +#define XTF_ARM_DESC_H + +#endif /* XTF_ARM_DESC_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/div.h b/arch/arm/include/arch/div.h new file mode 100644 index 00000000..d66ba7d2 --- /dev/null +++ b/arch/arm/include/arch/div.h @@ -0,0 +1,35 @@ +/** + * @file arch/arm/include/arch/div.h + */ +#ifndef XTF_ARM_DIV_H +#define XTF_ARM_DIV_H + +#include + +/* + * Divide a 64bit number by 32bit divisor without software support. + * + * The dividend is modified in place, and the modulus is returned. + */ +static inline uint32_t divmod64(uint64_t *dividend, uint32_t divisor) +{ +#ifdef CONFIG_ARM_64 + uint32_t remainder = *dividend % divisor; + *dividend = *dividend / divisor; + return remainder; +#else + UNIMPLEMENTED(); +#endif +} + +#endif /* XTF_ARM_DIV_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/extable.h b/arch/arm/include/arch/extable.h new file mode 100644 index 00000000..9560b962 --- /dev/null +++ b/arch/arm/include/arch/extable.h @@ -0,0 +1,19 @@ +/** + * @file arch/arm/include/arch/extable.h + * + * Common arm exception table helper functions. + */ +#ifndef XTF_ARM64_EXTABLE_H +#define XTF_ARM64_EXTABLE_H + +#endif /* XTF_ARM_EXTABLE_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/hypercall.h b/arch/arm/include/arch/hypercall.h new file mode 100644 index 00000000..626f8a67 --- /dev/null +++ b/arch/arm/include/arch/hypercall.h @@ -0,0 +1,44 @@ +/** + * @file arch/arm/include/arch/hypercall.h + * + * Hypercall primitives for arm. + */ +#ifndef XTF_ARM_HYPERCALL_H +#define XTF_ARM_HYPERCALL_H + +#include +#include +#include +#include + +int hypercall_memory_op(unsigned int cmd, void *arg); +int hypercall_domctl(unsigned long op); +int hypercall_sched_op(int cmd, void *arg); +int hypercall_console_io(int cmd, int count, char *str); +int hypercall_xen_version(int cmd, void *arg); +int hypercall_event_channel_op(int cmd, void *op); +int hypercall_physdev_op(void *physdev_op); +int hypercall_sysctl(xen_sysctl_t *arg); +int hypercall_hvm_op(unsigned long op, void *arg); +int hypercall_grant_table_op(unsigned int cmd, void *uop, unsigned int count); +int hypercall_vcpu_op(int cmd, int vcpuid, void *extra_args); + +/* + * Higher level hypercall helpers + */ +static inline void hypercall_console_write(const char *buf, size_t count) +{ + (void)hypercall_console_io(CONSOLEIO_write, count, (char *)buf); +} + +#endif /* XTF_ARM_HYPERCALL_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/mm.h b/arch/arm/include/arch/mm.h new file mode 100644 index 00000000..03698d56 --- /dev/null +++ b/arch/arm/include/arch/mm.h @@ -0,0 +1,119 @@ +/** + * @file arch/arm/include/arch/mm.h + * + * Memory management on arm. + */ +#ifndef XTF_ARM_MM_H +#define XTF_ARM_MM_H + +#include +#include + +/* + * Granularity: 4KB + * VA width: 39bit + * Tables: L1, L2, L3(fixmap) + */ +#define VA_WIDTH 39 +#define SZ_2M 0x200000 +#define VA_LIMIT 0xFFFFFFFFFFFFFFFF +#define VA_START (VA_LIMIT << VA_WIDTH) +#define PAGE_OFFSET (VA_LIMIT << (VA_WIDTH - 1)) +#define TABLE_ENTRIES 512 +#define TABLE_ADDR_MASK (TABLE_ENTRIES -1) +#define FIXMAP_ADDR(n) (VA_START + SZ_2M + n * PAGE_SIZE) + +/* + * L1 translation table + * 1 entry = 1GB + */ +#define L1_TABLE_SHIFT 30 +#define L1_TABLE_SIZE (1 << L1_TABLE_SHIFT) +#define L1_TABLE_OFFSET (L1_TABLE_SIZE - 1) +#define L1_TABLE_INDEX(x) ((x >> L1_TABLE_SHIFT) & TABLE_ADDR_MASK) + +/* + * L2 translation table + * 1 entry = 2MB + */ +#define L2_TABLE_SHIFT 21 +#define L2_TABLE_SIZE (1 << L2_TABLE_SHIFT) +#define L2_TABLE_OFFSET (L2_TABLE_SIZE - 1) +#define L2_TABLE_INDEX(x) ((x >> L2_TABLE_SHIFT) & TABLE_ADDR_MASK) + +/* + * L3 translation table + * 1 entry = 4KB + */ +#define L3_TABLE_SHIFT PAGE_SHIFT +#define L3_TABLE_SIZE (1 << L3_TABLE_SHIFT) +#define L3_TABLE_OFFSET (L3_TABLE_SIZE - 1) +#define L3_TABLE_INDEX(x) ((x >> L3_TABLE_SHIFT) & TABLE_ADDR_MASK) + +/* Fixmap slots */ +#define FIXMAP_UART 0 +#define FIXMAP_PV_CONSOLE 1 + +/* Descriptors */ +#define DESCR_BAD 0x0 +#define DESCR_VALID 0x1 +#define DESC_TYPE_TABLE (0x1 << 1) +#define DESC_TYPE_BLOCK (0x0 << 1) +#define DESC_MAIR_INDEX(x) (x << 2) +#define DESC_NS(x) (x << 5) +#define DESC_AP(x) (x << 6) +#define DESC_SH(x) (x << 8) +#define DESC_AF(x) (x << 10) +#define DESC_PXN(x) (x << 53) +#define DESC_UXN(x) (x << 54) + +#define DESC_PAGE_TABLE (DESCR_VALID | DESC_TYPE_TABLE) + +#define DESC_PAGE_BLOCK (DESCR_VALID | DESC_TYPE_BLOCK |\ + DESC_MAIR_INDEX(MT_NORMAL) |\ + DESC_AF(0x1) | DESC_SH(0x3)) + +#define DESC_PAGE_TABLE_DEV (DESCR_VALID | DESC_TYPE_TABLE |\ + DESC_MAIR_INDEX(MT_DEVICE_nGnRnE) |\ + DESC_AF(0x1) | DESC_SH(0x3)) + +#ifndef __ASSEMBLY__ +typedef uint64_t paddr_t; +extern paddr_t phys_offset; + +/* + * PFN - physical frame number + * MFN - machine frame number + * PO - physical offset + * PA - physical address + * VA - virtual address + * + * PA = PO + VA + * VA = PA - PO + */ +#define phys(x) ((paddr_t)(x) + phys_offset) +#define virt(x) (void *)(((x) - phys_offset) +#define pfn_to_phys(x) ((paddr_t)(x) << PAGE_SHIFT) +#define phys_to_pfn(x) ((unsigned long)((x) >> PAGE_SHIFT)) +#define mfn_to_virt(x) (virt(pfn_to_phys(x))) +#define virt_to_mfn(x) (phys_to_pfn(phys(x))) +#define pfn_to_virt(x) (virt(pfn_to_phys(x))) +#define virt_to_pfn(x) (phys_to_pfn(phys(x))) + +void store_pgt_entry(uint64_t *addr, uint64_t val); +uint64_t set_fixmap(uint8_t slot, paddr_t pa, uint64_t flags); +void setup_mm(paddr_t boot_phys_offset); + +#endif /* __ASSEMBLY__ */ + +#endif /* XTF_ARM_MM_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/page.h b/arch/arm/include/arch/page.h new file mode 100644 index 00000000..9c4291e0 --- /dev/null +++ b/arch/arm/include/arch/page.h @@ -0,0 +1,82 @@ +/** + * @file arch/arm/include/arch/page.h + */ +#ifndef XTF_ARM_PAGE_H +#define XTF_ARM_PAGE_H + +#include + +/* 4kB pages */ +#define PAGE_SHIFT 12 +#define PAGE_SIZE (_AC(1, L) << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) + +#define STACK_ORDER 2 +#define STACK_SIZE (PAGE_SIZE << STACK_ORDER) + +/* Attribute Indexes */ +#define MT_DEVICE_nGnRnE 0x0 +#define MT_NORMAL_NC 0x1 +#define MT_NORMAL_WT 0x2 +#define MT_NORMAL_WB 0x3 +#define MT_DEVICE_nGnRE 0x4 +#define MT_NORMAL 0x7 + +/* LPAE Memory region attributes */ +#define MAIR0(attr, mt) ((attr) << ((mt) * 8)) +#define MAIR1(attr, mt) ((attr) << (((mt) * 8) - 32)) + +#define MAIR0VAL (MAIR0(0x00, MT_DEVICE_nGnRnE)| \ + MAIR0(0x44, MT_NORMAL_NC) | \ + MAIR0(0xaa, MT_NORMAL_WT) | \ + MAIR0(0xee, MT_NORMAL_WB)) + +#define MAIR1VAL (MAIR1(0x04, MT_DEVICE_nGnRE) | \ + MAIR1(0xff, MT_NORMAL)) + +#define MAIRVAL (MAIR1VAL << 32 | MAIR0VAL) + +/* SCTLR_EL1 */ +#define SCTLR_M (1 << 0) +#define SCTLR_C (1 << 2) + +/* TCR_EL1 */ +#define TCR_T0SZ ((64 - VA_WIDTH) << 0) +#define TCR_T1SZ ((64 - VA_WIDTH) << 16) + +/* ASID - 16bit */ +#define TCR_AS (0x1 << 36) + +/* 4K granularity */ +#define TCR_TG0_4K (0x0 << 14) +#define TCR_TG1_4K (0x2 << 30) + +/* Normal memory, In/Out Write-Back Read-Allocate Write-Allocate Cacheable */ +#define TCR_IRGN0 (0x1 << 8) +#define TCR_IRGN1 (0x1 << 24) +#define TCR_ORGN0 (0x1 << 10) +#define TCR_ORGN1 (0x1 << 26) + +/* Inner shareable */ +#define TCR_SH0_IS (0x3 << 12) +#define TCR_SH1_IS (0x3 << 28) + +/* Disable walks from the lower/upper region */ +#define TCR_EPD0 (0x1 << 7) +#define TCR_EPD1 (0x1 << 23) + +#define TCRVAL (TCR_T1SZ | TCR_T0SZ | TCR_TG1_4K | TCR_TG0_4K |\ + TCR_IRGN1 | TCR_ORGN1 | TCR_IRGN0 | TCR_IRGN0 |\ + TCR_SH1_IS | TCR_SH0_IS | TCR_AS) + +#endif /* XTF_ARM_PAGE_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/pl011.h b/arch/arm/include/arch/pl011.h new file mode 100644 index 00000000..805aa4c1 --- /dev/null +++ b/arch/arm/include/arch/pl011.h @@ -0,0 +1,65 @@ +/** + * @file arch/arm/include/arch/pl011.h + * + * ARM PrimeCell UART PL011. + */ +#ifndef XTF_ARM_PL011_H +#define XTF_ARM_PL011_H + +#include +#include +#include + +#ifdef CONFIG_MMU +#define PL011_EARLY_VA FIXMAP_ADDR(FIXMAP_UART) +#define PL011_REG(reg) (volatile void *)(PL011_EARLY_VA + reg) +#else +#define PL011_REG(reg) (volatile void *)(CONFIG_PL011_ADDRESS + reg) +#endif + +/* UART register offsets */ +#define PL011_UARTDR 0x00 /* Data register. */ +#define PL011_UARTRSR 0x04 /* Receive status register (Read). */ +#define PL011_UARTECR 0x04 /* Error clear register (Write). */ +#define PL011_UARTFR 0x18 /* Flag register (Read only). */ +#define PL011_UARTILPR 0x20 /* IrDA low power counter register. */ +#define PL011_UARTIBRD 0x24 /* Integer baud rate divisor register. */ +#define PL011_UARTFBRD 0x28 /* Fractional baud rate divisor register. */ +#define PL011_UARTLCR 0x2C /* Line control register. */ +#define PL011_UARTCR 0x30 /* Control register. */ +#define PL011_UARTIFLS 0x34 /* Interrupt fifo level select. */ +#define PL011_UARTIMSC 0x38 /* Interrupt mask. */ +#define PL011_UARTRIS 0x3C /* Raw interrupt status. */ +#define PL011_UARTMIS 0x40 /* Masked interrupt status. */ +#define PL011_UARTICR 0x44 /* Interrupt clear register. */ +#define PL011_UARTDMACR 0x48 /* DMA control register. */ + +/* UARTFR bits */ +#define PL011_FR_BUSY (1 << 3) /* Transmit is not complete. */ + +/* UARTCR bits */ +#define PL011_ENABLE (1 << 0) /* UART enable. */ +#define PL011_TX_ENABLE (1 << 8) /* Transmit enable. */ + +/* UARTLCR bits */ +#define PL011_WLEN_8 (3 << 5) /* 8bits word length. */ +#define PL011_PEN (1 << 1) /* Parity enable. */ + +#ifndef __ASSEMBLY__ +void pl011_init(void); +void pl011_console_write(const char *buf, size_t len); +void pl011_putc(char c); +void pl011_puts(const char *s, size_t len); +#endif + +#endif /* XTF_ARM_PL011_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/regs.h b/arch/arm/include/arch/regs.h new file mode 100644 index 00000000..b2f1aa8a --- /dev/null +++ b/arch/arm/include/arch/regs.h @@ -0,0 +1,25 @@ +/** + * @file arch/arm/include/arch/regs.h + * + * arm CPU user registers. + */ +#ifndef XTF_ARM_REGS_H +#define XTF_ARM_REGS_H + +#ifdef CONFIG_ARM_64 +#include +#else +#include +#endif + +#endif /* XTF_ARM_REGS_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/system.h b/arch/arm/include/arch/system.h new file mode 100644 index 00000000..3c39d1b3 --- /dev/null +++ b/arch/arm/include/arch/system.h @@ -0,0 +1,23 @@ +/** + * @file arch/arm/include/arch/system.h + */ +#ifndef XTF_ARM_SYSTEM_H +#define XTF_ARM_SYSTEM_H + +#ifdef CONFIG_ARM_64 +#include +#else +#include +#endif + +#endif /* XTF_ARM_SYSTEM_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/traps.h b/arch/arm/include/arch/traps.h new file mode 100644 index 00000000..8c420642 --- /dev/null +++ b/arch/arm/include/arch/traps.h @@ -0,0 +1,22 @@ +/** + * @file arch/arm/include/arch/traps.h + */ +#ifndef XTF_ARM_TRAPS_H +#define XTF_ARM_TRAPS_H + +#include +#include + +void __noreturn arch_crash_hard(void); + +#endif /* XTF_ARM_TRAPS_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/include/arch/xtf.h b/arch/arm/include/arch/xtf.h new file mode 100644 index 00000000..7b256170 --- /dev/null +++ b/arch/arm/include/arch/xtf.h @@ -0,0 +1,17 @@ +/** + * @file arch/arm/include/arch/xtf.h + */ +#ifndef XTF_ARM_XTF_H +#define XTF_ARM_XTF_H + +#endif /* XTF_ARM_XTF_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/link.lds.S b/arch/arm/link.lds.S new file mode 100644 index 00000000..3160cf13 --- /dev/null +++ b/arch/arm/link.lds.S @@ -0,0 +1,58 @@ +#include + +#if defined(__arm__) +OUTPUT_ARCH(arm) +OUTPUT_FORMAT("elf32-littlearm") +#elif defined(__aarch64__) +OUTPUT_ARCH(aarch64) +OUTPUT_FORMAT("elf64-littleaarch64") +#endif + +ENTRY(_start) + +SECTIONS +{ + . = XTF_VIRT_START; + _text = .; + + .text : { + *(.text) + } + + . = ALIGN(PAGE_SIZE); + + .data : { + *(.data) + + . = ALIGN(PAGE_SIZE); + *(.data.page_aligned) + } + + . = ALIGN(PAGE_SIZE); + + .rodata : { + *(.rodata) + *(.rodata.*) + } + + . = ALIGN(PAGE_SIZE); + + .bss : { + __start_bss = .; + *(.bss) + + . = ALIGN(PAGE_SIZE); + *(.bss.page_aligned) + + __end_bss = .; + } + + _end = .; + + /* + * It is possible for a GNU linker to add a .note.gnu.build-id section + * before .text which causes zimage header to be shifted resulting in + * a bad magic. Discard this section to prevent errors. + */ + /DISCARD/ : { *(.note.gnu.build-id) } +} diff --git a/arch/arm/mm.c b/arch/arm/mm.c new file mode 100644 index 00000000..b52fcf65 --- /dev/null +++ b/arch/arm/mm.c @@ -0,0 +1,54 @@ +/** + * @file arch/arm/mm.c + * + * Memory management on arm. + */ + +#include +#include +#include + +paddr_t phys_offset; + +/* + * Static boot page tables used before BSS is zeroed. + * Make boot page tables part of the loaded image by putting them inside + * ".data.page_aligned" so that they are zeroed when loading image into memory. + */ +uint64_t __aligned(PAGE_SIZE) __section(".data.page_aligned") l1_bpgtable[512]; +uint64_t __aligned(PAGE_SIZE) __section(".data.page_aligned") l2_bpgtable[512]; +uint64_t __aligned(PAGE_SIZE) __section(".data.page_aligned") l1_idmap[512]; +uint64_t __aligned(PAGE_SIZE) __section(".data.page_aligned") fix_pgtable[512]; + +void store_pgt_entry(uint64_t *addr, uint64_t val) +{ + *addr = val; + dsb(ishst); + isb(); +} + +/* Map a 4k page in a fixmap entry */ +uint64_t set_fixmap(uint8_t slot, paddr_t pa, uint64_t flags) +{ + unsigned int index; + + index = L3_TABLE_INDEX(FIXMAP_ADDR(slot)); + store_pgt_entry(&fix_pgtable[index], ((pa & ~(L3_TABLE_SIZE - 1)) | flags)); + + return (uint64_t)(FIXMAP_ADDR(slot) + (pa & PAGE_OFFSET)); +} + +void setup_mm(paddr_t boot_phys_offset) +{ + phys_offset = boot_phys_offset; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/pl011.c b/arch/arm/pl011.c new file mode 100644 index 00000000..8a4b8333 --- /dev/null +++ b/arch/arm/pl011.c @@ -0,0 +1,71 @@ +/** + * @file arch/arm/pl011.c + * + * ARM PrimeCell UART PL011. + */ +#include +#include + +static inline uint32_t pl011_read(const volatile void *addr) +{ + uint32_t val; +#ifdef CONFIG_ARM_64 + asm volatile("ldr %w0, [%1]\n" : "=r" (val) : "r" (addr)); +#else + asm volatile("ldr %1, %0\n": "+Qo" (*(volatile uint32_t*)addr), "=r" (val)); +#endif + rmb(); + return val; +} + +static inline void pl011_write(uint32_t val, volatile void *addr) +{ + wmb(); +#ifdef CONFIG_ARM_64 + asm volatile("str %w0, [%1]\n" : : "r" (val), "r" (addr)); +#else + asm volatile("str %1, %0\n": "+Qo" (*(volatile uint32_t*)addr) : "r" (val)); +#endif +} + +void pl011_putc(char c) +{ + uint32_t busy; + do { + busy = pl011_read(PL011_REG(PL011_UARTFR)); + } while(busy & PL011_FR_BUSY); + + pl011_write((uint32_t)(unsigned char)c, PL011_REG(PL011_UARTDR)); +} + +void pl011_puts(const char *s, size_t len) +{ + for(; len > 0; len--, s++) + { + char c = *s; + pl011_putc(c); + } +} + +void pl011_init(void) +{ + /* 8-N-1 */ + pl011_write(PL011_WLEN_8, PL011_REG(PL011_UARTLCR)); + /* Enable UART TX */ + pl011_write((PL011_TX_ENABLE | PL011_ENABLE), PL011_REG(PL011_UARTCR)); +} + +void pl011_console_write(const char *buf, size_t len) +{ + pl011_puts(buf, len); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/setup.c b/arch/arm/setup.c new file mode 100644 index 00000000..1d9d32fd --- /dev/null +++ b/arch/arm/setup.c @@ -0,0 +1,95 @@ +/** + * @file arch/arm/setup.c + * + * Early bringup code for arm. + */ +#include +#include +#include +#include + +const char environment_description[] = ENVIRONMENT_DESCRIPTION; + +/* Structure to store boot arguments */ +struct init_data +{ + uint64_t phys_offset; + void *fdt; +} boot_data; + +static void setup_console(void) +{ +#ifdef CONFIG_PL011_UART +#ifndef CONFIG_PL011_EARLY_PRINTK + /* Initialize UART */ + pl011_init(); +#endif + /* Use PL011 UART to print messages */ + register_console_callback(pl011_console_write); +#else + /* Use Xen console to print messages */ + register_console_callback(hypercall_console_write); +#endif +} + +#ifdef CONFIG_MMU +static void setup_pv_console(void) +{ + xencons_interface_t *cons_ring; + evtchn_port_t cons_evtchn; + uint64_t raw_ev = 0, raw_pfn = 0, phys, pfn; + + if (hvm_get_param(HVM_PARAM_CONSOLE_EVTCHN, &raw_ev) != 0 || + hvm_get_param(HVM_PARAM_CONSOLE_PFN, &raw_pfn) != 0) + return; + + cons_evtchn = raw_ev; + phys = pfn_to_phys(raw_pfn); + pfn = set_fixmap(FIXMAP_PV_CONSOLE, phys, DESC_PAGE_TABLE_DEV); + cons_ring = (xencons_interface_t *)pfn; + + init_pv_console(cons_ring, cons_evtchn); +} + +static bool is_initdomain(void) +{ + xen_feature_info_t fi; + int ret; + + fi.submap_idx = 0; + ret = hypercall_xen_version(XENVER_get_features, &fi); + + if (ret) + panic("Failed to obtain Xen features. ret=%d\n", ret); + + if (fi.submap & (1 << XENFEAT_dom0)) + return true; + + return false; +} +#endif + +void arch_setup(void) +{ + setup_console(); +#ifdef CONFIG_MMU + setup_mm(boot_data.phys_offset); + if (!is_initdomain()) + setup_pv_console(); +#endif +} + +void test_setup(void) +{ + /* Nothing to be done here for now */ +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/arm/traps.c b/arch/arm/traps.c new file mode 100644 index 00000000..95550dc8 --- /dev/null +++ b/arch/arm/traps.c @@ -0,0 +1,116 @@ +/** + * @file arch/arm/traps.c + * + * Arm trap handlers. + */ +#include +#include +#include +#include +#include + +static const char *handler[]= { + "Synchronous Abort", + "IRQ", + "FIQ", + "Error" +}; + +void __noreturn arch_crash_hard(void) +{ + /* Sit in the infinite loop */ + while (1); + unreachable(); +} + +#ifdef CONFIG_ARM_64 +static void show_registers64(struct cpu_regs *regs) +{ + printk(" PC: 0x%016lx\n", regs->pc); + printk(" LR: 0x%016lx\n", regs->lr); + printk(" CPSR: 0x%016lx\n", regs->cpsr); + printk(" SP: 0x%016lx\n", regs->sp); + printk(" X0: 0x%016lx\t X1: 0x%016lx\tX2: 0x%016lx\n", + regs->x0, regs->x1, regs->x2); + printk(" X3: 0x%016lx\t X4: 0x%016lx\tX5: 0x%016lx\n", + regs->x3, regs->x4, regs->x5); + printk(" X6: 0x%016lx\t X7: 0x%016lx\tX8: 0x%016lx\n", + regs->x6, regs->x7, regs->x8); + printk(" X9: 0x%016lx\tX10: 0x%016lx\tX11: 0x%016lx\n", + regs->x9, regs->x10, regs->x11); + printk("X12: 0x%016lx\tX13: 0x%016lx\tX14: 0x%016lx\n", + regs->x12, regs->x13, regs->x14); + printk("X15: 0x%016lx\tX16: 0x%016lx\tX17: 0x%016lx\n", + regs->x15, regs->x16, regs->x17); + printk("X18: 0x%016lx\tX19: 0x%016lx\tX20: 0x%016lx\n", + regs->x18, regs->x19, regs->x20); + printk("X21: 0x%016lx\tX22: 0x%016lx\tX23: 0x%016lx\n", + regs->x21, regs->x22, regs->x23); + printk("X24: 0x%016lx\tX25: 0x%016lx\tX26: 0x%016lx\n", + regs->x24, regs->x25, regs->x26); + printk("X27: 0x%016lx\tX28: 0x%016lx\tFP: 0x%016lx\n", + regs->x27, regs->x28, regs->fp); +} +#else +static void show_registers32(struct cpu_regs *regs) +{ + printk(" PC: 0x%08x\n", regs->pc); + printk(" CPSR: 0x%08x\n", regs->cpsr); + printk(" R0: 0x%08x\t R1: 0x%08x\tR2: 0x%08x\n", + regs->r0, regs->r1, regs->r2); + printk(" R3: 0x%08x\t R4: 0x%08x\tR5: 0x%08x\n", + regs->r3, regs->r4, regs->r5); + printk(" R6: 0x%08x\t R7: 0x%08x\tR8: 0x%08x\n", + regs->r6, regs->r7, regs->r8); + printk(" R9: 0x%08x\tR10: 0x%08x\tR11: 0x%08x\n", + regs->r9, regs->r10, regs->fp); + printk("R12: 0x%08x\n", regs->r12); +} +#endif + +static void show_registers(struct cpu_regs *regs) +{ +#ifdef CONFIG_ARM_64 + show_registers64(regs); +#else + show_registers32(regs); +#endif +} + +/* + * Impossible case in the exception vector + */ +void do_bad_mode(struct cpu_regs *regs, int reason) +{ + printk("---Bad mode detected in \"%s\" handler---\n", handler[reason]); + local_irq_disable(); + panic("Bad mode\n"); +} + +/* + * Synchronous exception received + */ +void do_trap_sync(struct cpu_regs *regs) +{ + printk("---Trap sync:---\n"); + show_registers(regs); + panic("Trap sync\n"); +} + +/* + * IRQ received + */ +void do_trap_irq(struct cpu_regs *regs) +{ + UNIMPLEMENTED(); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/x86/include/arch/hypercall.h b/arch/x86/include/arch/hypercall.h new file mode 100644 index 00000000..e0302f4c --- /dev/null +++ b/arch/x86/include/arch/hypercall.h @@ -0,0 +1,185 @@ +#ifndef XTF_X86_HYPERCALL_H +#define XTF_X86_HYPERCALL_H + +#include +#include +#include +#include + +#if defined(__x86_64__) + +# include +# define HYPERCALL1 _hypercall64_1 +# define HYPERCALL2 _hypercall64_2 +# define HYPERCALL3 _hypercall64_3 +# define HYPERCALL4 _hypercall64_4 +# define HYPERCALL5 _hypercall64_5 + +#elif defined(__i386__) + +# include +# define HYPERCALL1 _hypercall32_1 +# define HYPERCALL2 _hypercall32_2 +# define HYPERCALL3 _hypercall32_3 +# define HYPERCALL4 _hypercall32_4 +# define HYPERCALL5 _hypercall32_5 + +#endif + +extern uint8_t hypercall_page[PAGE_SIZE]; + +/* + * Hypercall primatives, compiled for the correct bitness + */ +static inline long hypercall_set_trap_table(const struct xen_trap_info *ti) +{ + return HYPERCALL1(long, __HYPERVISOR_set_trap_table, ti); +} + +static inline long hypercall_mmu_update(const mmu_update_t reqs[], + unsigned int count, + unsigned int *done, + unsigned int foreigndom) +{ + return HYPERCALL4(long, __HYPERVISOR_mmu_update, + reqs, count, done, foreigndom); +} + +static inline long hypercall_set_gdt(const unsigned long *mfns, + unsigned int entries) +{ + return HYPERCALL2(long, __HYPERVISOR_set_gdt, mfns, entries); +} + +static inline long hypercall_stack_switch(const unsigned int ss, const void *sp) +{ + return HYPERCALL2(long, __HYPERVISOR_stack_switch, ss, sp); +} + +static inline long hypercall_update_descriptor(uint64_t maddr, user_desc desc) +{ +#ifdef __x86_64__ + return HYPERCALL2(long, __HYPERVISOR_update_descriptor, maddr, desc.raw); +#else + return HYPERCALL4(long, __HYPERVISOR_update_descriptor, + maddr, maddr >> 32, desc.lo, desc.hi); +#endif +} + +/* + * This hypercall is misnamed in the Xen ABI, and actually operates on a + * linear address, not a virtual address. + */ +static inline long hypercall_update_va_mapping( + unsigned long linear, uint64_t npte, enum XEN_UVMF flags) +{ +#ifdef __x86_64__ + return HYPERCALL3(long, __HYPERVISOR_update_va_mapping, linear, npte, flags); +#else + return HYPERCALL4(long, __HYPERVISOR_update_va_mapping, + linear, npte, npte >> 32, flags); +#endif +} + +static inline long hypercall_mmuext_op(const mmuext_op_t ops[], + unsigned int count, + unsigned int *done, + unsigned int foreigndom) +{ + return HYPERCALL4(long, __HYPERVISOR_mmuext_op, + ops, count, done, foreigndom); +} + +static inline long hypercall_callback_op(unsigned int cmd, const void *arg) +{ + return HYPERCALL2(long, __HYPERVISOR_callback_op, cmd, arg); +} + +static inline long hypercall_memory_op(unsigned int cmd, void *arg) +{ + return HYPERCALL2(long, __HYPERVISOR_memory_op, cmd, arg); +} + +static inline long hypercall_multicall(struct multicall_entry *list, + unsigned int nr) +{ + return HYPERCALL2(long, __HYPERVISOR_multicall, list, nr); +} + +static inline long hypercall_xen_version(unsigned int cmd, void *arg) +{ + return HYPERCALL2(long, __HYPERVISOR_xen_version, cmd, arg); +} + +static inline long hypercall_grant_table_op(unsigned int cmd, void *args, + unsigned int count) +{ + return HYPERCALL3(long, __HYPERVISOR_grant_table_op, cmd, args, count); +} + +static inline long hypercall_vm_assist(unsigned int cmd, unsigned int type) +{ + return HYPERCALL2(long, __HYPERVISOR_vm_assist, cmd, type); +} + +static inline long hypercall_vcpu_op(unsigned int cmd, unsigned int vcpu, + void *extra) +{ + return HYPERCALL3(long, __HYPERVISOR_vcpu_op, cmd, vcpu, extra); +} + +static inline long hypercall_sched_op(unsigned int cmd, void *arg) +{ + return HYPERCALL2(long, __HYPERVISOR_sched_op, cmd, arg); +} + +static inline long hypercall_event_channel_op(unsigned int cmd, void *arg) +{ + return HYPERCALL2(long, __HYPERVISOR_event_channel_op, cmd, arg); +} + +static inline long hypercall_physdev_op(unsigned int cmd, void *arg) +{ + return HYPERCALL2(long, __HYPERVISOR_physdev_op, cmd, arg); +} + +static inline long hypercall_hvm_op(unsigned int cmd, void *arg) +{ + return HYPERCALL2(long, __HYPERVISOR_hvm_op, cmd, arg); +} + +static inline long hypercall_sysctl(xen_sysctl_t *arg) +{ + return HYPERCALL1(long, __HYPERVISOR_sysctl, arg); +} + +static inline long hypercall_argo_op(unsigned int cmd, void *arg1, void *arg2, + unsigned long arg3, unsigned long arg4) +{ + return HYPERCALL5(long, __HYPERVISOR_argo_op, cmd, arg1, arg2, arg3, arg4); +} + +/* + * Higher level hypercall helpers + */ +static inline int hypercall_register_callback(const xen_callback_register_t *arg) +{ + return hypercall_callback_op(CALLBACKOP_register, arg); +} + +static inline void hypercall_console_write(const char *buf, unsigned long count) +{ + (void)HYPERCALL3(long, __HYPERVISOR_console_io, CONSOLEIO_write, count, buf); +} + +#endif /* XTF_X86_HYPERCALL_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/build/arm-common/arch-common.mk b/build/arm-common/arch-common.mk new file mode 100644 index 00000000..232a6e00 --- /dev/null +++ b/build/arm-common/arch-common.mk @@ -0,0 +1,39 @@ +# Common makefile for arm + +# Compilation recipe +# arm needs linking normally, then converting to a binary format +define build-arm + $(LD) $$(LDFLAGS_$(1)) $$(DEPS-$(1)) -o $$@-syms + $(OBJCOPY) $$@-syms -O binary $$@ +endef + +# Specify the load address on the command line using: +# CONFIG_LOAD_ADDRESS=
+ifdef CONFIG_LOAD_ADDRESS +COMMON_AFLAGS += -DCONFIG_LOAD_ADDRESS=$(CONFIG_LOAD_ADDRESS) +endif + +# Specify whether to use PL011 UART: +# CONFIG_PL011_UART= +ifeq ($(CONFIG_PL011_UART), y) +COMMON_AFLAGS += -DCONFIG_PL011_UART +COMMON_CFLAGS += -DCONFIG_PL011_UART + +# Specify the PL011 UART base address on the command line using: +# CONFIG_PL011_ADDRESS=
+ifndef CONFIG_PL011_ADDRESS +$(error "You must specify CONFIG_PL011_ADDRESS.") +else +COMMON_AFLAGS += -DCONFIG_PL011_ADDRESS=$(CONFIG_PL011_ADDRESS) +COMMON_CFLAGS += -DCONFIG_PL011_ADDRESS=$(CONFIG_PL011_ADDRESS) +endif + +# Specify whether to enable early printk using PL011 UART +# Otherwise Xen debug console will be used to print boot messages +# CONFIG_PL011_EARLY_PRINTK= +ifeq ($(CONFIG_PL011_EARLY_PRINTK), y) +COMMON_AFLAGS += -DCONFIG_PL011_EARLY_PRINTK +COMMON_CFLAGS += -DCONFIG_PL011_EARLY_PRINTK +endif + +endif # CONFIG_PL011_UART diff --git a/build/arm-common/arch-files.mk b/build/arm-common/arch-files.mk new file mode 100644 index 00000000..26ca94fe --- /dev/null +++ b/build/arm-common/arch-files.mk @@ -0,0 +1,21 @@ +# Common files compiled and linked for arm + +obj-perenv += $(ROOT)/common/console.o +obj-perenv += $(ROOT)/common/lib.o +obj-perenv += $(ROOT)/common/libc/stdio.o +obj-perenv += $(ROOT)/common/libc/string.o +obj-perenv += $(ROOT)/common/libc/vsnprintf.o +obj-perenv += $(ROOT)/common/report.o +obj-perenv += $(ROOT)/common/setup.o +obj-perenv += $(ROOT)/common/xenbus.o + +obj-perenv += $(ROOT)/arch/arm/decode.o +obj-perenv += $(ROOT)/arch/arm/setup.o +obj-perenv += $(ROOT)/arch/arm/traps.o +ifeq ($(CONFIG_PL011_UART), y) +obj-perenv += $(ROOT)/arch/arm/pl011.o +endif + +# MMU specific objects +obj-mmu += $(ROOT)/arch/arm/mm.o +$(foreach env,$(MMU_ENVIRONMENTS),$(eval obj-$(env) += $(obj-mmu))) diff --git a/build/arm32/arch-common.mk b/build/arm32/arch-common.mk new file mode 100644 index 00000000..a81d22fd --- /dev/null +++ b/build/arm32/arch-common.mk @@ -0,0 +1,14 @@ +# Architecture specific configuration for arm32 + +SUBARCH := arm +ALL_ENVIRONMENTS := 32le + +$(foreach env,$(ALL_ENVIRONMENTS),$(eval $(env)_guest := arm32)) +$(foreach env,$(ALL_ENVIRONMENTS),$(eval $(env)_arch := arm32)) + +defcfg-arm32 := $(ROOT)/config/default-arm.cfg.in + +COMMON_CFLAGS += -march=armv7-a + +# Include arm common makefile +include $(ROOT)/build/arm-common/arch-common.mk diff --git a/build/arm32/arch-files.mk b/build/arm32/arch-files.mk new file mode 100644 index 00000000..ae5a5830 --- /dev/null +++ b/build/arm32/arch-files.mk @@ -0,0 +1,7 @@ +# Architecture specific files compiled and linked for arm32 + +# Include arm common files +include $(ROOT)/build/arm-common/arch-files.mk + +# Specific files for arm32 +obj-perenv += $(ROOT)/arch/arm/arm32/hypercall.o diff --git a/build/arm32/arch-tests.mk b/build/arm32/arch-tests.mk new file mode 100644 index 00000000..a02b6e55 --- /dev/null +++ b/build/arm32/arch-tests.mk @@ -0,0 +1,4 @@ +# Supported tests by arm32 + +# Currently only example test is supported +TESTS := $(ROOT)/tests/example diff --git a/build/arm64/arch-common.mk b/build/arm64/arch-common.mk new file mode 100644 index 00000000..f6ce2e30 --- /dev/null +++ b/build/arm64/arch-common.mk @@ -0,0 +1,18 @@ +# Architecture specific configuration for arm64 + +SUBARCH := arm +ALL_ENVIRONMENTS := 64le mmu64le + +MMU_ENVIRONMENTS := $(filter mmu%,$(ALL_ENVIRONMENTS)) + +$(foreach env,$(ALL_ENVIRONMENTS),$(eval $(env)_guest := arm64)) +$(foreach env,$(ALL_ENVIRONMENTS),$(eval $(env)_arch := arm64)) + +defcfg-arm64 := $(ROOT)/config/default-arm.cfg.in + +COMMON_CFLAGS += -march=armv8-a +# Prevent the compiler from using FP/ASIMD registers +COMMON_CFLAGS += -mgeneral-regs-only + +# Include arm common makefile +include $(ROOT)/build/arm-common/arch-common.mk diff --git a/build/arm64/arch-files.mk b/build/arm64/arch-files.mk new file mode 100644 index 00000000..ec424c03 --- /dev/null +++ b/build/arm64/arch-files.mk @@ -0,0 +1,8 @@ +# Architecture specific files compiled and linked for arm64 + +# Include arm common files +include $(ROOT)/build/arm-common/arch-files.mk + +# Specific files for arm64 +obj-perenv += $(ROOT)/arch/arm/arm64/cache.o +obj-perenv += $(ROOT)/arch/arm/arm64/hypercall.o diff --git a/build/arm64/arch-tests.mk b/build/arm64/arch-tests.mk new file mode 100644 index 00000000..1a13ba92 --- /dev/null +++ b/build/arm64/arch-tests.mk @@ -0,0 +1,4 @@ +# Supported tests by arm64 + +# Currently only example test is supported +TESTS := $(ROOT)/tests/example diff --git a/build/common.mk b/build/common.mk index 886f190a..70c9bdfa 100644 --- a/build/common.mk +++ b/build/common.mk @@ -1,21 +1,6 @@ -ALL_CATEGORIES := special functional xsa utility in-development - -ALL_ENVIRONMENTS := pv64 pv32pae hvm64 hvm32pae hvm32pse hvm32 - -PV_ENVIRONMENTS := $(filter pv%,$(ALL_ENVIRONMENTS)) -HVM_ENVIRONMENTS := $(filter hvm%,$(ALL_ENVIRONMENTS)) -32BIT_ENVIRONMENTS := $(filter pv32% hvm32%,$(ALL_ENVIRONMENTS)) -64BIT_ENVIRONMENTS := $(filter pv64% hvm64%,$(ALL_ENVIRONMENTS)) - -# $(env)_guest => pv or hvm mapping -$(foreach env,$(PV_ENVIRONMENTS),$(eval $(env)_guest := pv)) -$(foreach env,$(HVM_ENVIRONMENTS),$(eval $(env)_guest := hvm)) - -# $(env)_arch => x86_32/64 mapping -$(foreach env,$(32BIT_ENVIRONMENTS),$(eval $(env)_arch := x86_32)) -$(foreach env,$(64BIT_ENVIRONMENTS),$(eval $(env)_arch := x86_64)) - -COMMON_FLAGS := -pipe -I$(ROOT)/include -I$(ROOT)/arch/x86/include -MMD -MP +# Architecture independent/common configuration +ALL_CATEGORIES := special functional xsa utility in-development +COMMON_FLAGS := -pipe -I$(ROOT)/include -MMD -MP cc-option = $(shell if [ -z "`echo 'int p=1;' | $(CC) $(1) -S -o /dev/null -x c - 2>&1`" ]; \ then echo y; else echo n; fi) @@ -25,26 +10,31 @@ COMMON_CFLAGS-$(call cc-option,-no-pie) += -no-pie COMMON_AFLAGS := $(COMMON_FLAGS) -D__ASSEMBLY__ COMMON_CFLAGS := $(COMMON_FLAGS) $(COMMON_CFLAGS-y) + +# Include architecture specific configuration +include $(ROOT)/build/$(ARCH)/arch-common.mk + +COMMON_CFLAGS += -I$(ROOT)/arch/$(SUBARCH)/include +COMMON_AFLAGS += -I$(ROOT)/arch/$(SUBARCH)/include COMMON_CFLAGS += -Wall -Wextra -Werror -std=gnu99 -Wstrict-prototypes -O3 -g COMMON_CFLAGS += -fno-common -fno-asynchronous-unwind-tables -fno-strict-aliasing COMMON_CFLAGS += -fno-stack-protector -fno-pic -ffreestanding -nostdinc -COMMON_CFLAGS += -mno-red-zone -mno-sse COMMON_CFLAGS += -Wno-unused-parameter -Winline -COMMON_AFLAGS-x86_32 := -m32 -COMMON_AFLAGS-x86_64 := -m64 - -COMMON_CFLAGS-x86_32 := -m32 -COMMON_CFLAGS-x86_64 := -m64 - +# Default guest configfiles defcfg-pv := $(ROOT)/config/default-pv.cfg.in defcfg-hvm := $(ROOT)/config/default-hvm.cfg.in +# Following variables needs to be set up in $(ROOT)/build/$(ARCH)/arch-files.mk +# obj-perarch get compiled once per architecture +# obj-perenv get compiled once for each environment +# obj-$(env) are objects unique to a specific environment obj-perarch := obj-perenv := -include $(ROOT)/build/files.mk -# Run once per environment to set up some common bits & pieces +include $(ROOT)/build/$(ARCH)/arch-files.mk + +# Set up some common bits and pieces for specified environment define PERENV_setup AFLAGS_$($(1)_arch) := $$(COMMON_AFLAGS) $$(COMMON_AFLAGS-$($(1)_arch)) @@ -53,8 +43,8 @@ CFLAGS_$($(1)_arch) := $$(COMMON_CFLAGS) $$(COMMON_CFLAGS-$($(1)_arch)) AFLAGS_$(1) := $$(AFLAGS_$($(1)_arch)) $$(COMMON_AFLAGS-$(1)) -DCONFIG_ENV_$(1) -include arch/config.h CFLAGS_$(1) := $$(CFLAGS_$($(1)_arch)) $$(COMMON_CFLAGS-$(1)) -DCONFIG_ENV_$(1) -include arch/config.h -head-$(1) := $(ROOT)/arch/x86/$($(1)_guest)/head-$(1).o -link-$(1) := $(ROOT)/arch/x86/link-$(1).lds +link-$(1) := $(ROOT)/arch/$(SUBARCH)/link-$(1).lds +head-$(1) := $(ROOT)/arch/$(SUBARCH)/$($(1)_guest)/head-$(1).o LDFLAGS_$(1) := -T $$(link-$(1)) -nostdlib $(LDFLAGS-y) @@ -63,7 +53,7 @@ DEPS-$(1) = $$(head-$(1)) \ $$(obj-perarch:%.o=%-$($(1)_arch).o) \ $$(obj-$(1):%.o=%-$(1).o) $$(obj-perenv:%.o=%-$(1).o) -# Generate .lds with approprate flags +# Generate .lds with appropriate flags %/link-$(1).lds: %/link.lds.S $$(CPP) $$(AFLAGS_$(1)) -P -C $$< -o $$@ @@ -85,6 +75,7 @@ DEPS-$(1) = $$(head-$(1)) \ endef +# Make a call to a function PERENV_setup once per each environment $(foreach env,$(ALL_ENVIRONMENTS),$(eval $(call PERENV_setup,$(env)))) define move-if-changed diff --git a/build/gen.mk b/build/gen.mk index 25dd5c62..661cbf9b 100644 --- a/build/gen.mk +++ b/build/gen.mk @@ -1,6 +1,6 @@ +# Architecture independent makefile for compiling tests # Sanity checking of expected parameters - ifeq ($(NAME),) $(error NAME should be specified) endif @@ -26,17 +26,17 @@ VCPUS := 1 # Default to 1 vcpu if not provided endif ifneq ($(VARY-CFG),) -TEST-CFGS := $(foreach env,$(TEST-ENVS),$(foreach vary,$(VARY-CFG),test-$(env)-$(NAME)~$(vary).cfg)) +TEST-CFGS := $(foreach env,$(TEST-ENVS),$(foreach vary,$(VARY-CFG),test-$(SUBARCH)-$(env)-$(NAME)~$(vary).cfg)) else -TEST-CFGS := $(foreach env,$(TEST-ENVS),test-$(env)-$(NAME).cfg) +TEST-CFGS := $(foreach env,$(TEST-ENVS),test-$(SUBARCH)-$(env)-$(NAME).cfg) endif .PHONY: build -build: $(foreach env,$(TEST-ENVS),test-$(env)-$(NAME)) $(TEST-CFGS) +build: $(foreach env,$(TEST-ENVS),test-$(SUBARCH)-$(env)-$(NAME)) $(TEST-CFGS) build: info.json info.json: $(ROOT)/build/mkinfo.py FORCE - @$(PYTHON) $< $@.tmp "$(NAME)" "$(CATEGORY)" "$(TEST-ENVS)" "$(VARY-CFG)" + @$(PYTHON) $< $@.tmp "$(NAME)" "$(CATEGORY)" "$(SUBARCH)" "$(TEST-ENVS)" "$(VARY-CFG)" @$(call move-if-changed,$@.tmp,$@) .PHONY: install install-each-env @@ -44,35 +44,39 @@ install: install-each-env info.json @$(INSTALL_DIR) $(DESTDIR)$(xtftestdir)/$(NAME) $(INSTALL_DATA) info.json $(DESTDIR)$(xtftestdir)/$(NAME) -hvm64-format := $(firstword $(filter elf32-x86-64,$(shell $(OBJCOPY) --help)) elf32-i386) - +# Build a test for specified environment define PERENV_build -ifneq ($(1),hvm64) -# Generic link line for most environments -test-$(1)-$(NAME): $$(DEPS-$(1)) $$(link-$(1)) - $(LD) $$(LDFLAGS_$(1)) $$(DEPS-$(1)) -o $$@ +# If any subarchitecture/environment needs a special compilation/linking recipe +# instead of the default one, a custom recipe called build-$(SUBARCH) or +# build-$(env) e.g. build-arm or build-hvm64 should be created in +# $(ROOT)/build/$(ARCH)/arch-common.mk + +test-$(SUBARCH)-$(1)-$(NAME): $$(DEPS-$(1)) $$(link-$(1)) +ifdef build-$(SUBARCH) + @# Sub-architecture specific compilation recipe + $(call build-$(SUBARCH),$(1)) +else ifdef build-$(1) + @# Environment specific compilation recipe + $(call build-$(1)) else -# hvm64 needs linking normally, then converting to elf32-x86-64 or elf32-i386 -test-$(1)-$(NAME): $$(DEPS-$(1)) $$(link-$(1)) - $(LD) $$(LDFLAGS_$(1)) $$(DEPS-$(1)) -o $$@.tmp - $(OBJCOPY) $$@.tmp -O $(hvm64-format) $$@ - rm -f $$@.tmp + @# Generic link line for most environments + $(LD) $$(LDFLAGS_$(1)) $$(DEPS-$(1)) -o $$@ endif cfg-$(1) ?= $(defcfg-$($(1)_guest)) cfg-default-deps := $(ROOT)/build/mkcfg.py $$(cfg-$(1)) $(TEST-EXTRA-CFG) FORCE -test-$(1)-$(NAME).cfg: $$(cfg-default-deps) +test-$(SUBARCH)-$(1)-$(NAME).cfg: $$(cfg-default-deps) $(PYTHON) $$< $$@.tmp "$$(cfg-$(1))" "$(VCPUS)" "$(TEST-EXTRA-CFG)" "" @$(call move-if-changed,$$@.tmp,$$@) -test-$(1)-$(NAME)~%.cfg: $$(cfg-default-deps) %.cfg.in +test-$(SUBARCH)-$(1)-$(NAME)~%.cfg: $$(cfg-default-deps) %.cfg.in $(PYTHON) $$< $$@.tmp "$$(cfg-$(1))" "$(VCPUS)" "$(TEST-EXTRA-CFG)" "$$*.cfg.in" @$(call move-if-changed,$$@.tmp,$$@) -test-$(1)-$(NAME)~%.cfg: $$(cfg-default-deps) $(ROOT)/config/%.cfg.in +test-$(SUBARCH)-$(1)-$(NAME)~%.cfg: $$(cfg-default-deps) $(ROOT)/config/%.cfg.in $(PYTHON) $$< $$@.tmp "$$(cfg-$(1))" "$(VCPUS)" "$(TEST-EXTRA-CFG)" "$(ROOT)/config/$$*.cfg.in" @$(call move-if-changed,$$@.tmp,$$@) @@ -80,23 +84,25 @@ test-$(1)-$(NAME)~%.cfg: $$(cfg-default-deps) $(ROOT)/config/%.cfg.in -include $$(DEPS-$(1):%.o=%.d) .PHONY: install-$(1) install-$(1).cfg -install-$(1): test-$(1)-$(NAME) +install-$(1): test-$(SUBARCH)-$(1)-$(NAME) @$(INSTALL_DIR) $(DESTDIR)$(xtftestdir)/$(NAME) $(INSTALL_PROGRAM) $$< $(DESTDIR)$(xtftestdir)/$(NAME) -install-$(1).cfg: $(filter test-$(1)-%,$(TEST-CFGS)) +install-$(1).cfg: $(filter test-$(SUBARCH)-$(1)-%,$(TEST-CFGS)) @$(INSTALL_DIR) $(DESTDIR)$(xtftestdir)/$(NAME) $(INSTALL_DATA) $$^ $(DESTDIR)$(xtftestdir)/$(NAME) install-each-env: install-$(1) install-$(1).cfg endef + +# Make a call to a function PERENV_build once per each test's environment $(foreach env,$(TEST-ENVS),$(eval $(call PERENV_build,$(env)))) .PHONY: clean clean: find $(ROOT) \( -name "*.o" -o -name "*.d" \) -delete - rm -f $(foreach env,$(TEST-ENVS),test-$(env)-$(NAME) test-$(env)-$(NAME)*.cfg) + rm -f $(foreach env,$(TEST-ENVS),test-$(SUBARCH)-$(env)-$(NAME) test-$(SUBARCH)-$(env)-$(NAME)*.cfg) .PHONY: %var %var: diff --git a/build/mkcfg.py b/build/mkcfg.py index 7f8e3d52..a942c893 100644 --- a/build/mkcfg.py +++ b/build/mkcfg.py @@ -11,8 +11,8 @@ # Usage: mkcfg.py $OUT $DEFAULT-CFG $EXTRA-CFG $VARY-CFG _, out, defcfg, vcpus, extracfg, varycfg = sys.argv -# Evaluate environment and name from $OUT -_, env, name = out.split('.')[0].split('-', 2) +# Evaluate subarch, environment and name from $OUT +_, subarch, env, name = out.split('.')[0].split('-', 3) # Possibly split apart the variation suffix variation = '' @@ -28,6 +28,7 @@ def expand(text): .replace("@@VCPUS@@", vcpus) .replace("@@XTFDIR@@", os.environ["xtfdir"]) .replace("@@VARIATION@@", variation) + .replace("@@SUBARCH@@", subarch) ) config = open(defcfg).read() diff --git a/build/mkinfo.py b/build/mkinfo.py index 50819e2c..fdb50398 100644 --- a/build/mkinfo.py +++ b/build/mkinfo.py @@ -3,12 +3,13 @@ import sys, json -# Usage: mkcfg.py $OUT $NAME $CATEGORY $ENVS $VARIATIONS -_, out, name, cat, envs, variations = sys.argv +# Usage: mkcfg.py $OUT $NAME $CATEGORY $SUBARCH $ENVS $VARIATIONS +_, out, name, cat, subarch, envs, variations = sys.argv template = { "name": name, "category": cat, + "subarch": subarch, "environments": [], "variations": [], } diff --git a/build/x86/arch-common.mk b/build/x86/arch-common.mk new file mode 100644 index 00000000..914f71fe --- /dev/null +++ b/build/x86/arch-common.mk @@ -0,0 +1,34 @@ +# Architecture specific configuration for x86 + +SUBARCH := x86 +ALL_ENVIRONMENTS := pv64 pv32pae hvm64 hvm32pae hvm32pse hvm32 + +PV_ENVIRONMENTS := $(filter pv%,$(ALL_ENVIRONMENTS)) +HVM_ENVIRONMENTS := $(filter hvm%,$(ALL_ENVIRONMENTS)) +32BIT_ENVIRONMENTS := $(filter pv32% hvm32%,$(ALL_ENVIRONMENTS)) +64BIT_ENVIRONMENTS := $(filter pv64% hvm64%,$(ALL_ENVIRONMENTS)) + +# $(env)_guest => pv or hvm mapping +$(foreach env,$(PV_ENVIRONMENTS),$(eval $(env)_guest := pv)) +$(foreach env,$(HVM_ENVIRONMENTS),$(eval $(env)_guest := hvm)) + +# $(env)_arch => x86_32/64 mapping +$(foreach env,$(32BIT_ENVIRONMENTS),$(eval $(env)_arch := x86_32)) +$(foreach env,$(64BIT_ENVIRONMENTS),$(eval $(env)_arch := x86_64)) + +COMMON_CFLAGS += -mno-red-zone -mno-sse + +COMMON_AFLAGS-x86_32 := -m32 +COMMON_AFLAGS-x86_64 := -m64 +COMMON_CFLAGS-x86_32 := -m32 +COMMON_CFLAGS-x86_64 := -m64 + +hvm64-format := $(firstword $(filter elf32-x86-64,$(shell $(OBJCOPY) --help)) elf32-i386) + +# Compilation recipe for hvm64 +# hvm64 needs linking normally, then converting to elf32-x86-64 or elf32-i386 +define build-hvm64 + $(LD) $$(LDFLAGS_hvm64) $$(DEPS-hvm64) -o $$@.tmp + $(OBJCOPY) $$@.tmp -O $(hvm64-format) $$@ + rm -f $$@.tmp +endef diff --git a/build/files.mk b/build/x86/arch-files.mk similarity index 86% rename from build/files.mk rename to build/x86/arch-files.mk index dfa27e48..b02c849d 100644 --- a/build/files.mk +++ b/build/x86/arch-files.mk @@ -1,9 +1,6 @@ -# Files compiled and linked for different architectures and environments -# -# obj-perarch get compiled once per architecture -# obj-perenv get get compiled once for each environment -# obj-$(env) are objects unique to a specific environment +# Architecture specific files compiled and linked for x86 +# Per architecture obj-perarch += $(ROOT)/common/console.o obj-perarch += $(ROOT)/common/exlog.o obj-perarch += $(ROOT)/common/extable.o @@ -17,6 +14,7 @@ obj-perarch += $(ROOT)/common/report.o obj-perarch += $(ROOT)/common/setup.o obj-perarch += $(ROOT)/common/xenbus.o +# Per environment obj-perenv += $(ROOT)/arch/x86/decode.o obj-perenv += $(ROOT)/arch/x86/desc.o obj-perenv += $(ROOT)/arch/x86/extable.o @@ -26,7 +24,6 @@ obj-perenv += $(ROOT)/arch/x86/msr.o obj-perenv += $(ROOT)/arch/x86/setup.o obj-perenv += $(ROOT)/arch/x86/traps.o - # HVM specific objects obj-hvm += $(ROOT)/arch/x86/apic.o obj-hvm += $(ROOT)/arch/x86/hpet.o @@ -40,17 +37,14 @@ obj-hvm += $(ROOT)/arch/x86/x86-tss.o $(foreach env,$(HVM_ENVIRONMENTS),$(eval obj-$(env) += $(obj-hvm))) - # PV specific objects obj-pv += $(ROOT)/arch/x86/pv/traps.o $(foreach env,$(PV_ENVIRONMENTS),$(eval obj-$(env) += $(obj-pv))) - # 32bit specific objects obj-32 += $(ROOT)/arch/x86/entry_32.o $(foreach env,$(32BIT_ENVIRONMENTS),$(eval obj-$(env) += $(obj-32))) - # 64bit specific objects obj-64 += $(ROOT)/arch/x86/entry_64.o $(foreach env,$(64BIT_ENVIRONMENTS),$(eval obj-$(env) += $(obj-64))) diff --git a/config/default-arm.cfg.in b/config/default-arm.cfg.in new file mode 100644 index 00000000..0d27178c --- /dev/null +++ b/config/default-arm.cfg.in @@ -0,0 +1,6 @@ +name="test-@@SUBARCH@@-@@ENV@@-@@NAME@@@@VARIATION@@" + +vcpus=@@VCPUS@@ + +memory=128 +kernel="@@XTFDIR@@/tests/@@NAME@@/test-@@SUBARCH@@-@@ENV@@-@@NAME@@" diff --git a/config/default-hvm.cfg.in b/config/default-hvm.cfg.in index ed53cb95..43421a1c 100644 --- a/config/default-hvm.cfg.in +++ b/config/default-hvm.cfg.in @@ -1,4 +1,4 @@ -name="test-@@ENV@@-@@NAME@@@@VARIATION@@" +name="test-@@SUBARCH@@-@@ENV@@-@@NAME@@@@VARIATION@@" vcpus=@@VCPUS@@ @@ -6,7 +6,7 @@ type="hvm" builder="hvm" # Legacy for before Xen 4.10 memory=128 -firmware_override="@@XTFDIR@@/tests/@@NAME@@/test-@@ENV@@-@@NAME@@" +firmware_override="@@XTFDIR@@/tests/@@NAME@@/test-@@SUBARCH@@-@@ENV@@-@@NAME@@" # The framework doesn't reboot. A reboot signal is almost certainly a triple # fault instead. Prevent it turning into a runaway domain. diff --git a/config/default-pv.cfg.in b/config/default-pv.cfg.in index 3e7b918c..23f2389f 100644 --- a/config/default-pv.cfg.in +++ b/config/default-pv.cfg.in @@ -1,4 +1,4 @@ -name="test-@@ENV@@-@@NAME@@@@VARIATION@@" +name="test-@@SUBARCH@@-@@ENV@@-@@NAME@@@@VARIATION@@" vcpus=@@VCPUS@@ @@ -6,4 +6,4 @@ type="pv" loader="generic" # Legacy for before Xen 4.10 memory=128 -kernel="@@XTFDIR@@/tests/@@NAME@@/test-@@ENV@@-@@NAME@@" +kernel="@@XTFDIR@@/tests/@@NAME@@/test-@@SUBARCH@@-@@ENV@@-@@NAME@@" diff --git a/docs/introduction.dox b/docs/introduction.dox index 9207941d..c49f5bbd 100644 --- a/docs/introduction.dox +++ b/docs/introduction.dox @@ -6,7 +6,7 @@ A test has several important attributes, and are often referred to in the form: - test-$ENVIRONMENT-$NAME[~$VARIATION] + test-$SUBARCH-$ENVIRONMENT-$NAME[~$VARIATION] This identifies a single test instance, with the purpose of executing and providing a single result (See @ref running). @@ -38,17 +38,31 @@ categories are: A test is built for one or more environments. The environment encodes: +For x86 architecture: - The Xen VM ABI in use (PV or HVM). - The compilation width (32bit or 64bit). - The primary paging mode (none, PSE, PAE). -All available environments are: +For arm32 there is currently a single environment called 32le. +For arm64 there are 2 environments: mmu64le, 64le where the former has +MMU support and the latter does not. + +All available environments for x86 are: +@dontinclude build/x86/arch-common.mk @skipline ALL_ENVIRONMENTS -Some more specific collections for environments are also available: +Some more specific collections for x86 environments are also available: @skipline PV_ENVIRONMENTS @until 64BIT_ENVIRONMENTS +All available environments for arm64 are: +@dontinclude build/arm64/arch-common.mk +@skipline ALL_ENVIRONMENTS + +All available environments for arm32 are: +@dontinclude build/arm32/arch-common.mk +@skipline ALL_ENVIRONMENTS + An individual test, compiled for more than one environment, will end up with a individual microkernel binary for each specified environment. @@ -123,21 +137,21 @@ Building this will generate a number of files. main-pv64.d main-pv64.o Makefile - test-hvm32-example - test-hvm32-example.cfg - test-hvm32pae-example - test-hvm32pae-example.cfg - test-hvm32pse-example - test-hvm32pse-example.cfg - test-hvm64-example - test-hvm64-example.cfg - test-pv32pae-example - test-pv32pae-example.cfg - test-pv64-example - test-pv64-example.cfg + test-x86-hvm32-example + test-x86-hvm32-example.cfg + test-x86-hvm32pae-example + test-x86-hvm32pae-example.cfg + test-x86-hvm32pse-example + test-x86-hvm32pse-example.cfg + test-x86-hvm64-example + test-x86-hvm64-example.cfg + test-x86-pv32pae-example + test-x86-pv32pae-example.cfg + test-x86-pv64-example + test-x86-pv64-example.cfg The `.o` and `.d` files are build artefacts, leading to the eventual -`test-$ENV-$NAME` microkernel. Individual `xl.cfg` files are generated for +`test-$SUBARCH-$ENV-$NAME` microkernel. Individual `xl.cfg` files are generated for each microkernel. `info.json` contains metadata about the test. @@ -145,7 +159,7 @@ each microkernel. `info.json` contains metadata about the test. If XTF in being built in dom0, all paths should be set up to run correctly. - # xl create tests/example/test-hvm64-example.cfg + # xl create tests/example/test-x86-hvm64-example.cfg If XTF is built elsewhere, it should be installed: @@ -158,18 +172,18 @@ with paths appropriate for the system under test. A test will by default write synchronously to all available consoles: - # ./xtf-runner test-hvm64-example - Executing 'xl create -p tests/example/test-hvm64-example.cfg' - Parsing config from tests/example/test-hvm64-example.cfg - Executing 'xl console test-hvm64-example' - Executing 'xl unpause test-hvm64-example' + # ./xtf-runner test-x86-hvm64-example + Executing 'xl create -p tests/example/test-x86-hvm64-example.cfg' + Parsing config from tests/example/test-x86-hvm64-example.cfg + Executing 'xl console test-x86-hvm64-example' + Executing 'xl unpause test-x86-hvm64-example' --- Xen Test Framework --- Environment: HVM 64bit (Long mode 4 levels) Hello World Test result: SUCCESS Combined test results: - test-hvm64-example SUCCESS + test-x86-hvm64-example SUCCESS The result is covered by the report.h API. In short, the options are: diff --git a/docs/mainpage.dox b/docs/mainpage.dox index d9558d62..319941eb 100644 --- a/docs/mainpage.dox +++ b/docs/mainpage.dox @@ -18,8 +18,14 @@ The build system and library abstractions are specifically designed to make it easy to write code once and compile it for multiple different environments (virtual machines). +Currently there are 3 architectures available: x86, arm64 and arm32 although +only x86 is truly supported. Initial support for arm64 is added allowing to run +hello-world test. Support for arm32 allows to run startup code. +This creates a base for future implementation. + The current environments supported are: +x86: Environment | Guest | Width | Paging :-----------|:------|:------|:--------- `pv32pae` | PV | 32bit | PAE @@ -29,6 +35,16 @@ Environment | Guest | Width | Paging `hvm32pae` | HVM | 32bit | PAE `hvm64` | HVM | 64bit | Long mode +arm64: +Environment | Guest | Width | Endianness | Paging +:-----------|:------|:------|:-----------|:---------------- +`64le` | arm64 | 64bit | little | no MMU +`mmu64le` | arm64 | 64bit | little | 4KB + +arm32: +Environment | Guest | Width | Endianness | Paging +:-----------|:------|:------|:-----------|:---------------- +`32le` | arm32 | 32bit | little | no MMU @section getting-started Getting Started @@ -46,26 +62,41 @@ For x86: `elf32-i386` will be used which will load correctly, but disassemble incorrectly. +For arm64/arm32: +-when cross-compiling: + - GNU compatible cross-compiler toolchain for Aarch64/Aarch32 +-when building natively: + - GNU compatible toolchain for Aarch64/Aarch32 + To obtain and build: $ git clone git://xenbits.xen.org/xtf.git $ cd xtf + # To build for x86: $ make -j4 + # To build for arm64 natively: + $ make ARCH=arm64 + # To build for arm32 natively: + $ make ARCH=arm32 + # To build for arm64 when cross compiling: + $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- + # To build for arm32 when cross compiling: + $ make ARCH=arm32 CROSS_COMPILE=arm-linux-gnueabi- To run tests on a Xen host: (see @ref errata first) - # ./xtf-runner test-pv64-example - Executing 'xl create -p tests/example/test-pv64-example.cfg' - Parsing config from tests/example/test-pv64-example.cfg - Executing 'xl console test-pv64-example' - Executing 'xl unpause test-pv64-example' + # ./xtf-runner test-x86-pv64-example + Executing 'xl create -p tests/example/test-x86-pv64-example.cfg' + Parsing config from tests/example/test-x86-pv64-example.cfg + Executing 'xl console test-x86-pv64-example' + Executing 'xl unpause test-x86-pv64-example' --- Xen Test Framework --- Environment: PV 64bit (Long mode 4 levels) Hello World Test result: SUCCESS Combined test results: - test-pv64-example SUCCESS + test-x86-pv64-example SUCCESS @section errata Errata diff --git a/include/xen/arch-arm.h b/include/xen/arch-arm.h new file mode 100644 index 00000000..ab8d238a --- /dev/null +++ b/include/xen/arch-arm.h @@ -0,0 +1,452 @@ +#ifndef XEN_PUBLIC_ARCH_ARM_H +#define XEN_PUBLIC_ARCH_ARM_H + +/* + * `incontents 50 arm_abi Hypercall Calling Convention + * + * A hypercall is issued using the ARM HVC instruction. + * + * A hypercall can take up to 5 arguments. These are passed in + * registers, the first argument in x0/r0 (for arm64/arm32 guests + * respectively irrespective of whether the underlying hypervisor is + * 32- or 64-bit), the second argument in x1/r1, the third in x2/r2, + * the forth in x3/r3 and the fifth in x4/r4. + * + * The hypercall number is passed in r12 (arm) or x16 (arm64). In both + * cases the relevant ARM procedure calling convention specifies this + * is an inter-procedure-call scratch register (e.g. for use in linker + * stubs). This use does not conflict with use during a hypercall. + * + * The HVC ISS must contain a Xen specific TAG: XEN_HYPERCALL_TAG. + * + * The return value is in x0/r0. + * + * The hypercall will clobber x16/r12 and the argument registers used + * by that hypercall (except r0 which is the return value) i.e. in + * addition to x16/r12 a 2 argument hypercall will clobber x1/r1 and a + * 4 argument hypercall will clobber x1/r1, x2/r2 and x3/r3. + * + * Parameter structs passed to hypercalls are laid out according to + * the Procedure Call Standard for the ARM Architecture (AAPCS, AKA + * EABI) and Procedure Call Standard for the ARM 64-bit Architecture + * (AAPCS64). Where there is a conflict the 64-bit standard should be + * used regardless of guest type. Structures which are passed as + * hypercall arguments are always little endian. + * + * All memory which is shared with other entities in the system + * (including the hypervisor and other guests) must reside in memory + * which is mapped as Normal Inner Write-Back Outer Write-Back Inner-Shareable. + * This applies to: + * - hypercall arguments passed via a pointer to guest memory. + * - memory shared via the grant table mechanism (including PV I/O + * rings etc). + * - memory shared with the hypervisor (struct shared_info, struct + * vcpu_info, the grant table, etc). + * + * Any cache allocation hints are acceptable. + */ + +/* + * `incontents 55 arm_hcall Supported Hypercalls + * + * Xen on ARM makes extensive use of hardware facilities and therefore + * only a subset of the potential hypercalls are required. + * + * Since ARM uses second stage paging any machine/physical addresses + * passed to hypercalls are Guest Physical Addresses (Intermediate + * Physical Addresses) unless otherwise noted. + * + * The following hypercalls (and sub operations) are supported on the + * ARM platform. Other hypercalls should be considered + * unavailable/unsupported. + * + * HYPERVISOR_memory_op + * All generic sub-operations + * + * HYPERVISOR_domctl + * All generic sub-operations, with the exception of: + * * XEN_DOMCTL_irq_permission (not yet implemented) + * + * HYPERVISOR_sched_op + * All generic sub-operations, with the exception of: + * * SCHEDOP_block -- prefer wfi hardware instruction + * + * HYPERVISOR_console_io + * All generic sub-operations + * + * HYPERVISOR_xen_version + * All generic sub-operations + * + * HYPERVISOR_event_channel_op + * All generic sub-operations + * + * HYPERVISOR_physdev_op + * No sub-operations are currenty supported + * + * HYPERVISOR_sysctl + * All generic sub-operations, with the exception of: + * * XEN_SYSCTL_page_offline_op + * * XEN_SYSCTL_get_pmstat + * * XEN_SYSCTL_pm_op + * + * HYPERVISOR_hvm_op + * Exactly these sub-operations are supported: + * * HVMOP_set_param + * * HVMOP_get_param + * + * HYPERVISOR_grant_table_op + * All generic sub-operations + * + * HYPERVISOR_vcpu_op + * Exactly these sub-operations are supported: + * * VCPUOP_register_vcpu_info + * * VCPUOP_register_runstate_memory_area + * + * + * Other notes on the ARM ABI: + * + * - struct start_info is not exported to ARM guests. + * + * - struct shared_info is mapped by ARM guests using the + * HYPERVISOR_memory_op sub-op XENMEM_add_to_physmap, passing + * XENMAPSPACE_shared_info as space parameter. + * + * - All the per-cpu struct vcpu_info are mapped by ARM guests using the + * HYPERVISOR_vcpu_op sub-op VCPUOP_register_vcpu_info, including cpu0 + * struct vcpu_info. + * + * - The grant table is mapped using the HYPERVISOR_memory_op sub-op + * XENMEM_add_to_physmap, passing XENMAPSPACE_grant_table as space + * parameter. The memory range specified under the Xen compatible + * hypervisor node on device tree can be used as target gpfn for the + * mapping. + * + * - Xenstore is initialized by using the two hvm_params + * HVM_PARAM_STORE_PFN and HVM_PARAM_STORE_EVTCHN. They can be read + * with the HYPERVISOR_hvm_op sub-op HVMOP_get_param. + * + * - The paravirtualized console is initialized by using the two + * hvm_params HVM_PARAM_CONSOLE_PFN and HVM_PARAM_CONSOLE_EVTCHN. They + * can be read with the HYPERVISOR_hvm_op sub-op HVMOP_get_param. + * + * - Event channel notifications are delivered using the percpu GIC + * interrupt specified under the Xen compatible hypervisor node on + * device tree. + * + * - The device tree Xen compatible node is fully described under Linux + * at Documentation/devicetree/bindings/arm/xen.txt. + */ + +#define XEN_HYPERCALL_TAG 0XEA1 + +#define int64_aligned_t int64_t __attribute__((aligned(8))) +#define uint64_aligned_t uint64_t __attribute__((aligned(8))) + +#ifndef __ASSEMBLY__ +#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \ + typedef union { type *p; unsigned long q; } \ + __guest_handle_ ## name; \ + typedef union { type *p; uint64_aligned_t q; } \ + __guest_handle_64_ ## name + +/* + * XEN_GUEST_HANDLE represents a guest pointer, when passed as a field + * in a struct in memory. On ARM is always 8 bytes sizes and 8 bytes + * aligned. + * XEN_GUEST_HANDLE_PARAM represents a guest pointer, when passed as an + * hypercall argument. It is 4 bytes on aarch32 and 8 bytes on aarch64. + */ +#define __DEFINE_XEN_GUEST_HANDLE(name, type) \ + ___DEFINE_XEN_GUEST_HANDLE(name, type); \ + ___DEFINE_XEN_GUEST_HANDLE(const_##name, const type) +#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name) +#define __XEN_GUEST_HANDLE(name) __guest_handle_64_ ## name +#define XEN_GUEST_HANDLE(name) __XEN_GUEST_HANDLE(name) +#define XEN_GUEST_HANDLE_PARAM(name) __guest_handle_ ## name +#define set_xen_guest_handle_raw(hnd, val) \ + do { \ + typeof(&(hnd)) _sxghr_tmp = &(hnd); \ + _sxghr_tmp->q = 0; \ + _sxghr_tmp->p = val; \ + } while ( 0 ) +#define set_xen_guest_handle(hnd, val) set_xen_guest_handle_raw(hnd, val) + +typedef uint64_t xen_pfn_t; +#define PRI_xen_pfn PRIx64 +#define PRIu_xen_pfn PRIu64 + +/* + * Maximum number of virtual CPUs in legacy multi-processor guests. + * Only one. All other VCPUS must use VCPUOP_register_vcpu_info. + */ +#define XEN_LEGACY_MAX_VCPUS 1 + +typedef uint64_t xen_ulong_t; +#define PRI_xen_ulong PRIx64 + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +/* Anonymous union includes both 32- and 64-bit names (e.g., r0/x0). */ +# define __DECL_REG(n64, n32) union { \ + uint64_t n64; \ + uint32_t n32; \ + } +#else +/* Non-gcc sources must always use the proper 64-bit name (e.g., x0). */ +#define __DECL_REG(n64, n32) uint64_t n64 +#endif + +struct vcpu_guest_core_regs +{ + /* Aarch64 Aarch32 */ + __DECL_REG(x0, r0_usr); + __DECL_REG(x1, r1_usr); + __DECL_REG(x2, r2_usr); + __DECL_REG(x3, r3_usr); + __DECL_REG(x4, r4_usr); + __DECL_REG(x5, r5_usr); + __DECL_REG(x6, r6_usr); + __DECL_REG(x7, r7_usr); + __DECL_REG(x8, r8_usr); + __DECL_REG(x9, r9_usr); + __DECL_REG(x10, r10_usr); + __DECL_REG(x11, r11_usr); + __DECL_REG(x12, r12_usr); + + __DECL_REG(x13, sp_usr); + __DECL_REG(x14, lr_usr); + + __DECL_REG(x15, __unused_sp_hyp); + + __DECL_REG(x16, lr_irq); + __DECL_REG(x17, sp_irq); + + __DECL_REG(x18, lr_svc); + __DECL_REG(x19, sp_svc); + + __DECL_REG(x20, lr_abt); + __DECL_REG(x21, sp_abt); + + __DECL_REG(x22, lr_und); + __DECL_REG(x23, sp_und); + + __DECL_REG(x24, r8_fiq); + __DECL_REG(x25, r9_fiq); + __DECL_REG(x26, r10_fiq); + __DECL_REG(x27, r11_fiq); + __DECL_REG(x28, r12_fiq); + + __DECL_REG(x29, sp_fiq); + __DECL_REG(x30, lr_fiq); + + /* Return address and mode */ + __DECL_REG(pc64, pc32); /* ELR_EL2 */ + uint64_t cpsr; /* SPSR_EL2 */ + + union { + uint64_t spsr_el1; /* AArch64 */ + uint32_t spsr_svc; /* AArch32 */ + }; + + /* AArch32 guests only */ + uint32_t spsr_fiq, spsr_irq, spsr_und, spsr_abt; + + /* AArch64 guests only */ + uint64_t sp_el0; + uint64_t sp_el1, elr_el1; +}; +typedef struct vcpu_guest_core_regs vcpu_guest_core_regs_t; +DEFINE_XEN_GUEST_HANDLE(vcpu_guest_core_regs_t); + +#undef __DECL_REG + +struct vcpu_guest_context { +#define _VGCF_online 0 +#define VGCF_online (1<<_VGCF_online) + uint32_t flags; /* VGCF_* */ + + struct vcpu_guest_core_regs user_regs; /* Core CPU registers */ + + uint64_t sctlr; + uint64_t ttbcr, ttbr0, ttbr1; +}; +typedef struct vcpu_guest_context vcpu_guest_context_t; +DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); + +/* + * struct xen_arch_domainconfig's ABI is covered by + * XEN_DOMCTL_INTERFACE_VERSION. + */ +#define XEN_DOMCTL_CONFIG_GIC_NATIVE 0 +#define XEN_DOMCTL_CONFIG_GIC_V2 1 +#define XEN_DOMCTL_CONFIG_GIC_V3 2 + +#define XEN_DOMCTL_CONFIG_TEE_NONE 0 +#define XEN_DOMCTL_CONFIG_TEE_OPTEE 1 + +struct xen_arch_domainconfig { + /* IN/OUT */ + uint8_t gic_version; + /* IN */ + uint16_t tee_type; + /* IN */ + uint32_t nr_spis; + /* + * OUT + * Based on the property clock-frequency in the DT timer node. + * The property may be present when the bootloader/firmware doesn't + * set correctly CNTFRQ which hold the timer frequency. + * + * As it's not possible to trap this register, we have to replicate + * the value in the guest DT. + * + * = 0 => property not present + * > 0 => Value of the property + * + */ + uint32_t clock_frequency; +}; + +struct arch_vcpu_info { +}; +typedef struct arch_vcpu_info arch_vcpu_info_t; + +struct arch_shared_info { +}; +typedef struct arch_shared_info arch_shared_info_t; +typedef uint64_t xen_callback_t; + +#endif + +/* PSR bits (CPSR, SPSR) */ + +#define PSR_THUMB (1<<5) /* Thumb Mode enable */ +#define PSR_FIQ_MASK (1<<6) /* Fast Interrupt mask */ +#define PSR_IRQ_MASK (1<<7) /* Interrupt mask */ +#define PSR_ABT_MASK (1<<8) /* Asynchronous Abort mask */ +#define PSR_BIG_ENDIAN (1<<9) /* arm32: Big Endian Mode */ +#define PSR_DBG_MASK (1<<9) /* arm64: Debug Exception mask */ +#define PSR_IT_MASK (0x0600fc00) /* Thumb If-Then Mask */ +#define PSR_JAZELLE (1<<24) /* Jazelle Mode */ + +/* 32 bit modes */ +#define PSR_MODE_USR 0x10 +#define PSR_MODE_FIQ 0x11 +#define PSR_MODE_IRQ 0x12 +#define PSR_MODE_SVC 0x13 +#define PSR_MODE_MON 0x16 +#define PSR_MODE_ABT 0x17 +#define PSR_MODE_HYP 0x1a +#define PSR_MODE_UND 0x1b +#define PSR_MODE_SYS 0x1f + +/* 64 bit modes */ +#define PSR_MODE_BIT 0x10 /* Set iff AArch32 */ +#define PSR_MODE_EL3h 0x0d +#define PSR_MODE_EL3t 0x0c +#define PSR_MODE_EL2h 0x09 +#define PSR_MODE_EL2t 0x08 +#define PSR_MODE_EL1h 0x05 +#define PSR_MODE_EL1t 0x04 +#define PSR_MODE_EL0t 0x00 + +#define PSR_GUEST32_INIT (PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_SVC) +#define PSR_GUEST64_INIT (PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_EL1h) + +#define SCTLR_GUEST_INIT xen_mk_ullong(0x00c50078) + +/* + * Virtual machine platform (memory layout, interrupts) + * + * These are defined for consistency between the tools and the + * hypervisor. Guests must not rely on these hardcoded values but + * should instead use the FDT. + */ + +/* Physical Address Space */ + +/* + * vGIC mappings: Only one set of mapping is used by the guest. + * Therefore they can overlap. + */ + +/* vGIC v2 mappings */ +#define GUEST_GICD_BASE xen_mk_ullong(0x03001000) +#define GUEST_GICD_SIZE xen_mk_ullong(0x00001000) +#define GUEST_GICC_BASE xen_mk_ullong(0x03002000) +#define GUEST_GICC_SIZE xen_mk_ullong(0x00002000) + +/* vGIC v3 mappings */ +#define GUEST_GICV3_GICD_BASE xen_mk_ullong(0x03001000) +#define GUEST_GICV3_GICD_SIZE xen_mk_ullong(0x00010000) + +#define GUEST_GICV3_RDIST_REGIONS 1 + +#define GUEST_GICV3_GICR0_BASE xen_mk_ullong(0x03020000) /* vCPU0..127 */ +#define GUEST_GICV3_GICR0_SIZE xen_mk_ullong(0x01000000) + +/* ACPI tables physical address */ +#define GUEST_ACPI_BASE xen_mk_ullong(0x20000000) +#define GUEST_ACPI_SIZE xen_mk_ullong(0x02000000) + +/* PL011 mappings */ +#define GUEST_PL011_BASE xen_mk_ullong(0x22000000) +#define GUEST_PL011_SIZE xen_mk_ullong(0x00001000) + +/* + * 16MB == 4096 pages reserved for guest to use as a region to map its + * grant table in. + */ +#define GUEST_GNTTAB_BASE xen_mk_ullong(0x38000000) +#define GUEST_GNTTAB_SIZE xen_mk_ullong(0x01000000) + +#define GUEST_MAGIC_BASE xen_mk_ullong(0x39000000) +#define GUEST_MAGIC_SIZE xen_mk_ullong(0x01000000) + +#define GUEST_RAM_BANKS 2 + +#define GUEST_RAM0_BASE xen_mk_ullong(0x40000000) /* 3GB of low RAM @ 1GB */ +#define GUEST_RAM0_SIZE xen_mk_ullong(0xc0000000) + +#define GUEST_RAM1_BASE xen_mk_ullong(0x0200000000) /* 1016GB of RAM @ 8GB */ +#define GUEST_RAM1_SIZE xen_mk_ullong(0xfe00000000) + +#define GUEST_RAM_BASE GUEST_RAM0_BASE /* Lowest RAM address */ +/* Largest amount of actual RAM, not including holes */ +#define GUEST_RAM_MAX (GUEST_RAM0_SIZE + GUEST_RAM1_SIZE) +/* Suitable for e.g. const uint64_t ramfoo[] = GUEST_RAM_BANK_FOOS; */ +#define GUEST_RAM_BANK_BASES { GUEST_RAM0_BASE, GUEST_RAM1_BASE } +#define GUEST_RAM_BANK_SIZES { GUEST_RAM0_SIZE, GUEST_RAM1_SIZE } + +/* Current supported guest VCPUs */ +#define GUEST_MAX_VCPUS 128 + +/* Interrupts */ +#define GUEST_TIMER_VIRT_PPI 27 +#define GUEST_TIMER_PHYS_S_PPI 29 +#define GUEST_TIMER_PHYS_NS_PPI 30 +#define GUEST_EVTCHN_PPI 31 + +#define GUEST_VPL011_SPI 32 + +/* PSCI functions */ +#define PSCI_cpu_suspend 0 +#define PSCI_cpu_off 1 +#define PSCI_cpu_on 2 +#define PSCI_migrate 3 + +#ifndef __ASSEMBLY__ +/* Stub definition of PMU structure */ +typedef struct xen_pmu_arch { uint8_t dummy; } xen_pmu_arch_t; +#endif + +#endif /* XEN_PUBLIC_ARCH_ARM_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/include/xen/features.h b/include/xen/features.h new file mode 100644 index 00000000..9ea25e90 --- /dev/null +++ b/include/xen/features.h @@ -0,0 +1,107 @@ +/* + * Xen public feature flags, reported by XENVER_get_features + */ + +#ifndef __XEN_PUBLIC_FEATURES_H__ +#define __XEN_PUBLIC_FEATURES_H__ + +/* + * If set, the guest does not need to write-protect its pagetables, and can + * update them via direct writes. + */ +#define XENFEAT_writable_page_tables 0 + +/* + * If set, the guest does not need to write-protect its segment descriptor + * tables, and can update them via direct writes. + */ +#define XENFEAT_writable_descriptor_tables 1 + +/* + * If set, translation between the guest's 'pseudo-physical' address space + * and the host's machine address space are handled by the hypervisor. In this + * mode the guest does not need to perform phys-to/from-machine translations + * when performing page table operations. + */ +#define XENFEAT_auto_translated_physmap 2 + +/* If set, the guest is running in supervisor mode (e.g., x86 ring 0). */ +#define XENFEAT_supervisor_mode_kernel 3 + +/* + * If set, the guest does not need to allocate x86 PAE page directories + * below 4GB. This flag is usually implied by auto_translated_physmap. + */ +#define XENFEAT_pae_pgdir_above_4gb 4 + +/* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */ +#define XENFEAT_mmu_pt_update_preserve_ad 5 + +/* x86: Does this Xen host support the MMU_{CLEAR,COPY}_PAGE hypercall? */ +#define XENFEAT_highmem_assist 6 + +/* + * If set, GNTTABOP_map_grant_ref honors flags to be placed into guest kernel + * available pte bits. + */ +#define XENFEAT_gnttab_map_avail_bits 7 + +/* x86: Does this Xen host support the HVM callback vector type? */ +#define XENFEAT_hvm_callback_vector 8 + +/* x86: pvclock algorithm is safe to use on HVM */ +#define XENFEAT_hvm_safe_pvclock 9 + +/* x86: pirq can be used by HVM guests */ +#define XENFEAT_hvm_pirqs 10 + +/* operation as Dom0 is supported */ +#define XENFEAT_dom0 11 + +/* Xen also maps grant references at pfn = mfn. + * This feature flag is deprecated and should not be used. +#define XENFEAT_grant_map_identity 12 + */ + +/* Guest can use XENMEMF_vnode to specify virtual node for memory op. */ +#define XENFEAT_memory_op_vnode_supported 13 + +/* arm: Hypervisor supports ARM SMC calling convention. */ +#define XENFEAT_ARM_SMCCC_supported 14 + +/* + * x86/PVH: If set, ACPI RSDP can be placed at any address. Otherwise RSDP + * must be located in lower 1MB, as required by ACPI Specification for IA-PC + * systems. + * This feature flag is only consulted if XEN_ELFNOTE_GUEST_OS contains + * the "linux" string. + */ +#define XENFEAT_linux_rsdp_unrestricted 15 + +/* + * A direct-mapped (or 1:1 mapped) domain is a domain for which its + * local pages have gfn == mfn. If a domain is direct-mapped, + * XENFEAT_direct_mapped is set; otherwise XENFEAT_not_direct_mapped + * is set. + * + * If neither flag is set (e.g. older Xen releases) the assumptions are: + * - not auto_translated domains (x86 only) are always direct-mapped + * - on x86, auto_translated domains are not direct-mapped + * - on ARM, Dom0 is direct-mapped, DomUs are not + */ +#define XENFEAT_not_direct_mapped 16 +#define XENFEAT_direct_mapped 17 + +#define XENFEAT_NR_SUBMAPS 1 + +#endif /* __XEN_PUBLIC_FEATURES_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/include/xen/version.h b/include/xen/version.h index 45ce490b..67b59784 100644 --- a/include/xen/version.h +++ b/include/xen/version.h @@ -24,6 +24,16 @@ typedef struct xen_compile_info xen_compile_info_t; #define XENVER_changeset 4 typedef char xen_changeset_info_t[64]; +#define XENVER_get_features 6 +struct xen_feature_info { + unsigned int submap_idx; /* IN: which 32-bit submap to return */ + uint32_t submap; /* OUT: 32-bit submap */ +}; +typedef struct xen_feature_info xen_feature_info_t; + +/* Declares the features reported by XENVER_get_features. */ +#include "features.h" + #endif /* __XEN_PUBLIC_VERSION_H__ */ /* diff --git a/include/xen/xen.h b/include/xen/xen.h index 11af1677..9ea6024f 100644 --- a/include/xen/xen.h +++ b/include/xen/xen.h @@ -7,6 +7,8 @@ #if defined(__i386__) || defined(__x86_64__) #include "arch-x86/xen.h" +#elif defined(__arm__) || defined (__aarch64__) +#include "arch-arm.h" #else #error Bad architecture #endif diff --git a/include/xtf/hypercall.h b/include/xtf/hypercall.h index fcd16dc3..917fcc74 100644 --- a/include/xtf/hypercall.h +++ b/include/xtf/hypercall.h @@ -1,36 +1,15 @@ #ifndef XTF_HYPERCALL_H #define XTF_HYPERCALL_H -#include -#include -#include -#include - -#if defined(__x86_64__) - -# include -# define HYPERCALL0 _hypercall64_0 -# define HYPERCALL1 _hypercall64_1 -# define HYPERCALL2 _hypercall64_2 -# define HYPERCALL3 _hypercall64_3 -# define HYPERCALL4 _hypercall64_4 -# define HYPERCALL5 _hypercall64_5 - -#elif defined(__i386__) - -# include -# define HYPERCALL0 _hypercall32_0 -# define HYPERCALL1 _hypercall32_1 -# define HYPERCALL2 _hypercall32_2 -# define HYPERCALL3 _hypercall32_3 -# define HYPERCALL4 _hypercall32_4 -# define HYPERCALL5 _hypercall32_5 - -#else -# error Bad architecture for hypercalls -#endif - -extern uint8_t hypercall_page[PAGE_SIZE]; +/* + * Each architecture needs to define its own hypercall handling interface. + * The hypercall handler should be named as follows: + * hypercall_ + * e.g. hypercall_console_io + * The reason for that is to have a standard way of calling hypercalls + * in the common code. + */ +#include /* All Xen ABI for includers convenience .*/ #include @@ -49,145 +28,7 @@ extern uint8_t hypercall_page[PAGE_SIZE]; #include #include -/* - * Hypercall primatives, compiled for the correct bitness - */ -static inline long hypercall_set_trap_table(const struct xen_trap_info *ti) -{ - return HYPERCALL1(long, __HYPERVISOR_set_trap_table, ti); -} - -static inline long hypercall_mmu_update(const mmu_update_t reqs[], - unsigned int count, - unsigned int *done, - unsigned int foreigndom) -{ - return HYPERCALL4(long, __HYPERVISOR_mmu_update, - reqs, count, done, foreigndom); -} - -static inline long hypercall_set_gdt(const unsigned long *mfns, - unsigned int entries) -{ - return HYPERCALL2(long, __HYPERVISOR_set_gdt, mfns, entries); -} - -static inline long hypercall_stack_switch(const unsigned int ss, const void *sp) -{ - return HYPERCALL2(long, __HYPERVISOR_stack_switch, ss, sp); -} - -static inline long hypercall_update_descriptor(uint64_t maddr, user_desc desc) -{ -#ifdef __x86_64__ - return HYPERCALL2(long, __HYPERVISOR_update_descriptor, maddr, desc.raw); -#else - return HYPERCALL4(long, __HYPERVISOR_update_descriptor, - maddr, maddr >> 32, desc.lo, desc.hi); -#endif -} - -static inline long hypercall_memory_op(unsigned int cmd, void *arg) -{ - return HYPERCALL2(long, __HYPERVISOR_memory_op, cmd, arg); -} - -static inline long hypercall_multicall(struct multicall_entry *list, - unsigned int nr) -{ - return HYPERCALL2(long, __HYPERVISOR_multicall, list, nr); -} - -/* - * This hypercall is misnamed in the Xen ABI, and actually operates on a - * linear address, not a virtual address. - */ -static inline long hypercall_update_va_mapping( - unsigned long linear, uint64_t npte, enum XEN_UVMF flags) -{ -#ifdef __x86_64__ - return HYPERCALL3(long, __HYPERVISOR_update_va_mapping, linear, npte, flags); -#else - return HYPERCALL4(long, __HYPERVISOR_update_va_mapping, - linear, npte, npte >> 32, flags); -#endif -} - -static inline long hypercall_xen_version(unsigned int cmd, void *arg) -{ - return HYPERCALL2(long, __HYPERVISOR_xen_version, cmd, arg); -} - -static inline long hypercall_grant_table_op(unsigned int cmd, void *args, - unsigned int count) -{ - return HYPERCALL3(long, __HYPERVISOR_grant_table_op, cmd, args, count); -} - -static inline long hypercall_vm_assist(unsigned int cmd, unsigned int type) -{ - return HYPERCALL2(long, __HYPERVISOR_vm_assist, cmd, type); -} - -static inline long hypercall_vcpu_op(unsigned int cmd, unsigned int vcpu, - void *extra) -{ - return HYPERCALL3(long, __HYPERVISOR_vcpu_op, cmd, vcpu, extra); -} - -static inline long hypercall_mmuext_op(const mmuext_op_t ops[], - unsigned int count, - unsigned int *done, - unsigned int foreigndom) -{ - return HYPERCALL4(long, __HYPERVISOR_mmuext_op, - ops, count, done, foreigndom); -} - -static inline long hypercall_sched_op(unsigned int cmd, void *arg) -{ - return HYPERCALL2(long, __HYPERVISOR_sched_op, cmd, arg); -} - -static inline long hypercall_callback_op(unsigned int cmd, const void *arg) -{ - return HYPERCALL2(long, __HYPERVISOR_callback_op, cmd, arg); -} - -static inline long hypercall_event_channel_op(unsigned int cmd, void *arg) -{ - return HYPERCALL2(long, __HYPERVISOR_event_channel_op, cmd, arg); -} - -static inline long hypercall_physdev_op(unsigned int cmd, void *arg) -{ - return HYPERCALL2(long, __HYPERVISOR_physdev_op, cmd, arg); -} - -static inline long hypercall_hvm_op(unsigned int cmd, void *arg) -{ - return HYPERCALL2(long, __HYPERVISOR_hvm_op, cmd, arg); -} - -static inline long hypercall_sysctl(xen_sysctl_t *arg) -{ - return HYPERCALL1(long, __HYPERVISOR_sysctl, arg); -} - -static inline long hypercall_argo_op(unsigned int cmd, void *arg1, void *arg2, - unsigned long arg3, unsigned long arg4) -{ - return HYPERCALL5(long, __HYPERVISOR_argo_op, cmd, arg1, arg2, arg3, arg4); -} - -/* - * Higher level hypercall helpers - */ -static inline void hypercall_console_write(const char *buf, unsigned long count) -{ - (void)HYPERCALL3(long, __HYPERVISOR_console_io, CONSOLEIO_write, count, buf); -} - +/* Common hypercall helpers */ static inline long hypercall_shutdown(unsigned int reason) { return hypercall_sched_op(SCHEDOP_shutdown, &reason); @@ -205,11 +46,6 @@ static inline long hypercall_poll(evtchn_port_t port) return hypercall_sched_op(SCHEDOP_poll, &poll); } -static inline int hypercall_register_callback(const xen_callback_register_t *arg) -{ - return hypercall_callback_op(CALLBACKOP_register, arg); -} - static inline int hypercall_evtchn_send(evtchn_port_t port) { return hypercall_event_channel_op(EVTCHNOP_send, &port); diff --git a/include/xtf/lib.h b/include/xtf/lib.h index 3348464b..8afdcf2e 100644 --- a/include/xtf/lib.h +++ b/include/xtf/lib.h @@ -5,9 +5,9 @@ #include #include -#if defined(__i386__) +#if defined(__i386__) || defined(__arm__) # define BYTES_PER_LONG 4 -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__aarch64__) # define BYTES_PER_LONG 8 #else # errror Bad width @@ -36,6 +36,11 @@ void __noreturn panic(const char *fmt, ...) __printf(1, 2); ((void)sizeof(struct { char: -!!(cond); })) #endif +#define UNIMPLEMENTED() do { \ + panic("Unimplemented function -> %s:%u\n", \ + __FILE__, __LINE__); \ +} while(0) + #define min(a, b) \ ({ \ const typeof(a) _a = (a); \ diff --git a/xtf-runner b/xtf-runner index 6352a5b3..54dee6f9 100755 --- a/xtf-runner +++ b/xtf-runner @@ -49,8 +49,16 @@ all_categories = default_categories | non_default_categories # All test environments pv_environments = set(("pv64", "pv32pae")) hvm_environments = set(("hvm64", "hvm32pae", "hvm32pse", "hvm32")) -all_environments = pv_environments | hvm_environments +arm_environments = set(["mmu64le"]) +all_environments = pv_environments | hvm_environments | arm_environments +# Unsupported environments from xtf-runner point of view. +# Exmaple: arm's environment 64le does not have pv console support hence +# it cannot be run using xtf-runner. +unsupported_envs = set(["64le"]) + +# All sub-architectures +all_subarchs = set(("x86", "arm")) class RunnerError(Exception): """ Errors relating to xtf-runner itself """ @@ -60,7 +68,11 @@ class TestInstance(object): def __init__(self, arg): """ Parse and verify 'arg' as a test instance. """ - self.env, self.name, self.variation = parse_test_instance_string(arg) + self.subarch, self.env, self.name, self.variation = \ + parse_test_instance_string(arg) + + if self.subarch is None: + raise RunnerError("No subarch for '{0}'".format(arg)) if self.env is None: raise RunnerError("No environment for '{0}'".format(arg)) @@ -79,9 +91,10 @@ class TestInstance(object): def __repr__(self): if not self.variation: - return "test-{0}-{1}".format(self.env, self.name) + return "test-{0}-{1}-{2}".format(self.subarch, self.env, self.name) else: - return "test-{0}-{1}~{2}".format(self.env, self.name, self.variation) + return "test-{0}-{1}-{2}~{3}".format( + self.subarch, self.env, self.name, self.variation) def __hash__(self): return hash(repr(self)) @@ -111,6 +124,12 @@ class TestInfo(object): .format(type(name))) self.name = name + subarch = test_json["subarch"] + if not isinstance(subarch, basestring): + raise TypeError("Expected string for 'subarch', got '{0}'" + .format(type(subarch))) + self.subarch = subarch + cat = test_json["category"] if not isinstance(cat, basestring): raise TypeError("Expected string for 'category', got '{0}'" @@ -120,6 +139,11 @@ class TestInfo(object): self.cat = cat envs = test_json["environments"] + # Remove unsupported environments from envs + for env in unsupported_envs: + if env in envs: + envs.remove(env) + if not isinstance(envs, list): raise TypeError("Expected list for 'environments', got '{0}'" .format(type(envs))) @@ -156,10 +180,12 @@ class TestInfo(object): if variations: for env in envs: for vary in variations: - res.append(TestInstance("test-{0}-{1}~{2}" - .format(env, self.name, vary))) + res.append(TestInstance("test-{0}-{1}-{2}~{3}" + .format(self.subarch, env, + self.name, vary))) else: - res = [ TestInstance("test-{0}-{1}".format(env, self.name)) + res = [ TestInstance("test-{0}-{1}-{2}" + .format(self.subarch, env, self.name)) for env in envs ] return res @@ -170,19 +196,21 @@ class TestInfo(object): def parse_test_instance_string(arg): """Parse a test instance string. - Has the form: '[[test-]$ENV-]$NAME[~$VARIATION]' + Has the form: '[[test-]$SUBARCH-]$ENV-]$NAME[~$VARIATION]' Optional 'test-' prefix + Optional $SUBARCH Optional $ENV environment part Mandatory $NAME Optional ~$VARIATION suffix Verifies: - $NAME is valid + - if $SUBARCH, it is valid for $NAME - if $ENV, it is valid for $NAME - if $VARIATION, it is valid for $NAME - Returns: tuple($ENV or None, $NAME, $VARIATION or None) + Returns: tuple($SUBARCH or None, $ENV or None, $NAME, $VARIATION or None) """ all_tests = get_all_test_info() @@ -191,27 +219,33 @@ def parse_test_instance_string(arg): if '~' in arg: arg, variation = arg.split('~', 1) - parts = arg.split('-', 2) + parts = arg.split('-', 3) parts_len = len(parts) - # If arg =~ test-$ENV-$NAME - if parts_len == 3 and parts[0] == "test" and parts[1] in all_environments: - _, env, name = parts + # If arg =~ test-$SUBARCH-$ENV-$NAME + if parts_len == 4 and parts[0] == "test" and parts[1] in all_subarchs and \ + parts[2] in all_environments: + _, subarch, env, name = parts + + # If arg =~ $SUBARCH-$ENV-$NAME + elif parts_len == 3 and parts[0] in all_subarchs and \ + parts[1] in all_environments: + subarch, env, name = parts[0], parts[1], "-".join(parts[2:]) # If arg =~ $ENV-$NAME - elif parts_len > 0 and parts[0] in all_environments: - env, name = parts[0], "-".join(parts[1:]) + elif parts_len == 2 and parts[0] in all_environments: + subarch, env, name = None, parts[0], "-".join(parts[1:]) # If arg =~ $NAME elif arg in all_tests: - env, name = None, arg + subarch, env, name = None, None, arg # Otherwise, give up else: raise RunnerError("Unrecognised test '{0}'".format(arg)) - # At this point, 'env' has always been checked for plausibility. 'name' - # might not be + # At this point, 'env' and 'subarch' have always been checked for + # plausibility. 'name' might not be if name not in all_tests: raise RunnerError("Unrecognised test name '{0}' for '{1}'" @@ -223,6 +257,10 @@ def parse_test_instance_string(arg): raise RunnerError("Test '{0}' has no environment '{1}'" .format(name, env)) + if subarch and subarch not in info.subarch: + raise RunnerError("Test '{0}' has no subarch '{1}'" + .format(name, subarch)) + # If a variation has been given, check it is valid if variation is not None: if not info.variations: @@ -231,7 +269,7 @@ def parse_test_instance_string(arg): raise RunnerError("No variation '{0}' for test '{1}'" .format(variation, name)) - return env, name, variation + return subarch, env, name, variation # Cached test json from disk @@ -383,7 +421,7 @@ def interpret_selection(opts): # Second, sanity check others as full or partial test names for arg in others: - env, name, vary = parse_test_instance_string(arg) + _, env, name, vary = parse_test_instance_string(arg) instances = all_tests[name].all_instances( env_filter = env and [env] or None, @@ -669,8 +707,8 @@ def main(): " ./xtf-runner pv-iopl\n" " \n" " Combined test results:\n" - " test-pv64-pv-iopl SUCCESS\n" - " test-pv32pae-pv-iopl SUCCESS\n" + " test-x86-pv64-pv-iopl SUCCESS\n" + " test-x86-pv32pae-pv-iopl SUCCESS\n" "\n" " Exit code for this script:\n" " 0: everything is ok\n"