Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d808df0 authored by Paul Mackerras's avatar Paul Mackerras
Browse files

KVM: PPC: Book3S HV: Save/restore XER in checkpointed register state



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: e4e38121 ("KVM: PPC: Book3S HV: Add transactional memory support")
Fixes: 0a8eccef ("KVM: PPC: Book3S HV: Add missing code for transaction reclaim on guest exit")
Cc: stable@vger.kernel.org # v3.15+
Signed-off-by: default avatarPaul Mackerras <paulus@ozlabs.org>
Reviewed-by: default avatarThomas Huth <thuth@redhat.com>
Signed-off-by: default avatarPaul Mackerras <paulus@ozlabs.org>
parent a56ee9f8
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -2039,6 +2039,7 @@ registers, find a list below:
  PPC   | KVM_REG_PPC_TM_VSCR           | 32
  PPC   | KVM_REG_PPC_TM_VSCR           | 32
  PPC   | KVM_REG_PPC_TM_DSCR           | 64
  PPC   | KVM_REG_PPC_TM_DSCR           | 64
  PPC   | KVM_REG_PPC_TM_TAR            | 64
  PPC   | KVM_REG_PPC_TM_TAR            | 64
  PPC   | KVM_REG_PPC_TM_XER            | 64
        |                               |
        |                               |
  MIPS  | KVM_REG_MIPS_R0               | 64
  MIPS  | KVM_REG_MIPS_R0               | 64
          ...
          ...
+1 −0
Original line number Original line Diff line number Diff line
@@ -565,6 +565,7 @@ struct kvm_vcpu_arch {
	u64 tfiar;
	u64 tfiar;


	u32 cr_tm;
	u32 cr_tm;
	u64 xer_tm;
	u64 lr_tm;
	u64 lr_tm;
	u64 ctr_tm;
	u64 ctr_tm;
	u64 amr_tm;
	u64 amr_tm;
+1 −0
Original line number Original line Diff line number Diff line
@@ -596,6 +596,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_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_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_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 */
/* PPC64 eXternal Interrupt Controller Specification */
#define KVM_DEV_XICS_GRP_SOURCES	1	/* 64-bit source attributes */
#define KVM_DEV_XICS_GRP_SOURCES	1	/* 64-bit source attributes */
+1 −0
Original line number Original line Diff line number Diff line
@@ -569,6 +569,7 @@ int main(void)
	DEFINE(VCPU_VRS_TM, offsetof(struct kvm_vcpu, arch.vr_tm.vr));
	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_VRSAVE_TM, offsetof(struct kvm_vcpu, arch.vrsave_tm));
	DEFINE(VCPU_CR_TM, offsetof(struct kvm_vcpu, arch.cr_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_LR_TM, offsetof(struct kvm_vcpu, arch.lr_tm));
	DEFINE(VCPU_CTR_TM, offsetof(struct kvm_vcpu, arch.ctr_tm));
	DEFINE(VCPU_CTR_TM, offsetof(struct kvm_vcpu, arch.ctr_tm));
	DEFINE(VCPU_AMR_TM, offsetof(struct kvm_vcpu, arch.amr_tm));
	DEFINE(VCPU_AMR_TM, offsetof(struct kvm_vcpu, arch.amr_tm));
+6 −0
Original line number Original line Diff line number Diff line
@@ -1288,6 +1288,9 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
	case KVM_REG_PPC_TM_CR:
	case KVM_REG_PPC_TM_CR:
		*val = get_reg_val(id, vcpu->arch.cr_tm);
		*val = get_reg_val(id, vcpu->arch.cr_tm);
		break;
		break;
	case KVM_REG_PPC_TM_XER:
		*val = get_reg_val(id, vcpu->arch.xer_tm);
		break;
	case KVM_REG_PPC_TM_LR:
	case KVM_REG_PPC_TM_LR:
		*val = get_reg_val(id, vcpu->arch.lr_tm);
		*val = get_reg_val(id, vcpu->arch.lr_tm);
		break;
		break;
@@ -1498,6 +1501,9 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
	case KVM_REG_PPC_TM_CR:
	case KVM_REG_PPC_TM_CR:
		vcpu->arch.cr_tm = set_reg_val(id, *val);
		vcpu->arch.cr_tm = set_reg_val(id, *val);
		break;
		break;
	case KVM_REG_PPC_TM_XER:
		vcpu->arch.xer_tm = set_reg_val(id, *val);
		break;
	case KVM_REG_PPC_TM_LR:
	case KVM_REG_PPC_TM_LR:
		vcpu->arch.lr_tm = set_reg_val(id, *val);
		vcpu->arch.lr_tm = set_reg_val(id, *val);
		break;
		break;
Loading