diff --git a/.clang-format b/.clang-format
index c58fbe7..f7e7406 100644
--- a/.clang-format
+++ b/.clang-format
@@ -13,10 +13,30 @@ Language: Cpp
AccessModifierOffset: -8
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
-AlignConsecutiveMacros: Consecutive
-AlignConsecutiveAssignments: Consecutive
-AlignConsecutiveBitFields: None
-AlignConsecutiveDeclarations: Consecutive
+AlignConsecutiveAssignments:
+ Enabled: true
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ PadOperators: true
+AlignConsecutiveBitFields:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ PadOperators: true
+AlignConsecutiveDeclarations:
+ Enabled: true
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ PadOperators: true
+AlignConsecutiveMacros:
+ Enabled: true
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ PadOperators: true
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
@@ -49,6 +69,11 @@ AttributeMacros:
- RELEASE_READ
- REQUIRE_READ
- EXCLUDE_READ
+ - ACQUIRE_RCU_READ
+ - TRY_ACQUIRE_RCU_READ
+ - RELEASE_RCU_READ
+ - REQUIRE_RCU_READ
+ - EXCLUDE_RCU_READ
- LOCK_IMPL
- ACQUIRE_SPINLOCK
- ACQUIRE_SPINLOCK_NP
@@ -84,7 +109,7 @@ BraceWrapping:
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
-BreakBeforeConceptDeclarations: true
+BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeComma
@@ -95,6 +120,7 @@ BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 80
CommentPragmas: '^ FIXME:'
+QualifierAlignment: Left
CompactNamespaces: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
@@ -105,6 +131,10 @@ DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
+PackConstructorInitializers: BinPack
+BasedOnStyle: ''
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
ForEachMacros:
- list_foreach
@@ -155,9 +185,10 @@ IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
-IndentRequires: false
+IndentRequiresClause: false
IndentWidth: 8
IndentWrappedFunctionNames: false
+InsertBraces: true
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
@@ -176,6 +207,7 @@ PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
+PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 10
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 100
@@ -185,6 +217,9 @@ PointerAlignment: Right
PPIndentWidth: -1
ReferenceAlignment: Pointer
ReflowComments: true
+RemoveBracesLLVM: false
+RequiresClausePosition: OwnLine
+SeparateDefinitionBlocks: Always
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
@@ -198,6 +233,16 @@ SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
+SpaceBeforeParensOptions:
+ AfterControlStatements: true
+ AfterForeachMacros: true
+ AfterFunctionDefinitionName: false
+ AfterFunctionDeclarationName: false
+ AfterIfMacros: true
+ AfterOverloadedOperator: false
+ AfterRequiresInClause: false
+ AfterRequiresInExpression: false
+ BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyBlock: true
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..b5cb7d6
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,16 @@
+root = True
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+charset = utf-8
+tab_width = 8
+
+[*.{c,h,tc,ev,S,hvc}]
+indent_style = tab
+indent_size = 8
+
+[*.{py,md}]
+indent_style = space
+indent_size = 4
diff --git a/.gitignore b/.gitignore
index d0fec74..8bd4bf9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
/.ninja_log
/.sconsign.dblite
/build*/
+hyp/**/*.o
# Ignore Python precompiled bitcode
*.pyc
@@ -20,3 +21,10 @@
# Ignore Vim temporary files
.*.sw[a-p]
.*.un~
+
+# Ignore host test temporary files
+*.o
+
+# Ignore documentation output
+*.pdf
+*.html
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 53cbb98..55a361d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
-# Changelog
+# Status and Changelog
-All notable changes to this project will be documented in this file.
+This page documents current status, known issues and work in progress. Some of
+these may impact your development or hypervisor usage.
## Open Issues
@@ -9,15 +10,29 @@ All notable changes to this project will be documented in this file.
The Resource Manager being the root-VM, manages creation of the Primary VM
(HLOS) and controls the rights to create additional VMs. In the Gunyah Resource
Manager design, VM management services are provided by the Resource Manager
-(although it is technically possible for these rights to be delegated to other
-VMs).
-The current Resource Manager does not support Secondary VM loading. Support
-will be added in a subsequent contribution.
+Gunyah patches are required in Linux and the CrosVM VMM to support SVM loading.
-### 2. Virtio support
+### Known issues:
-Virtio support is under development and should be contributed along with secondary VM support.
+- Only QEMU serial communication is tested. Using host Linux networking (qemu
+ virtio) with adb (network) connection will permit greater flexibility in
+ connecting to the device.
+- SVM booting with Crosvm uses uart emulation, its very slow.
+- Crosvm opens the UART console in the current terminal, so it is via the host
+ uart terminal. We have not configured a way to open multiple terminals yet.
+- Debugging a system running QEMU with a remote gdb connection is unstable.
+
+### Untested scenarios:
+
+- Launching of multiple SVM's simultaneously from PVM, because of the known
+ issue of having only one console available.
+
+### TODO list:
+
+- Hardcoded platform parameters
+ + Memory address ranges are hardcoded (get from dtb nodes)
+ + Dtb address is hardcoded (get from register)
## Unreleased
@@ -27,7 +42,7 @@ Unreleased changes in the `develop` branch may be added here.
Individual releases are tagged, and the latest release will be available in the `main` branch.
-* No releases have been made at this time.
+* No tagged releases have been made at this time.
## Contributions
@@ -38,4 +53,5 @@ Significant contributions are listed here.
This is the initial contribution of source code to the Gunyah Hypervisor.
* Support for QEMU AArch64 Simulator
-* Support unmodified Linux Primary VM kernel
+* Support unmodified Linux Primary VM kernel or with Gunyah patches for VM loading
+* Support unmodified Linux Secondary VM kernel
diff --git a/README.md b/README.md
index 825bbe1..bf25cad 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,27 @@
-
+[
](https://github.com/quic)
# Gunyah Hypervisor
+Gunyah is a high performance, scalable and flexible hypervisor built for
+demanding battery powered, real-time, safety and security use cases.
+
+The Gunyah Hypervisor open source project provides a reference Type-1
+hypervisor configuration suitable for general purpose hosting of multiple
+trusted and dependent VMs.
+
+## Gunyah Origins
+
*Gunyah* is an Australian Aboriginal word. See: https://en.wiktionary.org/wiki/gunyah
The Gunyah Hypervisor was developed by Qualcomm in Sydney Australia.
## Type-1 Hypervisor Concept
-Gunyah is a Type-1 hypervisor, meaning that it is independent of any high-level
-OS kernel, and runs in a higher CPU privilege level. It does not depend on any
-lower-privileged OS kernel/code for its core functionality. This increases its
-security and can support a much smaller trusted computing base than a Type-2
-hypervisor.
+Gunyah is a Type-1 hypervisor, meaning that it runs independently of any
+high-level OS kernel - such as Linux, and runs in a higher CPU privilege level
+than VMs. It does not depend on any lower-privileged OS kernel/code for its
+core functionality. This increases its security and can support a much smaller
+trusted computing base than a Type-2 like hosted-hypervisors.
Gunyah's design principle is not dissimilar to a traditional microkernel in
that it provides only a minimal set of critical services to its clients, and
@@ -21,15 +30,16 @@ less-privileged) processes, wherever this is possible without an adverse impact
on performance or security.
The hypervisor uses the CPU's virtualization mode and features to isolate
-itself from OS kernels in VMs. On ARM, this includes trapping privileged
-registers, using GIC virtualization support, and the Stage-2 MMU to provide
-isolated VMs in EL1/0.
+itself from OS kernels in VMs and isolate VMs from each other. On ArM, this
+includes trapping and emulating registers as required, virtualizing core
+platform devices, Arm's GIC virtualization support, and the CPU's Stage-2 MMU
+to provide isolated VMs in EL1/0.
## Why Gunyah
-- **strong security**: Mobile payments, secure user-interface, and many more security sensitive use-cases all require strong security. Gunyah's design is suited to providing strong isolation guarantees and its small size is conducive to audit.
-- **performance**: Mobile devices are particularly demanding. Battery powered devices demand low software overheads to get the most performance per-watt. Gunyah is designed to have high performance with minimal impact to high-level operating systems.
-- **modularity**: The hypervisor is designed to be modular, allowing customization and enhancement by swapping out module implementations and adding new feature via new modules.
+- **Strong security**: Mobile payments, secure user-interface, and many more security sensitive use-cases all require strong security. Gunyah's design is suited to providing strong isolation guarantees and its small size is conducive to audit.
+- **Performance**: Mobile devices are particularly demanding. Battery powered devices demand low software overheads to get the most performance per-watt. Gunyah is designed to have high performance with minimal impact to high-level operating systems.
+- **Modularity**: The hypervisor is designed to be modular, allowing customization and enhancement by swapping out module implementations and adding new feature via new modules.
## Features
@@ -41,17 +51,23 @@ isolated VMs in EL1/0.
## Platform Support
-Gunyah is architected to support other CPU architectures, so its core design ensures architecture independence and portability in non-architecture specific areas.
+Gunyah is architected to support multiple CPU architectures, so its core design
+ensures architecture independence and portability in non-architecture specific
+areas.
-Gunyah currently supports ARMv8.2+ platforms as it uses AArch64 EL2 in VHE mode. Some porting is required to support ARMv8.0.
+Gunyah currently supports the ARM64 (ARMv8+) architecure, it uses AArch64 EL2
+in VHE mode by default.
-We have developed an initial port of Gunyah to the QEMU ARMv8 simulator. *Note QEMU v5+ is required*. Additional platforms are expected to be supported in future contributions.
+We have developed an initial port of Gunyah to the QEMU Arm System emulator.
+*Note QEMU v7+ is recommended*. Additional platforms are expected to be
+supported in future contributions.
## Getting Started
+- [Terminology](docs/terminology.md)
- [Setup Instructions](docs/setup.md)
+ + [Quick Start Instructions](https://github.com/quic/gunyah-support-scripts/blob/develop/quickstart.md)
- [Build Instructions](docs/build.md)
-- [Testing Instructions](docs/test.md)
-- [Changelog](CHANGELOG.md)
+- [Status and Changelog](CHANGELOG.md)
## Resources
- [Gunyah Hypercall API](docs/api/gunyah_api.md)
diff --git a/SConstruct b/SConstruct
index 8b8f160..d7c9052 100644
--- a/SConstruct
+++ b/SConstruct
@@ -10,8 +10,10 @@ import os
env_vars = {
'PATH': os.environ['PATH'],
- 'LLVM': os.environ['LLVM'],
}
+if 'LLVM' in os.environ:
+ env_vars['LLVM'] = os.environ['LLVM']
+
env = Environment(tools={}, SCANNERS=[], BUILDERS={}, ENV=env_vars)
configure.SConsBuild(env, Builder, Action, arguments=SCons.Script.ARGUMENTS)()
diff --git a/config/arch/aarch64.conf b/config/arch/aarch64.conf
index d718fd4..a5c6221 100644
--- a/config/arch/aarch64.conf
+++ b/config/arch/aarch64.conf
@@ -6,6 +6,5 @@ is_abi
# Use the Linux target because it knows how to link with LLD
target_triple aarch64-linux-gnu
defines_link
-defines_registers
flags -mgeneral-regs-only -mtp=el2
configs ARCH_IS_64BIT=1 ARCH_ENDIAN_LITTLE=1
diff --git a/config/arch/cortex-a-v8_0.conf b/config/arch/cortex-a-v8_0.conf
new file mode 100644
index 0000000..7357280
--- /dev/null
+++ b/config/arch/cortex-a-v8_0.conf
@@ -0,0 +1,28 @@
+# © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+base_arch armv8-64
+
+configs ARCH_AARCH64_32BIT_EL0=1
+configs ARCH_AARCH64_32BIT_EL0_ALL_CORES=1
+# FIXME
+configs ARCH_AARCH64_32BIT_EL1=0
+
+# Mandatory architecture extensions in v8.0
+configs ARCH_ARM_PMU_VER=3
+
+# The number of implemented ICH_LR_EL2 registers.
+configs CPU_GICH_LR_COUNT=4U
+
+# The number of implemented ICH_APR[01]R_EL2 registers.
+configs CPU_GICH_APR_COUNT=1U
+
+# The number of implemented DBGB[CV]R_EL1 (HW breakpoint) registers.
+configs CPU_DEBUG_BP_COUNT=6U
+
+# The number of implemented DBGW[CV]R_EL1 (HW watchpoint) registers.
+configs CPU_DEBUG_WP_COUNT=4U
+
+# These CPUs always have an ETM.
+configs PLATFORM_HAS_NO_ETM_BASE=0
diff --git a/config/arch/cortex-a-v8_2.conf b/config/arch/cortex-a-v8_2.conf
index 0091510..b3b8c14 100644
--- a/config/arch/cortex-a-v8_2.conf
+++ b/config/arch/cortex-a-v8_2.conf
@@ -5,28 +5,36 @@
base_arch armv8-64
configs ARCH_AARCH64_32BIT_EL0=1
+configs ARCH_AARCH64_32BIT_EL0_ALL_CORES=1
configs ARCH_AARCH64_32BIT_EL1=0
+# Checked for Cortex-(A55,A65,A75,A76,A77,A78,X1)
+configs CPU_HAS_NO_ACTLR_EL1=1
+configs CPU_HAS_NO_AMAIR_EL1=1
+configs CPU_HAS_NO_AFSR0_EL1=1
+configs CPU_HAS_NO_AFSR1_EL1=1
+
# Mandatory architecture extensions in v8.2
-configs ARCH_ARM_8_0_CSV2=1
-configs ARCH_ARM_8_0_CSV3=1
-
-configs ARCH_ARM_8_1_HPD=1
-configs ARCH_ARM_8_1_LSE=1
-configs ARCH_ARM_8_1_LOR=1
-configs ARCH_ARM_8_1_PAN=1
-configs ARCH_ARM_8_1_RDMA=1
-configs ARCH_ARM_8_1_VHE=1
-
-configs ARCH_ARM_8_2_A64ISA=1
-configs ARCH_ARM_8_2_ATS1E1=1
-configs ARCH_ARM_8_2_DCPOP=1
-configs ARCH_ARM_8_2_DEBUG=1
-configs ARCH_ARM_8_2_DOTPROD=1
-configs ARCH_ARM_8_2_RAS=1
-configs ARCH_ARM_8_2_TTCNP=1
-configs ARCH_ARM_8_2_TTS2UXN=1
-configs ARCH_ARM_8_2_UAO=1
+configs ARCH_ARM_FEAT_CSV2=1
+configs ARCH_ARM_FEAT_CSV3=1
+
+configs ARCH_ARM_FEAT_HPDS=1
+configs ARCH_ARM_FEAT_LSE=1
+configs ARCH_ARM_FEAT_LOR=1
+configs ARCH_ARM_FEAT_PAN=1
+configs ARCH_ARM_FEAT_RDM=1
+configs ARCH_ARM_FEAT_VHE=1
+configs ARCH_ARM_FEAT_CRC32=1
+
+configs ARCH_ARM_FEAT_ASMv8p2=1
+configs ARCH_ARM_FEAT_PAN2=1
+configs ARCH_ARM_FEAT_DPB=1
+configs ARCH_ARM_FEAT_DEBUGv8p2=1
+configs ARCH_ARM_FEAT_DotProd=1
+configs ARCH_ARM_FEAT_RAS=1
+configs ARCH_ARM_FEAT_TTCNP=1
+configs ARCH_ARM_FEAT_XNX=1
+configs ARCH_ARM_FEAT_UAO=1
configs ARCH_AARCH64_ASID16=1 ARCH_ARM_PMU_VER=3
@@ -44,9 +52,7 @@ configs CPU_DEBUG_WP_COUNT=4U
# The level of support for ARMv8.4-TTRem on this CPU (encoded the same way
# as ID_AA64MMFR2_EL1.BBM).
-configs CPU_PGTABLE_BLOCK_SPLIT_LEVEL=2U
-# The FORCE config is set to ignore the ID register, since these CPUs do not
-# implement the extension but for most purposes behave as if they do so at
-# level 2; the only difference apart from the ID register is that TLB conflict
-# aborts may be reported to EL1 when stage 2 is enabled.
-configs CPU_PGTABLE_BLOCK_SPLIT_LEVEL_FORCE=1
+configs CPU_PGTABLE_BBM_LEVEL=0U
+
+# These CPUs always have an ETM.
+configs PLATFORM_HAS_NO_ETM_BASE=0
diff --git a/config/arch/cortex-a53.conf b/config/arch/cortex-a53.conf
new file mode 100644
index 0000000..1b85801
--- /dev/null
+++ b/config/arch/cortex-a53.conf
@@ -0,0 +1,19 @@
+# © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+base_arch cortex-a-v8_0
+flags -mcpu=cortex-a53
+
+configs ARCH_CORE_IDS=CORTEX_A53
+
+configs CPU_PGTABLE_BBM_LEVEL=0U
+
+configs CPU_HAS_NO_ACTLR_EL1=1
+configs CPU_HAS_NO_AMAIR_EL1=1
+configs CPU_HAS_NO_AFSR0_EL1=1
+configs CPU_HAS_NO_AFSR1_EL1=1
+
+# Fixed fields in cortex-a53
+configs PLATFORM_MPIDR_AFF3_MASK=0
+configs PLATFORM_MPIDR_AFF3_SHIFT=0
diff --git a/config/arch/cortex-a55-a76.conf b/config/arch/cortex-a55-a76.conf
index a42412b..6585b53 100644
--- a/config/arch/cortex-a55-a76.conf
+++ b/config/arch/cortex-a55-a76.conf
@@ -4,5 +4,8 @@
base_arch cortex-a-v8_2
flags -mcpu=cortex-a76
-configs ARCH_AARCH64_USE_PAN=1
+configs ARCH_CORE_IDS=CORTEX_A55,CORTEX_A76
+
+configs ARCH_AARCH64_BIG_END_ALL_CORES=1
+
configs ARCH_ARM_PMU_HPMN_UNPREDICTABLE=1
diff --git a/config/arch/cortex-a55-a77.conf b/config/arch/cortex-a55-a77.conf
index 967024c..3300340 100644
--- a/config/arch/cortex-a55-a77.conf
+++ b/config/arch/cortex-a55-a77.conf
@@ -4,10 +4,13 @@
base_arch cortex-a-v8_2
flags -mcpu=cortex-a77
-configs ARCH_AARCH64_USE_PAN=1
-configs ARCH_ARM_8_1_VMID16=1
+configs ARCH_CORE_IDS=CORTEX_A55,CORTEX_A77
+
+configs ARCH_AARCH64_BIG_END_ALL_CORES=1
+
+configs ARCH_ARM_FEAT_VMID16=1
configs ARCH_ARM_PMU_HPMN_UNPREDICTABLE=1
-configs ARCH_ARM_8_1_PMU=1
-configs ARCH_ARM_8_2_IESB=1
-configs ARCH_ARM_8_2_TTPBHA=1
+configs ARCH_ARM_FEAT_PMUv3p1=1
+configs ARCH_ARM_FEAT_IESB=1
+configs ARCH_ARM_FEAT_HPDS2=1
diff --git a/config/arch/cortex-a55-a78-x1.conf b/config/arch/cortex-a55-a78-x1.conf
index eb63bb3..68bb977 100644
--- a/config/arch/cortex-a55-a78-x1.conf
+++ b/config/arch/cortex-a55-a78-x1.conf
@@ -4,10 +4,13 @@
base_arch cortex-a-v8_2
flags -mcpu=cortex-x1
-configs ARCH_AARCH64_USE_PAN=1
-configs ARCH_ARM_8_1_VMID16=1
+
+configs ARCH_AARCH64_BIG_END_ALL_CORES=1
+
+configs ARCH_CORE_IDS=CORTEX_A55,CORTEX_A78,CORTEX_X1
+configs ARCH_ARM_FEAT_VMID16=1
configs ARCH_ARM_PMU_HPMN_UNPREDICTABLE=1
-configs ARCH_ARM_8_1_PMU=1
-configs ARCH_ARM_8_2_IESB=1
-configs ARCH_ARM_8_2_TTPBHA=1
+configs ARCH_ARM_FEAT_PMUv3p1=1
+configs ARCH_ARM_FEAT_IESB=1
+configs ARCH_ARM_FEAT_HPDS2=1
diff --git a/config/arch/cortex-a55.conf b/config/arch/cortex-a55.conf
index 102472b..e12504b 100644
--- a/config/arch/cortex-a55.conf
+++ b/config/arch/cortex-a55.conf
@@ -4,10 +4,10 @@
base_arch cortex-a-v8_2
flags -mcpu=cortex-a55
-configs ARCH_AARCH64_USE_PAN=1
-configs ARCH_ARM_8_1_VMID16=1
+configs ARCH_CORE_IDS=CORTEX_A55
+configs ARCH_ARM_FEAT_VMID16=1
configs ARCH_ARM_PMU_HPMN_UNPREDICTABLE=1
-configs ARCH_ARM_8_1_PMU=1
-configs ARCH_ARM_8_2_IESB=1
-configs ARCH_ARM_8_2_TTPBHA=1
+configs ARCH_ARM_FEAT_PMUv3p1=1
+configs ARCH_ARM_FEAT_IESB=1
+configs ARCH_ARM_FEAT_HPDS2=1
diff --git a/config/arch/cortex-a78.conf b/config/arch/cortex-a78.conf
index 54f9223..07c2af1 100644
--- a/config/arch/cortex-a78.conf
+++ b/config/arch/cortex-a78.conf
@@ -4,10 +4,10 @@
base_arch cortex-a-v8_2
flags -mcpu=cortex-a78
-configs ARCH_AARCH64_USE_PAN=1
-configs ARCH_ARM_8_1_VMID16=1
+configs ARCH_CORE_IDS=CORTEX_A78
+configs ARCH_ARM_FEAT_VMID16=1
configs ARCH_ARM_PMU_HPMN_UNPREDICTABLE=1
-configs ARCH_ARM_8_1_PMU=1
-configs ARCH_ARM_8_2_IESB=1
-configs ARCH_ARM_8_2_TTPBHA=1
+configs ARCH_ARM_FEAT_PMUv3p1=1
+configs ARCH_ARM_FEAT_IESB=1
+configs ARCH_ARM_FEAT_HPDS2=1
diff --git a/config/arch/gic-500.conf b/config/arch/gic-500.conf
new file mode 100644
index 0000000..338c577
--- /dev/null
+++ b/config/arch/gic-500.conf
@@ -0,0 +1,15 @@
+# © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+configs GICV3_EXT_IRQS=0
+# There may be an ITS, but it is not useful to the hypervisor without vLPIs
+configs GICV3_HAS_ITS=0
+configs GICV3_HAS_LPI=0
+configs GICV3_HAS_VLPI=0
+configs GICV3_HAS_VLPI_V4_1=0
+configs GICV3_HAS_1N=1
+configs GICV3_HAS_GICD_ICLAR=0
+configs GICV3_HAS_SECURITY_DISABLED=0
+configs PLATFORM_GICD_BASE=PLATFORM_GIC_BASE
+configs PLATFORM_GICR_SIZE=(0x20000*PLATFORM_MAX_CORES)
diff --git a/config/arch/gic-600.conf b/config/arch/gic-600.conf
new file mode 100644
index 0000000..7a9a45d
--- /dev/null
+++ b/config/arch/gic-600.conf
@@ -0,0 +1,20 @@
+# © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+configs GICV3_EXT_IRQS=0
+# There may be an ITS, but it is not useful to the hypervisor without vLPIs
+configs GICV3_HAS_ITS=0
+configs GICV3_HAS_LPI=0
+configs GICV3_HAS_VLPI=0
+configs GICV3_HAS_VLPI_V4_1=0
+configs GICV3_HAS_1N=1
+configs GICV3_HAS_GICD_ICLAR=1
+configs GICV3_HAS_SECURITY_DISABLED=0
+configs PLATFORM_GICD_BASE=PLATFORM_GIC_BASE
+configs PLATFORM_GICA_BASE=(PLATFORM_GIC_BASE+0x10000U)
+configs PLATFORM_GITS_BASE=(PLATFORM_GIC_BASE+0x40000U)
+configs PLATFORM_GITS_SIZE=(0x20000U*PLATFORM_GITS_COUNT)
+configs PLATFORM_GICR_BASE=(PLATFORM_GITS_BASE+PLATFORM_GITS_SIZE)
+configs PLATFORM_GICR_SIZE=(0x20000U*PLATFORM_GICR_COUNT)
+configs PLATFORM_GIC_SIZE=(0x50000U+PLATFORM_GITS_SIZE+PLATFORM_GICR_SIZE)
diff --git a/config/arch/gic-700-vlpi.conf b/config/arch/gic-700-vlpi.conf
new file mode 100644
index 0000000..24e41d8
--- /dev/null
+++ b/config/arch/gic-700-vlpi.conf
@@ -0,0 +1,19 @@
+# © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+configs GICV3_EXT_IRQS=0
+configs GICV3_HAS_ITS=1
+configs GICV3_HAS_LPI=1
+configs GICV3_HAS_VLPI=1
+configs GICV3_HAS_VLPI_V4_1=1
+configs GICV3_HAS_1N=1
+configs GICV3_HAS_GICD_ICLAR=1
+configs GICV3_HAS_SECURITY_DISABLED=0
+configs PLATFORM_GICD_BASE=PLATFORM_GIC_BASE
+configs PLATFORM_GICA_BASE=(PLATFORM_GIC_BASE+0x10000U)
+configs PLATFORM_GITS_BASE=(PLATFORM_GIC_BASE+0x40000U)
+configs PLATFORM_GITS_SIZE=(0x40000U*PLATFORM_GITS_COUNT)
+configs PLATFORM_GICR_BASE=(PLATFORM_GITS_BASE+PLATFORM_GITS_SIZE)
+configs PLATFORM_GICR_SIZE=(0x40000U*PLATFORM_GICR_COUNT)
+configs PLATFORM_GIC_SIZE=(0x50000U+PLATFORM_GITS_SIZE+PLATFORM_GICR_SIZE)
diff --git a/config/arch/gic-qemu.conf b/config/arch/gic-qemu.conf
index 6fb1f46..d0105bf 100644
--- a/config/arch/gic-qemu.conf
+++ b/config/arch/gic-qemu.conf
@@ -5,12 +5,15 @@
configs GICV3_EXT_IRQS=0
# There may be an ITS, but it is not useful to the hypervisor without vLPIs
configs GICV3_HAS_ITS=0
+configs GICV3_HAS_LPI=0
+configs GICV3_HAS_VLPI=0
+configs GICV3_HAS_VLPI_V4_1=0
configs GICV3_HAS_1N=0
configs GICV3_HAS_GICD_ICLAR=0
configs GICV3_HAS_SECURITY_DISABLED=1
configs PLATFORM_GICD_BASE=PLATFORM_GIC_BASE
configs PLATFORM_GITS_BASE=(PLATFORM_GIC_BASE+0x80000U)
-configs PLATFORM_GITS_SIZE=(0x20000*PLATFORM_GITS_COUNT)
+configs PLATFORM_GITS_SIZE=(0x20000U*PLATFORM_GITS_COUNT)
configs PLATFORM_GICR_BASE=(PLATFORM_GITS_BASE+PLATFORM_GITS_SIZE)
-configs PLATFORM_GICR_SIZE=(0x20000*PLATFORM_MAX_CORES)
-configs PLATFORM_GIC_SIZE=(0x50000+PLATFORM_GITS_SIZE+PLATFORM_GICR_SIZE)
+configs PLATFORM_GICR_SIZE=(0x20000U*PLATFORM_MAX_CORES)
+configs PLATFORM_GIC_SIZE=(0x50000U+PLATFORM_GITS_SIZE+PLATFORM_GICR_SIZE)
diff --git a/config/arch/qemu-armv8-5a-rng.conf b/config/arch/qemu-armv8-5a-rng.conf
index b6e2ee7..3661e22 100644
--- a/config/arch/qemu-armv8-5a-rng.conf
+++ b/config/arch/qemu-armv8-5a-rng.conf
@@ -1,8 +1,79 @@
-# © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+# © 2022 Qualcomm Innovation Center, Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
-base_arch cortex-a55-a77
+base_arch armv8-64
flags -march=armv8.5-a+rng
-configs ARCH_ARM_8_5_RNG=1
+configs PLATFORM_MAX_CORES=8U
+configs PLATFORM_USABLE_CORES=0xFFU
+
+configs PLATFORM_MPIDR_AFF0_MASK=0x7U
+configs PLATFORM_MPIDR_AFF0_SHIFT=0
+configs PLATFORM_MPIDR_AFF1_MASK=0U
+configs PLATFORM_MPIDR_AFF1_SHIFT=0
+configs PLATFORM_MPIDR_AFF2_MASK=0U
+configs PLATFORM_MPIDR_AFF2_SHIFT=0
+configs PLATFORM_MPIDR_AFF3_MASK=0U
+configs PLATFORM_MPIDR_AFF3_SHIFT=0
+
+configs ARCH_CORE_IDS=QEMU
+
+configs ARCH_ARM_FEAT_AES=1
+configs ARCH_ARM_FEAT_PMULL=1
+configs ARCH_ARM_FEAT_SHA1=1
+configs ARCH_ARM_FEAT_RNG=1
+
+configs ARCH_AARCH64_BIG_END_ALL_CORES=1
+configs ARCH_AARCH64_32BIT_EL0=1
+configs ARCH_AARCH64_32BIT_EL0_ALL_CORES=1
+configs ARCH_AARCH64_32BIT_EL1=0
+
+configs ARCH_ARM_FEAT_VMID16=1
+configs ARCH_ARM_PMU_HPMN_UNPREDICTABLE=1
+
+configs ARCH_ARM_FEAT_PMUv3p1=1
+configs ARCH_ARM_FEAT_IESB=1
+configs ARCH_ARM_FEAT_HPDS2=1
+# Assume sve128=on
+configs ARCH_ARM_FEAT_SVE=1
+configs PLATFORM_SVE_REG_SIZE=16U
+
+configs ARCH_ARM_FEAT_CSV2=1
+configs ARCH_ARM_FEAT_CSV3=1
+
+configs ARCH_ARM_FEAT_HPDS=1
+configs ARCH_ARM_FEAT_LSE=1
+configs ARCH_ARM_FEAT_LOR=1
+configs ARCH_ARM_FEAT_PAN=1
+configs ARCH_ARM_FEAT_RDM=1
+configs ARCH_ARM_FEAT_VHE=1
+configs ARCH_ARM_FEAT_CRC32=1
+
+configs ARCH_ARM_FEAT_ASMv8p2=1
+configs ARCH_ARM_FEAT_PAN2=1
+configs ARCH_ARM_FEAT_DPB=1
+configs ARCH_ARM_FEAT_DEBUGv8p2=1
+configs ARCH_ARM_FEAT_DotProd=1
+configs ARCH_ARM_FEAT_RAS=1
+configs ARCH_ARM_FEAT_TTCNP=1
+configs ARCH_ARM_FEAT_XNX=1
+configs ARCH_ARM_FEAT_UAO=1
+
+configs ARCH_AARCH64_ASID16=1 ARCH_ARM_PMU_VER=3
+
+# The number of implemented ICH_LR_EL2 registers.
+configs CPU_GICH_LR_COUNT=4U
+
+# The number of implemented ICH_APR[01]R_EL2 registers.
+configs CPU_GICH_APR_COUNT=1U
+
+# The number of implemented DBGB[CV]R_EL1 (HW breakpoint) registers.
+configs CPU_DEBUG_BP_COUNT=6U
+
+# The number of implemented DBGW[CV]R_EL1 (HW watchpoint) registers.
+configs CPU_DEBUG_WP_COUNT=4U
+
+# The level of support for ARMv8.4-TTRem on this CPU (encoded the same way
+# as ID_AA64MMFR2_EL1.BBM).
+configs CPU_PGTABLE_BBM_LEVEL=0U
diff --git a/config/featureset/gunyah-rm-qemu.conf b/config/featureset/gunyah-rm-qemu.conf
index 59c5eb6..0f545ca 100644
--- a/config/featureset/gunyah-rm-qemu.conf
+++ b/config/featureset/gunyah-rm-qemu.conf
@@ -27,6 +27,8 @@ module core/irq
module core/task_queue
module core/timer
module core/power
+module core/wait_queue_broadcast
+module core/globals
module debug/object_lists
module debug/symbol_version
module ipc/doorbell
@@ -37,22 +39,28 @@ module mem/memdb
module mem/hyp_aspace
module mem/pgtable
module mem/addrspace
-module mem/memextent
+module mem/memextent_sparse
module misc/elf
module misc/prng_hw
module misc/prng_simple
module misc/trace_standard
module misc/smc_trace
module misc/log_standard
+module platform/arm_generic
module platform/arm_smccc
module platform/arm_trng_fi
+arch_module aarch64 misc/spectre_arm
+module misc/qcbor
module vm/rootvm
module vm/rootvm_package
-module vm/vcpu
module vm/slat
+module vm/vcpu
+module vm/vcpu_power
+module vm/vcpu_run
arch_module armv8 vm/smccc
arch_module armv8 vm/psci_pc
arch_module armv8 vm/vdebug
arch_module armv8 vm/vgic
arch_module armv8 vm/arm_vm_timer
arch_module armv8 vm/arm_vm_pmu
+arch_module armv8 vm/arm_vm_sve_simple
diff --git a/config/featureset/unittests-qemu.conf b/config/featureset/unittests-qemu.conf
new file mode 100644
index 0000000..4072ff8
--- /dev/null
+++ b/config/featureset/unittests-qemu.conf
@@ -0,0 +1,54 @@
+# © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+configs HYP_CONF_STR=unittest UNITTESTS=1
+configs UNIT_TESTS=1
+platforms qemu
+
+module core/api
+module core/base
+module core/boot
+module core/util
+module misc/abort
+module core/object_standard
+module core/thread_standard
+module core/idle
+module core/scheduler_fprr
+module core/partition_standard
+module core/preempt
+module core/cpulocal
+module core/spinlock_ticket
+module core/mutex_trivial
+module core/rcu_bitmap
+module core/cspace_twolevel
+module core/tests
+module core/vectors
+module core/debug
+module core/ipi
+module core/irq
+module core/virq_null
+module core/timer
+module core/power
+module debug/object_lists
+module debug/symbol_version
+module mem/allocator_list
+configs ALLOCATOR_DEBUG=1
+module mem/allocator_boot
+module mem/memdb
+module mem/hyp_aspace
+module mem/pgtable
+module mem/addrspace
+module mem/memextent_sparse
+module misc/elf
+module misc/gpt
+module misc/prng_simple
+module misc/trace_standard
+module misc/log_standard
+module misc/smc_trace
+module misc/qcbor
+arch_module aarch64 misc/spectre_arm
+module platform/arm_generic
+module platform/arm_smccc
+module vm/slat
+configs POWER_START_ALL_CORES=1
diff --git a/config/include/debug_no_cspace_rand.conf b/config/include/debug_no_cspace_rand.conf
new file mode 100644
index 0000000..689ec86
--- /dev/null
+++ b/config/include/debug_no_cspace_rand.conf
@@ -0,0 +1,5 @@
+# © 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+configs DISABLE_CSPACE_RAND=1
diff --git a/config/include/debug_no_kaslr.conf b/config/include/debug_no_kaslr.conf
new file mode 100644
index 0000000..c9f4e87
--- /dev/null
+++ b/config/include/debug_no_kaslr.conf
@@ -0,0 +1,5 @@
+# © 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+configs DISABLE_KASLR=1
diff --git a/config/include/debug_no_rootvm_aslr.conf b/config/include/debug_no_rootvm_aslr.conf
new file mode 100644
index 0000000..1a2915c
--- /dev/null
+++ b/config/include/debug_no_rootvm_aslr.conf
@@ -0,0 +1,5 @@
+# © 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+configs DISABLE_ROOTVM_ASLR=1
diff --git a/config/platform/qemu.conf b/config/platform/qemu.conf
index 1a6794d..bc612f2 100644
--- a/config/platform/qemu.conf
+++ b/config/platform/qemu.conf
@@ -11,28 +11,47 @@ module platform/soc_qemu
module platform/arm_arch_timer
module platform/arm_pmu
module platform/arm_rng
+
+# PLATFORM_LMA_BASE is used in linker script
+# this is used to link Hyp image to this address
configs PLATFORM_LMA_BASE=0x80000000
-configs PLATFORM_MAX_CORES=8
-configs PLATFORM_USABLE_CORES=0xFF
+
+# These define what is the installed memory range of
+# the platform hardware (memsize while invoking qemu)
+configs PLATFORM_DDR_BASE=0x40000000U
+configs PLATFORM_DDR_SIZE=0x80000000U
+
+# These define the amount of memory given to the HLOS
+# which is defined in the DT loaded for linux
+configs HLOS_VM_DDR_BASE=0x40000000U
+configs HLOS_VM_DDR_SIZE=0x40000000U
+
+# Address locations where Linux kernel, DT and RAMFS are
+# loaded when Qemu is started
+configs HLOS_ENTRY_POINT=0x41000000
+configs HLOS_DT_BASE=0x40F00000
+configs HLOS_RAM_FS_BASE=0x40800000
+
configs PLATFORM_HEAP_PRIVATE_SIZE=0x200000
-configs PLATFORM_ROOTVM_LMA_BASE=0x80480000
-configs PLATFORM_ROOTVM_LMA_SIZE=0xa0000
-configs HYP_ASPACE_MAP_DIRECT_BITS=36
+configs PLATFORM_RW_DATA_SIZE=0x200000
+configs PLATFORM_ROOTVM_LMA_BASE=0x80480000U
+configs PLATFORM_ROOTVM_LMA_SIZE=0xa0000U
+configs PLATFORM_PHYS_ADDRESS_BITS=36
configs PLATFORM_VM_ADDRESS_SPACE_BITS=36
configs PLATFORM_PGTABLE_4K_GRANULE=1
configs PLATFORM_ARCH_TIMER_FREQ=62500000
configs PLATFORM_HYP_ARCH_TIMER_IRQ=26
-configs PLATFORM_VM_ARCH_VIRTUAL_TIMER_IRQ=27
+configs PLATFORM_VM_ARCH_VIRTUAL_TIMER_IRQ=27U
configs PLATFORM_VM_ARCH_PHYSICAL_TIMER_IRQ=30
configs PLATFORM_GIC_BASE=0x08000000U
+configs PLATFORM_GICR_COUNT=PLATFORM_MAX_CORES
+configs PLATFORM_MAX_CLUSTERS=1U
+configs PLATFORM_MAX_HIERARCHY=1U
configs PLATFORM_GITS_COUNT=1
configs PLATFORM_GICH_IRQ=25
configs PLATFORM_PMU_IRQ=23
configs PLATFORM_VM_PMU_IRQ=23
configs PLATFORM_PMU_CNT_NUM=4
-configs ARCH_ARM_8_0_AES=1
-configs ARCH_ARM_8_0_AES_PMULL=1
-configs ARCH_ARM_8_0_SHA=1
# We currently do not have a wdog QEMU platform implementation
configs WATCHDOG_DISABLE=1
# QEMU does not use affinity levels and uses original powerstate format
diff --git a/config/quality/debug.conf b/config/quality/debug.conf
index 0645c26..8ffdf8f 100644
--- a/config/quality/debug.conf
+++ b/config/quality/debug.conf
@@ -5,13 +5,16 @@
configs VERBOSE=1
configs VERBOSE_TRACE=1
configs RESET_ON_ABORT=0
-configs DISABLE_CSPACE_RAND=1
-configs DISABLE_ROOTVM_ASLR=1
configs QUALITY=debug
flags -O1 -g -mstrict-align
-arch_configs aarch64 ARCH_SANITIZE_STACK_SIZE=1536
+#include include/debug_no_kaslr
+include include/debug_no_cspace_rand
+include include/debug_no_rootvm_aslr
+
+arch_configs aarch64 ARCH_SANITIZE_STACK_SIZE=1536U
+arch_configs aarch64 VCPU_MIN_STACK_SIZE=8192U
# The trace entry numbers include the header
arch_configs qemu TRACE_BOOT_ENTRIES=128 PER_CPU_TRACE_ENTRIES=4096 TRACE_FORMAT=1
-arch_configs qemu TRACE_AREA_SIZE=0x2000000U EXTRA_PRIVATE_HEAP_SIZE=0x100000U EXTRA_ROOT_HEAP_SIZE=0x300000U
+arch_configs qemu TRACE_AREA_SIZE=0x2000000 EXTRA_PRIVATE_HEAP_SIZE=0x100000 EXTRA_ROOT_HEAP_SIZE=0x300000
diff --git a/config/quality/production-unchecked.conf b/config/quality/production-unchecked.conf
index a41a046..7e8b57f 100644
--- a/config/quality/production-unchecked.conf
+++ b/config/quality/production-unchecked.conf
@@ -7,8 +7,9 @@ configs RESET_ON_ABORT=1
configs QUALITY=perf
flags -flto -O3 -g
+# This is slightly overkill for LTO builds, but safe.
arch_configs aarch64 ARCH_SANITIZE_STACK_SIZE=1024
# The trace entry numbers include the header
arch_configs qemu TRACE_BOOT_ENTRIES=128 PER_CPU_TRACE_ENTRIES=4096 TRACE_FORMAT=1
-arch_configs qemu TRACE_AREA_SIZE=0x200000U EXTRA_PRIVATE_HEAP_SIZE=0x100000U EXTRA_ROOT_HEAP_SIZE=0x300000U
+arch_configs qemu TRACE_AREA_SIZE=0x2000000U EXTRA_PRIVATE_HEAP_SIZE=0x100000U EXTRA_ROOT_HEAP_SIZE=0x300000U
diff --git a/configure.py b/configure.py
index adde557..91ed1cc 100755
--- a/configure.py
+++ b/configure.py
@@ -501,6 +501,12 @@ def __call__(self, gen_cmd=None, **kwargs):
# Add a phony rule for always-built targets
self.add_alias(self._phony_always, [])
+ # Add phony rules for all of the generator sources, so Ninja
+ # does not fail if one of them disappears (e.g. if a module
+ # is renamed, or an older branch is checked out)
+ for f in sorted(self._gen_sources):
+ self.add_alias(f, [])
+
# Add a rule and targets for all of the automatically created parent
# directories. We do this in deepest-first order at the end of the
# build file because ninja -t clean always processes targets in the
diff --git a/docs/api/Makefile b/docs/api/Makefile
new file mode 100644
index 0000000..15efcd1
--- /dev/null
+++ b/docs/api/Makefile
@@ -0,0 +1,9 @@
+%.pdf: %.md Makefile
+ pandoc -s --toc --pdf-engine=xelatex -N --top-level-division=part \
+ --metadata=title:'Gunyah Hypercall API' \
+ --variable=class:book \
+ --variable=mainfont:LiberationSans \
+ --variable=monofont:LiberationMono \
+ $< -o $@
+
+all: gunyah_api.pdf
diff --git a/docs/api/gunyah_api.md b/docs/api/gunyah_api.md
index 19a1495..b4df733 100644
--- a/docs/api/gunyah_api.md
+++ b/docs/api/gunyah_api.md
@@ -1,26 +1,6 @@
-# Gunyah Hypercall API
-
-1. [AARCH64 HVC ABI](#aarch64-hvc-abi)
-1. [Common Types](#common-types)
-1. [Object Rights](#object-rights)
-1. [Hypervisor Identification](#hypervisor-identification)
-1. [Partitions](#partitions)
-1. [Object Management](#object-management)
-1. [Communication APIs](#communication-apis)
- 7.1 [Doorbell Management](#doorbell-management)
- 7.2 [Message Queue Management](#message-queue-management)
-1. [Capability Management](#capability-management)
-1. [Interrupt Management](#interrupt-management)
-1. [Address Space Management](#address-space-management)
-1. [Memory Extent Management](#memory-extent-management)
-1. [VCPU Management](#vcpu-management)
-1. [Scheduler Management](#scheduler-management)
-1. [Virtual PM Group Management](#virtual-pm-group-management)
-1. [Trace Buffer Management](#trace-buffer-management)
-1. [Watchdog Management](#watchdog-management)
-1. [Error Results](#error-results)
-
-## AARCH64 HVC ABI
+# Gunyah API
+
+## AArch64 HVC ABI
The Gunyah AArch64 hypercall interface generally follows the ARM AAPCS64 conventions for general purpose register argument and result passing, and preservation of registers, unless explicitly documented otherwise. The hypervisor does not use SIMD, Floating-Point or SVE registers in the hypercall interface.
Gunyah hypercalls use a range of HVC opcode immediate numbers, and reserves the following HVC immediate range:
@@ -35,8 +15,8 @@ Note, Gunyah hypercalls encode the Call-ID in the HVC immediate, encoded within
### General-purpose Register
-| Register | Role in AAPCS64 | Role in Gunyah HVC |
-|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
+| Register | Role in AAPCS64 | Role in Gunyah HVC |
+|--|---|-----|
| SP_EL0 / SP_EL1 | The Stack Pointers | Preserved. (Callee-saved) |
| r30 / LR | The Link Register | Preserved. (Callee-saved) |
| r29 / FR | The Frame Register | Preserved. (Callee-saved) |
@@ -92,14 +72,18 @@ A pointer in the VM’s current virtual address space, in the context of the cal
A pointer in the VM’s physical address space. In ARMv8 terminology, this is an IPA.
+### Access Rights
+
+An enumeration describing the rights given to a memory mapping. Follows the standard RWX format.
+
### Virtual IRQ Info
A bitfield type that identifies a virtual IRQ within a virtual interrupt controller.
*Virtual IRQ Info:*
-| Bit Numbers | Mask | Description |
-|----------------------|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 23:0 | `0x00FFFFFF` | Virtual IRQ Number. The valid range of this field is defined by the platform-specific virtual interrupt controller implementation. The range may be discontiguous, and some sub-ranges may have special meanings (e.g. there may be a range reserved for VCPU-specific VIRQs). |
| 31..24 | `0xFF000000` | Target VCPU index. This is the attachment index of a VCPU as defined by the hypercall API that configures the virtual interrupt controller. Valid only if the virtual IRQ number is in a range reserved by the virtual interrupt controller for VCPU-specific IRQs, and the operation being performed is implemented for VCPU-specific IRQs. |
| 63:32 | `0xFFFFFFFF.00000000` | Reserved, Must be Zero |
@@ -121,6 +105,7 @@ Generic rights are valid for all object types.
| Right | Value |
|-------------------|-------------------|
| Partition Object Create | `0x00000001` |
+| Partition Donate | `0x00000002` |
### Capability Space Rights
@@ -137,6 +122,7 @@ Generic rights are valid for all object types.
|-------------------|-------------------|
| Address Space Attach | `0x00000001` |
| Address Space Map | `0x00000002` |
+| Address Space Lookup | `0x00000004` |
### Memory Extent Rights
@@ -145,6 +131,8 @@ Generic rights are valid for all object types.
| Memory Extent Map | `0x00000001` |
| Memory Extent Derive | `0x00000002` |
| Memory Extent Attach | `0x00000004` |
+| Memory Extent Lookup | `0x00000008` |
+| Memory Extent Donate | `0x00000010` |
### Thread Rights
@@ -155,7 +143,11 @@ Generic rights are valid for all object types.
| Thread Set Priority | `0x00000004` |
| Thread Set Timeslice | `0x00000008` |
| Thread Yield To | `0x00000010` |
+| Thread Bind VIRQ | `0x00000020` |
+| Thread Access State | `0x00000040` |
| Thread Lifecycle | `0x00000080` |
+| Thread Write Context | `0x00000100` |
+| Thread Disable | `0x00000200` |
### Doorbell Rights
@@ -238,8 +230,8 @@ Identifies the hypervisor version and feature set.
*Hyp API Info:*
-| Bit Numbers | Mask | Description |
-|-----------------|------------------------|---------------------------------------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 13:0 | `0x00001FFF` | API Version = “1” |
| 14 | `0x00004000` | 0 = API is Little Endian.
1 = API is Big Endian. |
| 15 | `0x00008000` | If set to 1, the API is 64-bit, otherwise 32-bit. |
@@ -248,8 +240,8 @@ Identifies the hypervisor version and feature set.
*API Flags 0:*
-| Bit Numbers | Mask | Description |
-|----------------------|----------------------------|--------------------------------------------------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 0 | `0x1` | 1 = Partition and CSpace APIs supported |
| 1 | `0x2` | 1 = Doorbell APIs supported |
| 2 | `0x4` | 1 = Message Queue APIs supported |
@@ -265,15 +257,15 @@ Identifies the hypervisor version and feature set.
*API Flags 1:*
-| Bit Numbers | Mask | Description |
-|----------------------|----------------------------|---------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 0 | `0x1` | 1 = ARM v8.2 SVE support |
| 63:1 | `0xFFFFFFFF.FFFFFFFF ` | Reserved = 0 |
*API Flags 2:*
-| Bit Numbers | Mask | Description |
-|----------------------|----------------------------|----------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 63:0 | `0xFFFFFFFF.FFFFFFFF` | Reserved = 0 |
@@ -288,7 +280,7 @@ Allocates a new Partition object from the Partition and allocates a Capability I
| Call number: | `hvc 0x6001` |
| Inputs: | X0: Partition CapID |
| | X1: CSpace CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: Partition CapID |
@@ -311,7 +303,7 @@ Allocates a new CSpace object from the Partition and allocates a Capability ID f
| Call number: | `hvc 0x6002` |
| Inputs: | X0: Partition CapID |
| | X1: CSpace CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: Cspace CapID |
@@ -335,7 +327,7 @@ Allocates a new Address Space object from the Partition and allocates a Capabili
| Call number: | `hvc 0x6003` |
| Inputs: | X0: Partition CapID |
| | X1: CSpace CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
On successful creation, the new Address Space object is created and its state is OBJECT_STATE_INIT.
@@ -357,7 +349,7 @@ Allocates a new Memory Extent object from the Partition and allocates a Capabili
| Call number: | `hvc 0x6004` |
| Inputs: | X0: Partition CapID |
| | X1: CSpace CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: MemExtent CapID |
@@ -380,7 +372,7 @@ Allocates a new Thread object from the Partition and allocates a Capability ID f
| Call number: | `hvc 0x6005` |
| Inputs: | X0: Partition CapID |
| | X1: CSpace CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: Thread CapID |
@@ -403,7 +395,7 @@ Allocates a new Doorbell object from the Partition and allocates a Capability ID
| Call number: | `hvc 0x6006` |
| Inputs: | X0: Partition CapID |
| | X1: CSpace CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: Doorbell CapID |
@@ -426,7 +418,7 @@ Allocates a new Message Queue object from the Partition and allocates a Capabili
| Call number: | `hvc 0x6007` |
| Inputs: | X0: Partition CapID |
| | X1: CSpace CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: MessageQueue CapID |
@@ -449,7 +441,7 @@ Allocates a new Watchdog object from the Partition and allocates a Capability ID
| Call number: | `hvc 0x6009` |
| Inputs: | X0: Partition CapID |
| | X1: CSpace CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: Watchdog CapID |
@@ -472,7 +464,7 @@ Allocates a new Virtual Interrupt Controller object from the Partition and alloc
| Call number: | `hvc 0x600A` |
| Inputs: | X0: Partition CapID |
| | X1: CSpace CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: Virtual IC CapID |
@@ -495,7 +487,7 @@ Allocates a new Virtual PM Group object from the Partition and allocates a Capab
| Call number: | `hvc 0x600B` |
| Inputs: | X0: Partition CapID |
| | X1: CSpace CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: VPMGroup CapID |
@@ -509,6 +501,29 @@ ERROR_NOMEM – the creation failed due to memory allocation error.
Also see: [Capability Errors](#capability-errors)
+### Virtual IO MMIO object creation
+
+Allocates a new Virtual IO MMIO object from the Partition and allocates a Capability ID from the CSpace.
+
+| **Hypercall**: | `partition_create_virtio_mmio` |
+|-------------------------|---------------------------------------|
+| Call number: | `hvc 0x6048` |
+| Inputs: | X0: Partition CapID |
+| | X1: CSpace CapID |
+| | X2: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+| | X1: VirtioMMIO CapID |
+
+On successful creation, the new Virtual IO MMIO object is created and its state is OBJECT_STATE_INIT.
+
+**Errors:**
+
+OK – the operation was successful, and the result is valid.
+
+ERROR_NOMEM – the creation failed due to memory allocation error.
+
+Also see: [Capability Errors](#capability-errors)
+
## Object Management
### Activate an Object
@@ -519,14 +534,14 @@ Activate an object.
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x600C` |
| Inputs: | X0: Cap CapID |
-| | X1: Reserved – Must be Zero |
+| | X1: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
-OK – the operation was successful, and the result is valid.
+OK – the operation was successful, and the object has moved into `OBJECT_STATE_ACTIVE` state.
-ERROR_OBJECT_STATE - if the object is not in OBJECT_STATE_INIT state.
+ERROR_OBJECT_STATE – if the object is not in OBJECT_STATE_INIT state.
Additional [error codes](#error-code-enumeration) can be returned depending on the type of object to be activated.
@@ -541,14 +556,14 @@ Activate an object from a Cspace.
| Call number: | `hvc 0x600D` |
| Inputs: | X0: CSpace CapID |
| | X1: Cap CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
OK – the operation was successful, and the result is valid.
-ERROR_OBJECT_STATE - if the object is not in OBJECT_STATE_INIT state.
+ERROR_OBJECT_STATE – if the object is not in OBJECT_STATE_INIT state.
Additional [error codes](#error-code-enumeration) can be returned depending on the type of object to be activated.
@@ -562,14 +577,14 @@ Reset an object to its initial state.
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x600E` |
| Inputs: | X0: Cap CapID |
-| | X1: Reserved – Must be Zero |
+| | X1: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
OK – the operation was successful, and the result is valid.
-ERROR_UNIMPLEMENTED - if functionality not implemented.
+ERROR_UNIMPLEMENTED – if functionality not implemented.
Additional [error codes](#error-code-enumeration) can be returned depending on the type of object to be reset.
@@ -584,14 +599,14 @@ Reset an object from a Cspace to its initial state.
| Call number: | `hvc 0x600F` |
| Inputs: | X0: CSpace CapID |
| | X1: Cap CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
OK – the operation was successful, and the result is valid.
-ERROR_UNIMPLEMENTED - if functionality not implemented.
+ERROR_UNIMPLEMENTED – if functionality not implemented.
Additional [error codes](#error-code-enumeration) can be returned depending on the type of object to be reset.
@@ -601,7 +616,7 @@ Also see: [Capability Errors](#capability-errors)
-0x6008 - `Reserved`
+0x6008 – `Reserved`
## Communication APIs
@@ -617,7 +632,7 @@ Binds a Doorbell to a virtual interrupt.
| Inputs: | X0: Doorbell CapID |
| | X1: Virtual IC CapID |
| | X2: Virtual IRQ Info |
-| | X3: Reserved – Must be Zero |
+| | X3: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -642,7 +657,7 @@ Unbinds a Doorbell from a virtual IRQ number.
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x6011` |
| Inputs: | X0: Doorbell CapID |
-| | X1: Reserved – Must be Zero |
+| | X1: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -660,7 +675,7 @@ Sets flags in the Doorbell. If following the send, the set of enabled flags as d
| Call number: | `hvc 0x6012` |
| Inputs: | X0: Doorbell CapID |
| | X1: NewFlags FlagsBitmap – Must be non-zero. |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: OldFlags FlagsBitmap |
@@ -686,8 +701,8 @@ Reads and clears the flags of the Doorbell. If there is a pending bound virtual
|-------------------------|-------------------------------------------------------|
| Call number: | `hvc 0x6013` |
| Inputs: | X0: Doorbell CapID |
-| | X1: ClearFlags FlagsBitmap - Must be non-zero. |
-| | X2: Reserved – Must be Zero |
+| | X1: ClearFlags FlagsBitmap – Must be non-zero. |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: OldFlags FlagsBitmap |
@@ -713,7 +728,7 @@ Clears all the flags of the Doorbell and sets all bits in the Doorbell’s mask.
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x6014` |
| Inputs: | X0: Doorbell CapID |
-| | X1: Reserved – Must be Zero |
+| | X1: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -732,7 +747,7 @@ Sets the Doorbell object’s masks. A Doorbell object has two masks which are co
| Inputs: | X0: Doorbell CapID |
| | X1: EnableMask FlagsBitmap |
| | X2: AckMask FlagsBitmap |
-| | X3: Reserved – Must be Zero |
+| | X3: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Types:**
@@ -749,7 +764,7 @@ Also see: [Capability Errors](#capability-errors)
-0x6016 - `Reserved`
+0x6016 – `Reserved`
### Message Queue Management
@@ -763,7 +778,7 @@ Binds a Message Queue send interface to a virtual IRQ number.
| Inputs: | X0: Message Queue CapID |
| | X1: Virtual IC CapID |
| | X2: Virtual IRQ Info |
-| | X3: Reserved – Must be Zero |
+| | X3: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -790,7 +805,7 @@ Binds a Message Queue receive interface to a virtual IRQ number.
| Inputs: | X0: Message Queue CapID |
| | X1: Virtual IC CapID |
| | X2: Virtual IRQ Info |
-| | X3: Reserved – Must be Zero |
+| | X3: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -815,7 +830,7 @@ Unbinds a Message Queue send interface virtual IRQ number.
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x6019` |
| Inputs: | X0: Message Queue CapID |
-| | X1: Reserved – Must be Zero |
+| | X1: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -832,7 +847,7 @@ Unbinds a Message Queue receive interface virtual IRQ number.
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x601A` |
| Inputs: | X0: Message Queue CapID |
-| | X1: Reserved – Must be Zero |
+| | X1: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -849,10 +864,10 @@ Append a message to the tail of a Message Queue, if it is not full. The message
|-------------------------|--------------------------------------------|
| Call number: | `hvc 0x601B` |
| Inputs: | X0: Message Queue CapID |
-| | X1: Size Size Must be non-zero. |
+| | X1: Size Size — Must be non-zero. |
| | X2: Data VMAddr |
| | X3: MsgQSendFlags |
-| | X4: Reserved – Must be Zero |
+| | X4: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: NotFull Boolean |
@@ -860,10 +875,10 @@ Append a message to the tail of a Message Queue, if it is not full. The message
*MsgQSendFlags:*
-| Bit Numbers | Mask | Description |
-|----------------------|----------------------------|---------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 0 | `0x1` | Message Push |
-| 63:1 | `0xFFFFFFFF.FFFFFFFE` | Reserved, Must be Zero |
+| 63:1 | `0xFFFFFFFF.FFFFFFFE` | Reserved — Must be Zero |
Message Push: If set to 0x1, this flag indicates that the hypervisor should push the message immediately to the receiver. This may cause a receive interrupt to be raised immediately, regardless of any interrupt threshold or interrupt delay configuration.
@@ -889,7 +904,7 @@ Fetch a message from the head of a Message Queue, if it is not empty, into a spe
| Inputs: | X0: Message Queue CapID |
| | X1: Buffer VMAddr |
| | X2: MaximumSize Size |
-| | X3: Reserved – Must be Zero |
+| | X3: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: Size Size |
| | X2: NotEmpty Boolean |
@@ -914,7 +929,7 @@ Rmoves all messages from a Message Queue. If the Message Queue was previously no
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x601D` |
| Inputs: | X0: Message Queue CapID |
-| | X1: Reserved – Must be Zero |
+| | X1: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -927,7 +942,7 @@ Also see: [Capability Errors](#capability-errors)
-0x601E - `Reserved`
+0x601E – `Reserved`
#### Message Queue Configure Send
@@ -939,7 +954,7 @@ Modify configuration of a Message Queue send interface. The interface allows for
| Inputs: | X0: Message Queue CapID |
| | X1: NotFull interrupt threshold |
| | X2: NotFull threshold delay (microseconds) |
-| | X3: Reserved – Must be -1 |
+| | X3: Reserved — Must be -1 |
| Outputs: | X0: Error Result |
Any parameter passed in as -1 indicates no change to the corresponding is requested.
@@ -966,7 +981,7 @@ Modify configuration of a Message Queue receive interface. The interface allows
| Inputs: | X0: Message Queue CapID |
| | X1: NotEmpty interrupt threshold |
| | X2: NotEmpty threshold delay (microseconds) |
-| | X3: Reserved – Must be -1 |
+| | X3: Reserved — Must be -1 |
| Outputs: | X0: Error Result |
Any parameter passed in as -1 indicates no change to the corresponding is requested.
@@ -992,15 +1007,15 @@ Configure a Message Queue whose state is OBJECT_STATE_INIT.
| Call number: | `hvc 0x6021` |
| Inputs: | X0: Message Queue CapID |
| | X1: MessageQueueCreateInfo |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Types:**
*MessageQueueCreateInfo:*
-| Bit Numbers | Mask | Description |
-|----------------------|----------------------------|---------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 15:0 | `0x0000FFFF` | Queue Depth |
| 31:15 | `0xFFFF0000` | Max Message Size |
| 63:32 | `0xFFFFFFFF.00000000` | Reserved, Must be Zero |
@@ -1028,7 +1043,7 @@ Delete a Capability in a CSpace.
| Call number: | `hvc 0x6022` |
| Inputs: | X0: CSpace CapID |
| | X1: Cap CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
@@ -1049,7 +1064,7 @@ Copy a Capability from one CSpace to another.
| | X1: SourceCap CapID |
| | X2: DestCSpace CapID |
| | X3: RightsMask |
-| | X4: Reserved – Must be Zero |
+| | X4: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: New CapID |
@@ -1070,14 +1085,14 @@ Revoke a Capability from another CSpace.
| Call number: | `hvc 0x6024` |
| Inputs: | X0: CSpace CapID |
| | X1: Cap CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
OK – the operation was successful, and the result is valid.
-ERROR_UNIMPLEMENTED - if functionality not implemented.
+ERROR_UNIMPLEMENTED – if functionality not implemented.
`TODO: TBD. Currently unimplemented`
@@ -1092,7 +1107,7 @@ Configure a CSpace whose state is OBJECT_STATE_INIT.
| Call number: | `hvc 0x6025` |
| Inputs: | X0: CSpace CapID |
| | X1: MaxCaps |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1101,7 +1116,7 @@ OK – the operation was successful, and the result is valid.
ERROR_OBJECT_STATE – if the Cspace is not in OBJECT_STATE_INIT state.
-ERROR_ARGUMENT_INVALID - a value passed in an argument was invalid. This could be due to an invalid Max Caps value.
+ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid Max Caps value.
Also see: [Capability Errors](#capability-errors)
@@ -1116,7 +1131,7 @@ Attaches a thread to a CSpace. The Cspace object must have been activated before
| Call number: | `hvc 0x603e` |
| Inputs: | X0: CSpace CapID |
| | X1: Thread CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1136,7 +1151,7 @@ Revoke children Capabilities from a CSpace.
| Call number: | `hvc 0x6059` |
| Inputs: | X0: CSpace CapID |
| | X1: MasterCap CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1157,7 +1172,7 @@ Binds a hardware IRQ number to a virtual IRQ number.
| Inputs: | X0: HW IRQ CapID |
| | X1: Virtual IC CapID |
| | X2: Virtual IRQ Info |
-| | X3: Reserved – Must be Zero |
+| | X3: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1182,7 +1197,7 @@ Unbinds a hardware IRQ number from a virtual IRQ number.
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x6027` |
| Inputs: | X0: HW IRQ CapID |
-| | X1: Reserved – Must be Zero |
+| | X1: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1205,7 +1220,7 @@ Note that both of these numbers may have implementation-defined upper bounds. Al
| Inputs: | X0: VIC CapID |
| | X1: MaxVCPUs |
| | X2: MaxSharedVIRQs |
-| | X3: Reserved – Must be Zero |
+| | X3: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1228,7 +1243,7 @@ Attaches a VCPU to a Virtual Interrupt Controller. The Virtual Interrupt Control
| Inputs: | X0: Virtual IC CapID |
| | X1: VCPU CapID |
| | X2: Index |
-| | X3: Reserved – Must be Zero |
+| | X3: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1257,7 +1272,7 @@ In the current implementation, the only type of MSI source supported is a GICv4
| Inputs: | X0: Virtual IC CapID |
| | X1: MSI Source (platform-specific object type) CapID |
| | X2: Index |
-| | X3: Reserved – Must be Zero |
+| | X3: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
@@ -1284,7 +1299,7 @@ Attaches an address space to a thread. The address space object must have been a
| Call number: | `hvc 0x602a` |
| Inputs: | X0: Address Space CapID |
| | X1: Thread CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1299,7 +1314,11 @@ Also see: [capability errors](#capability-errors)
### Address Space Map
-Maps a memory extent into a specified address space. The entire memory extent range is mapped, except for any carveouts contained within the extent.
+Map a memory extent into a specified address space. By default, the entire memory extent is mapped, except for any carveouts contained within the extent.
+
+If the Partial flag is set in Map Flags, only the range of the memory extent specified by Offset and Size will be mapped. If not set, these arguments are ignored. Partial mappings are only supported by sparse memory extents.
+
+If successful, the hypervisor will automatically synchronise with other cores to ensure they have observed the map operation. This behaviour is skipped if the NoSync flag is set.
| **Hypercall**: | `addrspace_map` |
|-------------------------|--------------------------------------|
@@ -1308,39 +1327,53 @@ Maps a memory extent into a specified address space. The entire memory extent ra
| | X1: Memory Extent CapID |
| | X2: Base VMAddr |
| | X3: Map Attributes |
-| | X4: Reserved – Must be Zero |
+| | X4: Map Flags |
+| | X5: Offset |
+| | X6: Size |
| Outputs: | X0: Error Result |
**Types:**
-*Map Atrributes:*
+*Map Attributes:*
-| Bit Numbers | Mask | Description |
-|----------------------|----------------------------|-----------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 2..0 | `0x7` | User Access (if Supported) |
| 6..4 | `0x70` | Kernel Access |
| 23:16 | `0xFF0000` | Memory Type |
| 63:24,15:7,3 | `0xFFFFFFFF.0000FF88` | Reserved, Must be Zero |
+*Map Flags:*
+
+| Bits | Mask | Description |
+|-|---|-----|
+| 0 | `0x1` | Partial |
+| 31 | `0x80000000` | NoSync |
+| 30:1 | `0x7FFFFFFE` | Reserved, Must be Zero |
+
**Errors:**
OK – the operation was successful, and the result is valid.
ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid Address Space.
-ERROR_MEMEXTENT_MAPPINGS_FULL– the memory extent has exceeded its mappings capacity. Currently it can have up to 4 mappings.
+ERROR_MEMEXTENT_MAPPINGS_FULL – the memory extent has exceeded its mappings capacity. Currently it can have up to 4 mappings.
-ERROR_DENIED - the specified Address Space is not allowed to execute map operations.
+ERROR_DENIED – the specified Address Space is not allowed to execute map operations.
-ERROR_ARGUMENT_ALIGNMENT - the specificied base address is not page size aligned.
+ERROR_ARGUMENT_ALIGNMENT – the specified base address is not page size aligned.
-ERROR_ADDR_OVERFLOW - the specified base address may cause an overflow.
+ERROR_ADDR_OVERFLOW – the specified base address may cause an overflow.
Also see: [capability errors](#capability-errors)
### Address Space Unmap
-Unmaps a memory extent from a specified address space. The entire memory extent range is unmapped, except for any carveouts contained within the extent.
+Unmaps a memory extent from a specified address space. By default, the entire memory extent range is unmapped, except for any carveouts contained within the extent.
+
+If the Partial flag is set in Map Flags, only the range of the Memory Extent specified by Offset and Size will be unmapped. If not set, these arguments are ignored. Partial unmappings are only supported by sparse memory memextents.
+
+If successful, the hypervisor will automatically synchronise with other cores to ensure they have observed the unmap operation. This behaviour is skipped if the NoSync flag is set.
| **Hypercall**: | `addrspace_unmap` |
|-------------------------|--------------------------------------|
@@ -1348,7 +1381,9 @@ Unmaps a memory extent from a specified address space. The entire memory extent
| Inputs: | X0: Address Space CapID |
| | X1: Memory Extent CapID |
| | X2: Base VMAddr |
-| | X3: Reserved – Must be Zero |
+| | X3: Map Flags |
+| | X4: Offset |
+| | X5: Size |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1357,9 +1392,9 @@ OK – the operation was successful, and the result is valid.
ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid Address Space or a non-existing mapping.
-ERROR_DENIED - the specified Address Space is not allowed to execute map operations.
+ERROR_DENIED – the specified Address Space is not allowed to execute map operations.
-ERROR_ARGUMENT_ALIGNMENT - the specificied base address is not page size aligned.
+ERROR_ARGUMENT_ALIGNMENT – the specified base address is not page size aligned.
Also see: [capability errors](#capability-errors)
@@ -1367,22 +1402,28 @@ Also see: [capability errors](#capability-errors)
Update access rights on an existing mapping.
+If the Partial flag is set in Map Flags, only the range of the Memory Extent specified by Offset and Size will be updated. If not set, these arguments are ignored. Partial access updates are only supported by sparse memory extents.
+
+If successful, the hypervisor will automatically synchronise with other cores to ensure they have observed the mapping update. This behaviour is skipped if the NoSync flag is set.
+
| **Hypercall**: | `addrspace_update_access` |
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x602d` |
| Inputs: | X0: Address Space CapID |
| | X1: Memory Extent CapID |
| | X2: Base VMAddr |
-| | X3: Update Attributes |
-| | X5: Reserved – Must be Zero |
+| | X3: Update Attributes |
+| | X4: Map Flags |
+| | X5: Offset |
+| | X6: Size |
| Outputs: | X0: Error Result |
**Types:**
*Update Attributes:*
-| Bit Numbers | Mask | Description |
-|----------------------|----------------------------|-----------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 2..0 | `0x7` | User Access (if Supported) |
| 6..4 | `0x70` | Kernel Access |
| 63:7,3 | `0xFFFFFFFF.FFFFFF88` | Reserved, Must be Zero |
@@ -1393,22 +1434,22 @@ OK – the operation was successful, and the result is valid.
ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid Address Space or a non-existing mapping.
-ERROR_ARGUMENT_ALIGNMENT - the specificied base address is not page size aligned.
+ERROR_ARGUMENT_ALIGNMENT – the specified base address is not page size aligned.
-ERROR_DENIED - the specified Address Space is not allowed to update access of mappings.
+ERROR_DENIED – the specified Address Space is not allowed to update access of mappings.
Also see: [capability errors](#capability-errors)
### Configure an Address Space
-Configure a address space whose state is OBJECT_STATE_INIT.
+Configure an address space whose state is OBJECT_STATE_INIT.
-| **Hypercall**: | `addrspace_configure` |
+| **Hypercall**: | `addrspace_configure` |
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x602e` |
| Inputs: | X0: Address Space CapID |
| | X1: VMID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Types:**
@@ -1425,6 +1466,31 @@ ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could
Also see: [capability errors](#capability-errors)
+### Configure the information area of an Address Space
+
+Configure the information area of an address space whose state is OBJECT_STATE_INIT.
+
+| **Hypercall**: | `addrspace_configure_info_area` |
+|-------------------------|--------------------------------------|
+| Call number: | `hvc 0x605b` |
+| Inputs: | X0: Address Space CapID |
+| | X1: Info area memextent CapID |
+| | X2: Info area IPA |
+| | X3: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Errors:**
+
+OK – The operation was successful, and the result is valid.
+
+ERROR_OBJECT_STATE – The Address Space object has already been activated.
+
+ERROR_ADDR_INVALID – The provided IPA is invalid.
+
+ERROR_ARGUMENT_INVALID – A value passed in an argument was invalid.
+
+Also see: [capability errors](#capability-errors)
+
### Address Space to DMA-capable Object Attachment
Attaches an address space to any type of object that has a virtual DMA port which it can use to independently access memory in a VM address space. For types of object that have more than one virtual DMA port (e.g. a DMA-based IPC object), an index may be specified to indicate which port should be attached. Note that VCPUs do not access the VM address spaces through a virtual DMA port when executing VM code; they use a separate attachment call, described in [section](#address-space-to-thread-attachment) above.
@@ -1439,40 +1505,208 @@ In the current implementation, the only object type with a virtual DMA port is t
| Inputs: | X0: Address Space CapID |
| | X1: Virtual DMA-capable Object CapID |
| | X2: Virtual DMA Port Index |
-| | X3: Reserved – Must be Zero |
+| | X3: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
-OK – the operation was successful, and the result is valid.
+OK – the operation was successful.
ERROR_NOMEM – the operation failed due to memory allocation error.
ERROR_ARGUMENT_INVALID – the specified object is virtual DMA capable, but the port index is outside the valid range for the object.
+ERROR_CSPACE_WRONG_OBJECT_TYPE – the specified virtual device object does not have any virtual DMA ports; or the specified address space object is not an address space.
+
ERROR_BUSY – the specified port already has an address space attached, and the object does not support changing an existing attachment.
ERROR_OBJECT_STATE – the Address Space object has not yet been activated.
Also see: [capability errors](#capability-errors)
+### Address Space to Virtual Device Attachment
+
+Attaches an address space to any type of object that presents a virtual memory-mapped device register interfaces. For types of object that have more than one virtual device interface, an index may be specified to indicate which interface should be attached. The meaning of this index depends on the object type.
+
+After this call succeeds, accesses by any VCPU attached to the address space that lie within the specified IPA range and fault in the IPA translation will be forwarded to the specified virtual device for emulation. The addresses, access sizes, access types, and semantics of the emulated registers depend entirely on the device implementation. Also, the behaviour of any access that does not match an emulated register depends on the device implementation, and may include either faulting as if the virtual device was not attached, or returning a constant value (typically 0 or 0xff) for reads and ignoring writes.
+
+Note that the register interface will not function correctly if any memory extent is mapped in the specified IPA range. The hypervisor will not check for such overlapping mappings.
+
+The specified IPA range must be large enough to contain the selected register interface, and must not be attached to any other virtual device. If the specified range is undersized, some registers may not be accessible. If the specified range is oversized, any extra space will become unavailable to other virtual devices; the behaviour of an access to this extra space is unspecified.
+
+| **Hypercall**: | `addrspace_attach_vdevice` |
+|-------------------------|---------------------------------------------|
+| Call number: | `hvc 0x6062` |
+| Inputs: | X0: Address Space CapID |
+| | X1: Virtual Device Object CapID |
+| | X2: Virtual Device Interface Index |
+| | X3: Base IPA |
+| | X4: Size |
+| | X5: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Index values:**
+
+| **Type** | **Index** | **Size** | **Description** |
+|--|-|--|-----|
+| vGIC | 0 | 64KiB | GIC Distributor registers |
+| vGIC | 1..N | 64KiB | GIC Redistributor registers for VCPUs 0..(N-1) |
+| vITS | 0 | 64KiB | GIC ITS registers |
+
+**Errors:**
+
+OK – the operation was successful.
+
+ERROR_NOMEM – the operation failed due to memory allocation error.
+
+ERROR_ARGUMENT_INVALID – the specified object is a virtual device, but the interface index is outside the valid range for the object.
+
+ERROR_CSPACE_WRONG_OBJECT_TYPE – the specified virtual device object does not support memory-mapped interfaces or is not a virtual device; or the specified address space object is not an address space.
+
+ERROR_BUSY – the specified address range already contains a virtual device.
+
+ERROR_OBJECT_STATE – the Address Space object has not yet been activated.
+
+Also see: [capability errors](#capability-errors)
+
+### Address Space Lookup
+
+Lookup a memextent mapping in an address space. If successful, returns the offset and size within the memextent, as well as the attributes of the mapping.
+
+| **Hypercall**: | `addrspace_lookup` |
+|-------------------------|--------------------------------------|
+| Call number: | `hvc 0x605a` |
+| Inputs: | X0: Address Space CapID |
+| | X1: Memory Extent CapID |
+| | X2: Base VMAddr |
+| | X3: Size |
+| | X4: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+| | X1: Offset |
+| | X2: Size |
+| | X3: Map Attributes |
+
+**Types:**
+
+*Map Attributes:*
+
+See: [Address Space Map](#address-space-map)
+
+**Errors:**
+
+OK – the operation was successful, and the result is valid.
+
+ERROR_ARGUMENT_INVALID – one of the given arguments is invalid. This could be due to an invalid Address Space.
+
+ERROR_ARGUMENT_SIZE – the specified size is invalid.
+
+ERROR_ARGUMENT_ALIGNMENT – the specified base address or size is not page size aligned.
+
+ERROR_ADDR_OVERFLOW – the specified base address may cause an overflow.
+
+ERROR_ADDR_INVALID – the specified base address is not mapped in the Address Space.
+
+ERROR_MEMDB_NOT_OWNER – the memory mapped in the Address Space is not owned by the specified Memory Extent.
+
+Also see: [capability errors](#capability-errors)
+
+### Address Space Virtual MMIO Area Configuration
+
+Configure the virtual MMIO device regions for the address space.
+
+A virtual MMIO device region is a region of the address space in which translation faults may be handled by an unprivileged VMM residing in another VM.
+This allows the unprivileged VMM to emulate memory-mapped I/O devices.
+Note that other types of fault, such as permission or alignment faults, cannot be handled by this mechanism.
+Also, depending on the architecture, this mechanism may only support translation faults generated by specific types of instruction.
+On AArch64, it is limited to single-register load & store instructions without base register writeback, which are decoded by the CPU into the `ESR_EL2` syndrome bits.
+
+This call may be made before or after activation of the address space object.
+This is to permit delegation of the right to call this API to the VM that runs in the address space, so it can explicitly acknowledge that the specified region should not be used for sensitive data.
+
+An address range that is added must not overlap any existing range, and must not wrap around the end of the address space.
+There are no other restrictions on the size or alignment of ranges added to the address space.
+However, a limit may be imposed on the total number of ranges added to an address space.
+
+A removed address range must exactly match a single previously added address range. Note that removal of a range will prevent the VMM receiving any new faults that occur in that range after the removal operation completes, but does not guarantee that the VMM has finished handling all faults in the removed range.
+
+| **Hypercall**: | `addrspace_configure_vmmio` |
+|-------------------------|------------------------------------|
+| Call number: | `hvc 0x6060` |
+| Inputs: | X0: Address Space CapID |
+| | X1: Base VMAddr |
+| | X2: Size |
+| | X3: VMMIOConfigureOperation |
+| | X4: Reserved – Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Types:**
+
+*VMMIOConfigureOperation:*
+
+| Operation Enumerator | Integer Value |
+|-----------------------------------------|------------------------|
+| VMMIO_CONFIGURE_OP_ADD_RANGE | 0 |
+| VMMIO_CONFIGURE_OP_REMOVE_RANGE | 1 |
+
+**Errors:**
+
+OK – the operation was successful.
+
+ERROR_ADDR_OVERFLOW – the specified range wraps around the end of the address space.
+
+ERROR_ADDR_INVALID – the specified range is not completely within the input address range of the address space.
+
+ERROR_ARGUMENT_INVALID – the specified range to be added overlaps a previously added range, or the specified range to be removed does not match a previously added range.
+
+ERROR_NORESOURCES – the number of nominated ranges has reached an implementation-defined limit, or the hypervisor was unable to allocate memory for bookkeeping.
+
+ERROR_UNIMPLEMENTED — unprivileged VMMs are unable to handle faults in this configuration, or an unknown operation was requested.
+
+Also see: [capability errors](#capability-errors)
+
## Memory Extent Management
-### Memory Extent Unmap All
+### Memory Extent Modify
+
+Perform a modification on a memory extent.
-Unmaps a memory extent from all address spaces it was mapped into. The entire range is unmapped, except for any carveouts contained within the extent.
+For range operations, only the range of the memory extent specified by Offset and Size will be modified. For all other operations these arguments are ignored.
-| **Hypercall**: | `memextent_unmap_all` |
+For operations that affect address space mappings, the hypervisor will automatically synchronise with other cores to ensure they have observed any successful changes in mappings. This behaviour is skipped if the NoSync flag is set. For other operations the NoSync flag must be set as specified below.
+
+| **Hypercall**: | `memextent_modify` |
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x6030` |
| Inputs: | X0: Memory Extent CapID |
-| | X1: Reserved – Must be Zero |
+| | X1: Memextent Modify Flags |
+| | X2: Offset |
+| | X3: Size |
| Outputs: | X0: Error Result |
+**Types:**
+
+*MemExtent Modify Flags:*
+
+| Bit Numbers | Mask | Description |
+|---------------------|-------------------|---------------------------------|
+| 7:0 | `0xFF` | Memextent Modify Operation |
+| 31 | `0x80000000` | NoSync |
+| 30:8 | `0x7FFFFF00` | Reserved, Must be Zero |
+
+*MemExtent Modify Operation:*
+
+| Modify Operation | Integer Value | Description |
+|------------------------------------|-------------------|-------------------------------------------------------------------------------------------------|
+| MEMEXTENT_MODIFY_OP_UNMAP_ALL | 0 | Unmap the memory extent from all address spaces it was mapped into. |
+| MEMEXTENT_MODIFY_OP_ZERO_RANGE | 1 | Zero the owned memory of an extent within the specified range. The NoSync flag must be set. |
+| MEMEXTENT_MODIFY_OP_SYNC_ALL | 255 | Synchronise all previous memory extent operations. The NoSync flag must not be set. |
+
**Errors:**
OK – the operation was successful, and the result is valid.
+ERROR_ARGUMENT_INVALID – the specified modify flags are invalid.
+
Also see: [Capability Errors](#capability-errors)
### Configure a Memory Extent
@@ -1486,19 +1720,36 @@ Configure a memory extent whose state is OBJECT_STATE_INIT.
| | X1: Phys Base |
| | X2: Size |
| | X3: MemExtent Attributes |
-| | X4: Reserved – Must be Zero |
+| | X4: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Types:**
*MemExtent Attributes:*
-| Bit Numbers | Mask | Description |
-|----------------------|-------------------|---------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 2..0 | `0x7` | Access Rights |
| 9:8 | `0x300` | MemExtent MemType |
+| 17:16 | `0x30000` | MemExtent Type |
| 31 | `0x80000000` | List Append |
-| 30:19,7:3 | `0x7FFFFCF8` | Reserved, Must be Zero |
+| 30:18,15:10,7:3 | `0x7FFCFCF8` | Reserved, Must be Zero |
+
+*Memextent Type*
+
+| Memextent Type | Integer Value | Description |
+|-----------------------|---------------------|------------------------------------------------------|
+| BASIC | 0 | Extent with basic functionality. |
+| SPARSE | 1 | Extent supporting donation and partial mappings. |
+
+*Memextent MemType*
+
+| Memextent MemType | Integer Value | Description |
+|-------------------------|---------------------|----------------------------------------------------|
+| ANY | 0 | Allow mappings of any memory type. |
+| DEVICE | 1 | Restrict mappings to device memory types only. |
+| UNCACHED | 2 | Force mappings to be uncached. |
+| CACHED | 3 | Force mappings to be writeback cacheable. |
**Errors:**
@@ -1520,7 +1771,7 @@ Configure a derived memory extent whose state is OBJECT_STATE_INIT. The extent w
| | X2: Offset |
| | X3: Size |
| | X4: MemExtent Attributes |
-| | X5: Reserved – Must be Zero |
+| | X5: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1531,11 +1782,54 @@ ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could
Also see: [Capability Errors](#capability-errors)
-### Memory Extent Reserved
+### Memory Extent Donate
-
+Donate memory from one extent to another. This includes donations from parent to child, child to parent and between siblings.
+
+For non-derived memory extents, the parent is considered to be the partition that was used to create the extent. Donation is only supported for sparse memory extents.
+
+If successful, the hypervisor will automatically synchronise with other cores to ensure they have observed the donation and any mapping changes that may have occurred. This behaviour is skipped if the NoSync flag is set.
+
+| **Hypercall**: | `memextent_donate` |
+|-------------------------|---------------------------------------|
+| Call number: | `hvc 0x6033` |
+| Inputs: | X0: Memextent Donate Options |
+| | X1: From CapID |
+| | X2: To CapID |
+| | X3: Offset |
+| | X4: Size |
+| | X5: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
-0x6033 - `Reserved`
+**Types:**
+
+*Memextent Donate Options*
+
+| Bits | Mask | Description |
+|-|---|-----|
+| 7:0 | `0xFF` | Memextent Donate Type |
+| 31 | `0x80000000` | NoSync |
+| 30:8 | `0x7FFFFF00` | Reserved — Must be Zero |
+
+*Memextent Donate Type*
+
+| Memextent Donate Type | Integer Value | Description |
+|------------------------------|---------------------|-------------------------------------------------|
+| TO_CHILD | 0 | Donate to a child extent from its parent. |
+| TO_PARENT | 1 | Donate from a child extent to its parent. |
+| TO_SIBLING | 2 | Donate from one sibling extent to another. |
+
+**Errors:**
+
+OK – the operation was successful, and the result is valid.
+
+ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid donate option, offset or size.
+
+ERROR_ARGUMENT_SIZE – the Size provided is zero, or leads to an overflow.
+
+ERROR_MEMDB_NOT_OWNER – the donating memory extent did not have ownership of the specified memory range.
+
+Also see: [Capability Errors](#capability-errors)
## VCPU Management
@@ -1548,15 +1842,15 @@ Configure a VCPU Thread whose state is OBJECT_STATE_INIT.
| Call number: | `hvc 0x6034` |
| Inputs: | X0: vCPU CapID |
| | X1: vCPUOptionFlags |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Types:**
*vCPUOptionFlags:*
-| Bit Numbers | Mask | Description |
-|----------------------|----------------------------|-----------------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 0 | `0x1` | AArch64 Self-hosted Debug Enable |
| 1 | `0x2` | VCPU containing HLOS VM |
| 63:2 | `0xFFFFFFFF.FFFFFFFE` | Reserved, Must be Zero |
@@ -1569,7 +1863,7 @@ OK – the operation was successful, and the result is valid.
ERROR_OBJECT_STATE – if the VCPU object is not in OBJECT_STATE_INIT state.
-ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid VCPU or option flags.
+ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid VCPU or option flag.
Also see: [Capability Errors](#capability-errors)
@@ -1588,12 +1882,16 @@ If the call targets a VCPU that is currently running on a different physical CPU
| Call number: | `hvc 0x603d` |
| Inputs: | X0: vCPU CapID |
| | X1: Affinity CPUIndex |
-| | X2: Reserved – Must be -1 |
+| | X2: Reserved — Must be -1 |
| Outputs: | X0: Error Result |
**Types:**
-CPUIndex — a number identifying the target physical CPU. For hardware platforms with physical CPUs that are linearly numbered from 0, this is equal to the physical CPU number; for AArch64 platforms, this is the case if three of the four affinity fields in MPIDR_EL1 have a zero value on every physical PE, and the CPUIndex corresponds to the value of the remaining MPIDR_EL1 affinity field. Otherwise, the hypervisor’s platform driver defines the mapping between CPUIndex values and physical CPUs, and VMs may be informed of this mapping at boot time via the boot environment data. If the scheduler supports directed yields and/or automatic migration of threads, the value -1 may be used to indicate that the VCPU should not have affinity to any physical CPU.
+CPUIndex — a number identifying the target physical CPU.
+
+For hardware platforms with physical CPUs that are linearly numbered from 0, this is equal to the physical CPU number; for AArch64 platforms, this is the case if three of the four affinity fields in `MPIDR_EL1` have a zero value on every physical PE, and the CPUIndex corresponds to the value of the remaining `MPIDR_EL1` affinity field. Otherwise, the hypervisor’s platform driver defines the mapping between CPUIndex values and physical CPUs, and VMs may be informed of this mapping at boot time via the boot environment data.
+
+The value -1 (`CPU_INDEX_INVALID`) may be used to indicate that the VCPU should not have affinity to any physical CPU. If the scheduler does not support automatic migration of threads, this will effectively disable the VCPU, so an additional object right (Thread Disable) is required in this case.
**Errors:**
@@ -1607,43 +1905,109 @@ ERROR_DENIED – the specified VCPU is not permitted to change affinity because
Also see: [Capability Errors](#capability-errors)
+### Write to the Register Context of a VCPU Thread
+
+Write a specified value to one of a VCPU's registers.
+
+This may be called for any VCPU thread object that is currently in a virtual power-off state.
+This includes VCPU objects that have not yet been activated.
+Note that powering on a VCPU using a platform-specific power control API, such as `PSCI_CPU_ON`, might overwrite values set by this call.
+
+The register to write is identified by an architecture-specific enumeration identifying the set or group of registers, and an index into that set or group.
+The primary purpose of this hypercall is to set the initial state of a VCPU before it is powered on.
+Therefore, the architecture will typically only define access to the general-purpose registers, excluding extended register sets such as system control registers and floating-point or vector registers.
+
+| **Hypercall**: | `vcpu_register_write` |
+|-------------------------|--------------------------------------|
+| Call number: | `hvc 0x6064` |
+| Inputs: | X0: vCPU CapID |
+| | X1: RegisterSet |
+| | X2: Index |
+| | X3: Value |
+| | X4: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Types:**
+
+*RegisterSet (AArch64)*
+
+| **RegisterSet** | **Name** | **Indices** | **Description** |
+|-|---|-|-----|
+| 0 | `VCPU_REGISTER_SET_X` | 0–31 | 64-bit general purpose registers X0-X30 |
+| 1 | `VCPU_REGISTER_SET_PC` | 0 | Program counter (4-byte aligned) |
+| 2 | `VCPU_REGISTER_SET_SP_EL` | 0–1 | Stack pointers for EL0 and EL1 |
+
### Power on a VCPU Thread
-Set a VCPU Thread’s initial execution state, including its entry point and context.
+Bring a VCPU Thread out of its initial virtual power-off state.
+
+This call can also set the minimal initial execution state of the VCPU, including its entry point and a context pointer, avoiding the need to call `vcpu_register_write`.
+The hypervisor does not dereference, check, or otherwise define any particular meaning for the context pointer.
+It will be written to the first argument register in the VCPU's standard calling convention; for an AArch64 VCPU, this is X0.
+
+The entry point and context pointer each have a corresponding flag in the flags argument which will cause this call to discard the provided value and preserve the current state of the respective VCPU register.
| **Hypercall**: | `vcpu_poweron` |
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x6038` |
| Inputs: | X0: vCPU CapID |
-| | X1: vCPU EntryPointAddr |
-| | X2: vCPU Context |
-| | X3: Reserved – Must be Zero |
+| | X1: EntryPointAddr VMPhysAddr |
+| | X2: ContextPtr Register |
+| | X3: vCPUPowerOnFlags |
| Outputs: | X0: Error Result |
+**Types:**
+
+*vCPUPowerOnFlags:*
+
+| Bits | Mask | Description |
+|-|---|-----|
+| 0 | `0x1` | Preserve entry point |
+| 1 | `0x2` | Preserve context |
+| 63:2 | `0xFFFFFFFF.FFFFFFFC` | Reserved — Must be Zero |
+
**Errors:**
OK – the operation was successful, and the result is valid.
ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid VCPU.
-ERROR_BUSY - the specified VCPU is currently busy and cannot be powered on at the moment.
+ERROR_BUSY – the specified VCPU is currently busy and cannot be powered on at the moment.
Also see: [Capability Errors](#capability-errors)
### Power off a VCPU Thread
-Tear down the current thread’s VCPU execution state. This call will not return when successful.
+Halt execution of the calling VCPU, and apply architecture-defined reset values to its register context.
+The effect of the reset is architecture-specific, but will typically disable the first stage of address translation, and may also disable caches, mask interrupts, etc.
+
+This call will not return when successful.
+
+The specified VCPU capability must refer to the calling VCPU. Specifying any other VCPU is invalid.
+
+The last-VCPU bit in the flags argument must be set if, and only if, the caller is either the sole powered-on VCPU attached to a Virtual PM Group, or not attached to a Virtual PM Group at all. If this flag is not set correctly, the call may return ERROR_DENIED. This requirement prevents a VM inadvertently powering off all of its VCPUs, which is a state it cannot recover from without outside assistance.
| **Hypercall**: | `vcpu_poweroff` |
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x6039` |
| Inputs: | X0: vCPU CapID |
-| | X1: Reserved – Must be Zero |
+| | X1: vCPUPowerOffFlags |
| Outputs: | X0: Error Result |
+**Types:**
+
+*vCPUPowerOffFlags:*
+
+| Bits | Mask | Description |
+|-|---|-----|
+| 0 | `0x1` | Last VCPU to power off in VM |
+| 63:1 | `0xFFFFFFFF.FFFFFFFE` | Reserved — Must be Zero |
+
**Errors:**
-ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid VCPU.
+ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an unrecognised flag value, or specifying a VCPU that is not the caller.
+
+ERROR_DENIED — the caller is the sole powered-on VCPU in a Virtual PM Group, and the last-VCPU flag was not set; or the caller is not the sole powered-on VCPU in a Virtual PM Group, and the last-VCPU flag was set.
Also see: [Capability Errors](#capability-errors)
@@ -1699,7 +2063,9 @@ Also see: [Capability Errors](#capability-errors)
### VCPU vIRQ Bind
-Binds a VCPU interface to a virtual interrupt.
+Each VCPU may have one or more associated virtual interrupt sources, depending on its configuration. This API binds one of those sources to a virtual IRQ number.
+
+If the IRQ type is set to `VCPU_RUN_WAKEUP`, binding the IRQ will automatically place the VCPU into a state in which it can only be scheduled by calling `vcpu_run`. Refer to the [documentation](#run-a-proxy-scheduled-vcpu-thread) for that hypercall for further details.
| **Hypercall**: | `vcpu_bind_virq` |
|-------------------------|--------------------------------------|
@@ -1708,14 +2074,14 @@ Binds a VCPU interface to a virtual interrupt.
| | X1: Virtual IC CapID |
| | X2: Virtual IRQ Info |
| | X3: VCPU Virtual IRQ Type |
-| | X4: Reserved – Must be Zero |
+| | X4: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Types:**
| VCPU Virtual IRQ Type | Integer Value |
|--------------------------------|------------------------|
-| HALT | 0 |
+| VCPU_RUN_WAKEUP | 1 |
**Errors:**
@@ -1733,98 +2099,172 @@ Also see: [Capability Errors](#capability-errors)
### VCPU vIRQ Unbind
-Unbinds a VCPU interface from a virtual IRQ number.
+Unbinds a VCPU interrupt source from a virtual IRQ number.
+
+If the IRQ type is set to `VCPU_RUN_WAKEUP`, unbinding the IRQ will allow the VCPU to run without a `vcpu_run` call, subject to its normal scheduling parameters and state. Note that in some cases this can cause incorrect execution in the VCPU. Refer to the [documentation](#run-a-proxy-scheduled-vcpu-thread) for that hypercall for further details.
| **Hypercall**: | `vcpu_unbind_virq` |
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x605d` |
| Inputs: | X0: VCPU CapID |
| | X1: VCPU Virtual IRQ Type |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
+**Types:**
+
+| VCPU Virtual IRQ Type | Integer Value |
+|--------------------------------|------------------------|
+| VCPU_RUN_WAKEUP | 1 |
+
**Errors:**
OK – the operation was successful, or the VCPU interrupt was already unbound.
Also see: [Capability Errors](#capability-errors)
-### VCPU Write State
+### Kill a VCPU thread
-It updates the VCPU information related to the VCPUState specified.
+Places the VCPU thread in a killed state, forcing it to exit and end execution. The VCPU can no longer be scheduled once it has exited. If the calling VCPU is targeting itself, this call will not return if successful.
-| **Hypercall**: | `vcpu_write_state` |
-|-------------------------|--------------------------------------------|
-| Call number: | `hvc 0x605e` |
-| Inputs: | X0: VCPU CapID |
-| | X1: VCPUState |
-| | X2: Data VMAddr |
-| | X3: Size Size Must be non-zero. |
-| | X4: Reserved – Must be Zero |
-| Outputs: | X0: Error Result |
+| **Hypercall**: | `vcpu_kill` |
+|-------------------------|--------------------------------------|
+| Call number: | `hvc 0x603a` |
+| Inputs: | X0: VCPU CapID |
+| | X1: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+**Errors:**
-**Types:**
+OK – the operation was successful.
-*VCPUState:*
+ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid VCPU.
-| VCPUState | Integer Value |
-|--------------------|------------------------|
-| HALT | 0 |
+ERROR_OBJECT_STATE – the VCPU thread was not active, or has already been killed.
-**Errors:**
+Also see: [Capability Errors](#capability-errors)
-OK – the operation was successful, and the result is valid.
+### Run a Proxy-Scheduled VCPU thread
-ERROR_UNIMPLEMENTED - if functionality not implemented.
+Donates CPU time to a VCPU that is configured for proxy scheduling. This is an optional mechanism that gives a privileged VM's scheduler limited control over the scheduling of another VM's VCPUs.
-`TODO: TBD. Currently unimplemented`
+This call may only be used on a VCPU that has a VIRQ bound to its `VCPU_RUN_WAKEUP` interrupt source. A VCPU that is in that state cannot be scheduled normally by the hypervisor scheduler; it will only execute when this hypercall is used to give it CPU time.
-Also see: [Capability Errors](#capability-errors)
+If all arguments are valid, this hypercall will attempt to context-switch to the specified VCPU. It returns when the caller is preempted or when the specified VCPU is unable to continue running. The VCPU state result indicates the reason that it was unable to continue.
-### VCPU Read State
+Some states may return additional state-specific data to allow the caller to take appropriate actions, and/or require additional data to resume execution which must be passed to the next `vcpu_run` call for the same VCPU. Also, some states may persist for some length of time that can't be directly predicted by the caller; when the VCPU leaves one of these states, it will assert the VIRQ bound to its `VCPU_RUN_WAKEUP` interrupt source.
-It fetches the VCPU information related to the VCPUState specified.
+For this call to behave as intended, the specified VCPU should have lower scheduling priority than the caller. Otherwise, the return from this call may be delayed until execution of the specified VCPU is blocked or its own timeslice expires. This rule is not enforced by the implementation.
-| **Hypercall**: | `vcpu_read_state` |
+| **Hypercall**: | `vcpu_run` |
|-------------------------|--------------------------------------|
-| Call number: | `hvc 0x605f` |
+| Call number: | `hvc 0x6065` |
| Inputs: | X0: VCPU CapID |
-| | X1: VCPUState |
-| | X2: Buffer VMAddr |
-| | X3: MaximumSize Size |
-| | X4: Reserved – Must be Zero |
+| | X1: State-specific Resume Data 1 |
+| | X2: State-specific Resume Data 2 |
+| | X3: State-specific Resume Data 3 |
+| | X4: Reserved —Must be Zero |
| Outputs: | X0: Error Result |
-| | X1: Size Size |
+| | X1: VCPU Run State |
+| | X2: State-specific Data 1 |
+| | X3: State-specific Data 2 |
+| | X4: State-specific Data 3 |
-Size: is the number of bytes received.
+**Types**:
-**Errors:**
+*VCPU Run State*:
-OK – the operation was successful.
+The following table shows the expected types of the state-specific data and resume data for each state. A 0 indicates that the argument or result is currently reserved and must be zero.
-ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid VCPU State value.
+| State | Name | State Data 1 | State Data 2 | State Data 3 | Resume Data 1 |
+|-|--|--|--|--|--|
+| 0x0 | `READY` | 0 | 0 | 0 | 0 |
+| 0x1 | `EXPECTS_WAKEUP` | VCPU Sleep Type | 0 | 0 | 0 |
+| 0x2 | `POWERED_OFF` | VCPU Poweroff Type | 0 | 0 | 0 |
+| 0x3 | `BLOCKED` | 0 | 0 | 0 | 0 |
+| 0x4 | `ADDRSPACE_VMMIO_READ` | VMPhysAddr | Size | 0 | Register |
+| 0x5 | `ADDRSPACE_VMMIO_WRITE` | VMPhysAddr | Size | Register | 0 |
+| 0x100 | `PSCI_SYSTEM_RESET` | PSCI Reset Type | 0 | 0 | 0 |
-ERROR_DENIED – VCPU State passed does not comply with current VCPU state.
+The Resume Data 2 and 3 arguments are currently unused and must be zero for all states.
-ERROR_ARGUMENT_SIZE – the MaximumSize provided is smaller than the information to be fetched.
+0x0 `READY`
+:The caller's hypervisor timeslice ended, or the caller received an interrupt. The caller should retry after handling any pending interrupts.
-ERROR_ADDR_OVERFLOW – the information to be fetched is larger than the provided buffer, and could not be received.
+0x1 `EXPECTS_WAKEUP`
+:The VCPU is waiting to receive an interrupt; for example, it may have executed a WFI instruction, or made a firmware call requesting entry into a low-power state. In the latter case, the state-specific data in X2 will be a platform-specific nonzero value indicating the requested power state. For a platform that implements Arm's PSCI standard, it is in the same format as the state argument to a `PSCI_CPU_SUSPEND` call. The `VCPU_RUN_WAKEUP` VIRQ will be asserted when the VCPU leaves this state.
-ERROR_ADDR_INVALID – some, or the whole of the provided buffer is not mapped.
+0x2 `POWERED_OFF`
+:The VCPU has not yet been started by calling `vcpu_poweron`, or has stopped itself by calling `vcpu_poweroff`, or has been terminated due to a reset request from another VM. If PSCI is implemented, this state is also reachable via PSCI calls. The `VCPU_RUN_WAKEUP` VIRQ will be asserted when the VCPU leaves this state. The first state data word contains a VCPU Poweroff Type value (defined below).
+
+0x3 `BLOCKED`
+:The VCPU is temporarily unable to run due to a hypervisor operation. This may include a hypercall made by the VCPU that transiently blocks it, or by an incomplete migration from another physical CPU. The caller should retry after yielding to the calling VM's scheduler.
+
+0x4 `ADDRSPACE_VMMIO_READ`
+:The VCPU has performed a read access to an unmapped stage 2 address inside a range previously nominated by a call to `addrspace_configure_vmmio`. The first two state data words contain the base IPA and the access size, respectively. The VCPU will be automatically resumed by the next `vcpu_run` call. The first resume data word for that call should be set to the value that will be returned by the read access.
+
+0x5 `ADDRSPACE_VMMIO_WRITE`
+:The VCPU has performed a write access to an unmapped stage 2 address inside a range previously nominated by a call to `addrspace_configure_vmmio`. The three state data words contain the base IPA, access size, and the value written by the access, respectively. The VCPU will be automatically resumed by the next `vcpu_run` call.
+
+0x6 `FAULT`
+: The VCPU has an unrecoverable fault.
+
+0x100 `PSCI_SYSTEM_RESET`
+:On a platform that implements PSCI, the VCPU has made a call to `PSCI_SYSTEM_RESET` or `PSCI_SYSTEM_RESET2`. The first state data word contains a PSCI Reset Type value (defined below). For a `PSCI_SYSTEM_RESET2` call, the second state data word contains the cookie value.
+
+*VCPU Sleep Type:*
+
+This is a platform-specific unsigned word indicating a low-power suspend state. The value 0 is reserved for a trapped wait-for-interrupt or halt instruction, such as the AArch64 `WFI` instruction.
+
+If the platform implements PSCI, nonzero values are power state values as passed to `PSCI_CPU_SUSPEND`.
+
+*VCPU Poweroff Type*:
+
+| Value | Description |
+|-|-----|
+| 0 | Recoverable power-off state, e.g. `vcpu_poweroff` called. |
+| 1 | Terminated; cannot run until the VM resets. |
+| >1 | Reserved. |
+
+*PSCI Reset Type:*
+
+| Bits | Mask | Description |
+|-|---|-----|
+| 31:0 | `0xffffffff` | Reset type for `PSCI_SYSTEM_RESET2`; 0 for `PSCI_SYSTEM_RESET` |
+| 61:32 | `0x3FFFFFFF.00000000` | Reserved — Must be Zero |
+| 62 | `0x40000000.00000000` | 1: `PSCI_SYSTEM_RESET2` SMC64 call, 0: SMC32 call |
+| 63 | `0x80000000.00000000` | 1: `PSCI_SYSTEM_RESET` call, 0: `PSCI_SYSTEM_RESET2` |
+
+**Errors:**
+
+OK – the operation was successful.
+
+ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid VCPU.
+
+ERROR_BUSY – the specified VCPU does not have a bound `VCPU_RUN_WAKEUP` VIRQ.
+
+ERROR_OBJECT_STATE – the VCPU thread was not active, or has already been killed.
Also see: [Capability Errors](#capability-errors)
-### Kill a VCPU thread
+### Check the State of a Halted VCPU
-Places the VCPU thread in a killed state, forcing it to exit and end execution. The VCPU can no longer be scheduled once it has exited. If the calling VCPU is targeting itself, this call will not return if successful.
+Query the state of a VCPU that has generated a halt VIRQ to determine why it halted. The state is described the same way as for `vcpu_run`, but the VCPU is not required to be proxy-scheduled.
-| **Hypercall**: | `vcpu_kill` |
+| **Hypercall**: | `vcpu_run_check` |
|-------------------------|--------------------------------------|
-| Call number: | `hvc 0x603a` |
+| Call number: | `hvc 0x6068` |
| Inputs: | X0: VCPU CapID |
-| | X1: Reserved – Must be Zero |
+| | X4: Reserved – Must be Zero |
| Outputs: | X0: Error Result |
+| | X1: VCPU Run State |
+| | X2: State-specific Data |
+| | X3: State-specific Data |
+| | X4: State-specific Data |
+
+**Types**:
+
+Refer to the [documentation for `vcpu_run_thread`](#run-a-proxy-scheduled-vcpu-thread).
**Errors:**
@@ -1832,6 +2272,8 @@ OK – the operation was successful.
ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid VCPU.
+ERROR_BUSY — the specified VCPU is not halted.
+
ERROR_OBJECT_STATE – the VCPU thread was not active, or has already been killed.
Also see: [Capability Errors](#capability-errors)
@@ -1840,20 +2282,20 @@ Also see: [Capability Errors](#capability-errors)
### Scheduler Yield
-Attaches a VCPU to a Virtual PM Group. The Virtual PM Group object must have been activated before this function is called. The VCPU object must not have been activated. An attachment index must be specified which must be a non-negative integer less than the maximum number of attachments supported by this Virtual PM Group object.
+Informs the hypervisor scheduler that the caller is executing a low priority task or waiting for a non-wakeup event to occur, and wants to give other VCPUs a chance to run. A hint argument may be provided to suggest to the scheduler that a particular VCPU or class of VCPUs should be run instead.
| **Hypercall**: | `scheduler_yield` |
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x603b` |
| Inputs: | X0: control |
| | X1: arg1 |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
*Control:*
-| Bit Numbers | Mask | Description |
-|----------------------|-------------------|----------------------------------------------------------------------------------------------------------------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 15:0 | `0xffff` | hint: Yield type hint. |
| 31 | `0x80000000` | imp_def: Implementation defined flag. If set, the hint value specifies a scheduler implementation specific yield operation. |
@@ -1872,7 +2314,42 @@ Also see: [Capability Errors](#capability-errors)
## Virtual PM Group Management
-A Virtual PM Group is a collection of VCPUs which share a virtual power management state. This state may be accessible via a virtualised platform-specific interface; on AArch64 this is the ARM PSCI (Platform State Configuration Interface) API. Attachment to this object type is optional for VCPUs in single-processor VMs that do not participate in power management decisions.
+A Virtual PM Group is a collection of VCPUs which share a virtual power management state. This state may be accessible via a virtualised platform-specific interface; on AArch64 this is the Arm PSCI (Platform State Configuration Interface) API. Attachment to this object type is optional for VCPUs in single-processor VMs that do not participate in power management decisions.
+
+### Configure a Virtual PM Group
+
+Set configuration options for a Virtual PM Group whose state is `OBJECT_STATE_INIT`. Making this call is optional.
+
+| **Hypercall**: | `vpm_group_configure` |
+|-------------------------|--------------------------------------|
+| Call number: | `hvc 0x6066` |
+| Inputs: | X0: VPMGroup CapID |
+| | X1: VPMGroupOptionFlags |
+| | X2: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Types:**
+
+*VPMGroupOptionFlags:*
+
+| Bit Numbers | Mask | Description |
+|----------------------|----------------------------|---------------------------------|
+| 0 | `0x1` | Exclude from aggregation |
+| 63:1 | `0xFFFFFFFF.FFFFFFFE` | Reserved — Must be Zero |
+
+**Errors:**
+
+OK – the operation was successful.
+
+ERROR_ARGUMENT_INVALID – an unsupported or invalid configuration option was specified.
+
+Also see: [Capability Errors](#capability-errors)
+
+#### Power State Aggregation
+
+If the flags argument's "exclude from aggregation" bit is clear, which is the default configuration, the Virtual PM Group will collect power state votes from its attached VCPUs. These votes will be used when determining what power state the physical device should enter when one or more physical CPUs becomes idle. In general, a physical CPU will enter the shallowest available idle state permitted by the votes of its VCPUs, i.e. a state with wakeup latency no higher than the acceptable limit for each of the VCPUs.
+
+If the "exclude from aggregation" bit is set, the platform-specific power management API calls will still be available, but their effect on the physical power state may be limited. Also, validation of the power management API calls may be relaxed; e.g. for Arm PSCI implementations, the power state argument to `PSCI_CPU_SUSPEND` will not be validated against the states supported by the physical device.
### Virtual PM Group to VCPU Attachment
@@ -1884,7 +2361,7 @@ Attaches a VCPU to a Virtual PM Group. The Virtual PM Group object must have bee
| Inputs: | X0: VPMGroup CapID |
| | X1: VCPU CapID |
| | X2: Index |
-| | X3: Reserved – Must be Zero |
+| | X3: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1909,7 +2386,7 @@ Binds a Virtual PM Group to a virtual interrupt.
| Inputs: | X0: VPMGroup CapID |
| | X1: Virtual IC CapID |
| | X2: Virtual IRQ Info |
-| | X3: Reserved – Must be Zero |
+| | X3: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1934,7 +2411,7 @@ Unbinds a Virtual PM Group from a virtual IRQ number.
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x6044` |
| Inputs: | X0: VPMGroup CapID |
-| | X1: Reserved – Must be Zero |
+| | X1: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -1951,7 +2428,7 @@ Gets the state of the Virtual PM Group.
|-------------------------|--------------------------------------|
| Call number: | `hvc 0x6045` |
| Inputs: | X0: VPMGroup CapID |
-| | X1: Reserved – Must be Zero |
+| | X1: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: VPMState |
@@ -1983,7 +2460,7 @@ Update the trace class flags values by specifying which flags to set and clear.
| Call number: | `hvc 0x603f` |
| Inputs: | X0: SetFlags |
| | X1: ClearFlags |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: SetFlags |
@@ -2002,15 +2479,15 @@ Configure a Watchdog whose state is OBJECT_STATE_INIT.
| Call number: | `hvc 0x6058` |
| Inputs: | X0: Watchdog CapID |
| | X1: WatchdogOptionFlags |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Types:**
*WatchdogOptionFlags:*
-| Bit Numbers | Mask | Description |
-|----------------------|----------------------------|---------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 0 | `0x1` | Critical bite |
| 63:1 | `0xFFFFFFFF.FFFFFFFE` | Reserved, Must be Zero |
@@ -2033,7 +2510,7 @@ Attaches a Watchdog object to a vCPU. The Watchdog object must have been activat
| Call number: | `hvc 0x6040` |
| Inputs: | X0: Watchdog CapID |
| | X1: vCPU CapID |
-| | X2: Reserved – Must be Zero |
+| | X2: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
**Errors:**
@@ -2063,8 +2540,8 @@ Binds a Watchgdog (bark or bite) interface to a virtual IRQ number.
*WatchdogBindOptionFlags:*
-| Bit Numbers | Mask | Description |
-|----------------------|----------------------------|----------------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 0 | `0x1` | Bite virq (If unset, bark virq) |
| 63:1 | `0xFFFFFFFF.FFFFFFFE` | Reserved, Must be Zero |
@@ -2099,8 +2576,8 @@ Unbinds a Watchdog (bark or bite) interface virtual IRQ number.
*WatchdogBindOptionFlags:*
-| Bit Numbers | Mask | Description |
-|----------------------|----------------------------|----------------------------------------|
+| Bits | Mask | Description |
+|-|---|-----|
| 0 | `0x1` | Bite virq (If unset, bark virq) |
| 63:1 | `0xFFFFFFFF.FFFFFFFE` | Reserved, Must be Zero |
@@ -2112,6 +2589,342 @@ OK – the operation was successful, or the watchdog interrupt was already unbou
Also see: [Capability Errors](#capability-errors)
+### Watchdog Runtime Management
+
+Performs miscellaneous management operations on an arbitrary watchdog object (not necessarily the calling VM's watchdog). Currently, three operations are defined:
+
+1. Freeze a watchdog's counter, preventing a bark or bite occurring (if no such event has already occurred).
+1. Freeze a watchdog's counter as above, and also reset the counter to 0.
+1. Unfreeze a watchdog's counter.
+
+This is intended primarily for use by the manager of a proxy-scheduled VM, to prevent watchdog events occurring in the VM if the proxy threads cannot be scheduled.
+
+Note that freeze and unfreeze operations are counted, and the watchdog counter will only progress while the the freeze count is zero (i.e. freeze and unfreeze operations are balanced). Also, freeze and unfreeze operations may be performed automatically by the hypervisor in some cases.
+
+| **Hypercall**: | `watchdog_manage` |
+|-------------------------|------------------------------------|
+| Call number: | `hvc 0x6063` |
+| Inputs: | X0: Watchdog CapID |
+| | X1: WatchdogManageOperation |
+| Outputs: | X0: Error Result |
+
+**Types:**
+
+*WatchdogManageOperation*:
+
+| Operation Enumerator | Integer Value |
+|-----------------------------------------|------------------------|
+| WATCHDOG_MANAGE_OP_FREEZE | 0 |
+| WATCHDOG_MANAGE_OP_FREEZE_AND_RESET | 1 |
+| WATCHDOG_MANAGE_OP_UNFREEZE | 2 |
+
+**Errors:**
+
+OK – the operation was successful, or the watchdog interrupt was already unbound.
+
+ERROR_BUSY – the operation failed because it would otherwise have overflowed or underflowed the watchdog's freeze count.
+
+Also see: [Capability Errors](#capability-errors)
+
+## Virtual IO MMIO Management
+
+### Configure a Virtual IO MMIO
+
+Configure a Virtual IO MMIO whose state is OBJECT_STATE_INIT. The Virtual IO MMIO device needs to get a reference to memextent that covers its range.
+
+| **Hypercall**: | `virtio_mmio_configure` |
+|-------------------------|--------------------------------------|
+| Call number: | `hvc 0x6049` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: Memextent CapID |
+| | X3: VQsNum |
+| | X3: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+
+**Errors:**
+
+OK – the operation was successful, and the result is valid.
+
+ERROR_OBJECT_STATE – if the Virtual IO MMIO object is not in OBJECT_STATE_INIT state.
+
+ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to a VQsNum out of range or if the specified memextent is not contiguous.
+
+Also see: [Capability Errors](#capability-errors)
+
+### Virtual IO MMIO Backend vIRQ Bind
+
+Binds a Virtual IO MMIO backend interface to a virtual interrupt.
+
+| **Hypercall**: | `virtio_mmio_bind_backend_virq` |
+|-------------------------|----------------------------------------|
+| Call number: | `hvc 0x604a` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: Virtual IC CapID |
+| | X2: Virtual IRQ Info |
+| | X3: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Errors:**
+
+OK – the operation was successful, and the result is valid.
+
+ERROR_NOMEM – the operation failed due to memory allocation error.
+
+ERROR_VIRQ_BOUND – the specified virtual IO MMIO is already bound to a VIRQ number.
+
+ERROR_BUSY – the specified VIRQ number is already bound to a source.
+
+ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid Virtual IRQ Info value.
+
+Also see: [Capability Errors](#capability-errors)
+
+### Virtual IO MMIO Backend vIRQ Unbind
+
+Unbinds a Virtual IO MMIO backend interface from a virtual IRQ number.
+
+| **Hypercall**: | `virtio_mmio_unbind_backend_virq` |
+|-------------------------|------------------------------------------|
+| Call number: | `hvc 0x604b` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Errors:**
+
+OK – the operation was successful, or the virtual IO MMIO interrupt was already unbound.
+
+Also see: [Capability Errors](#capability-errors)
+
+### Virtual IO MMIO Frontend vIRQ Bind
+
+Binds a Virtual IO MMIO frontend interface to a virtual interrupt.
+
+| **Hypercall**: | `virtio_mmio_bind_frontend_virq` |
+|-------------------------|-----------------------------------------|
+| Call number: | `hvc 0x604c` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: Virtual IC CapID |
+| | X2: Virtual IRQ Info |
+| | X3: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Errors:**
+
+OK – the operation was successful, and the result is valid.
+
+ERROR_NOMEM – the operation failed due to memory allocation error.
+
+ERROR_VIRQ_BOUND – the specified virtual IO MMIO is already bound to a VIRQ number.
+
+ERROR_BUSY – the specified VIRQ number is already bound to a source.
+
+ERROR_ARGUMENT_INVALID – a value passed in an argument was invalid. This could be due to an invalid Virtual IRQ Info value.
+
+Also see: [Capability Errors](#capability-errors)
+
+### Virtual IO MMIO Frontend vIRQ Unbind
+
+Unbinds a Virtual IO MMIO backend interface from a virtual IRQ number.
+
+| **Hypercall**: | `virtio_mmio_unbind_frontend_virq` |
+|-------------------------|-------------------------------------------|
+| Call number: | `hvc 0x604d` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Errors:**
+
+OK – the operation was successful, or the virtual IO MMIO interrupt was already unbound.
+
+Also see: [Capability Errors](#capability-errors)
+
+### Virtual IO MMIO Backend Assert vIRQ
+
+The backend makes this call to assert the virtual IRQ directed to the frontend and writes a bit mask of events that caused the assertion.
+
+| **Hypercall**: | `virtio_mmio_backend_assert_virq` |
+|-------------------------|------------------------------------------|
+| Call number: | `hvc 0x604e` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: InterruptStatus |
+| | X2: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Errors:**
+
+OK – the operation was successful, or the virtual IO MMIO interrupt was already unbound.
+
+ERROR_DENIED – Cannot assert irq since there is a reset currently pending.
+
+ERROR_ARGUMENT_INVALID – A value passed in an argument was invalid.
+
+Also see: [Capability Errors](#capability-errors)
+
+### Virtual IO MMIO Backend Set DeviceFeatures
+
+Set the device features flags based on the specified device features selector. The device features specified must comply with the features enforced by the hypervisor (VIRTIO_F_VERSION_1, VIRTIO_F_ACCESS_PLATFORM, !VIRTIO_F_NOTIFICATION_DATA).
+
+| **Hypercall**: | `virtio_mmio_backend_set_dev_features` |
+|-------------------------|-----------------------------------------------|
+| Call number: | `hvc 0x604f` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: DeviceFeaturesSel |
+| | X2: DeviceFeatures |
+| | X3: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Errors:**
+
+OK – The operation was successful, and the result is valid.
+
+ERROR_ARGUMENT_INVALID – A value passed in an argument was invalid.
+
+ERROR_DENIED – Device features passed do not comply with the features enforced by the hypervisor.
+
+Also see: [Capability Errors](#capability-errors)
+
+### Virtual IO MMIO Backend Set QueueNumMax
+
+Set maximum virtual queue size of the queue specified by the queue selector.
+
+| **Hypercall**: | `virtio_mmio_backend_set_queue_num_max` |
+|-------------------------|------------------------------------------------|
+| Call number: | `hvc 0x6050` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: QueueSel |
+| | X2: QueueNumMax |
+| | X3: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Errors:**
+
+OK – The operation was successful, and the result is valid.
+
+ERROR_ARGUMENT_INVALID – A value passed in an argument was invalid.
+
+Also see: [Capability Errors](#capability-errors)
+
+### Virtual IO MMIO Backend Get DriverFeatures
+
+Get the driver features flags based on the specified driver features selector.
+
+| **Hypercall**: | `virtio_mmio_backend_get_drv_features` |
+|-------------------------|-----------------------------------------------|
+| Call number: | `hvc 0x6051` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: DriverFeaturesSel |
+| | X2: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+| | X1: DriverFeatures |
+
+**Errors:**
+
+OK – The operation was successful, and the result is valid.
+
+ERROR_ARGUMENT_INVALID – A value passed in an argument was invalid.
+
+Also see: [Capability Errors](#capability-errors)
+
+### Virtual IO MMIO Backend Get Queue Info
+
+Get information from the queue specified by the queue selector.
+
+| **Hypercall**: | `virtio_mmio_backend_get_queue_info` |
+|-------------------------|---------------------------------------------|
+| Call number: | `hvc 0x6052` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: QueueSel |
+| | X2: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+| | X1: QueueNum |
+| | X2: QueueReady |
+| | X3: QueueDesc (low and high) |
+| | X4: QueueDriver (low and high) |
+| | X5: QueueDevice (low and high) |
+
+**Errors:**
+
+OK – The operation was successful, and the result is valid.
+
+ERROR_ARGUMENT_INVALID – A value passed in an argument was invalid.
+
+Also see: [Capability Errors](#capability-errors)
+
+### Virtual IO MMIO Backend Get Notification
+
+The backend should make this call, when its VIRQ is asserted, to get a bitmap of the virtual queues that need to be notified and a bitmap of the reasons why the VIRQ was asserted. This calls also deasserts the backend’s VIRQ.
+
+| **Hypercall**: | `virtio_mmio_backend_get_notification` |
+|-------------------------|-----------------------------------------------|
+| Call number: | `hvc 0x6053` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+| | X1: VQs Bitmap |
+| | X2: NotifyReason Bitmap |
+
+**Types:**
+
+*NotifyReason:*
+
+| Bits | Mask | Description |
+|-|---|-----|
+| 0 | `0x1` | 1 = NEW_BUFFER: notifies the device that there are new buffers to process in a queue. |
+| 1 | `0x2` | 1 = RESET_RQST: notifies the device that a device reset has been requested. |
+| 2 | `0x4` | 1 = INTERRUPT_ACK: notifies the device that the frontend wrote to the InterruptACK register. |
+| 3 | `0x8` | 1 = DRIVER_OK: notifies the device that the frontend has set the DRIVER_OK bit of the Status register. |
+| 4 | `0x10` | 1 = FAILED: notifies the device that the frontend has set the FAILED bit of the Status register. |
+| 63:5 | `0xFFFFFFFF.FFFFFFE0` | Reserved = 0 [TBD notify reasons] |
+
+**Errors:**
+
+OK – The operation was successful, and the result is valid.
+
+ERROR_ARGUMENT_INVALID – A value passed in an argument was invalid.
+
+Also see: [Capability Errors](#capability-errors)
+
+### Virtual IO MMIO Backend Acknowledge Reset
+
+The backend should make this call after a device reset is completed. This call will clear all bits in QueueReady for all queues in the device.
+
+| **Hypercall**: | `virtio_mmio_backend_acknowledge_reset` |
+|-------------------------|------------------------------------------------|
+| Call number: | `hvc 0x6054` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Errors:**
+
+OK – The operation was successful, and the result is valid.
+
+ERROR_ARGUMENT_INVALID – A value passed in an argument was invalid.
+
+Also see: [Capability Errors](#capability-errors)
+
+### Virtual IO MMIO Backend Set Status
+
+This calls sets status register.
+
+| **Hypercall**: | `virtio_mmio_backend_set_status` |
+|-------------------------|-----------------------------------------|
+| Call number: | `hvc 0x6055` |
+| Inputs: | X0: VirtioMMIO CapID |
+| | X1: Status |
+| | X2: Reserved — Must be Zero |
+| Outputs: | X0: Error Result |
+
+**Errors:**
+
+OK – The operation was successful, and the result is valid.
+
+ERROR_ARGUMENT_INVALID – A value passed in an argument was invalid.
+
+Also see: [Capability Errors](#capability-errors)
+
## PRNG Management
### PRNG Get Entropy
@@ -2122,7 +2935,7 @@ Gets random numbers from a DRBG that is seeded by a TRNG. Typically this API wil
|---------------------|--------------------------------|
| Call number: | `hvc 0x6057` |
| Inputs: | X0: NumBytes |
-| | X1: Reserved – Must be Zero |
+| | X1: Reserved — Must be Zero |
| Outputs: | X0: Error Result |
| | X1: Data0 |
| | X2: Data1 |
@@ -2135,13 +2948,14 @@ OK – the operation was successful, and the result is valid.
ERROR_ARGUMENT_SIZE – the NumBytes provided is zero, or exceeds the possible bytes to be returned in the Data output registers.
-ERROR_BUSY - Called within the read rate-limit window.
+ERROR_BUSY – Called within the read rate-limit window.
-ERROR_UNIMPLEMENTED - if functionality not implemented.
+ERROR_UNIMPLEMENTED – if functionality not implemented.
Also see: [Capability Errors](#capability-errors)
## Error Results
+
### Error Code Enumeration
| Error Enumerator | Integer Value |
@@ -2179,17 +2993,19 @@ Also see: [Capability Errors](#capability-errors)
| ERROR_MSGQUEUE_EMPTY | 60 |
| ERROR_MSGQUEUE_FULL | 61 |
| | |
+| ERROR_MEMDB_NOT_OWNER | 111 |
| ERROR_MEMEXTENT_MAPPINGS_FULL | 120 |
+| ERROR_MEMEXTENT_TYPE | 121 |
| ERROR_EXISTING_MAPPING | 200 |
### Capability Errors
-ERROR_CSPACE_CAP_NULL - invalid CapID.
+ERROR_CSPACE_CAP_NULL – invalid CapID.
-ERROR_CSPACE_CAP_REVOKED - CapID no longer valid since it has already been revoked.
+ERROR_CSPACE_CAP_REVOKED – CapID no longer valid since it has already been revoked.
-ERROR_CSPACE_WRONG_OBJECT_TYPE - CapID does not correspond with the specified object type.
+ERROR_CSPACE_WRONG_OBJECT_TYPE – CapID does not correspond with the specified object type.
-ERROR_CSPACE_INSUFFICIENT_RIGHTS - CapID has not enough rights to execute operation.
+ERROR_CSPACE_INSUFFICIENT_RIGHTS – CapID has not enough rights to execute operation.
-ERROR_CSPACE_FULL - CSpace has reached maximum number of capabilities allowed.
+ERROR_CSPACE_FULL – CSpace has reached maximum number of capabilities allowed.
diff --git a/docs/build.md b/docs/build.md
index b7bbea4..f3e803d 100644
--- a/docs/build.md
+++ b/docs/build.md
@@ -15,54 +15,73 @@ Always ensure you have activated the `gunyah-venv` *before* running `configure`
The following repositories are needed to build a Gunyah Hypervisor image:
-- [Gunyah Hypervisor](https://github.com/quic/gunyah-hypervisor) - The Gunyah Hypervisor.
+These should all be cloned into the same top-level directory (this assumed in the Docker setup).
+
+- [Gunyah Hypervisor](https://github.com/quic/gunyah-hypervisor) — The Gunyah Hypervisor.
```bash
- git clone https://github.com/quic/gunyah-hypervisor.git
+ git clone https://github.com/quic/gunyah-hypervisor.git hyp
```
-- [Resource Manager](https://github.com/quic/gunyah-resource-manager) - The privileged root VM and VM manager supporting the Gunyah Hypervisor.
+- [Resource Manager](https://github.com/quic/gunyah-resource-manager) — The privileged root VM and VM manager supporting the Gunyah Hypervisor.
```bash
- git clone https://github.com/quic/gunyah-resource-manager.git
+ git clone https://github.com/quic/gunyah-resource-manager.git resource-manager
```
-- [Gunyah C Runtime](https://github.com/quic/gunyah-c-runtime) - A runtime for light-weight OS-less application VMs.
+- [Gunyah C Runtime](https://github.com/quic/gunyah-c-runtime) — A runtime for light-weight OS-less application VMs.
```bash
-git clone https://github.com/quic/gunyah-c-runtime.git
+git clone https://github.com/quic/gunyah-c-runtime.git musl-c-runtime
```
## Build Configuration
The build system has several configuration parameters that must be set:
-* `platform`: selects the target hardware platform;
-* `featureset`: selects a named set of enabled features; and
-* `quality`: specifies the build quality, e.g. `debug`, `production` etc, which affect compilation of runtime assertions, compiler optimisations etc.
+* `platform`: selects the target hardware platform
+* `featureset`: selects a named hypervisor architecture configuration
+* `quality`: specifies the build quality, e.g. `debug`, `production` etc., which modify the build - such as including runtime assertions, compiler optimisations etc.
-These parameters must be set on the build system's command line; if one or more of them is left unset, the build system will print the known values for the missing parameter and abort. You may specify a comma-separated list to select multiple values for a parameter, or `all` to select every known value. You may also specify `all=true`, which is equivalent to specifying `all` for every parameter that is not otherwise specified. The when multiple options are selected, each combination (variant) will be built in separate output directories under the `build` directory.
+These parameters must be set on the build system's command line; if one or more
+of them is left unset, the build system will print the known values for the
+missing parameter and abort. You may specify a comma-separated list to select
+multiple values for a parameter, or `all` to select every valid combination.
+You may also specify simply `all=true`, which is equivalent to specifying `all`
+for every parameter that is not otherwise specified. The when multiple options
+are selected, each combination (variant) will be built in separate output
+directories under the `build` directory.
-Each project may be build using `ninja` or `scons` and the process for build configuration depends on the selected build tool used. See the sections below.
+Each project may be built using `ninja` or `scons` and the process for build configuration depends on the selected build tool used. See the sections below.
## Building
-The Gunyah Hypervisor, Resource Manager and C runtime are built separately, each following the same build instructions below. These will be packages together into a final boot image.
+The Gunyah Hypervisor, Resource Manager and C runtime are built separately,
+each following the similar build instructions below. These separate images need
+to be packaged together into a final boot image.
-> IMPORTANT! If making hypervisor public API changes, these changes need to be added to the Resource Manager and libc Runtime.
+> IMPORTANT! If making hypervisor public API changes, these changes will need to be updated in the Resource Manager and Runtime sources.
### Building with Ninja
-To configure the build for using *Ninja*, run `./configure.py `, specifying the configuration parameters.
+To configure the build for use with *Ninja*, run `./configure.py `
+in the top-level source repository of the component, specifying the desired
+configuration parameters.
-For example, in each of the Gunyah Hypervisor, Resource Manager and Gunyah C Runtime checkouts, run:
+For example, in each of the Gunyah Hypervisor, Resource Manager and Gunyah C Runtime source directories, run:
```sh
./configure.py platform=qemu featureset=gunyah-rm-qemu quality=production
```
-or to build all available configurations for QEMU:
+or to build all available configurations for the QEMU platform:
```sh
./configure.py platform=qemu all=true
```
This will create a `build` directory and Ninja build rules file for each enabled build variant. Generally, the `configure` step only needs to be run once.
-Run `ninja` to build. There is usually no need to specify `-j` or similar, as Ninja will select this automatically. Ninja also will incrementally re-build if run again after making code changes.
+```sh
+ninja
+```
+
+Run `ninja` to build. There is usually no need to specify `-j` or similar, as
+Ninja will select this automatically. Ninja also will incrementally re-build if
+run again after making code changes.
> Note, if configuration files are modified, Ninja will rerun the configuration tool with the previous parameters. However, you must manually rerun the configuration step if you rename or delete an existing module or configuration parameter, as Ninja will refuse to run if a build configuration file is missing.
To build a specific file (for example, a single variant when multiple variants have been configured), specify its full name as the target on the `ninja` command line.
@@ -71,19 +90,21 @@ To clean the build, run `ninja -t clean`. It should not be necessary to do this
### Building with SCons
-To perform a standalone SCons build, run `scons`, specifying the configuration parameters. For example, to build debug builds of all available feature sets for the QEMU:
+To perform a standalone SCons build, run `scons`, specifying the configuration
+parameters. For example, to build debug builds of all available feature sets
+for the QEMU platform:
```sh
scons platform=qemu featureset=all quality=debug
```
-Note, configuration parameters *must* be specified on every SCons build; they will not be cached.
+Note, configuration parameters *must* be specified on every time you perform a SCons build; configuration is not cached.
To clean the build, run `scons -c all=true`, or use configuration parameters to select a specific variant to clean. It should not be necessary to do this routinely.
## Producing a Boot Image
-Once you have built the Gunyah Hypervisor, Resource Manager and C Runtime, a boot image can be prepared.
+Once you have built the Gunyah Hypervisor, Resource Manager and C Runtime, a boot image needs be generated.
To reduce the size of the boot image, the generated binaries of Resource Manager and C Runtime need to be stripped with the following commands:
```bash
@@ -93,7 +114,9 @@ $LLVM/bin/llvm-strip -o /build/runtime.strip
git clone https://github.com/eliben/pyelftools.git
@@ -102,10 +125,10 @@ git clone https://github.com/eliben/pyelftools.git
To generate `hypvm.elf` boot image run these steps (substituting ``s for each tool / executable):
```bash
cd
-PYTHONPATH=/pyelftools tools/elf/package_apps.py \
+tools/elf/package_apps.py \
-a /build/resource-manager.strip \
-r /build/runtime.strip \
/build/qemu/gunyah-rm-qemu/production/hyp.elf \
-o /hypvm.elf
```
-> Note, you may wish to pick a different hypervisor `hyp.elf` from a different build variant (i.e. `build/qemu/gunyah-rm-qemu/production/`).
+> Note, you may wish to pick a different hypervisor `hyp.elf` from a different build variant (i.e. `build/qemu/gunyah-rm-qemu/debug/`).
diff --git a/docs/docker.md b/docs/docker.md
deleted file mode 100644
index 1682834..0000000
--- a/docs/docker.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Docker
-
-A Docker container can be used to host the build tools and QEMU simulator. This is an alternative to installing them directly on a host Linux workstation.
-
-## Installation
-
-Install Docker in your machine following the instructions: https://docs.docker.com/engine/install/
-
-## Build the Docker image from a Dockerfile
-
-A Dockerfile may be found here: [Gunyah support scripts](https://github.com/quic/gunyah-support-scripts)
-
-To build the Docker image, first go to the directory that contains the [Dockerfile](https://github.com/quic/gunyah-support-scripts/tree/develop/gunyah-qemu-aarch64/Dockerfile):
-```bash
-cd
-```
-
-Build the Dockerfile and give it a name and optionally a tag using the following command:
-```bash
-docker build -f Dockerfile -t : .
-```
-
-> Note, for building this image you may need to increase the available disk space for Docker.
-
-Finally, run the generated Docker image with this command:
-```bash
-docker run -it :
-```
-## Development
-
-Once your Docker container is setup, proceed to building the hypervisor: [Build instructions](build.md)
diff --git a/docs/setup.md b/docs/setup.md
index 200c99d..1bde4c6 100644
--- a/docs/setup.md
+++ b/docs/setup.md
@@ -1,48 +1,37 @@
# Setup Instructions
-The following instructions describe setting up a Linux machine for Gunyah development and testing. You may alternatively wish to use Docker:
+## Development Environment
-[Docker Instructions](docker.md)
+We recommend using a Docker container with the required compilers and tools for
+convenience.
-## Toolchain
-The Gunyah Hypervisor projects use the LLVM 10+ toolchain, cross-compiled for AArch64. Standalone applications (Resource Manager) are built with the musl libc library.
+A separate _Gunyah Support Scripts_ repository is maintained with reference
+Docker based environment instructions and scripts.
-A [script](https://github.com/quic/gunyah-support-scripts/tree/develop/gunyah-qemu-aarch64/llvm_musl_build.sh) to help build a suitable LLVM compiler (with musl libc) can be found in [Gunyah support scripts](https://github.com/quic/gunyah-support-scripts).
+See:
+[Gunyah Support Scripts](https://github.com/quic/gunyah-support-scripts/tree/develop)
```bash
git clone https://github.com/quic/gunyah-support-scripts.git
```
-To build the LLVM toolchain, first execute the provided [script](https://github.com/quic/gunyah-support-scripts/tree/develop/gunyah-qemu-aarch64/llvm_musl_build.sh) in the directory where you want it to be installed.
+## Custom Dev Environment
-```bash
-cd
-.//llvm_musl_build.sh
-```
-
-> Note, this script requires cmake to be installed.
-
-This script will generate a `llvm-musl-install` folder in the current directory.
+If you intend to setup your own development environment, you can follow the
+reference Docker setup on your development host. This process is not
+documented.
-## C Application Sysroot
+### Toolchain
-The Resource Manager needs to be compiled using the libfdt library, cross-compiled for AArch64.
-
-The following instructions indicate how to get the libfdt source code and cross compile it for AArch64:
-
-```bash
-git clone https://github.com/dgibson/dtc.git
-cd dtc
-CC=aarch64-linux-gnu-gcc make install libfdt PREFIX=
-```
+The Gunyah Hypervisor projects use the LLVM v15 toolchain, cross-compiled for
+AArch64 and musl libc. This is due to standalone application VMs (Resource
+Manager) are built with a runtime supporting the musl libc library.
-> Note, \ refers to the desired path where the built will be installed.
+### Set up environment variables
-## Set up environment variables
You must set the following environment variables:
-- To point to the toolchain (assumed to be Clang 10.0 or later):
```bash
-export LLVM=/path/to/llvm10/
+export LLVM=/path/to/llvm15/
```
> Note, when using the toolchain built with the provided script, point to the "llvm-musl-install" generated folder.
> `export LLVM=/path/to/llvm-musl-install`
@@ -52,7 +41,7 @@ export LLVM=/path/to/llvm10/
export LOCAL_SYSROOT=/path/to/c-application-sysroot
```
-## Install the Python dependencies
+### Install the Python dependencies
Create a virtual environment, activate it, and install the modules used by the auto-generation code:
@@ -62,4 +51,6 @@ python3 -m venv gunyah-venv
pip install -r /tools/requirements.txt
```
-We recommend installing the Python environment _outside_ the Gunyah source directory. This is so the automatic dependency detection in the Python scripts ignores modules imported from the virtual environment.
+We recommend installing the Python environment _outside_ the Gunyah source
+directory. This is so the automatic dependency detection in the Python scripts
+ignores modules imported from the virtual environment.
diff --git a/docs/terminology.md b/docs/terminology.md
new file mode 100644
index 0000000..a267e70
--- /dev/null
+++ b/docs/terminology.md
@@ -0,0 +1,12 @@
+## Terminology:
+
+### PVM : **P**rimary **V**irtual **M**achine
+- This is the VM that's created for the primary HLOS to execute
+- Generally all the resources are assigned to this VM
+
+### HLOS : **H**igh **L**evel **OS**
+- Mean the main OS owning the majority of the HW device access.
+- Typically used as a synonym for PVM.
+
+### SVM : **S**econdary **V**irtual **M**achine
+- These VM's are created and launched from the PVM
diff --git a/docs/test.md b/docs/test.md
index f36abe5..68613c6 100644
--- a/docs/test.md
+++ b/docs/test.md
@@ -1,54 +1,18 @@
# Testing Gunyah Hypervisor
We provide two ways of testing the hypervisor:
-1. [Using a Docker container](#1-using-a-docker-container)
-2. [Using local machine](#2-using-a-local-linux-machine)
+1. [Using a Docker container](#using-a-docker-container)
+2. [Using local machine](#using-a-local-linux-machine)
-## 1. Using a Docker container
+## Using a Docker container
-A Docker image can been built (with this [Dockerfile](https://github.com/quic/gunyah-support-scripts/tree/develop/gunyah-qemu-aarch64/Dockerfile)) to make the testing easier, without needing to install the tools directly on your machine.
+A Docker image can been built with the required compiler and QEMU Arm System emulator.
+See [Setup Instructions](setup.md).
-The Dockerfile provided contains:
-- Latest QEMU (version required: >= 5.0.0)
-- GDB 9.2 (version required: >= 9.2)
-- Latest Linux image (to be used as primary VM)
-- RAM disk generated with Busybox-1.33.0 (to be used by primary VM)
-- Device tree (to be used by primary VM)
-- LLVM 10.0.1 toolchain with musl libc for AArch64
-- Virtual environment (gunyah-venv)
-- Script with the QEMU start command (start_cmd.sh)
-- Required environment variables set
-- Required dependencies installed
+## Using a local Linux machine
-Once a Docker image is built, the required files can be found in `$OUTPUT_DIR` (`/usr/local/src/out`).
-
-### Instructions
-
-1. Build the Docker image:
- [Docker instructions](docker.md)
-
-> Note, make sure that at this point you are running on the Docker container's shell. (e.g. `docker run -it :`)
-
-2. Download and build the hypervisor source code:
- [Build instructions](build.md)
-3. Boot the Gunyah Hypervisor with the Linux VM on the QEMU simulator.
-
- Use the following QEMU start command:
-```bash
-qemu-system-aarch64 -machine virt,virtualization=on,gic-version=3,highmem=off \
--cpu max -m size=2G -smp cpus=8 -nographic \
--kernel /hypvm.elf \
--device loader,file=$OUTPUT_DIR/Image,addr=$LINUX_BASE \
--device loader,file=$OUTPUT_DIR/virt.dtb,addr=$DT_BASE \
--device loader,file=$OUTPUT_DIR/initrd.img,addr=$INITRD_BASE
-```
-
-> Note, see [Hardcoded Parameters](#hardcoded-parameters) section for an explanation of why these `_BASE` values have been set as environment variables.
-
-## 2. Using a local Linux machine
-
-1. Install latest QEMU:
- [QEMU instructions](qemu.md)
+1. Build and install a recent QEMU (v7.2 is tested):
+ - See Docker support scripts for reference
2. Download and build the hypervisor source code:
- [Setup Instructions](setup.md)
- [Build instructions](build.md)
@@ -56,69 +20,7 @@ qemu-system-aarch64 -machine virt,virtualization=on,gic-version=3,highmem=off \
[Linux instructions](linux.md)
4. Create a RAM disk for Linux:
[RAM disk instructions](ramdisk.md)
-5. Generate a device tree with 512M of RAM:
-
-```bash
-qemu-system-aarch64 \
--machine virt,virtualization=on,gic-version=3,highmem=off \
--cpu max -m size=512M -smp cpus=8 -nographic \
--kernel /hypvm.elf \
--append "rw root=/dev/ram rdinit=/sbin/init earlyprintk=serial,ttyAMA0 console=ttyAMA0" \
--machine dumpdtb=virt_qemu.dtb
-```
-
-6. Modify the "chosen" node in the device tree based on the created RAM disk:
-
- Create a device tree overlay with the new "chosen" node values and apply it to the dtb generated in the previous step.
-
-```bash
-export INITRD_BASE=0x44400000
-export INITRD_SIZE=$(stat -Lc %s /initrd.img)
-export INITRD_END=$(printf "0x%x" $((${INITRD_BASE} + ${INITRD_SIZE})))
-cat < overlay.dts
-/dts-v1/;
-/{
-fragment@0{
-target-path = "/chosen";
-__overlay__{
-linux,initrd-start = <${INITRD_BASE}>;
-linux,initrd-end = <${INITRD_END}>;
-};
-};
-};
-EOF
-dtc -@ -I dts -O dtb overlay.dts -o overlay.dtbo
-fdtoverlay -v -i virt_qemu.dtb -o virt.dtb overlay.dtbo
-rm overlay.dts overlay.dtbo virt_qemu.dtb
-dtc -I dtb -O dts virt.dtb > virt.dts
-cp virt.dts /.
-cp virt.dtb /.
-```
-
+5. Generate a device tree for the QEMU platform:
+ - See Docker support scripts for reference
7. Boot the Gunyah Hypervisor with the Linux VM on the QEMU simulator:
-
-```bash
-qemu-system-aarch64 \
--machine virt,virtualization=on,gic-version=3,highmem=off \
--cpu max -m size=2G -smp cpus=8 -nographic \
--kernel /hypvm.elf \
--device loader,file=/Image,addr=$LINUX_BASE \
--device loader,file=/virt.dtb,addr=$DT_BASE \
--device loader,file=/initrd.img,addr=$INITRD_BASE
-```
-
-> Note, see [Hardcoded Parameters](#hardcoded-parameters) section for an explanation of why these `_BASE` values have been set as environment variables.
-
-## Hardcoded parameters
-
-In the [Gunyah Hypervisor](https://github.com/quic/gunyah-hypervisor) repository, specifically in `hyp/platform/soc_qemu/src/boot.c`, we currently have hardcoded the base addresses to be used in the QEMU start command. We hope to address this in future contributions such that these values only need to be set in the QEMU command. For now, in case you want to change these values in the start command, please make sure you also modify these values in the code, without overlapping with the range assigned to the hypervisor RAM.
-
-The current hardcoded addresses that need to be used in the QEMU start command are:
-(set in [boot.c](https://github.com/quic/gunyah-hypervisor/tree/develop/hyp/platform/soc_qemu/src/boot.c) in function soc_qemu_handle_rootvm_init())
-- LINUX_BASE=0x41080000
-- DT_BASE=0x44200000
-- INITRD_BASE=0x44400000
-
-Current hypervisor RAM range:
-(set in [boot.c](https://github.com/quic/gunyah-hypervisor/tree/develop/hyp/platform/soc_qemu/src/boot.c) in function platform_ram_probe())
-- 0x80000000..0xBFFFFFFF
+ - See Docker support scripts for reference
diff --git a/hyp/arch/aarch64/include/asm/asm_defs.inc b/hyp/arch/aarch64/include/asm/asm_defs.inc
index a0a3869..6f789b9 100644
--- a/hyp/arch/aarch64/include/asm/asm_defs.inc
+++ b/hyp/arch/aarch64/include/asm/asm_defs.inc
@@ -49,7 +49,7 @@
.endm
// Branch target identification helpers
-#if defined(ARCH_ARM_8_5_BTI)
+#if defined(ARCH_ARM_FEAT_BTI)
#define BRANCH_TARGET(type, ...) \
bti type; \
__VA_ARGS__
diff --git a/hyp/arch/aarch64/include/asm/barrier.h b/hyp/arch/aarch64/include/asm/barrier.h
index e64e4c9..dab8db1 100644
--- a/hyp/arch/aarch64/include/asm/barrier.h
+++ b/hyp/arch/aarch64/include/asm/barrier.h
@@ -21,4 +21,4 @@
// The asm_ordering variable is used as an artificial dependency to order
// different individual asm statements with respect to each other in a way that
// is lighter weight than a full "memory" clobber.
-extern struct asm_ordering_dummy asm_ordering;
+extern asm_ordering_dummy_t asm_ordering;
diff --git a/hyp/arch/aarch64/include/asm/panic.inc b/hyp/arch/aarch64/include/asm/panic.inc
index f26f27e..ac26422 100644
--- a/hyp/arch/aarch64/include/asm/panic.inc
+++ b/hyp/arch/aarch64/include/asm/panic.inc
@@ -7,6 +7,6 @@
local panic_str\@:
.asciz "\panic_str"
.popsection
- adr x0, LOCAL(panic_str\@)
+ adrl x0, LOCAL(panic_str\@)
bl panic
.endm
diff --git a/hyp/arch/aarch64/include/asm/sysregs.h b/hyp/arch/aarch64/include/asm/sysregs.h
index ba6649a..6b89691 100644
--- a/hyp/arch/aarch64/include/asm/sysregs.h
+++ b/hyp/arch/aarch64/include/asm/sysregs.h
@@ -4,17 +4,17 @@
#define sysreg64_read(reg, val) \
do { \
- register_t _val; \
- __asm__ volatile("mrs %0, " #reg ";" : "=r"(_val)); \
- val = (__typeof__(val))_val; \
+ register_t val_; \
+ __asm__ volatile("mrs %0, " #reg ";" : "=r"(val_)); \
+ val = (__typeof__(val))val_; \
} while (0)
#define sysreg64_read_ordered(reg, val, ordering_var) \
do { \
- register_t _val; \
+ register_t val_; \
__asm__ volatile("mrs %0, " #reg ";" \
- : "=r"(_val), "+m"(ordering_var)); \
- val = (__typeof__(val))_val; \
+ : "=r"(val_), "+m"(ordering_var)); \
+ val = (__typeof__(val))val_; \
} while (0)
#define sysreg64_write(reg, val) \
diff --git a/hyp/arch/aarch64/include/asm/system_registers.h b/hyp/arch/aarch64/include/asm/system_registers.h
index 4e84023..a6a2c00 100644
--- a/hyp/arch/aarch64/include/asm/system_registers.h
+++ b/hyp/arch/aarch64/include/asm/system_registers.h
@@ -40,12 +40,14 @@
#define ISS_MRS_MSR_ID_AA64PFR0_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 4, 0)
#define ISS_MRS_MSR_ID_AA64PFR1_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 4, 1)
#define ISS_MRS_MSR_ID_AA64ZFR0_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 4, 4)
+#define ISS_MRS_MSR_ID_AA64SMFR0_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 4, 5)
#define ISS_MRS_MSR_ID_AA64DFR0_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 5, 0)
#define ISS_MRS_MSR_ID_AA64DFR1_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 5, 1)
#define ISS_MRS_MSR_ID_AA64AFR0_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 5, 4)
#define ISS_MRS_MSR_ID_AA64AFR1_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 5, 5)
#define ISS_MRS_MSR_ID_AA64ISAR0_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 6, 0)
#define ISS_MRS_MSR_ID_AA64ISAR1_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 6, 1)
+#define ISS_MRS_MSR_ID_AA64ISAR2_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 6, 2)
#define ISS_MRS_MSR_ID_AA64MMFR0_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 7, 0)
#define ISS_MRS_MSR_ID_AA64MMFR1_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 7, 1)
#define ISS_MRS_MSR_ID_AA64MMFR2_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 0, 7, 2)
@@ -68,6 +70,7 @@
#define ISS_MRS_MSR_PMCCFILTR_EL0 ISS_OP0_OP1_CRN_CRM_OP2(3, 3, 14, 15, 7)
#define ISS_MRS_MSR_SCTLR_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 1, 0, 0)
+#define ISS_MRS_MSR_ACTLR_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 1, 0, 1)
#define ISS_MRS_MSR_TTBR0_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 2, 0, 0)
#define ISS_MRS_MSR_TTBR1_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 2, 0, 1)
#define ISS_MRS_MSR_TCR_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 2, 0, 2)
@@ -109,7 +112,7 @@
#define ISS_MRS_MSR_DC_CISW ISS_OP0_OP1_CRN_CRM_OP2(1, 0, 7, 14, 2)
#define ISS_MRS_MSR_DC_ISW ISS_OP0_OP1_CRN_CRM_OP2(1, 0, 7, 6, 2)
-#if defined(ARCH_ARM_8_4_AMU) || defined(ARCH_ARM_8_6_AMU)
+#if defined(ARCH_ARM_FEAT_AMUv1) || defined(ARCH_ARM_FEAT_AMUv1p1)
#define ISS_MRS_MSR_AMCR_EL0 ISS_OP0_OP1_CRN_CRM_OP2(3, 3, 13, 2, 0)
#define ISS_MRS_MSR_AMCFGR_EL0 ISS_OP0_OP1_CRN_CRM_OP2(3, 3, 13, 2, 1)
#define ISS_MRS_MSR_AMCGCR_EL0 ISS_OP0_OP1_CRN_CRM_OP2(3, 3, 13, 2, 2)
@@ -118,7 +121,7 @@
#define ISS_MRS_MSR_AMCNTENSET0_EL0 ISS_OP0_OP1_CRN_CRM_OP2(3, 3, 13, 2, 5)
#define ISS_MRS_MSR_AMCNTENCLR1_EL0 ISS_OP0_OP1_CRN_CRM_OP2(3, 3, 13, 3, 0)
#define ISS_MRS_MSR_AMCNTENSET1_EL0 ISS_OP0_OP1_CRN_CRM_OP2(3, 3, 13, 3, 1)
-#if defined(ARCH_ARM_8_6_AMU)
+#if defined(ARCH_ARM_FEAT_AMUv1p1)
#define ISS_MRS_MSR_AMCG1IDR_EL0 ISS_OP0_OP1_CRN_CRM_OP2(3, 3, 13, 2, 6)
#endif
#endif
diff --git a/hyp/arch/aarch64/include/reg/registers_arm.inc b/hyp/arch/aarch64/include/reg/registers_arm.inc
new file mode 100644
index 0000000..6233a3d
--- /dev/null
+++ b/hyp/arch/aarch64/include/reg/registers_arm.inc
@@ -0,0 +1,13 @@
+// © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier; BSD-3-Clause
+
+#if defined(ARCH_ARM_FEAT_VHE)
+#define VHE(X) X##2 [X!]
+#define VHE_V(X, V) X##2 [V]
+#define VHE_T(X, T) X##2 [X!]
+#else
+#define VHE(X) X
+#define VHE_V(X, V) X [V]
+#define VHE_T(X, T) X
+#endif
diff --git a/hyp/arch/aarch64/link.lds b/hyp/arch/aarch64/link.lds
index da09d39..42d0f5a 100644
--- a/hyp/arch/aarch64/link.lds
+++ b/hyp/arch/aarch64/link.lds
@@ -32,6 +32,7 @@ SECTIONS
image_phys_start = LOADADDR(.text);
.text : AT (PLATFORM_LMA_BASE) {
*(.text.boot)
+ *(.text.boot.*)
*(SORT_BY_ALIGNMENT(.text .text.*))
KEEP(*(.text.debug));
} : text
@@ -61,7 +62,11 @@ SECTIONS
/* Package data for RootVM */
. = ALIGN(4096);
+#ifdef PLATFORM_ROOTVM_PKG_START_BASE
+ image_pkg_start = PLATFORM_ROOTVM_PKG_START_BASE;
+#else
image_pkg_start = . - image_virt_start + image_phys_start;
+#endif
/* align RW sections to the next 2MB page */
. = ALIGN(0x200000);
@@ -86,9 +91,12 @@ SECTIONS
#endif
. = ALIGN(64);
+#if PLATFORM_RW_DATA_SIZE < 0x200000
+#error PLATFORM_RW_DATA_SIZE too small
+#endif
.heap.root (NOLOAD) : {
heap_private_start = .;
- . = ALIGN(PLATFORM_HEAP_PRIVATE_SIZE);
+ . = data_base + PLATFORM_RW_DATA_SIZE;
heap_private_end = .;
} : NONE
image_virt_last = . - 1;
diff --git a/hyp/arch/aarch64/registers.reg b/hyp/arch/aarch64/registers.reg
index b353dfa..1425360 100644
--- a/hyp/arch/aarch64/registers.reg
+++ b/hyp/arch/aarch64/registers.reg
@@ -2,15 +2,7 @@
//
// SPDX-License-Identifier; BSD-3-Clause
-#if defined(ARCH_ARM_8_1_VHE)
-#define VHE(X) X##2 [X!]
-#define VHE_V(X, V) X##2 [V]
-#define VHE_T(X, T) X##2 [X!]
-#else
-#define VHE(X) X
-#define VHE_V(X, V) X [V]
-#define VHE_T(X, T) X
-#endif
+#include
ACTLR_EL1
ACTLR_EL2
@@ -25,7 +17,7 @@ CCSIDR_EL1 R
CCSIDR2_EL1 R
CLIDR_EL1 r
CNTFRQ_EL0
-#if defined(ARCH_ARM_8_1_VHE)
+#if defined(ARCH_ARM_FEAT_VHE)
CNTHCTL_EL2 [E2H0 E2H1]
#else
CNTHCTL_EL2 [E2H0]
@@ -56,13 +48,16 @@ VHE_T(CNTV_CVAL_EL0, CNT_CVAL!) oOrwR
VHE_T(CNTV_TVAL_EL0, CNT_TVAL!)
CNTVCT_EL0 R
+#if defined(ARCH_ARM_FEAT_ECV)
+CNTPOFF_EL2
+#endif
CNTVOFF_EL2
VHE(CONTEXTIDR_EL1)
-#if defined(ARCH_ARM_8_1_VHE)
+#if defined(ARCH_ARM_FEAT_VHE)
CONTEXTIDR_EL2
#endif
VHE(CPACR_EL1)
-#if defined(ARCH_ARM_8_1_VHE)
+#if defined(ARCH_ARM_FEAT_VHE)
CPTR_EL2 [E2H0 E2H1] oOrw
#else
CPTR_EL2 [E2H0] oOrw
@@ -81,7 +76,7 @@ VHE(ELR_EL1)
//ELR_EL2
//SPSR_EL2 [A32 A64]
-#if (defined(ARCH_ARM_8_2_RAS) || defined(ARCH_ARM_8_4_RAS))
+#if (defined(ARCH_ARM_FEAT_RAS) || defined(ARCH_ARM_FEAT_RASv1p1))
//ERRIDR_EL1 r
ERRSELR_EL1 Orw
//ERXADDR_EL1
@@ -112,8 +107,9 @@ HSTR_EL2
//ID_AA64AFR1_EL1 r
ID_AA64DFR0_EL1 r
//ID_AA64DFR1_EL1 r
-//ID_AA64ISAR0_EL1 r
+ID_AA64ISAR0_EL1 r
ID_AA64ISAR1_EL1 r
+ID_AA64ISAR2_EL1 r
ID_AA64MMFR0_EL1 r
ID_AA64MMFR1_EL1 r
ID_AA64MMFR2_EL1 r
@@ -246,7 +242,7 @@ PMCR_EL0 oOrw
//PMXEVTYPER_EL0
//REVIDR_EL1 r
VHE(SCTLR_EL1)
-#if defined(ARCH_ARM_8_1_VHE)
+#if defined(ARCH_ARM_FEAT_VHE)
SCTLR_EL2 [VM E2H_TGE]
#else
SCTLR_EL2 [VM]
@@ -258,7 +254,7 @@ SP_EL2
SPSel
VHE_V(SPSR_EL1, SPSR_EL1_A64!)
VHE(TCR_EL1)
-#if defined(ARCH_ARM_8_1_VHE)
+#if defined(ARCH_ARM_FEAT_VHE)
TCR_EL2 [E2H0 E2H1] rwW
#else
TCR_EL2 [E2H0] rwW
@@ -267,7 +263,7 @@ TPIDR_EL0
TPIDR_EL1
TPIDR_EL2
TPIDRRO_EL0
-#if defined(ARCH_ARM_8_4_TRACE)
+#if defined(ARCH_ARM_FEAT_TRF)
VHE(TRFCR_EL1) Orw
#endif
VHE(TTBR0_EL1)
@@ -285,7 +281,7 @@ VSESR_EL2 w
//VSTCR_EL2
//VSTTBR_EL2
VTCR_EL2
-VTTBR_EL2
+VTTBR_EL2 oOrw
//VHE(ZCR_EL1)
//ZCR_EL2
@@ -335,7 +331,7 @@ ICH_VMCR_EL2 oOrw
ICH_VTR_EL2 r
#endif
-#if defined(ARCH_ARM_8_3_PAUTH)
+#if defined(ARCH_ARM_FEAT_PAuth)
APDAKeyHi_EL1 rw
APDAKeyLo_EL1 rw
APDBKeyHi_EL1 rw
@@ -348,7 +344,7 @@ APGAKeyHi_EL1 rw
APGAKeyLo_EL1 rw
#endif
-#if defined(ARCH_ARM_8_5_MEMTAG) && defined(INTERFACE_VCPU)
+#if defined(ARCH_ARM_FEAT_MTE) && defined(INTERFACE_VCPU)
GCR_EL1 rw
RGSR_EL1 rw
VHE(TFSR_EL1) rw
@@ -395,7 +391,9 @@ DBGCLAIMSET_EL1 Ow
//DBGDTRRX_EL0 Or
//DBGDTRTX_EL0 Ow
//DBGPRCR_EL1
-//DBGVCR32_EL2
+#if ARCH_AARCH64_32BIT_EL1
+DBGVCR32_EL2 Orw
+#endif
DBGWCR0_EL1 Orw
DBGWCR1_EL1 Orw
DBGWCR2_EL1 Orw
@@ -442,12 +440,189 @@ OSLSR_EL1 Or
//SDER32_EL2
#endif
-#if defined(ARCH_ARM_8_5_RNG)
+#if defined(ARCH_ARM_FEAT_TRF)
+TRFCR_EL2 Orw
+#endif
+
+#if defined(MODULE_PLATFORM_ETE)
+TRCLAR Orw
+TRCIDR0 r
+TRCIDR2 r
+TRCIDR3 r
+TRCIDR4 r
+TRCIDR5 r
+TRCSTATR Orw
+TRCPRGCTLR Orw
+TRCCONFIGR Orw
+TRCAUXCTLR Orw
+TRCEVENTCTL0R Orw
+TRCEVENTCTL1R Orw
+TRCRSR Orw
+TRCSTALLCTLR Orw
+TRCTSCTLR Orw
+TRCSYNCPR Orw
+TRCCCCTLR Orw
+TRCBBCTLR Orw
+TRCTRACEIDR Orw
+TRCQCTLR Orw
+TRCVICTLR Orw
+TRCVIIECTLR Orw
+TRCVISSCTLR Orw
+TRCVIPCSSCTLR Orw
+TRCSEQEVR0 Orw
+TRCSEQEVR1 Orw
+TRCSEQEVR2 Orw
+TRCSEQRSTEVR Orw
+TRCSEQSTR Orw
+TRCEXTINSELR0 Orw
+TRCEXTINSELR1 Orw
+TRCEXTINSELR2 Orw
+TRCEXTINSELR3 Orw
+TRCCNTRLDVR0 Orw
+TRCCNTRLDVR1 Orw
+TRCCNTRLDVR2 Orw
+TRCCNTRLDVR3 Orw
+TRCCNTCTLR0 Orw
+TRCCNTCTLR1 Orw
+TRCCNTCTLR2 Orw
+TRCCNTCTLR3 Orw
+TRCCNTVR0 Orw
+TRCCNTVR1 Orw
+TRCCNTVR2 Orw
+TRCCNTVR3 Orw
+TRCIMSPEC1 Orw
+TRCIMSPEC2 Orw
+TRCIMSPEC3 Orw
+TRCIMSPEC4 Orw
+TRCIMSPEC5 Orw
+TRCIMSPEC6 Orw
+TRCIMSPEC7 Orw
+TRCRSCTLR2 Orw
+TRCRSCTLR3 Orw
+TRCRSCTLR4 Orw
+TRCRSCTLR5 Orw
+TRCRSCTLR6 Orw
+TRCRSCTLR7 Orw
+TRCRSCTLR8 Orw
+TRCRSCTLR9 Orw
+TRCRSCTLR10 Orw
+TRCRSCTLR11 Orw
+TRCRSCTLR12 Orw
+TRCRSCTLR13 Orw
+TRCRSCTLR14 Orw
+TRCRSCTLR15 Orw
+TRCRSCTLR16 Orw
+TRCRSCTLR17 Orw
+TRCRSCTLR18 Orw
+TRCRSCTLR19 Orw
+TRCRSCTLR20 Orw
+TRCRSCTLR21 Orw
+TRCRSCTLR22 Orw
+TRCRSCTLR23 Orw
+TRCRSCTLR24 Orw
+TRCRSCTLR25 Orw
+TRCRSCTLR26 Orw
+TRCRSCTLR27 Orw
+TRCRSCTLR28 Orw
+TRCRSCTLR29 Orw
+TRCRSCTLR30 Orw
+TRCRSCTLR31 Orw
+TRCSSCCR0 Orw
+TRCSSCCR1 Orw
+TRCSSCCR2 Orw
+TRCSSCCR3 Orw
+TRCSSCCR4 Orw
+TRCSSCCR5 Orw
+TRCSSCCR6 Orw
+TRCSSCCR7 Orw
+TRCSSCSR0 Orw
+TRCSSCSR1 Orw
+TRCSSCSR2 Orw
+TRCSSCSR3 Orw
+TRCSSCSR4 Orw
+TRCSSCSR5 Orw
+TRCSSCSR6 Orw
+TRCSSCSR7 Orw
+TRCSSPCICR0 Orw
+TRCSSPCICR1 Orw
+TRCSSPCICR2 Orw
+TRCSSPCICR3 Orw
+TRCSSPCICR4 Orw
+TRCSSPCICR5 Orw
+TRCSSPCICR6 Orw
+TRCSSPCICR7 Orw
+TRCACVR0 Orw
+TRCACVR1 Orw
+TRCACVR2 Orw
+TRCACVR3 Orw
+TRCACVR4 Orw
+TRCACVR5 Orw
+TRCACVR6 Orw
+TRCACVR7 Orw
+TRCACVR8 Orw
+TRCACVR9 Orw
+TRCACVR10 Orw
+TRCACVR11 Orw
+TRCACVR12 Orw
+TRCACVR13 Orw
+TRCACVR14 Orw
+TRCACVR15 Orw
+TRCACATR0 Orw
+TRCACATR1 Orw
+TRCACATR2 Orw
+TRCACATR3 Orw
+TRCACATR4 Orw
+TRCACATR5 Orw
+TRCACATR6 Orw
+TRCACATR7 Orw
+TRCACATR8 Orw
+TRCACATR9 Orw
+TRCACATR10 Orw
+TRCACATR11 Orw
+TRCACATR12 Orw
+TRCACATR13 Orw
+TRCACATR14 Orw
+TRCACATR15 Orw
+TRCCIDCVR0 Orw
+TRCCIDCVR1 Orw
+TRCCIDCVR2 Orw
+TRCCIDCVR3 Orw
+TRCCIDCVR4 Orw
+TRCCIDCVR5 Orw
+TRCCIDCVR6 Orw
+TRCCIDCVR7 Orw
+TRCVMIDCVR0 Orw
+TRCVMIDCVR1 Orw
+TRCVMIDCVR2 Orw
+TRCVMIDCVR3 Orw
+TRCVMIDCVR4 Orw
+TRCVMIDCVR5 Orw
+TRCVMIDCVR6 Orw
+TRCVMIDCVR7 Orw
+TRCCIDCCTLR0 Orw
+TRCCIDCCTLR1 Orw
+TRCVMIDCCTLR0 Orw
+TRCVMIDCCTLR1 Orw
+
+TRCCLAIMCLR Orw
+TRCCLAIMSET Orw
+#endif
+
+#if defined(MODULE_PLATFORM_TBRE)
+TRBLIMITR_EL1 Orw
+TRBPTR_EL1 Orw
+TRBBASER_EL1 Orw
+TRBSR_EL1 Orw
+TRBMAR_EL1 Orw
+TRBTRG_EL1 Orw
+#endif
+
+#if defined(ARCH_ARM_FEAT_RNG)
RNDR O
RNDRRS O
#endif
-#if defined(ARCH_ARM_8_4_AMU) || defined(ARCH_ARM_8_6_AMU)
+#if defined(ARCH_ARM_FEAT_AMUv1) || defined(ARCH_ARM_FEAT_AMUv1p1)
AMCR_EL0 r
AMCFGR_EL0 r
AMCGCR_EL0 r
@@ -456,7 +631,7 @@ AMCNTENCLR1_EL0 r
AMCNTENSET0_EL0 r
AMCNTENSET1_EL0 r
AMUSERENR_EL0
-#if defined(ARCH_ARM_8_6_AMU)
+#if defined(ARCH_ARM_FEAT_AMUv1p1)
AMCG1IDR_EL0 r
#endif
#endif
@@ -464,3 +639,10 @@ AMCG1IDR_EL0 r
#if defined(MODULE_PLATFORM_ARM_DSU) && defined(INTERFACE_VCPU)
S3_0_C15_C3_1 [IMP_CLUSTERIDR_EL1!] Or
#endif
+
+#if defined(ARCH_ARM_FEAT_CSV2_2) || defined(ARCH_ARM_FEAT_CSV2_1p2) || \
+ defined(ARCH_ARM_FEAT_CSV2_3)
+SCXTNUM_EL0
+SCXTNUM_EL1
+SCXTNUM_EL2
+#endif
diff --git a/hyp/arch/aarch64/src/asm_ordering.c b/hyp/arch/aarch64/src/asm_ordering.c
index c8b5198..03f2149 100644
--- a/hyp/arch/aarch64/src/asm_ordering.c
+++ b/hyp/arch/aarch64/src/asm_ordering.c
@@ -6,4 +6,4 @@
#include
-struct asm_ordering_dummy asm_ordering;
+asm_ordering_dummy_t asm_ordering;
diff --git a/hyp/arch/aarch64/src/nospec_checks.c b/hyp/arch/aarch64/src/nospec_checks.c
index 4a4aa6b..176fab3 100644
--- a/hyp/arch/aarch64/src/nospec_checks.c
+++ b/hyp/arch/aarch64/src/nospec_checks.c
@@ -16,8 +16,9 @@ nospec_range_check(index_t val, index_t limit)
"cset %w[valid], lo;"
"csel %w[result_r], %w[val], wzr, lo;"
"csdb;"
- : [valid] "=r"(valid), [result_r] "=r"(result.r)
- : [val] "r"(val), [limit] "r"(limit));
+ : [valid] "=&r"(valid), [result_r] "=r"(result.r)
+ : [val] "r"(val), [limit] "r"(limit)
+ : "cc");
if (valid) {
result.e = OK;
diff --git a/hyp/arch/aarch64/registers.tmpl b/hyp/arch/aarch64/templates/hypregisters.h.tmpl
similarity index 96%
rename from hyp/arch/aarch64/registers.tmpl
rename to hyp/arch/aarch64/templates/hypregisters.h.tmpl
index 450d940..90a664e 100644
--- a/hyp/arch/aarch64/registers.tmpl
+++ b/hyp/arch/aarch64/templates/hypregisters.h.tmpl
@@ -34,7 +34,7 @@ ${t}_raw(${v})#slurp
static inline ${vt}_t
register_${vn}_read${suffix}(
#if ordered
-struct asm_ordering_dummy *ordering_var
+asm_ordering_dummy_t *ordering_var
#else
void
#end if
@@ -67,7 +67,7 @@ void
static inline void
register_${vn}_write${suffix}(const ${vt}_t val
#if ordered
-, struct asm_ordering_dummy *ordering_var
+, asm_ordering_dummy_t *ordering_var
#end if
)
{
diff --git a/hyp/arch/aarch64/types.tc b/hyp/arch/aarch64/types.tc
index 4e0952f..82af192 100644
--- a/hyp/arch/aarch64/types.tc
+++ b/hyp/arch/aarch64/types.tc
@@ -6,16 +6,16 @@ define asm_ordering_dummy structure {
dummy char;
};
-define AARCH64_INST_EXCEPTION_VAL constant = 0xd4000000;
-define AARCH64_INST_EXCEPTION_MASK constant = 0xff000000;
+define AARCH64_INST_EXCEPTION_VAL constant uint32 = 0xd4000000;
+define AARCH64_INST_EXCEPTION_MASK constant uint32 = 0xff000000;
-define AARCH64_INST_EXCEPTION_IMM16_MASK constant = 0x001fffe0;
+define AARCH64_INST_EXCEPTION_IMM16_MASK constant uint32 = 0x001fffe0;
define AARCH64_INST_EXCEPTION_IMM16_SHIFT constant = 5;
-define AARCH64_INST_EXCEPTION_SUBTYPE_HLT_VAL constant = 0x00400000;
-define AARCH64_INST_EXCEPTION_SUBTYPE_MASK constant = 0x00e0001f;
+define AARCH64_INST_EXCEPTION_SUBTYPE_HLT_VAL constant uint32 = 0x00400000;
+define AARCH64_INST_EXCEPTION_SUBTYPE_MASK constant uint32 = 0x00e0001f;
-#if defined(ARCH_ARM_8_3_PAUTH)
+#if defined(ARCH_ARM_FEAT_PAuth)
define aarch64_pauth_key structure(aligned(16)) {
lo uint64;
hi uint64;
@@ -28,4 +28,4 @@ define aarch64_pauth_keys structure(aligned(16)) {
ib structure aarch64_pauth_key;
ga structure aarch64_pauth_key;
};
-#endif // defined(ARCH_ARM_8_3_PAUTH)
+#endif // defined(ARCH_ARM_FEAT_PAuth)
diff --git a/hyp/arch/armv8/include/asm/cache.h b/hyp/arch/armv8/include/asm/cache.h
index 25a7fe2..0744532 100644
--- a/hyp/arch/armv8/include/asm/cache.h
+++ b/hyp/arch/armv8/include/asm/cache.h
@@ -2,40 +2,43 @@
//
// SPDX-License-Identifier: BSD-3-Clause
-#define CACHE_DO_OP(x, size, op, is_object) \
+#define CACHE_BARRIER_OBJECT_LOAD(x, order) \
+ __asm__ volatile("" : "=r"(order) : "m"(*(x)))
+#define CACHE_BARRIER_OBJECT_STORE(x, order) \
+ __asm__ volatile("" : "+r"(order), "+m"(*(x)))
+#define CACHE_BARRIER_MEMORY_LOAD(x, order) \
+ __asm__ volatile("" : "=r"(order) : : "memory")
+#define CACHE_BARRIER_MEMORY_STORE(x, order) \
+ __asm__ volatile("" : "+r"(order) : : "memory")
+
+#define CACHE_DO_OP(x, size, op, CACHE_BARRIER) \
do { \
- size_t _line_size = 1U << CPU_L1D_LINE_BITS; \
+ const size_t line_size_ = 1U << CPU_L1D_LINE_BITS; \
\
- uintptr_t _base = \
- util_balign_down((uintptr_t)(x), _line_size); \
- uintptr_t _end = (uintptr_t)(x) + (size); \
+ uintptr_t line_base_ = \
+ util_balign_down((uintptr_t)(x), line_size_); \
+ uintptr_t end_ = (uintptr_t)(x) + (size); \
register_t ordering; \
\
- assert(!util_add_overflows((uintptr_t)x, (size)-1)); \
+ assert(!util_add_overflows((uintptr_t)x, (size)-1U)); \
\
- if (is_object) { \
- __asm__ volatile("" : "=r"(ordering) : "m"(*(x))); \
- } else { \
- __asm__ volatile("" : "=r"(ordering) : : "memory"); \
- } \
+ CACHE_BARRIER##_LOAD(x, ordering); \
\
do { \
__asm__ volatile("DC " #op ", %1" \
: "+r"(ordering) \
- : "r"(_base)); \
- _base = _base + _line_size; \
- } while (_base < _end); \
+ : "r"(line_base_)); \
+ line_base_ = line_base_ + line_size_; \
+ } while (line_base_ < end_); \
\
__asm__ volatile("dsb ish" : "+r"(ordering)); \
- if (is_object) { \
- __asm__ volatile("" : "+r"(ordering), "+m"(*(x))); \
- } else { \
- __asm__ volatile("" : "+r"(ordering) : : "memory"); \
- } \
+ CACHE_BARRIER##_STORE(x, ordering); \
} while (0)
-#define CACHE_OP_RANGE(x, size, op) CACHE_DO_OP(x, size, op, false)
-#define CACHE_OP_OBJECT(x, op) CACHE_DO_OP(&(x), sizeof(x), op, true)
+#define CACHE_OP_RANGE(x, size, op) \
+ CACHE_DO_OP(x, size, op, CACHE_BARRIER_MEMORY)
+#define CACHE_OP_OBJECT(x, op) \
+ CACHE_DO_OP(&(x), sizeof(x), op, CACHE_BARRIER_OBJECT)
#define CACHE_CLEAN_RANGE(x, size) CACHE_OP_RANGE(x, size, CVAC)
#define CACHE_INVALIDATE_RANGE(x, size) CACHE_OP_RANGE(x, size, IVAC)
@@ -49,8 +52,8 @@
do { \
struct { \
char p[size]; \
- } *_x = (void *)x; \
- CACHE_OP_OBJECT(*_x, op); \
+ } *x_ = (void *)x; \
+ CACHE_OP_OBJECT(*x_, op); \
} while (0)
#define CACHE_CLEAN_FIXED_RANGE(x, size) CACHE_OP_FIXED_RANGE(x, size, CVAC)
diff --git a/hyp/arch/build.conf b/hyp/arch/build.conf
index bc25161..3461f5b 100644
--- a/hyp/arch/build.conf
+++ b/hyp/arch/build.conf
@@ -2,7 +2,12 @@
#
# SPDX-License-Identifier: BSD-3-Clause
-arch_source aarch64 timestamp.c asm_ordering.c nospec_checks.c
arch_types aarch64 types.tc
+arch_template registers aarch64 hypregisters.h
+arch_registers aarch64 registers.reg
+
+arch_source aarch64 timestamp.c asm_ordering.c nospec_checks.c
arch_source cortex-a-v8_2 sysreg_init.c
arch_events cortex-a-v8_2 sysreg_init.ev
+arch_source cortex-a-v9 sysreg_init.c
+arch_events cortex-a-v9 sysreg_init.ev
diff --git a/hyp/arch/cortex-a-v8_0/include/asm/cpu.h b/hyp/arch/cortex-a-v8_0/include/asm/cpu.h
new file mode 100644
index 0000000..7bde800
--- /dev/null
+++ b/hyp/arch/cortex-a-v8_0/include/asm/cpu.h
@@ -0,0 +1,17 @@
+// © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Miscellaneous definitions describing the CPU implementation.
+
+// The size in address bits of a line in the innermost visible data cache.
+#define CPU_L1D_LINE_BITS 6U
+
+// The size in address bits of the CPU's DC ZVA block. This is nearly always
+// the same as CPU_L1D_LINE_BITS.
+#define CPU_DCZVA_BITS 6U
+
+// The largest difference between the source and destination pointers during
+// the optimised memcpy() for this CPU. This is here because it might depend
+// on CPU_L1D_LINE_BITS in some implementations.
+#define CPU_MEMCPY_STRIDE 256U
diff --git a/hyp/arch/cortex-a-v8_0/include/asm/system_registers_cpu.h b/hyp/arch/cortex-a-v8_0/include/asm/system_registers_cpu.h
new file mode 100644
index 0000000..c12bd69
--- /dev/null
+++ b/hyp/arch/cortex-a-v8_0/include/asm/system_registers_cpu.h
@@ -0,0 +1,11 @@
+// © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+// AArch64 System Register Encoding (CPU Implementation Defined Registers)
+//
+// This list is not exhaustive, it contains mostly registers likely to be
+// trapped and accessed indirectly.
+
+#define ISS_MRS_MSR_CPUACTLR_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 1, 15, 2, 0)
+#define ISS_MRS_MSR_CPUECTLR_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 1, 15, 2, 1)
diff --git a/hyp/arch/cortex-a-v8_0/src/sysreg_init.c b/hyp/arch/cortex-a-v8_0/src/sysreg_init.c
new file mode 100644
index 0000000..2bd9d78
--- /dev/null
+++ b/hyp/arch/cortex-a-v8_0/src/sysreg_init.c
@@ -0,0 +1,20 @@
+// © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include
+
+#include
+
+#include "event_handlers.h"
+
+void
+arch_cortex_a_v80_handle_boot_cpu_warm_init(void)
+{
+ // ACTLR_EL2 controls EL1 access to some important features such as
+ // CLUSTERPMU and power control registers, which can be exploited to
+ // perform security/DoS attacks. Therefore, we deny all these accesses
+ // by writing 0 to this register.
+ ACTLR_EL2_t val = ACTLR_EL2_default();
+ register_ACTLR_EL2_write(val);
+}
diff --git a/hyp/arch/cortex-a-v8_0/sysreg_init.ev b/hyp/arch/cortex-a-v8_0/sysreg_init.ev
new file mode 100644
index 0000000..5f3db9b
--- /dev/null
+++ b/hyp/arch/cortex-a-v8_0/sysreg_init.ev
@@ -0,0 +1,8 @@
+// © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+module arch
+
+subscribe boot_cpu_warm_init
+ handler arch_cortex_a_v80_handle_boot_cpu_warm_init
diff --git a/hyp/arch/cortex-a-v9/include/asm/cpu.h b/hyp/arch/cortex-a-v9/include/asm/cpu.h
new file mode 100644
index 0000000..7bde800
--- /dev/null
+++ b/hyp/arch/cortex-a-v9/include/asm/cpu.h
@@ -0,0 +1,17 @@
+// © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Miscellaneous definitions describing the CPU implementation.
+
+// The size in address bits of a line in the innermost visible data cache.
+#define CPU_L1D_LINE_BITS 6U
+
+// The size in address bits of the CPU's DC ZVA block. This is nearly always
+// the same as CPU_L1D_LINE_BITS.
+#define CPU_DCZVA_BITS 6U
+
+// The largest difference between the source and destination pointers during
+// the optimised memcpy() for this CPU. This is here because it might depend
+// on CPU_L1D_LINE_BITS in some implementations.
+#define CPU_MEMCPY_STRIDE 256U
diff --git a/hyp/arch/cortex-a-v9/include/asm/system_registers_cpu.h b/hyp/arch/cortex-a-v9/include/asm/system_registers_cpu.h
new file mode 100644
index 0000000..332aa23
--- /dev/null
+++ b/hyp/arch/cortex-a-v9/include/asm/system_registers_cpu.h
@@ -0,0 +1,13 @@
+// © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+// AArch64 System Register Encoding (CPU Implementation Defined Registers)
+//
+// This list is not exhaustive, it contains mostly registers likely to be
+// trapped and accessed indirectly.
+
+#define ISS_MRS_MSR_CPUACTLR_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 15, 1, 0)
+#define ISS_MRS_MSR_A7X_CPUACTLR2_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 15, 1, 1)
+#define ISS_MRS_MSR_CPUECTLR_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 15, 1, 4)
+#define ISS_MRS_MSR_CPUPWRCTLR_EL1 ISS_OP0_OP1_CRN_CRM_OP2(3, 0, 15, 2, 7)
diff --git a/hyp/arch/cortex-a-v9/src/sysreg_init.c b/hyp/arch/cortex-a-v9/src/sysreg_init.c
new file mode 100644
index 0000000..d7364d2
--- /dev/null
+++ b/hyp/arch/cortex-a-v9/src/sysreg_init.c
@@ -0,0 +1,20 @@
+// © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include
+
+#include
+
+#include "event_handlers.h"
+
+void
+arch_cortex_a_v9_handle_boot_cpu_warm_init(void)
+{
+ // ACTLR_EL2 controls EL1 access to some important features such as
+ // CLUSTERPMU and power control registers, which can be exploited to
+ // perform security/DoS attacks. Therefore, we deny all these accesses
+ // by writing 0 to this register.
+ ACTLR_EL2_t val = ACTLR_EL2_default();
+ register_ACTLR_EL2_write(val);
+}
diff --git a/hyp/arch/cortex-a-v9/sysreg_init.ev b/hyp/arch/cortex-a-v9/sysreg_init.ev
new file mode 100644
index 0000000..009544b
--- /dev/null
+++ b/hyp/arch/cortex-a-v9/sysreg_init.ev
@@ -0,0 +1,8 @@
+// © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+module arch
+
+subscribe boot_cpu_warm_init
+ handler arch_cortex_a_v9_handle_boot_cpu_warm_init
diff --git a/hyp/arch/qemu-armv8-5a-rng/include/asm/cpu.h b/hyp/arch/qemu-armv8-5a-rng/include/asm/cpu.h
new file mode 100644
index 0000000..f17f918
--- /dev/null
+++ b/hyp/arch/qemu-armv8-5a-rng/include/asm/cpu.h
@@ -0,0 +1,17 @@
+// © 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Miscellaneous definitions describing the CPU implementation.
+
+// The size in address bits of a line in the innermost visible data cache.
+#define CPU_L1D_LINE_BITS 6U
+
+// The size in address bits of the CPU's DC ZVA block. This is nearly always
+// the same as CPU_L1D_LINE_BITS.
+#define CPU_DCZVA_BITS 6U
+
+// The largest difference between the source and destination pointers during
+// the optimised memcpy() for this CPU. This is here because it might depend
+// on CPU_L1D_LINE_BITS in some implementations.
+#define CPU_MEMCPY_STRIDE 256U
diff --git a/hyp/core/api/aarch64/templates/c_wrapper.c.tmpl b/hyp/core/api/aarch64/templates/c_wrapper.c.tmpl
index fef2f20..1b420f4 100644
--- a/hyp/core/api/aarch64/templates/c_wrapper.c.tmpl
+++ b/hyp/core/api/aarch64/templates/c_wrapper.c.tmpl
@@ -35,17 +35,17 @@
#def trace_out(hypcall_num, hypcall)
#set trace_fmt = $hypcall.name + " ret:"
- #for i, input in $hypcall.outputs[:4]
+ #for i, input in $hypcall.outputs[:5]
#if not $input.ignore
#set trace_fmt = trace_fmt + " {:#x}"
#end if
#end for
TRACE(USER, HYPERCALL, "${trace_fmt}"
#if len($hypcall.outputs) == 1
- , (register_t)_ret
+ , (register_t)ret_
#else
- #for i, output in $hypcall.outputs[:4]
- , (register_t)_ret.$register_expr($output)
+ #for i, output in $hypcall.outputs[:5]
+ , (register_t)ret_.$register_expr($output)
#end for
#end if
);
@@ -71,7 +71,7 @@ ${type_signature($hypcall, suffix=$wrapper_suffix, ignored_inputs=True)}
${type_signature($hypcall, suffix=$wrapper_suffix, ignored_inputs=True)} {
#if $hypcall.outputs
- $return_type($hypcall) _ret;
+ $return_type($hypcall) ret_;
#end if
trigger_thread_entry_from_user_event(THREAD_ENTRY_REASON_HYPERCALL);
@@ -97,9 +97,9 @@ ${type_signature($hypcall, suffix=$wrapper_suffix, ignored_inputs=True)} {
#set has_ignores = True
if (compiler_unexpected(${input.name} != (${input.ctype})${input.default}U)) {
#if len($hypcall.outputs) == 1
- _ret = ERROR_ARGUMENT_INVALID;
+ ret_ = ERROR_ARGUMENT_INVALID;
#else
- _ret = ($return_type($hypcall)){ .${error_ret.name} = ERROR_ARGUMENT_INVALID };
+ ret_ = ($return_type($hypcall)){ .${error_ret.name} = ERROR_ARGUMENT_INVALID };
#end if
goto out;
}
@@ -116,7 +116,7 @@ ${type_signature($hypcall, suffix=$wrapper_suffix, ignored_inputs=True)} {
## call the implementation
#if $hypcall.outputs
- _ret =
+ ret_ =
#end if
$prefix${hypcall.name}(#slurp
#set sep=''
@@ -140,7 +140,7 @@ out:
## return the result, if any
#if $hypcall.outputs
- return _ret;
+ return ret_;
#else
#if has_ignores:
return;
diff --git a/hyp/core/api/aarch64/templates/hypcall_table.S.tmpl b/hyp/core/api/aarch64/templates/hypcall_table.S.tmpl
index 44bcd16..245b627 100644
--- a/hyp/core/api/aarch64/templates/hypcall_table.S.tmpl
+++ b/hyp/core/api/aarch64/templates/hypcall_table.S.tmpl
@@ -10,7 +10,7 @@
\#include
\#include
-\#if defined(ARCH_ARM_8_5_BTI)
+\#if defined(ARCH_ARM_FEAT_BTI)
#define BTI_J bti j
#define BTI_NOP nop
#define HYPERCALL_ALIGN 0x10
diff --git a/hyp/core/api/api.tc b/hyp/core/api/api.tc
index 9f12e66..04b59ef 100644
--- a/hyp/core/api/api.tc
+++ b/hyp/core/api/api.tc
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: BSD-3-Clause
extend trace_class enumeration {
- USER;
+ USER = 2;
};
extend trace_id enumeration {
diff --git a/hyp/core/base/aarch64/enums.tc b/hyp/core/base/aarch64/enums.tc
index 760b5b8..b04c96c 100644
--- a/hyp/core/base/aarch64/enums.tc
+++ b/hyp/core/base/aarch64/enums.tc
@@ -22,30 +22,59 @@ extend esr_ec enumeration {
BRK = 0x3c;
};
-#if defined(ARCH_ARM_8_3_PAUTH)
+#if defined(ARCH_ARM_FEAT_PAuth)
extend esr_ec enumeration {
PAUTH = 0x09;
-#if defined(ARCH_ARM_8_3_NV)
+#if defined(ARCH_ARM_FEAT_NV)
ERET = 0x1a;
#endif
-#if defined(ARCH_ARM_8_3_FPAC)
+#if defined(ARCH_ARM_FEAT_FPAC)
FPAC = 0x1c;
#endif
};
#endif
-#if defined(ARCH_ARM_8_5_BTI)
+#if defined(ARCH_ARM_FEAT_BTI)
extend esr_ec enumeration {
BTI = 0x0d;
};
#endif
-#if defined(ARCH_ARM_8_2_SVE)
+#if defined(ARCH_ARM_FEAT_SVE)
extend esr_ec enumeration {
SVE = 0x19;
};
#endif
+#if defined(ARCH_ARM_FEAT_LS64)
+extend esr_ec enumeration {
+ LD64B_ST64B = 0x0a;
+};
+#endif
+
+#if defined(ARCH_ARM_FEAT_TME)
+extend esr_ec enumeration {
+ TSTART = 0x1b;
+};
+#endif
+
+#if defined(ARCH_ARM_FEAT_SME)
+extend esr_ec enumeration {
+ SME = 0x1d;
+};
+#endif
+
+#if defined(ARCH_ARM_FEAT_RME)
+extend esr_ec enumeration {
+ RME = 0x1e;
+};
+#endif
+
+#if defined(ARCH_ARM_FEAT_MOPS)
+extend esr_ec enumeration {
+ MOPS = 0x27;
+};
+#endif
extend iss_da_ia_fsc enumeration {
TRANSLATION_0 = 0x04;
@@ -59,7 +88,7 @@ extend iss_da_ia_fsc enumeration {
PAGE_DOMAIN = 0x3e;
};
-#if defined(ARCH_ARM_8_1_TTHM)
+#if defined(ARCH_ARM_FEAT_HAFDBS)
extend iss_da_ia_fsc enumeration {
ATOMIC_HW_UPDATE = 0x31;
};
@@ -134,7 +163,7 @@ define tcr_ps enumeration {
SIZE_52BITS = 0b110;
};
-#ifdef ARCH_ARM_8_4_TLBI
+#ifdef ARCH_ARM_FEAT_TLBIRANGE
define tlbi_range_tg enumeration {
GRANULE_SIZE_4KB = 0b01;
GRANULE_SIZE_16KB = 0b10;
@@ -147,3 +176,10 @@ define cptr_zen enumeration {
trap_all = 0x02;
trap_none = 0x03;
};
+
+#if defined(ARCH_ARM_FEAT_WFxT)
+extend iss_wfx_ti enumeration {
+ WFIT = 0b10;
+ WFET = 0b11;
+};
+#endif
diff --git a/hyp/core/base/aarch64/src/core_id.c b/hyp/core/base/aarch64/src/core_id.c
new file mode 100644
index 0000000..5ab57b9
--- /dev/null
+++ b/hyp/core/base/aarch64/src/core_id.c
@@ -0,0 +1,119 @@
+// © 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// FIXME:
+#if !defined(MODULE_PLATFORM_SOC_QCOM)
+// Platforms may override this with their own implementation
+core_id_t WEAK
+platform_cpu_get_coreid(MIDR_EL1_t midr)
+{
+ (void)midr;
+ return CORE_ID_UNKNOWN;
+}
+#endif
+
+static core_id_t
+get_core_id(uint16_t partnum, uint8_t variant, uint8_t revision)
+{
+ static const coreid_info_t core_id_data[] = {
+ { .part_num = 0xD03, .core_ID = CORE_ID_CORTEX_A53 },
+ { .part_num = 0xD05, .core_ID = CORE_ID_CORTEX_A55 },
+ { .part_num = 0xD07, .core_ID = CORE_ID_CORTEX_A57 },
+ { .part_num = 0xD08, .core_ID = CORE_ID_CORTEX_A72 },
+ { .part_num = 0xD09, .core_ID = CORE_ID_CORTEX_A73 },
+ { .part_num = 0xD0A, .core_ID = CORE_ID_CORTEX_A75 },
+ { .part_num = 0xD0B, .core_ID = CORE_ID_CORTEX_A76 },
+ { .part_num = 0xD0C, .core_ID = CORE_ID_NEOVERSE_N1 },
+ { .part_num = 0xD0D, .core_ID = CORE_ID_CORTEX_A77 },
+ { .part_num = 0xD0E, .core_ID = CORE_ID_CORTEX_A76AE },
+ { .part_num = 0xD40, .core_ID = CORE_ID_NEOVERSE_V1 },
+ { .part_num = 0xD41, .core_ID = CORE_ID_CORTEX_A78 },
+ { .part_num = 0xD42, .core_ID = CORE_ID_CORTEX_A78AE },
+ { .part_num = 0xD44, .core_ID = CORE_ID_CORTEX_X1 },
+ { .part_num = 0xD46, .core_ID = CORE_ID_CORTEX_A510 },
+ { .part_num = 0xD47, .core_ID = CORE_ID_CORTEX_A710 },
+ { .part_num = 0xD48, .core_ID = CORE_ID_CORTEX_X2 },
+ { .part_num = 0xD49, .core_ID = CORE_ID_NEOVERSE_N2 },
+ { .part_num = 0xD4B, .core_ID = CORE_ID_CORTEX_A78C },
+ { .part_num = 0xD4D, .core_ID = CORE_ID_CORTEX_A715 },
+ { .part_num = 0xD4E, .core_ID = CORE_ID_CORTEX_X3 },
+ };
+
+ static const count_t NUM_CORE_ID =
+ (count_t)util_array_size(core_id_data);
+ core_id_t coreid = CORE_ID_UNKNOWN;
+
+ uint32_t start;
+
+ bool core_identified = false;
+
+ for (start = 0; ((start < NUM_CORE_ID) && (!core_identified));
+ start++) {
+ if (partnum == core_id_data[start].part_num) {
+ if ((partnum == 0xD81U) || (partnum == 0xD82U)) {
+ if ((variant == 0U) && (revision == 0U)) {
+ coreid = core_id_data[start].core_ID;
+ } else {
+ coreid = CORE_ID_UNKNOWN;
+ }
+ } else {
+ coreid = core_id_data[start].core_ID;
+ }
+ core_identified = true;
+ }
+ }
+
+ return coreid;
+}
+
+core_id_t
+get_current_core_id(void) REQUIRE_PREEMPT_DISABLED
+{
+ core_id_t coreid;
+
+ assert_cpulocal_safe();
+
+ MIDR_EL1_t midr = register_MIDR_EL1_read();
+
+ uint8_t implementer = MIDR_EL1_get_Implementer(&midr);
+ uint16_t partnum = MIDR_EL1_get_PartNum(&midr);
+ uint8_t variant = MIDR_EL1_get_Variant(&midr);
+ uint8_t revision = MIDR_EL1_get_Revision(&midr);
+
+ if ((char)implementer == 'A') {
+ coreid = get_core_id(partnum, variant, revision);
+ } else {
+ coreid = CORE_ID_UNKNOWN;
+ }
+
+ if (coreid == CORE_ID_UNKNOWN) {
+ coreid = platform_cpu_get_coreid(midr);
+ }
+
+#if defined(VERBOSE) && VERBOSE
+ if (coreid == CORE_ID_UNKNOWN) {
+ cpu_index_t cpu = cpulocal_get_index();
+
+ LOG(DEBUG, WARN,
+ "detected unknown core ID, cpu: {:d}, MIDR: {:#08x}", cpu,
+ MIDR_EL1_raw(midr));
+ }
+#endif
+
+ return coreid;
+}
diff --git a/hyp/core/base/aarch64/sysregs.tc b/hyp/core/base/aarch64/sysregs.tc
index b98e9be..a140996 100644
--- a/hyp/core/base/aarch64/sysregs.tc
+++ b/hyp/core/base/aarch64/sysregs.tc
@@ -49,7 +49,7 @@ define CCSIDR_EL1 bitfield<64> {
63:32 unknown=0;
};
-#if defined(ARCH_ARM_8_3_CCIDX)
+#if defined(ARCH_ARM_FEAT_CCIDX)
extend CCSIDR_EL1 bitfield {
delete Associativity;
23:3 Associativity uint32;
@@ -80,7 +80,7 @@ define CLIDR_EL1 bitfield<64> {
63:33 unknown=0;
};
-#if defined(ARCH_ARM_8_5_MEMTAG)
+#if defined(ARCH_ARM_FEAT_MTE)
extend CLIDR_EL1 bitfield {
34:33 Ttype1 uint8;
36:35 Ttype2 uint8;
@@ -106,7 +106,7 @@ define CNTHCTL_EL2_E2H0 bitfield<64> {
63:8 unknown=0;
};
-#if defined(ARCH_ARM_8_1_VHE)
+#if defined(ARCH_ARM_FEAT_VHE)
define CNTHCTL_EL2_E2H1 bitfield<64> {
0 EL0PCTEN bool;
1 EL0VCTEN bool;
@@ -121,6 +121,28 @@ define CNTHCTL_EL2_E2H1 bitfield<64> {
};
#endif
+#if defined(ARCH_ARM_FEAT_ECV)
+extend CNTHCTL_EL2_E2H0 bitfield {
+ 12 ECV bool;
+ 13 EL1TVT bool;
+ 14 EL1TVCT bool;
+ 15 EL1NVPCT bool;
+ 16 EL1NVVCT bool;
+ 17 EVNTIS bool;
+};
+
+#if defined(ARCH_ARM_FEAT_VHE)
+extend CNTHCTL_EL2_E2H1 bitfield {
+ 12 ECV bool;
+ 13 EL1TVT bool;
+ 14 EL1TVCT bool;
+ 15 EL1NVPCT bool;
+ 16 EL1NVVCT bool;
+ 17 EVNTIS bool;
+};
+#endif
+#endif
+
define CNT_CTL bitfield<64> {
0 ENABLE bool;
1 IMASK bool;
@@ -156,6 +178,12 @@ define CNTVCT_EL0 bitfield<64> {
63:0 CountValue uint64;
};
+#if defined(ARCH_ARM_FEAT_ECV)
+define CNTPOFF_EL2 bitfield<64> {
+ 63:0 PhysicalOffset uint64;
+};
+#endif
+
define CNTVOFF_EL2 bitfield<64> {
63:0 VirtualOffset uint64;
};
@@ -177,7 +205,7 @@ define CPACR_EL1 bitfield<64> {
63:29 unknown=0;
};
-#if defined(ARCH_ARM_8_2_SVE)
+#if defined(ARCH_ARM_FEAT_SVE)
extend CPACR_EL1 bitfield {
17:16 ZEN uint8;
};
@@ -198,7 +226,7 @@ define CPTR_EL2_E2H0 bitfield<64> {
63:32 unknown=0;
};
-#if defined(ARCH_ARM_8_1_VHE)
+#if defined(ARCH_ARM_FEAT_VHE)
define CPTR_EL2_E2H1 bitfield<64> {
15:0 unknown=0;
17:16 unknown=0;
@@ -213,19 +241,19 @@ define CPTR_EL2_E2H1 bitfield<64> {
};
#endif
-#if defined(ARCH_ARM_8_2_SVE)
+#if defined(ARCH_ARM_FEAT_SVE)
extend CPTR_EL2_E2H0 bitfield {
8 TZ bool;
};
#endif
-#if defined(ARCH_ARM_8_2_SVE)
+#if defined(ARCH_ARM_FEAT_SVE)
extend CPTR_EL2_E2H1 bitfield {
17:16 ZEN enumeration cptr_zen;
};
#endif
-#if defined(ARCH_ARM_8_4_AMU) || defined(ARCH_ARM_8_6_AMU)
+#if defined(ARCH_ARM_FEAT_AMUv1) || defined(ARCH_ARM_FEAT_AMUv1p1)
extend CPTR_EL2_E2H1 bitfield {
30 TAM bool;
};
@@ -240,7 +268,7 @@ define CSSELR_EL1 bitfield<64> {
63:4 unknown=0;
};
-#if defined(ARCH_ARM_8_5_MEMTAG)
+#if defined(ARCH_ARM_FEAT_MTE)
extend CSSELR_EL1 bitfield {
4 TnD bool;
};
@@ -260,7 +288,7 @@ define CTR_EL0 bitfield<64> {
63:32 unknown=0;
};
-#if defined(ARCH_ARM_8_5_MEMTAG)
+#if defined(ARCH_ARM_FEAT_MTE)
extend CTR_EL0 bitfield {
37:32 TminLine uint8;
};
@@ -320,7 +348,7 @@ define ELR_##el bitfield<64> { \
ELR(EL1)
ELR(EL2)
-#if defined(ARCH_ARM_8_2_RAS) || defined(ARCH_ARM_8_4_RAS)
+#if defined(ARCH_ARM_FEAT_RAS) || defined(ARCH_ARM_FEAT_RASv1p1)
define ERRSELR_EL1 bitfield<64> {
15:0 SEL uint16;
others unknown=0;
@@ -469,54 +497,66 @@ define HCR_EL2 bitfield<64> {
63:48 unknown=0;
};
-#if defined(ARCH_ARM_8_1_VHE)
+#if defined(ARCH_ARM_FEAT_VHE)
extend HCR_EL2 bitfield {
34 E2H bool;
35 TLOR bool;
};
#endif
-#if defined(ARCH_ARM_8_2_RAS) || defined(ARCH_ARM_8_4_RAS)
+#if defined(ARCH_ARM_FEAT_RAS) || defined(ARCH_ARM_FEAT_RASv1p1)
extend HCR_EL2 bitfield {
36 TERR bool;
37 TEA bool;
};
#endif
-#if defined(ARCH_ARM_8_3_PAUTH)
+#if defined(ARCH_ARM_FEAT_PAuth)
extend HCR_EL2 bitfield {
40 APK bool;
41 API bool;
};
#endif
-#if defined(ARCH_ARM_8_3_NV)
+#if defined(ARCH_ARM_FEAT_NV)
extend HCR_EL2 bitfield {
+ 42 NV bool;
+ 43 NV1 bool;
44 AT bool;
};
#endif
-#if defined(ARCH_ARM_8_4_NV)
+#if defined(ARCH_ARM_FEAT_NV2)
extend HCR_EL2 bitfield {
- 42 NV bool;
- 43 NV1 bool;
45 NV2 bool;
};
#endif
-#if defined(ARCH_ARM_8_4_S2FWB)
+#if defined(ARCH_ARM_FEAT_S2FWB)
extend HCR_EL2 bitfield {
46 FWB bool;
};
#endif
-#if defined(ARCH_ARM_8_4_RAS)
+#if defined(ARCH_ARM_FEAT_RASv1p1)
extend HCR_EL2 bitfield {
47 FIEN bool;
};
#endif
-#if defined(ARCH_ARM_8_5_MEMTAG)
+#if defined(ARCH_ARM_FEAT_CSV2_2) || defined(ARCH_ARM_FEAT_CSV2_1p2) || \
+ defined(ARCH_ARM_FEAT_CSV2_3)
+#if !defined(ARCH_ARM_FEAT_CSV2)
+#error ARCH_ARM_FEAT_CSV2 not defined
+#endif
+define ARCH_ARM_HAVE_SCXT constant bool = 1;
+
+extend HCR_EL2 bitfield {
+ 53 EnSCXT bool;
+};
+#endif
+
+#if defined(ARCH_ARM_FEAT_MTE)
extend HCR_EL2 bitfield {
56 ATA bool;
57 DCT bool;
@@ -532,14 +572,14 @@ define HPFAR_EL2 bitfield<64> {
63 unknown=0;
};
-#if defined(ARCH_ARM_8_2_LPA)
+#if defined(ARCH_ARM_FEAT_LPA)
extend HPFAR_EL2 bitfield {
delete FIPA;
43:4 FIPA uint64 lsl(12);
};
#endif
-#if defined(ARCH_ARM_8_4_SECEL2)
+#if defined(ARCH_ARM_FEAT_SEL2)
extend HPFAR_EL2 bitfield {
63 NS bool;
};
@@ -594,6 +634,8 @@ define ID_AA64MMFR0_EL1 bitfield<64> {
43:40 TGran4_2 uint8;
47:44 ExS uint8;
63:48 unknown=0;
+ 59:56 FGT uint8;
+ 63:60 ECV uint8;
};
define ID_AA64MMFR1_EL1 bitfield<64> {
@@ -605,7 +647,14 @@ define ID_AA64MMFR1_EL1 bitfield<64> {
23:20 PAN uint8;
27:24 SpecSEI uint8;
31:28 XNX uint8;
- 63:32 unknown=0;
+ 35:32 TWED uint8;
+ 39:36 ETS uint8;
+ 43:40 HCX uint8;
+ 47:44 AFP uint8;
+ 51:48 nTLBPA uint8;
+ 55:52 TIDCP1 uint8;
+ 59:56 CMOW uint8;
+ 63:60 ECBHB uint8;
};
define ID_AA64MMFR2_EL1 bitfield<64> {
@@ -641,7 +690,7 @@ define ID_AA64PFR0_EL1 bitfield<64> {
43:40 MPAM uint8;
47:44 AMU uint8;
51:48 DIT uint8;
- 55:52 unknown=0;
+ 55:52 RME uint8;
59:56 CSV2 uint8;
63:60 CSV3 uint8;
};
@@ -651,7 +700,12 @@ define ID_AA64PFR1_EL1 bitfield<64> {
7:4 SSBS uint8;
11:8 MTE uint8;
15:12 RAS_frac uint8;
- 63:16 unknown=0;
+ 19:16 MPAM_frac uint8;
+ 27:24 SME uint8;
+ 31:28 RNDR_trap uint8;
+ 35:32 CSV2_frac uint8;
+ 39:36 NMI uint8;
+ others unknown=0;
};
define ID_AA64ISAR0_EL1 bitfield<64> {
@@ -691,6 +745,18 @@ define ID_AA64ISAR1_EL1 bitfield<64> {
others unknown=0;
};
+define ID_AA64ISAR2_EL1 bitfield<64> {
+ 3:0 WFxT uint8;
+ 7:4 RPRES uint8;
+ 11:8 GPA3 uint8;
+ 15:12 APA3 uint8;
+ 19:16 MOPS uint8;
+ 23:20 BC uint8;
+ 27:24 PAC_frac uint8;
+ 31:28 CLRBHB uint8;
+ 63:32 unknown=0;
+};
+
define ID_DFR0_EL1 bitfield<64> {
3:0 CopDbg uint8;
7:4 CopSDbg uint8;
@@ -888,18 +954,20 @@ define MAIR_ATTR enumeration {
DEVICE_nGRE = 0x8;
DEVICE_GRE = 0xc;
+ DEVICE_nGnRnE_XS= 0x1;
+ DEVICE_nGnRE_XS = 0x5;
+ DEVICE_nGRE_XS = 0x9;
+ DEVICE_GRE_XS = 0xd;
+
NORMAL_NC = 0x44; // Inner+outer non-cacheable
NORMAL_WB_OUTER_NC = 0x4f; // Inner writeback RW alloc
-#if defined(ARCH_ARM_8_5_MEMTAG)
+#if defined(ARCH_ARM_FEAT_MTE)
TAGGED_NORMAL_WB = 0xf0; // Inner+outer writeback RW alloc, MT enabled
#endif
NORMAL_WB = 0xff; // Inner/outer writeback RW alloc
// Other combinations of types not enumerated
};
-// Bits valid for device types
-define MAIR_ATTR_DEVICE_MASK constant enumeration MAIR_ATTR = 0xc;
-
// Bits that indicate RW alloc hints for normal memory types (other than
// TAGGED_NORMAL_WB which is special)
define MAIR_ATTR_ALLOC_HINT_MASK constant enumeration MAIR_ATTR = 0x33;
@@ -939,20 +1007,20 @@ extend MDCR_EL2 bitfield {
};
#endif
-#if defined(ARCH_ARM_SPE)
+#if defined(ARCH_ARM_FEAT_SPEv1p1)
extend MDCR_EL2 bitfield {
13:12 E2PB uint8;
14 TPMS bool;
};
#endif
-#if defined(ARCH_ARM_8_1_PMU) || defined(ARCH_ARM_8_4_PMU)
+#if defined(ARCH_ARM_FEAT_PMUv3p1) || defined(ARCH_ARM_FEAT_PMUv3p4)
extend MDCR_EL2 bitfield {
17 HPMD bool;
};
#endif
-#if defined(ARCH_ARM_8_4_TRACE)
+#if defined(ARCH_ARM_FEAT_TRF)
extend MDCR_EL2 bitfield {
19 TTRF bool;
};
@@ -1018,7 +1086,7 @@ define PAR_EL1_F0 bitfield<64> {
63:56 ATTR enumeration MAIR_ATTR;
};
-#if defined(ARCH_ARM_8_2_LPA)
+#if defined(ARCH_ARM_FEAT_LPA)
extend PAR_EL1_F0 bitfield {
delete PA;
51:12 PA uint64 lsl(12);
@@ -1060,7 +1128,7 @@ define PMCR_EL0 bitfield<64> {
63:32 unknown=0;
};
-#if defined(ARCH_ARM_8_5_PMU)
+#if defined(ARCH_ARM_FEAT_PMUv3p5)
extend PMCR_EL0 bitfield {
7 LP bool;
};
@@ -1100,26 +1168,26 @@ define SCTLR_EL1 bitfield<64> {
63:32 unknown=0;
};
-#if defined(ARCH_ARM_8_1_PAN)
+#if defined(ARCH_ARM_FEAT_PAN)
extend SCTLR_EL1 bitfield {
23 SPAN bool;
};
#endif
-#if defined(ARCH_ARM_8_2_IESB)
+#if defined(ARCH_ARM_FEAT_IESB)
extend SCTLR_EL1 bitfield {
21 IESB bool;
};
#endif
-#if defined(ARCH_ARM_8_2_LSMAOC)
+#if defined(ARCH_ARM_FEAT_LSMAOC)
extend SCTLR_EL1 bitfield {
28 nTLSMD bool;
29 LSMAOE bool;
};
#endif
-#if defined(ARCH_ARM_8_3_PAUTH)
+#if defined(ARCH_ARM_FEAT_PAuth)
extend SCTLR_EL1 bitfield {
13 EnDB bool;
27 EnDA bool;
@@ -1128,13 +1196,13 @@ extend SCTLR_EL1 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_4_LSE)
+#if defined(ARCH_ARM_FEAT_LSE2)
extend SCTLR_EL1 bitfield {
6 nAA bool;
};
#endif
-#if defined(ARCH_ARM_8_5_MEMTAG)
+#if defined(ARCH_ARM_FEAT_MTE)
extend SCTLR_EL1 bitfield {
43 ATA bool;
42 ATA0 bool;
@@ -1144,7 +1212,7 @@ extend SCTLR_EL1 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_0_SSBS)
+#if defined(ARCH_ARM_FEAT_SSBS)
extend SCTLR_EL1 bitfield {
44 DSSBS bool;
};
@@ -1179,7 +1247,7 @@ define SCTLR_EL2_VM bitfield<64> {
63:32 unknown=0;
};
-#if defined(ARCH_ARM_8_1_VHE)
+#if defined(ARCH_ARM_FEAT_VHE)
define SCTLR_EL2_E2H_TGE bitfield<64> {
0 M bool;
1 A bool;
@@ -1215,7 +1283,7 @@ define SCTLR_EL2_E2H_TGE bitfield<64> {
};
#endif
-#if defined(ARCH_ARM_8_2_IESB)
+#if defined(ARCH_ARM_FEAT_IESB)
extend SCTLR_EL2_VM bitfield {
21 IESB bool;
};
@@ -1224,14 +1292,14 @@ extend SCTLR_EL2_E2H_TGE bitfield {
};
#endif
-#if defined(ARCH_ARM_8_2_LSMAOC)
+#if defined(ARCH_ARM_FEAT_LSMAOC)
extend SCTLR_EL2_E2H_TGE bitfield {
28 nTLSMD bool;
29 LSMAOE bool;
};
#endif
-#if defined(ARCH_ARM_8_3_PAUTH)
+#if defined(ARCH_ARM_FEAT_PAuth)
extend SCTLR_EL2_VM bitfield {
13 EnDB bool;
27 EnDA bool;
@@ -1246,7 +1314,7 @@ extend SCTLR_EL2_E2H_TGE bitfield {
};
#endif
-#if defined(ARCH_ARM_8_4_LSE)
+#if defined(ARCH_ARM_FEAT_LSE2)
extend SCTLR_EL2_VM bitfield {
6 nAA bool;
};
@@ -1255,7 +1323,7 @@ extend SCTLR_EL2_E2H_TGE bitfield {
};
#endif
-#if defined(ARCH_ARM_8_5_MEMTAG)
+#if defined(ARCH_ARM_FEAT_MTE)
extend SCTLR_EL2_VM bitfield {
43 ATA bool;
42 ATA0 bool;
@@ -1270,7 +1338,7 @@ extend SCTLR_EL2_E2H_TGE bitfield {
};
#endif
-#if defined(ARCH_ARM_8_0_SSBS)
+#if defined(ARCH_ARM_FEAT_SSBS)
extend SCTLR_EL2_VM bitfield {
44 DSSBS bool;
};
@@ -1314,13 +1382,13 @@ define SPSR_EL2_A32 bitfield<64> {
63:32 unknown=0;
};
-#if defined(ARCH_ARM_8_1_PAN)
+#if defined(ARCH_ARM_FEAT_PAN)
extend SPSR_EL2_A32 bitfield {
22 PAN bool;
};
#endif
-#if defined(ARCH_ARM_8_4_DIT)
+#if defined(ARCH_ARM_FEAT_DIT)
extend SPSR_EL2_A32 bitfield {
23 DIT bool;
};
@@ -1350,7 +1418,7 @@ define SPSR_##el##_A64 bitfield<64> { \
SPSR_A64(EL1)
SPSR_A64(EL2)
-#if defined(ARCH_ARM_8_5_BTI)
+#if defined(ARCH_ARM_FEAT_BTI)
extend SPSR_EL1_A64 bitfield {
11:10 BTYPE uint8;
};
@@ -1359,7 +1427,7 @@ extend SPSR_EL2_A64 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_0_SSBS)
+#if defined(ARCH_ARM_FEAT_SSBS)
extend SPSR_EL1_A64 bitfield {
12 SSBS bool;
};
@@ -1368,7 +1436,7 @@ extend SPSR_EL2_A64 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_1_PAN)
+#if defined(ARCH_ARM_FEAT_PAN)
extend SPSR_EL1_A64 bitfield {
22 PAN bool;
};
@@ -1377,7 +1445,7 @@ extend SPSR_EL2_A64 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_2_UAO)
+#if defined(ARCH_ARM_FEAT_UAO)
extend SPSR_EL1_A64 bitfield {
23 UAO bool;
};
@@ -1386,7 +1454,7 @@ extend SPSR_EL2_A64 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_4_DIT)
+#if defined(ARCH_ARM_FEAT_DIT)
extend SPSR_EL1_A64 bitfield {
24 DIT bool;
};
@@ -1395,7 +1463,7 @@ extend SPSR_EL2_A64 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_5_MEMTAG)
+#if defined(ARCH_ARM_FEAT_MTE)
extend SPSR_EL1_A64 bitfield {
25 TCO bool;
};
@@ -1404,7 +1472,19 @@ extend SPSR_EL2_A64 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_5_MEMTAG)
+define SPSR_EL2_base bitfield<64> {
+ 3:0 unknown=0;
+ 4 M4 bool;
+ 63:5 unknown=0;
+};
+
+define SPSR_EL2 union {
+ a32 bitfield SPSR_EL2_A32;
+ a64 bitfield SPSR_EL2_A64;
+ base bitfield SPSR_EL2_base;
+};
+
+#if defined(ARCH_ARM_FEAT_MTE)
define TCO bitfield<64> {
24:0 unknown=0;
25 TCO bool;
@@ -1440,21 +1520,21 @@ define TCR_EL1 bitfield<64> {
63:55 unknown=0;
};
-#if defined(ARCH_ARM_8_1_TTHM)
+#if defined(ARCH_ARM_FEAT_HAFDBS)
extend TCR_EL1 bitfield {
39 HA bool;
40 HD bool;
};
#endif
-#if defined(ARCH_ARM_8_1_HPD)
+#if defined(ARCH_ARM_FEAT_HPDS)
extend TCR_EL1 bitfield {
41 HPD0 bool;
42 HPD1 bool;
};
#endif
-#if defined(ARCH_ARM_8_2_TTPBHA)
+#if defined(ARCH_ARM_FEAT_HPDS2)
extend TCR_EL1 bitfield {
43 HWU059 bool;
44 HWU060 bool;
@@ -1467,21 +1547,21 @@ extend TCR_EL1 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_2_SVE)
+#if defined(ARCH_ARM_FEAT_SVE)
extend TCR_EL1 bitfield {
53 NFD0 bool;
54 NFD1 bool;
};
#endif
-#if defined(ARCH_ARM_8_3_PAUTH)
+#if defined(ARCH_ARM_FEAT_PAuth)
extend TCR_EL1 bitfield {
51 TBID0 bool;
52 TBID1 bool;
};
#endif
-#if defined(ARCH_ARM_8_5_MEMTAG)
+#if defined(ARCH_ARM_FEAT_MTE)
extend TCR_EL1 bitfield {
57 TCMA0 bool;
58 TCMA1 bool;
@@ -1508,7 +1588,7 @@ define TCR_EL2_E2H0 bitfield<64> {
63:32 unknown=0;
};
-#if defined(ARCH_ARM_8_1_VHE)
+#if defined(ARCH_ARM_FEAT_VHE)
define TCR_EL2_E2H1 bitfield<64> {
5:0 T0SZ uint8;
6 unknown=0;
@@ -1533,7 +1613,7 @@ define TCR_EL2_E2H1 bitfield<64> {
};
#endif
-#if defined(ARCH_ARM_8_1_TTHM)
+#if defined(ARCH_ARM_FEAT_HAFDBS)
extend TCR_EL2_E2H0 bitfield {
21 HA bool;
22 HD bool;
@@ -1544,7 +1624,7 @@ extend TCR_EL2_E2H1 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_1_HPD)
+#if defined(ARCH_ARM_FEAT_HPDS)
extend TCR_EL2_E2H0 bitfield {
24 HPD bool;
};
@@ -1554,13 +1634,13 @@ extend TCR_EL2_E2H1 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_1_VHE)
+#if defined(ARCH_ARM_FEAT_VHE)
extend TCR_EL2_E2H1 bitfield {
37 TBI0 bool;
};
#endif
-#if defined(ARCH_ARM_8_2_TTPBHA)
+#if defined(ARCH_ARM_FEAT_HPDS2)
extend TCR_EL2_E2H0 bitfield {
25 HWU059 bool;
26 HWU060 bool;
@@ -1579,14 +1659,14 @@ extend TCR_EL2_E2H1 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_2_SVE)
+#if defined(ARCH_ARM_FEAT_SVE)
extend TCR_EL2_E2H1 bitfield {
53 NFD0 bool;
54 NFD1 bool;
};
#endif
-#if defined(ARCH_ARM_8_3_PAUTH)
+#if defined(ARCH_ARM_FEAT_PAuth)
extend TCR_EL2_E2H0 bitfield {
29 TBID bool;
};
@@ -1596,7 +1676,7 @@ extend TCR_EL2_E2H1 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_5_MEMTAG)
+#if defined(ARCH_ARM_FEAT_MTE)
extend TCR_EL2_E2H0 bitfield {
30 TCMA bool;
};
@@ -1626,7 +1706,7 @@ TTBR(1,EL1)
TTBR(0,EL2)
TTBR(1,EL2)
-#if defined(ARCH_ARM_8_4_TRACE)
+#if defined(ARCH_ARM_FEAT_TRF)
define TRFCR_EL2 bitfield<64> {
0 E0HTRE bool = 0;
1 E2TRE bool = 0;
@@ -1680,20 +1760,20 @@ define VTCR_EL2 bitfield<64> {
63:32 unknown=0;
};
-#if defined(ARCH_ARM_8_1_VMID16)
+#if defined(ARCH_ARM_FEAT_VMID16)
extend VTCR_EL2 bitfield {
19 VS bool;
};
#endif
-#if defined(ARCH_ARM_8_1_TTHM)
+#if defined(ARCH_ARM_FEAT_HAFDBS)
extend VTCR_EL2 bitfield {
21 HA bool;
22 HD bool;
};
#endif
-#if defined(ARCH_ARM_8_2_TTPBHA)
+#if defined(ARCH_ARM_FEAT_HPDS2)
extend VTCR_EL2 bitfield {
25 HWU059 bool;
26 HWU060 bool;
@@ -1702,7 +1782,7 @@ extend VTCR_EL2 bitfield {
};
#endif
-#if defined(ARCH_ARM_8_4_SECEL2)
+#if defined(ARCH_ARM_FEAT_SEL2)
extend VTCR_EL2 bitfield {
29 NSW bool;
30 NSA bool;
@@ -1717,7 +1797,7 @@ define VTTBR_EL2 bitfield<64> {
};
-#if defined(ARCH_ARM_8_1_VMID16)
+#if defined(ARCH_ARM_FEAT_VMID16)
extend VTTBR_EL2 bitfield {
delete VMID;
63:48 VMID uint32;
@@ -1728,12 +1808,21 @@ extend VTTBR_EL2 bitfield {
// ESR_EL2 ISS encodings (only some ISS encodings have been added)
define ESR_EL2_ISS_WFI_WFE bitfield<25> {
- 0 TI bool;
+ 0 TI enumeration iss_wfx_ti;
19:1 unknown=0;
23:20 COND uint8;
24 CV bool;
};
+#if defined(ARCH_ARM_FEAT_WFxT)
+extend ESR_EL2_ISS_WFI_WFE bitfield {
+ delete TI;
+ 1:0 TI enumeration iss_wfx_ti;
+ 2 RV bool;
+ 9:5 Rn uint8;
+};
+#endif
+
define ESR_EL2_ISS_HVC bitfield<25> {
15:0 imm16 uint16;
24:16 unknown=0;
@@ -1835,10 +1924,10 @@ define ESR_EL2_ISS_LDC_STC bitfield<25> {
};
#endif
-#if defined(ARCH_ARM_8_4_AMU) || defined(ARCH_ARM_8_6_AMU)
+#if defined(ARCH_ARM_FEAT_AMUv1) || defined(ARCH_ARM_FEAT_AMUv1p1)
define AMCR_EL0 bitfield<64> {
10 HDBG bool;
-#if defined(ARCH_ARM_8_6_AMU)
+#if defined(ARCH_ARM_FEAT_AMUv1p1)
17 CG1RZ bool;
#endif
others unknown=0;
@@ -1858,3 +1947,49 @@ define AMCGCR_EL0 bitfield<64> {
others unknown=0;
};
#endif
+
+#if defined(ARCH_ARM_FEAT_FGT)
+define HFGWTR_EL2 bitfield<64> {
+ 0 AFSR0_EL1 bool;
+ 1 AFSR1_EL1 bool;
+ 3 AMAIR_EL1 bool;
+ 4 APDAKey bool;
+ 5 APDBKey bool;
+ 6 APGAKey bool;
+ 7 APIAKey bool;
+ 8 APIBKey bool;
+ 11 CONTEXTIDR_EL1 bool;
+ 12 CPACR_EL1 bool;
+ 13 CSSELR_EL1 bool;
+ 16 ESR_EL1 bool;
+ 17 FAR_EL1 bool;
+ 19 LORC_EL1 bool;
+ 20 LOREA_EL1 bool;
+ 22 LORN_EL1 bool;
+ 23 LORSA_EL1 bool;
+ 24 MAIR_EL1 bool;
+ 27 PAR_EL1 bool;
+ 29 SCTLR_EL1 bool;
+ 30 SCTXNUM_EL1 bool;
+ 31 SCTXNUM_EL0 bool;
+ 32 TCR_EL1 bool;
+ 33 TPIDR_EL1 bool;
+ 34 TPIDRRO_EL0 bool;
+ 35 TPIDR_EL0 bool;
+ 36 TTBR0_EL1 bool;
+ 37 TTBR1_EL1 bool;
+ 38 VBAR_EL1 bool;
+ 39 ICC_IGRPENn_EL1 bool;
+ 41 ERRSELR_EL1 bool;
+ 43 ERXCTLR_EL1 bool;
+ 44 ERXSTATUS_EL1 bool;
+ 45 ERXMISCn_EL1 bool;
+ 47 ERXPFGCTL_EL1 bool;
+ 48 ERXPFGCDN_EL1 bool;
+ 49 ERXADDR_EL1 bool;
+ 50 nACCDATA_EL1 bool;
+ 54 nSMPRI_EL1 bool;
+ 55 nTPIDR2_EL0 bool;
+ others unknown=0;
+};
+#endif
diff --git a/hyp/core/base/aarch64/types.tc b/hyp/core/base/aarch64/types.tc
index 136198c..be7f31f 100644
--- a/hyp/core/base/aarch64/types.tc
+++ b/hyp/core/base/aarch64/types.tc
@@ -3,3 +3,11 @@
// SPDX-License-Identifier: BSD-3-Clause
define paddr_t public newtype uregister;
+
+define PADDR_INVALID constant type paddr_t = -1;
+define VADDR_INVALID constant uintptr = -1;
+
+define coreid_info structure {
+ part_num uint16;
+ core_ID enumeration core_id;
+};
diff --git a/hyp/core/base/armv8/enums.tc b/hyp/core/base/armv8/enums.tc
index afa0b90..0bc72b3 100644
--- a/hyp/core/base/armv8/enums.tc
+++ b/hyp/core/base/armv8/enums.tc
@@ -65,3 +65,8 @@ define spsr_32bit_mode enumeration {
Undefined = 0b11011;
System = 0b11111;
};
+
+define iss_wfx_ti enumeration {
+ WFI = 0b00;
+ WFE = 0b01;
+};
diff --git a/hyp/core/base/build.conf b/hyp/core/base/build.conf
index d6d3420..2189a03 100644
--- a/hyp/core/base/build.conf
+++ b/hyp/core/base/build.conf
@@ -4,9 +4,12 @@
interface base
types types.tc
+source base.c
+arch_source aarch64 core_id.c
arch_types armv8 enums.tc
arch_types aarch64 types.tc enums.tc sysregs.tc
arch_types cortex-a-v8_2 sysregs_cpu.tc
+arch_types cortex-a-v9 sysregs_cpu.tc
template typed hypconstants.h
template typed hypcontainers.h
template typed hypresult.h
diff --git a/hyp/core/base/cortex-a-v9/sysregs_cpu.tc b/hyp/core/base/cortex-a-v9/sysregs_cpu.tc
new file mode 100644
index 0000000..9d7ce12
--- /dev/null
+++ b/hyp/core/base/cortex-a-v9/sysregs_cpu.tc
@@ -0,0 +1,15 @@
+// © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+// This needs to be double-checked.
+// FIXME:
+extend ACTLR_EL2 bitfield {
+ 0 ACTLREN bool;
+ 1 ECTLREN bool;
+ 4 AMEN bool;
+ 5 ERXPFGEN bool;
+ 7 PWREN bool;
+ 11 SMEN bool;
+ 12 CLUSTERPMUEN bool;
+};
diff --git a/hyp/core/base/src/base.c b/hyp/core/base/src/base.c
new file mode 100644
index 0000000..e7fb378
--- /dev/null
+++ b/hyp/core/base/src/base.c
@@ -0,0 +1,13 @@
+// © 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include
+#include
+
+// Gunyah compiler assumption sanity checks.
+#if ARCH_IS_64BIT
+static_assert(SIZE_MAX == UINT64_MAX, "SIZE_MAX smaller than machine width");
+#else
+#error unsupported
+#endif
diff --git a/hyp/core/base/templates/accessors.c.tmpl b/hyp/core/base/templates/accessors.c.tmpl
index 2282568..7da3d48 100644
--- a/hyp/core/base/templates/accessors.c.tmpl
+++ b/hyp/core/base/templates/accessors.c.tmpl
@@ -15,8 +15,10 @@
#for $definition in $definitions
#if $definition.category == "bitfield"
#set type_name=$definition.type_name
+#set unit_type=$definition.unit_type
#set unit_cnt=$definition.unit_count
#set compare_masks=$definition.compare_masks
+#set init_values=$definition.init_values
#set all_fields_boolean=$definition.all_fields_boolean
#set boolean_masks=$definition.boolean_masks
#set trivial = True
@@ -32,29 +34,37 @@ ${type_name}_init(${type_name}_t *bit_field) {
}
#if $unit_cnt == 1
-${definition.unit_type}
+$unit_type
${type_name}_raw(${type_name}_t bit_field) {
return bit_field.bf[0];
}
-_Atomic ${definition.unit_type} *
+_Atomic $unit_type *
${type_name}_atomic_ptr_raw(_Atomic ${type_name}_t *ptr) {
- return (_Atomic ${definition.unit_type} *)&((${type_name}_t *)ptr)->bf[0];
+ return (_Atomic $unit_type *)&((${type_name}_t *)ptr)->bf[0];
}
#end if
+#set $unit_size_mask = (1 << definition.unit_size) - 1
${type_name}_t
-${type_name}_clean(${type_name}_t val) {
+${type_name}_clean(${type_name}_t bit_field) {
#if trivial
- (void)val;
+ (void)bit_field;
#end if
return (${type_name}_t) { .bf = { #slurp
#for i in range($unit_cnt)
#if $compare_masks[$i] != 0
#set mask = hex($compare_masks[$i])
- val.bf[$i] & ${mask}U,
+#if $init_values[$i] != 0
+#set init = hex($init_values[$i])
+## Keep any default values, only for `unknown = XX` fields
+ // (${init}U & ~${mask}U) |
+ ($unit_type)(${hex($init_values[$i] & ($compare_masks[$i] ^ unit_size_mask))}U) |
+#end if
+ (bit_field.bf[$i] & ${mask}U),
#else
- 0,
+#set init = hex($init_values[$i])
+ ${init},
#end if
#end for
} };
@@ -90,6 +100,41 @@ ${type_name}_is_equal(${type_name}_t b1, ${type_name}_t b2) {
#set bool_trivial = False
#end if
#end for
+
+#if $all_fields_boolean
+bool
+${type_name}_is_empty(${type_name}_t bit_field)
+{
+return#slurp
+#set $first = True
+#for $unit in range($unit_cnt)
+#if not $first
+ &slurp
+#end if
+#set $first = False
+ ((bit_field.bf[$unit] & ${hex($boolean_masks[$unit])}U) == 0U)#slurp
+#end for
+;
+}
+#end if
+
+#if $all_fields_boolean
+bool
+${type_name}_is_clean(${type_name}_t bit_field)
+{
+return#slurp
+#set $first = True
+#for $unit in range($unit_cnt)
+#if not $first
+ &slurp
+#end if
+#set $first = False
+ ((bit_field.bf[$unit] & ${hex($boolean_masks[$unit] ^ $unit_size_mask)}U) == ${hex($init_values[$i] & ~$compare_masks[$i])}U)#slurp
+#end for
+;
+}
+#end if
+
${type_name}_t
${type_name}_union(${type_name}_t b1, ${type_name}_t b2)
{
@@ -122,7 +167,7 @@ ${type_name}_intersection(${type_name}_t b1, ${type_name}_t b2)
b1.bf[$i] & b2.bf[$i],
#elif $boolean_masks[$i] != 0
#set mask = hex($boolean_masks[$i])
- b1.bf[$i] & (b2.bf[$i] | ~($definition.unit_type)${mask}U),
+ b1.bf[$i] & (b2.bf[$i] | ~($unit_type)${mask}U),
#else
b1.bf[$i],
#end if
@@ -157,7 +202,7 @@ ${type_name}_difference(${type_name}_t b1, ${type_name}_t b2)
${type_name}_t
${type_name}_atomic_union(_Atomic ${type_name}_t *b1, ${type_name}_t b2, memory_order order)
{
- _Atomic ${definition.unit_type} *bf = (_Atomic ${definition.unit_type} *) & ((${type_name}_t *) b1)->bf[0];
+ _Atomic $unit_type *bf = (_Atomic $unit_type *) & ((${type_name}_t *) b1)->bf[0];
return (${type_name}_t){ .bf = { #slurp
#if $all_fields_boolean
atomic_fetch_or_explicit(bf, b2.bf[0], order)
@@ -170,12 +215,12 @@ ${type_name}_atomic_union(_Atomic ${type_name}_t *b1, ${type_name}_t b2, memory_
${type_name}_t
${type_name}_atomic_intersection(_Atomic ${type_name}_t *b1, ${type_name}_t b2, memory_order order)
{
- _Atomic ${definition.unit_type} *bf = (_Atomic ${definition.unit_type} *) & ((${type_name}_t *) b1)->bf[0];
+ _Atomic $unit_type *bf = (_Atomic $unit_type *) & ((${type_name}_t *) b1)->bf[0];
return (${type_name}_t){ .bf = { #slurp
#if $all_fields_boolean
atomic_fetch_and_explicit(bf, b2.bf[0], order)
#else
- atomic_fetch_and_explicit(bf, b2.bf[0] | ~($definition.unit_type)${mask}U, order)
+ atomic_fetch_and_explicit(bf, b2.bf[0] | ~($unit_type)${mask}U, order)
#end if
} };
}
@@ -190,32 +235,46 @@ ${type_name}_atomic_difference(_Atomic ${type_name}_t *b1, ${type_name}_t b2, me
#end if
#for $dec in $definition._all_declarations:
#if not $dec.is_ignore
-#set field_type = $dec.compound_type.gen_type_name(unqualified=True)
+#set field_type = $dec.compound_type
+#set field_type_type_name = $dec.compound_type.gen_type_name(unqualified=True)
#if $dec.is_nested_bitfield
-#set field_type_name = $dec.compound_type.type_name
-#set field_unit_type = $dec.compound_type.definition.unit_type
-#set val_expr = $field_type_name + '_raw(val)'
+#set field_type_name = $field_type.type_name
+#set field_unit_type = $field_type.definition.unit_type
+#set val_expr = '(' + $dec.unit_type + ')' + $field_type_name + '_raw(val)'
#else
-#set val_expr = 'val'
+#set val_expr = '(' + $dec.unit_type + ')val'
#end if
#if not $dec.is_const:
-void ${dec.bf_type_name}_set_${dec.field_name}(${dec.bf_type_name}_t *bit_field, ${dec.compound_type.gen_declaration('val')}) {
- ${dec.unit_type} *bf = (${dec.unit_type} *)bit_field;
+void ${dec.bf_type_name}_set_${dec.field_name}(${dec.bf_type_name}_t *bit_field, ${field_type.gen_declaration('val')}) {
+## Handle MISRA Boolean type casting
+#if not $dec.is_nested_bitfield
+#if ($field_type.basic_type.bitsize == 1) and ($field_type.basic_type.category == 'primitive')
+ ${dec.unit_type} bool_val = val ? (${dec.unit_type})1 : (${dec.unit_type})0;
+#set val_expr = 'bool_val'
+#end if
+#end if
+ ${dec.unit_type} *bf = &bit_field->bf[0];
#for $map in $dec.field_maps:
#set $m = (1 << $map.length) - 1
#set unit = $map.mapped_bit // $dec.unit_size
#set mapped_bit = $map.mapped_bit % $dec.unit_size
bf[$unit] &= (${dec.unit_type})${hex(((2 ** dec.unit_size) - 1) ^ (m << $mapped_bit))}U;
- bf[$unit] |= ((((${dec.unit_type})${val_expr}) >> ${map.field_bit}U) & (${dec.unit_type})${hex(m)}U) << ${mapped_bit}U;
+ bf[$unit] |= ((${val_expr} >> ${map.field_bit}U) & (${dec.unit_type})${hex(m)}U) << ${mapped_bit}U;
#end for
}
#end if
#if not $dec.is_writeonly:
-${field_type}
+${field_type_type_name}
${dec.bf_type_name}_get_${dec.field_name}(const ${dec.bf_type_name}_t *bit_field) {
- ${dec.unit_type} val = 0U;
+ ${dec.unit_type} val = 0;
const ${dec.unit_type} *bf = (const ${dec.unit_type} *)&bit_field->bf[0];
+#set $bool_type = False
+#if not $dec.is_nested_bitfield
+#if ($field_type.basic_type.bitsize == 1) and ($field_type.basic_type.category == 'primitive')
+#set $bool_type = True
+#end if
+#end if
#for $map in $dec.field_maps:
#set $m = (1 << $map.length) - 1
@@ -225,10 +284,16 @@ ${dec.bf_type_name}_get_${dec.field_name}(const ${dec.bf_type_name}_t *bit_field
#end for
#if $dec.field_signed
#set l=hex(1 << ($dec.field_length - 1)) + 'U'
- return (${field_type})((val ^ $l) - $l);
+ return (${field_type_type_name})((val ^ $l) - $l);
#else
#if not $dec.is_nested_bitfield
- return (${field_type})val;
+#if $bool_type
+ return val != (${dec.unit_type})0;
+#else if $field_type.is_pointer
+ return (${field_type_type_name})(uintptr_t)val;
+#else
+ return (${field_type_type_name})val;
+#end if
#else
return ${field_type_name}_cast((${field_unit_type})val);
#end if
diff --git a/hyp/core/base/templates/hypresult.c.tmpl b/hyp/core/base/templates/hypresult.c.tmpl
index 00bee88..97b91ef 100644
--- a/hyp/core/base/templates/hypresult.c.tmpl
+++ b/hyp/core/base/templates/hypresult.c.tmpl
@@ -74,7 +74,7 @@ ${name}_ptr_result_ok(${type_name} * ret)
#continue
#end if
#end if
-#if $category in ['enumeration', 'primitive', 'bitfield', 'structure']
+#if $category in ['enumeration', 'primitive', 'bitfield', 'structure'] and $d.size != 0
$declare_result(d.indicator, type_name)
$declare_result_ptr(d.indicator, type_name)
#else if $category in ['union', 'object']
diff --git a/hyp/core/base/templates/hypresult.h.tmpl b/hyp/core/base/templates/hypresult.h.tmpl
index 8e6c9b7..48b965d 100644
--- a/hyp/core/base/templates/hypresult.h.tmpl
+++ b/hyp/core/base/templates/hypresult.h.tmpl
@@ -60,7 +60,7 @@ ${name}_ptr_result_ok(${type_name} * ret);
#set category = $basic_type.category
#end if
#end if
-#if $category in ['enumeration', 'primitive', 'bitfield', 'structure']
+#if $category in ['enumeration', 'primitive', 'bitfield', 'structure'] and $d.size != 0
$declare_result(d.indicator, type_name)
$declare_result_ptr(d.indicator, type_name)
#else if $category in ['union', 'object']
diff --git a/hyp/core/base/types.tc b/hyp/core/base/types.tc
index 2a391c7..b648672 100644
--- a/hyp/core/base/types.tc
+++ b/hyp/core/base/types.tc
@@ -52,6 +52,9 @@ define sregister_t public newtype sregister;
define count_t public newtype uint32;
define index_t public newtype uint32;
+define COUNT_INVALID constant type count_t = -1;
+define INDEX_INVALID constant type index_t = -1;
+
// Dummy lockable structure used for thread safety analysis of public lock
// APIs that lock static variables, without having to expose the static
// variable. These are always declared extern; they don't need to be defined.
diff --git a/hyp/core/boot/aarch64/include/arch/reloc.h b/hyp/core/boot/aarch64/include/arch/reloc.h
index 142b63d..c152919 100644
--- a/hyp/core/boot/aarch64/include/arch/reloc.h
+++ b/hyp/core/boot/aarch64/include/arch/reloc.h
@@ -6,4 +6,4 @@
(((R_TYPE(r_info) == R_AARCH64_NONE) || \
(R_TYPE(r_info) == R_AARCH64_NULL) || \
(R_TYPE(r_info) == R_AARCH64_RELATIVE)) && \
- (R_SYM(r_info) == 0))
+ (R_SYM(r_info) == 0U))
diff --git a/hyp/core/boot/aarch64/src/aarch64_boot.c b/hyp/core/boot/aarch64/src/aarch64_boot.c
index 6060cd1..3dfd689 100644
--- a/hyp/core/boot/aarch64/src/aarch64_boot.c
+++ b/hyp/core/boot/aarch64/src/aarch64_boot.c
@@ -13,7 +13,7 @@
void
aarch64_handle_boot_runtime_init(void)
{
-#if defined(ARCH_ARM_8_1_VHE)
+#if defined(ARCH_ARM_FEAT_VHE)
CPTR_EL2_E2H1_t cptr = CPTR_EL2_E2H1_default();
register_CPTR_EL2_E2H1_write_ordered(cptr, &asm_ordering);
#else
diff --git a/hyp/core/boot/aarch64/src/init_el2.S b/hyp/core/boot/aarch64/src/init_el2.S
index 83f608a..a2d8028 100644
--- a/hyp/core/boot/aarch64/src/init_el2.S
+++ b/hyp/core/boot/aarch64/src/init_el2.S
@@ -11,10 +11,10 @@
// This stack is used by boot_cold_init. It must be large enough to run
// all the first-boot event triggers. This memory is then reclaimed by
// the hypervisor_partition.
- _bss aarch64_boot_stack, BOOT_STACK_SIZE, THREAD_STACK_MAP_ALIGN
+ _bss aarch64_boot_stack, BOOT_STACK_SIZE, 16
.space BOOT_STACK_SIZE
-#if defined(ARCH_ARM_8_3_PAUTH)
+#if defined(ARCH_ARM_FEAT_PAuth)
// Pointer authentication keys shared by all EL2 threads.
_bss aarch64_pauth_keys, AARCH64_PAUTH_KEYS_SIZE, \
AARCH64_PAUTH_KEYS_ALIGN
@@ -45,7 +45,8 @@
// x0-x3: 256-bit RNG seed from the platform code
// w4: Logical CPU number from the platform code
-function aarch64_init
+ .section .text.boot.init
+function aarch64_init, section=nosection
// Disable debug, aborts and interrupts.
msr DAIFSet, 0xf
@@ -109,7 +110,7 @@ function aarch64_init
cmp x8, x22
beq aarch64_boot_error
-#if defined(ARCH_ARM_8_3_PAUTH)
+#if defined(ARCH_ARM_FEAT_PAuth)
// Generate the PAC keys
adrl x21, aarch64_pauth_keys
mov x23, AARCH64_PAUTH_KEYS_SIZE
@@ -145,7 +146,7 @@ function_end aarch64_init
// x0: Virtual pointer to the CPU's idle thread
// w1: Logical CPU number from the platform code
-function aarch64_secondary_init
+function aarch64_secondary_init, section=nosection
// Disable debug, aborts and interrupts.
msr DAIFSet, 0xf
@@ -195,7 +196,7 @@ function aarch64_secondary_init
cmp x8, x22
beq aarch64_boot_error
-#if defined(ARCH_ARM_8_3_PAUTH)
+#if defined(ARCH_ARM_FEAT_PAuth)
// Load the PAC keys into registers
kernel_pauth_entry x0, x1, x2
@@ -222,7 +223,7 @@ function_end aarch64_secondary_init
// Input arguments:
// x0: Virtual pointer to the CPU's idle thread.
-function aarch64_warm_init
+function aarch64_warm_init, section=nosection
// Disable debug, aborts and interrupts.
msr DAIFSet, 0xf
@@ -266,7 +267,7 @@ function aarch64_warm_init
cmp x8, x22
beq aarch64_boot_error
-#if defined(ARCH_ARM_8_3_PAUTH)
+#if defined(ARCH_ARM_FEAT_PAuth)
// Load the PAC keys into registers
kernel_pauth_entry x0, x1, x2
@@ -284,7 +285,7 @@ function aarch64_warm_init
b boot_warm_init
function_end aarch64_warm_init
-function aarch64_boot_error
+function aarch64_boot_error, section=nosection
9:
wfi
b 9b
diff --git a/hyp/core/boot/aarch64/src/init_el2_mmu.S b/hyp/core/boot/aarch64/src/init_el2_mmu.S
index 1b85452..0925c63 100644
--- a/hyp/core/boot/aarch64/src/init_el2_mmu.S
+++ b/hyp/core/boot/aarch64/src/init_el2_mmu.S
@@ -9,9 +9,9 @@
bss64 aarch64_kaslr_base, local
bss64 hypervisor_prng_nonce
- .section .text
+ .section .text.boot.init
-function aarch64_init_generate_seed, local
+function aarch64_init_generate_seed, local, section=nosection
// KASLR - Seed is passed in x0-x3, however, for portability it may not
// be random. Mix in some values from registers that are UNKNOWN after
// reset: TPIDR_EL2, TTBR0_EL2, MAIR_EL2, VBAR_EL2 and FAR_EL2.
@@ -93,10 +93,14 @@ function_end aarch64_init_generate_seed
#define VSMAv8_AF_SHIFT (LOWER_ATTRS + VMSA_STG1_LOWER_ATTRS_AF_SHIFT)
#define VSMAv8_NG_SHIFT (LOWER_ATTRS + VMSA_STG1_LOWER_ATTRS_NG_SHIFT)
+#if defined(ARCH_ARM_FEAT_VHE)
#define VSMAv8_UXN_SHIFT (UPPER_ATTRS + VMSA_STG1_UPPER_ATTRS_UXN_SHIFT)
#define VSMAv8_PXN_SHIFT (UPPER_ATTRS + VMSA_STG1_UPPER_ATTRS_PXN_SHIFT)
+#else
+#define VSMAv8_XN_SHIFT (UPPER_ATTRS + VMSA_STG1_UPPER_ATTRS_XN_SHIFT)
+#endif
-#if defined(ARCH_ARM_8_5_BTI)
+#if defined(ARCH_ARM_FEAT_BTI)
#define VSMAv8_GP_SHIFT (UPPER_ATTRS + VMSA_STG1_UPPER_ATTRS_GP_SHIFT)
#endif
@@ -128,41 +132,45 @@ function_end aarch64_init_generate_seed
(1 << VSMAv8_PXN_SHIFT)
// (DBM << 51) | (CONTIG << 52) | (PXN << 53) | (UXN << 54)
-#if defined(ARCH_ARM_8_5_BTI)
+#if defined(ARCH_ARM_FEAT_BTI)
#define GUARDED_PAGE (1 << VSMAv8_GP_SHIFT)
#endif
-// FIXME: move these to type system
-#define TCR_RGN_NORMAL_NC ENUM_TCR_RGN_NORMAL_NONCACHEABLE
-#define TCR_RGN_NORMAL_WB_RA_WA ENUM_TCR_RGN_NORMAL_WRITEBACK_RA_WA
-#define TCR_RGN_NORMAL_WT_RA_NWA ENUM_TCR_RGN_NORMAL_WRITETHROUGH_RA
-#define TCR_RGN_NORMAL_WB_RA_NWA ENUM_TCR_RGN_NORMAL_WRITEBACK_RA
-#define TCR_SH_NONE ENUM_TCR_SH_NON_SHAREABLE
-#define TCR_SH_OUTER ENUM_TCR_SH_OUTER_SHAREABLE
-#define TCR_SH_INNER ENUM_TCR_SH_INNER_SHAREABLE
-#define TCR_TG0_4KB ENUM_TCR_TG0_GRANULE_SIZE_4KB
-#define TCR_TG1_4KB ENUM_TCR_TG1_GRANULE_SIZE_4KB
-#define TCR_IPS_32BIT ENUM_TCR_PS_SIZE_32BITS
-#define TCR_IPS_36BIT ENUM_TCR_PS_SIZE_36BITS
-#define TCR_IPS_40BIT ENUM_TCR_PS_SIZE_40BITS
-#define TCR_IPS_42BIT ENUM_TCR_PS_SIZE_42BITS
-#define TCR_IPS_44BIT ENUM_TCR_PS_SIZE_44BITS
-#define TCR_IPS_48BIT ENUM_TCR_PS_SIZE_48BITS
-#define TCR_IPS_52BIT ENUM_TCR_PS_SIZE_52BITS
+#define TCR_RGN ENUM_TCR_RGN_NORMAL_WRITEBACK_RA_WA
+#define TCR_SH ENUM_TCR_SH_INNER_SHAREABLE
+#define TCR_TG0 ENUM_TCR_TG0_GRANULE_SIZE_4KB
+#define TCR_TG1 ENUM_TCR_TG1_GRANULE_SIZE_4KB
+// Note: the nested macros are are needed to expand the config to a number
+// before it is pasted into the enum macro name.
+#define TCR_PS TCR_PS_FOR_CONFIG(PLATFORM_PHYS_ADDRESS_BITS)
+#define TCR_PS_FOR_CONFIG(x) TCR_PS_FOR_SIZE(x)
+#define TCR_PS_FOR_SIZE(x) ENUM_TCR_PS_SIZE_##x##BITS
+
+#if defined(ARCH_ARM_FEAT_VHE)
#define TCR_EL2_HYP ( \
TCR_EL2_E2H1_EPD0_MASK | \
(HYP_T1SZ << TCR_EL2_E2H1_T1SZ_SHIFT) | \
(0 << TCR_EL2_E2H1_A1_SHIFT) | \
- (TCR_RGN_NORMAL_WB_RA_WA << TCR_EL2_E2H1_IRGN1_SHIFT) | \
- (TCR_RGN_NORMAL_WB_RA_WA << TCR_EL2_E2H1_ORGN1_SHIFT) | \
- (TCR_SH_INNER << TCR_EL2_E2H1_SH1_SHIFT) | \
- (TCR_TG1_4KB << TCR_EL2_E2H1_TG1_SHIFT) | \
- (TCR_IPS_40BIT << TCR_EL2_E2H1_IPS_SHIFT))
+ (TCR_RGN << TCR_EL2_E2H1_IRGN1_SHIFT) | \
+ (TCR_RGN << TCR_EL2_E2H1_ORGN1_SHIFT) | \
+ (TCR_SH << TCR_EL2_E2H1_SH1_SHIFT) | \
+ (TCR_TG1 << TCR_EL2_E2H1_TG1_SHIFT) | \
+ (TCR_PS << TCR_EL2_E2H1_IPS_SHIFT))
+#else
+#define TCR_EL2_HYP ( \
+ (HYP_T0SZ << TCR_EL2_E2H0_T0SZ_SHIFT) | \
+ (TCR_RGN << TCR_EL2_E2H0_IRGN0_SHIFT) | \
+ (TCR_RGN << TCR_EL2_E2H0_ORGN0_SHIFT) | \
+ (TCR_SH << TCR_EL2_E2H0_SH0_SHIFT) | \
+ (TCR_TG0 << TCR_EL2_E2H0_TG0_SHIFT) | \
+ (TCR_PS << TCR_EL2_E2H0_PS_SHIFT))
+#endif
#if defined(__ARM_FEATURE_UNALIGNED)
#define SCTLR_EL2_VM_HYP_DEBUG 0
#else
+// FIXME:
//#define SCTLR_EL2_VM_HYP_DEBUG SCTLR_EL2_VM_A_MASK
#define SCTLR_EL2_VM_HYP_DEBUG 0
#endif
@@ -174,6 +182,8 @@ function_end aarch64_init_generate_seed
SCTLR_EL2_VM_I_MASK | \
SCTLR_EL2_VM_WXN_MASK)
+#if defined(ARCH_ARM_FEAT_VHE)
+// Enable EL2 E2H (hosted hypervisor) mode
#define HCR_EL2_HYP ( \
HCR_EL2_FMO_MASK | HCR_EL2_IMO_MASK | HCR_EL2_AMO_MASK | \
HCR_EL2_TGE_MASK | HCR_EL2_E2H_MASK)
@@ -185,6 +195,19 @@ function_end aarch64_init_generate_seed
#define HYP_LEVEL1_ALIGN (37 - HYP_T1SZ)
#define HYP_LEVEL1_ENTRIES (1U << (HYP_ASPACE_HIGH_BITS - 30))
+#else
+#define HCR_EL2_HYP ( \
+ HCR_EL2_FMO_MASK | HCR_EL2_IMO_MASK | HCR_EL2_AMO_MASK | \
+ HCR_EL2_TGE_MASK)
+
+// Kernel main pagetable in TTBR0_EL2
+// 39 bit address space (3-level) for KASLR
+// HYP_T0SZ = 64 - 39 = 25
+#define HYP_T0SZ (64 - HYP_ASPACE_LOW_BITS)
+#define HYP_LEVEL1_ALIGN (40 - HYP_T0SZ)
+#define HYP_LEVEL1_ENTRIES (1U << (HYP_ASPACE_LOW_BITS - 30))
+#endif
+
#define BITS_2MiB 21
#define BITS_1GiB 30
#define SIZE_2MiB (1 << BITS_2MiB)
@@ -203,17 +226,20 @@ function_end aarch64_init_generate_seed
// x19-x28: preserved as per AAPCS64
// Returns:
// x0: KASLR base
-function aarch64_init_kaslr
+function aarch64_init_kaslr, section=nosection
stp x29, x30, [sp, -16]!
mov x29, sp
bl aarch64_init_generate_seed
- // To test pathological seed, uncomment below
- //mov x0, 0
+ // To test pathological seed, define this below
+#if defined(DISABLE_KASLR) && DISABLE_KASLR
+ mov x0, 0
+#endif
- // - calculate KASLR virtual base address
+ // Calculate KASLR virtual base address
local mm_calc_virt_base:
+#if defined(ARCH_ARM_FEAT_VHE)
mov x10, 0xffffffffffe00000
ubfiz x9, x0, BITS_2MiB, (HYP_ASPACE_HIGH_BITS - BITS_2MiB)
eor x14, x10, x9
@@ -226,10 +252,33 @@ local mm_calc_virt_base:
adds x10, x10, x14
bcc 1f
- // -- virt address range either wraps, or ends at -1; try again
+ // -- virtual address wraps or ends at -1, try again
lsr x0, x0, 18
movk x0, 0x5555, lsl 48
b LOCAL(mm_calc_virt_base)
+#else
+ // - KASLR base needs to be in the lower half of the the address space,
+ // because the upper half is reserved for physaccess
+ ubfiz x9, x0, BITS_2MiB, (HYP_ASPACE_LOWER_HALF_BITS - BITS_2MiB)
+ // Ensure the KASLR base is outside of the 1:1 area
+ mov x10, (1 << HYP_ASPACE_MAP_DIRECT_BITS)
+ orr x14, x10, x9
+
+ // - ensure that the hypervisor image doesn't go out of the lower half of
+ // the address space
+ adr x10, image_virt_start
+ adrl x11, image_virt_last
+ sub x10, x11, x10
+ add x10, x10, x14
+ mov x9, (1 << HYP_ASPACE_LOWER_HALF_BITS)
+ cmp x9, x10
+ bhi 1f
+
+ // -- virtual address overlaps the upper half, try again
+ lsr x0, x0, (HYP_ASPACE_LOWER_HALF_BITS - BITS_2MiB)
+ movk x0, 0x5555, lsl 32
+ b LOCAL(mm_calc_virt_base)
+#endif
1:
adrp x9, aarch64_kaslr_base
@@ -246,14 +295,13 @@ function_end aarch64_init_kaslr
// pointer may be invalid and should not be accessed.
//
// Input / preserve registers:
-// w2: bool cold_boot
+// w2: bool first_boot
// x30: Physical address of return (to be translated to virtual address)
// x19-x28: preserved as per AAPCS64
-function aarch64_init_address_space
+function aarch64_init_address_space, section=nosection
// Ensure TLB-EL2 is clean, dsb and isb deferred until before mmu enable
tlbi alle2
- // Enable EL2 E2H (hosted hypervisor) mode
abs64 x9, HCR_EL2_HYP
msr HCR_EL2, x9
isb
@@ -268,11 +316,17 @@ function aarch64_init_address_space
abs64 x9, MAIR_DEFAULTS
msr MAIR_EL2, x9
- // - setup TTBR1_EL2 (hypervisor code / data)
- adrl x12, aarch64_pt_ttbr1_level1 // get physical addresses for el2 pt
+ // - setup TTBRx_EL2 (hypervisor code / data)
+ adrl x12, aarch64_pt_ttbr_level1 // physical addresses of EL2 PT
+#if defined(ARCH_ARM_FEAT_VHE)
orr x9, x12, TTBR1_EL2_CNP_MASK
// -- preserve x12 for use below
msr TTBR1_EL2, x9
+#else
+ orr x9, x12, TTBR0_EL2_CNP_MASK
+ // -- preserve x12 for use below
+ msr TTBR0_EL2, x9
+#endif
isb
// Load the KASLR base address
@@ -289,7 +343,7 @@ function aarch64_init_address_space
add x9, x9, x14
// - set the MMU-init vectors to: vectors_boot_aarch64
- // -- on enabling the mmu, the resulting Data Abort will jump there
+ // -- on enabling the MMU, the resulting prefetch abort will jump there
msr VBAR_EL2, x9
// Skip the PT setup if this is not the first boot
@@ -297,9 +351,13 @@ function aarch64_init_address_space
// === Setup the TTBR1_EL2 mappings for the hypervisor
// - create hypervisor text/ro 2MB mapping
- adrl x13, aarch64_pt_ttbr1_level2
+ adrl x13, aarch64_pt_ttbr_level2
// -- calculate 2MB table entries
- ubfx x10, x9, VSMAv8_ADDRESS_BITS_LEVEL1, HYP_ASPACE_HIGH_BITS-VSMAv8_ADDRESS_BITS_LEVEL1
+#if defined(ARCH_ARM_FEAT_VHE)
+ ubfx x10, x9, VSMAv8_ADDRESS_BITS_LEVEL1, HYP_ASPACE_HIGH_BITS - VSMAv8_ADDRESS_BITS_LEVEL1
+#else
+ ubfx x10, x9, VSMAv8_ADDRESS_BITS_LEVEL1, HYP_ASPACE_LOW_BITS - VSMAv8_ADDRESS_BITS_LEVEL1
+#endif
add x10, x12, x10, lsl VSMAv8_ENTRY_BITS // x10 points to Level-1 table entry
ubfx x11, x9, VSMAv8_ADDRESS_BITS_LEVEL2, VSMAv8_LEVEL_BITS
add x11, x13, x11, lsl VSMAv8_ENTRY_BITS // x11 points to Level-2 table entry
@@ -314,7 +372,7 @@ function aarch64_init_address_space
bic x12, x12, MASK_2MiB //
orr x9, x12, VSMAv8_BLOCK_TYPE
movz x10, LOWER_ATTRIBUTES_HYP_R
-#if defined(ARCH_ARM_8_5_BTI)
+#if defined(ARCH_ARM_FEAT_BTI)
movk x10, ((UPPER_ATTRIBUTES_HYP_X | GUARDED_PAGE) >> 48), LSL 48
#else
movk x10, (UPPER_ATTRIBUTES_HYP_X >> 48), LSL 48
@@ -336,17 +394,25 @@ function aarch64_init_address_space
// -- RW section falls on the next 1GiB page, so we need a new table
// entry and use the second level2 page-table
- adrl x12, aarch64_pt_ttbr1_level1
+ adrl x12, aarch64_pt_ttbr_level1
add x13, x13, (1 << (VSMAv8_LEVEL_BITS + VSMAv8_ENTRY_BITS))
// -- Update entry count for first level 1 entry
- ubfx x10, x14, VSMAv8_ADDRESS_BITS_LEVEL1, HYP_ASPACE_HIGH_BITS-VSMAv8_ADDRESS_BITS_LEVEL1
+#if defined(ARCH_ARM_FEAT_VHE)
+ ubfx x10, x14, VSMAv8_ADDRESS_BITS_LEVEL1, HYP_ASPACE_HIGH_BITS - VSMAv8_ADDRESS_BITS_LEVEL1
+#else
+ ubfx x10, x14, VSMAv8_ADDRESS_BITS_LEVEL1, HYP_ASPACE_LOW_BITS - VSMAv8_ADDRESS_BITS_LEVEL1
+#endif
add x10, x12, x10, lsl VSMAv8_ENTRY_BITS // x10 points to Level-1 table entry
ldr x11, [x10]
sub x11, x11, (1 << VSMAv8_TABLE_REFCOUNT_SHIFT)
str x11, [x10]
// -- calculate 2MB hyp table entries
- ubfx x10, x15, VSMAv8_ADDRESS_BITS_LEVEL1, HYP_ASPACE_HIGH_BITS-VSMAv8_ADDRESS_BITS_LEVEL1
+#if defined(ARCH_ARM_FEAT_VHE)
+ ubfx x10, x15, VSMAv8_ADDRESS_BITS_LEVEL1, HYP_ASPACE_HIGH_BITS - VSMAv8_ADDRESS_BITS_LEVEL1
+#else
+ ubfx x10, x15, VSMAv8_ADDRESS_BITS_LEVEL1, HYP_ASPACE_LOW_BITS - VSMAv8_ADDRESS_BITS_LEVEL1
+#endif
add x10, x12, x10, lsl VSMAv8_ENTRY_BITS // x10 points to Level-1 table entry
ubfx x11, x15, VSMAv8_ADDRESS_BITS_LEVEL2, VSMAv8_LEVEL_BITS
add x11, x13, x11, lsl VSMAv8_ENTRY_BITS // x11 points to Level-2 table entry
@@ -360,7 +426,9 @@ local mm_init_rw_level2:
add x11, x13, x11, lsl VSMAv8_ENTRY_BITS // x11 points to Level-2 table entry
orr x9, x9, VSMAv8_BLOCK_TYPE
movz x10, LOWER_ATTRIBUTES_HYP_RW
+#if defined(ARCH_ARM_FEAT_VHE)
movk x10, (UPPER_ATTRIBUTES_HYP_NX >> 48), LSL 48
+#endif
orr x9, x9, x10
str x9, [x11]
@@ -396,17 +464,22 @@ vector_aarch64_\name\():
.endm
- .section .text.boot.vectors
+ .section .text.boot_vectors
// Alignment for Boot Vectors
.balign 2048
// Vectors for booting EL2
+ // w2 = bool first_boot
// x30 = virtual return address
vectors_boot_aarch64:
boot_vector self_sync_mmu_init 0x0
- adr x9, vectors_aarch64
+ // For the first boot we must use the emergency vectors
+ adr x9, kernel_vectors_aarch64
+ adr x10, emergency_vectors_aarch64
+ cmp w2, 0
+ csel x9, x9, x10, eq
msr VBAR_EL2, x9
isb
msr DAIFclr, 4
@@ -417,8 +490,15 @@ boot_vector self_sync_mmu_init 0x0
.section .bss.hyp_pt.level1, "aw", @nobits
.p2align HYP_LEVEL1_ALIGN
+ .global aarch64_pt_ttbr_level1
+aarch64_pt_ttbr_level1:
+#if defined(ARCH_ARM_FEAT_VHE)
.global aarch64_pt_ttbr1_level1
aarch64_pt_ttbr1_level1:
+#else
+ .global aarch64_pt_ttbr0_level1
+aarch64_pt_ttbr0_level1:
+#endif
.space HYP_LEVEL1_ENTRIES * 8
// We have two 4KB level2 tables here, to handle the case where the
@@ -426,5 +506,5 @@ aarch64_pt_ttbr1_level1:
// level 1 entries).
.section .bss.hyp.pt.level2, "aw", @nobits
.balign 4096
-aarch64_pt_ttbr1_level2:
+aarch64_pt_ttbr_level2:
.space (1 << (VSMAv8_LEVEL_BITS + VSMAv8_ENTRY_BITS)) * 2
diff --git a/hyp/core/boot/boot.tc b/hyp/core/boot/boot.tc
index 64857ea..569cd57 100644
--- a/hyp/core/boot/boot.tc
+++ b/hyp/core/boot/boot.tc
@@ -9,7 +9,5 @@ define boot_env_phys_range public structure {
size size;
};
-define boot_env_data public structure {
- free_ranges array(BOOT_ENV_RANGES_NUM) structure boot_env_phys_range;
- free_ranges_count type count_t;
+define hyp_env_data structure {
};
diff --git a/hyp/core/boot/include/boot_init.h b/hyp/core/boot/include/boot_init.h
index 8dba29a..a09d593 100644
--- a/hyp/core/boot/include/boot_init.h
+++ b/hyp/core/boot/include/boot_init.h
@@ -21,6 +21,7 @@ boot_secondary_init(cpu_index_t cpu);
noreturn void
boot_warm_init(void);
-// Add address range to free ranges in env_data
+// Add address range to free ranges in env data stream
error_t
-boot_add_free_range(paddr_t base, size_t size, void *arg);
+boot_add_free_range(uintptr_t object, memdb_type_t type,
+ qcbor_enc_ctxt_t *qcbor_enc_ctxt);
diff --git a/hyp/core/boot/src/boot.c b/hyp/core/boot/src/boot.c
index d657cad..3128e4c 100644
--- a/hyp/core/boot/src/boot.c
+++ b/hyp/core/boot/src/boot.c
@@ -10,7 +10,9 @@
#include
#include
#include
+#include
#include
+#include
#include
#include
#include
@@ -47,15 +49,17 @@ boot_cold_init(cpu_index_t cpu) LOCK_IMPL
assert(guard_r.e == OK);
__stack_chk_guard = (uintptr_t)guard_r.r;
- // We can't trace yet because the CPU index in the thread is possibly
- // wrong (if cpu is nonzero), but the cpulocal handler for
- // boot_cpu_cold_init will do it for us.
- LOG(ERROR, WARN, "Hypervisor cold boot, version: {:s} ({:s})",
- (register_t)hypervisor_version, (register_t)hypervisor_build_date);
+ // We can't trace/log early because the CPU index and preemption count
+ // in the thread are still uninitialized.
trigger_boot_cpu_early_init_event();
trigger_boot_cold_init_event(cpu);
trigger_boot_cpu_cold_init_event(cpu);
+
+ // It's safe to log now.
+ LOG(ERROR, WARN, "Hypervisor cold boot, version: {:s} ({:s})",
+ (register_t)hypervisor_version, (register_t)hypervisor_build_date);
+
TRACE(DEBUG, INFO, "boot_cpu_warm_init");
trigger_boot_cpu_warm_init_event();
TRACE(DEBUG, INFO, "boot_hypervisor_start");
@@ -68,7 +72,7 @@ boot_cold_init(cpu_index_t cpu) LOCK_IMPL
#if defined(VERBOSE) && VERBOSE
#define STACK_GUARD_BYTE 0xb8
-#define STACK_GUARD_SIZE 256
+#define STACK_GUARD_SIZE 256U
#include