target/arm: Implement HCR.FB

The HCR.FB virtualization configuration register bit requests that
TLB maintenance, branch predictor invalidate-all and icache
invalidate-all operations performed in NS EL1 should be upgraded
from "local CPU only to "broadcast within Inner Shareable domain".
For QEMU we NOP the branch predictor and icache operations, so
we only need to upgrade the TLB invalidates:
AArch32 TLBIALL, TLBIMVA, TLBIASID, DTLBIALL, DTLBIMVA, DTLBIASID,
ITLBIALL, ITLBIMVA, ITLBIASID, TLBIMVAA, TLBIMVAL, TLBIMVAAL
AArch64 TLBI VMALLE1, TLBI VAE1, TLBI ASIDE1, TLBI VAAE1,
TLBI VALE1, TLBI VAALE1

Backports commit b4ab8ce98b8c482c8986785800f238d32a1578a9 from qemu
This commit is contained in:
Peter Maydell 2018-11-10 09:15:07 -05:00 committed by Lioncash
parent a0358202a7
commit b9e7fa2d80
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -428,12 +428,61 @@ static void contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri,
raw_write(env, ri, value);
}
/* IS variants of TLB operations must affect all cores */
static void tlbiall_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
//CPUState *cs = ENV_GET_CPU(env);
//tlb_flush_all_cpus_synced(cs);
}
static void tlbiasid_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
//CPUState *cs = ENV_GET_CPU(env);
//tlb_flush_all_cpus_synced(cs);
}
static void tlbimva_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
//CPUState *cs = ENV_GET_CPU(env);
//tlb_flush_page_all_cpus_synced(cs, value & TARGET_PAGE_MASK);
}
static void tlbimvaa_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
//CPUState *cs = ENV_GET_CPU(env);
//tlb_flush_page_all_cpus_synced(cs, value & TARGET_PAGE_MASK);
}
/*
* Non-IS variants of TLB operations are upgraded to
* IS versions if we are at NS EL1 and HCR_EL2.FB is set to
* force broadcast of these operations.
*/
static bool tlb_force_broadcast(CPUARMState *env)
{
return (env->cp15.hcr_el2 & HCR_FB) &&
arm_current_el(env) == 1 && arm_is_secure_below_el3(env);
}
static void tlbiall_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* Invalidate all (TLBIALL) */
ARMCPU *cpu = arm_env_get_cpu(env);
if (tlb_force_broadcast(env)) {
tlbiall_is_write(env, NULL, value);
return;
}
tlb_flush(CPU(cpu));
}
@ -443,6 +492,11 @@ static void tlbimva_write(CPUARMState *env, const ARMCPRegInfo *ri,
/* Invalidate single TLB entry by MVA and ASID (TLBIMVA) */
ARMCPU *cpu = arm_env_get_cpu(env);
if (tlb_force_broadcast(env)) {
tlbimva_is_write(env, NULL, value);
return;
}
tlb_flush_page(CPU(cpu), value & TARGET_PAGE_MASK);
}
@ -452,6 +506,11 @@ static void tlbiasid_write(CPUARMState *env, const ARMCPRegInfo *ri,
/* Invalidate by ASID (TLBIASID) */
ARMCPU *cpu = arm_env_get_cpu(env);
if (tlb_force_broadcast(env)) {
tlbiasid_is_write(env, NULL, value);
return;
}
tlb_flush(CPU(cpu));
}
@ -461,42 +520,14 @@ static void tlbimvaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
/* Invalidate single entry by MVA, all ASIDs (TLBIMVAA) */
ARMCPU *cpu = arm_env_get_cpu(env);
if (tlb_force_broadcast(env)) {
tlbimvaa_is_write(env, NULL, value);
return;
}
tlb_flush_page(CPU(cpu), value & TARGET_PAGE_MASK);
}
/* IS variants of TLB operations must affect all cores */
static void tlbiall_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
//struct uc_struct *uc = env->uc;
// TODO: issue #642
// tlb_flush(other_cpu);
}
static void tlbiasid_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
//struct uc_struct *uc = env->uc;
// TODO: issue #642
// tlb_flush(other_cpu);
}
static void tlbimva_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
//struct uc_struct *uc = env->uc;
// TODO: issue #642
// tlb_flush(other_cpu);
}
static void tlbimvaa_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
//struct uc_struct *uc = env->uc;
// TODO: issue #642
// tlb_flush(other_cpu);
}
static void tlbiall_nsnh_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
@ -2733,23 +2764,6 @@ static CPAccessResult aa64_cacheop_access(CPUARMState *env,
* Page D4-1736 (DDI0487A.b)
*/
static void tlbi_aa64_vmalle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
ARMCPU *cpu = arm_env_get_cpu(env);
CPUState *cs = CPU(cpu);
if (arm_is_secure_below_el3(env)) {
tlb_flush_by_mmuidx(cs,
ARMMMUIdxBit_S1SE1 |
ARMMMUIdxBit_S1SE0);
} else {
tlb_flush_by_mmuidx(cs,
ARMMMUIdxBit_S12NSE1 |
ARMMMUIdxBit_S12NSE0);
}
}
static void tlbi_aa64_vmalle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
@ -2770,6 +2784,27 @@ static void tlbi_aa64_vmalle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
#endif
}
static void tlbi_aa64_vmalle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
CPUState *cs = ENV_GET_CPU(env);
if (tlb_force_broadcast(env)) {
tlbi_aa64_vmalle1_write(env, NULL, value);
return;
}
if (arm_is_secure_below_el3(env)) {
tlb_flush_by_mmuidx(cs,
ARMMMUIdxBit_S1SE1 |
ARMMMUIdxBit_S1SE0);
} else {
tlb_flush_by_mmuidx(cs,
ARMMMUIdxBit_S12NSE1 |
ARMMMUIdxBit_S12NSE0);
}
}
static void tlbi_aa64_alle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
@ -2868,29 +2903,6 @@ static void tlbi_aa64_alle3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
#endif
}
static void tlbi_aa64_vae1_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* Invalidate by VA, EL1&0 (AArch64 version).
* Currently handles all of VAE1, VAAE1, VAALE1 and VALE1,
* since we don't support flush-for-specific-ASID-only or
* flush-last-level-only.
*/
ARMCPU *cpu = arm_env_get_cpu(env);
CPUState *cs = CPU(cpu);
uint64_t pageaddr = sextract64(value << 12, 0, 56);
if (arm_is_secure_below_el3(env)) {
tlb_flush_page_by_mmuidx(cs, pageaddr,
ARMMMUIdxBit_S1SE1 |
ARMMMUIdxBit_S1SE0);
} else {
tlb_flush_page_by_mmuidx(cs, pageaddr,
ARMMMUIdxBit_S12NSE1 |
ARMMMUIdxBit_S12NSE0);
}
}
static void tlbi_aa64_vae2_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
@ -2940,6 +2952,34 @@ static void tlbi_aa64_vae1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
#endif
}
static void tlbi_aa64_vae1_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* Invalidate by VA, EL1&0 (AArch64 version).
* Currently handles all of VAE1, VAAE1, VAALE1 and VALE1,
* since we don't support flush-for-specific-ASID-only or
* flush-last-level-only.
*/
ARMCPU *cpu = arm_env_get_cpu(env);
CPUState *cs = CPU(cpu);
uint64_t pageaddr = sextract64(value << 12, 0, 56);
if (tlb_force_broadcast(env)) {
tlbi_aa64_vae1is_write(env, NULL, value);
return;
}
if (arm_is_secure_below_el3(env)) {
tlb_flush_page_by_mmuidx(cs, pageaddr,
ARMMMUIdxBit_S1SE1 |
ARMMMUIdxBit_S1SE0);
} else {
tlb_flush_page_by_mmuidx(cs, pageaddr,
ARMMMUIdxBit_S12NSE1 |
ARMMMUIdxBit_S12NSE0);
}
}
static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{