Commit f5223a33 authored by Sean Christopherson's avatar Sean Christopherson
Browse files

KVM: x86: Use explicit case-statements for MCx banks in {g,s}et_msr_mce()



Use an explicit case statement to grab the full range of MCx bank MSRs
in {g,s}et_msr_mce(), and manually check only the "end" (the number of
banks configured by userspace may be less than the max).  The "default"
trick works, but is a bit odd now, and will be quite odd if/when support
for accessing MCx_CTL2 MSRs is added, which has near identical logic.

Hoist "offset" to function scope so as to avoid curly braces for the case
statement, and because MCx_CTL2 support will need the same variables.

Opportunstically clean up the comment about allowing bit 10 to be cleared
from bank 4.

No functional change intended.

Cc: Jue Wang <juew@google.com>
Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
Reviewed-by: default avatarJim Mattson <jmattson@google.com>
Link: https://lore.kernel.org/r/20220512222716.4112548-3-seanjc@google.com
parent 2368048b
Loading
Loading
Loading
Loading
+39 −36
Original line number Diff line number Diff line
@@ -3209,6 +3209,7 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
	unsigned bank_num = mcg_cap & 0xff;
	u32 msr = msr_info->index;
	u64 data = msr_info->data;
	u32 offset, last_msr;

	switch (msr) {
	case MSR_IA32_MCG_STATUS:
@@ -3222,35 +3223,36 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
			return 1;
		vcpu->arch.mcg_ctl = data;
		break;
	default:
		if (msr >= MSR_IA32_MC0_CTL &&
		    msr < MSR_IA32_MCx_CTL(bank_num)) {
			u32 offset = array_index_nospec(
				msr - MSR_IA32_MC0_CTL,
				MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL);

			/* only 0 or all 1s can be written to IA32_MCi_CTL
			 * some Linux kernels though clear bit 10 in bank 4 to
			 * workaround a BIOS/GART TBL issue on AMD K8s, ignore
			 * this to avoid an uncatched #GP in the guest.
	case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1:
		last_msr = MSR_IA32_MCx_CTL(bank_num) - 1;
		if (msr > last_msr)
			return 1;

		offset = array_index_nospec(msr - MSR_IA32_MC0_CTL,
					    last_msr + 1 - MSR_IA32_MC0_CTL);

		/*
		 * Only 0 or all 1s can be written to IA32_MCi_CTL, all other
		 * values are architecturally undefined.  But, some Linux
		 * kernels clear bit 10 in bank 4 to workaround a BIOS/GART TLB
		 * issue on AMD K8s, allow bit 10 to be clear when setting all
		 * other bits in order to avoid an uncaught #GP in the guest.
		 *
			 * UNIXWARE clears bit 0 of MC1_CTL to ignore
			 * correctable, single-bit ECC data errors.
		 * UNIXWARE clears bit 0 of MC1_CTL to ignore correctable,
		 * single-bit ECC data errors.
		 */
		if ((offset & 0x3) == 0 &&
		    data != 0 && (data | (1 << 10) | 1) != ~(u64)0)
			return 1;

		/* MCi_STATUS */
			if (!msr_info->host_initiated &&
			    (offset & 0x3) == 1 && data != 0) {
				if (!can_set_mci_status(vcpu))
		if (!msr_info->host_initiated && (offset & 0x3) == 1 &&
		    data != 0 && !can_set_mci_status(vcpu))
			return 1;
			}

		vcpu->arch.mce_banks[offset] = data;
		break;
		}
	default:
		return 1;
	}
	return 0;
@@ -3819,6 +3821,7 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host)
	u64 data;
	u64 mcg_cap = vcpu->arch.mcg_cap;
	unsigned bank_num = mcg_cap & 0xff;
	u32 offset, last_msr;

	switch (msr) {
	case MSR_IA32_P5_MC_ADDR:
@@ -3836,16 +3839,16 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host)
	case MSR_IA32_MCG_STATUS:
		data = vcpu->arch.mcg_status;
		break;
	default:
		if (msr >= MSR_IA32_MC0_CTL &&
		    msr < MSR_IA32_MCx_CTL(bank_num)) {
			u32 offset = array_index_nospec(
				msr - MSR_IA32_MC0_CTL,
				MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL);
	case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1:
		last_msr = MSR_IA32_MCx_CTL(bank_num) - 1;
		if (msr > last_msr)
			return 1;

		offset = array_index_nospec(msr - MSR_IA32_MC0_CTL,
					    last_msr + 1 - MSR_IA32_MC0_CTL);
		data = vcpu->arch.mce_banks[offset];
		break;
		}
	default:
		return 1;
	}
	*pdata = data;