OSDN Git Service

KVM: arm64: Refactor vcpu_{read,write}_sys_reg
authorMarc Zyngier <maz@kernel.org>
Thu, 20 Jun 2019 10:17:00 +0000 (11:17 +0100)
committerMarc Zyngier <maz@kernel.org>
Thu, 28 May 2020 10:57:10 +0000 (11:57 +0100)
Extract the direct HW accessors for later reuse.

Reviewed-by: James Morse <james.morse@arm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/sys_regs.c

index 620eaf1..50e328c 100644 (file)
@@ -64,11 +64,8 @@ static bool write_to_read_only(struct kvm_vcpu *vcpu,
        return false;
 }
 
-u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)
+static bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val)
 {
-       if (!vcpu->arch.sysregs_loaded_on_cpu)
-               goto immediate_read;
-
        /*
         * System registers listed in the switch are not saved on every
         * exit from the guest but are only saved on vcpu_put.
@@ -79,40 +76,37 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)
         * thread when emulating cross-VCPU communication.
         */
        switch (reg) {
-       case CSSELR_EL1:        return read_sysreg_s(SYS_CSSELR_EL1);
-       case SCTLR_EL1:         return read_sysreg_s(SYS_SCTLR_EL12);
-       case ACTLR_EL1:         return read_sysreg_s(SYS_ACTLR_EL1);
-       case CPACR_EL1:         return read_sysreg_s(SYS_CPACR_EL12);
-       case TTBR0_EL1:         return read_sysreg_s(SYS_TTBR0_EL12);
-       case TTBR1_EL1:         return read_sysreg_s(SYS_TTBR1_EL12);
-       case TCR_EL1:           return read_sysreg_s(SYS_TCR_EL12);
-       case ESR_EL1:           return read_sysreg_s(SYS_ESR_EL12);
-       case AFSR0_EL1:         return read_sysreg_s(SYS_AFSR0_EL12);
-       case AFSR1_EL1:         return read_sysreg_s(SYS_AFSR1_EL12);
-       case FAR_EL1:           return read_sysreg_s(SYS_FAR_EL12);
-       case MAIR_EL1:          return read_sysreg_s(SYS_MAIR_EL12);
-       case VBAR_EL1:          return read_sysreg_s(SYS_VBAR_EL12);
-       case CONTEXTIDR_EL1:    return read_sysreg_s(SYS_CONTEXTIDR_EL12);
-       case TPIDR_EL0:         return read_sysreg_s(SYS_TPIDR_EL0);
-       case TPIDRRO_EL0:       return read_sysreg_s(SYS_TPIDRRO_EL0);
-       case TPIDR_EL1:         return read_sysreg_s(SYS_TPIDR_EL1);
-       case AMAIR_EL1:         return read_sysreg_s(SYS_AMAIR_EL12);
-       case CNTKCTL_EL1:       return read_sysreg_s(SYS_CNTKCTL_EL12);
-       case PAR_EL1:           return read_sysreg_s(SYS_PAR_EL1);
-       case DACR32_EL2:        return read_sysreg_s(SYS_DACR32_EL2);
-       case IFSR32_EL2:        return read_sysreg_s(SYS_IFSR32_EL2);
-       case DBGVCR32_EL2:      return read_sysreg_s(SYS_DBGVCR32_EL2);
+       case CSSELR_EL1:        *val = read_sysreg_s(SYS_CSSELR_EL1);   break;
+       case SCTLR_EL1:         *val = read_sysreg_s(SYS_SCTLR_EL12);   break;
+       case ACTLR_EL1:         *val = read_sysreg_s(SYS_ACTLR_EL1);    break;
+       case CPACR_EL1:         *val = read_sysreg_s(SYS_CPACR_EL12);   break;
+       case TTBR0_EL1:         *val = read_sysreg_s(SYS_TTBR0_EL12);   break;
+       case TTBR1_EL1:         *val = read_sysreg_s(SYS_TTBR1_EL12);   break;
+       case TCR_EL1:           *val = read_sysreg_s(SYS_TCR_EL12);     break;
+       case ESR_EL1:           *val = read_sysreg_s(SYS_ESR_EL12);     break;
+       case AFSR0_EL1:         *val = read_sysreg_s(SYS_AFSR0_EL12);   break;
+       case AFSR1_EL1:         *val = read_sysreg_s(SYS_AFSR1_EL12);   break;
+       case FAR_EL1:           *val = read_sysreg_s(SYS_FAR_EL12);     break;
+       case MAIR_EL1:          *val = read_sysreg_s(SYS_MAIR_EL12);    break;
+       case VBAR_EL1:          *val = read_sysreg_s(SYS_VBAR_EL12);    break;
+       case CONTEXTIDR_EL1:    *val = read_sysreg_s(SYS_CONTEXTIDR_EL12);break;
+       case TPIDR_EL0:         *val = read_sysreg_s(SYS_TPIDR_EL0);    break;
+       case TPIDRRO_EL0:       *val = read_sysreg_s(SYS_TPIDRRO_EL0);  break;
+       case TPIDR_EL1:         *val = read_sysreg_s(SYS_TPIDR_EL1);    break;
+       case AMAIR_EL1:         *val = read_sysreg_s(SYS_AMAIR_EL12);   break;
+       case CNTKCTL_EL1:       *val = read_sysreg_s(SYS_CNTKCTL_EL12); break;
+       case PAR_EL1:           *val = read_sysreg_s(SYS_PAR_EL1);      break;
+       case DACR32_EL2:        *val = read_sysreg_s(SYS_DACR32_EL2);   break;
+       case IFSR32_EL2:        *val = read_sysreg_s(SYS_IFSR32_EL2);   break;
+       case DBGVCR32_EL2:      *val = read_sysreg_s(SYS_DBGVCR32_EL2); break;
+       default:                return false;
        }
 
-immediate_read:
-       return __vcpu_sys_reg(vcpu, reg);
+       return true;
 }
 
-void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
+static bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg)
 {
-       if (!vcpu->arch.sysregs_loaded_on_cpu)
-               goto immediate_write;
-
        /*
         * System registers listed in the switch are not restored on every
         * entry to the guest but are only restored on vcpu_load.
@@ -122,32 +116,52 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
         * once, before running the VCPU, and never changed later.
         */
        switch (reg) {
-       case CSSELR_EL1:        write_sysreg_s(val, SYS_CSSELR_EL1);    return;
-       case SCTLR_EL1:         write_sysreg_s(val, SYS_SCTLR_EL12);    return;
-       case ACTLR_EL1:         write_sysreg_s(val, SYS_ACTLR_EL1);     return;
-       case CPACR_EL1:         write_sysreg_s(val, SYS_CPACR_EL12);    return;
-       case TTBR0_EL1:         write_sysreg_s(val, SYS_TTBR0_EL12);    return;
-       case TTBR1_EL1:         write_sysreg_s(val, SYS_TTBR1_EL12);    return;
-       case TCR_EL1:           write_sysreg_s(val, SYS_TCR_EL12);      return;
-       case ESR_EL1:           write_sysreg_s(val, SYS_ESR_EL12);      return;
-       case AFSR0_EL1:         write_sysreg_s(val, SYS_AFSR0_EL12);    return;
-       case AFSR1_EL1:         write_sysreg_s(val, SYS_AFSR1_EL12);    return;
-       case FAR_EL1:           write_sysreg_s(val, SYS_FAR_EL12);      return;
-       case MAIR_EL1:          write_sysreg_s(val, SYS_MAIR_EL12);     return;
-       case VBAR_EL1:          write_sysreg_s(val, SYS_VBAR_EL12);     return;
-       case CONTEXTIDR_EL1:    write_sysreg_s(val, SYS_CONTEXTIDR_EL12); return;
-       case TPIDR_EL0:         write_sysreg_s(val, SYS_TPIDR_EL0);     return;
-       case TPIDRRO_EL0:       write_sysreg_s(val, SYS_TPIDRRO_EL0);   return;
-       case TPIDR_EL1:         write_sysreg_s(val, SYS_TPIDR_EL1);     return;
-       case AMAIR_EL1:         write_sysreg_s(val, SYS_AMAIR_EL12);    return;
-       case CNTKCTL_EL1:       write_sysreg_s(val, SYS_CNTKCTL_EL12);  return;
-       case PAR_EL1:           write_sysreg_s(val, SYS_PAR_EL1);       return;
-       case DACR32_EL2:        write_sysreg_s(val, SYS_DACR32_EL2);    return;
-       case IFSR32_EL2:        write_sysreg_s(val, SYS_IFSR32_EL2);    return;
-       case DBGVCR32_EL2:      write_sysreg_s(val, SYS_DBGVCR32_EL2);  return;
+       case CSSELR_EL1:        write_sysreg_s(val, SYS_CSSELR_EL1);    break;
+       case SCTLR_EL1:         write_sysreg_s(val, SYS_SCTLR_EL12);    break;
+       case ACTLR_EL1:         write_sysreg_s(val, SYS_ACTLR_EL1);     break;
+       case CPACR_EL1:         write_sysreg_s(val, SYS_CPACR_EL12);    break;
+       case TTBR0_EL1:         write_sysreg_s(val, SYS_TTBR0_EL12);    break;
+       case TTBR1_EL1:         write_sysreg_s(val, SYS_TTBR1_EL12);    break;
+       case TCR_EL1:           write_sysreg_s(val, SYS_TCR_EL12);      break;
+       case ESR_EL1:           write_sysreg_s(val, SYS_ESR_EL12);      break;
+       case AFSR0_EL1:         write_sysreg_s(val, SYS_AFSR0_EL12);    break;
+       case AFSR1_EL1:         write_sysreg_s(val, SYS_AFSR1_EL12);    break;
+       case FAR_EL1:           write_sysreg_s(val, SYS_FAR_EL12);      break;
+       case MAIR_EL1:          write_sysreg_s(val, SYS_MAIR_EL12);     break;
+       case VBAR_EL1:          write_sysreg_s(val, SYS_VBAR_EL12);     break;
+       case CONTEXTIDR_EL1:    write_sysreg_s(val, SYS_CONTEXTIDR_EL12);break;
+       case TPIDR_EL0:         write_sysreg_s(val, SYS_TPIDR_EL0);     break;
+       case TPIDRRO_EL0:       write_sysreg_s(val, SYS_TPIDRRO_EL0);   break;
+       case TPIDR_EL1:         write_sysreg_s(val, SYS_TPIDR_EL1);     break;
+       case AMAIR_EL1:         write_sysreg_s(val, SYS_AMAIR_EL12);    break;
+       case CNTKCTL_EL1:       write_sysreg_s(val, SYS_CNTKCTL_EL12);  break;
+       case PAR_EL1:           write_sysreg_s(val, SYS_PAR_EL1);       break;
+       case DACR32_EL2:        write_sysreg_s(val, SYS_DACR32_EL2);    break;
+       case IFSR32_EL2:        write_sysreg_s(val, SYS_IFSR32_EL2);    break;
+       case DBGVCR32_EL2:      write_sysreg_s(val, SYS_DBGVCR32_EL2);  break;
+       default:                return false;
        }
 
-immediate_write:
+       return true;
+}
+
+u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)
+{
+       u64 val = 0x8badf00d8badf00d;
+
+       if (vcpu->arch.sysregs_loaded_on_cpu &&
+           __vcpu_read_sys_reg_from_cpu(reg, &val))
+               return val;
+
+       return __vcpu_sys_reg(vcpu, reg);
+}
+
+void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
+{
+       if (vcpu->arch.sysregs_loaded_on_cpu &&
+           __vcpu_write_sys_reg_to_cpu(val, reg))
+               return;
+
         __vcpu_sys_reg(vcpu, reg) = val;
 }