Merge tag 'pull-target-arm-20251010' of https://gitlab.com/pm215/qemu into staging

target-arm queue:
 * Implement FEAT_GCS
 * Implement FEAT_MEC

# -----BEGIN PGP SIGNATURE-----
#
# iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmjpBGAZHHBldGVyLm1h
# eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3nyaEACV1f4oBSn/rzEgX0PYmYzj
# jW3tGbEk1i1QFApjkOSbjqNRBKEYLj1LsaeNOVqixRswATe1mMx9ZNWHqJnSd/tw
# 7XLr7dN+YsVvYViILL4VLrHipYcLrgyC1Vlg+UK5RsuVPV2O4PZw6T0LoV32CSF6
# r/LbEGKH4VKHOVMRIR7SJlajmkFbHQvTTj3jjXCgQCUQaKfMzkEGK/UGOt2D3H54
# oSrGLif9nRg0o6Ce9NzfC2xb4XSvdwyT3RE84vkuSSlRcmjt9zQEE+kds4yHhAAi
# D6w1m+Aq8zh4sKJbqVRp9M7ymb5465xv6p/4Av2r3Gxy3v4d0ADgQahel+AYh8Sp
# urzqZWAR66RLrWSEj51K5nbW8yUM6OYNC/VXrtcMBXgBRMeCYVLgZF3hCrqVyDtv
# fP61xJBHPd2+nlcJNFEE5yqazFkcpUsoE/gm2lDPPsdPF5DFKky4VkVqJIGreain
# 25zGj44q9vDY7slMJMW38rbB3f1pxbxlcljG93N8+2ZzPLKz+7ezvgXFpY2lij0r
# qNn7eFEG80roh+lykTe7BroQSQ+pIAxOXM/ouwr+59fsXtnCKrdFG+96WdS+yhsC
# 4ss24hvHUvVMGnEGiYbUL/tIwFJku1wBq+a745DiwJwqyVGbavOGApVbrv/9xuWN
# s2MWF0xy8CnhPBJwyK4iOg==
# =yKgg
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 10 Oct 2025 06:04:32 AM PDT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [unknown]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [unknown]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [unknown]
# gpg:                 aka "Peter Maydell <peter@archaic.org.uk>" [unknown]
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* tag 'pull-target-arm-20251010' of https://gitlab.com/pm215/qemu: (76 commits)
  target/arm: Enable FEAT_MEC in -cpu max
  target/arm: Implement FEAT_MEC registers
  target/arm: Add a cpreg flag to indicate no trap in NV
  tests/tcg/aarch64: Add gcsss
  tests/tcg/aarch64: Add gcspushm
  tests/tcg/aarch64: Add gcsstr
  linux-user/aarch64: Enable GCS in HWCAP
  linux-user/aarch64: Generate GCS signal records
  linux-user/aarch64: Inject SIGSEGV for GCS faults
  target/arm: Enable GCSPR_EL0 for read in user-mode
  linux-user/aarch64: Implement map_shadow_stack syscall
  linux-user/aarch64: Release gcs stack on thread exit
  linux-user/aarch64: Allocate new gcs stack on clone
  linux-user/aarch64: Implement prctls for GCS
  target/arm: Enable FEAT_GCS with -cpu max
  target/arm: Implement EXLOCK check during exception return
  target/arm: Copy EXLOCKEn to EXLOCK on exception to the same EL
  target/arm: Load gcs record for RET with PAuth
  target/arm: Load gcs record for RET
  target/arm: Add gcs record for BLR with PAuth
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson
2025-10-10 08:26:09 -07:00
48 changed files with 2810 additions and 610 deletions
-3
View File
@@ -90,9 +90,6 @@
*/
QEMU_BUILD_BUG_ON(sizeof(vaddr) > sizeof(run_on_cpu_data));
/* We currently can't handle more than 16 bits in the MMUIDX bitmask.
*/
QEMU_BUILD_BUG_ON(NB_MMU_MODES > 16);
#define ALL_MMUIDX_BITS ((1 << NB_MMU_MODES) - 1)
static inline size_t tlb_n_entries(CPUTLBDescFast *fast)
+7
View File
@@ -28,6 +28,7 @@ the following architecture extensions:
- FEAT_BF16 (AArch64 BFloat16 instructions)
- FEAT_BTI (Branch Target Identification)
- FEAT_CCIDX (Extended cache index)
- FEAT_CHK (Check Feature Status)
- FEAT_CMOW (Control for cache maintenance permission)
- FEAT_CRC32 (CRC32 instructions)
- FEAT_Crypto (Cryptographic Extension)
@@ -72,6 +73,7 @@ the following architecture extensions:
- FEAT_FRINTTS (Floating-point to integer instructions)
- FEAT_FlagM (Flag manipulation instructions v2)
- FEAT_FlagM2 (Enhancements to flag manipulation instructions)
- FEAT_GCS (Guarded Control Stack Extension)
- FEAT_GTG (Guest translation granule size)
- FEAT_HAFDBS (Hardware management of the access flag and dirty bit state)
- FEAT_HBC (Hinted conditional branches)
@@ -92,6 +94,9 @@ the following architecture extensions:
- FEAT_LSE2 (Large System Extensions v2)
- FEAT_LSE128 (128-bit Atomics)
- FEAT_LVA (Large Virtual Address space)
- FEAT_MEC (Memory Encryption Contexts)
* This is a register-only implementation without encryption.
- FEAT_MixedEnd (Mixed-endian support)
- FEAT_MixedEndEL0 (Mixed-endian support at EL0)
- FEAT_MOPS (Standardization of memory operations)
@@ -123,6 +128,8 @@ the following architecture extensions:
- FEAT_RME_GPC2 (RME Granule Protection Check 2 Extension)
- FEAT_RNG (Random number generator)
- FEAT_RPRES (Increased precision of FRECPE and FRSQRTE)
- FEAT_S1PIE (Stage 1 permission indirections)
- FEAT_S2PIE (Stage 2 permission indirections)
- FEAT_S2FWB (Stage 2 forced Write-Back)
- FEAT_SB (Speculation Barrier)
- FEAT_SCTLR2 (Extension to SCTLR_ELx)
+5 -4
View File
@@ -25,9 +25,10 @@ typedef uint32_t MemOpIdx;
static inline MemOpIdx make_memop_idx(MemOp op, unsigned idx)
{
#ifdef CONFIG_DEBUG_TCG
assert(idx <= 15);
assert(idx <= 31);
assert(clz32(op) >= 5);
#endif
return (op << 4) | idx;
return (op << 5) | idx;
}
/**
@@ -38,7 +39,7 @@ static inline MemOpIdx make_memop_idx(MemOp op, unsigned idx)
*/
static inline MemOp get_memop(MemOpIdx oi)
{
return oi >> 4;
return oi >> 5;
}
/**
@@ -49,7 +50,7 @@ static inline MemOp get_memop(MemOpIdx oi)
*/
static inline unsigned get_mmuidx(MemOpIdx oi)
{
return oi & 15;
return oi & 31;
}
#endif
+4 -3
View File
@@ -198,10 +198,11 @@ struct CPUClass {
};
/*
* Fix the number of mmu modes to 16.
* Fix the number of mmu modes across all targets.
* Current maximum is target/arm/.
*/
#define NB_MMU_MODES 16
typedef uint16_t MMUIdxMap;
#define NB_MMU_MODES 22
typedef uint32_t MMUIdxMap;
/* Use a fully associative victim tlb of 8 entries. */
#define CPU_VTLB_SIZE 8
+5
View File
@@ -89,6 +89,11 @@ static void signal_for_exception(CPUARMState *env, vaddr addr)
si_code = TARGET_ILL_ILLOPN;
break;
case EC_GCS:
si_signo = TARGET_SIGSEGV;
si_code = TARGET_SEGV_CPERR;
break;
case EC_MOP:
/*
* FIXME: The kernel fixes up wrong-option exceptions.
+1
View File
@@ -169,6 +169,7 @@ abi_ulong get_elf_hwcap(CPUState *cs)
GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC);
GET_FEATURE_ID(aa64_gcs, ARM_HWCAP_A64_GCS);
return hwcaps;
}
+38
View File
@@ -0,0 +1,38 @@
/*
* AArch64 gcs functions for linux-user
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef AARCH64_GCS_INTERNAL_H
#define AARCH64_GCS_INTERNAL_H
#ifndef PR_SHADOW_STACK_ENABLE
# define PR_SHADOW_STACK_ENABLE (1U << 0)
# define PR_SHADOW_STACK_WRITE (1U << 1)
# define PR_SHADOW_STACK_PUSH (1U << 2)
#endif
static inline uint64_t gcs_get_el0_mode(CPUArchState *env)
{
uint64_t cr = env->cp15.gcscr_el[0];
abi_ulong flags = 0;
flags |= cr & GCSCR_PCRSEL ? PR_SHADOW_STACK_ENABLE : 0;
flags |= cr & GCSCR_STREN ? PR_SHADOW_STACK_WRITE : 0;
flags |= cr & GCSCR_PUSHMEN ? PR_SHADOW_STACK_PUSH : 0;
return flags;
}
static inline void gcs_set_el0_mode(CPUArchState *env, uint64_t flags)
{
uint64_t cr = GCSCRE0_NTR;
cr |= flags & PR_SHADOW_STACK_ENABLE ? GCSCR_RVCHKEN | GCSCR_PCRSEL : 0;
cr |= flags & PR_SHADOW_STACK_WRITE ? GCSCR_STREN : 0;
cr |= flags & PR_SHADOW_STACK_PUSH ? GCSCR_PUSHMEN : 0;
env->cp15.gcscr_el[0] = cr;
}
#endif
+132 -6
View File
@@ -22,6 +22,7 @@
#include "signal-common.h"
#include "linux-user/trace.h"
#include "target/arm/cpu-features.h"
#include "gcs-internal.h"
struct target_sigcontext {
uint64_t fault_address;
@@ -152,6 +153,16 @@ struct target_zt_context {
QEMU_BUILD_BUG_ON(TARGET_ZT_SIG_REG_BYTES != \
sizeof_field(CPUARMState, za_state.zt0));
#define TARGET_GCS_MAGIC 0x47435300
#define GCS_SIGNAL_CAP(X) ((X) & TARGET_PAGE_MASK)
struct target_gcs_context {
struct target_aarch64_ctx head;
uint64_t gcspr;
uint64_t features_enabled;
uint64_t reserved;
};
struct target_rt_sigframe {
struct target_siginfo info;
struct target_ucontext uc;
@@ -322,6 +333,35 @@ static void target_setup_zt_record(struct target_zt_context *zt,
}
}
static bool target_setup_gcs_record(struct target_gcs_context *ctx,
CPUARMState *env, uint64_t return_addr)
{
uint64_t mode = gcs_get_el0_mode(env);
uint64_t gcspr = env->cp15.gcspr_el[0];
if (mode & PR_SHADOW_STACK_ENABLE) {
/* Push a cap for the signal frame. */
gcspr -= 8;
if (put_user_u64(GCS_SIGNAL_CAP(gcspr), gcspr)) {
return false;
}
/* Push a gcs entry for the trampoline. */
if (put_user_u64(return_addr, gcspr - 8)) {
return false;
}
env->cp15.gcspr_el[0] = gcspr - 8;
}
__put_user(TARGET_GCS_MAGIC, &ctx->head.magic);
__put_user(sizeof(*ctx), &ctx->head.size);
__put_user(gcspr, &ctx->gcspr);
__put_user(mode, &ctx->features_enabled);
__put_user(0, &ctx->reserved);
return true;
}
static void target_restore_general_frame(CPUARMState *env,
struct target_rt_sigframe *sf)
{
@@ -502,6 +542,64 @@ static bool target_restore_zt_record(CPUARMState *env,
return true;
}
static bool target_restore_gcs_record(CPUARMState *env,
struct target_gcs_context *ctx,
bool *rebuild_hflags)
{
TaskState *ts = get_task_state(env_cpu(env));
uint64_t cur_mode = gcs_get_el0_mode(env);
uint64_t new_mode, gcspr;
__get_user(new_mode, &ctx->features_enabled);
__get_user(gcspr, &ctx->gcspr);
/*
* The kernel pushes the value through the hw register:
* write_sysreg_s(gcspr, SYS_GCSPR_EL0) in restore_gcs_context,
* then read_sysreg_s(SYS_GCSPR_EL0) in gcs_restore_signal.
* Since the bottom 3 bits are RES0, this can (CONSTRAINED UNPREDICTABLE)
* force align the value. Mirror the choice from gcspr_write().
*/
gcspr &= ~7;
if (new_mode & ~(PR_SHADOW_STACK_ENABLE |
PR_SHADOW_STACK_WRITE |
PR_SHADOW_STACK_PUSH)) {
return false;
}
if ((new_mode ^ cur_mode) & ts->gcs_el0_locked) {
return false;
}
if (new_mode & ~cur_mode & PR_SHADOW_STACK_ENABLE) {
return false;
}
if (new_mode & PR_SHADOW_STACK_ENABLE) {
uint64_t cap;
/* Pop and clear the signal cap. */
if (get_user_u64(cap, gcspr)) {
return false;
}
if (cap != GCS_SIGNAL_CAP(gcspr)) {
return false;
}
if (put_user_u64(0, gcspr)) {
return false;
}
gcspr += 8;
} else {
new_mode = 0;
}
env->cp15.gcspr_el[0] = gcspr;
if (new_mode != cur_mode) {
*rebuild_hflags = true;
gcs_set_el0_mode(env, new_mode);
}
return true;
}
static int target_restore_sigframe(CPUARMState *env,
struct target_rt_sigframe *sf)
{
@@ -511,8 +609,10 @@ static int target_restore_sigframe(CPUARMState *env,
struct target_za_context *za = NULL;
struct target_tpidr2_context *tpidr2 = NULL;
struct target_zt_context *zt = NULL;
struct target_gcs_context *gcs = NULL;
uint64_t extra_datap = 0;
bool used_extra = false;
bool rebuild_hflags = false;
int sve_size = 0;
int za_size = 0;
int zt_size = 0;
@@ -582,6 +682,15 @@ static int target_restore_sigframe(CPUARMState *env,
zt_size = size;
break;
case TARGET_GCS_MAGIC:
if (gcs
|| size != sizeof(struct target_gcs_context)
|| !cpu_isar_feature(aa64_gcs, env_archcpu(env))) {
goto err;
}
gcs = (struct target_gcs_context *)ctx;
break;
case TARGET_EXTRA_MAGIC:
if (extra || size != sizeof(struct target_extra_context)) {
goto err;
@@ -612,6 +721,10 @@ static int target_restore_sigframe(CPUARMState *env,
goto err;
}
if (gcs && !target_restore_gcs_record(env, gcs, &rebuild_hflags)) {
goto err;
}
/* SVE data, if present, overwrites FPSIMD data. */
if (sve && !target_restore_sve_record(env, sve, sve_size, &svcr)) {
goto err;
@@ -631,6 +744,9 @@ static int target_restore_sigframe(CPUARMState *env,
}
if (env->svcr != svcr) {
env->svcr = svcr;
rebuild_hflags = true;
}
if (rebuild_hflags) {
arm_rebuild_hflags(env);
}
unlock_user(extra, extra_datap, 0);
@@ -701,7 +817,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
uc.tuc_mcontext.__reserved),
};
int fpsimd_ofs, fr_ofs, sve_ofs = 0, za_ofs = 0, tpidr2_ofs = 0;
int zt_ofs = 0, esr_ofs = 0;
int zt_ofs = 0, esr_ofs = 0, gcs_ofs = 0;
int sve_size = 0, za_size = 0, tpidr2_size = 0, zt_size = 0;
struct target_rt_sigframe *frame;
struct target_rt_frame_record *fr;
@@ -720,6 +836,11 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
&layout);
}
if (env->cp15.gcspr_el[0]) {
gcs_ofs = alloc_sigframe_space(sizeof(struct target_gcs_context),
&layout);
}
/* SVE state needs saving only if it exists. */
if (cpu_isar_feature(aa64_sve, env_archcpu(env)) ||
cpu_isar_feature(aa64_sme, env_archcpu(env))) {
@@ -779,6 +900,12 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
goto give_sigsegv;
}
if (ka->sa_flags & TARGET_SA_RESTORER) {
return_addr = ka->sa_restorer;
} else {
return_addr = default_rt_sigreturn;
}
target_setup_general_frame(frame, env, set);
target_setup_fpsimd_record((void *)frame + fpsimd_ofs, env);
if (esr_ofs) {
@@ -786,6 +913,10 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
/* Leave ESR_EL1 clear while it's not relevant. */
env->cp15.esr_el[1] = 0;
}
if (gcs_ofs &&
!target_setup_gcs_record((void *)frame + gcs_ofs, env, return_addr)) {
goto give_sigsegv;
}
target_setup_end_record((void *)frame + layout.std_end_ofs);
if (layout.extra_ofs) {
target_setup_extra_record((void *)frame + layout.extra_ofs,
@@ -811,11 +942,6 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
__put_user(env->xregs[29], &fr->fp);
__put_user(env->xregs[30], &fr->lr);
if (ka->sa_flags & TARGET_SA_RESTORER) {
return_addr = ka->sa_restorer;
} else {
return_addr = default_rt_sigreturn;
}
env->xregs[0] = usig;
env->xregs[29] = frame_addr + fr_ofs;
env->xregs[30] = return_addr;
+96
View File
@@ -6,8 +6,10 @@
#ifndef AARCH64_TARGET_PRCTL_H
#define AARCH64_TARGET_PRCTL_H
#include "qemu/units.h"
#include "target/arm/cpu-features.h"
#include "mte_user_helper.h"
#include "gcs-internal.h"
static abi_long do_prctl_sve_get_vl(CPUArchState *env)
{
@@ -206,4 +208,98 @@ static abi_long do_prctl_get_tagged_addr_ctrl(CPUArchState *env)
}
#define do_prctl_get_tagged_addr_ctrl do_prctl_get_tagged_addr_ctrl
static abi_long do_prctl_get_shadow_stack_status(CPUArchState *env,
abi_long arg2)
{
ARMCPU *cpu = env_archcpu(env);
if (!cpu_isar_feature(aa64_gcs, cpu)) {
return -TARGET_EINVAL;
}
return put_user_ual(gcs_get_el0_mode(env), arg2);
}
#define do_prctl_get_shadow_stack_status do_prctl_get_shadow_stack_status
static abi_long gcs_alloc(abi_ulong hint, abi_ulong size)
{
/*
* Without softmmu, we cannot protect GCS memory properly.
* Make do with normal read/write permissions. This at least allows
* emulation of correct programs which don't access the gcs stack
* with normal instructions.
*/
return target_mmap(hint, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS |
(hint ? MAP_FIXED_NOREPLACE : 0), -1, 0);
}
static abi_ulong gcs_new_stack(TaskState *ts)
{
/* Use guest_stack_size as a proxy for RLIMIT_STACK. */
abi_ulong size = MIN(MAX(guest_stack_size / 2, TARGET_PAGE_SIZE), 2 * GiB);
abi_ulong base = gcs_alloc(0, size);
if (base == -1) {
return -1;
}
ts->gcs_base = base;
ts->gcs_size = size;
return base + size - 8;
}
static abi_long do_prctl_set_shadow_stack_status(CPUArchState *env,
abi_long new_mode)
{
ARMCPU *cpu = env_archcpu(env);
TaskState *ts = get_task_state(env_cpu(env));
abi_long cur_mode;
if (!cpu_isar_feature(aa64_gcs, cpu)) {
return -TARGET_EINVAL;
}
if (new_mode & ~(PR_SHADOW_STACK_ENABLE |
PR_SHADOW_STACK_WRITE |
PR_SHADOW_STACK_PUSH)) {
return -TARGET_EINVAL;
}
cur_mode = gcs_get_el0_mode(env);
if ((new_mode ^ cur_mode) & ts->gcs_el0_locked) {
return -TARGET_EBUSY;
}
if (new_mode & ~cur_mode & PR_SHADOW_STACK_ENABLE) {
abi_long gcspr;
if (ts->gcs_base || env->cp15.gcspr_el[0]) {
return -EINVAL;
}
gcspr = gcs_new_stack(ts);
if (gcspr == -1) {
return -TARGET_ENOMEM;
}
env->cp15.gcspr_el[0] = gcspr;
}
gcs_set_el0_mode(env, new_mode);
arm_rebuild_hflags(env);
return 0;
}
#define do_prctl_set_shadow_stack_status do_prctl_set_shadow_stack_status
static abi_long do_prctl_lock_shadow_stack_status(CPUArchState *env,
abi_long arg2)
{
ARMCPU *cpu = env_archcpu(env);
TaskState *ts = get_task_state(env_cpu(env));
if (!cpu_isar_feature(aa64_gcs, cpu)) {
return -EINVAL;
}
ts->gcs_el0_locked |= arg2;
return 0;
}
#define do_prctl_lock_shadow_stack_status do_prctl_lock_shadow_stack_status
#endif /* AARCH64_TARGET_PRCTL_H */
+1
View File
@@ -7,6 +7,7 @@
#define TARGET_SEGV_MTEAERR 8 /* Asynchronous ARM MTE error */
#define TARGET_SEGV_MTESERR 9 /* Synchronous ARM MTE exception */
#define TARGET_SEGV_CPERR 10 /* Control protection fault */
#define TARGET_ARCH_HAS_SETUP_FRAME
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
+5
View File
@@ -121,6 +121,11 @@ struct TaskState {
abi_ulong child_tidptr;
#ifdef TARGET_M68K
abi_ulong tp_value;
#endif
#if defined(TARGET_AARCH64)
vaddr gcs_base;
abi_ulong gcs_size;
abi_ulong gcs_el0_locked;
#endif
int used; /* non zero if used */
struct image_info *info;
+114
View File
@@ -6353,6 +6353,17 @@ abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
# define PR_SME_VL_LEN_MASK 0xffff
# define PR_SME_VL_INHERIT (1 << 17)
#endif
#ifndef PR_GET_SHADOW_STACK_STATUS
# define PR_GET_SHADOW_STACK_STATUS 74
# define PR_SET_SHADOW_STACK_STATUS 75
# define PR_LOCK_SHADOW_STACK_STATUS 76
#endif
#ifndef SHADOW_STACK_SET_TOKEN
# define SHADOW_STACK_SET_TOKEN (1u << 0)
#endif
#ifndef SHADOW_STACK_SET_MARKER
# define SHADOW_STACK_SET_MARKER (1u << 1)
#endif
#include "target_prctl.h"
@@ -6399,6 +6410,15 @@ static abi_long do_prctl_inval1(CPUArchState *env, abi_long arg2)
#ifndef do_prctl_sme_set_vl
#define do_prctl_sme_set_vl do_prctl_inval1
#endif
#ifndef do_prctl_get_shadow_stack_status
#define do_prctl_get_shadow_stack_status do_prctl_inval1
#endif
#ifndef do_prctl_set_shadow_stack_status
#define do_prctl_set_shadow_stack_status do_prctl_inval1
#endif
#ifndef do_prctl_lock_shadow_stack_status
#define do_prctl_lock_shadow_stack_status do_prctl_inval1
#endif
static abi_long do_prctl_syscall_user_dispatch(CPUArchState *env,
abi_ulong arg2, abi_ulong arg3,
@@ -6499,6 +6519,21 @@ static abi_long do_prctl(CPUArchState *env, abi_long option, abi_long arg2,
return -TARGET_EINVAL;
}
return do_prctl_get_tagged_addr_ctrl(env);
case PR_GET_SHADOW_STACK_STATUS:
if (arg3 || arg4 || arg5) {
return -TARGET_EINVAL;
}
return do_prctl_get_shadow_stack_status(env, arg2);
case PR_SET_SHADOW_STACK_STATUS:
if (arg3 || arg4 || arg5) {
return -TARGET_EINVAL;
}
return do_prctl_set_shadow_stack_status(env, arg2);
case PR_LOCK_SHADOW_STACK_STATUS:
if (arg3 || arg4 || arg5) {
return -TARGET_EINVAL;
}
return do_prctl_lock_shadow_stack_status(env, arg2);
case PR_GET_UNALIGN:
return do_prctl_get_unalign(env, arg2);
@@ -6576,6 +6611,54 @@ static abi_long do_prctl(CPUArchState *env, abi_long option, abi_long arg2,
}
}
#ifdef TARGET_AARCH64
static abi_long do_map_shadow_stack(CPUArchState *env, abi_ulong addr,
abi_ulong size, abi_int flags)
{
ARMCPU *cpu = env_archcpu(env);
abi_ulong alloc_size;
if (!cpu_isar_feature(aa64_gcs, cpu)) {
return -TARGET_EOPNOTSUPP;
}
if (flags & ~(SHADOW_STACK_SET_TOKEN | SHADOW_STACK_SET_MARKER)) {
return -TARGET_EINVAL;
}
if (addr & ~TARGET_PAGE_MASK) {
return -TARGET_EINVAL;
}
if (size == 8 || !QEMU_IS_ALIGNED(size, 8)) {
return -TARGET_EINVAL;
}
alloc_size = TARGET_PAGE_ALIGN(size);
if (alloc_size < size) {
return -TARGET_EOVERFLOW;
}
mmap_lock();
addr = gcs_alloc(addr, alloc_size);
if (addr != -1) {
if (flags & SHADOW_STACK_SET_TOKEN) {
abi_ptr cap_ptr = addr + size - 8;
uint64_t cap_val;
if (flags & SHADOW_STACK_SET_MARKER) {
/* Leave an extra empty frame at top-of-stack. */
cap_ptr -= 8;
}
cap_val = (cap_ptr & TARGET_PAGE_MASK) | 1;
if (put_user_u64(cap_val, cap_ptr)) {
/* Allocation succeeded above. */
g_assert_not_reached();
}
}
}
mmap_unlock();
return get_errno(addr);
}
#endif
#define NEW_STACK_SIZE 0x40000
@@ -6657,6 +6740,21 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
ts = g_new0(TaskState, 1);
init_task_state(ts);
#ifdef TARGET_AARCH64
/*
* If GCS is enabled in the parent thread, it is also enabled
* in the child thread, but with a newly allocated stack.
*/
abi_long new_gcspr = 0;
if (env->cp15.gcscr_el[0] & GCSCR_PCRSEL) {
new_gcspr = gcs_new_stack(ts);
if (new_gcspr == -1) {
g_free(ts);
return -TARGET_ENOMEM;
}
}
#endif
/* Grab a mutex so that thread setup appears atomic. */
pthread_mutex_lock(&clone_lock);
@@ -6678,6 +6776,11 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
ts->info = parent_ts->info;
ts->signal_mask = parent_ts->signal_mask;
#ifdef TARGET_AARCH64
ts->gcs_el0_locked = parent_ts->gcs_el0_locked;
new_env->cp15.gcspr_el[0] = new_gcspr;
#endif
if (flags & CLONE_CHILD_CLEARTID) {
ts->child_tidptr = child_tidptr;
}
@@ -9380,6 +9483,12 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
}
#ifdef TARGET_AARCH64
if (ts->gcs_base) {
target_munmap(ts->gcs_base, ts->gcs_size);
}
#endif
object_unparent(OBJECT(cpu));
object_unref(OBJECT(cpu));
/*
@@ -14010,6 +14119,11 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
return do_riscv_hwprobe(cpu_env, arg1, arg2, arg3, arg4, arg5);
#endif
#ifdef TARGET_AARCH64
case TARGET_NR_map_shadow_stack:
return do_map_shadow_stack(cpu_env, arg1, arg2, arg3);
#endif
default:
qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
return -TARGET_ENOSYS;
+156
View File
@@ -0,0 +1,156 @@
/*
* QEMU ARM CP Register GCS regiters and instructions
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/timer.h"
#include "exec/icount.h"
#include "hw/irq.h"
#include "cpu.h"
#include "cpu-features.h"
#include "cpregs.h"
#include "internals.h"
static CPAccessResult access_gcs(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
if (arm_current_el(env) < 3
&& arm_feature(env, ARM_FEATURE_EL3)
&& !(env->cp15.scr_el3 & SCR_GCSEN)) {
return CP_ACCESS_TRAP_EL3;
}
return CP_ACCESS_OK;
}
static CPAccessResult access_gcs_el0(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
if (arm_current_el(env) == 0 && !(env->cp15.gcscr_el[0] & GCSCRE0_NTR)) {
return CP_ACCESS_TRAP_EL1;
}
return access_gcs(env, ri, isread);
}
static void gcspr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/*
* Bits [2:0] are RES0, so we might as well clear them now,
* rather than upon each usage a-la GetCurrentGCSPointer.
*/
raw_write(env, ri, value & ~7);
}
static CPAccessResult access_gcspushm(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
int el = arm_current_el(env);
if (!(env->cp15.gcscr_el[el] & GCSCR_PUSHMEN)) {
return CP_ACCESS_TRAP_BIT | (el ? el : 1);
}
return CP_ACCESS_OK;
}
static CPAccessResult access_gcspushx(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
/* Trap if lock taken, and enabled. */
if (!(env->pstate & PSTATE_EXLOCK)) {
int el = arm_current_el(env);
if (env->cp15.gcscr_el[el] & GCSCR_EXLOCKEN) {
return CP_ACCESS_EXLOCK;
}
}
return CP_ACCESS_OK;
}
static CPAccessResult access_gcspopcx(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
/* Trap if lock not taken, and enabled. */
if (env->pstate & PSTATE_EXLOCK) {
int el = arm_current_el(env);
if (env->cp15.gcscr_el[el] & GCSCR_EXLOCKEN) {
return CP_ACCESS_EXLOCK;
}
}
return CP_ACCESS_OK;
}
static const ARMCPRegInfo gcs_reginfo[] = {
{ .name = "GCSCRE0_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 5, .opc2 = 2,
.access = PL1_RW, .accessfn = access_gcs, .fgt = FGT_NGCS_EL0,
.fieldoffset = offsetof(CPUARMState, cp15.gcscr_el[0]) },
{ .name = "GCSCR_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 5, .opc2 = 0,
.access = PL1_RW, .accessfn = access_gcs, .fgt = FGT_NGCS_EL1,
.nv2_redirect_offset = 0x8d0 | NV2_REDIR_NV1,
.vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 5, 0),
.vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 5, 0),
.fieldoffset = offsetof(CPUARMState, cp15.gcscr_el[1]) },
{ .name = "GCSCR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 5, .opc2 = 0,
.access = PL2_RW, .accessfn = access_gcs,
.fieldoffset = offsetof(CPUARMState, cp15.gcscr_el[2]) },
{ .name = "GCSCR_EL3", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 6, .crn = 2, .crm = 5, .opc2 = 0,
.access = PL3_RW,
.fieldoffset = offsetof(CPUARMState, cp15.gcscr_el[3]) },
{ .name = "GCSPR_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 2, .crm = 5, .opc2 = 1,
.access = PL0_R | PL1_W, .accessfn = access_gcs_el0,
.fgt = FGT_NGCS_EL0, .writefn = gcspr_write,
.fieldoffset = offsetof(CPUARMState, cp15.gcspr_el[0]) },
{ .name = "GCSPR_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 5, .opc2 = 1,
.access = PL1_RW, .accessfn = access_gcs,
.fgt = FGT_NGCS_EL1, .writefn = gcspr_write,
.nv2_redirect_offset = 0x8c0 | NV2_REDIR_NV1,
.vhe_redir_to_el2 = ENCODE_AA64_CP_REG(3, 4, 2, 5, 1),
.vhe_redir_to_el01 = ENCODE_AA64_CP_REG(3, 5, 2, 5, 1),
.fieldoffset = offsetof(CPUARMState, cp15.gcspr_el[1]) },
{ .name = "GCSPR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 5, .opc2 = 1,
.access = PL2_RW, .accessfn = access_gcs, .writefn = gcspr_write,
.fieldoffset = offsetof(CPUARMState, cp15.gcspr_el[2]) },
{ .name = "GCSPR_EL3", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 6, .crn = 2, .crm = 5, .opc2 = 1,
.access = PL3_RW, .writefn = gcspr_write,
.fieldoffset = offsetof(CPUARMState, cp15.gcspr_el[2]) },
{ .name = "GCSPUSHM", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 7, .opc2 = 0,
.access = PL0_W, .accessfn = access_gcspushm,
.fgt = FGT_NGCSPUSHM_EL1, .type = ARM_CP_GCSPUSHM },
{ .name = "GCSPOPM", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 7, .opc2 = 1,
.access = PL0_R, .type = ARM_CP_GCSPOPM },
{ .name = "GCSSS1", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 7, .opc2 = 2,
.access = PL0_W, .type = ARM_CP_GCSSS1 },
{ .name = "GCSSS2", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 7, .opc2 = 3,
.access = PL0_R, .type = ARM_CP_GCSSS2 },
{ .name = "GCSPUSHX", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 7, .opc2 = 4,
.access = PL1_W, .accessfn = access_gcspushx, .fgt = FGT_NGCSEPP,
.type = ARM_CP_GCSPUSHX },
{ .name = "GCSPOPCX", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 7, .opc2 = 5,
.access = PL1_W, .accessfn = access_gcspopcx, .fgt = FGT_NGCSEPP,
.type = ARM_CP_GCSPOPCX },
{ .name = "GCSPOPX", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 7, .opc2 = 6,
.access = PL1_W, .type = ARM_CP_GCSPOPX },
};
void define_gcs_cpregs(ARMCPU *cpu)
{
if (cpu_isar_feature(aa64_gcs, cpu)) {
define_arm_cp_regs(cpu, gcs_reginfo);
}
}
+37 -5
View File
@@ -47,6 +47,14 @@ enum {
ARM_CP_DC_ZVA = 0x0005,
ARM_CP_DC_GVA = 0x0006,
ARM_CP_DC_GZVA = 0x0007,
/* Special: gcs instructions */
ARM_CP_GCSPUSHM = 0x0008,
ARM_CP_GCSPOPM = 0x0009,
ARM_CP_GCSPUSHX = 0x000a,
ARM_CP_GCSPOPX = 0x000b,
ARM_CP_GCSPOPCX = 0x000c,
ARM_CP_GCSSS1 = 0x000d,
ARM_CP_GCSSS2 = 0x000e,
/* Flag: reads produce resetvalue; writes ignored. */
ARM_CP_CONST = 1 << 4,
@@ -136,6 +144,11 @@ enum {
* identically to the normal one, other than FGT trapping handling.)
*/
ARM_CP_ADD_TLBI_NXS = 1 << 21,
/*
* Flag: even though this sysreg has opc1 == 4 or 5, it
* should not trap to EL2 when HCR_EL2.NV is set.
*/
ARM_CP_NV_NO_TRAP = 1 << 22,
};
/*
@@ -351,6 +364,14 @@ typedef enum CPAccessResult {
* specified target EL.
*/
CP_ACCESS_UNDEFINED = (2 << 2),
/*
* Access fails with EXLOCK, a GCS exception syndrome.
* These traps are always to the current execution EL,
* which is the same as the usual target EL because
* they cannot occur from EL0.
*/
CP_ACCESS_EXLOCK = (3 << 2),
} CPAccessResult;
/* Indexes into fgt_read[] */
@@ -779,8 +800,12 @@ typedef enum FGTBit {
DO_BIT(HFGRTR, VBAR_EL1),
DO_BIT(HFGRTR, ICC_IGRPENN_EL1),
DO_BIT(HFGRTR, ERRIDR_EL1),
DO_REV_BIT(HFGRTR, NGCS_EL0),
DO_REV_BIT(HFGRTR, NGCS_EL1),
DO_REV_BIT(HFGRTR, NSMPRI_EL1),
DO_REV_BIT(HFGRTR, NTPIDR2_EL0),
DO_REV_BIT(HFGRTR, NPIRE0_EL1),
DO_REV_BIT(HFGRTR, NPIR_EL1),
/* Trap bits in HDFGRTR_EL2 / HDFGWTR_EL2, starting from bit 0. */
DO_BIT(HDFGRTR, DBGBCRN_EL1),
@@ -859,6 +884,8 @@ typedef enum FGTBit {
DO_BIT(HFGITR, DVPRCTX),
DO_BIT(HFGITR, CPPRCTX),
DO_BIT(HFGITR, DCCVAC),
DO_REV_BIT(HFGITR, NGCSPUSHM_EL1),
DO_REV_BIT(HFGITR, NGCSEPP),
DO_BIT(HFGITR, ATS1E1A),
} FGTBit;
@@ -1156,12 +1183,17 @@ static inline bool arm_cpreg_traps_in_nv(const ARMCPRegInfo *ri)
* fragile to future new sysregs, but this seems the least likely
* to break.
*
* In particular, note that the released sysreg XML defines that
* the FEAT_MEC sysregs and instructions do not follow this FEAT_NV
* trapping rule, so we will need to add an ARM_CP_* flag to indicate
* "register does not trap on NV" to handle those if/when we implement
* FEAT_MEC.
* In particular, note that the FEAT_MEC sysregs and instructions
* are exceptions to this trapping rule, so they are marked as
* ARM_CP_NV_NO_TRAP to indicate that they should not be trapped
* to EL2. (They are an exception because the FEAT_MEC sysregs UNDEF
* unless in Realm, and Realm is not expected to be virtualized.)
*/
if (ri->type & ARM_CP_NV_NO_TRAP) {
return false;
}
return ri->opc1 == 4 || ri->opc1 == 5;
}
+20
View File
@@ -1149,6 +1149,11 @@ static inline bool isar_feature_aa64_nmi(const ARMISARegisters *id)
return FIELD_EX64_IDREG(id, ID_AA64PFR1, NMI) != 0;
}
static inline bool isar_feature_aa64_gcs(const ARMISARegisters *id)
{
return FIELD_EX64_IDREG(id, ID_AA64PFR1, GCS) != 0;
}
static inline bool isar_feature_aa64_tgran4_lpa2(const ARMISARegisters *id)
{
return FIELD_SEX64_IDREG(id, ID_AA64MMFR0, TGRAN4) >= 1;
@@ -1349,6 +1354,21 @@ static inline bool isar_feature_aa64_sctlr2(const ARMISARegisters *id)
return FIELD_EX64_IDREG(id, ID_AA64MMFR3, SCTLRX) != 0;
}
static inline bool isar_feature_aa64_s1pie(const ARMISARegisters *id)
{
return FIELD_EX64_IDREG(id, ID_AA64MMFR3, S1PIE) != 0;
}
static inline bool isar_feature_aa64_s2pie(const ARMISARegisters *id)
{
return FIELD_EX64_IDREG(id, ID_AA64MMFR3, S2PIE) != 0;
}
static inline bool isar_feature_aa64_mec(const ARMISARegisters *id)
{
return FIELD_EX64_IDREG(id, ID_AA64MMFR3, MEC) != 0;
}
static inline bool isar_feature_aa64_pmuv3p1(const ARMISARegisters *id)
{
return FIELD_EX64_IDREG(id, ID_AA64DFR0, PMUVER) >= 4 &&
+17 -3
View File
@@ -311,6 +311,10 @@ static void arm_cpu_reset_hold(Object *obj, ResetType type)
env->cp15.mdscr_el1 |= 1 << 12;
/* Enable FEAT_MOPS */
env->cp15.sctlr_el[1] |= SCTLR_MSCEN;
/* For Linux, GCSPR_EL0 is always readable. */
if (cpu_isar_feature(aa64_gcs, cpu)) {
env->cp15.gcscr_el[0] = GCSCRE0_NTR;
}
#else
/* Reset into the highest available EL */
if (arm_feature(env, ARM_FEATURE_EL3)) {
@@ -635,12 +639,22 @@ void arm_emulate_firmware_reset(CPUState *cpustate, int target_el)
if (cpu_isar_feature(aa64_fgt, cpu)) {
env->cp15.scr_el3 |= SCR_FGTEN;
}
if (cpu_isar_feature(aa64_gcs, cpu)) {
env->cp15.scr_el3 |= SCR_GCSEN;
}
if (cpu_isar_feature(aa64_tcr2, cpu)) {
env->cp15.scr_el3 |= SCR_TCR2EN;
}
if (cpu_isar_feature(aa64_sctlr2, cpu)) {
env->cp15.scr_el3 |= SCR_SCTLR2EN;
}
if (cpu_isar_feature(aa64_s1pie, cpu) ||
cpu_isar_feature(aa64_s2pie, cpu)) {
env->cp15.scr_el3 |= SCR_PIEN;
}
if (cpu_isar_feature(aa64_mec, cpu)) {
env->cp15.scr_el3 |= SCR_MECEN;
}
}
if (target_el == 2) {
@@ -819,7 +833,7 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
uint32_t psr = pstate_read(env);
uint64_t psr = pstate_read(env);
int i, j;
int el = arm_current_el(env);
uint64_t hcr = arm_hcr_el2_eff(env);
@@ -841,7 +855,7 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
} else {
ns_status = "";
}
qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
qemu_fprintf(f, "PSTATE=%016" PRIx64 " %c%c%c%c %sEL%d%c",
psr,
psr & PSTATE_N ? 'N' : '-',
psr & PSTATE_Z ? 'Z' : '-',
@@ -858,7 +872,7 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
(FIELD_EX64(env->svcr, SVCR, SM) ? 'S' : '-'));
}
if (cpu_isar_feature(aa64_bti, cpu)) {
qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
qemu_fprintf(f, " BTYPE=%d", (int)(psr & PSTATE_BTYPE) >> 10);
}
qemu_fprintf(f, "%s%s%s",
(hcr & HCR_NV) ? " NV" : "",
+38 -215
View File
@@ -33,6 +33,7 @@
#include "target/arm/multiprocessing.h"
#include "target/arm/gtimer.h"
#include "target/arm/cpu-sysregs.h"
#include "target/arm/mmuidx.h"
#define EXCP_UDEF 1 /* undefined instruction */
#define EXCP_SWI 2 /* software interrupt */
@@ -267,7 +268,7 @@ typedef struct CPUArchState {
uint64_t xregs[32];
uint64_t pc;
/* PSTATE isn't an architectural register for ARMv8. However, it is
* convenient for us to assemble the underlying state into a 32 bit format
* convenient for us to assemble the underlying state into a 64 bit format
* identical to the architectural format used for the SPSR. (This is also
* what the Linux kernel's 'pstate' field in signal handlers and KVM's
* 'pstate' register are.) Of the PSTATE bits:
@@ -279,7 +280,7 @@ typedef struct CPUArchState {
* SM and ZA are kept in env->svcr
* all other bits are stored in their correct places in env->pstate
*/
uint32_t pstate;
uint64_t pstate;
bool aarch64; /* True if CPU is in aarch64 state; inverse of PSTATE.nRW */
bool thumb; /* True if CPU is in thumb mode; cpsr[5] */
@@ -368,6 +369,9 @@ typedef struct CPUArchState {
uint64_t tcr2_el[3];
uint64_t vtcr_el2; /* Virtualization Translation Control. */
uint64_t vstcr_el2; /* Secure Virtualization Translation Control. */
uint64_t pir_el[4]; /* PIRE0_EL1, PIR_EL1, PIR_EL2, PIR_EL3 */
uint64_t pire0_el2;
uint64_t s2pir_el2;
uint32_t c2_data; /* MPU data cacheable bits. */
uint32_t c2_insn; /* MPU instruction cacheable bits. */
union { /* MMU domain access control register
@@ -576,6 +580,18 @@ typedef struct CPUArchState {
/* NV2 register */
uint64_t vncr_el2;
uint64_t gcscr_el[4]; /* GCSCRE0_EL1, GCSCR_EL[123] */
uint64_t gcspr_el[4]; /* GCSPR_EL[0123] */
/* MEC registers */
uint64_t mecid_p0_el2;
uint64_t mecid_a0_el2;
uint64_t mecid_p1_el2;
uint64_t mecid_a1_el2;
uint64_t mecid_rl_a_el3;
uint64_t vmecid_p_el2;
uint64_t vmecid_a_el2;
} cp15;
struct {
@@ -630,13 +646,10 @@ typedef struct CPUArchState {
* entry process.
*/
struct {
uint32_t syndrome; /* AArch64 format syndrome register */
uint32_t fsr; /* AArch32 format fault status register info */
uint64_t syndrome; /* AArch64 format syndrome register */
uint64_t vaddress; /* virtual addr associated with exception, if any */
uint32_t fsr; /* AArch32 format fault status register info */
uint32_t target_el; /* EL the exception should be targeted for */
/* If we implement EL2 we will also need to store information
* about the intermediate physical address for stage 2 faults.
*/
} exception;
/* Information associated with an SError */
@@ -1498,6 +1511,7 @@ void pmu_init(ARMCPU *cpu);
#define PSTATE_C (1U << 29)
#define PSTATE_Z (1U << 30)
#define PSTATE_N (1U << 31)
#define PSTATE_EXLOCK (1ULL << 34)
#define PSTATE_NZCV (PSTATE_N | PSTATE_Z | PSTATE_C | PSTATE_V)
#define PSTATE_DAIF (PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F)
#define CACHED_PSTATE_BITS (PSTATE_NZCV | PSTATE_DAIF | PSTATE_BTYPE)
@@ -1534,7 +1548,7 @@ static inline unsigned int aarch64_pstate_mode(unsigned int el, bool handler)
* interprocessing, so we don't attempt to sync with the cpsr state used by
* the 32 bit decoder.
*/
static inline uint32_t pstate_read(CPUARMState *env)
static inline uint64_t pstate_read(CPUARMState *env)
{
int ZF;
@@ -1544,7 +1558,7 @@ static inline uint32_t pstate_read(CPUARMState *env)
| env->pstate | env->daif | (env->btype << 10);
}
static inline void pstate_write(CPUARMState *env, uint32_t val)
static inline void pstate_write(CPUARMState *env, uint64_t val)
{
env->ZF = (~val) & PSTATE_Z;
env->NF = val;
@@ -1716,13 +1730,24 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
#define SCR_ENAS0 (1ULL << 36)
#define SCR_ADEN (1ULL << 37)
#define SCR_HXEN (1ULL << 38)
#define SCR_GCSEN (1ULL << 39)
#define SCR_TRNDR (1ULL << 40)
#define SCR_ENTP2 (1ULL << 41)
#define SCR_TCR2EN (1ULL << 43)
#define SCR_SCTLR2EN (1ULL << 44)
#define SCR_PIEN (1ULL << 45)
#define SCR_GPF (1ULL << 48)
#define SCR_MECEN (1ULL << 49)
#define SCR_NSE (1ULL << 62)
/* GCSCR_ELx fields */
#define GCSCR_PCRSEL (1ULL << 0)
#define GCSCR_RVCHKEN (1ULL << 5)
#define GCSCR_EXLOCKEN (1ULL << 6)
#define GCSCR_PUSHMEN (1ULL << 8)
#define GCSCR_STREN (1ULL << 9)
#define GCSCRE0_NTR (1ULL << 10)
/* Return the current FPSCR value. */
uint32_t vfp_get_fpscr(CPUARMState *env);
void vfp_set_fpscr(CPUARMState *env, uint32_t val);
@@ -2221,6 +2246,7 @@ static inline bool arm_is_el2_enabled(CPUARMState *env)
*/
uint64_t arm_hcr_el2_eff_secstate(CPUARMState *env, ARMSecuritySpace space);
uint64_t arm_hcr_el2_eff(CPUARMState *env);
uint64_t arm_hcr_el2_nvx_eff(CPUARMState *env);
uint64_t arm_hcrx_el2_eff(CPUARMState *env);
/*
@@ -2300,212 +2326,6 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
#define TYPE_ARM_HOST_CPU "host-" TYPE_ARM_CPU
/* ARM has the following "translation regimes" (as the ARM ARM calls them):
*
* If EL3 is 64-bit:
* + NonSecure EL1 & 0 stage 1
* + NonSecure EL1 & 0 stage 2
* + NonSecure EL2
* + NonSecure EL2 & 0 (ARMv8.1-VHE)
* + Secure EL1 & 0 stage 1
* + Secure EL1 & 0 stage 2 (FEAT_SEL2)
* + Secure EL2 (FEAT_SEL2)
* + Secure EL2 & 0 (FEAT_SEL2)
* + Realm EL1 & 0 stage 1 (FEAT_RME)
* + Realm EL1 & 0 stage 2 (FEAT_RME)
* + Realm EL2 (FEAT_RME)
* + EL3
* If EL3 is 32-bit:
* + NonSecure PL1 & 0 stage 1
* + NonSecure PL1 & 0 stage 2
* + NonSecure PL2
* + Secure PL1 & 0
* (reminder: for 32 bit EL3, Secure PL1 is *EL3*, not EL1.)
*
* For QEMU, an mmu_idx is not quite the same as a translation regime because:
* 1. we need to split the "EL1 & 0" and "EL2 & 0" regimes into two mmu_idxes,
* because they may differ in access permissions even if the VA->PA map is
* the same
* 2. we want to cache in our TLB the full VA->IPA->PA lookup for a stage 1+2
* translation, which means that we have one mmu_idx that deals with two
* concatenated translation regimes [this sort of combined s1+2 TLB is
* architecturally permitted]
* 3. we don't need to allocate an mmu_idx to translations that we won't be
* handling via the TLB. The only way to do a stage 1 translation without
* the immediate stage 2 translation is via the ATS or AT system insns,
* which can be slow-pathed and always do a page table walk.
* The only use of stage 2 translations is either as part of an s1+2
* lookup or when loading the descriptors during a stage 1 page table walk,
* and in both those cases we don't use the TLB.
* 4. we can also safely fold together the "32 bit EL3" and "64 bit EL3"
* translation regimes, because they map reasonably well to each other
* and they can't both be active at the same time.
* 5. we want to be able to use the TLB for accesses done as part of a
* stage1 page table walk, rather than having to walk the stage2 page
* table over and over.
* 6. we need separate EL1/EL2 mmu_idx for handling the Privileged Access
* Never (PAN) bit within PSTATE.
* 7. we fold together most secure and non-secure regimes for A-profile,
* because there are no banked system registers for aarch64, so the
* process of switching between secure and non-secure is
* already heavyweight.
* 8. we cannot fold together Stage 2 Secure and Stage 2 NonSecure,
* because both are in use simultaneously for Secure EL2.
*
* This gives us the following list of cases:
*
* EL0 EL1&0 stage 1+2 (aka NS PL0 PL1&0 stage 1+2)
* EL1 EL1&0 stage 1+2 (aka NS PL1 PL1&0 stage 1+2)
* EL1 EL1&0 stage 1+2 +PAN (aka NS PL1 P1&0 stage 1+2 +PAN)
* EL0 EL2&0
* EL2 EL2&0
* EL2 EL2&0 +PAN
* EL2 (aka NS PL2)
* EL3 (aka AArch32 S PL1 PL1&0)
* AArch32 S PL0 PL1&0 (we call this EL30_0)
* AArch32 S PL1 PL1&0 +PAN (we call this EL30_3_PAN)
* Stage2 Secure
* Stage2 NonSecure
* plus one TLB per Physical address space: S, NS, Realm, Root
*
* for a total of 16 different mmu_idx.
*
* R profile CPUs have an MPU, but can use the same set of MMU indexes
* as A profile. They only need to distinguish EL0 and EL1 (and
* EL2 for cores like the Cortex-R52).
*
* M profile CPUs are rather different as they do not have a true MMU.
* They have the following different MMU indexes:
* User
* Privileged
* User, execution priority negative (ie the MPU HFNMIENA bit may apply)
* Privileged, execution priority negative (ditto)
* If the CPU supports the v8M Security Extension then there are also:
* Secure User
* Secure Privileged
* Secure User, execution priority negative
* Secure Privileged, execution priority negative
*
* The ARMMMUIdx and the mmu index value used by the core QEMU TLB code
* are not quite the same -- different CPU types (most notably M profile
* vs A/R profile) would like to use MMU indexes with different semantics,
* but since we don't ever need to use all of those in a single CPU we
* can avoid having to set NB_MMU_MODES to "total number of A profile MMU
* modes + total number of M profile MMU modes". The lower bits of
* ARMMMUIdx are the core TLB mmu index, and the higher bits are always
* the same for any particular CPU.
* Variables of type ARMMUIdx are always full values, and the core
* index values are in variables of type 'int'.
*
* Our enumeration includes at the end some entries which are not "true"
* mmu_idx values in that they don't have corresponding TLBs and are only
* valid for doing slow path page table walks.
*
* The constant names here are patterned after the general style of the names
* of the AT/ATS operations.
* The values used are carefully arranged to make mmu_idx => EL lookup easy.
* For M profile we arrange them to have a bit for priv, a bit for negpri
* and a bit for secure.
*/
#define ARM_MMU_IDX_A 0x10 /* A profile */
#define ARM_MMU_IDX_NOTLB 0x20 /* does not have a TLB */
#define ARM_MMU_IDX_M 0x40 /* M profile */
/* Meanings of the bits for M profile mmu idx values */
#define ARM_MMU_IDX_M_PRIV 0x1
#define ARM_MMU_IDX_M_NEGPRI 0x2
#define ARM_MMU_IDX_M_S 0x4 /* Secure */
#define ARM_MMU_IDX_TYPE_MASK \
(ARM_MMU_IDX_A | ARM_MMU_IDX_M | ARM_MMU_IDX_NOTLB)
#define ARM_MMU_IDX_COREIDX_MASK 0xf
typedef enum ARMMMUIdx {
/*
* A-profile.
*/
ARMMMUIdx_E10_0 = 0 | ARM_MMU_IDX_A,
ARMMMUIdx_E20_0 = 1 | ARM_MMU_IDX_A,
ARMMMUIdx_E10_1 = 2 | ARM_MMU_IDX_A,
ARMMMUIdx_E20_2 = 3 | ARM_MMU_IDX_A,
ARMMMUIdx_E10_1_PAN = 4 | ARM_MMU_IDX_A,
ARMMMUIdx_E20_2_PAN = 5 | ARM_MMU_IDX_A,
ARMMMUIdx_E2 = 6 | ARM_MMU_IDX_A,
ARMMMUIdx_E3 = 7 | ARM_MMU_IDX_A,
ARMMMUIdx_E30_0 = 8 | ARM_MMU_IDX_A,
ARMMMUIdx_E30_3_PAN = 9 | ARM_MMU_IDX_A,
/*
* Used for second stage of an S12 page table walk, or for descriptor
* loads during first stage of an S1 page table walk. Note that both
* are in use simultaneously for SecureEL2: the security state for
* the S2 ptw is selected by the NS bit from the S1 ptw.
*/
ARMMMUIdx_Stage2_S = 10 | ARM_MMU_IDX_A,
ARMMMUIdx_Stage2 = 11 | ARM_MMU_IDX_A,
/* TLBs with 1-1 mapping to the physical address spaces. */
ARMMMUIdx_Phys_S = 12 | ARM_MMU_IDX_A,
ARMMMUIdx_Phys_NS = 13 | ARM_MMU_IDX_A,
ARMMMUIdx_Phys_Root = 14 | ARM_MMU_IDX_A,
ARMMMUIdx_Phys_Realm = 15 | ARM_MMU_IDX_A,
/*
* These are not allocated TLBs and are used only for AT system
* instructions or for the first stage of an S12 page table walk.
*/
ARMMMUIdx_Stage1_E0 = 0 | ARM_MMU_IDX_NOTLB,
ARMMMUIdx_Stage1_E1 = 1 | ARM_MMU_IDX_NOTLB,
ARMMMUIdx_Stage1_E1_PAN = 2 | ARM_MMU_IDX_NOTLB,
/*
* M-profile.
*/
ARMMMUIdx_MUser = ARM_MMU_IDX_M,
ARMMMUIdx_MPriv = ARM_MMU_IDX_M | ARM_MMU_IDX_M_PRIV,
ARMMMUIdx_MUserNegPri = ARMMMUIdx_MUser | ARM_MMU_IDX_M_NEGPRI,
ARMMMUIdx_MPrivNegPri = ARMMMUIdx_MPriv | ARM_MMU_IDX_M_NEGPRI,
ARMMMUIdx_MSUser = ARMMMUIdx_MUser | ARM_MMU_IDX_M_S,
ARMMMUIdx_MSPriv = ARMMMUIdx_MPriv | ARM_MMU_IDX_M_S,
ARMMMUIdx_MSUserNegPri = ARMMMUIdx_MUserNegPri | ARM_MMU_IDX_M_S,
ARMMMUIdx_MSPrivNegPri = ARMMMUIdx_MPrivNegPri | ARM_MMU_IDX_M_S,
} ARMMMUIdx;
/*
* Bit macros for the core-mmu-index values for each index,
* for use when calling tlb_flush_by_mmuidx() and friends.
*/
#define TO_CORE_BIT(NAME) \
ARMMMUIdxBit_##NAME = 1 << (ARMMMUIdx_##NAME & ARM_MMU_IDX_COREIDX_MASK)
typedef enum ARMMMUIdxBit {
TO_CORE_BIT(E10_0),
TO_CORE_BIT(E20_0),
TO_CORE_BIT(E10_1),
TO_CORE_BIT(E10_1_PAN),
TO_CORE_BIT(E2),
TO_CORE_BIT(E20_2),
TO_CORE_BIT(E20_2_PAN),
TO_CORE_BIT(E3),
TO_CORE_BIT(E30_0),
TO_CORE_BIT(E30_3_PAN),
TO_CORE_BIT(Stage2),
TO_CORE_BIT(Stage2_S),
TO_CORE_BIT(MUser),
TO_CORE_BIT(MPriv),
TO_CORE_BIT(MUserNegPri),
TO_CORE_BIT(MPrivNegPri),
TO_CORE_BIT(MSUser),
TO_CORE_BIT(MSPriv),
TO_CORE_BIT(MSUserNegPri),
TO_CORE_BIT(MSPrivNegPri),
} ARMMMUIdxBit;
#undef TO_CORE_BIT
#define MMU_USER_IDX 0
/* Indexes used when registering address spaces with cpu_address_space_init */
typedef enum ARMASIdx {
ARMASIdx_NS = 0,
@@ -2667,6 +2487,9 @@ FIELD(TBFLAG_A64, NV2_MEM_BE, 36, 1)
FIELD(TBFLAG_A64, AH, 37, 1) /* FPCR.AH */
FIELD(TBFLAG_A64, NEP, 38, 1) /* FPCR.NEP */
FIELD(TBFLAG_A64, ZT0EXC_EL, 39, 2)
FIELD(TBFLAG_A64, GCS_EN, 41, 1)
FIELD(TBFLAG_A64, GCS_RVCEN, 42, 1)
FIELD(TBFLAG_A64, GCSSTR_EL, 43, 2)
/*
* Helpers for using the above. Note that only the A64 accessors use
+2
View File
@@ -47,6 +47,7 @@ int aarch64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
case 32:
return gdb_get_reg64(mem_buf, env->pc);
case 33:
/* pstate is now a 64-bit value; can we simply adjust the xml? */
return gdb_get_reg32(mem_buf, pstate_read(env));
}
/* Unknown register. */
@@ -75,6 +76,7 @@ int aarch64_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 8;
case 33:
/* CPSR */
/* pstate is now a 64-bit value; can we simply adjust the xml? */
pstate_write(env, tmp);
return 4;
}
+339 -52
View File
File diff suppressed because it is too large Load Diff
+25 -126
View File
@@ -34,6 +34,7 @@
#include "system/memory.h"
#include "syndrome.h"
#include "cpu-features.h"
#include "mmuidx-internal.h"
/* register banks for CPU modes */
#define BANK_USRSYS 0
@@ -250,6 +251,7 @@ FIELD(VSTCR, SA, 30, 1)
#define HCRX_MSCEN (1ULL << 11)
#define HCRX_TCR2EN (1ULL << 14)
#define HCRX_SCTLR2EN (1ULL << 15)
#define HCRX_GCSEN (1ULL << 22)
#define HPFAR_NS (1ULL << 63)
@@ -304,14 +306,14 @@ FIELD(CNTHCTL, CNTPMASK, 19, 1)
* and never returns because we will longjump back up to the CPU main loop.
*/
G_NORETURN void raise_exception(CPUARMState *env, uint32_t excp,
uint32_t syndrome, uint32_t target_el);
uint64_t syndrome, uint32_t target_el);
/*
* Similarly, but also use unwinding to restore cpu state.
*/
G_NORETURN void raise_exception_ra(CPUARMState *env, uint32_t excp,
uint32_t syndrome, uint32_t target_el,
uintptr_t ra);
uint64_t syndrome, uint32_t target_el,
uintptr_t ra);
/*
* For AArch64, map a given EL to an index in the banked_spsr array.
@@ -752,6 +754,7 @@ struct ARMMMUFaultInfo {
bool s1ptw;
bool s1ns;
bool ea;
bool dirtybit; /* FEAT_S1PIE, FEAT_S2PIE */
};
/**
@@ -983,8 +986,6 @@ static inline ARMMMUIdx core_to_aa64_mmu_idx(int mmu_idx)
return mmu_idx | ARM_MMU_IDX_A;
}
int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx);
/* Return the MMU index for a v7M CPU in the specified security state */
ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate);
@@ -1027,108 +1028,10 @@ static inline void arm_call_el_change_hook(ARMCPU *cpu)
}
}
/*
* Return true if this address translation regime has two ranges.
* Note that this will not return the correct answer for AArch32
* Secure PL1&0 (i.e. mmu indexes E3, E30_0, E30_3_PAN), but it is
* never called from a context where EL3 can be AArch32. (The
* correct return value for ARMMMUIdx_E3 would be different for
* that case, so we can't just make the function return the
* correct value anyway; we would need an extra "bool e3_is_aarch32"
* argument which all the current callsites would pass as 'false'.)
*/
static inline bool regime_has_2_ranges(ARMMMUIdx mmu_idx)
{
switch (mmu_idx) {
case ARMMMUIdx_Stage1_E0:
case ARMMMUIdx_Stage1_E1:
case ARMMMUIdx_Stage1_E1_PAN:
case ARMMMUIdx_E10_0:
case ARMMMUIdx_E10_1:
case ARMMMUIdx_E10_1_PAN:
case ARMMMUIdx_E20_0:
case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN:
return true;
default:
return false;
}
}
static inline bool regime_is_pan(CPUARMState *env, ARMMMUIdx mmu_idx)
{
switch (mmu_idx) {
case ARMMMUIdx_Stage1_E1_PAN:
case ARMMMUIdx_E10_1_PAN:
case ARMMMUIdx_E20_2_PAN:
case ARMMMUIdx_E30_3_PAN:
return true;
default:
return false;
}
}
static inline bool regime_is_stage2(ARMMMUIdx mmu_idx)
{
return mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S;
}
/* Return the exception level which controls this address translation regime */
static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
{
switch (mmu_idx) {
case ARMMMUIdx_E20_0:
case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN:
case ARMMMUIdx_Stage2:
case ARMMMUIdx_Stage2_S:
case ARMMMUIdx_E2:
return 2;
case ARMMMUIdx_E3:
case ARMMMUIdx_E30_0:
case ARMMMUIdx_E30_3_PAN:
return 3;
case ARMMMUIdx_E10_0:
case ARMMMUIdx_Stage1_E0:
case ARMMMUIdx_Stage1_E1:
case ARMMMUIdx_Stage1_E1_PAN:
case ARMMMUIdx_E10_1:
case ARMMMUIdx_E10_1_PAN:
case ARMMMUIdx_MPrivNegPri:
case ARMMMUIdx_MUserNegPri:
case ARMMMUIdx_MPriv:
case ARMMMUIdx_MUser:
case ARMMMUIdx_MSPrivNegPri:
case ARMMMUIdx_MSUserNegPri:
case ARMMMUIdx_MSPriv:
case ARMMMUIdx_MSUser:
return 1;
default:
g_assert_not_reached();
}
}
static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx)
{
switch (mmu_idx) {
case ARMMMUIdx_E10_0:
case ARMMMUIdx_E20_0:
case ARMMMUIdx_E30_0:
case ARMMMUIdx_Stage1_E0:
case ARMMMUIdx_MUser:
case ARMMMUIdx_MSUser:
case ARMMMUIdx_MUserNegPri:
case ARMMMUIdx_MSUserNegPri:
return true;
default:
return false;
}
}
/* Return the SCTLR value which controls this address translation regime */
static inline uint64_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx)
{
return env->cp15.sctlr_el[regime_el(env, mmu_idx)];
return env->cp15.sctlr_el[regime_el(mmu_idx)];
}
/*
@@ -1160,13 +1063,13 @@ static inline uint64_t regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx)
v |= env->cp15.vtcr_el2 & VTCR_SHARED_FIELD_MASK;
return v;
}
return env->cp15.tcr_el[regime_el(env, mmu_idx)];
return env->cp15.tcr_el[regime_el(mmu_idx)];
}
/* Return true if the translation regime is using LPAE format page tables */
static inline bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx)
{
int el = regime_el(env, mmu_idx);
int el = regime_el(mmu_idx);
if (el == 2 || arm_el_is_aa64(env, el)) {
return true;
}
@@ -1378,25 +1281,6 @@ ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx);
ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env);
#endif
/**
* arm_mmu_idx_is_stage1_of_2:
* @mmu_idx: The ARMMMUIdx to test
*
* Return true if @mmu_idx is a NOTLB mmu_idx that is the
* first stage of a two stage regime.
*/
static inline bool arm_mmu_idx_is_stage1_of_2(ARMMMUIdx mmu_idx)
{
switch (mmu_idx) {
case ARMMMUIdx_Stage1_E0:
case ARMMMUIdx_Stage1_E1:
case ARMMMUIdx_Stage1_E1_PAN:
return true;
default:
return false;
}
}
static inline uint32_t aarch32_cpsr_valid_mask(uint64_t features,
const ARMISARegisters *id)
{
@@ -1491,7 +1375,7 @@ static inline int arm_granule_bits(ARMGranuleSize gran)
/*
* Parameters of a given virtual address, as extracted from the
* translation control register (TCR) for a given regime.
* translation controls for a given regime.
*/
typedef struct ARMVAParameters {
unsigned tsz : 8;
@@ -1506,6 +1390,7 @@ typedef struct ARMVAParameters {
bool ha : 1;
bool hd : 1;
ARMGranuleSize gran : 2;
bool pie : 1;
} ARMVAParameters;
/**
@@ -1576,6 +1461,13 @@ typedef struct ARMCacheAttrs {
typedef struct GetPhysAddrResult {
CPUTLBEntryFull f;
ARMCacheAttrs cacheattrs;
/*
* For ARMMMUIdx_Stage2*, the protection installed into f.prot
* is the result for AccessType_TTW, i.e. the page table walk itself.
* The protection installed info s2prot is the one to be merged
* with the stage1 protection.
*/
int s2prot;
} GetPhysAddrResult;
/**
@@ -1892,6 +1784,8 @@ void define_tlb_insn_regs(ARMCPU *cpu);
void define_at_insn_regs(ARMCPU *cpu);
/* Add the cpreg definitions for PM cpregs */
void define_pm_cpregs(ARMCPU *cpu);
/* Add the cpreg definitions for GCS cpregs */
void define_gcs_cpregs(ARMCPU *cpu);
/* Effective value of MDCR_EL2 */
static inline uint64_t arm_mdcr_el2_eff(CPUARMState *env)
@@ -2003,8 +1897,13 @@ void vfp_clear_float_status_exc_flags(CPUARMState *env);
*/
void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask);
bool arm_pan_enabled(CPUARMState *env);
uint32_t cpsr_read_for_spsr_elx(CPUARMState *env);
void cpsr_write_from_spsr_elx(CPUARMState *env, uint32_t val);
/* Compare uint64_t for qsort and bsearch. */
int compare_u64(const void *a, const void *b);
/* Used in FEAT_MEC to set the MECIDWidthm1 field in the MECIDR_EL2 register. */
#define MECID_WIDTH 16
#endif

Some files were not shown because too many files have changed in this diff Show More