From 4f744ebc76135fd69d39a696167fee2ba99a2d75 Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Wed, 18 Aug 2021 13:58:29 +0200 Subject: [PATCH 01/12] build: Modify build system to support multiple architectures Currently XTF build system is strictly made up for x86. Modify the build system so that it will be easier to add other architectures to XTF in the future. This is done by generalizing the common makefiles to be architecture independent and creating architecture specific makefiles. ARCH variable behaviour: By default ARCH is set to the host architecture where make is executed, provided that it is supported by XTF. In order to perform cross compilation, ARCH needs to be set to the target architecture (when invoking make) e.g. ARCH=x86, together with specifying cross compiler prefix e.g. CROSS_COMPILE=x86_64-linux-gnu-. Introduce new variable called BASE_ARCH that contains the name of the architecture devoided of information about bitness. It may be that BASE_ARCH == ARCH for some architectures. For example: ARCH=x86, BASE_ARCH=x86 ARCH=arm{64,32}, BASE_ARCH=arm ARCH=riscv{64,32}, BASE_ARCH=riscv Signed-off-by: Michal Orzel --- INSTALL | 12 +++++++ Makefile | 29 +++++++++++++++-- build/common.mk | 45 +++++++++++---------------- build/gen.mk | 22 +++++++------ build/x86/arch-common.mk | 36 +++++++++++++++++++++ build/{files.mk => x86/arch-files.mk} | 12 ++----- docs/mainpage.dox | 3 ++ 7 files changed, 112 insertions(+), 47 deletions(-) create mode 100644 build/x86/arch-common.mk rename build/{files.mk => x86/arch-files.mk} (87%) diff --git a/INSTALL b/INSTALL index ed19623b..a88a799f 100644 --- a/INSTALL +++ b/INSTALL @@ -2,6 +2,18 @@ Xen Test Framework Build requirements: - GNU Make >= 3.81 + +For x86: - GNU compatible compiler, capable of: -std=gnu99 -m64 and -m32 + +By default ARCH is set to the host architecture where make is executed, +provided that it is supported by XTF. +In order to perform cross compilation, ARCH needs to be set to the target +architecture (when invoking make) e.g. ARCH=x86, together with specifying +cross compiler prefix e.g. CROSS_COMPILE=x86_64-linux-gnu-. + +To build XTF: +-for x86: +make ARCH=x86 CROSS_COMPILE= diff --git a/Makefile b/Makefile index b6e0dd8b..ec48c3cc 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ MAKEFLAGS += -rR ROOT := $(abspath $(CURDIR)) -export ROOT # Default to the all rule all: @@ -25,7 +24,33 @@ endif xtftestdir := $(xtfdir)/tests -export DESTDIR xtfdir xtftestdir +# Supported architectures +SUPPORTED_ARCH := x86 + +# By default ARCH is set to the host architecture where make is executed, +# provided that it is supported by XTF. +# In order to perform cross compilation, ARCH needs to be set to the target +# architecture (when invoking make) e.g. ARCH=x86, together with specifying +# cross compiler prefix e.g. CROSS_COMPILE=x86_64-linux-gnu-. + +# Read machine hardware name using 'uname -m' and try to match it with the list +# of architectures passed as the first argument (space separated). +match-arch = $(shell echo $(1) | grep -w -q $(shell uname -m 2>/dev/null || \ + echo none) && echo y || echo n) + +# Set ARCH to the host architecture +ifeq ($(call match-arch, x86_64 i386),y) +ARCH ?= x86 +else +ARCH ?= none +endif + +# 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 diff --git a/build/common.mk b/build/common.mk index f81b2dab..2fadcb43 100644 --- a/build/common.mk +++ b/build/common.mk @@ -1,21 +1,7 @@ -ALL_CATEGORIES := special functional xsa utility in-development +# Architecture independent/common configuration -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 +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 +11,32 @@ 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/$(BASE_ARCH)/include +COMMON_AFLAGS += -I$(ROOT)/arch/$(BASE_ARCH)/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,7 +45,7 @@ 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 -link-$(1) := $(ROOT)/arch/x86/link-$(1).lds +link-$(1) := $(ROOT)/arch/$(BASE_ARCH)/link-$(1).lds LDFLAGS_$(1) := -T $$(link-$(1)) -nostdlib $(LDFLAGS-y) @@ -84,6 +76,7 @@ DEPS-$(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..a6f3fc68 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 @@ -44,20 +44,20 @@ 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 +# If any environment needs a special compilation/linking recipe instead of +# the default one, a custom recipe called build-$(env) e.g. build-hvm64 +# should be created in $(ROOT)/build/$(ARCH)/arch-common.mk + test-$(1)-$(NAME): $$(DEPS-$(1)) $$(link-$(1)) +ifndef build-$(1) + @# Generic link line for most environments $(LD) $$(LDFLAGS_$(1)) $$(DEPS-$(1)) -o $$@ 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 + @# Environment specific compilation recipe + $(call build-$(1)) endif cfg-$(1) ?= $(defcfg-$($(1)_guest)) @@ -91,6 +91,8 @@ install-$(1).cfg: $(filter test-$(1)-%,$(TEST-CFGS)) 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 diff --git a/build/x86/arch-common.mk b/build/x86/arch-common.mk new file mode 100644 index 00000000..213317bb --- /dev/null +++ b/build/x86/arch-common.mk @@ -0,0 +1,36 @@ +# Architecture specific configuration for x86 + +# BASE_ARCH is the architecture name devoided of information about bitness. +# It may be that BASE_ARCH == ARCH for some architectures. +BASE_ARCH := 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 87% rename from build/files.mk rename to build/x86/arch-files.mk index af31c659..f358545d 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 @@ -18,6 +15,7 @@ obj-perarch += $(ROOT)/common/setup.o obj-perarch += $(ROOT)/common/xenbus.o obj-perarch += $(ROOT)/common/weak-defaults.o +# Per environment obj-perenv += $(ROOT)/arch/x86/decode.o obj-perenv += $(ROOT)/arch/x86/desc.o obj-perenv += $(ROOT)/arch/x86/extable.o @@ -27,7 +25,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 @@ -42,18 +39,15 @@ 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/head.o 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/docs/mainpage.dox b/docs/mainpage.dox index d9558d62..d1ae067a 100644 --- a/docs/mainpage.dox +++ b/docs/mainpage.dox @@ -50,7 +50,10 @@ To obtain and build: $ git clone git://xenbits.xen.org/xtf.git $ cd xtf + # To build natively (by default ARCH targets the host architecture) $ make -j4 + # To build for x86 + $ make ARCH=x86 CROSS_COMPILE= To run tests on a Xen host: (see @ref errata first) From adeea3a06d372498453abfd8153fec38b9790e78 Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Tue, 15 Mar 2022 08:40:00 +0100 Subject: [PATCH 02/12] arm: Add initial architecture code for arm64 and arm32 Add initial support to XTF for arm64/arm32 without modifying existing XTF architecture. Some of the files are just dummy files waiting to be properly implemented step by step later on. The purpose of this change is to add the initial code and minimal set of files to support XTF on arm without modifying the existing XTF design. This creates a base for further implementation. Based-on-the-work-from: Julien Grall Signed-off-by: Michal Orzel --- arch/arm/arm32/head.S | 61 ++++++++++++++++++ arch/arm/arm64/head.S | 76 ++++++++++++++++++++++ arch/arm/include/arch/arm32/regs.h | 71 ++++++++++++++++++++ arch/arm/include/arch/arm64/regs.h | 100 +++++++++++++++++++++++++++++ arch/arm/include/arch/asm_macros.h | 26 ++++++++ arch/arm/include/arch/barrier.h | 41 ++++++++++++ arch/arm/include/arch/bitops.h | 45 +++++++++++++ arch/arm/include/arch/config.h | 35 ++++++++++ arch/arm/include/arch/desc.h | 16 +++++ arch/arm/include/arch/div.h | 35 ++++++++++ arch/arm/include/arch/extable.h | 19 ++++++ arch/arm/include/arch/hypercall.h | 45 +++++++++++++ arch/arm/include/arch/page.h | 24 +++++++ arch/arm/include/arch/regs.h | 25 ++++++++ arch/arm/include/arch/traps.h | 17 +++++ arch/arm/include/arch/xtf.h | 17 +++++ arch/arm/link.lds.S | 59 +++++++++++++++++ arch/arm/setup.c | 18 ++++++ 18 files changed, 730 insertions(+) create mode 100644 arch/arm/arm32/head.S create mode 100644 arch/arm/arm64/head.S create mode 100644 arch/arm/include/arch/arm32/regs.h create mode 100644 arch/arm/include/arch/arm64/regs.h create mode 100644 arch/arm/include/arch/asm_macros.h create mode 100644 arch/arm/include/arch/barrier.h create mode 100644 arch/arm/include/arch/bitops.h create mode 100644 arch/arm/include/arch/config.h create mode 100644 arch/arm/include/arch/desc.h create mode 100644 arch/arm/include/arch/div.h create mode 100644 arch/arm/include/arch/extable.h create mode 100644 arch/arm/include/arch/hypercall.h create mode 100644 arch/arm/include/arch/page.h create mode 100644 arch/arm/include/arch/regs.h create mode 100644 arch/arm/include/arch/traps.h create mode 100644 arch/arm/include/arch/xtf.h create mode 100644 arch/arm/link.lds.S create mode 100644 arch/arm/setup.c diff --git a/arch/arm/arm32/head.S b/arch/arm/arm32/head.S new file mode 100644 index 00000000..15d2ac33 --- /dev/null +++ b/arch/arm/arm32/head.S @@ -0,0 +1,61 @@ +#include +#include +#include + +#define ZIMAGE_MAGIC_NUMBER 0x016f2818 + +/* + * Print a string on the debug console + * + * Clobbers: r0, r1, r2, r3, r12 + */ +#define PRINT(s) \ + ldr r2, =98f; \ + add r2, r2, r9; \ + mov r1, #0; \ +97: ldrb r3, [r2, r1]; \ + add r1, r1, #1; \ + cmp r3, #0; \ + bne 97b; \ + mov r0, #CONSOLEIO_write; \ + mov r12, #__HYPERVISOR_console_io; \ + __HVC(XEN_HYPERCALL_TAG); \ +.pushsection .rodata.str, "aMS", %progbits, 1; \ +98: .asciz s; \ +.popsection + +.section ".text.head", "ax", %progbits +.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 */ + + PRINT("- XTF booting -\n") + + /* Start an infinite loop */ + PRINT("- Infinite loop -\n") +1: b 1b diff --git a/arch/arm/arm64/head.S b/arch/arm/arm64/head.S new file mode 100644 index 00000000..9fa0f6aa --- /dev/null +++ b/arch/arm/arm64/head.S @@ -0,0 +1,76 @@ +#include +#include +#include + +/* 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)) + +/* + * Print a string on the debug console + * + * Clobbers: x0, x1, x2, x3, x16 + */ +#define PRINT(s) \ + adr x2, 98f; \ + 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; \ +.pushsection .rodata.str, "aMS", %progbits, 1; \ +98: .asciz s; \ +.popsection + +.section ".bss.page_aligned" +.p2align PAGE_SHIFT + +.section ".text.head", "ax", @progbits + 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) + /* Save DTB pointer */ + mov x20, x0 + + /* Calculate where we are */ + ldr x22, =_start /* x22 := vaddr(_start) */ + adr x21, _start /* x21 := paddr(_start) */ + sub x21, x21, x22 /* x21 := phys-offset */ + + PRINT("- XTF booting -\n") + + /* Start an infinite loop */ + PRINT("- Infinite loop -\n") +1: b 1b 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/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/asm_macros.h b/arch/arm/include/arch/asm_macros.h new file mode 100644 index 00000000..186fd727 --- /dev/null +++ b/arch/arm/include/arch/asm_macros.h @@ -0,0 +1,26 @@ +/** + * @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 + +#ifdef CONFIG_ARM_32 +#define __HVC(imm16) .long \ + ((0xE1400070 | (((imm16) & 0xFFF0) << 4) | ((imm16) & 0x000F)) & 0xFFFFFFFF) +#endif + +#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..d1aa1943 --- /dev/null +++ b/arch/arm/include/arch/config.h @@ -0,0 +1,35 @@ +/** + * @file arch/arm/include/arch/config.h + * + * A Linux-style configuration list. + */ +#ifndef XTF_ARM_CONFIG_H +#define XTF_ARM_CONFIG_H + +#define XTF_VIRT_START 0x40000000 + +#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_32le) +#define CONFIG_ARM_32 1 +#define CONFIG_32BIT 1 +#define CONFIG_LE 1 +#define ENVIRONMENT_DESCRIPTION "ARM32 LE" +#else +#error "Bad environment" +#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..4abb80fc --- /dev/null +++ b/arch/arm/include/arch/hypercall.h @@ -0,0 +1,45 @@ +/** + * @file arch/arm/include/arch/hypercall.h + * + * Hypercall primitives for arm. + */ +#ifndef XTF_ARM_HYPERCALL_H +#define XTF_ARM_HYPERCALL_H + +#include + +#define _hypercall_1(type, hcall, a1) \ + ({ \ + UNIMPLEMENTED(); \ + (type)0; \ + }) + +#define _hypercall_2(type, hcall, a1, a2) \ + ({ \ + UNIMPLEMENTED(); \ + (type)0; \ + }) + +#define _hypercall_3(type, hcall, a1, a2, a3) \ + ({ \ + UNIMPLEMENTED(); \ + (type)0; \ + }) + +#define _hypercall_5(type, hcall, a1, a2, a3, a4, a5) \ + ({ \ + UNIMPLEMENTED(); \ + (type)0; \ + }) + +#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/page.h b/arch/arm/include/arch/page.h new file mode 100644 index 00000000..fd796a20 --- /dev/null +++ b/arch/arm/include/arch/page.h @@ -0,0 +1,24 @@ +/** + * @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)) + +#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/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/traps.h b/arch/arm/include/arch/traps.h new file mode 100644 index 00000000..f5240dfb --- /dev/null +++ b/arch/arm/include/arch/traps.h @@ -0,0 +1,17 @@ +/** + * @file arch/arm/include/arch/traps.h + */ +#ifndef XTF_ARM_TRAPS_H +#define XTF_ARM_TRAPS_H + +#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..e97bcb31 --- /dev/null +++ b/arch/arm/link.lds.S @@ -0,0 +1,59 @@ +#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.head) + *(.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/setup.c b/arch/arm/setup.c new file mode 100644 index 00000000..9a5ea879 --- /dev/null +++ b/arch/arm/setup.c @@ -0,0 +1,18 @@ +/** + * @file arch/arm/setup.c + * + * Early bringup code for arm. + */ +#include + +const char environment_description[] = ENVIRONMENT_DESCRIPTION; + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ From 7ce01a70f276a0263e5ede3847ee5d1a9066f28f Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Wed, 16 Mar 2022 08:41:17 +0100 Subject: [PATCH 03/12] arm64: Add BSS zeroing Add BSS zeroing into arm64 startup code head.S and implement a function clean_and_invalidate_dcache. Image protocol states that the state of the cache for BSS region is not known as BSS is not part of the loaded image. This is why it is required to invalidate the cache before and after zeroing BSS. Signed-off-by: Michal Orzel --- arch/arm/arm64/cache.S | 26 ++++++++++++++++++++++++++ arch/arm/arm64/head.S | 21 ++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 arch/arm/arm64/cache.S diff --git a/arch/arm/arm64/cache.S b/arch/arm/arm64/cache.S new file mode 100644 index 00000000..6b3813fc --- /dev/null +++ b/arch/arm/arm64/cache.S @@ -0,0 +1,26 @@ +#include + +/* + * clean_and_invalidate_dcache(start, end) + * - x0(start) - start address of a region + * - x1(end) - end address of a region + * Clobbers: x2, x3, x4 + */ +ENTRY(clean_and_invalidate_dcache) + /* 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(clean_and_invalidate_dcache) diff --git a/arch/arm/arm64/head.S b/arch/arm/arm64/head.S index 9fa0f6aa..00fc89dc 100644 --- a/arch/arm/arm64/head.S +++ b/arch/arm/arm64/head.S @@ -71,6 +71,25 @@ ENTRY(_start) PRINT("- XTF booting -\n") + PRINT("- Zero BSS -\n") + + load_paddr x0, __start_bss + load_paddr x1, __end_bss + + /* + * The BSS is not going to be part of the loaded image, so there is no + * guarantee in the state of the cache. Therefore we need to clean and + * invalidate the cache for BSS region before and after zeroing BSS. + */ + bl clean_and_invalidate_dcache +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 */ + load_paddr x0, __start_bss + bl clean_and_invalidate_dcache + /* Start an infinite loop */ PRINT("- Infinite loop -\n") -1: b 1b +2: b 2b From 93e7dc8e9811bba33923a6a1cca29f1270b30588 Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Tue, 15 Mar 2022 13:43:01 +0100 Subject: [PATCH 04/12] arm: Add build support for arm64/arm32 Add support for arm64/arm32 in the build system, modify the common headers to be aware of the new architectures and update the documentation. Architecture can be set using: ARCH=arm64 or ARCH=arm32. Currently only one test: tests/example is supported allowing the startup code head.S to be executed ending up in an infinite loop. Debug messages are printed using hypercall console_io. Signed-off-by: Michal Orzel --- INSTALL | 10 + Makefile | 10 +- README | 6 + build/arm-common/arch-common.mk | 8 + build/arm-common/arch-files.mk | 13 + build/arm32/arch-common.mk | 14 + build/arm32/arch-files.mk | 7 + build/arm32/arch-tests.mk | 4 + build/arm64/arch-common.mk | 14 + build/arm64/arch-files.mk | 8 + build/arm64/arch-tests.mk | 4 + build/gen.mk | 18 +- config/default-arm.cfg.in | 6 + docs/introduction.dox | 16 +- docs/mainpage.dox | 25 ++ include/xen/arch-arm.h | 454 ++++++++++++++++++++++++++++++++ include/xen/xen.h | 2 + include/xtf/hypercall.h | 82 +++--- include/xtf/lib.h | 5 + 19 files changed, 666 insertions(+), 40 deletions(-) create mode 100644 build/arm-common/arch-common.mk create mode 100644 build/arm-common/arch-files.mk create mode 100644 build/arm32/arch-common.mk create mode 100644 build/arm32/arch-files.mk create mode 100644 build/arm32/arch-tests.mk create mode 100644 build/arm64/arch-common.mk create mode 100644 build/arm64/arch-files.mk create mode 100644 build/arm64/arch-tests.mk create mode 100644 config/default-arm.cfg.in create mode 100644 include/xen/arch-arm.h diff --git a/INSTALL b/INSTALL index a88a799f..04a360c0 100644 --- a/INSTALL +++ b/INSTALL @@ -8,6 +8,12 @@ For x86: -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 + By default ARCH is set to the host architecture where make is executed, provided that it is supported by XTF. In order to perform cross compilation, ARCH needs to be set to the target @@ -17,3 +23,7 @@ cross compiler prefix e.g. CROSS_COMPILE=x86_64-linux-gnu-. To build XTF: -for x86: make ARCH=x86 CROSS_COMPILE= +-for arm64: +make ARCH=arm64 CROSS_COMPILE= +-for arm32: +make ARCH=arm32 CROSS_COMPILE= diff --git a/Makefile b/Makefile index ec48c3cc..e39c951a 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ endif xtftestdir := $(xtfdir)/tests # Supported architectures -SUPPORTED_ARCH := x86 +SUPPORTED_ARCH := x86 arm64 arm32 # By default ARCH is set to the host architecture where make is executed, # provided that it is supported by XTF. @@ -41,6 +41,10 @@ match-arch = $(shell echo $(1) | grep -w -q $(shell uname -m 2>/dev/null || \ # Set ARCH to the host architecture ifeq ($(call match-arch, x86_64 i386),y) ARCH ?= x86 +else ifeq ($(call match-arch, aarch64 arm64),y) +ARCH ?= arm64 +else ifeq ($(call match-arch, arm arm32),y) +ARCH ?= arm32 else ARCH ?= none endif @@ -81,6 +85,10 @@ 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 $(ROOT)/tests/*) diff --git a/README b/README index 20d91270..e601c3f4 100644 --- a/README +++ b/README @@ -9,12 +9,18 @@ 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 and arm32 is added +allowing to run a startup code based on the test: tests/example. +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/arm32 (startup code running) ## TODO List: diff --git a/build/arm-common/arch-common.mk b/build/arm-common/arch-common.mk new file mode 100644 index 00000000..b12e18f6 --- /dev/null +++ b/build/arm-common/arch-common.mk @@ -0,0 +1,8 @@ +# 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 diff --git a/build/arm-common/arch-files.mk b/build/arm-common/arch-files.mk new file mode 100644 index 00000000..bba1340a --- /dev/null +++ b/build/arm-common/arch-files.mk @@ -0,0 +1,13 @@ +# 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)/common/weak-defaults.o + +obj-perenv += $(ROOT)/arch/arm/setup.o diff --git a/build/arm32/arch-common.mk b/build/arm32/arch-common.mk new file mode 100644 index 00000000..817387c7 --- /dev/null +++ b/build/arm32/arch-common.mk @@ -0,0 +1,14 @@ +# Architecture specific configuration for arm32 + +BASE_ARCH := 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=armv7ve + +# 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..c7be0886 --- /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/head.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..4b8da782 --- /dev/null +++ b/build/arm64/arch-common.mk @@ -0,0 +1,14 @@ +# Architecture specific configuration for arm64 + +BASE_ARCH := arm +ALL_ENVIRONMENTS := 64le + +$(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 + +# 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..0d1782ea --- /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/head.o +obj-perenv += $(ROOT)/arch/arm/arm64/cache.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/gen.mk b/build/gen.mk index a6f3fc68..7f9f999a 100644 --- a/build/gen.mk +++ b/build/gen.mk @@ -47,17 +47,21 @@ install: install-each-env info.json # Build a test for specified environment define PERENV_build -# If any environment needs a special compilation/linking recipe instead of -# the default one, a custom recipe called build-$(env) e.g. build-hvm64 -# should be created in $(ROOT)/build/$(ARCH)/arch-common.mk +# If any base architecture/environment needs a special compilation/linking +# recipe instead of the default one, a custom recipe called build-$(BASE_ARCH) +# or build-$(env) e.g. build-arm or build-hvm64 should be created in +# $(ROOT)/build/$(ARCH)/arch-common.mk test-$(1)-$(NAME): $$(DEPS-$(1)) $$(link-$(1)) -ifndef build-$(1) - @# Generic link line for most environments - $(LD) $$(LDFLAGS_$(1)) $$(DEPS-$(1)) -o $$@ -else +ifdef build-$(BASE_ARCH) + @# Base-architecture specific compilation recipe + $(call build-$(BASE_ARCH),$(1)) +else ifdef build-$(1) @# Environment specific compilation recipe $(call build-$(1)) +else + @# Generic link line for most environments + $(LD) $$(LDFLAGS_$(1)) $$(DEPS-$(1)) -o $$@ endif cfg-$(1) ?= $(defcfg-$($(1)_guest)) diff --git a/config/default-arm.cfg.in b/config/default-arm.cfg.in new file mode 100644 index 00000000..26c0c505 --- /dev/null +++ b/config/default-arm.cfg.in @@ -0,0 +1,6 @@ +name="test-@@ENV@@-@@NAME@@@@VARIATION@@" + +vcpus=@@VCPUS@@ + +memory=128 +kernel="@@XTFDIR@@/tests/@@NAME@@/test-@@ENV@@-@@NAME@@" diff --git a/docs/introduction.dox b/docs/introduction.dox index 9207941d..501def3a 100644 --- a/docs/introduction.dox +++ b/docs/introduction.dox @@ -38,17 +38,29 @@ 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 arm64/arm32 there is currently a single environment called {64/32}le. + +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. diff --git a/docs/mainpage.dox b/docs/mainpage.dox index d1ae067a..1b63c678 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 and arm32 is added +allowing to run a startup code based on the test: tests/example. +This creates a base for future implementation. + The current environments supported are: +x86: Environment | Guest | Width | Paging :-----------|:------|:------|:--------- `pv32pae` | PV | 32bit | PAE @@ -29,6 +35,15 @@ Environment | Guest | Width | Paging `hvm32pae` | HVM | 32bit | PAE `hvm64` | HVM | 64bit | Long mode +arm64: +Environment | Guest | Width | Endianness | Paging +:-----------|:------|:------|:-----------|:---------------- +`64le` | arm64 | 64bit | little | Currently no MMU + +arm32: +Environment | Guest | Width | Endianness | Paging +:-----------|:------|:------|:-----------|:---------------- +`32le` | arm32 | 32bit | little | Currently no MMU @section getting-started Getting Started @@ -46,6 +61,12 @@ 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 @@ -54,6 +75,10 @@ To obtain and build: $ make -j4 # To build for x86 $ make ARCH=x86 CROSS_COMPILE= + # To build for arm64 + $ make ARCH=arm64 CROSS_COMPILE= + # To build for arm32 + $ make ARCH=arm32 CROSS_COMPILE= To run tests on a Xen host: (see @ref errata first) diff --git a/include/xen/arch-arm.h b/include/xen/arch-arm.h new file mode 100644 index 00000000..baea8496 --- /dev/null +++ b/include/xen/arch-arm.h @@ -0,0 +1,454 @@ +#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 + * + * HYPERVISOR_argo_op + * All generic sub-operations + * + * 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 */ + uint32_t cpsr; /* SPSR_EL2 */ + + union { + uint32_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/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..d9d2c320 100644 --- a/include/xtf/hypercall.h +++ b/include/xtf/hypercall.h @@ -26,6 +26,14 @@ # define HYPERCALL4 _hypercall32_4 # define HYPERCALL5 _hypercall32_5 +#elif defined(__aarch64__) || defined(__arm__) + +#include +# define HYPERCALL1 _hypercall_1 +# define HYPERCALL2 _hypercall_2 +# define HYPERCALL3 _hypercall_3 +# define HYPERCALL5 _hypercall_5 + #else # error Bad architecture for hypercalls #endif @@ -52,6 +60,10 @@ extern uint8_t hypercall_page[PAGE_SIZE]; /* * Hypercall primatives, compiled for the correct bitness */ + +/* x86 specific hypercalls */ +#if defined(__x86_64__) || defined(__i386__) + static inline long hypercall_set_trap_table(const struct xen_trap_info *ti) { return HYPERCALL1(long, __HYPERVISOR_set_trap_table, ti); @@ -87,17 +99,6 @@ static inline long hypercall_update_descriptor(uint64_t maddr, user_desc desc) #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. @@ -113,6 +114,34 @@ static inline long hypercall_update_va_mapping( #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); +} + +#endif /* defined(__x86_64__) || defined(__i386__) */ + +/* Common hypercalls */ +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); @@ -135,25 +164,11 @@ static inline long hypercall_vcpu_op(unsigned int cmd, unsigned int vcpu, 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); @@ -183,6 +198,18 @@ static inline long hypercall_argo_op(unsigned int cmd, void *arg1, void *arg2, /* * Higher level hypercall helpers */ + +/* x86 specific hypercall helpers */ +#if defined(__x86_64__) || defined(__i386__) + +static inline int hypercall_register_callback(const xen_callback_register_t *arg) +{ + return hypercall_callback_op(CALLBACKOP_register, arg); +} + +#endif /* defined(__x86_64__) || defined(__i386__) */ + +/* Common hypercall helpers */ static inline void hypercall_console_write(const char *buf, unsigned long count) { (void)HYPERCALL3(long, __HYPERVISOR_console_io, CONSOLEIO_write, count, buf); @@ -205,11 +232,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 9ced1e79..b9b482fe 100644 --- a/include/xtf/lib.h +++ b/include/xtf/lib.h @@ -25,6 +25,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); \ From 0ac3f2480ac2833a8df62fcf49e8cc14878e3139 Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Thu, 25 Mar 2021 09:26:15 +0100 Subject: [PATCH 05/12] xtf: Make the common hypercall header arch independent 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. Modify the common header to be architecture independent and move x86 handlers to architecture specific code. Signed-off-by: Michal Orzel --- arch/x86/include/arch/hypercall.h | 185 +++++++++++++++++++++++++++ include/xtf/hypercall.h | 202 ++---------------------------- 2 files changed, 193 insertions(+), 194 deletions(-) create mode 100644 arch/x86/include/arch/hypercall.h 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/include/xtf/hypercall.h b/include/xtf/hypercall.h index d9d2c320..917fcc74 100644 --- a/include/xtf/hypercall.h +++ b/include/xtf/hypercall.h @@ -1,44 +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 - -#elif defined(__aarch64__) || defined(__arm__) - +/* + * 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 -# define HYPERCALL1 _hypercall_1 -# define HYPERCALL2 _hypercall_2 -# define HYPERCALL3 _hypercall_3 -# define HYPERCALL5 _hypercall_5 - -#else -# error Bad architecture for hypercalls -#endif - -extern uint8_t hypercall_page[PAGE_SIZE]; /* All Xen ABI for includers convenience .*/ #include @@ -57,164 +28,7 @@ extern uint8_t hypercall_page[PAGE_SIZE]; #include #include -/* - * Hypercall primatives, compiled for the correct bitness - */ - -/* x86 specific hypercalls */ -#if defined(__x86_64__) || defined(__i386__) - -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); -} - -#endif /* defined(__x86_64__) || defined(__i386__) */ - -/* Common hypercalls */ -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 - */ - -/* x86 specific hypercall helpers */ -#if defined(__x86_64__) || defined(__i386__) - -static inline int hypercall_register_callback(const xen_callback_register_t *arg) -{ - return hypercall_callback_op(CALLBACKOP_register, arg); -} - -#endif /* defined(__x86_64__) || defined(__i386__) */ - /* Common hypercall helpers */ -static inline void hypercall_console_write(const char *buf, unsigned long count) -{ - (void)HYPERCALL3(long, __HYPERVISOR_console_io, CONSOLEIO_write, count, buf); -} - static inline long hypercall_shutdown(unsigned int reason) { return hypercall_sched_op(SCHEDOP_shutdown, &reason); From ec16784d5ecf0bb68f5f99fa71905995c4f0a8e9 Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Thu, 25 Mar 2021 09:32:41 +0100 Subject: [PATCH 06/12] arm: Add the hypercall handling interfaces Add the hypercall wrappers for arm64 and arm32 from Linux. The hypercalls are defined in the assembly files hypercall.S and they are specific to arm64/arm32. The prototypes and higher level wrappers are defined in arch/arm/include/arch/hypercall.h as they are common to both arm64 and arm32. Signed-off-by: Michal Orzel --- arch/arm/arm32/hypercall.S | 72 +++++++++++++++++++++++++++++++ arch/arm/arm64/hypercall.S | 63 +++++++++++++++++++++++++++ arch/arm/include/arch/hypercall.h | 43 +++++++++--------- build/arm32/arch-files.mk | 1 + build/arm64/arch-files.mk | 1 + 5 files changed, 158 insertions(+), 22 deletions(-) create mode 100644 arch/arm/arm32/hypercall.S create mode 100644 arch/arm/arm64/hypercall.S diff --git a/arch/arm/arm32/hypercall.S b/arch/arm/arm32/hypercall.S new file mode 100644 index 00000000..362549a1 --- /dev/null +++ b/arch/arm/arm32/hypercall.S @@ -0,0 +1,72 @@ +/* + * Xen hypercall wrappers + * + * Stefano Stabellini , Citrix, 2012 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#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/hypercall.S b/arch/arm/arm64/hypercall.S new file mode 100644 index 00000000..2af29f0a --- /dev/null +++ b/arch/arm/arm64/hypercall.S @@ -0,0 +1,63 @@ +/* + * Xen hypercall wrappers + * + * Stefano Stabellini , Citrix, 2012 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#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/include/arch/hypercall.h b/arch/arm/include/arch/hypercall.h index 4abb80fc..626f8a67 100644 --- a/arch/arm/include/arch/hypercall.h +++ b/arch/arm/include/arch/hypercall.h @@ -7,30 +7,29 @@ #define XTF_ARM_HYPERCALL_H #include +#include +#include +#include -#define _hypercall_1(type, hcall, a1) \ - ({ \ - UNIMPLEMENTED(); \ - (type)0; \ - }) +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); -#define _hypercall_2(type, hcall, a1, a2) \ - ({ \ - UNIMPLEMENTED(); \ - (type)0; \ - }) - -#define _hypercall_3(type, hcall, a1, a2, a3) \ - ({ \ - UNIMPLEMENTED(); \ - (type)0; \ - }) - -#define _hypercall_5(type, hcall, a1, a2, a3, a4, a5) \ - ({ \ - UNIMPLEMENTED(); \ - (type)0; \ - }) +/* + * 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 */ diff --git a/build/arm32/arch-files.mk b/build/arm32/arch-files.mk index c7be0886..6124e171 100644 --- a/build/arm32/arch-files.mk +++ b/build/arm32/arch-files.mk @@ -5,3 +5,4 @@ include $(ROOT)/build/arm-common/arch-files.mk # Specific files for arm32 obj-perenv += $(ROOT)/arch/arm/arm32/head.o +obj-perenv += $(ROOT)/arch/arm/arm32/hypercall.o diff --git a/build/arm64/arch-files.mk b/build/arm64/arch-files.mk index 0d1782ea..c9f5d23e 100644 --- a/build/arm64/arch-files.mk +++ b/build/arm64/arch-files.mk @@ -6,3 +6,4 @@ include $(ROOT)/build/arm-common/arch-files.mk # Specific files for arm64 obj-perenv += $(ROOT)/arch/arm/arm64/head.o obj-perenv += $(ROOT)/arch/arm/arm64/cache.o +obj-perenv += $(ROOT)/arch/arm/arm64/hypercall.o From d4aae2338e70d5ee6da93411c693f6e1938033f0 Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Tue, 15 Mar 2022 15:28:24 +0100 Subject: [PATCH 07/12] arm64: Startup code improvements + traps handling Improve the startup code for arm64 and implement the proper traps handling for arm. At this point it would be possible to jump to the C world. However MMU and PV console support shall be done first. Signed-off-by: Michal Orzel --- arch/arm/arm64/head.S | 173 ++++++++++++++++++++++++++- arch/arm/include/arch/arm32/system.h | 20 ++++ arch/arm/include/arch/arm64/system.h | 20 ++++ arch/arm/include/arch/page.h | 30 +++++ arch/arm/include/arch/system.h | 23 ++++ arch/arm/setup.c | 7 ++ arch/arm/traps.c | 100 ++++++++++++++++ build/arm-common/arch-files.mk | 1 + build/arm64/arch-common.mk | 3 + 9 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/arch/arm32/system.h create mode 100644 arch/arm/include/arch/arm64/system.h create mode 100644 arch/arm/include/arch/system.h create mode 100644 arch/arm/traps.c diff --git a/arch/arm/arm64/head.S b/arch/arm/arm64/head.S index 00fc89dc..8d0e04f7 100644 --- a/arch/arm/arm64/head.S +++ b/arch/arm/arm64/head.S @@ -2,6 +2,9 @@ #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) @@ -31,6 +34,10 @@ .section ".bss.page_aligned" .p2align PAGE_SHIFT +stack_start: + .space STACK_SIZE +stack_end: + .section ".text.head", "ax", @progbits b _start /* branch to kernel start, magic */ .long 0 /* Executable code */ @@ -61,9 +68,23 @@ * x30 - lr */ ENTRY(_start) + /* Disable all IRQs */ + msr daifset, #0xf + /* Save DTB pointer */ mov x20, x0 + /* + * Turn off D-cache. + * No need to disable MMU. Image protocol mandates that MMU must be off + * when entering the kernel. + */ + dsb sy + mrs x2, sctlr_el1 + bic x2, x2, #SCTLR_C + msr sctlr_el1, x2 + isb + /* Calculate where we are */ ldr x22, =_start /* x22 := vaddr(_start) */ adr x21, _start /* x21 := paddr(_start) */ @@ -71,8 +92,14 @@ ENTRY(_start) PRINT("- XTF booting -\n") - PRINT("- Zero BSS -\n") + PRINT("- Setup CPU -\n") + bl cpu_setup + + /* Load the vector table */ + ldr x2, =vector_table + msr vbar_el1, x2 + PRINT("- Zero BSS -\n") load_paddr x0, __start_bss load_paddr x1, __end_bss @@ -90,6 +117,150 @@ ENTRY(_start) load_paddr x0, __start_bss bl clean_and_invalidate_dcache + PRINT("- Setup stack -\n") + ldr x1, =stack_end + mov sp, x1 + + /* Save boot arguments */ + ldr x0, =boot_data + stp x21, x20, [x0] + /* Start an infinite loop */ PRINT("- Infinite loop -\n") 2: b 2b +ENDFUNC(_start) + +/* + * Setup CPU for enabling MMU. + * + * Clobbers: x0 + */ +cpu_setup: + dsb sy + + /* Set up memory attribute type tables */ + ldr x0, =MAIRVAL + msr mair_el1, x0 + isb + + ret +ENDFUNC(cpu_setup) + +/* 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 + +/* + * Invalid vector entry trap handler. + * + * Clobbers: x0 + */ +invalid_vector_entry: + mov x0, sp + b do_bad_mode +ENDFUNC(invalid_vector_entry) + + .align 6 +/* + * SYNC exception handler. + * + * Clobbers: x0 + */ +el1_sync: + entry_trap + mov x0, sp + bl do_trap_sync + exit_trap +ENDFUNC(el1_sync) + + .align 6 +/* + * IRQ exception handler. + * + * Clobbers: x0 + */ +el1_irq: + entry_trap + mov x0, sp + bl do_trap_irq + exit_trap +ENDFUNC(el1_irq) + +.macro ventry label + .align 7 + b \label +.endm + + .align 11 + +/* Vector table for exceptions. */ +vector_table: + ventry invalid_vector_entry /* Synchronous EL1t */ + ventry invalid_vector_entry /* IRQ EL1t */ + ventry invalid_vector_entry /* FIQ EL1t */ + ventry invalid_vector_entry /* Error EL1t */ + + ventry el1_sync /* Synchronous EL1h */ + ventry el1_irq /* IRQ EL1h */ + ventry invalid_vector_entry /* FIQ EL1h */ + ventry invalid_vector_entry /* Error EL1h */ + + ventry invalid_vector_entry /* Synchronous 64-bit EL0 */ + ventry invalid_vector_entry /* IRQ 64-bit EL0 */ + ventry invalid_vector_entry /* FIQ 64-bit EL0 */ + ventry invalid_vector_entry /* Error 64-bit EL0 */ + + ventry invalid_vector_entry /* Synchronous 32-bit EL0 */ + ventry invalid_vector_entry /* IRQ 32-bit EL0 */ + ventry invalid_vector_entry /* FIQ 32-bit EL0 */ + ventry invalid_vector_entry /* Error 32-bit EL0 */ +ENDFUNC(vector_table) 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/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/page.h b/arch/arm/include/arch/page.h index fd796a20..0e71dbef 100644 --- a/arch/arm/include/arch/page.h +++ b/arch/arm/include/arch/page.h @@ -11,6 +11,36 @@ #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) + + #endif /* XTF_ARM_PAGE_H */ /* 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/setup.c b/arch/arm/setup.c index 9a5ea879..11d9f59b 100644 --- a/arch/arm/setup.c +++ b/arch/arm/setup.c @@ -5,6 +5,13 @@ */ #include +/* Structure to store boot arguments. */ +struct init_data +{ + uint64_t phys_offset; + void *fdt; +} boot_data; + const char environment_description[] = ENVIRONMENT_DESCRIPTION; /* diff --git a/arch/arm/traps.c b/arch/arm/traps.c new file mode 100644 index 00000000..406b7052 --- /dev/null +++ b/arch/arm/traps.c @@ -0,0 +1,100 @@ +/** + * @file arch/arm/traps.c + * + * Arm trap handlers. + */ +#include +#include +#include + +#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) +{ + printk("---Bad mode detected---\n"); + 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/build/arm-common/arch-files.mk b/build/arm-common/arch-files.mk index bba1340a..1c3b6969 100644 --- a/build/arm-common/arch-files.mk +++ b/build/arm-common/arch-files.mk @@ -11,3 +11,4 @@ obj-perenv += $(ROOT)/common/xenbus.o obj-perenv += $(ROOT)/common/weak-defaults.o obj-perenv += $(ROOT)/arch/arm/setup.o +obj-perenv += $(ROOT)/arch/arm/traps.o diff --git a/build/arm64/arch-common.mk b/build/arm64/arch-common.mk index 4b8da782..950d91eb 100644 --- a/build/arm64/arch-common.mk +++ b/build/arm64/arch-common.mk @@ -10,5 +10,8 @@ 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 From 66ba008d314e50e4b9b1335045e13a6516a7e0b2 Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Wed, 16 Mar 2022 09:56:42 +0100 Subject: [PATCH 08/12] arm64: Add boot MMU support Add the following to the startup code head.S: -setup boot page tables -setup identity mapping -enable MMU MMU configuration: -granularity: 4KB -VA width: 39bit -VA start: 0xffffff8000000000 -3 levels of lookup: L1->L2->2M blocks, L2->L3->4KB pages(fixmap) -1GB identity mapping removed before jumping into C Modify the arm64 environment from 64le to mmu64le to reflect that it has MMU enabled. Signed-off-by: Michal Orzel --- arch/arm/arm64/head.S | 165 ++++++++++++++++++++++++++++++++- arch/arm/include/arch/config.h | 13 ++- arch/arm/include/arch/mm.h | 83 +++++++++++++++++ arch/arm/include/arch/page.h | 28 ++++++ arch/arm/mm.c | 28 ++++++ build/arm-common/arch-files.mk | 4 + build/arm64/arch-common.mk | 5 +- docs/introduction.dox | 3 +- docs/mainpage.dox | 2 +- 9 files changed, 320 insertions(+), 11 deletions(-) create mode 100644 arch/arm/include/arch/mm.h create mode 100644 arch/arm/mm.c diff --git a/arch/arm/arm64/head.S b/arch/arm/arm64/head.S index 8d0e04f7..44d0aa8e 100644 --- a/arch/arm/arm64/head.S +++ b/arch/arm/arm64/head.S @@ -1,4 +1,3 @@ -#include #include #include @@ -99,9 +98,35 @@ ENTRY(_start) ldr x2, =vector_table msr vbar_el1, x2 + /* + * 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 + + /* + * 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 + PRINT("- Zero BSS -\n") - load_paddr x0, __start_bss - load_paddr x1, __end_bss + ldr x0, =__start_bss + ldr x1, =__end_bss /* * The BSS is not going to be part of the loaded image, so there is no @@ -114,7 +139,7 @@ ENTRY(_start) b.lo 1b /* Load BSS start address again as x0 has been modified in the upper loop */ - load_paddr x0, __start_bss + ldr x0, =__start_bss bl clean_and_invalidate_dcache PRINT("- Setup stack -\n") @@ -133,7 +158,7 @@ ENDFUNC(_start) /* * Setup CPU for enabling MMU. * - * Clobbers: x0 + * Clobbers: x0, x1 */ cpu_setup: dsb sy @@ -141,11 +166,141 @@ cpu_setup: /* 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) +/* + * Enable MMU and D-cache. + * + * Clobbers: x2 + */ +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) + +/* + * Create MMU page tables. + * + * Clobbers: x0, x1, x2, x3, x4, x5, x6, x7 + */ +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) + +/* + * Create identity mapping. + * + * Clobbers: x0, x1, x2, x3, x4 + */ +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) + +/* + * Link the fixmap in the page table. + * + * Clobbers: x0, x1, x2, x3, x4, x5 + */ +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] + + dsb nshst + + ret +ENDFUNC(setup_fixmap) + /* Save state */ .macro entry_trap sub sp, sp, #(272 - 240) /* offset: spsr_el1 - lr */ diff --git a/arch/arm/include/arch/config.h b/arch/arm/include/arch/config.h index d1aa1943..4f677733 100644 --- a/arch/arm/include/arch/config.h +++ b/arch/arm/include/arch/config.h @@ -6,13 +6,14 @@ #ifndef XTF_ARM_CONFIG_H #define XTF_ARM_CONFIG_H -#define XTF_VIRT_START 0x40000000 +#include -#if defined(CONFIG_ENV_64le) +#if defined(CONFIG_ENV_mmu64le) #define CONFIG_ARM_64 1 #define CONFIG_64BIT 1 #define CONFIG_LE 1 -#define ENVIRONMENT_DESCRIPTION "ARM64 LE" +#define CONFIG_MMU 1 +#define ENVIRONMENT_DESCRIPTION "ARM64 LE MMU" #elif defined(CONFIG_ENV_32le) #define CONFIG_ARM_32 1 #define CONFIG_32BIT 1 @@ -22,6 +23,12 @@ #error "Bad environment" #endif +#ifdef CONFIG_MMU +#define XTF_VIRT_START VA_START +#else +#define XTF_VIRT_START 0x40000000 +#endif + #endif /* XTF_ARM_CONFIG_H */ /* diff --git a/arch/arm/include/arch/mm.h b/arch/arm/include/arch/mm.h new file mode 100644 index 00000000..667badb8 --- /dev/null +++ b/arch/arm/include/arch/mm.h @@ -0,0 +1,83 @@ +/** + * @file arch/arm/include/arch/mm.h + * + * Memory management on arm. + */ +#ifndef XTF_ARM_MM_H +#define XTF_ARM_MM_H + +#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) + +/* + * 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) + + +/* + * 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) + +/* 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)) + +#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 index 0e71dbef..1a3abb33 100644 --- a/arch/arm/include/arch/page.h +++ b/arch/arm/include/arch/page.h @@ -40,6 +40,34 @@ #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 */ diff --git a/arch/arm/mm.c b/arch/arm/mm.c new file mode 100644 index 00000000..8dd0978e --- /dev/null +++ b/arch/arm/mm.c @@ -0,0 +1,28 @@ +/** + * @file arch/arm/mm.c + * + * Memory management on arm. + */ + +#include +#include + +/* + * 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]; + +/* + * 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-files.mk b/build/arm-common/arch-files.mk index 1c3b6969..dc61f91f 100644 --- a/build/arm-common/arch-files.mk +++ b/build/arm-common/arch-files.mk @@ -12,3 +12,7 @@ obj-perenv += $(ROOT)/common/weak-defaults.o obj-perenv += $(ROOT)/arch/arm/setup.o obj-perenv += $(ROOT)/arch/arm/traps.o + +# MMU environment specific objects +obj-mmu += $(ROOT)/arch/arm/mm.o +$(foreach env,$(MMU_ENVIRONMENTS),$(eval obj-$(env) += $(obj-mmu))) diff --git a/build/arm64/arch-common.mk b/build/arm64/arch-common.mk index 950d91eb..9970d50f 100644 --- a/build/arm64/arch-common.mk +++ b/build/arm64/arch-common.mk @@ -1,7 +1,10 @@ # Architecture specific configuration for arm64 BASE_ARCH := arm -ALL_ENVIRONMENTS := 64le +ALL_ENVIRONMENTS := mmu64le + +# On arm64 all environments need to have MMU enabled +MMU_ENVIRONMENTS := $(ALL_ENVIRONMENTS) $(foreach env,$(ALL_ENVIRONMENTS),$(eval $(env)_guest := arm64)) $(foreach env,$(ALL_ENVIRONMENTS),$(eval $(env)_arch := arm64)) diff --git a/docs/introduction.dox b/docs/introduction.dox index 501def3a..cc55f469 100644 --- a/docs/introduction.dox +++ b/docs/introduction.dox @@ -43,7 +43,8 @@ For x86 architecture: - The compilation width (32bit or 64bit). - The primary paging mode (none, PSE, PAE). -For arm64/arm32 there is currently a single environment called {64/32}le. +For arm64 there is currently a single environment called mmu64le (with MMU). +For arm32 there is currently a single environment called 32le (no MMU). All available environments for x86 are: @dontinclude build/x86/arch-common.mk diff --git a/docs/mainpage.dox b/docs/mainpage.dox index 1b63c678..d81359d6 100644 --- a/docs/mainpage.dox +++ b/docs/mainpage.dox @@ -38,7 +38,7 @@ Environment | Guest | Width | Paging arm64: Environment | Guest | Width | Endianness | Paging :-----------|:------|:------|:-----------|:---------------- -`64le` | arm64 | 64bit | little | Currently no MMU +`mmu64le` | arm64 | 64bit | little | 4kB arm32: Environment | Guest | Width | Endianness | Paging From 54d32e88d7809639f425c3d7bfae636046086306 Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Wed, 16 Mar 2022 10:28:41 +0100 Subject: [PATCH 09/12] arm: Add MMU helpers Add macros to convert between frame numbers and address formats. Add functions to store page table entry and setup fixmap. Signed-off-by: Michal Orzel --- arch/arm/include/arch/mm.h | 34 +++++++++++++++++++++++++++++++++- arch/arm/mm.c | 26 ++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/arch/mm.h b/arch/arm/include/arch/mm.h index 667badb8..fb981fe2 100644 --- a/arch/arm/include/arch/mm.h +++ b/arch/arm/include/arch/mm.h @@ -7,6 +7,7 @@ #define XTF_ARM_MM_H #include +#include /* * Granularity: 4KB @@ -29,6 +30,7 @@ #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 @@ -37,7 +39,7 @@ #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 @@ -46,6 +48,7 @@ #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) /* Descriptors */ #define DESCR_BAD 0x0 @@ -70,6 +73,35 @@ 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 */ /* diff --git a/arch/arm/mm.c b/arch/arm/mm.c index 8dd0978e..1e0d1669 100644 --- a/arch/arm/mm.c +++ b/arch/arm/mm.c @@ -6,6 +6,9 @@ #include #include +#include + +paddr_t phys_offset; /* * Static boot page tables used before BSS is zeroed. @@ -17,6 +20,29 @@ 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 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 From 4345eb777297d5aa8bfeda372217d707ee75d30d Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Wed, 16 Mar 2022 10:38:06 +0100 Subject: [PATCH 10/12] arm64: Jump to C world and run hello-world test Now, when everything is ready, get rid of infinite loop from the startup code and jump to C world. Because there is no PV console support added yet, use hypercall_console_io to print messages using printk so that we can see the results from running the hello-world test. Result: (d1) - XTF booting - (d1) - Setup CPU - (d1) - Setup page tables - (d1) - Enable MMU - (d1) - Zero BSS - (d1) - Setup stack - (d1) - Jump to C world- (d1) --- Xen Test Framework --- (d1) Environment: ARM64 LE MMU (d1) Hello World (d1) Test result: SUCCESS Signed-off-by: Michal Orzel --- arch/arm/arm64/head.S | 5 ++--- arch/arm/setup.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/arch/arm/arm64/head.S b/arch/arm/arm64/head.S index 44d0aa8e..92466927 100644 --- a/arch/arm/arm64/head.S +++ b/arch/arm/arm64/head.S @@ -150,9 +150,8 @@ mmu_enabled: ldr x0, =boot_data stp x21, x20, [x0] - /* Start an infinite loop */ - PRINT("- Infinite loop -\n") -2: b 2b + PRINT("- Jump to C world-\n") + b xtf_main ENDFUNC(_start) /* diff --git a/arch/arm/setup.c b/arch/arm/setup.c index 11d9f59b..c8489378 100644 --- a/arch/arm/setup.c +++ b/arch/arm/setup.c @@ -4,6 +4,7 @@ * Early bringup code for arm. */ #include +#include /* Structure to store boot arguments. */ struct init_data @@ -14,6 +15,20 @@ struct init_data const char environment_description[] = ENVIRONMENT_DESCRIPTION; +static void setup_console(void) +{ + /* Use Xen console to print messages */ + register_console_callback(hypercall_console_write); +} + +void arch_setup(void) +{ + setup_console(); +#ifdef CONFIG_MMU + setup_mm(boot_data.phys_offset); +#endif +} + /* * Local variables: * mode: C From 0adf28a74d7f67f3cbb5dfe92d1e12b124102bdd Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Thu, 5 Aug 2021 08:29:35 +0200 Subject: [PATCH 11/12] xen/version: Add XENVER_get_features operation ... together with public header features.h storing feature flags reported by XENVER_get_features. Signed-off-by: Michal Orzel --- include/xen/features.h | 107 +++++++++++++++++++++++++++++++++++++++++ include/xen/version.h | 10 ++++ 2 files changed, 117 insertions(+) create mode 100644 include/xen/features.h diff --git a/include/xen/features.h b/include/xen/features.h new file mode 100644 index 00000000..3675a974 --- /dev/null +++ b/include/xen/features.h @@ -0,0 +1,107 @@ +/* + * 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__ */ /* From 62f362fac4f70a1f634db0269554695a63e0568f Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Wed, 16 Mar 2022 10:55:51 +0100 Subject: [PATCH 12/12] arm: Add support for PV console ... so that we can connect to a guest console using xl console. PV console should not be used when XTF is running as dom0. For that purpose, implement a function is_initdomain that uses hypercall xen_version to get Xen features and checks if bit XENFEAT_dom0 is set. Signed-off-by: Michal Orzel --- arch/arm/include/arch/mm.h | 3 +++ arch/arm/setup.c | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/arch/arm/include/arch/mm.h b/arch/arm/include/arch/mm.h index fb981fe2..c70f1d22 100644 --- a/arch/arm/include/arch/mm.h +++ b/arch/arm/include/arch/mm.h @@ -50,6 +50,9 @@ #define L3_TABLE_OFFSET (L3_TABLE_SIZE - 1) #define L3_TABLE_INDEX(x) ((x >> L3_TABLE_SHIFT) & TABLE_ADDR_MASK) +/* Fixmap slots */ +#define FIXMAP_PV_CONSOLE 0 + /* Descriptors */ #define DESCR_BAD 0x0 #define DESCR_VALID 0x1 diff --git a/arch/arm/setup.c b/arch/arm/setup.c index c8489378..df42a3a8 100644 --- a/arch/arm/setup.c +++ b/arch/arm/setup.c @@ -15,10 +15,52 @@ struct init_data const char environment_description[] = ENVIRONMENT_DESCRIPTION; +#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 + static void setup_console(void) { /* Use Xen console to print messages */ register_console_callback(hypercall_console_write); +#ifdef CONFIG_MMU + /* Use PV console when running as a guest */ + if (!is_initdomain()) + setup_pv_console(); +#endif } void arch_setup(void)