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