KVM: PPC: Book3S HV: Save/restore XER in checkpointed register state
authorPaul Mackerras <paulus@ozlabs.org>
Mon, 7 Nov 2016 04:09:58 +0000 (15:09 +1100)
committerSasha Levin <alexander.levin@verizon.com>
Fri, 13 Jan 2017 01:56:54 +0000 (20:56 -0500)
[ Upstream commit 0d808df06a44200f52262b6eb72bcb6042f5a7c5 ]

When switching from/to a guest that has a transaction in progress,
we need to save/restore the checkpointed register state.  Although
XER is part of the CPU state that gets checkpointed, the code that
does this saving and restoring doesn't save/restore XER.

This fixes it by saving and restoring the XER.  To allow userspace
to read/write the checkpointed XER value, we also add a new ONE_REG
specifier.

The visible effect of this bug is that the guest may see its XER
value being corrupted when it uses transactions.

Fixes: e4e38121507a ("KVM: PPC: Book3S HV: Add transactional memory support")
Fixes: 0a8eccefcb34 ("KVM: PPC: Book3S HV: Add missing code for transaction reclaim on guest exit")
Cc: stable@vger.kernel.org # v3.15+
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
Documentation/virtual/kvm/api.txt
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/uapi/asm/kvm.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S

index 9fa2bf8c3f6f13282c92c33671b5ad9a3eaa1d0a..7830f1c34a7d6fd01455446edb0a517325d6852c 100644 (file)
@@ -1955,6 +1955,7 @@ registers, find a list below:
   PPC   | KVM_REG_PPC_TM_VSCR           | 32
   PPC   | KVM_REG_PPC_TM_DSCR           | 64
   PPC   | KVM_REG_PPC_TM_TAR            | 64
+  PPC   | KVM_REG_PPC_TM_XER            | 64
         |                               |
   MIPS  | KVM_REG_MIPS_R0               | 64
           ...
index a193a13cf08bf1dd40a51e393aeeab4456ce42b0..7fe65af0035de520308958e949496f70820aceec 100644 (file)
@@ -532,6 +532,7 @@ struct kvm_vcpu_arch {
        u64 tfiar;
 
        u32 cr_tm;
+       u64 xer_tm;
        u64 lr_tm;
        u64 ctr_tm;
        u64 amr_tm;
index ab4d4732c492ebc4dd9514733cbb8461af0dbf87..720b71a636c851739adc2e88a4fc2de024ecf7b8 100644 (file)
@@ -587,6 +587,7 @@ struct kvm_get_htab_header {
 #define KVM_REG_PPC_TM_VSCR    (KVM_REG_PPC_TM | KVM_REG_SIZE_U32 | 0x67)
 #define KVM_REG_PPC_TM_DSCR    (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x68)
 #define KVM_REG_PPC_TM_TAR     (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x69)
+#define KVM_REG_PPC_TM_XER     (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x6a)
 
 /* PPC64 eXternal Interrupt Controller Specification */
 #define KVM_DEV_XICS_GRP_SOURCES       1       /* 64-bit source attributes */
index 0034b6b3556a4f6b571ec60fdd55c02535c6ea97..d8d332e65078ed36478d9cb9b22fc5a88e78a366 100644 (file)
@@ -583,6 +583,7 @@ int main(void)
        DEFINE(VCPU_VRS_TM, offsetof(struct kvm_vcpu, arch.vr_tm.vr));
        DEFINE(VCPU_VRSAVE_TM, offsetof(struct kvm_vcpu, arch.vrsave_tm));
        DEFINE(VCPU_CR_TM, offsetof(struct kvm_vcpu, arch.cr_tm));
+       DEFINE(VCPU_XER_TM, offsetof(struct kvm_vcpu, arch.xer_tm));
        DEFINE(VCPU_LR_TM, offsetof(struct kvm_vcpu, arch.lr_tm));
        DEFINE(VCPU_CTR_TM, offsetof(struct kvm_vcpu, arch.ctr_tm));
        DEFINE(VCPU_AMR_TM, offsetof(struct kvm_vcpu, arch.amr_tm));
index f5b3de7f7fa2402740891d75bde94f562f6ac7e2..63c37fd2b7a644191d988d499553083b5a48fe55 100644 (file)
@@ -1171,6 +1171,9 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
        case KVM_REG_PPC_TM_CR:
                *val = get_reg_val(id, vcpu->arch.cr_tm);
                break;
+       case KVM_REG_PPC_TM_XER:
+               *val = get_reg_val(id, vcpu->arch.xer_tm);
+               break;
        case KVM_REG_PPC_TM_LR:
                *val = get_reg_val(id, vcpu->arch.lr_tm);
                break;
@@ -1378,6 +1381,9 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
        case KVM_REG_PPC_TM_CR:
                vcpu->arch.cr_tm = set_reg_val(id, *val);
                break;
+       case KVM_REG_PPC_TM_XER:
+               vcpu->arch.xer_tm = set_reg_val(id, *val);
+               break;
        case KVM_REG_PPC_TM_LR:
                vcpu->arch.lr_tm = set_reg_val(id, *val);
                break;
index 11d82b91aa4f1f8fe92236ffff4143a4ec409fcb..70eaf547703e177479886e89fa46a5725bea73f5 100644 (file)
@@ -2399,11 +2399,13 @@ kvmppc_save_tm:
        mfctr   r7
        mfspr   r8, SPRN_AMR
        mfspr   r10, SPRN_TAR
+       mfxer   r11
        std     r5, VCPU_LR_TM(r9)
        stw     r6, VCPU_CR_TM(r9)
        std     r7, VCPU_CTR_TM(r9)
        std     r8, VCPU_AMR_TM(r9)
        std     r10, VCPU_TAR_TM(r9)
+       std     r11, VCPU_XER_TM(r9)
 
        /* Restore r12 as trap number. */
        lwz     r12, VCPU_TRAP(r9)
@@ -2496,11 +2498,13 @@ kvmppc_restore_tm:
        ld      r7, VCPU_CTR_TM(r4)
        ld      r8, VCPU_AMR_TM(r4)
        ld      r9, VCPU_TAR_TM(r4)
+       ld      r10, VCPU_XER_TM(r4)
        mtlr    r5
        mtcr    r6
        mtctr   r7
        mtspr   SPRN_AMR, r8
        mtspr   SPRN_TAR, r9
+       mtxer   r10
 
        /*
         * Load up PPR and DSCR values but don't put them in the actual SPRs