Skip to content

Commit

Permalink
Integrate hflags mechanism from mainline QEMU (#20)
Browse files Browse the repository at this point in the history
* WIP: copy hflags cache from mainline QEMU

* added rebuild call to reset, changed cpu_get_tb_cpu_state

* use hflags-based version of cpu_mmu_index

* added missing rebuild calls

* refresh prebuilt
  • Loading branch information
snps-virtualprototyping authored Oct 10, 2023
1 parent 18dcbcb commit 3a06e67
Show file tree
Hide file tree
Showing 16 changed files with 580 additions and 388 deletions.
Binary file modified prebuilt/libunicorn.a
Binary file not shown.
6 changes: 6 additions & 0 deletions qemu/aarch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -5086,4 +5086,10 @@
#define helper_sev helper_sev_aarch64
#define helper_sevl helper_sevl_aarch64
#define helper_call_breakpoints helper_call_breakpoints_aarch64
#define arm_rebuild_hflags arm_rebuild_hflags_aarch64
#define helper_rebuild_hflags_a64 helper_rebuild_hflags_a64_aarch64
#define helper_rebuild_hflags_m32_newel helper_rebuild_hflags_m32_newel_aarch64
#define helper_rebuild_hflags_m32 helper_rebuild_hflags_m32_aarch64
#define helper_rebuild_hflags_a32_newel helper_rebuild_hflags_a32_newel_aarch64
#define helper_rebuild_hflags_a32 helper_rebuild_hflags_a32_aarch64
#endif
6 changes: 6 additions & 0 deletions qemu/aarch64eb.h
Original file line number Diff line number Diff line change
Expand Up @@ -5086,4 +5086,10 @@
#define helper_sev helper_sev_aarch64eb
#define helper_sevl helper_sevl_aarch64eb
#define helper_call_breakpoints helper_call_breakpoints_aarch64eb
#define arm_rebuild_hflags arm_rebuild_hflags_aarch64eb
#define helper_rebuild_hflags_a64 helper_rebuild_hflags_a64_aarch64eb
#define helper_rebuild_hflags_m32_newel helper_rebuild_hflags_m32_newel_aarch64eb
#define helper_rebuild_hflags_m32 helper_rebuild_hflags_m32_aarch64eb
#define helper_rebuild_hflags_a32_newel helper_rebuild_hflags_a32_newel_aarch64eb
#define helper_rebuild_hflags_a32 helper_rebuild_hflags_a32_aarch64eb
#endif
6 changes: 6 additions & 0 deletions qemu/arm.h
Original file line number Diff line number Diff line change
Expand Up @@ -3801,4 +3801,10 @@
#define helper_sev helper_sev_arm
#define helper_sevl helper_sevl_arm
#define helper_call_breakpoints helper_call_breakpoints_arm
#define arm_rebuild_hflags arm_rebuild_hflags_arm
#define helper_rebuild_hflags_a64 helper_rebuild_hflags_a64_arm
#define helper_rebuild_hflags_m32_newel helper_rebuild_hflags_m32_newel_arm
#define helper_rebuild_hflags_m32 helper_rebuild_hflags_m32_arm
#define helper_rebuild_hflags_a32_newel helper_rebuild_hflags_a32_newel_arm
#define helper_rebuild_hflags_a32 helper_rebuild_hflags_a32_arm
#endif
6 changes: 6 additions & 0 deletions qemu/armeb.h
Original file line number Diff line number Diff line change
Expand Up @@ -3801,4 +3801,10 @@
#define helper_sev helper_sev_armeb
#define helper_sevl helper_sevl_armeb
#define helper_call_breakpoints helper_call_breakpoints_armeb
#define arm_rebuild_hflags arm_rebuild_hflags_armeb
#define helper_rebuild_hflags_a64 helper_rebuild_hflags_a64_armeb
#define helper_rebuild_hflags_m32_newel helper_rebuild_hflags_m32_newel_armeb
#define helper_rebuild_hflags_m32 helper_rebuild_hflags_m32_armeb
#define helper_rebuild_hflags_a32_newel helper_rebuild_hflags_a32_newel_armeb
#define helper_rebuild_hflags_a32 helper_rebuild_hflags_a32_armeb
#endif
14 changes: 14 additions & 0 deletions qemu/header_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -3814,6 +3814,13 @@
'helper_sev',
'helper_sevl',
'helper_call_breakpoints',

'arm_rebuild_hflags',
'helper_rebuild_hflags_a64',
'helper_rebuild_hflags_m32_newel',
'helper_rebuild_hflags_m32',
'helper_rebuild_hflags_a32_newel',
'helper_rebuild_hflags_a32',
)

aarch64_symbols = (
Expand Down Expand Up @@ -5244,6 +5251,13 @@
'helper_sev',
'helper_sevl',
'helper_call_breakpoints',

'arm_rebuild_hflags',
'helper_rebuild_hflags_a64',
'helper_rebuild_hflags_m32_newel',
'helper_rebuild_hflags_m32',
'helper_rebuild_hflags_a32_newel',
'helper_rebuild_hflags_a32',
)

m68k_symbols = (
Expand Down
3 changes: 3 additions & 0 deletions qemu/target/arm/arm-powerctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ int arm_set_cpu_on(struct uc_struct *uc,
target_cpu->env.regs[0] = context_id;
}

/* CP15 update requires rebuilding hflags */
arm_rebuild_hflags(&target_cpu->env);

/* Start the new CPU at the requested address */
cpu_set_pc(target_cpu_state, entry);

Expand Down
2 changes: 2 additions & 0 deletions qemu/target/arm/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,8 @@ static void arm_cpu_reset(CPUState *s)

if (arm_feature(env, ARM_FEATURE_EL3) && arm_feature(env, ARM_FEATURE_EL2))
env->cp15.scr_el3 |= SCR_HCE; // hypervisor call available

arm_rebuild_hflags(env);
}

static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
Expand Down
84 changes: 54 additions & 30 deletions qemu/target/arm/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@ typedef struct CPUARMState {
uint32_t pstate;
uint32_t aarch64; /* 1 if CPU is in aarch64 state; inverse of PSTATE.nRW */

/* Cached TBFLAGS state. See below for which bits are included. */
uint32_t hflags;

/* Frequently accessed CPSR bits are stored separately for efficiency.
This contains all the other bits. Use cpsr_{read,write} to access
the whole CPSR. */
Expand Down Expand Up @@ -3057,16 +3060,6 @@ typedef enum ARMMMUIdxBit {

#define MMU_USER_IDX 0

/**
* cpu_mmu_index:
* @env: The cpu environment
* @ifetch: True for code access, false for data access.
*
* Return the core mmu index for the current translation regime.
* This function is used by generic TCG code paths.
*/
int cpu_mmu_index(CPUARMState *env, bool ifetch);

/* Indexes used when registering address spaces with cpu_address_space_init */
typedef enum ARMASIdx {
ARMASIdx_NS = 0,
Expand Down Expand Up @@ -3220,32 +3213,44 @@ static inline bool arm_sctlr_b(CPUARMState *env)

uint64_t arm_sctlr(CPUARMState *env, int el);

static inline bool arm_cpu_data_is_big_endian_a32(CPUARMState *env,
bool sctlr_b)
{
#ifdef CONFIG_USER_ONLY
/*
* In system mode, BE32 is modelled in line with the
* architecture (as word-invariant big-endianness), where loads
* and stores are done little endian but from addresses which
* are adjusted by XORing with the appropriate constant. So the
* endianness to use for the raw data access is not affected by
* SCTLR.B.
* In user mode, however, we model BE32 as byte-invariant
* big-endianness (because user-only code cannot tell the
* difference), and so we need to use a data access endianness
* that depends on SCTLR.B.
*/
if (sctlr_b) {
return true;
}
#endif
/* In 32bit endianness is determined by looking at CPSR's E bit */
return env->uncached_cpsr & CPSR_E;
}

static inline bool arm_cpu_data_is_big_endian_a64(int el, uint64_t sctlr)
{
return sctlr & (el ? SCTLR_EE : SCTLR_E0E);
}

/* Return true if the processor is in big-endian mode. */
static inline bool arm_cpu_data_is_big_endian(CPUARMState *env)
{
/* In 32bit endianness is determined by looking at CPSR's E bit */
if (!is_a64(env)) {
return
#ifdef CONFIG_USER_ONLY
/* In system mode, BE32 is modelled in line with the
* architecture (as word-invariant big-endianness), where loads
* and stores are done little endian but from addresses which
* are adjusted by XORing with the appropriate constant. So the
* endianness to use for the raw data access is not affected by
* SCTLR.B.
* In user mode, however, we model BE32 as byte-invariant
* big-endianness (because user-only code cannot tell the
* difference), and so we need to use a data access endianness
* that depends on SCTLR.B.
*/
arm_sctlr_b(env) ||
#endif
((env->uncached_cpsr & CPSR_E) ? 1 : 0);
return arm_cpu_data_is_big_endian_a32(env, arm_sctlr_b(env));
} else {
int cur_el = arm_current_el(env);
uint64_t sctlr = arm_sctlr(env, cur_el);

return (sctlr & (cur_el ? SCTLR_EE : SCTLR_E0E)) != 0;
return arm_cpu_data_is_big_endian_a64(cur_el, sctlr);
}
}

Expand All @@ -3268,7 +3273,8 @@ typedef ARMCPU ArchCPU;
* | | TBFLAG_A64 |
* +--------------+-------------------------------------+
* 31 20 0
*
*
* Unless otherwise noted, these bits are cached in env->hflags.
*/
FIELD(TBFLAG_ANY, AARCH64_STATE, 31, 1)
FIELD(TBFLAG_ANY, SS_ACTIVE, 30, 1)
Expand Down Expand Up @@ -3337,6 +3343,18 @@ FIELD(TBFLAG_A64, TCMA, 16, 2)
FIELD(TBFLAG_A64, MTE_ACTIVE, 18, 1)
FIELD(TBFLAG_A64, MTE0_ACTIVE, 19, 1)

/**
* cpu_mmu_index:
* @env: The cpu environment
* @ifetch: True for code access, false for data access.
*
* Return the core mmu index for the current translation regime.
* This function is used by generic TCG code paths.
*/
static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
{
return FIELD_EX32(env->hflags, TBFLAG_ANY, MMUIDX);
}

static inline bool bswap_code(bool sctlr_b)
{
Expand Down Expand Up @@ -3420,6 +3438,12 @@ void arm_register_pre_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, void
*opaque);

/**
* arm_rebuild_hflags:
* Rebuild the cached TBFLAGS for arbitrary changed processor state.
*/
void arm_rebuild_hflags(CPUARMState *env);

/**
* aa32_vfp_dreg:
* Return a pointer to the Dn register within env in 32-bit mode.
Expand Down
23 changes: 23 additions & 0 deletions qemu/target/arm/helper-a64.c
Original file line number Diff line number Diff line change
Expand Up @@ -1000,18 +1000,41 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
} else {
env->regs[15] = new_pc & ~0x3;
}
helper_rebuild_hflags_a32(env, new_el);
qemu_log_mask(CPU_LOG_INT, "Exception return from AArch64 EL%d to "
"AArch32 EL%d PC 0x%" PRIx32 "\n",
cur_el, new_el, env->regs[15]);
} else {
int tbii;

env->aarch64 = 1;
spsr &= aarch64_pstate_valid_mask(&env_archcpu(env)->isar);
pstate_write(env, spsr);
if (!arm_singlestep_active(env)) {
env->pstate &= ~PSTATE_SS;
}
aarch64_restore_sp(env, new_el);
helper_rebuild_hflags_a64(env, new_el);

/*
* Apply TBI to the exception return address. We had to delay this
* until after we selected the new EL, so that we could select the
* correct TBI+TBID bits. This is made easier by waiting until after
* the hflags rebuild, since we can pull the composite TBII field
* from there.
*/
tbii = FIELD_EX32(env->hflags, TBFLAG_A64, TBII);
if ((tbii >> extract64(new_pc, 55, 1)) & 1) {
/* TBI is enabled. */
int core_mmu_idx = cpu_mmu_index(env, false);
if (regime_has_2_ranges(core_to_aa64_mmu_idx(core_mmu_idx))) {
new_pc = sextract64(new_pc, 0, 56);
} else {
new_pc = extract64(new_pc, 0, 56);
}
}
env->pc = new_pc;

qemu_log_mask(CPU_LOG_INT, "Exception return from AArch64 EL%d to "
"AArch64 EL%d PC 0x%" PRIx64 "\n",
cur_el, new_el, env->pc);
Expand Down
Loading

0 comments on commit 3a06e67

Please sign in to comment.