mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 22:14:03 +02:00
When handling userspace SREGS writes, check the validity of EFER (i.e. allowed bits) before writing the new value of EFER through the per-vendor set_efer callbacks. This prevents userspace from writing bogus values (e.g. EFER.SVME=1 with nested=0). Note: on KVM_SET_MSRS, KVM only checks EFER validity in terms of KVM caps, not guest caps, so it is possible to set EFER bits that are supported by KVM but not by the guest CPUID. Potentially allowing userspace to set msrs before CPUID. However, for KVM_SET_SREGS*, check the validity of the set bits against both KVM and guest caps. This is consistent with other validity checks (e.g. for CR4) that check validity against guest caps, which already imposes the need to set CPUID before SREGS. Cc: stable@vger.kernel.org Signed-off-by: Yosry Ahmed <yosry@kernel.org> Link: https://patch.msgid.link/20260713180153.2728382-2-yosry@kernel.org Signed-off-by: Sean Christopherson <seanjc@google.com>
876 lines
23 KiB
C
876 lines
23 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
#include <linux/kvm_host.h>
|
|
|
|
#include "lapic.h"
|
|
#include "mmu.h"
|
|
#include "regs.h"
|
|
#include "x86.h"
|
|
|
|
unsigned long kvm_get_linear_rip(struct kvm_vcpu *vcpu)
|
|
{
|
|
/* Can't read the RIP when guest state is protected, just return 0 */
|
|
if (vcpu->arch.guest_state_protected)
|
|
return 0;
|
|
|
|
if (is_64_bit_mode(vcpu))
|
|
return kvm_rip_read(vcpu);
|
|
return (u32)(kvm_get_segment_base(vcpu, VCPU_SREG_CS) +
|
|
kvm_rip_read(vcpu));
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_linear_rip);
|
|
|
|
bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip)
|
|
{
|
|
return kvm_get_linear_rip(vcpu) == linear_rip;
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_is_linear_rip);
|
|
|
|
unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu)
|
|
{
|
|
unsigned long rflags;
|
|
|
|
rflags = kvm_x86_call(get_rflags)(vcpu);
|
|
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
|
|
rflags &= ~X86_EFLAGS_TF;
|
|
return rflags;
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_rflags);
|
|
|
|
void __kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
|
|
{
|
|
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP &&
|
|
kvm_is_linear_rip(vcpu, vcpu->arch.singlestep_rip))
|
|
rflags |= X86_EFLAGS_TF;
|
|
kvm_x86_call(set_rflags)(vcpu, rflags);
|
|
}
|
|
|
|
void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
|
|
{
|
|
__kvm_set_rflags(vcpu, rflags);
|
|
kvm_make_request(KVM_REQ_EVENT, vcpu);
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_rflags);
|
|
|
|
static void __get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
|
{
|
|
if (vcpu->arch.emulate_regs_need_sync_to_vcpu) {
|
|
/*
|
|
* We are here if userspace calls get_regs() in the middle of
|
|
* instruction emulation. Registers state needs to be copied
|
|
* back from emulation context to vcpu. Userspace shouldn't do
|
|
* that usually, but some bad designed PV devices (vmware
|
|
* backdoor interface) need this to work
|
|
*/
|
|
emulator_writeback_register_cache(vcpu->arch.emulate_ctxt);
|
|
vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
|
|
}
|
|
regs->rax = kvm_rax_read_raw(vcpu);
|
|
regs->rbx = kvm_rbx_read_raw(vcpu);
|
|
regs->rcx = kvm_rcx_read_raw(vcpu);
|
|
regs->rdx = kvm_rdx_read_raw(vcpu);
|
|
regs->rsi = kvm_rsi_read_raw(vcpu);
|
|
regs->rdi = kvm_rdi_read_raw(vcpu);
|
|
regs->rsp = kvm_rsp_read(vcpu);
|
|
regs->rbp = kvm_rbp_read_raw(vcpu);
|
|
#ifdef CONFIG_X86_64
|
|
regs->r8 = kvm_r8_read_raw(vcpu);
|
|
regs->r9 = kvm_r9_read_raw(vcpu);
|
|
regs->r10 = kvm_r10_read_raw(vcpu);
|
|
regs->r11 = kvm_r11_read_raw(vcpu);
|
|
regs->r12 = kvm_r12_read_raw(vcpu);
|
|
regs->r13 = kvm_r13_read_raw(vcpu);
|
|
regs->r14 = kvm_r14_read_raw(vcpu);
|
|
regs->r15 = kvm_r15_read_raw(vcpu);
|
|
#endif
|
|
|
|
regs->rip = kvm_rip_read(vcpu);
|
|
regs->rflags = kvm_get_rflags(vcpu);
|
|
}
|
|
|
|
int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
|
{
|
|
if (vcpu->kvm->arch.has_protected_state &&
|
|
vcpu->arch.guest_state_protected)
|
|
return -EINVAL;
|
|
|
|
vcpu_load(vcpu);
|
|
__get_regs(vcpu, regs);
|
|
vcpu_put(vcpu);
|
|
return 0;
|
|
}
|
|
|
|
static void __set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
|
{
|
|
vcpu->arch.emulate_regs_need_sync_from_vcpu = true;
|
|
vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
|
|
|
|
kvm_rax_write_raw(vcpu, regs->rax);
|
|
kvm_rbx_write_raw(vcpu, regs->rbx);
|
|
kvm_rcx_write_raw(vcpu, regs->rcx);
|
|
kvm_rdx_write_raw(vcpu, regs->rdx);
|
|
kvm_rsi_write_raw(vcpu, regs->rsi);
|
|
kvm_rdi_write_raw(vcpu, regs->rdi);
|
|
kvm_rsp_write(vcpu, regs->rsp);
|
|
kvm_rbp_write_raw(vcpu, regs->rbp);
|
|
#ifdef CONFIG_X86_64
|
|
kvm_r8_write_raw(vcpu, regs->r8);
|
|
kvm_r9_write_raw(vcpu, regs->r9);
|
|
kvm_r10_write_raw(vcpu, regs->r10);
|
|
kvm_r11_write_raw(vcpu, regs->r11);
|
|
kvm_r12_write_raw(vcpu, regs->r12);
|
|
kvm_r13_write_raw(vcpu, regs->r13);
|
|
kvm_r14_write_raw(vcpu, regs->r14);
|
|
kvm_r15_write_raw(vcpu, regs->r15);
|
|
#endif
|
|
|
|
kvm_rip_write(vcpu, regs->rip);
|
|
kvm_set_rflags(vcpu, regs->rflags | X86_EFLAGS_FIXED);
|
|
|
|
vcpu->arch.exception.pending = false;
|
|
vcpu->arch.exception_vmexit.pending = false;
|
|
|
|
kvm_make_request(KVM_REQ_EVENT, vcpu);
|
|
}
|
|
|
|
int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
|
{
|
|
if (vcpu->kvm->arch.has_protected_state &&
|
|
vcpu->arch.guest_state_protected)
|
|
return -EINVAL;
|
|
|
|
vcpu_load(vcpu);
|
|
__set_regs(vcpu, regs);
|
|
vcpu_put(vcpu);
|
|
return 0;
|
|
}
|
|
|
|
static inline u64 pdptr_rsvd_bits(struct kvm_vcpu *vcpu)
|
|
{
|
|
return vcpu->arch.reserved_gpa_bits | rsvd_bits(5, 8) | rsvd_bits(1, 2);
|
|
}
|
|
|
|
/*
|
|
* Load the pae pdptrs. Return 1 if they are all valid, 0 otherwise.
|
|
*/
|
|
int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
|
|
{
|
|
struct kvm_pagewalk *w = &vcpu->arch.gva_walk;
|
|
gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
|
|
gpa_t real_gpa;
|
|
int i;
|
|
int ret;
|
|
u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)];
|
|
|
|
/*
|
|
* If the MMU is nested, CR3 holds an L2 GPA and needs to be translated
|
|
* to an L1 GPA.
|
|
*/
|
|
real_gpa = kvm_translate_gpa(vcpu, w, gfn_to_gpa(pdpt_gfn),
|
|
PFERR_USER_MASK | PFERR_WRITE_MASK |
|
|
PFERR_GUEST_PAGE_MASK, NULL, 0);
|
|
if (real_gpa == INVALID_GPA)
|
|
return 0;
|
|
|
|
/* Note the offset, PDPTRs are 32 byte aligned when using PAE paging. */
|
|
ret = kvm_vcpu_read_guest_page(vcpu, gpa_to_gfn(real_gpa), pdpte,
|
|
cr3 & GENMASK(11, 5), sizeof(pdpte));
|
|
if (ret < 0)
|
|
return 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
|
|
if ((pdpte[i] & PT_PRESENT_MASK) &&
|
|
(pdpte[i] & pdptr_rsvd_bits(vcpu))) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Marking VCPU_REG_PDPTR dirty doesn't work for !tdp_enabled.
|
|
* Shadow page roots need to be reconstructed instead.
|
|
*/
|
|
if (!tdp_enabled && memcmp(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs)))
|
|
kvm_mmu_free_roots(vcpu->kvm, &vcpu->arch.root_mmu,
|
|
KVM_MMU_ROOT_CURRENT);
|
|
|
|
memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs));
|
|
kvm_register_mark_dirty(vcpu, VCPU_REG_PDPTR);
|
|
kvm_make_request(KVM_REQ_LOAD_MMU_PGD, vcpu);
|
|
vcpu->arch.pdptrs_from_userspace = false;
|
|
|
|
return 1;
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(load_pdptrs);
|
|
|
|
static bool kvm_is_valid_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
|
|
{
|
|
#ifdef CONFIG_X86_64
|
|
if (cr0 & 0xffffffff00000000UL)
|
|
return false;
|
|
#endif
|
|
|
|
if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD))
|
|
return false;
|
|
|
|
if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE))
|
|
return false;
|
|
|
|
return kvm_x86_call(is_valid_cr0)(vcpu, cr0);
|
|
}
|
|
|
|
void kvm_post_set_cr0(struct kvm_vcpu *vcpu, unsigned long old_cr0, unsigned long cr0)
|
|
{
|
|
/*
|
|
* CR0.WP is incorporated into the MMU role, but only for non-nested,
|
|
* indirect shadow MMUs. If paging is disabled, no updates are needed
|
|
* as there are no permission bits to emulate. If TDP is enabled, the
|
|
* MMU's metadata needs to be updated, e.g. so that emulating guest
|
|
* translations does the right thing, but there's no need to unload the
|
|
* root as CR0.WP doesn't affect SPTEs.
|
|
*/
|
|
if ((cr0 ^ old_cr0) == X86_CR0_WP) {
|
|
if (!(cr0 & X86_CR0_PG))
|
|
return;
|
|
|
|
if (tdp_enabled) {
|
|
kvm_init_mmu(vcpu);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ((cr0 ^ old_cr0) & X86_CR0_PG) {
|
|
/*
|
|
* Clearing CR0.PG is defined to flush the TLB from the guest's
|
|
* perspective.
|
|
*/
|
|
if (!(cr0 & X86_CR0_PG))
|
|
kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
|
|
/*
|
|
* Check for async #PF completion events when enabling paging,
|
|
* as the vCPU may have previously encountered async #PFs (it's
|
|
* entirely legal for the guest to toggle paging on/off without
|
|
* waiting for the async #PF queue to drain).
|
|
*/
|
|
else if (kvm_pv_async_pf_enabled(vcpu))
|
|
kvm_make_request(KVM_REQ_APF_READY, vcpu);
|
|
}
|
|
|
|
if ((cr0 ^ old_cr0) & KVM_MMU_CR0_ROLE_BITS)
|
|
kvm_mmu_reset_context(vcpu);
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_post_set_cr0);
|
|
|
|
int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
|
|
{
|
|
unsigned long old_cr0 = kvm_read_cr0(vcpu);
|
|
|
|
if (!kvm_is_valid_cr0(vcpu, cr0))
|
|
return 1;
|
|
|
|
cr0 |= X86_CR0_ET;
|
|
|
|
/* Write to CR0 reserved bits are ignored, even on Intel. */
|
|
cr0 &= ~CR0_RESERVED_BITS;
|
|
|
|
#ifdef CONFIG_X86_64
|
|
if ((vcpu->arch.efer & EFER_LME) && !is_paging(vcpu) &&
|
|
(cr0 & X86_CR0_PG)) {
|
|
int cs_db, cs_l;
|
|
|
|
if (!is_pae(vcpu))
|
|
return 1;
|
|
kvm_x86_call(get_cs_db_l_bits)(vcpu, &cs_db, &cs_l);
|
|
if (cs_l)
|
|
return 1;
|
|
}
|
|
#endif
|
|
if (!(vcpu->arch.efer & EFER_LME) && (cr0 & X86_CR0_PG) &&
|
|
is_pae(vcpu) && ((cr0 ^ old_cr0) & X86_CR0_PDPTR_BITS) &&
|
|
!load_pdptrs(vcpu, kvm_read_cr3(vcpu)))
|
|
return 1;
|
|
|
|
if (!(cr0 & X86_CR0_PG) &&
|
|
(is_64_bit_mode(vcpu) || kvm_is_cr4_bit_set(vcpu, X86_CR4_PCIDE)))
|
|
return 1;
|
|
|
|
if (!(cr0 & X86_CR0_WP) && kvm_is_cr4_bit_set(vcpu, X86_CR4_CET))
|
|
return 1;
|
|
|
|
kvm_x86_call(set_cr0)(vcpu, cr0);
|
|
|
|
kvm_post_set_cr0(vcpu, old_cr0, cr0);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr0);
|
|
|
|
void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
|
|
{
|
|
(void)kvm_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~0x0eul) | (msw & 0x0f));
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_lmsw);
|
|
|
|
int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
|
|
{
|
|
bool skip_tlb_flush = false;
|
|
unsigned long pcid = 0;
|
|
#ifdef CONFIG_X86_64
|
|
if (kvm_is_cr4_bit_set(vcpu, X86_CR4_PCIDE)) {
|
|
skip_tlb_flush = cr3 & X86_CR3_PCID_NOFLUSH;
|
|
cr3 &= ~X86_CR3_PCID_NOFLUSH;
|
|
pcid = cr3 & X86_CR3_PCID_MASK;
|
|
}
|
|
#endif
|
|
|
|
/* PDPTRs are always reloaded for PAE paging. */
|
|
if (cr3 == kvm_read_cr3(vcpu) && !is_pae_paging(vcpu))
|
|
goto handle_tlb_flush;
|
|
|
|
/*
|
|
* Do not condition the GPA check on long mode, this helper is used to
|
|
* stuff CR3, e.g. for RSM emulation, and there is no guarantee that
|
|
* the current vCPU mode is accurate.
|
|
*/
|
|
if (!kvm_vcpu_is_legal_cr3(vcpu, cr3))
|
|
return 1;
|
|
|
|
if (is_pae_paging(vcpu) && !load_pdptrs(vcpu, cr3))
|
|
return 1;
|
|
|
|
if (cr3 != kvm_read_cr3(vcpu))
|
|
kvm_mmu_new_pgd(vcpu, cr3);
|
|
|
|
vcpu->arch.cr3 = cr3;
|
|
kvm_register_mark_dirty(vcpu, VCPU_REG_CR3);
|
|
/* Do not call post_set_cr3, we do not get here for confidential guests. */
|
|
|
|
handle_tlb_flush:
|
|
/*
|
|
* A load of CR3 that flushes the TLB flushes only the current PCID,
|
|
* even if PCID is disabled, in which case PCID=0 is flushed. It's a
|
|
* moot point in the end because _disabling_ PCID will flush all PCIDs,
|
|
* and it's impossible to use a non-zero PCID when PCID is disabled,
|
|
* i.e. only PCID=0 can be relevant.
|
|
*/
|
|
if (!skip_tlb_flush)
|
|
kvm_invalidate_pcid(vcpu, pcid);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr3);
|
|
|
|
static bool kvm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
|
|
{
|
|
return __kvm_is_valid_cr4(vcpu, cr4) &&
|
|
kvm_x86_call(is_valid_cr4)(vcpu, cr4);
|
|
}
|
|
|
|
void kvm_post_set_cr4(struct kvm_vcpu *vcpu, unsigned long old_cr4, unsigned long cr4)
|
|
{
|
|
if ((cr4 ^ old_cr4) & KVM_MMU_CR4_ROLE_BITS)
|
|
kvm_mmu_reset_context(vcpu);
|
|
|
|
/*
|
|
* If CR4.PCIDE is changed 0 -> 1, there is no need to flush the TLB
|
|
* according to the SDM; however, stale prev_roots could be reused
|
|
* incorrectly in the future after a MOV to CR3 with NOFLUSH=1, so we
|
|
* free them all. This is *not* a superset of KVM_REQ_TLB_FLUSH_GUEST
|
|
* or KVM_REQ_TLB_FLUSH_CURRENT, because the hardware TLB is not flushed,
|
|
* so fall through.
|
|
*/
|
|
if (!tdp_enabled &&
|
|
(cr4 & X86_CR4_PCIDE) && !(old_cr4 & X86_CR4_PCIDE))
|
|
kvm_mmu_unload(vcpu);
|
|
|
|
/*
|
|
* The TLB has to be flushed for all PCIDs if any of the following
|
|
* (architecturally required) changes happen:
|
|
* - CR4.PCIDE is changed from 1 to 0
|
|
* - CR4.PGE is toggled
|
|
*
|
|
* This is a superset of KVM_REQ_TLB_FLUSH_CURRENT.
|
|
*/
|
|
if (((cr4 ^ old_cr4) & X86_CR4_PGE) ||
|
|
(!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
|
|
kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
|
|
|
|
/*
|
|
* The TLB has to be flushed for the current PCID if any of the
|
|
* following (architecturally required) changes happen:
|
|
* - CR4.SMEP is changed from 0 to 1
|
|
* - CR4.PAE is toggled
|
|
*/
|
|
else if (((cr4 ^ old_cr4) & X86_CR4_PAE) ||
|
|
((cr4 & X86_CR4_SMEP) && !(old_cr4 & X86_CR4_SMEP)))
|
|
kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
|
|
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_post_set_cr4);
|
|
|
|
int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
|
|
{
|
|
unsigned long old_cr4 = kvm_read_cr4(vcpu);
|
|
|
|
if (!kvm_is_valid_cr4(vcpu, cr4))
|
|
return 1;
|
|
|
|
if (is_long_mode(vcpu)) {
|
|
if (!(cr4 & X86_CR4_PAE))
|
|
return 1;
|
|
if ((cr4 ^ old_cr4) & X86_CR4_LA57)
|
|
return 1;
|
|
} else if (is_paging(vcpu) && (cr4 & X86_CR4_PAE)
|
|
&& ((cr4 ^ old_cr4) & X86_CR4_PDPTR_BITS)
|
|
&& !load_pdptrs(vcpu, kvm_read_cr3(vcpu)))
|
|
return 1;
|
|
|
|
if ((cr4 & X86_CR4_PCIDE) && !(old_cr4 & X86_CR4_PCIDE)) {
|
|
/* PCID can not be enabled when cr3[11:0]!=000H or EFER.LMA=0 */
|
|
if ((kvm_read_cr3(vcpu) & X86_CR3_PCID_MASK) || !is_long_mode(vcpu))
|
|
return 1;
|
|
}
|
|
|
|
if ((cr4 & X86_CR4_CET) && !kvm_is_cr0_bit_set(vcpu, X86_CR0_WP))
|
|
return 1;
|
|
|
|
kvm_x86_call(set_cr4)(vcpu, cr4);
|
|
|
|
kvm_post_set_cr4(vcpu, old_cr4, cr4);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr4);
|
|
|
|
int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
|
|
{
|
|
if (cr8 & CR8_RESERVED_BITS)
|
|
return 1;
|
|
if (lapic_in_kernel(vcpu))
|
|
kvm_lapic_set_tpr(vcpu, cr8);
|
|
else
|
|
vcpu->arch.cr8 = cr8;
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr8);
|
|
|
|
unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu)
|
|
{
|
|
if (lapic_in_kernel(vcpu))
|
|
return kvm_lapic_get_cr8(vcpu);
|
|
else
|
|
return vcpu->arch.cr8;
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_cr8);
|
|
|
|
static void __get_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
|
|
{
|
|
struct desc_ptr dt;
|
|
|
|
if (vcpu->arch.guest_state_protected)
|
|
goto skip_protected_regs;
|
|
|
|
kvm_handle_exception_payload_quirk(vcpu);
|
|
|
|
kvm_get_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
|
|
kvm_get_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
|
|
kvm_get_segment(vcpu, &sregs->es, VCPU_SREG_ES);
|
|
kvm_get_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
|
|
kvm_get_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
|
|
kvm_get_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
|
|
|
|
kvm_get_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
|
|
kvm_get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
|
|
|
|
kvm_x86_call(get_idt)(vcpu, &dt);
|
|
sregs->idt.limit = dt.size;
|
|
sregs->idt.base = dt.address;
|
|
kvm_x86_call(get_gdt)(vcpu, &dt);
|
|
sregs->gdt.limit = dt.size;
|
|
sregs->gdt.base = dt.address;
|
|
|
|
sregs->cr2 = vcpu->arch.cr2;
|
|
sregs->cr3 = kvm_read_cr3(vcpu);
|
|
|
|
skip_protected_regs:
|
|
sregs->cr0 = kvm_read_cr0(vcpu);
|
|
sregs->cr4 = kvm_read_cr4(vcpu);
|
|
sregs->cr8 = kvm_get_cr8(vcpu);
|
|
sregs->efer = vcpu->arch.efer;
|
|
sregs->apic_base = vcpu->arch.apic_base;
|
|
}
|
|
|
|
static void __get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
|
|
{
|
|
__get_sregs_common(vcpu, sregs);
|
|
|
|
if (vcpu->arch.guest_state_protected)
|
|
return;
|
|
|
|
if (vcpu->arch.interrupt.injected && !vcpu->arch.interrupt.soft)
|
|
set_bit(vcpu->arch.interrupt.nr,
|
|
(unsigned long *)sregs->interrupt_bitmap);
|
|
}
|
|
|
|
int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
|
|
struct kvm_sregs *sregs)
|
|
{
|
|
if (vcpu->kvm->arch.has_protected_state &&
|
|
vcpu->arch.guest_state_protected)
|
|
return -EINVAL;
|
|
|
|
vcpu_load(vcpu);
|
|
__get_sregs(vcpu, sregs);
|
|
vcpu_put(vcpu);
|
|
return 0;
|
|
}
|
|
|
|
void kvm_vcpu_ioctl_x86_get_sregs2(struct kvm_vcpu *vcpu,
|
|
struct kvm_sregs2 *sregs2)
|
|
{
|
|
int i;
|
|
|
|
__get_sregs_common(vcpu, (struct kvm_sregs *)sregs2);
|
|
|
|
if (vcpu->arch.guest_state_protected)
|
|
return;
|
|
|
|
if (is_pae_paging(vcpu)) {
|
|
kvm_vcpu_srcu_read_lock(vcpu);
|
|
for (i = 0 ; i < 4 ; i++)
|
|
sregs2->pdptrs[i] = kvm_pdptr_read(vcpu, i);
|
|
sregs2->flags |= KVM_SREGS2_FLAGS_PDPTRS_VALID;
|
|
kvm_vcpu_srcu_read_unlock(vcpu);
|
|
}
|
|
}
|
|
|
|
static bool kvm_is_valid_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
|
|
{
|
|
if ((sregs->efer & EFER_LME) && (sregs->cr0 & X86_CR0_PG)) {
|
|
/*
|
|
* When EFER.LME and CR0.PG are set, the processor is in
|
|
* 64-bit mode (though maybe in a 32-bit code segment).
|
|
* CR4.PAE and EFER.LMA must be set.
|
|
*/
|
|
if (!(sregs->cr4 & X86_CR4_PAE) || !(sregs->efer & EFER_LMA))
|
|
return false;
|
|
if (!kvm_vcpu_is_legal_cr3(vcpu, sregs->cr3))
|
|
return false;
|
|
} else {
|
|
/*
|
|
* Not in 64-bit mode: EFER.LMA is clear and the code
|
|
* segment cannot be 64-bit.
|
|
*/
|
|
if (sregs->efer & EFER_LMA || sregs->cs.l)
|
|
return false;
|
|
}
|
|
|
|
return kvm_is_valid_cr4(vcpu, sregs->cr4) &&
|
|
kvm_is_valid_cr0(vcpu, sregs->cr0) &&
|
|
kvm_valid_efer(vcpu, sregs->efer);
|
|
}
|
|
|
|
static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs,
|
|
int *mmu_reset_needed, bool update_pdptrs)
|
|
{
|
|
int idx;
|
|
struct desc_ptr dt;
|
|
|
|
if (!kvm_is_valid_sregs(vcpu, sregs))
|
|
return -EINVAL;
|
|
|
|
if (kvm_apic_set_base(vcpu, sregs->apic_base, true))
|
|
return -EINVAL;
|
|
|
|
if (vcpu->arch.guest_state_protected)
|
|
return 0;
|
|
|
|
dt.size = sregs->idt.limit;
|
|
dt.address = sregs->idt.base;
|
|
kvm_x86_call(set_idt)(vcpu, &dt);
|
|
dt.size = sregs->gdt.limit;
|
|
dt.address = sregs->gdt.base;
|
|
kvm_x86_call(set_gdt)(vcpu, &dt);
|
|
|
|
vcpu->arch.cr2 = sregs->cr2;
|
|
*mmu_reset_needed |= kvm_read_cr3(vcpu) != sregs->cr3;
|
|
vcpu->arch.cr3 = sregs->cr3;
|
|
kvm_register_mark_dirty(vcpu, VCPU_REG_CR3);
|
|
kvm_x86_call(post_set_cr3)(vcpu, sregs->cr3);
|
|
|
|
*mmu_reset_needed |= vcpu->arch.efer != sregs->efer;
|
|
kvm_x86_call(set_efer)(vcpu, sregs->efer);
|
|
|
|
*mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0;
|
|
kvm_x86_call(set_cr0)(vcpu, sregs->cr0);
|
|
|
|
*mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
|
|
kvm_x86_call(set_cr4)(vcpu, sregs->cr4);
|
|
|
|
if (update_pdptrs) {
|
|
idx = srcu_read_lock(&vcpu->kvm->srcu);
|
|
if (is_pae_paging(vcpu)) {
|
|
load_pdptrs(vcpu, kvm_read_cr3(vcpu));
|
|
*mmu_reset_needed = 1;
|
|
}
|
|
srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
|
}
|
|
|
|
kvm_set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
|
|
kvm_set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
|
|
kvm_set_segment(vcpu, &sregs->es, VCPU_SREG_ES);
|
|
kvm_set_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
|
|
kvm_set_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
|
|
kvm_set_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
|
|
|
|
kvm_set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
|
|
kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
|
|
|
|
kvm_set_cr8(vcpu, sregs->cr8);
|
|
|
|
/* Older userspace won't unhalt the vcpu on reset. */
|
|
if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 &&
|
|
sregs->cs.selector == 0xf000 && sregs->cs.base == 0xffff0000 &&
|
|
!is_protmode(vcpu))
|
|
kvm_set_mp_state(vcpu, KVM_MP_STATE_RUNNABLE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
|
|
{
|
|
int pending_vec, max_bits;
|
|
int mmu_reset_needed = 0;
|
|
int ret = __set_sregs_common(vcpu, sregs, &mmu_reset_needed, true);
|
|
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (mmu_reset_needed) {
|
|
kvm_mmu_reset_context(vcpu);
|
|
kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
|
|
}
|
|
|
|
max_bits = KVM_NR_INTERRUPTS;
|
|
pending_vec = find_first_bit(
|
|
(const unsigned long *)sregs->interrupt_bitmap, max_bits);
|
|
|
|
if (pending_vec < max_bits) {
|
|
kvm_queue_interrupt(vcpu, pending_vec, false);
|
|
pr_debug("Set back pending irq %d\n", pending_vec);
|
|
kvm_make_request(KVM_REQ_EVENT, vcpu);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
|
|
struct kvm_sregs *sregs)
|
|
{
|
|
int ret;
|
|
|
|
if (vcpu->kvm->arch.has_protected_state &&
|
|
vcpu->arch.guest_state_protected)
|
|
return -EINVAL;
|
|
|
|
vcpu_load(vcpu);
|
|
ret = __set_sregs(vcpu, sregs);
|
|
vcpu_put(vcpu);
|
|
return ret;
|
|
}
|
|
|
|
int kvm_vcpu_ioctl_x86_set_sregs2(struct kvm_vcpu *vcpu,
|
|
struct kvm_sregs2 *sregs2)
|
|
{
|
|
int mmu_reset_needed = 0;
|
|
bool valid_pdptrs = sregs2->flags & KVM_SREGS2_FLAGS_PDPTRS_VALID;
|
|
bool pae = (sregs2->cr0 & X86_CR0_PG) && (sregs2->cr4 & X86_CR4_PAE) &&
|
|
!(sregs2->efer & EFER_LMA);
|
|
int i, ret;
|
|
|
|
if (sregs2->flags & ~KVM_SREGS2_FLAGS_PDPTRS_VALID)
|
|
return -EINVAL;
|
|
|
|
if (valid_pdptrs && (!pae || vcpu->arch.guest_state_protected))
|
|
return -EINVAL;
|
|
|
|
ret = __set_sregs_common(vcpu, (struct kvm_sregs *)sregs2,
|
|
&mmu_reset_needed, !valid_pdptrs);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (valid_pdptrs) {
|
|
for (i = 0; i < 4 ; i++)
|
|
kvm_pdptr_write(vcpu, i, sregs2->pdptrs[i]);
|
|
|
|
kvm_register_mark_dirty(vcpu, VCPU_REG_PDPTR);
|
|
mmu_reset_needed = 1;
|
|
vcpu->arch.pdptrs_from_userspace = true;
|
|
}
|
|
if (mmu_reset_needed) {
|
|
kvm_mmu_reset_context(vcpu);
|
|
kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void kvm_run_sync_regs_to_user(struct kvm_vcpu *vcpu)
|
|
{
|
|
BUILD_BUG_ON(sizeof(struct kvm_sync_regs) > SYNC_REGS_SIZE_BYTES);
|
|
|
|
if (vcpu->run->kvm_valid_regs & KVM_SYNC_X86_REGS)
|
|
__get_regs(vcpu, &vcpu->run->s.regs.regs);
|
|
|
|
if (vcpu->run->kvm_valid_regs & KVM_SYNC_X86_SREGS)
|
|
__get_sregs(vcpu, &vcpu->run->s.regs.sregs);
|
|
}
|
|
|
|
int kvm_run_sync_regs_from_user(struct kvm_vcpu *vcpu)
|
|
{
|
|
if (vcpu->run->kvm_dirty_regs & KVM_SYNC_X86_REGS) {
|
|
__set_regs(vcpu, &vcpu->run->s.regs.regs);
|
|
vcpu->run->kvm_dirty_regs &= ~KVM_SYNC_X86_REGS;
|
|
}
|
|
|
|
if (vcpu->run->kvm_dirty_regs & KVM_SYNC_X86_SREGS) {
|
|
struct kvm_sregs sregs = vcpu->run->s.regs.sregs;
|
|
|
|
if (__set_sregs(vcpu, &sregs))
|
|
return -EINVAL;
|
|
|
|
vcpu->run->kvm_dirty_regs &= ~KVM_SYNC_X86_SREGS;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void kvm_update_dr0123(struct kvm_vcpu *vcpu)
|
|
{
|
|
int i;
|
|
|
|
if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
|
|
for (i = 0; i < KVM_NR_DB_REGS; i++)
|
|
vcpu->arch.eff_db[i] = vcpu->arch.db[i];
|
|
}
|
|
}
|
|
|
|
void kvm_update_dr7(struct kvm_vcpu *vcpu)
|
|
{
|
|
unsigned long dr7;
|
|
|
|
if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
|
|
dr7 = vcpu->arch.guest_debug_dr7;
|
|
else
|
|
dr7 = vcpu->arch.dr7;
|
|
kvm_x86_call(set_dr7)(vcpu, dr7);
|
|
vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_BP_ENABLED;
|
|
if (dr7 & DR7_BP_EN_MASK)
|
|
vcpu->arch.switch_db_regs |= KVM_DEBUGREG_BP_ENABLED;
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_update_dr7);
|
|
|
|
static u64 kvm_dr6_fixed(struct kvm_vcpu *vcpu)
|
|
{
|
|
u64 fixed = DR6_FIXED_1;
|
|
|
|
if (!guest_cpu_cap_has(vcpu, X86_FEATURE_RTM))
|
|
fixed |= DR6_RTM;
|
|
|
|
if (!guest_cpu_cap_has(vcpu, X86_FEATURE_BUS_LOCK_DETECT))
|
|
fixed |= DR6_BUS_LOCK;
|
|
return fixed;
|
|
}
|
|
|
|
int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
|
|
{
|
|
size_t size = ARRAY_SIZE(vcpu->arch.db);
|
|
|
|
switch (dr) {
|
|
case 0 ... 3:
|
|
vcpu->arch.db[array_index_nospec(dr, size)] = val;
|
|
if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
|
|
vcpu->arch.eff_db[dr] = val;
|
|
break;
|
|
case 4:
|
|
case 6:
|
|
if (!kvm_dr6_valid(val))
|
|
return 1; /* #GP */
|
|
vcpu->arch.dr6 = (val & DR6_VOLATILE) | kvm_dr6_fixed(vcpu);
|
|
break;
|
|
case 5:
|
|
default: /* 7 */
|
|
if (!kvm_dr7_valid(val))
|
|
return 1; /* #GP */
|
|
vcpu->arch.dr7 = (val & DR7_VOLATILE) | DR7_FIXED_1;
|
|
kvm_update_dr7(vcpu);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_dr);
|
|
|
|
unsigned long kvm_get_dr(struct kvm_vcpu *vcpu, int dr)
|
|
{
|
|
size_t size = ARRAY_SIZE(vcpu->arch.db);
|
|
|
|
switch (dr) {
|
|
case 0 ... 3:
|
|
return vcpu->arch.db[array_index_nospec(dr, size)];
|
|
case 4:
|
|
case 6:
|
|
return vcpu->arch.dr6;
|
|
case 5:
|
|
default: /* 7 */
|
|
return vcpu->arch.dr7;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_dr);
|
|
|
|
int kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
|
|
struct kvm_debugregs *dbgregs)
|
|
{
|
|
unsigned int i;
|
|
|
|
if (vcpu->kvm->arch.has_protected_state &&
|
|
vcpu->arch.guest_state_protected)
|
|
return -EINVAL;
|
|
|
|
kvm_handle_exception_payload_quirk(vcpu);
|
|
|
|
memset(dbgregs, 0, sizeof(*dbgregs));
|
|
|
|
BUILD_BUG_ON(ARRAY_SIZE(vcpu->arch.db) != ARRAY_SIZE(dbgregs->db));
|
|
for (i = 0; i < ARRAY_SIZE(vcpu->arch.db); i++)
|
|
dbgregs->db[i] = vcpu->arch.db[i];
|
|
|
|
dbgregs->dr6 = vcpu->arch.dr6;
|
|
dbgregs->dr7 = vcpu->arch.dr7;
|
|
return 0;
|
|
}
|
|
|
|
int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
|
|
struct kvm_debugregs *dbgregs)
|
|
{
|
|
unsigned int i;
|
|
|
|
if (vcpu->kvm->arch.has_protected_state &&
|
|
vcpu->arch.guest_state_protected)
|
|
return -EINVAL;
|
|
|
|
if (dbgregs->flags)
|
|
return -EINVAL;
|
|
|
|
if (!kvm_dr6_valid(dbgregs->dr6))
|
|
return -EINVAL;
|
|
if (!kvm_dr7_valid(dbgregs->dr7))
|
|
return -EINVAL;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(vcpu->arch.db); i++)
|
|
vcpu->arch.db[i] = dbgregs->db[i];
|
|
|
|
kvm_update_dr0123(vcpu);
|
|
vcpu->arch.dr6 = dbgregs->dr6;
|
|
vcpu->arch.dr7 = dbgregs->dr7;
|
|
kvm_update_dr7(vcpu);
|
|
|
|
return 0;
|
|
}
|