Commit f5223a33 authored by Sean Christopherson's avatar Sean Christopherson

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
...@@ -3209,6 +3209,7 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) ...@@ -3209,6 +3209,7 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
unsigned bank_num = mcg_cap & 0xff; unsigned bank_num = mcg_cap & 0xff;
u32 msr = msr_info->index; u32 msr = msr_info->index;
u64 data = msr_info->data; u64 data = msr_info->data;
u32 offset, last_msr;
switch (msr) { switch (msr) {
case MSR_IA32_MCG_STATUS: case MSR_IA32_MCG_STATUS:
...@@ -3222,35 +3223,36 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) ...@@ -3222,35 +3223,36 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
return 1; return 1;
vcpu->arch.mcg_ctl = data; vcpu->arch.mcg_ctl = data;
break; break;
default: case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1:
if (msr >= MSR_IA32_MC0_CTL && last_msr = MSR_IA32_MCx_CTL(bank_num) - 1;
msr < MSR_IA32_MCx_CTL(bank_num)) { if (msr > last_msr)
u32 offset = array_index_nospec( return 1;
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.
*
* 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 */ offset = array_index_nospec(msr - MSR_IA32_MC0_CTL,
if (!msr_info->host_initiated && last_msr + 1 - MSR_IA32_MC0_CTL);
(offset & 0x3) == 1 && data != 0) {
if (!can_set_mci_status(vcpu))
return 1;
}
vcpu->arch.mce_banks[offset] = data; /*
break; * 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.
*/
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 && !can_set_mci_status(vcpu))
return 1;
vcpu->arch.mce_banks[offset] = data;
break;
default:
return 1; return 1;
} }
return 0; return 0;
...@@ -3819,6 +3821,7 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) ...@@ -3819,6 +3821,7 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host)
u64 data; u64 data;
u64 mcg_cap = vcpu->arch.mcg_cap; u64 mcg_cap = vcpu->arch.mcg_cap;
unsigned bank_num = mcg_cap & 0xff; unsigned bank_num = mcg_cap & 0xff;
u32 offset, last_msr;
switch (msr) { switch (msr) {
case MSR_IA32_P5_MC_ADDR: 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) ...@@ -3836,16 +3839,16 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host)
case MSR_IA32_MCG_STATUS: case MSR_IA32_MCG_STATUS:
data = vcpu->arch.mcg_status; data = vcpu->arch.mcg_status;
break; break;
default: case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1:
if (msr >= MSR_IA32_MC0_CTL && last_msr = MSR_IA32_MCx_CTL(bank_num) - 1;
msr < MSR_IA32_MCx_CTL(bank_num)) { if (msr > last_msr)
u32 offset = array_index_nospec( return 1;
msr - MSR_IA32_MC0_CTL,
MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL);
data = vcpu->arch.mce_banks[offset]; offset = array_index_nospec(msr - MSR_IA32_MC0_CTL,
break; last_msr + 1 - MSR_IA32_MC0_CTL);
} data = vcpu->arch.mce_banks[offset];
break;
default:
return 1; return 1;
} }
*pdata = data; *pdata = data;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment