target-arm queue:
* Implement Armv8.5-BTI extension for system emulation mode * Implement the PR_PAC_RESET_KEYS prctl() for linux-user mode's Armv8.3-PAuth support * Support TBI (top-byte-ignore) properly for linux-user mode * gdbstub: allow killing QEMU via vKill command * hw/arm/boot: Support DTB autoload for firmware-only boots * target/arm: Make FPSCR/FPCR trapped-exception bits RAZ/WI -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAlxZwhYZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3uoCEACm4ds3KGV+bA1dtC367Th7 UKsxiVJ6xD7d1BaN3TyofkLTp0aJZgaYKqFjFhnagP8JoDgerdbno0xZ/9Wu2xIC CFopSO9MP373wdBy/fbIoYoiSle0P/Gofk40C8HnbRb+C4mj2X0oft33DVlo50RK p7JZSvHUqvCGrWLqeIKjJ1R+U31/dBx9Xprcg75EOiGGc+9Urb9w3Zmj11QE/eHh X6cFMM6xUn2aDYLRkbyHNjSOADHehtC/UhnHOpnsiQSnIfkYudF/pwDOPuBjmZkm 9rv8DzR9KvAy2ybbD4lrywH7W00QAnS2COVmpcFidWe9ur+glPMCk2XAuuWOK5J3 +WFsWxCg3VuZ74PL/DclKNp7QqgKhloTV0Q1TPp0z894HYca8faIXEJLoLtHSR7+ 2cAFJ7vaj9FMw4wn6XGrcx7olhPy81BhzM2g0eTSOb8T8Fe1mje0Q9Zg5Sc+sTYj 5vIjl37fHclBjxhnD3+F+ZQ+P2GK4/5gFPY9gezXPQWJAtD80MLBn6h/fvT8tTJm DlaMqFrIiQatllQDm9DmhNJg8707t6m8A6FIjhRDbfjS8Uw45Q+H2KdUfnVQJP8N 1ZCbTGRfhl4qwUy3jigYM448W10/T1l4/0BFcXdt/qc6C3QSjsqfHPlsft4XIaRf rUgbqfNBHr/i1n+SN5L4KQ== =XEy2 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190205' into staging target-arm queue: * Implement Armv8.5-BTI extension for system emulation mode * Implement the PR_PAC_RESET_KEYS prctl() for linux-user mode's Armv8.3-PAuth support * Support TBI (top-byte-ignore) properly for linux-user mode * gdbstub: allow killing QEMU via vKill command * hw/arm/boot: Support DTB autoload for firmware-only boots * target/arm: Make FPSCR/FPCR trapped-exception bits RAZ/WI # gpg: Signature made Tue 05 Feb 2019 17:04:22 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20190205: (22 commits) target/arm: Make FPSCR/FPCR trapped-exception bits RAZ/WI hw/arm/boot: Support DTB autoload for firmware-only boots hw/arm/boot: Clarify why arm_setup_firmware_boot() doesn't set env->boot_info hw/arm/boot: Factor out "set up firmware boot" code hw/arm/boot: Factor out "direct kernel boot" code into its own function hw/arm/boot: Fix block comment style in arm_load_kernel() gdbstub: allow killing QEMU via vKill command target/arm: Enable TBI for user-only target/arm: Compute TB_FLAGS for TBI for user-only target/arm: Clean TBI for data operations in the translator target/arm: Add TBFLAG_A64_TBID, split out gen_top_byte_ignore tests/tcg/aarch64: Add pauth smoke test linux-user: Implement PR_PAC_RESET_KEYS target/arm: Enable BTI for -cpu max target/arm: Set btype for indirect branches target/arm: Reset btype for direct branches target/arm: Default handling of BTYPE during translation target/arm: Cache the GP bit for a page in MemTxAttrs exec: Add target-specific tlb bits to MemTxAttrs target/arm: Add BT and BTYPE to tb->flags ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
47994e16b1
@ -1359,6 +1359,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
||||
|
||||
put_packet(s, buf);
|
||||
break;
|
||||
} else if (strncmp(p, "Kill;", 5) == 0) {
|
||||
/* Kill the target */
|
||||
error_report("QEMU: Terminated via GDBstub");
|
||||
exit(0);
|
||||
} else {
|
||||
goto unknown_command;
|
||||
}
|
||||
|
166
hw/arm/boot.c
166
hw/arm/boot.c
@ -949,9 +949,12 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base,
|
||||
return size;
|
||||
}
|
||||
|
||||
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
|
||||
struct arm_boot_info *info)
|
||||
{
|
||||
/* Set up for a direct boot of a kernel image file. */
|
||||
CPUState *cs;
|
||||
AddressSpace *as = arm_boot_address_space(cpu, info);
|
||||
int kernel_size;
|
||||
int initrd_size;
|
||||
int is_linux = 0;
|
||||
@ -959,70 +962,6 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
int elf_machine;
|
||||
hwaddr entry;
|
||||
static const ARMInsnFixup *primary_loader;
|
||||
AddressSpace *as = arm_boot_address_space(cpu, info);
|
||||
|
||||
/* CPU objects (unlike devices) are not automatically reset on system
|
||||
* reset, so we must always register a handler to do so. If we're
|
||||
* actually loading a kernel, the handler is also responsible for
|
||||
* arranging that we start it correctly.
|
||||
*/
|
||||
for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) {
|
||||
qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
|
||||
}
|
||||
|
||||
/* The board code is not supposed to set secure_board_setup unless
|
||||
* running its code in secure mode is actually possible, and KVM
|
||||
* doesn't support secure.
|
||||
*/
|
||||
assert(!(info->secure_board_setup && kvm_enabled()));
|
||||
|
||||
info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
|
||||
info->dtb_limit = 0;
|
||||
|
||||
/* Load the kernel. */
|
||||
if (!info->kernel_filename || info->firmware_loaded) {
|
||||
|
||||
if (have_dtb(info)) {
|
||||
/* If we have a device tree blob, but no kernel to supply it to (or
|
||||
* the kernel is supposed to be loaded by the bootloader), copy the
|
||||
* DTB to the base of RAM for the bootloader to pick up.
|
||||
*/
|
||||
info->dtb_start = info->loader_start;
|
||||
}
|
||||
|
||||
if (info->kernel_filename) {
|
||||
FWCfgState *fw_cfg;
|
||||
bool try_decompressing_kernel;
|
||||
|
||||
fw_cfg = fw_cfg_find();
|
||||
try_decompressing_kernel = arm_feature(&cpu->env,
|
||||
ARM_FEATURE_AARCH64);
|
||||
|
||||
/* Expose the kernel, the command line, and the initrd in fw_cfg.
|
||||
* We don't process them here at all, it's all left to the
|
||||
* firmware.
|
||||
*/
|
||||
load_image_to_fw_cfg(fw_cfg,
|
||||
FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
|
||||
info->kernel_filename,
|
||||
try_decompressing_kernel);
|
||||
load_image_to_fw_cfg(fw_cfg,
|
||||
FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
|
||||
info->initrd_filename, false);
|
||||
|
||||
if (info->kernel_cmdline) {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
|
||||
strlen(info->kernel_cmdline) + 1);
|
||||
fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
|
||||
info->kernel_cmdline);
|
||||
}
|
||||
}
|
||||
|
||||
/* We will start from address 0 (typically a boot ROM image) in the
|
||||
* same way as hardware.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
|
||||
primary_loader = bootloader_aarch64;
|
||||
@ -1045,7 +984,8 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
if (info->nb_cpus == 0)
|
||||
info->nb_cpus = 1;
|
||||
|
||||
/* We want to put the initrd far enough into RAM that when the
|
||||
/*
|
||||
* We want to put the initrd far enough into RAM that when the
|
||||
* kernel is uncompressed it will not clobber the initrd. However
|
||||
* on boards without much RAM we must ensure that we still leave
|
||||
* enough room for a decent sized initrd, and on boards with large
|
||||
@ -1062,12 +1002,14 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
kernel_size = arm_load_elf(info, &elf_entry, &elf_low_addr,
|
||||
&elf_high_addr, elf_machine, as);
|
||||
if (kernel_size > 0 && have_dtb(info)) {
|
||||
/* If there is still some room left at the base of RAM, try and put
|
||||
/*
|
||||
* If there is still some room left at the base of RAM, try and put
|
||||
* the DTB there like we do for images loaded with -bios or -pflash.
|
||||
*/
|
||||
if (elf_low_addr > info->loader_start
|
||||
|| elf_high_addr < info->loader_start) {
|
||||
/* Set elf_low_addr as address limit for arm_load_dtb if it may be
|
||||
/*
|
||||
* Set elf_low_addr as address limit for arm_load_dtb if it may be
|
||||
* pointing into RAM, otherwise pass '0' (no limit)
|
||||
*/
|
||||
if (elf_low_addr < info->loader_start) {
|
||||
@ -1128,7 +1070,8 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
fixupcontext[FIXUP_BOARDID] = info->board_id;
|
||||
fixupcontext[FIXUP_BOARD_SETUP] = info->board_setup_addr;
|
||||
|
||||
/* for device tree boot, we pass the DTB directly in r2. Otherwise
|
||||
/*
|
||||
* for device tree boot, we pass the DTB directly in r2. Otherwise
|
||||
* we point to the kernel args.
|
||||
*/
|
||||
if (have_dtb(info)) {
|
||||
@ -1181,7 +1124,8 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
info->write_board_setup(cpu, info);
|
||||
}
|
||||
|
||||
/* Notify devices which need to fake up firmware initialization
|
||||
/*
|
||||
* Notify devices which need to fake up firmware initialization
|
||||
* that we're doing a direct kernel boot.
|
||||
*/
|
||||
object_child_foreach_recursive(object_get_root(),
|
||||
@ -1192,6 +1136,88 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) {
|
||||
ARM_CPU(cs)->env.boot_info = info;
|
||||
}
|
||||
}
|
||||
|
||||
static void arm_setup_firmware_boot(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
{
|
||||
/* Set up for booting firmware (which might load a kernel via fw_cfg) */
|
||||
|
||||
if (have_dtb(info)) {
|
||||
/*
|
||||
* If we have a device tree blob, but no kernel to supply it to (or
|
||||
* the kernel is supposed to be loaded by the bootloader), copy the
|
||||
* DTB to the base of RAM for the bootloader to pick up.
|
||||
*/
|
||||
info->dtb_start = info->loader_start;
|
||||
}
|
||||
|
||||
if (info->kernel_filename) {
|
||||
FWCfgState *fw_cfg;
|
||||
bool try_decompressing_kernel;
|
||||
|
||||
fw_cfg = fw_cfg_find();
|
||||
try_decompressing_kernel = arm_feature(&cpu->env,
|
||||
ARM_FEATURE_AARCH64);
|
||||
|
||||
/*
|
||||
* Expose the kernel, the command line, and the initrd in fw_cfg.
|
||||
* We don't process them here at all, it's all left to the
|
||||
* firmware.
|
||||
*/
|
||||
load_image_to_fw_cfg(fw_cfg,
|
||||
FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
|
||||
info->kernel_filename,
|
||||
try_decompressing_kernel);
|
||||
load_image_to_fw_cfg(fw_cfg,
|
||||
FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
|
||||
info->initrd_filename, false);
|
||||
|
||||
if (info->kernel_cmdline) {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
|
||||
strlen(info->kernel_cmdline) + 1);
|
||||
fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
|
||||
info->kernel_cmdline);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We will start from address 0 (typically a boot ROM image) in the
|
||||
* same way as hardware. Leave env->boot_info NULL, so that
|
||||
* do_cpu_reset() knows it does not need to alter the PC on reset.
|
||||
*/
|
||||
}
|
||||
|
||||
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
{
|
||||
CPUState *cs;
|
||||
AddressSpace *as = arm_boot_address_space(cpu, info);
|
||||
|
||||
/*
|
||||
* CPU objects (unlike devices) are not automatically reset on system
|
||||
* reset, so we must always register a handler to do so. If we're
|
||||
* actually loading a kernel, the handler is also responsible for
|
||||
* arranging that we start it correctly.
|
||||
*/
|
||||
for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) {
|
||||
qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
|
||||
}
|
||||
|
||||
/*
|
||||
* The board code is not supposed to set secure_board_setup unless
|
||||
* running its code in secure mode is actually possible, and KVM
|
||||
* doesn't support secure.
|
||||
*/
|
||||
assert(!(info->secure_board_setup && kvm_enabled()));
|
||||
|
||||
info->dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
|
||||
info->dtb_limit = 0;
|
||||
|
||||
/* Load the kernel. */
|
||||
if (!info->kernel_filename || info->firmware_loaded) {
|
||||
arm_setup_firmware_boot(cpu, info);
|
||||
} else {
|
||||
arm_setup_direct_kernel_boot(cpu, info);
|
||||
}
|
||||
|
||||
if (!info->skip_dtb_autoload && have_dtb(info)) {
|
||||
if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as) < 0) {
|
||||
|
@ -37,6 +37,16 @@ typedef struct MemTxAttrs {
|
||||
unsigned int user:1;
|
||||
/* Requester ID (for MSI for example) */
|
||||
unsigned int requester_id:16;
|
||||
/*
|
||||
* The following are target-specific page-table bits. These are not
|
||||
* related to actual memory transactions at all. However, this structure
|
||||
* is part of the tlb_fill interface, cached in the cputlb structure,
|
||||
* and has unused bits. These fields will be read by target-specific
|
||||
* helpers using env->iotlb[mmu_idx][tlb_index()].attrs.target_tlb_bitN.
|
||||
*/
|
||||
unsigned int target_tlb_bit0 : 1;
|
||||
unsigned int target_tlb_bit1 : 1;
|
||||
unsigned int target_tlb_bit2 : 1;
|
||||
} MemTxAttrs;
|
||||
|
||||
/* Bus masters which don't specify any attributes will get this,
|
||||
|
@ -22,6 +22,13 @@ struct target_pt_regs {
|
||||
#define TARGET_PR_SVE_SET_VL 50
|
||||
#define TARGET_PR_SVE_GET_VL 51
|
||||
|
||||
#define TARGET_PR_PAC_RESET_KEYS 54
|
||||
# define TARGET_PR_PAC_APIAKEY (1 << 0)
|
||||
# define TARGET_PR_PAC_APIBKEY (1 << 1)
|
||||
# define TARGET_PR_PAC_APDAKEY (1 << 2)
|
||||
# define TARGET_PR_PAC_APDBKEY (1 << 3)
|
||||
# define TARGET_PR_PAC_APGAKEY (1 << 4)
|
||||
|
||||
void arm_init_pauth_key(ARMPACKey *key);
|
||||
|
||||
#endif /* AARCH64_TARGET_SYSCALL_H */
|
||||
|
@ -9691,6 +9691,42 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
case TARGET_PR_PAC_RESET_KEYS:
|
||||
{
|
||||
CPUARMState *env = cpu_env;
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
|
||||
if (arg3 || arg4 || arg5) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (cpu_isar_feature(aa64_pauth, cpu)) {
|
||||
int all = (TARGET_PR_PAC_APIAKEY | TARGET_PR_PAC_APIBKEY |
|
||||
TARGET_PR_PAC_APDAKEY | TARGET_PR_PAC_APDBKEY |
|
||||
TARGET_PR_PAC_APGAKEY);
|
||||
if (arg2 == 0) {
|
||||
arg2 = all;
|
||||
} else if (arg2 & ~all) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (arg2 & TARGET_PR_PAC_APIAKEY) {
|
||||
arm_init_pauth_key(&env->apia_key);
|
||||
}
|
||||
if (arg2 & TARGET_PR_PAC_APIBKEY) {
|
||||
arm_init_pauth_key(&env->apib_key);
|
||||
}
|
||||
if (arg2 & TARGET_PR_PAC_APDAKEY) {
|
||||
arm_init_pauth_key(&env->apda_key);
|
||||
}
|
||||
if (arg2 & TARGET_PR_PAC_APDBKEY) {
|
||||
arm_init_pauth_key(&env->apdb_key);
|
||||
}
|
||||
if (arg2 & TARGET_PR_PAC_APGAKEY) {
|
||||
arm_init_pauth_key(&env->apga_key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -TARGET_EINVAL;
|
||||
#endif /* AARCH64 */
|
||||
case PR_GET_SECCOMP:
|
||||
case PR_SET_SECCOMP:
|
||||
|
@ -200,6 +200,12 @@ static void arm_cpu_reset(CPUState *s)
|
||||
env->vfp.zcr_el[1] = cpu->sve_max_vq - 1;
|
||||
env->vfp.zcr_el[2] = env->vfp.zcr_el[1];
|
||||
env->vfp.zcr_el[3] = env->vfp.zcr_el[1];
|
||||
/*
|
||||
* Enable TBI0 and TBI1. While the real kernel only enables TBI0,
|
||||
* turning on both here will produce smaller code and otherwise
|
||||
* make no difference to the user-level emulation.
|
||||
*/
|
||||
env->cp15.tcr_el[1].raw_tcr = (3ULL << 37);
|
||||
#else
|
||||
/* Reset into the highest available EL */
|
||||
if (arm_feature(env, ARM_FEATURE_EL3)) {
|
||||
|
@ -234,6 +234,7 @@ typedef struct CPUARMState {
|
||||
* semantics as for AArch32, as described in the comments on each field)
|
||||
* nRW (also known as M[4]) is kept, inverted, in env->aarch64
|
||||
* DAIF (exception masks) are kept in env->daif
|
||||
* BTYPE is kept in env->btype
|
||||
* all other bits are stored in their correct places in env->pstate
|
||||
*/
|
||||
uint32_t pstate;
|
||||
@ -263,6 +264,7 @@ typedef struct CPUARMState {
|
||||
uint32_t GE; /* cpsr[19:16] */
|
||||
uint32_t thumb; /* cpsr[5]. 0 = arm mode, 1 = thumb mode. */
|
||||
uint32_t condexec_bits; /* IT bits. cpsr[15:10,26:25]. */
|
||||
uint32_t btype; /* BTI branch type. spsr[11:10]. */
|
||||
uint64_t daif; /* exception masks, in the bits they are in PSTATE */
|
||||
|
||||
uint64_t elr_el[4]; /* AArch64 exception link regs */
|
||||
@ -1206,6 +1208,7 @@ void pmu_init(ARMCPU *cpu);
|
||||
#define PSTATE_I (1U << 7)
|
||||
#define PSTATE_A (1U << 8)
|
||||
#define PSTATE_D (1U << 9)
|
||||
#define PSTATE_BTYPE (3U << 10)
|
||||
#define PSTATE_IL (1U << 20)
|
||||
#define PSTATE_SS (1U << 21)
|
||||
#define PSTATE_V (1U << 28)
|
||||
@ -1214,7 +1217,7 @@ void pmu_init(ARMCPU *cpu);
|
||||
#define PSTATE_N (1U << 31)
|
||||
#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)
|
||||
#define CACHED_PSTATE_BITS (PSTATE_NZCV | PSTATE_DAIF | PSTATE_BTYPE)
|
||||
/* Mode values for AArch64 */
|
||||
#define PSTATE_MODE_EL3h 13
|
||||
#define PSTATE_MODE_EL3t 12
|
||||
@ -1246,7 +1249,7 @@ static inline uint32_t pstate_read(CPUARMState *env)
|
||||
ZF = (env->ZF == 0);
|
||||
return (env->NF & 0x80000000) | (ZF << 30)
|
||||
| (env->CF << 29) | ((env->VF & 0x80000000) >> 3)
|
||||
| env->pstate | env->daif;
|
||||
| env->pstate | env->daif | (env->btype << 10);
|
||||
}
|
||||
|
||||
static inline void pstate_write(CPUARMState *env, uint32_t val)
|
||||
@ -1256,6 +1259,7 @@ static inline void pstate_write(CPUARMState *env, uint32_t val)
|
||||
env->CF = (val >> 29) & 1;
|
||||
env->VF = (val << 3) & 0x80000000;
|
||||
env->daif = val & PSTATE_DAIF;
|
||||
env->btype = (val >> 10) & 3;
|
||||
env->pstate = val & ~CACHED_PSTATE_BITS;
|
||||
}
|
||||
|
||||
@ -1414,6 +1418,12 @@ void vfp_set_fpscr(CPUARMState *env, uint32_t val);
|
||||
#define FPSR_MASK 0xf800009f
|
||||
#define FPCR_MASK 0x07ff9f00
|
||||
|
||||
#define FPCR_IOE (1 << 8) /* Invalid Operation exception trap enable */
|
||||
#define FPCR_DZE (1 << 9) /* Divide by Zero exception trap enable */
|
||||
#define FPCR_OFE (1 << 10) /* Overflow exception trap enable */
|
||||
#define FPCR_UFE (1 << 11) /* Underflow exception trap enable */
|
||||
#define FPCR_IXE (1 << 12) /* Inexact exception trap enable */
|
||||
#define FPCR_IDE (1 << 15) /* Input Denormal exception trap enable */
|
||||
#define FPCR_FZ16 (1 << 19) /* ARMv8.2+, FP16 flush-to-zero */
|
||||
#define FPCR_FZ (1 << 24) /* Flush-to-zero enable bit */
|
||||
#define FPCR_DN (1 << 25) /* Default NaN enable bit */
|
||||
@ -1681,6 +1691,11 @@ FIELD(ID_AA64PFR0, GIC, 24, 4)
|
||||
FIELD(ID_AA64PFR0, RAS, 28, 4)
|
||||
FIELD(ID_AA64PFR0, SVE, 32, 4)
|
||||
|
||||
FIELD(ID_AA64PFR1, BT, 0, 4)
|
||||
FIELD(ID_AA64PFR1, SBSS, 4, 4)
|
||||
FIELD(ID_AA64PFR1, MTE, 8, 4)
|
||||
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
|
||||
|
||||
FIELD(ID_AA64MMFR0, PARANGE, 0, 4)
|
||||
FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4)
|
||||
FIELD(ID_AA64MMFR0, BIGEND, 8, 4)
|
||||
@ -3043,6 +3058,9 @@ FIELD(TBFLAG_A64, TBII, 0, 2)
|
||||
FIELD(TBFLAG_A64, SVEEXC_EL, 2, 2)
|
||||
FIELD(TBFLAG_A64, ZCR_LEN, 4, 4)
|
||||
FIELD(TBFLAG_A64, PAUTH_ACTIVE, 8, 1)
|
||||
FIELD(TBFLAG_A64, BT, 9, 1)
|
||||
FIELD(TBFLAG_A64, BTYPE, 10, 2)
|
||||
FIELD(TBFLAG_A64, TBID, 12, 2)
|
||||
|
||||
static inline bool bswap_code(bool sctlr_b)
|
||||
{
|
||||
@ -3328,6 +3346,11 @@ static inline bool isar_feature_aa64_lor(const ARMISARegisters *id)
|
||||
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, LO) != 0;
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa64_bti(const ARMISARegisters *id)
|
||||
{
|
||||
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Forward to the above feature tests given an ARMCPU pointer.
|
||||
*/
|
||||
|
@ -324,6 +324,10 @@ static void aarch64_max_initfn(Object *obj)
|
||||
t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1);
|
||||
cpu->isar.id_aa64pfr0 = t;
|
||||
|
||||
t = cpu->isar.id_aa64pfr1;
|
||||
t = FIELD_DP64(t, ID_AA64PFR1, BT, 1);
|
||||
cpu->isar.id_aa64pfr1 = t;
|
||||
|
||||
t = cpu->isar.id_aa64mmfr1;
|
||||
t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */
|
||||
t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1);
|
||||
|
@ -7197,7 +7197,7 @@ uint32_t HELPER(rbit)(uint32_t x)
|
||||
return revbit32(x);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
|
||||
/* These should probably raise undefined insn exceptions. */
|
||||
void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
|
||||
@ -9571,6 +9571,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
|
||||
}
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
/* Return the exception level which controls this address translation regime */
|
||||
static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
@ -9600,6 +9601,8 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
/* Return the SCTLR value which controls this address translation regime */
|
||||
static inline uint32_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
@ -9655,6 +9658,22 @@ static inline bool regime_translation_big_endian(CPUARMState *env,
|
||||
return (regime_sctlr(env, mmu_idx) & SCTLR_EE) != 0;
|
||||
}
|
||||
|
||||
/* Return the TTBR associated with this translation regime */
|
||||
static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx,
|
||||
int ttbrn)
|
||||
{
|
||||
if (mmu_idx == ARMMMUIdx_S2NS) {
|
||||
return env->cp15.vttbr_el2;
|
||||
}
|
||||
if (ttbrn == 0) {
|
||||
return env->cp15.ttbr0_el[regime_el(env, mmu_idx)];
|
||||
} else {
|
||||
return env->cp15.ttbr1_el[regime_el(env, mmu_idx)];
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
/* Return the TCR controlling this translation regime */
|
||||
static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
@ -9675,20 +9694,6 @@ static inline ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx)
|
||||
return mmu_idx;
|
||||
}
|
||||
|
||||
/* Return the TTBR associated with this translation regime */
|
||||
static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx,
|
||||
int ttbrn)
|
||||
{
|
||||
if (mmu_idx == ARMMMUIdx_S2NS) {
|
||||
return env->cp15.vttbr_el2;
|
||||
}
|
||||
if (ttbrn == 0) {
|
||||
return env->cp15.ttbr0_el[regime_el(env, mmu_idx)];
|
||||
} else {
|
||||
return env->cp15.ttbr1_el[regime_el(env, 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)
|
||||
@ -9714,6 +9719,7 @@ bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
return regime_using_lpae_format(env, mmu_idx);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
switch (mmu_idx) {
|
||||
@ -10419,6 +10425,7 @@ static uint8_t convert_stage2_attrs(CPUARMState *env, uint8_t s2attrs)
|
||||
|
||||
return (hiattr << 6) | (hihint << 4) | (loattr << 2) | lohint;
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
ARMVAParameters aa64_va_parameters_both(CPUARMState *env, uint64_t va,
|
||||
ARMMMUIdx mmu_idx)
|
||||
@ -10490,6 +10497,7 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va,
|
||||
ARMMMUIdx mmu_idx)
|
||||
{
|
||||
@ -10577,6 +10585,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
|
||||
bool ttbr1_valid;
|
||||
uint64_t descaddrmask;
|
||||
bool aarch64 = arm_el_is_aa64(env, el);
|
||||
bool guarded = false;
|
||||
|
||||
/* TODO:
|
||||
* This code does not handle the different format TCR for VTCR_EL2.
|
||||
@ -10756,6 +10765,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
|
||||
}
|
||||
/* Merge in attributes from table descriptors */
|
||||
attrs |= nstable << 3; /* NS */
|
||||
guarded = extract64(descriptor, 50, 1); /* GP */
|
||||
if (param.hpd) {
|
||||
/* HPD disables all the table attributes except NSTable. */
|
||||
break;
|
||||
@ -10801,6 +10811,10 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
|
||||
*/
|
||||
txattrs->secure = false;
|
||||
}
|
||||
/* When in aarch64 mode, and BTI is enabled, remember GP in the IOTLB. */
|
||||
if (aarch64 && guarded && cpu_isar_feature(aa64_bti, cpu)) {
|
||||
txattrs->target_tlb_bit0 = true;
|
||||
}
|
||||
|
||||
if (cacheattrs != NULL) {
|
||||
if (mmu_idx == ARMMMUIdx_S2NS) {
|
||||
@ -12623,6 +12637,12 @@ void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
|
||||
val &= ~FPCR_FZ16;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't implement trapped exception handling, so the
|
||||
* trap enable bits are all RAZ/WI (not RES0!)
|
||||
*/
|
||||
val &= ~(FPCR_IDE | FPCR_IXE | FPCR_UFE | FPCR_OFE | FPCR_DZE | FPCR_IOE);
|
||||
|
||||
changed = env->vfp.xregs[ARM_VFP_FPSCR];
|
||||
env->vfp.xregs[ARM_VFP_FPSCR] = (val & 0xffc8ffff);
|
||||
env->vfp.vec_len = (val >> 16) & 7;
|
||||
@ -13735,15 +13755,12 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
|
||||
if (is_a64(env)) {
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
uint64_t sctlr;
|
||||
|
||||
*pc = env->pc;
|
||||
flags = FIELD_DP32(flags, TBFLAG_ANY, AARCH64_STATE, 1);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/*
|
||||
* Get control bits for tagged addresses. Note that the
|
||||
* translator only uses this for instruction addresses.
|
||||
*/
|
||||
/* Get control bits for tagged addresses. */
|
||||
{
|
||||
ARMMMUIdx stage1 = stage_1_mmu_idx(mmu_idx);
|
||||
ARMVAParameters p0 = aa64_va_parameters_both(env, 0, stage1);
|
||||
@ -13760,8 +13777,8 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
}
|
||||
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, TBII, tbii);
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, TBID, tbid);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cpu_isar_feature(aa64_sve, cpu)) {
|
||||
int sve_el = sve_exception_el(env, current_el);
|
||||
@ -13779,6 +13796,12 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, ZCR_LEN, zcr_len);
|
||||
}
|
||||
|
||||
if (current_el == 0) {
|
||||
/* FIXME: ARMv8.1-VHE S2 translation regime. */
|
||||
sctlr = env->cp15.sctlr_el[1];
|
||||
} else {
|
||||
sctlr = env->cp15.sctlr_el[current_el];
|
||||
}
|
||||
if (cpu_isar_feature(aa64_pauth, cpu)) {
|
||||
/*
|
||||
* In order to save space in flags, we record only whether
|
||||
@ -13786,17 +13809,18 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
* a nop, or "active" when some action must be performed.
|
||||
* The decision of which action to take is left to a helper.
|
||||
*/
|
||||
uint64_t sctlr;
|
||||
if (current_el == 0) {
|
||||
/* FIXME: ARMv8.1-VHE S2 translation regime. */
|
||||
sctlr = env->cp15.sctlr_el[1];
|
||||
} else {
|
||||
sctlr = env->cp15.sctlr_el[current_el];
|
||||
}
|
||||
if (sctlr & (SCTLR_EnIA | SCTLR_EnIB | SCTLR_EnDA | SCTLR_EnDB)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, PAUTH_ACTIVE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (cpu_isar_feature(aa64_bti, cpu)) {
|
||||
/* Note that SCTLR_EL[23].BT == SCTLR_BT1. */
|
||||
if (sctlr & (current_el == 0 ? SCTLR_BT0 : SCTLR_BT1)) {
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, BT, 1);
|
||||
}
|
||||
flags = FIELD_DP32(flags, TBFLAG_A64, BTYPE, env->btype);
|
||||
}
|
||||
} else {
|
||||
*pc = env->regs[15];
|
||||
flags = FIELD_DP32(flags, TBFLAG_A32, THUMB, env->thumb);
|
||||
|
@ -268,6 +268,7 @@ enum arm_exception_class {
|
||||
EC_FPIDTRAP = 0x08,
|
||||
EC_PACTRAP = 0x09,
|
||||
EC_CP14RRTTRAP = 0x0c,
|
||||
EC_BTITRAP = 0x0d,
|
||||
EC_ILLEGALSTATE = 0x0e,
|
||||
EC_AA32_SVC = 0x11,
|
||||
EC_AA32_HVC = 0x12,
|
||||
@ -439,6 +440,11 @@ static inline uint32_t syn_pactrap(void)
|
||||
return EC_PACTRAP << ARM_EL_EC_SHIFT;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_btitrap(int btype)
|
||||
{
|
||||
return (EC_BTITRAP << ARM_EL_EC_SHIFT) | btype;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
|
||||
{
|
||||
return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
|
||||
@ -957,30 +963,9 @@ typedef struct ARMVAParameters {
|
||||
bool using64k : 1;
|
||||
} ARMVAParameters;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
static inline ARMVAParameters aa64_va_parameters_both(CPUARMState *env,
|
||||
uint64_t va,
|
||||
ARMMMUIdx mmu_idx)
|
||||
{
|
||||
return (ARMVAParameters) {
|
||||
/* 48-bit address space */
|
||||
.tsz = 16,
|
||||
/* We can't handle tagged addresses properly in user-only mode */
|
||||
.tbi = false,
|
||||
};
|
||||
}
|
||||
|
||||
static inline ARMVAParameters aa64_va_parameters(CPUARMState *env,
|
||||
uint64_t va,
|
||||
ARMMMUIdx mmu_idx, bool data)
|
||||
{
|
||||
return aa64_va_parameters_both(env, va, mmu_idx);
|
||||
}
|
||||
#else
|
||||
ARMVAParameters aa64_va_parameters_both(CPUARMState *env, uint64_t va,
|
||||
ARMMMUIdx mmu_idx);
|
||||
ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
|
||||
ARMMMUIdx mmu_idx, bool data);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -128,6 +128,29 @@ static inline int get_a64_user_mem_index(DisasContext *s)
|
||||
return arm_to_core_mmu_idx(useridx);
|
||||
}
|
||||
|
||||
static void reset_btype(DisasContext *s)
|
||||
{
|
||||
if (s->btype != 0) {
|
||||
TCGv_i32 zero = tcg_const_i32(0);
|
||||
tcg_gen_st_i32(zero, cpu_env, offsetof(CPUARMState, btype));
|
||||
tcg_temp_free_i32(zero);
|
||||
s->btype = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_btype(DisasContext *s, int val)
|
||||
{
|
||||
TCGv_i32 tcg_val;
|
||||
|
||||
/* BTYPE is a 2-bit field, and 0 should be done with reset_btype. */
|
||||
tcg_debug_assert(val >= 1 && val <= 3);
|
||||
|
||||
tcg_val = tcg_const_i32(val);
|
||||
tcg_gen_st_i32(tcg_val, cpu_env, offsetof(CPUARMState, btype));
|
||||
tcg_temp_free_i32(tcg_val);
|
||||
s->btype = -1;
|
||||
}
|
||||
|
||||
void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
|
||||
fprintf_function cpu_fprintf, int flags)
|
||||
{
|
||||
@ -163,6 +186,9 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
|
||||
el,
|
||||
psr & PSTATE_SP ? 'h' : 't');
|
||||
|
||||
if (cpu_isar_feature(aa64_bti, cpu)) {
|
||||
cpu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
|
||||
}
|
||||
if (!(flags & CPU_DUMP_FPU)) {
|
||||
cpu_fprintf(f, "\n");
|
||||
return;
|
||||
@ -258,10 +284,10 @@ void gen_a64_set_pc_im(uint64_t val)
|
||||
tcg_gen_movi_i64(cpu_pc, val);
|
||||
}
|
||||
|
||||
/* Load the PC from a generic TCG variable.
|
||||
/*
|
||||
* Handle Top Byte Ignore (TBI) bits.
|
||||
*
|
||||
* If address tagging is enabled via the TCR TBI bits, then loading
|
||||
* an address into the PC will clear out any tag in it:
|
||||
* If address tagging is enabled via the TCR TBI bits:
|
||||
* + for EL2 and EL3 there is only one TBI bit, and if it is set
|
||||
* then the address is zero-extended, clearing bits [63:56]
|
||||
* + for EL0 and EL1, TBI0 controls addresses with bit 55 == 0
|
||||
@ -269,45 +295,56 @@ void gen_a64_set_pc_im(uint64_t val)
|
||||
* If the appropriate TBI bit is set for the address then
|
||||
* the address is sign-extended from bit 55 into bits [63:56]
|
||||
*
|
||||
* We can avoid doing this for relative-branches, because the
|
||||
* PC + offset can never overflow into the tag bits (assuming
|
||||
* that virtual addresses are less than 56 bits wide, as they
|
||||
* are currently), but we must handle it for branch-to-register.
|
||||
* Here We have concatenated TBI{1,0} into tbi.
|
||||
*/
|
||||
static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src)
|
||||
static void gen_top_byte_ignore(DisasContext *s, TCGv_i64 dst,
|
||||
TCGv_i64 src, int tbi)
|
||||
{
|
||||
/* Note that TBII is TBI1:TBI0. */
|
||||
int tbi = s->tbii;
|
||||
|
||||
if (s->current_el <= 1) {
|
||||
if (tbi != 0) {
|
||||
/* Sign-extend from bit 55. */
|
||||
tcg_gen_sextract_i64(cpu_pc, src, 0, 56);
|
||||
|
||||
if (tbi != 3) {
|
||||
TCGv_i64 tcg_zero = tcg_const_i64(0);
|
||||
|
||||
/*
|
||||
* The two TBI bits differ.
|
||||
* If tbi0, then !tbi1: only use the extension if positive.
|
||||
* if !tbi0, then tbi1: only use the extension if negative.
|
||||
*/
|
||||
tcg_gen_movcond_i64(tbi == 1 ? TCG_COND_GE : TCG_COND_LT,
|
||||
cpu_pc, cpu_pc, tcg_zero, cpu_pc, src);
|
||||
tcg_temp_free_i64(tcg_zero);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (tbi == 0) {
|
||||
/* Load unmodified address */
|
||||
tcg_gen_mov_i64(dst, src);
|
||||
} else if (s->current_el >= 2) {
|
||||
/* FIXME: ARMv8.1-VHE S2 translation regime. */
|
||||
/* Force tag byte to all zero */
|
||||
tcg_gen_extract_i64(dst, src, 0, 56);
|
||||
} else {
|
||||
if (tbi != 0) {
|
||||
/* Force tag byte to all zero */
|
||||
tcg_gen_extract_i64(cpu_pc, src, 0, 56);
|
||||
return;
|
||||
/* Sign-extend from bit 55. */
|
||||
tcg_gen_sextract_i64(dst, src, 0, 56);
|
||||
|
||||
if (tbi != 3) {
|
||||
TCGv_i64 tcg_zero = tcg_const_i64(0);
|
||||
|
||||
/*
|
||||
* The two TBI bits differ.
|
||||
* If tbi0, then !tbi1: only use the extension if positive.
|
||||
* if !tbi0, then tbi1: only use the extension if negative.
|
||||
*/
|
||||
tcg_gen_movcond_i64(tbi == 1 ? TCG_COND_GE : TCG_COND_LT,
|
||||
dst, dst, tcg_zero, dst, src);
|
||||
tcg_temp_free_i64(tcg_zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Load unmodified address */
|
||||
tcg_gen_mov_i64(cpu_pc, src);
|
||||
static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src)
|
||||
{
|
||||
/*
|
||||
* If address tagging is enabled for instructions via the TCR TBI bits,
|
||||
* then loading an address into the PC will clear out any tag.
|
||||
*/
|
||||
gen_top_byte_ignore(s, cpu_pc, src, s->tbii);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a "clean" address for ADDR according to TBID.
|
||||
* This is always a fresh temporary, as we need to be able to
|
||||
* increment this independently of a dirty write-back address.
|
||||
*/
|
||||
static TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr)
|
||||
{
|
||||
TCGv_i64 clean = new_tmp_a64(s);
|
||||
gen_top_byte_ignore(s, clean, addr, s->tbid);
|
||||
return clean;
|
||||
}
|
||||
|
||||
typedef struct DisasCompare64 {
|
||||
@ -1349,6 +1386,7 @@ static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
|
||||
}
|
||||
|
||||
/* B Branch / BL Branch with link */
|
||||
reset_btype(s);
|
||||
gen_goto_tb(s, 0, addr);
|
||||
}
|
||||
|
||||
@ -1373,6 +1411,7 @@ static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
|
||||
tcg_cmp = read_cpu_reg(s, rt, sf);
|
||||
label_match = gen_new_label();
|
||||
|
||||
reset_btype(s);
|
||||
tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
|
||||
tcg_cmp, 0, label_match);
|
||||
|
||||
@ -1402,6 +1441,8 @@ static void disas_test_b_imm(DisasContext *s, uint32_t insn)
|
||||
tcg_cmp = tcg_temp_new_i64();
|
||||
tcg_gen_andi_i64(tcg_cmp, cpu_reg(s, rt), (1ULL << bit_pos));
|
||||
label_match = gen_new_label();
|
||||
|
||||
reset_btype(s);
|
||||
tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
|
||||
tcg_cmp, 0, label_match);
|
||||
tcg_temp_free_i64(tcg_cmp);
|
||||
@ -1428,6 +1469,7 @@ static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
|
||||
addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
|
||||
cond = extract32(insn, 0, 4);
|
||||
|
||||
reset_btype(s);
|
||||
if (cond < 0x0e) {
|
||||
/* genuinely conditional branches */
|
||||
TCGLabel *label_match = gen_new_label();
|
||||
@ -1592,6 +1634,7 @@ static void handle_sync(DisasContext *s, uint32_t insn,
|
||||
* a self-modified code correctly and also to take
|
||||
* any pending interrupts immediately.
|
||||
*/
|
||||
reset_btype(s);
|
||||
gen_goto_tb(s, 0, s->pc);
|
||||
return;
|
||||
default:
|
||||
@ -1963,6 +2006,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
|
||||
static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
|
||||
{
|
||||
unsigned int opc, op2, op3, rn, op4;
|
||||
unsigned btype_mod = 2; /* 0: BR, 1: BLR, 2: other */
|
||||
TCGv_i64 dst;
|
||||
TCGv_i64 modifier;
|
||||
|
||||
@ -1980,6 +2024,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
|
||||
case 0: /* BR */
|
||||
case 1: /* BLR */
|
||||
case 2: /* RET */
|
||||
btype_mod = opc;
|
||||
switch (op3) {
|
||||
case 0:
|
||||
/* BR, BLR, RET */
|
||||
@ -2023,7 +2068,6 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
|
||||
default:
|
||||
goto do_unallocated;
|
||||
}
|
||||
|
||||
gen_a64_set_pc(s, dst);
|
||||
/* BLR also needs to load return address */
|
||||
if (opc == 1) {
|
||||
@ -2039,6 +2083,7 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
|
||||
if ((op3 & ~1) != 2) {
|
||||
goto do_unallocated;
|
||||
}
|
||||
btype_mod = opc & 1;
|
||||
if (s->pauth_active) {
|
||||
dst = new_tmp_a64(s);
|
||||
modifier = cpu_reg_sp(s, op4);
|
||||
@ -2122,6 +2167,26 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
|
||||
return;
|
||||
}
|
||||
|
||||
switch (btype_mod) {
|
||||
case 0: /* BR */
|
||||
if (dc_isar_feature(aa64_bti, s)) {
|
||||
/* BR to {x16,x17} or !guard -> 1, else 3. */
|
||||
set_btype(s, rn == 16 || rn == 17 || !s->guarded_page ? 1 : 3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: /* BLR */
|
||||
if (dc_isar_feature(aa64_bti, s)) {
|
||||
/* BLR sets BTYPE to 2, regardless of source guarded page. */
|
||||
set_btype(s, 2);
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* RET or none of the above. */
|
||||
/* BTYPE will be set to 0 by normal end-of-insn processing. */
|
||||
break;
|
||||
}
|
||||
|
||||
s->base.is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
@ -2294,12 +2359,13 @@ static void gen_compare_and_swap(DisasContext *s, int rs, int rt,
|
||||
TCGv_i64 tcg_rs = cpu_reg(s, rs);
|
||||
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
||||
int memidx = get_mem_index(s);
|
||||
TCGv_i64 addr = cpu_reg_sp(s, rn);
|
||||
TCGv_i64 clean_addr;
|
||||
|
||||
if (rn == 31) {
|
||||
gen_check_sp_alignment(s);
|
||||
}
|
||||
tcg_gen_atomic_cmpxchg_i64(tcg_rs, addr, tcg_rs, tcg_rt, memidx,
|
||||
clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
|
||||
tcg_gen_atomic_cmpxchg_i64(tcg_rs, clean_addr, tcg_rs, tcg_rt, memidx,
|
||||
size | MO_ALIGN | s->be_data);
|
||||
}
|
||||
|
||||
@ -2310,12 +2376,13 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
|
||||
TCGv_i64 s2 = cpu_reg(s, rs + 1);
|
||||
TCGv_i64 t1 = cpu_reg(s, rt);
|
||||
TCGv_i64 t2 = cpu_reg(s, rt + 1);
|
||||
TCGv_i64 addr = cpu_reg_sp(s, rn);
|
||||
TCGv_i64 clean_addr;
|
||||
int memidx = get_mem_index(s);
|
||||
|
||||
if (rn == 31) {
|
||||
gen_check_sp_alignment(s);
|
||||
}
|
||||
clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
|
||||
|
||||
if (size == 2) {
|
||||
TCGv_i64 cmp = tcg_temp_new_i64();
|
||||
@ -2329,7 +2396,7 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
|
||||
tcg_gen_concat32_i64(cmp, s2, s1);
|
||||
}
|
||||
|
||||
tcg_gen_atomic_cmpxchg_i64(cmp, addr, cmp, val, memidx,
|
||||
tcg_gen_atomic_cmpxchg_i64(cmp, clean_addr, cmp, val, memidx,
|
||||
MO_64 | MO_ALIGN | s->be_data);
|
||||
tcg_temp_free_i64(val);
|
||||
|
||||
@ -2343,9 +2410,11 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
|
||||
if (HAVE_CMPXCHG128) {
|
||||
TCGv_i32 tcg_rs = tcg_const_i32(rs);
|
||||
if (s->be_data == MO_LE) {
|
||||
gen_helper_casp_le_parallel(cpu_env, tcg_rs, addr, t1, t2);
|
||||
gen_helper_casp_le_parallel(cpu_env, tcg_rs,
|
||||
clean_addr, t1, t2);
|
||||
} else {
|
||||
gen_helper_casp_be_parallel(cpu_env, tcg_rs, addr, t1, t2);
|
||||
gen_helper_casp_be_parallel(cpu_env, tcg_rs,
|
||||
clean_addr, t1, t2);
|
||||
}
|
||||
tcg_temp_free_i32(tcg_rs);
|
||||
} else {
|
||||
@ -2361,10 +2430,10 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
|
||||
TCGv_i64 zero = tcg_const_i64(0);
|
||||
|
||||
/* Load the two words, in memory order. */
|
||||
tcg_gen_qemu_ld_i64(d1, addr, memidx,
|
||||
tcg_gen_qemu_ld_i64(d1, clean_addr, memidx,
|
||||
MO_64 | MO_ALIGN_16 | s->be_data);
|
||||
tcg_gen_addi_i64(a2, addr, 8);
|
||||
tcg_gen_qemu_ld_i64(d2, addr, memidx, MO_64 | s->be_data);
|
||||
tcg_gen_addi_i64(a2, clean_addr, 8);
|
||||
tcg_gen_qemu_ld_i64(d2, clean_addr, memidx, MO_64 | s->be_data);
|
||||
|
||||
/* Compare the two words, also in memory order. */
|
||||
tcg_gen_setcond_i64(TCG_COND_EQ, c1, d1, s1);
|
||||
@ -2374,7 +2443,7 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
|
||||
/* If compare equal, write back new data, else write back old data. */
|
||||
tcg_gen_movcond_i64(TCG_COND_NE, c1, c2, zero, t1, d1);
|
||||
tcg_gen_movcond_i64(TCG_COND_NE, c2, c2, zero, t2, d2);
|
||||
tcg_gen_qemu_st_i64(c1, addr, memidx, MO_64 | s->be_data);
|
||||
tcg_gen_qemu_st_i64(c1, clean_addr, memidx, MO_64 | s->be_data);
|
||||
tcg_gen_qemu_st_i64(c2, a2, memidx, MO_64 | s->be_data);
|
||||
tcg_temp_free_i64(a2);
|
||||
tcg_temp_free_i64(c1);
|
||||
@ -2427,7 +2496,7 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
|
||||
int is_lasr = extract32(insn, 15, 1);
|
||||
int o2_L_o1_o0 = extract32(insn, 21, 3) * 2 | is_lasr;
|
||||
int size = extract32(insn, 30, 2);
|
||||
TCGv_i64 tcg_addr;
|
||||
TCGv_i64 clean_addr;
|
||||
|
||||
switch (o2_L_o1_o0) {
|
||||
case 0x0: /* STXR */
|
||||
@ -2438,8 +2507,8 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
|
||||
if (is_lasr) {
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
|
||||
}
|
||||
tcg_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
gen_store_exclusive(s, rs, rt, rt2, tcg_addr, size, false);
|
||||
clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
|
||||
gen_store_exclusive(s, rs, rt, rt2, clean_addr, size, false);
|
||||
return;
|
||||
|
||||
case 0x4: /* LDXR */
|
||||
@ -2447,9 +2516,9 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
|
||||
if (rn == 31) {
|
||||
gen_check_sp_alignment(s);
|
||||
}
|
||||
tcg_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
|
||||
s->is_ldex = true;
|
||||
gen_load_exclusive(s, rt, rt2, tcg_addr, size, false);
|
||||
gen_load_exclusive(s, rt, rt2, clean_addr, size, false);
|
||||
if (is_lasr) {
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
|
||||
}
|
||||
@ -2467,8 +2536,8 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
|
||||
gen_check_sp_alignment(s);
|
||||
}
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
|
||||
tcg_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
do_gpr_st(s, cpu_reg(s, rt), tcg_addr, size, true, rt,
|
||||
clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
|
||||
do_gpr_st(s, cpu_reg(s, rt), clean_addr, size, true, rt,
|
||||
disas_ldst_compute_iss_sf(size, false, 0), is_lasr);
|
||||
return;
|
||||
|
||||
@ -2483,8 +2552,8 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
|
||||
if (rn == 31) {
|
||||
gen_check_sp_alignment(s);
|
||||
}
|
||||
tcg_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
do_gpr_ld(s, cpu_reg(s, rt), tcg_addr, size, false, false, true, rt,
|
||||
clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
|
||||
do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, false, false, true, rt,
|
||||
disas_ldst_compute_iss_sf(size, false, 0), is_lasr);
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
|
||||
return;
|
||||
@ -2497,8 +2566,8 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
|
||||
if (is_lasr) {
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
|
||||
}
|
||||
tcg_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
gen_store_exclusive(s, rs, rt, rt2, tcg_addr, size, true);
|
||||
clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
|
||||
gen_store_exclusive(s, rs, rt, rt2, clean_addr, size, true);
|
||||
return;
|
||||
}
|
||||
if (rt2 == 31
|
||||
@ -2515,9 +2584,9 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
|
||||
if (rn == 31) {
|
||||
gen_check_sp_alignment(s);
|
||||
}
|
||||
tcg_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
|
||||
s->is_ldex = true;
|
||||
gen_load_exclusive(s, rt, rt2, tcg_addr, size, true);
|
||||
gen_load_exclusive(s, rt, rt2, clean_addr, size, true);
|
||||
if (is_lasr) {
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
|
||||
}
|
||||
@ -2566,7 +2635,7 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
|
||||
int opc = extract32(insn, 30, 2);
|
||||
bool is_signed = false;
|
||||
int size = 2;
|
||||
TCGv_i64 tcg_rt, tcg_addr;
|
||||
TCGv_i64 tcg_rt, clean_addr;
|
||||
|
||||
if (is_vector) {
|
||||
if (opc == 3) {
|
||||
@ -2588,17 +2657,17 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
|
||||
|
||||
tcg_rt = cpu_reg(s, rt);
|
||||
|
||||
tcg_addr = tcg_const_i64((s->pc - 4) + imm);
|
||||
clean_addr = tcg_const_i64((s->pc - 4) + imm);
|
||||
if (is_vector) {
|
||||
do_fp_ld(s, rt, tcg_addr, size);
|
||||
do_fp_ld(s, rt, clean_addr, size);
|
||||
} else {
|
||||
/* Only unsigned 32bit loads target 32bit registers. */
|
||||
bool iss_sf = opc != 0;
|
||||
|
||||
do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false,
|
||||
do_gpr_ld(s, tcg_rt, clean_addr, size, is_signed, false,
|
||||
true, rt, iss_sf, false);
|
||||
}
|
||||
tcg_temp_free_i64(tcg_addr);
|
||||
tcg_temp_free_i64(clean_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2644,7 +2713,8 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
|
||||
bool postindex = false;
|
||||
bool wback = false;
|
||||
|
||||
TCGv_i64 tcg_addr; /* calculated address */
|
||||
TCGv_i64 clean_addr, dirty_addr;
|
||||
|
||||
int size;
|
||||
|
||||
if (opc == 3) {
|
||||
@ -2700,23 +2770,23 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
|
||||
gen_check_sp_alignment(s);
|
||||
}
|
||||
|
||||
tcg_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
|
||||
dirty_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
if (!postindex) {
|
||||
tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
|
||||
tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
|
||||
}
|
||||
clean_addr = clean_data_tbi(s, dirty_addr);
|
||||
|
||||
if (is_vector) {
|
||||
if (is_load) {
|
||||
do_fp_ld(s, rt, tcg_addr, size);
|
||||
do_fp_ld(s, rt, clean_addr, size);
|
||||
} else {
|
||||
do_fp_st(s, rt, tcg_addr, size);
|
||||
do_fp_st(s, rt, clean_addr, size);
|
||||
}
|
||||
tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
|
||||
tcg_gen_addi_i64(clean_addr, clean_addr, 1 << size);
|
||||
if (is_load) {
|
||||
do_fp_ld(s, rt2, tcg_addr, size);
|
||||
do_fp_ld(s, rt2, clean_addr, size);
|
||||
} else {
|
||||
do_fp_st(s, rt2, tcg_addr, size);
|
||||
do_fp_st(s, rt2, clean_addr, size);
|
||||
}
|
||||
} else {
|
||||
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
||||
@ -2728,30 +2798,28 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
|
||||
/* Do not modify tcg_rt before recognizing any exception
|
||||
* from the second load.
|
||||
*/
|
||||
do_gpr_ld(s, tmp, tcg_addr, size, is_signed, false,
|
||||
do_gpr_ld(s, tmp, clean_addr, size, is_signed, false,
|
||||
false, 0, false, false);
|
||||
tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
|
||||
do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false,
|
||||
tcg_gen_addi_i64(clean_addr, clean_addr, 1 << size);
|
||||
do_gpr_ld(s, tcg_rt2, clean_addr, size, is_signed, false,
|
||||
false, 0, false, false);
|
||||
|
||||
tcg_gen_mov_i64(tcg_rt, tmp);
|
||||
tcg_temp_free_i64(tmp);
|
||||
} else {
|
||||
do_gpr_st(s, tcg_rt, tcg_addr, size,
|
||||
do_gpr_st(s, tcg_rt, clean_addr, size,
|
||||
false, 0, false, false);
|
||||
tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
|
||||
do_gpr_st(s, tcg_rt2, tcg_addr, size,
|
||||
tcg_gen_addi_i64(clean_addr, clean_addr, 1 << size);
|
||||
do_gpr_st(s, tcg_rt2, clean_addr, size,
|
||||
false, 0, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (wback) {
|
||||
if (postindex) {
|
||||
tcg_gen_addi_i64(tcg_addr, tcg_addr, offset - (1 << size));
|
||||
} else {
|
||||
tcg_gen_subi_i64(tcg_addr, tcg_addr, 1 << size);
|
||||
tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
|
||||
}
|
||||
tcg_gen_mov_i64(cpu_reg_sp(s, rn), tcg_addr);
|
||||
tcg_gen_mov_i64(cpu_reg_sp(s, rn), dirty_addr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2788,7 +2856,7 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
|
||||
bool post_index;
|
||||
bool writeback;
|
||||
|
||||
TCGv_i64 tcg_addr;
|
||||
TCGv_i64 clean_addr, dirty_addr;
|
||||
|
||||
if (is_vector) {
|
||||
size |= (opc & 2) << 1;
|
||||
@ -2839,17 +2907,18 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
|
||||
if (rn == 31) {
|
||||
gen_check_sp_alignment(s);
|
||||
}
|
||||
tcg_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
|
||||
dirty_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
if (!post_index) {
|
||||
tcg_gen_addi_i64(tcg_addr, tcg_addr, imm9);
|
||||
tcg_gen_addi_i64(dirty_addr, dirty_addr, imm9);
|
||||
}
|
||||
clean_addr = clean_data_tbi(s, dirty_addr);
|
||||
|
||||
if (is_vector) {
|
||||
if (is_store) {
|
||||
do_fp_st(s, rt, tcg_addr, size);
|
||||
do_fp_st(s, rt, clean_addr, size);
|
||||
} else {
|
||||
do_fp_ld(s, rt, tcg_addr, size);
|
||||
do_fp_ld(s, rt, clean_addr, size);
|
||||
}
|
||||
} else {
|
||||
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
||||
@ -2857,10 +2926,10 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
|
||||
bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
|
||||
|
||||
if (is_store) {
|
||||
do_gpr_st_memidx(s, tcg_rt, tcg_addr, size, memidx,
|
||||
do_gpr_st_memidx(s, tcg_rt, clean_addr, size, memidx,
|
||||
iss_valid, rt, iss_sf, false);
|
||||
} else {
|
||||
do_gpr_ld_memidx(s, tcg_rt, tcg_addr, size,
|
||||
do_gpr_ld_memidx(s, tcg_rt, clean_addr, size,
|
||||
is_signed, is_extended, memidx,
|
||||
iss_valid, rt, iss_sf, false);
|
||||
}
|
||||
@ -2869,9 +2938,9 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
|
||||
if (writeback) {
|
||||
TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
|
||||
if (post_index) {
|
||||
tcg_gen_addi_i64(tcg_addr, tcg_addr, imm9);
|
||||
tcg_gen_addi_i64(dirty_addr, dirty_addr, imm9);
|
||||
}
|
||||
tcg_gen_mov_i64(tcg_rn, tcg_addr);
|
||||
tcg_gen_mov_i64(tcg_rn, dirty_addr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2910,8 +2979,7 @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
|
||||
bool is_store = false;
|
||||
bool is_extended = false;
|
||||
|
||||
TCGv_i64 tcg_rm;
|
||||
TCGv_i64 tcg_addr;
|
||||
TCGv_i64 tcg_rm, clean_addr, dirty_addr;
|
||||
|
||||
if (extract32(opt, 1, 1) == 0) {
|
||||
unallocated_encoding(s);
|
||||
@ -2945,27 +3013,28 @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
|
||||
if (rn == 31) {
|
||||
gen_check_sp_alignment(s);
|
||||
}
|
||||
tcg_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
dirty_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
|
||||
tcg_rm = read_cpu_reg(s, rm, 1);
|
||||
ext_and_shift_reg(tcg_rm, tcg_rm, opt, shift ? size : 0);
|
||||
|
||||
tcg_gen_add_i64(tcg_addr, tcg_addr, tcg_rm);
|
||||
tcg_gen_add_i64(dirty_addr, dirty_addr, tcg_rm);
|
||||
clean_addr = clean_data_tbi(s, dirty_addr);
|
||||
|
||||
if (is_vector) {
|
||||
if (is_store) {
|
||||
do_fp_st(s, rt, tcg_addr, size);
|
||||
do_fp_st(s, rt, clean_addr, size);
|
||||
} else {
|
||||
do_fp_ld(s, rt, tcg_addr, size);
|
||||
do_fp_ld(s, rt, clean_addr, size);
|
||||
}
|
||||
} else {
|
||||
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
||||
bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
|
||||
if (is_store) {
|
||||
do_gpr_st(s, tcg_rt, tcg_addr, size,
|
||||
do_gpr_st(s, tcg_rt, clean_addr, size,
|
||||
true, rt, iss_sf, false);
|
||||
} else {
|
||||
do_gpr_ld(s, tcg_rt, tcg_addr, size,
|
||||
do_gpr_ld(s, tcg_rt, clean_addr, size,
|
||||
is_signed, is_extended,
|
||||
true, rt, iss_sf, false);
|
||||
}
|
||||
@ -2999,7 +3068,7 @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
|
||||
unsigned int imm12 = extract32(insn, 10, 12);
|
||||
unsigned int offset;
|
||||
|
||||
TCGv_i64 tcg_addr;
|
||||
TCGv_i64 clean_addr, dirty_addr;
|
||||
|
||||
bool is_store;
|
||||
bool is_signed = false;
|
||||
@ -3032,24 +3101,25 @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
|
||||
if (rn == 31) {
|
||||
gen_check_sp_alignment(s);
|
||||
}
|
||||
tcg_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
dirty_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
offset = imm12 << size;
|
||||
tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
|
||||
tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
|
||||
clean_addr = clean_data_tbi(s, dirty_addr);
|
||||
|
||||
if (is_vector) {
|
||||
if (is_store) {
|
||||
do_fp_st(s, rt, tcg_addr, size);
|
||||
do_fp_st(s, rt, clean_addr, size);
|
||||
} else {
|
||||
do_fp_ld(s, rt, tcg_addr, size);
|
||||
do_fp_ld(s, rt, clean_addr, size);
|
||||
}
|
||||
} else {
|
||||
TCGv_i64 tcg_rt = cpu_reg(s, rt);
|
||||
bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
|
||||
if (is_store) {
|
||||
do_gpr_st(s, tcg_rt, tcg_addr, size,
|
||||
do_gpr_st(s, tcg_rt, clean_addr, size,
|
||||
true, rt, iss_sf, false);
|
||||
} else {
|
||||
do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended,
|
||||
do_gpr_ld(s, tcg_rt, clean_addr, size, is_signed, is_extended,
|
||||
true, rt, iss_sf, false);
|
||||
}
|
||||
}
|
||||
@ -3075,7 +3145,7 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
|
||||
int rs = extract32(insn, 16, 5);
|
||||
int rn = extract32(insn, 5, 5);
|
||||
int o3_opc = extract32(insn, 12, 4);
|
||||
TCGv_i64 tcg_rn, tcg_rs;
|
||||
TCGv_i64 tcg_rs, clean_addr;
|
||||
AtomicThreeOpFn *fn;
|
||||
|
||||
if (is_vector || !dc_isar_feature(aa64_atomics, s)) {
|
||||
@ -3118,7 +3188,7 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
|
||||
if (rn == 31) {
|
||||
gen_check_sp_alignment(s);
|
||||
}
|
||||
tcg_rn = cpu_reg_sp(s, rn);
|
||||
clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
|
||||
tcg_rs = read_cpu_reg(s, rs, true);
|
||||
|
||||
if (o3_opc == 1) { /* LDCLR */
|
||||
@ -3128,7 +3198,7 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
|
||||
/* The tcg atomic primitives are all full barriers. Therefore we
|
||||
* can ignore the Acquire and Release bits of this instruction.
|
||||
*/
|
||||
fn(cpu_reg(s, rt), tcg_rn, tcg_rs, get_mem_index(s),
|
||||
fn(cpu_reg(s, rt), clean_addr, tcg_rs, get_mem_index(s),
|
||||
s->be_data | size | MO_ALIGN);
|
||||
}
|
||||
|
||||
@ -3154,7 +3224,7 @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn,
|
||||
bool is_wback = extract32(insn, 11, 1);
|
||||
bool use_key_a = !extract32(insn, 23, 1);
|
||||
int offset;
|
||||
TCGv_i64 tcg_addr, tcg_rt;
|
||||
TCGv_i64 clean_addr, dirty_addr, tcg_rt;
|
||||
|
||||
if (size != 3 || is_vector || !dc_isar_feature(aa64_pauth, s)) {
|
||||
unallocated_encoding(s);
|
||||
@ -3164,29 +3234,31 @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn,
|
||||
if (rn == 31) {
|
||||
gen_check_sp_alignment(s);
|
||||
}
|
||||
tcg_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
dirty_addr = read_cpu_reg_sp(s, rn, 1);
|
||||
|
||||
if (s->pauth_active) {
|
||||
if (use_key_a) {
|
||||
gen_helper_autda(tcg_addr, cpu_env, tcg_addr, cpu_X[31]);
|
||||
gen_helper_autda(dirty_addr, cpu_env, dirty_addr, cpu_X[31]);
|
||||
} else {
|
||||
gen_helper_autdb(tcg_addr, cpu_env, tcg_addr, cpu_X[31]);
|
||||
gen_helper_autdb(dirty_addr, cpu_env, dirty_addr, cpu_X[31]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Form the 10-bit signed, scaled offset. */
|
||||
offset = (extract32(insn, 22, 1) << 9) | extract32(insn, 12, 9);
|
||||
offset = sextract32(offset << size, 0, 10 + size);
|
||||
tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
|
||||
tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
|
||||
|
||||
/* Note that "clean" and "dirty" here refer to TBI not PAC. */
|
||||
clean_addr = clean_data_tbi(s, dirty_addr);
|
||||
|
||||
tcg_rt = cpu_reg(s, rt);
|
||||
|
||||
do_gpr_ld(s, tcg_rt, tcg_addr, size, /* is_signed */ false,
|
||||
do_gpr_ld(s, tcg_rt, clean_addr, size, /* is_signed */ false,
|
||||
/* extend */ false, /* iss_valid */ !is_wback,
|
||||
/* iss_srt */ rt, /* iss_sf */ true, /* iss_ar */ false);
|
||||
|
||||
if (is_wback) {
|
||||
tcg_gen_mov_i64(cpu_reg_sp(s, rn), tcg_addr);
|
||||
tcg_gen_mov_i64(cpu_reg_sp(s, rn), dirty_addr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3255,7 +3327,7 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
|
||||
bool is_store = !extract32(insn, 22, 1);
|
||||
bool is_postidx = extract32(insn, 23, 1);
|
||||
bool is_q = extract32(insn, 30, 1);
|
||||
TCGv_i64 tcg_addr, tcg_rn, tcg_ebytes;
|
||||
TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
|
||||
TCGMemOp endian = s->be_data;
|
||||
|
||||
int ebytes; /* bytes per element */
|
||||
@ -3338,8 +3410,7 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
|
||||
elements = (is_q ? 16 : 8) / ebytes;
|
||||
|
||||
tcg_rn = cpu_reg_sp(s, rn);
|
||||
tcg_addr = tcg_temp_new_i64();
|
||||
tcg_gen_mov_i64(tcg_addr, tcg_rn);
|
||||
clean_addr = clean_data_tbi(s, tcg_rn);
|
||||
tcg_ebytes = tcg_const_i64(ebytes);
|
||||
|
||||
for (r = 0; r < rpt; r++) {
|
||||
@ -3349,14 +3420,15 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
|
||||
for (xs = 0; xs < selem; xs++) {
|
||||
int tt = (rt + r + xs) % 32;
|
||||
if (is_store) {
|
||||
do_vec_st(s, tt, e, tcg_addr, size, endian);
|
||||
do_vec_st(s, tt, e, clean_addr, size, endian);
|
||||
} else {
|
||||
do_vec_ld(s, tt, e, tcg_addr, size, endian);
|
||||
do_vec_ld(s, tt, e, clean_addr, size, endian);
|
||||
}
|
||||
tcg_gen_add_i64(tcg_addr, tcg_addr, tcg_ebytes);
|
||||
tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
tcg_temp_free_i64(tcg_ebytes);
|
||||
|
||||
if (!is_store) {
|
||||
/* For non-quad operations, setting a slice of the low
|
||||
@ -3374,13 +3446,11 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
|
||||
|
||||
if (is_postidx) {
|
||||
if (rm == 31) {
|
||||
tcg_gen_mov_i64(tcg_rn, tcg_addr);
|
||||
tcg_gen_addi_i64(tcg_rn, tcg_rn, rpt * elements * selem * ebytes);
|
||||
} else {
|
||||
tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm));
|
||||
}
|
||||
}
|
||||
tcg_temp_free_i64(tcg_ebytes);
|
||||
tcg_temp_free_i64(tcg_addr);
|
||||
}
|
||||
|
||||
/* AdvSIMD load/store single structure
|
||||
@ -3423,7 +3493,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
|
||||
bool replicate = false;
|
||||
int index = is_q << 3 | S << 2 | size;
|
||||
int ebytes, xs;
|
||||
TCGv_i64 tcg_addr, tcg_rn, tcg_ebytes;
|
||||
TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
|
||||
|
||||
if (extract32(insn, 31, 1)) {
|
||||
unallocated_encoding(s);
|
||||
@ -3483,8 +3553,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
|
||||
}
|
||||
|
||||
tcg_rn = cpu_reg_sp(s, rn);
|
||||
tcg_addr = tcg_temp_new_i64();
|
||||
tcg_gen_mov_i64(tcg_addr, tcg_rn);
|
||||
clean_addr = clean_data_tbi(s, tcg_rn);
|
||||
tcg_ebytes = tcg_const_i64(ebytes);
|
||||
|
||||
for (xs = 0; xs < selem; xs++) {
|
||||
@ -3492,7 +3561,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
|
||||
/* Load and replicate to all elements */
|
||||
TCGv_i64 tcg_tmp = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr,
|
||||
tcg_gen_qemu_ld_i64(tcg_tmp, clean_addr,
|
||||
get_mem_index(s), s->be_data + scale);
|
||||
tcg_gen_gvec_dup_i64(scale, vec_full_reg_offset(s, rt),
|
||||
(is_q + 1) * 8, vec_full_reg_size(s),
|
||||
@ -3501,24 +3570,23 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
|
||||
} else {
|
||||
/* Load/store one element per register */
|
||||
if (is_load) {
|
||||
do_vec_ld(s, rt, index, tcg_addr, scale, s->be_data);
|
||||
do_vec_ld(s, rt, index, clean_addr, scale, s->be_data);
|
||||
} else {
|
||||
do_vec_st(s, rt, index, tcg_addr, scale, s->be_data);
|
||||
do_vec_st(s, rt, index, clean_addr, scale, s->be_data);
|
||||
}
|
||||
}
|
||||
tcg_gen_add_i64(tcg_addr, tcg_addr, tcg_ebytes);
|
||||
tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes);
|
||||
rt = (rt + 1) % 32;
|
||||
}
|
||||
tcg_temp_free_i64(tcg_ebytes);
|
||||
|
||||
if (is_postidx) {
|
||||
if (rm == 31) {
|
||||
tcg_gen_mov_i64(tcg_rn, tcg_addr);
|
||||
tcg_gen_addi_i64(tcg_rn, tcg_rn, selem * ebytes);
|
||||
} else {
|
||||
tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm));
|
||||
}
|
||||
}
|
||||
tcg_temp_free_i64(tcg_ebytes);
|
||||
tcg_temp_free_i64(tcg_addr);
|
||||
}
|
||||
|
||||
/* Loads and stores */
|
||||
@ -13753,6 +13821,90 @@ static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* is_guarded_page:
|
||||
* @env: The cpu environment
|
||||
* @s: The DisasContext
|
||||
*
|
||||
* Return true if the page is guarded.
|
||||
*/
|
||||
static bool is_guarded_page(CPUARMState *env, DisasContext *s)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
return false; /* FIXME */
|
||||
#else
|
||||
uint64_t addr = s->base.pc_first;
|
||||
int mmu_idx = arm_to_core_mmu_idx(s->mmu_idx);
|
||||
unsigned int index = tlb_index(env, mmu_idx, addr);
|
||||
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
|
||||
|
||||
/*
|
||||
* We test this immediately after reading an insn, which means
|
||||
* that any normal page must be in the TLB. The only exception
|
||||
* would be for executing from flash or device memory, which
|
||||
* does not retain the TLB entry.
|
||||
*
|
||||
* FIXME: Assume false for those, for now. We could use
|
||||
* arm_cpu_get_phys_page_attrs_debug to re-read the page
|
||||
* table entry even for that case.
|
||||
*/
|
||||
return (tlb_hit(entry->addr_code, addr) &&
|
||||
env->iotlb[mmu_idx][index].attrs.target_tlb_bit0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* btype_destination_ok:
|
||||
* @insn: The instruction at the branch destination
|
||||
* @bt: SCTLR_ELx.BT
|
||||
* @btype: PSTATE.BTYPE, and is non-zero
|
||||
*
|
||||
* On a guarded page, there are a limited number of insns
|
||||
* that may be present at the branch target:
|
||||
* - branch target identifiers,
|
||||
* - paciasp, pacibsp,
|
||||
* - BRK insn
|
||||
* - HLT insn
|
||||
* Anything else causes a Branch Target Exception.
|
||||
*
|
||||
* Return true if the branch is compatible, false to raise BTITRAP.
|
||||
*/
|
||||
static bool btype_destination_ok(uint32_t insn, bool bt, int btype)
|
||||
{
|
||||
if ((insn & 0xfffff01fu) == 0xd503201fu) {
|
||||
/* HINT space */
|
||||
switch (extract32(insn, 5, 7)) {
|
||||
case 0b011001: /* PACIASP */
|
||||
case 0b011011: /* PACIBSP */
|
||||
/*
|
||||
* If SCTLR_ELx.BT, then PACI*SP are not compatible
|
||||
* with btype == 3. Otherwise all btype are ok.
|
||||
*/
|
||||
return !bt || btype != 3;
|
||||
case 0b100000: /* BTI */
|
||||
/* Not compatible with any btype. */
|
||||
return false;
|
||||
case 0b100010: /* BTI c */
|
||||
/* Not compatible with btype == 3 */
|
||||
return btype != 3;
|
||||
case 0b100100: /* BTI j */
|
||||
/* Not compatible with btype == 2 */
|
||||
return btype != 2;
|
||||
case 0b100110: /* BTI jc */
|
||||
/* Compatible with any btype. */
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
switch (insn & 0xffe0001fu) {
|
||||
case 0xd4200000u: /* BRK */
|
||||
case 0xd4400000u: /* HLT */
|
||||
/* Give priority to the breakpoint exception. */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* C3.1 A64 instruction index by encoding */
|
||||
static void disas_a64_insn(CPUARMState *env, DisasContext *s)
|
||||
{
|
||||
@ -13764,6 +13916,43 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
|
||||
|
||||
s->fp_access_checked = false;
|
||||
|
||||
if (dc_isar_feature(aa64_bti, s)) {
|
||||
if (s->base.num_insns == 1) {
|
||||
/*
|
||||
* At the first insn of the TB, compute s->guarded_page.
|
||||
* We delayed computing this until successfully reading
|
||||
* the first insn of the TB, above. This (mostly) ensures
|
||||
* that the softmmu tlb entry has been populated, and the
|
||||
* page table GP bit is available.
|
||||
*
|
||||
* Note that we need to compute this even if btype == 0,
|
||||
* because this value is used for BR instructions later
|
||||
* where ENV is not available.
|
||||
*/
|
||||
s->guarded_page = is_guarded_page(env, s);
|
||||
|
||||
/* First insn can have btype set to non-zero. */
|
||||
tcg_debug_assert(s->btype >= 0);
|
||||
|
||||
/*
|
||||
* Note that the Branch Target Exception has fairly high
|
||||
* priority -- below debugging exceptions but above most
|
||||
* everything else. This allows us to handle this now
|
||||
* instead of waiting until the insn is otherwise decoded.
|
||||
*/
|
||||
if (s->btype != 0
|
||||
&& s->guarded_page
|
||||
&& !btype_destination_ok(insn, s->bt, s->btype)) {
|
||||
gen_exception_insn(s, 4, EXCP_UDEF, syn_btitrap(s->btype),
|
||||
default_exception_el(s));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* Not the first insn: btype must be 0. */
|
||||
tcg_debug_assert(s->btype == 0);
|
||||
}
|
||||
}
|
||||
|
||||
switch (extract32(insn, 25, 4)) {
|
||||
case 0x0: case 0x1: case 0x3: /* UNALLOCATED */
|
||||
unallocated_encoding(s);
|
||||
@ -13800,6 +13989,14 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
|
||||
|
||||
/* if we allocated any temporaries, free them here */
|
||||
free_tmp_a64(s);
|
||||
|
||||
/*
|
||||
* After execution of most insns, btype is reset to 0.
|
||||
* Note that we set btype == -1 when the insn sets btype.
|
||||
*/
|
||||
if (s->btype > 0 && s->base.is_jmp != DISAS_NORETURN) {
|
||||
reset_btype(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
|
||||
@ -13829,6 +14026,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
|
||||
core_mmu_idx = FIELD_EX32(tb_flags, TBFLAG_ANY, MMUIDX);
|
||||
dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx);
|
||||
dc->tbii = FIELD_EX32(tb_flags, TBFLAG_A64, TBII);
|
||||
dc->tbid = FIELD_EX32(tb_flags, TBFLAG_A64, TBID);
|
||||
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
dc->user = (dc->current_el == 0);
|
||||
@ -13837,6 +14035,8 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
|
||||
dc->sve_excp_el = FIELD_EX32(tb_flags, TBFLAG_A64, SVEEXC_EL);
|
||||
dc->sve_len = (FIELD_EX32(tb_flags, TBFLAG_A64, ZCR_LEN) + 1) * 16;
|
||||
dc->pauth_active = FIELD_EX32(tb_flags, TBFLAG_A64, PAUTH_ACTIVE);
|
||||
dc->bt = FIELD_EX32(tb_flags, TBFLAG_A64, BT);
|
||||
dc->btype = FIELD_EX32(tb_flags, TBFLAG_A64, BTYPE);
|
||||
dc->vec_len = 0;
|
||||
dc->vec_stride = 0;
|
||||
dc->cp_regs = arm_cpu->cp_regs;
|
||||
|
@ -26,7 +26,8 @@ typedef struct DisasContext {
|
||||
int user;
|
||||
#endif
|
||||
ARMMMUIdx mmu_idx; /* MMU index to use for normal loads/stores */
|
||||
uint8_t tbii; /* TBI1|TBI0 for EL0/1 or TBI for EL2/3 */
|
||||
uint8_t tbii; /* TBI1|TBI0 for insns */
|
||||
uint8_t tbid; /* TBI1|TBI0 for data */
|
||||
bool ns; /* Use non-secure CPREG bank on access */
|
||||
int fp_excp_el; /* FP exception EL or 0 if enabled */
|
||||
int sve_excp_el; /* SVE exception EL or 0 if enabled */
|
||||
@ -69,6 +70,15 @@ typedef struct DisasContext {
|
||||
bool ss_same_el;
|
||||
/* True if v8.3-PAuth is active. */
|
||||
bool pauth_active;
|
||||
/* True with v8.5-BTI and SCTLR_ELx.BT* set. */
|
||||
bool bt;
|
||||
/*
|
||||
* >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
|
||||
* < 0, set by the current instruction.
|
||||
*/
|
||||
int8_t btype;
|
||||
/* True if this page is guarded. */
|
||||
bool guarded_page;
|
||||
/* Bottom two bits of XScale c15_cpar coprocessor access control reg */
|
||||
int c15_cpar;
|
||||
/* TCG op of the current insn_start. */
|
||||
|
@ -8,10 +8,14 @@ VPATH += $(AARCH64_SRC)
|
||||
# we don't build any of the ARM tests
|
||||
AARCH64_TESTS=$(filter-out $(ARM_TESTS), $(TESTS))
|
||||
AARCH64_TESTS+=fcvt
|
||||
TESTS:=$(AARCH64_TESTS)
|
||||
|
||||
fcvt: LDFLAGS+=-lm
|
||||
|
||||
run-fcvt: fcvt
|
||||
$(call run-test,$<,$(QEMU) $<, "$< on $(TARGET_NAME)")
|
||||
$(call diff-out,$<,$(AARCH64_SRC)/fcvt.ref)
|
||||
|
||||
AARCH64_TESTS += pauth-1
|
||||
run-pauth-%: QEMU += -cpu max
|
||||
|
||||
TESTS:=$(AARCH64_TESTS)
|
||||
|
23
tests/tcg/aarch64/pauth-1.c
Normal file
23
tests/tcg/aarch64/pauth-1.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include <assert.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
asm(".arch armv8.4-a");
|
||||
|
||||
#ifndef PR_PAC_RESET_KEYS
|
||||
#define PR_PAC_RESET_KEYS 54
|
||||
#define PR_PAC_APDAKEY (1 << 2)
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
int x;
|
||||
void *p0 = &x, *p1, *p2;
|
||||
|
||||
asm volatile("pacdza %0" : "=r"(p1) : "0"(p0));
|
||||
prctl(PR_PAC_RESET_KEYS, PR_PAC_APDAKEY, 0, 0, 0);
|
||||
asm volatile("pacdza %0" : "=r"(p2) : "0"(p0));
|
||||
|
||||
assert(p1 != p0);
|
||||
assert(p1 != p2);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user