xref: /linux/arch/x86/kvm/regs.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
12f5bb3feSSean Christopherson // SPDX-License-Identifier: GPL-2.0-only
22f5bb3feSSean Christopherson #include <linux/kvm_host.h>
32f5bb3feSSean Christopherson 
42f5bb3feSSean Christopherson #include "lapic.h"
52f5bb3feSSean Christopherson #include "mmu.h"
62f5bb3feSSean Christopherson #include "regs.h"
72f5bb3feSSean Christopherson #include "x86.h"
82f5bb3feSSean Christopherson 
92f5bb3feSSean Christopherson unsigned long kvm_get_linear_rip(struct kvm_vcpu *vcpu)
102f5bb3feSSean Christopherson {
112f5bb3feSSean Christopherson 	/* Can't read the RIP when guest state is protected, just return 0 */
122f5bb3feSSean Christopherson 	if (vcpu->arch.guest_state_protected)
132f5bb3feSSean Christopherson 		return 0;
142f5bb3feSSean Christopherson 
152f5bb3feSSean Christopherson 	if (is_64_bit_mode(vcpu))
162f5bb3feSSean Christopherson 		return kvm_rip_read(vcpu);
172f5bb3feSSean Christopherson 	return (u32)(kvm_get_segment_base(vcpu, VCPU_SREG_CS) +
182f5bb3feSSean Christopherson 		     kvm_rip_read(vcpu));
192f5bb3feSSean Christopherson }
202f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_linear_rip);
212f5bb3feSSean Christopherson 
222f5bb3feSSean Christopherson bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip)
232f5bb3feSSean Christopherson {
242f5bb3feSSean Christopherson 	return kvm_get_linear_rip(vcpu) == linear_rip;
252f5bb3feSSean Christopherson }
262f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_is_linear_rip);
272f5bb3feSSean Christopherson 
282f5bb3feSSean Christopherson unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu)
292f5bb3feSSean Christopherson {
302f5bb3feSSean Christopherson 	unsigned long rflags;
312f5bb3feSSean Christopherson 
322f5bb3feSSean Christopherson 	rflags = kvm_x86_call(get_rflags)(vcpu);
332f5bb3feSSean Christopherson 	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
342f5bb3feSSean Christopherson 		rflags &= ~X86_EFLAGS_TF;
352f5bb3feSSean Christopherson 	return rflags;
362f5bb3feSSean Christopherson }
372f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_rflags);
382f5bb3feSSean Christopherson 
392f5bb3feSSean Christopherson void __kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
402f5bb3feSSean Christopherson {
412f5bb3feSSean Christopherson 	if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP &&
422f5bb3feSSean Christopherson 	    kvm_is_linear_rip(vcpu, vcpu->arch.singlestep_rip))
432f5bb3feSSean Christopherson 		rflags |= X86_EFLAGS_TF;
442f5bb3feSSean Christopherson 	kvm_x86_call(set_rflags)(vcpu, rflags);
452f5bb3feSSean Christopherson }
462f5bb3feSSean Christopherson 
472f5bb3feSSean Christopherson void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
482f5bb3feSSean Christopherson {
492f5bb3feSSean Christopherson 	__kvm_set_rflags(vcpu, rflags);
502f5bb3feSSean Christopherson 	kvm_make_request(KVM_REQ_EVENT, vcpu);
512f5bb3feSSean Christopherson }
522f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_rflags);
532f5bb3feSSean Christopherson 
542f5bb3feSSean Christopherson static void __get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
552f5bb3feSSean Christopherson {
562f5bb3feSSean Christopherson 	if (vcpu->arch.emulate_regs_need_sync_to_vcpu) {
572f5bb3feSSean Christopherson 		/*
582f5bb3feSSean Christopherson 		 * We are here if userspace calls get_regs() in the middle of
592f5bb3feSSean Christopherson 		 * instruction emulation. Registers state needs to be copied
602f5bb3feSSean Christopherson 		 * back from emulation context to vcpu. Userspace shouldn't do
612f5bb3feSSean Christopherson 		 * that usually, but some bad designed PV devices (vmware
622f5bb3feSSean Christopherson 		 * backdoor interface) need this to work
632f5bb3feSSean Christopherson 		 */
642f5bb3feSSean Christopherson 		emulator_writeback_register_cache(vcpu->arch.emulate_ctxt);
652f5bb3feSSean Christopherson 		vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
662f5bb3feSSean Christopherson 	}
672f5bb3feSSean Christopherson 	regs->rax = kvm_rax_read_raw(vcpu);
682f5bb3feSSean Christopherson 	regs->rbx = kvm_rbx_read_raw(vcpu);
692f5bb3feSSean Christopherson 	regs->rcx = kvm_rcx_read_raw(vcpu);
702f5bb3feSSean Christopherson 	regs->rdx = kvm_rdx_read_raw(vcpu);
712f5bb3feSSean Christopherson 	regs->rsi = kvm_rsi_read_raw(vcpu);
722f5bb3feSSean Christopherson 	regs->rdi = kvm_rdi_read_raw(vcpu);
732f5bb3feSSean Christopherson 	regs->rsp = kvm_rsp_read(vcpu);
742f5bb3feSSean Christopherson 	regs->rbp = kvm_rbp_read_raw(vcpu);
752f5bb3feSSean Christopherson #ifdef CONFIG_X86_64
762f5bb3feSSean Christopherson 	regs->r8 = kvm_r8_read_raw(vcpu);
772f5bb3feSSean Christopherson 	regs->r9 = kvm_r9_read_raw(vcpu);
782f5bb3feSSean Christopherson 	regs->r10 = kvm_r10_read_raw(vcpu);
792f5bb3feSSean Christopherson 	regs->r11 = kvm_r11_read_raw(vcpu);
802f5bb3feSSean Christopherson 	regs->r12 = kvm_r12_read_raw(vcpu);
812f5bb3feSSean Christopherson 	regs->r13 = kvm_r13_read_raw(vcpu);
822f5bb3feSSean Christopherson 	regs->r14 = kvm_r14_read_raw(vcpu);
832f5bb3feSSean Christopherson 	regs->r15 = kvm_r15_read_raw(vcpu);
842f5bb3feSSean Christopherson #endif
852f5bb3feSSean Christopherson 
862f5bb3feSSean Christopherson 	regs->rip = kvm_rip_read(vcpu);
872f5bb3feSSean Christopherson 	regs->rflags = kvm_get_rflags(vcpu);
882f5bb3feSSean Christopherson }
892f5bb3feSSean Christopherson 
902f5bb3feSSean Christopherson int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
912f5bb3feSSean Christopherson {
922f5bb3feSSean Christopherson 	if (vcpu->kvm->arch.has_protected_state &&
932f5bb3feSSean Christopherson 	    vcpu->arch.guest_state_protected)
942f5bb3feSSean Christopherson 		return -EINVAL;
952f5bb3feSSean Christopherson 
962f5bb3feSSean Christopherson 	vcpu_load(vcpu);
972f5bb3feSSean Christopherson 	__get_regs(vcpu, regs);
982f5bb3feSSean Christopherson 	vcpu_put(vcpu);
992f5bb3feSSean Christopherson 	return 0;
1002f5bb3feSSean Christopherson }
1012f5bb3feSSean Christopherson 
1022f5bb3feSSean Christopherson static void __set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
1032f5bb3feSSean Christopherson {
1042f5bb3feSSean Christopherson 	vcpu->arch.emulate_regs_need_sync_from_vcpu = true;
1052f5bb3feSSean Christopherson 	vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
1062f5bb3feSSean Christopherson 
1072f5bb3feSSean Christopherson 	kvm_rax_write_raw(vcpu, regs->rax);
1082f5bb3feSSean Christopherson 	kvm_rbx_write_raw(vcpu, regs->rbx);
1092f5bb3feSSean Christopherson 	kvm_rcx_write_raw(vcpu, regs->rcx);
1102f5bb3feSSean Christopherson 	kvm_rdx_write_raw(vcpu, regs->rdx);
1112f5bb3feSSean Christopherson 	kvm_rsi_write_raw(vcpu, regs->rsi);
1122f5bb3feSSean Christopherson 	kvm_rdi_write_raw(vcpu, regs->rdi);
1132f5bb3feSSean Christopherson 	kvm_rsp_write(vcpu, regs->rsp);
1142f5bb3feSSean Christopherson 	kvm_rbp_write_raw(vcpu, regs->rbp);
1152f5bb3feSSean Christopherson #ifdef CONFIG_X86_64
1162f5bb3feSSean Christopherson 	kvm_r8_write_raw(vcpu, regs->r8);
1172f5bb3feSSean Christopherson 	kvm_r9_write_raw(vcpu, regs->r9);
1182f5bb3feSSean Christopherson 	kvm_r10_write_raw(vcpu, regs->r10);
1192f5bb3feSSean Christopherson 	kvm_r11_write_raw(vcpu, regs->r11);
1202f5bb3feSSean Christopherson 	kvm_r12_write_raw(vcpu, regs->r12);
1212f5bb3feSSean Christopherson 	kvm_r13_write_raw(vcpu, regs->r13);
1222f5bb3feSSean Christopherson 	kvm_r14_write_raw(vcpu, regs->r14);
1232f5bb3feSSean Christopherson 	kvm_r15_write_raw(vcpu, regs->r15);
1242f5bb3feSSean Christopherson #endif
1252f5bb3feSSean Christopherson 
1262f5bb3feSSean Christopherson 	kvm_rip_write(vcpu, regs->rip);
1272f5bb3feSSean Christopherson 	kvm_set_rflags(vcpu, regs->rflags | X86_EFLAGS_FIXED);
1282f5bb3feSSean Christopherson 
1292f5bb3feSSean Christopherson 	vcpu->arch.exception.pending = false;
1302f5bb3feSSean Christopherson 	vcpu->arch.exception_vmexit.pending = false;
1312f5bb3feSSean Christopherson 
1322f5bb3feSSean Christopherson 	kvm_make_request(KVM_REQ_EVENT, vcpu);
1332f5bb3feSSean Christopherson }
1342f5bb3feSSean Christopherson 
1352f5bb3feSSean Christopherson int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
1362f5bb3feSSean Christopherson {
1372f5bb3feSSean Christopherson 	if (vcpu->kvm->arch.has_protected_state &&
1382f5bb3feSSean Christopherson 	    vcpu->arch.guest_state_protected)
1392f5bb3feSSean Christopherson 		return -EINVAL;
1402f5bb3feSSean Christopherson 
1412f5bb3feSSean Christopherson 	vcpu_load(vcpu);
1422f5bb3feSSean Christopherson 	__set_regs(vcpu, regs);
1432f5bb3feSSean Christopherson 	vcpu_put(vcpu);
1442f5bb3feSSean Christopherson 	return 0;
1452f5bb3feSSean Christopherson }
1462f5bb3feSSean Christopherson 
1472f5bb3feSSean Christopherson static inline u64 pdptr_rsvd_bits(struct kvm_vcpu *vcpu)
1482f5bb3feSSean Christopherson {
1492f5bb3feSSean Christopherson 	return vcpu->arch.reserved_gpa_bits | rsvd_bits(5, 8) | rsvd_bits(1, 2);
1502f5bb3feSSean Christopherson }
1512f5bb3feSSean Christopherson 
1522f5bb3feSSean Christopherson /*
1532f5bb3feSSean Christopherson  * Load the pae pdptrs.  Return 1 if they are all valid, 0 otherwise.
1542f5bb3feSSean Christopherson  */
1552f5bb3feSSean Christopherson int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
1562f5bb3feSSean Christopherson {
157148fe965SPaolo Bonzini 	struct kvm_pagewalk *w = &vcpu->arch.gva_walk;
1582f5bb3feSSean Christopherson 	gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
1592f5bb3feSSean Christopherson 	gpa_t real_gpa;
1602f5bb3feSSean Christopherson 	int i;
1612f5bb3feSSean Christopherson 	int ret;
1622f5bb3feSSean Christopherson 	u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)];
1632f5bb3feSSean Christopherson 
1642f5bb3feSSean Christopherson 	/*
1652f5bb3feSSean Christopherson 	 * If the MMU is nested, CR3 holds an L2 GPA and needs to be translated
1662f5bb3feSSean Christopherson 	 * to an L1 GPA.
1672f5bb3feSSean Christopherson 	 */
168d42e93eeSPaolo Bonzini 	real_gpa = kvm_translate_gpa(vcpu, w, gfn_to_gpa(pdpt_gfn),
1692f5bb3feSSean Christopherson 				     PFERR_USER_MASK | PFERR_WRITE_MASK |
1702f5bb3feSSean Christopherson 				     PFERR_GUEST_PAGE_MASK, NULL, 0);
1712f5bb3feSSean Christopherson 	if (real_gpa == INVALID_GPA)
1722f5bb3feSSean Christopherson 		return 0;
1732f5bb3feSSean Christopherson 
1742f5bb3feSSean Christopherson 	/* Note the offset, PDPTRs are 32 byte aligned when using PAE paging. */
1752f5bb3feSSean Christopherson 	ret = kvm_vcpu_read_guest_page(vcpu, gpa_to_gfn(real_gpa), pdpte,
1762f5bb3feSSean Christopherson 				       cr3 & GENMASK(11, 5), sizeof(pdpte));
1772f5bb3feSSean Christopherson 	if (ret < 0)
1782f5bb3feSSean Christopherson 		return 0;
1792f5bb3feSSean Christopherson 
1802f5bb3feSSean Christopherson 	for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
1812f5bb3feSSean Christopherson 		if ((pdpte[i] & PT_PRESENT_MASK) &&
1822f5bb3feSSean Christopherson 		    (pdpte[i] & pdptr_rsvd_bits(vcpu))) {
1832f5bb3feSSean Christopherson 			return 0;
1842f5bb3feSSean Christopherson 		}
1852f5bb3feSSean Christopherson 	}
1862f5bb3feSSean Christopherson 
1872f5bb3feSSean Christopherson 	/*
1882f5bb3feSSean Christopherson 	 * Marking VCPU_REG_PDPTR dirty doesn't work for !tdp_enabled.
1892f5bb3feSSean Christopherson 	 * Shadow page roots need to be reconstructed instead.
1902f5bb3feSSean Christopherson 	 */
1912f5bb3feSSean Christopherson 	if (!tdp_enabled && memcmp(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs)))
192d42e93eeSPaolo Bonzini 		kvm_mmu_free_roots(vcpu->kvm, &vcpu->arch.root_mmu,
193d42e93eeSPaolo Bonzini 				   KVM_MMU_ROOT_CURRENT);
1942f5bb3feSSean Christopherson 
1952f5bb3feSSean Christopherson 	memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs));
1962f5bb3feSSean Christopherson 	kvm_register_mark_dirty(vcpu, VCPU_REG_PDPTR);
1972f5bb3feSSean Christopherson 	kvm_make_request(KVM_REQ_LOAD_MMU_PGD, vcpu);
1982f5bb3feSSean Christopherson 	vcpu->arch.pdptrs_from_userspace = false;
1992f5bb3feSSean Christopherson 
2002f5bb3feSSean Christopherson 	return 1;
2012f5bb3feSSean Christopherson }
2022f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(load_pdptrs);
2032f5bb3feSSean Christopherson 
2042f5bb3feSSean Christopherson static bool kvm_is_valid_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
2052f5bb3feSSean Christopherson {
2062f5bb3feSSean Christopherson #ifdef CONFIG_X86_64
2072f5bb3feSSean Christopherson 	if (cr0 & 0xffffffff00000000UL)
2082f5bb3feSSean Christopherson 		return false;
2092f5bb3feSSean Christopherson #endif
2102f5bb3feSSean Christopherson 
2112f5bb3feSSean Christopherson 	if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD))
2122f5bb3feSSean Christopherson 		return false;
2132f5bb3feSSean Christopherson 
2142f5bb3feSSean Christopherson 	if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE))
2152f5bb3feSSean Christopherson 		return false;
2162f5bb3feSSean Christopherson 
2172f5bb3feSSean Christopherson 	return kvm_x86_call(is_valid_cr0)(vcpu, cr0);
2182f5bb3feSSean Christopherson }
2192f5bb3feSSean Christopherson 
2202f5bb3feSSean Christopherson void kvm_post_set_cr0(struct kvm_vcpu *vcpu, unsigned long old_cr0, unsigned long cr0)
2212f5bb3feSSean Christopherson {
2222f5bb3feSSean Christopherson 	/*
2232f5bb3feSSean Christopherson 	 * CR0.WP is incorporated into the MMU role, but only for non-nested,
2242f5bb3feSSean Christopherson 	 * indirect shadow MMUs.  If paging is disabled, no updates are needed
2252f5bb3feSSean Christopherson 	 * as there are no permission bits to emulate.  If TDP is enabled, the
2262f5bb3feSSean Christopherson 	 * MMU's metadata needs to be updated, e.g. so that emulating guest
2272f5bb3feSSean Christopherson 	 * translations does the right thing, but there's no need to unload the
2282f5bb3feSSean Christopherson 	 * root as CR0.WP doesn't affect SPTEs.
2292f5bb3feSSean Christopherson 	 */
2302f5bb3feSSean Christopherson 	if ((cr0 ^ old_cr0) == X86_CR0_WP) {
2312f5bb3feSSean Christopherson 		if (!(cr0 & X86_CR0_PG))
2322f5bb3feSSean Christopherson 			return;
2332f5bb3feSSean Christopherson 
2342f5bb3feSSean Christopherson 		if (tdp_enabled) {
2352f5bb3feSSean Christopherson 			kvm_init_mmu(vcpu);
2362f5bb3feSSean Christopherson 			return;
2372f5bb3feSSean Christopherson 		}
2382f5bb3feSSean Christopherson 	}
2392f5bb3feSSean Christopherson 
2402f5bb3feSSean Christopherson 	if ((cr0 ^ old_cr0) & X86_CR0_PG) {
2412f5bb3feSSean Christopherson 		/*
2422f5bb3feSSean Christopherson 		 * Clearing CR0.PG is defined to flush the TLB from the guest's
2432f5bb3feSSean Christopherson 		 * perspective.
2442f5bb3feSSean Christopherson 		 */
2452f5bb3feSSean Christopherson 		if (!(cr0 & X86_CR0_PG))
2462f5bb3feSSean Christopherson 			kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
2472f5bb3feSSean Christopherson 		/*
2482f5bb3feSSean Christopherson 		 * Check for async #PF completion events when enabling paging,
2492f5bb3feSSean Christopherson 		 * as the vCPU may have previously encountered async #PFs (it's
2502f5bb3feSSean Christopherson 		 * entirely legal for the guest to toggle paging on/off without
2512f5bb3feSSean Christopherson 		 * waiting for the async #PF queue to drain).
2522f5bb3feSSean Christopherson 		 */
2532f5bb3feSSean Christopherson 		else if (kvm_pv_async_pf_enabled(vcpu))
2542f5bb3feSSean Christopherson 			kvm_make_request(KVM_REQ_APF_READY, vcpu);
2552f5bb3feSSean Christopherson 	}
2562f5bb3feSSean Christopherson 
2572f5bb3feSSean Christopherson 	if ((cr0 ^ old_cr0) & KVM_MMU_CR0_ROLE_BITS)
2582f5bb3feSSean Christopherson 		kvm_mmu_reset_context(vcpu);
2592f5bb3feSSean Christopherson }
2602f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_post_set_cr0);
2612f5bb3feSSean Christopherson 
2622f5bb3feSSean Christopherson int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
2632f5bb3feSSean Christopherson {
2642f5bb3feSSean Christopherson 	unsigned long old_cr0 = kvm_read_cr0(vcpu);
2652f5bb3feSSean Christopherson 
2662f5bb3feSSean Christopherson 	if (!kvm_is_valid_cr0(vcpu, cr0))
2672f5bb3feSSean Christopherson 		return 1;
2682f5bb3feSSean Christopherson 
2692f5bb3feSSean Christopherson 	cr0 |= X86_CR0_ET;
2702f5bb3feSSean Christopherson 
2712f5bb3feSSean Christopherson 	/* Write to CR0 reserved bits are ignored, even on Intel. */
2722f5bb3feSSean Christopherson 	cr0 &= ~CR0_RESERVED_BITS;
2732f5bb3feSSean Christopherson 
2742f5bb3feSSean Christopherson #ifdef CONFIG_X86_64
2752f5bb3feSSean Christopherson 	if ((vcpu->arch.efer & EFER_LME) && !is_paging(vcpu) &&
2762f5bb3feSSean Christopherson 	    (cr0 & X86_CR0_PG)) {
2772f5bb3feSSean Christopherson 		int cs_db, cs_l;
2782f5bb3feSSean Christopherson 
2792f5bb3feSSean Christopherson 		if (!is_pae(vcpu))
2802f5bb3feSSean Christopherson 			return 1;
2812f5bb3feSSean Christopherson 		kvm_x86_call(get_cs_db_l_bits)(vcpu, &cs_db, &cs_l);
2822f5bb3feSSean Christopherson 		if (cs_l)
2832f5bb3feSSean Christopherson 			return 1;
2842f5bb3feSSean Christopherson 	}
2852f5bb3feSSean Christopherson #endif
2862f5bb3feSSean Christopherson 	if (!(vcpu->arch.efer & EFER_LME) && (cr0 & X86_CR0_PG) &&
2872f5bb3feSSean Christopherson 	    is_pae(vcpu) && ((cr0 ^ old_cr0) & X86_CR0_PDPTR_BITS) &&
2882f5bb3feSSean Christopherson 	    !load_pdptrs(vcpu, kvm_read_cr3(vcpu)))
2892f5bb3feSSean Christopherson 		return 1;
2902f5bb3feSSean Christopherson 
2912f5bb3feSSean Christopherson 	if (!(cr0 & X86_CR0_PG) &&
2922f5bb3feSSean Christopherson 	    (is_64_bit_mode(vcpu) || kvm_is_cr4_bit_set(vcpu, X86_CR4_PCIDE)))
2932f5bb3feSSean Christopherson 		return 1;
2942f5bb3feSSean Christopherson 
2952f5bb3feSSean Christopherson 	if (!(cr0 & X86_CR0_WP) && kvm_is_cr4_bit_set(vcpu, X86_CR4_CET))
2962f5bb3feSSean Christopherson 		return 1;
2972f5bb3feSSean Christopherson 
2982f5bb3feSSean Christopherson 	kvm_x86_call(set_cr0)(vcpu, cr0);
2992f5bb3feSSean Christopherson 
3002f5bb3feSSean Christopherson 	kvm_post_set_cr0(vcpu, old_cr0, cr0);
3012f5bb3feSSean Christopherson 
3022f5bb3feSSean Christopherson 	return 0;
3032f5bb3feSSean Christopherson }
3042f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr0);
3052f5bb3feSSean Christopherson 
3062f5bb3feSSean Christopherson void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
3072f5bb3feSSean Christopherson {
3082f5bb3feSSean Christopherson 	(void)kvm_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~0x0eul) | (msw & 0x0f));
3092f5bb3feSSean Christopherson }
3102f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_lmsw);
3112f5bb3feSSean Christopherson 
3122f5bb3feSSean Christopherson int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
3132f5bb3feSSean Christopherson {
3142f5bb3feSSean Christopherson 	bool skip_tlb_flush = false;
3152f5bb3feSSean Christopherson 	unsigned long pcid = 0;
3162f5bb3feSSean Christopherson #ifdef CONFIG_X86_64
3172f5bb3feSSean Christopherson 	if (kvm_is_cr4_bit_set(vcpu, X86_CR4_PCIDE)) {
3182f5bb3feSSean Christopherson 		skip_tlb_flush = cr3 & X86_CR3_PCID_NOFLUSH;
3192f5bb3feSSean Christopherson 		cr3 &= ~X86_CR3_PCID_NOFLUSH;
3202f5bb3feSSean Christopherson 		pcid = cr3 & X86_CR3_PCID_MASK;
3212f5bb3feSSean Christopherson 	}
3222f5bb3feSSean Christopherson #endif
3232f5bb3feSSean Christopherson 
3242f5bb3feSSean Christopherson 	/* PDPTRs are always reloaded for PAE paging. */
3252f5bb3feSSean Christopherson 	if (cr3 == kvm_read_cr3(vcpu) && !is_pae_paging(vcpu))
3262f5bb3feSSean Christopherson 		goto handle_tlb_flush;
3272f5bb3feSSean Christopherson 
3282f5bb3feSSean Christopherson 	/*
3292f5bb3feSSean Christopherson 	 * Do not condition the GPA check on long mode, this helper is used to
3302f5bb3feSSean Christopherson 	 * stuff CR3, e.g. for RSM emulation, and there is no guarantee that
3312f5bb3feSSean Christopherson 	 * the current vCPU mode is accurate.
3322f5bb3feSSean Christopherson 	 */
3332f5bb3feSSean Christopherson 	if (!kvm_vcpu_is_legal_cr3(vcpu, cr3))
3342f5bb3feSSean Christopherson 		return 1;
3352f5bb3feSSean Christopherson 
3362f5bb3feSSean Christopherson 	if (is_pae_paging(vcpu) && !load_pdptrs(vcpu, cr3))
3372f5bb3feSSean Christopherson 		return 1;
3382f5bb3feSSean Christopherson 
3392f5bb3feSSean Christopherson 	if (cr3 != kvm_read_cr3(vcpu))
3402f5bb3feSSean Christopherson 		kvm_mmu_new_pgd(vcpu, cr3);
3412f5bb3feSSean Christopherson 
3422f5bb3feSSean Christopherson 	vcpu->arch.cr3 = cr3;
3432f5bb3feSSean Christopherson 	kvm_register_mark_dirty(vcpu, VCPU_REG_CR3);
3442f5bb3feSSean Christopherson 	/* Do not call post_set_cr3, we do not get here for confidential guests.  */
3452f5bb3feSSean Christopherson 
3462f5bb3feSSean Christopherson handle_tlb_flush:
3472f5bb3feSSean Christopherson 	/*
3482f5bb3feSSean Christopherson 	 * A load of CR3 that flushes the TLB flushes only the current PCID,
3492f5bb3feSSean Christopherson 	 * even if PCID is disabled, in which case PCID=0 is flushed.  It's a
3502f5bb3feSSean Christopherson 	 * moot point in the end because _disabling_ PCID will flush all PCIDs,
3512f5bb3feSSean Christopherson 	 * and it's impossible to use a non-zero PCID when PCID is disabled,
3522f5bb3feSSean Christopherson 	 * i.e. only PCID=0 can be relevant.
3532f5bb3feSSean Christopherson 	 */
3542f5bb3feSSean Christopherson 	if (!skip_tlb_flush)
3552f5bb3feSSean Christopherson 		kvm_invalidate_pcid(vcpu, pcid);
3562f5bb3feSSean Christopherson 
3572f5bb3feSSean Christopherson 	return 0;
3582f5bb3feSSean Christopherson }
3592f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr3);
3602f5bb3feSSean Christopherson 
3612f5bb3feSSean Christopherson static bool kvm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
3622f5bb3feSSean Christopherson {
3632f5bb3feSSean Christopherson 	return __kvm_is_valid_cr4(vcpu, cr4) &&
3642f5bb3feSSean Christopherson 	       kvm_x86_call(is_valid_cr4)(vcpu, cr4);
3652f5bb3feSSean Christopherson }
3662f5bb3feSSean Christopherson 
3672f5bb3feSSean Christopherson void kvm_post_set_cr4(struct kvm_vcpu *vcpu, unsigned long old_cr4, unsigned long cr4)
3682f5bb3feSSean Christopherson {
3692f5bb3feSSean Christopherson 	if ((cr4 ^ old_cr4) & KVM_MMU_CR4_ROLE_BITS)
3702f5bb3feSSean Christopherson 		kvm_mmu_reset_context(vcpu);
3712f5bb3feSSean Christopherson 
3722f5bb3feSSean Christopherson 	/*
3732f5bb3feSSean Christopherson 	 * If CR4.PCIDE is changed 0 -> 1, there is no need to flush the TLB
3742f5bb3feSSean Christopherson 	 * according to the SDM; however, stale prev_roots could be reused
3752f5bb3feSSean Christopherson 	 * incorrectly in the future after a MOV to CR3 with NOFLUSH=1, so we
3762f5bb3feSSean Christopherson 	 * free them all.  This is *not* a superset of KVM_REQ_TLB_FLUSH_GUEST
3772f5bb3feSSean Christopherson 	 * or KVM_REQ_TLB_FLUSH_CURRENT, because the hardware TLB is not flushed,
3782f5bb3feSSean Christopherson 	 * so fall through.
3792f5bb3feSSean Christopherson 	 */
3802f5bb3feSSean Christopherson 	if (!tdp_enabled &&
3812f5bb3feSSean Christopherson 	    (cr4 & X86_CR4_PCIDE) && !(old_cr4 & X86_CR4_PCIDE))
3822f5bb3feSSean Christopherson 		kvm_mmu_unload(vcpu);
3832f5bb3feSSean Christopherson 
3842f5bb3feSSean Christopherson 	/*
3852f5bb3feSSean Christopherson 	 * The TLB has to be flushed for all PCIDs if any of the following
3862f5bb3feSSean Christopherson 	 * (architecturally required) changes happen:
3872f5bb3feSSean Christopherson 	 * - CR4.PCIDE is changed from 1 to 0
3882f5bb3feSSean Christopherson 	 * - CR4.PGE is toggled
3892f5bb3feSSean Christopherson 	 *
3902f5bb3feSSean Christopherson 	 * This is a superset of KVM_REQ_TLB_FLUSH_CURRENT.
3912f5bb3feSSean Christopherson 	 */
3922f5bb3feSSean Christopherson 	if (((cr4 ^ old_cr4) & X86_CR4_PGE) ||
3932f5bb3feSSean Christopherson 	    (!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
3942f5bb3feSSean Christopherson 		kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
3952f5bb3feSSean Christopherson 
3962f5bb3feSSean Christopherson 	/*
3972f5bb3feSSean Christopherson 	 * The TLB has to be flushed for the current PCID if any of the
3982f5bb3feSSean Christopherson 	 * following (architecturally required) changes happen:
3992f5bb3feSSean Christopherson 	 * - CR4.SMEP is changed from 0 to 1
4002f5bb3feSSean Christopherson 	 * - CR4.PAE is toggled
4012f5bb3feSSean Christopherson 	 */
4022f5bb3feSSean Christopherson 	else if (((cr4 ^ old_cr4) & X86_CR4_PAE) ||
4032f5bb3feSSean Christopherson 		 ((cr4 & X86_CR4_SMEP) && !(old_cr4 & X86_CR4_SMEP)))
4042f5bb3feSSean Christopherson 		kvm_make_request(KVM_REQ_TLB_FLUSH_CURRENT, vcpu);
4052f5bb3feSSean Christopherson 
4062f5bb3feSSean Christopherson }
4072f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_post_set_cr4);
4082f5bb3feSSean Christopherson 
4092f5bb3feSSean Christopherson int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
4102f5bb3feSSean Christopherson {
4112f5bb3feSSean Christopherson 	unsigned long old_cr4 = kvm_read_cr4(vcpu);
4122f5bb3feSSean Christopherson 
4132f5bb3feSSean Christopherson 	if (!kvm_is_valid_cr4(vcpu, cr4))
4142f5bb3feSSean Christopherson 		return 1;
4152f5bb3feSSean Christopherson 
4162f5bb3feSSean Christopherson 	if (is_long_mode(vcpu)) {
4172f5bb3feSSean Christopherson 		if (!(cr4 & X86_CR4_PAE))
4182f5bb3feSSean Christopherson 			return 1;
4192f5bb3feSSean Christopherson 		if ((cr4 ^ old_cr4) & X86_CR4_LA57)
4202f5bb3feSSean Christopherson 			return 1;
4212f5bb3feSSean Christopherson 	} else if (is_paging(vcpu) && (cr4 & X86_CR4_PAE)
4222f5bb3feSSean Christopherson 		   && ((cr4 ^ old_cr4) & X86_CR4_PDPTR_BITS)
4232f5bb3feSSean Christopherson 		   && !load_pdptrs(vcpu, kvm_read_cr3(vcpu)))
4242f5bb3feSSean Christopherson 		return 1;
4252f5bb3feSSean Christopherson 
4262f5bb3feSSean Christopherson 	if ((cr4 & X86_CR4_PCIDE) && !(old_cr4 & X86_CR4_PCIDE)) {
4272f5bb3feSSean Christopherson 		/* PCID can not be enabled when cr3[11:0]!=000H or EFER.LMA=0 */
4282f5bb3feSSean Christopherson 		if ((kvm_read_cr3(vcpu) & X86_CR3_PCID_MASK) || !is_long_mode(vcpu))
4292f5bb3feSSean Christopherson 			return 1;
4302f5bb3feSSean Christopherson 	}
4312f5bb3feSSean Christopherson 
4322f5bb3feSSean Christopherson 	if ((cr4 & X86_CR4_CET) && !kvm_is_cr0_bit_set(vcpu, X86_CR0_WP))
4332f5bb3feSSean Christopherson 		return 1;
4342f5bb3feSSean Christopherson 
4352f5bb3feSSean Christopherson 	kvm_x86_call(set_cr4)(vcpu, cr4);
4362f5bb3feSSean Christopherson 
4372f5bb3feSSean Christopherson 	kvm_post_set_cr4(vcpu, old_cr4, cr4);
4382f5bb3feSSean Christopherson 
4392f5bb3feSSean Christopherson 	return 0;
4402f5bb3feSSean Christopherson }
4412f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr4);
4422f5bb3feSSean Christopherson 
4432f5bb3feSSean Christopherson int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
4442f5bb3feSSean Christopherson {
4452f5bb3feSSean Christopherson 	if (cr8 & CR8_RESERVED_BITS)
4462f5bb3feSSean Christopherson 		return 1;
4472f5bb3feSSean Christopherson 	if (lapic_in_kernel(vcpu))
4482f5bb3feSSean Christopherson 		kvm_lapic_set_tpr(vcpu, cr8);
4492f5bb3feSSean Christopherson 	else
4502f5bb3feSSean Christopherson 		vcpu->arch.cr8 = cr8;
4512f5bb3feSSean Christopherson 	return 0;
4522f5bb3feSSean Christopherson }
4532f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr8);
4542f5bb3feSSean Christopherson 
4552f5bb3feSSean Christopherson unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu)
4562f5bb3feSSean Christopherson {
4572f5bb3feSSean Christopherson 	if (lapic_in_kernel(vcpu))
4582f5bb3feSSean Christopherson 		return kvm_lapic_get_cr8(vcpu);
4592f5bb3feSSean Christopherson 	else
4602f5bb3feSSean Christopherson 		return vcpu->arch.cr8;
4612f5bb3feSSean Christopherson }
4622f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_cr8);
4632f5bb3feSSean Christopherson 
4642f5bb3feSSean Christopherson static void __get_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
4652f5bb3feSSean Christopherson {
4662f5bb3feSSean Christopherson 	struct desc_ptr dt;
4672f5bb3feSSean Christopherson 
4682f5bb3feSSean Christopherson 	if (vcpu->arch.guest_state_protected)
4692f5bb3feSSean Christopherson 		goto skip_protected_regs;
4702f5bb3feSSean Christopherson 
4712f5bb3feSSean Christopherson 	kvm_handle_exception_payload_quirk(vcpu);
4722f5bb3feSSean Christopherson 
4732f5bb3feSSean Christopherson 	kvm_get_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
4742f5bb3feSSean Christopherson 	kvm_get_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
4752f5bb3feSSean Christopherson 	kvm_get_segment(vcpu, &sregs->es, VCPU_SREG_ES);
4762f5bb3feSSean Christopherson 	kvm_get_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
4772f5bb3feSSean Christopherson 	kvm_get_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
4782f5bb3feSSean Christopherson 	kvm_get_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
4792f5bb3feSSean Christopherson 
4802f5bb3feSSean Christopherson 	kvm_get_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
4812f5bb3feSSean Christopherson 	kvm_get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
4822f5bb3feSSean Christopherson 
4832f5bb3feSSean Christopherson 	kvm_x86_call(get_idt)(vcpu, &dt);
4842f5bb3feSSean Christopherson 	sregs->idt.limit = dt.size;
4852f5bb3feSSean Christopherson 	sregs->idt.base = dt.address;
4862f5bb3feSSean Christopherson 	kvm_x86_call(get_gdt)(vcpu, &dt);
4872f5bb3feSSean Christopherson 	sregs->gdt.limit = dt.size;
4882f5bb3feSSean Christopherson 	sregs->gdt.base = dt.address;
4892f5bb3feSSean Christopherson 
4902f5bb3feSSean Christopherson 	sregs->cr2 = vcpu->arch.cr2;
4912f5bb3feSSean Christopherson 	sregs->cr3 = kvm_read_cr3(vcpu);
4922f5bb3feSSean Christopherson 
4932f5bb3feSSean Christopherson skip_protected_regs:
4942f5bb3feSSean Christopherson 	sregs->cr0 = kvm_read_cr0(vcpu);
4952f5bb3feSSean Christopherson 	sregs->cr4 = kvm_read_cr4(vcpu);
4962f5bb3feSSean Christopherson 	sregs->cr8 = kvm_get_cr8(vcpu);
4972f5bb3feSSean Christopherson 	sregs->efer = vcpu->arch.efer;
4982f5bb3feSSean Christopherson 	sregs->apic_base = vcpu->arch.apic_base;
4992f5bb3feSSean Christopherson }
5002f5bb3feSSean Christopherson 
5012f5bb3feSSean Christopherson static void __get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
5022f5bb3feSSean Christopherson {
5032f5bb3feSSean Christopherson 	__get_sregs_common(vcpu, sregs);
5042f5bb3feSSean Christopherson 
5052f5bb3feSSean Christopherson 	if (vcpu->arch.guest_state_protected)
5062f5bb3feSSean Christopherson 		return;
5072f5bb3feSSean Christopherson 
5082f5bb3feSSean Christopherson 	if (vcpu->arch.interrupt.injected && !vcpu->arch.interrupt.soft)
5092f5bb3feSSean Christopherson 		set_bit(vcpu->arch.interrupt.nr,
5102f5bb3feSSean Christopherson 			(unsigned long *)sregs->interrupt_bitmap);
5112f5bb3feSSean Christopherson }
5122f5bb3feSSean Christopherson 
5132f5bb3feSSean Christopherson int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
5142f5bb3feSSean Christopherson 				  struct kvm_sregs *sregs)
5152f5bb3feSSean Christopherson {
5162f5bb3feSSean Christopherson 	if (vcpu->kvm->arch.has_protected_state &&
5172f5bb3feSSean Christopherson 	    vcpu->arch.guest_state_protected)
5182f5bb3feSSean Christopherson 		return -EINVAL;
5192f5bb3feSSean Christopherson 
5202f5bb3feSSean Christopherson 	vcpu_load(vcpu);
5212f5bb3feSSean Christopherson 	__get_sregs(vcpu, sregs);
5222f5bb3feSSean Christopherson 	vcpu_put(vcpu);
5232f5bb3feSSean Christopherson 	return 0;
5242f5bb3feSSean Christopherson }
5252f5bb3feSSean Christopherson 
5262f5bb3feSSean Christopherson void kvm_vcpu_ioctl_x86_get_sregs2(struct kvm_vcpu *vcpu,
5272f5bb3feSSean Christopherson 				   struct kvm_sregs2 *sregs2)
5282f5bb3feSSean Christopherson {
5292f5bb3feSSean Christopherson 	int i;
5302f5bb3feSSean Christopherson 
5312f5bb3feSSean Christopherson 	__get_sregs_common(vcpu, (struct kvm_sregs *)sregs2);
5322f5bb3feSSean Christopherson 
5332f5bb3feSSean Christopherson 	if (vcpu->arch.guest_state_protected)
5342f5bb3feSSean Christopherson 		return;
5352f5bb3feSSean Christopherson 
5362f5bb3feSSean Christopherson 	if (is_pae_paging(vcpu)) {
5372f5bb3feSSean Christopherson 		kvm_vcpu_srcu_read_lock(vcpu);
5382f5bb3feSSean Christopherson 		for (i = 0 ; i < 4 ; i++)
5392f5bb3feSSean Christopherson 			sregs2->pdptrs[i] = kvm_pdptr_read(vcpu, i);
5402f5bb3feSSean Christopherson 		sregs2->flags |= KVM_SREGS2_FLAGS_PDPTRS_VALID;
5412f5bb3feSSean Christopherson 		kvm_vcpu_srcu_read_unlock(vcpu);
5422f5bb3feSSean Christopherson 	}
5432f5bb3feSSean Christopherson }
5442f5bb3feSSean Christopherson 
5452f5bb3feSSean Christopherson static bool kvm_is_valid_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
5462f5bb3feSSean Christopherson {
5472f5bb3feSSean Christopherson 	if ((sregs->efer & EFER_LME) && (sregs->cr0 & X86_CR0_PG)) {
5482f5bb3feSSean Christopherson 		/*
5492f5bb3feSSean Christopherson 		 * When EFER.LME and CR0.PG are set, the processor is in
5502f5bb3feSSean Christopherson 		 * 64-bit mode (though maybe in a 32-bit code segment).
5512f5bb3feSSean Christopherson 		 * CR4.PAE and EFER.LMA must be set.
5522f5bb3feSSean Christopherson 		 */
5532f5bb3feSSean Christopherson 		if (!(sregs->cr4 & X86_CR4_PAE) || !(sregs->efer & EFER_LMA))
5542f5bb3feSSean Christopherson 			return false;
5552f5bb3feSSean Christopherson 		if (!kvm_vcpu_is_legal_cr3(vcpu, sregs->cr3))
5562f5bb3feSSean Christopherson 			return false;
5572f5bb3feSSean Christopherson 	} else {
5582f5bb3feSSean Christopherson 		/*
5592f5bb3feSSean Christopherson 		 * Not in 64-bit mode: EFER.LMA is clear and the code
5602f5bb3feSSean Christopherson 		 * segment cannot be 64-bit.
5612f5bb3feSSean Christopherson 		 */
5622f5bb3feSSean Christopherson 		if (sregs->efer & EFER_LMA || sregs->cs.l)
5632f5bb3feSSean Christopherson 			return false;
5642f5bb3feSSean Christopherson 	}
5652f5bb3feSSean Christopherson 
5662f5bb3feSSean Christopherson 	return kvm_is_valid_cr4(vcpu, sregs->cr4) &&
567*184bd464SYosry Ahmed 	       kvm_is_valid_cr0(vcpu, sregs->cr0) &&
568*184bd464SYosry Ahmed 	       kvm_valid_efer(vcpu, sregs->efer);
5692f5bb3feSSean Christopherson }
5702f5bb3feSSean Christopherson 
5712f5bb3feSSean Christopherson static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs,
5722f5bb3feSSean Christopherson 			      int *mmu_reset_needed, bool update_pdptrs)
5732f5bb3feSSean Christopherson {
5742f5bb3feSSean Christopherson 	int idx;
5752f5bb3feSSean Christopherson 	struct desc_ptr dt;
5762f5bb3feSSean Christopherson 
5772f5bb3feSSean Christopherson 	if (!kvm_is_valid_sregs(vcpu, sregs))
5782f5bb3feSSean Christopherson 		return -EINVAL;
5792f5bb3feSSean Christopherson 
5802f5bb3feSSean Christopherson 	if (kvm_apic_set_base(vcpu, sregs->apic_base, true))
5812f5bb3feSSean Christopherson 		return -EINVAL;
5822f5bb3feSSean Christopherson 
5832f5bb3feSSean Christopherson 	if (vcpu->arch.guest_state_protected)
5842f5bb3feSSean Christopherson 		return 0;
5852f5bb3feSSean Christopherson 
5862f5bb3feSSean Christopherson 	dt.size = sregs->idt.limit;
5872f5bb3feSSean Christopherson 	dt.address = sregs->idt.base;
5882f5bb3feSSean Christopherson 	kvm_x86_call(set_idt)(vcpu, &dt);
5892f5bb3feSSean Christopherson 	dt.size = sregs->gdt.limit;
5902f5bb3feSSean Christopherson 	dt.address = sregs->gdt.base;
5912f5bb3feSSean Christopherson 	kvm_x86_call(set_gdt)(vcpu, &dt);
5922f5bb3feSSean Christopherson 
5932f5bb3feSSean Christopherson 	vcpu->arch.cr2 = sregs->cr2;
5942f5bb3feSSean Christopherson 	*mmu_reset_needed |= kvm_read_cr3(vcpu) != sregs->cr3;
5952f5bb3feSSean Christopherson 	vcpu->arch.cr3 = sregs->cr3;
5962f5bb3feSSean Christopherson 	kvm_register_mark_dirty(vcpu, VCPU_REG_CR3);
5972f5bb3feSSean Christopherson 	kvm_x86_call(post_set_cr3)(vcpu, sregs->cr3);
5982f5bb3feSSean Christopherson 
5992f5bb3feSSean Christopherson 	*mmu_reset_needed |= vcpu->arch.efer != sregs->efer;
6002f5bb3feSSean Christopherson 	kvm_x86_call(set_efer)(vcpu, sregs->efer);
6012f5bb3feSSean Christopherson 
6022f5bb3feSSean Christopherson 	*mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0;
6032f5bb3feSSean Christopherson 	kvm_x86_call(set_cr0)(vcpu, sregs->cr0);
6042f5bb3feSSean Christopherson 
6052f5bb3feSSean Christopherson 	*mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
6062f5bb3feSSean Christopherson 	kvm_x86_call(set_cr4)(vcpu, sregs->cr4);
6072f5bb3feSSean Christopherson 
6082f5bb3feSSean Christopherson 	if (update_pdptrs) {
6092f5bb3feSSean Christopherson 		idx = srcu_read_lock(&vcpu->kvm->srcu);
6102f5bb3feSSean Christopherson 		if (is_pae_paging(vcpu)) {
6112f5bb3feSSean Christopherson 			load_pdptrs(vcpu, kvm_read_cr3(vcpu));
6122f5bb3feSSean Christopherson 			*mmu_reset_needed = 1;
6132f5bb3feSSean Christopherson 		}
6142f5bb3feSSean Christopherson 		srcu_read_unlock(&vcpu->kvm->srcu, idx);
6152f5bb3feSSean Christopherson 	}
6162f5bb3feSSean Christopherson 
6172f5bb3feSSean Christopherson 	kvm_set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
6182f5bb3feSSean Christopherson 	kvm_set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
6192f5bb3feSSean Christopherson 	kvm_set_segment(vcpu, &sregs->es, VCPU_SREG_ES);
6202f5bb3feSSean Christopherson 	kvm_set_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
6212f5bb3feSSean Christopherson 	kvm_set_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
6222f5bb3feSSean Christopherson 	kvm_set_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
6232f5bb3feSSean Christopherson 
6242f5bb3feSSean Christopherson 	kvm_set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
6252f5bb3feSSean Christopherson 	kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
6262f5bb3feSSean Christopherson 
6272f5bb3feSSean Christopherson 	kvm_set_cr8(vcpu, sregs->cr8);
6282f5bb3feSSean Christopherson 
6292f5bb3feSSean Christopherson 	/* Older userspace won't unhalt the vcpu on reset. */
6302f5bb3feSSean Christopherson 	if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 &&
6312f5bb3feSSean Christopherson 	    sregs->cs.selector == 0xf000 && sregs->cs.base == 0xffff0000 &&
6322f5bb3feSSean Christopherson 	    !is_protmode(vcpu))
6332f5bb3feSSean Christopherson 		kvm_set_mp_state(vcpu, KVM_MP_STATE_RUNNABLE);
6342f5bb3feSSean Christopherson 
6352f5bb3feSSean Christopherson 	return 0;
6362f5bb3feSSean Christopherson }
6372f5bb3feSSean Christopherson 
6382f5bb3feSSean Christopherson static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
6392f5bb3feSSean Christopherson {
6402f5bb3feSSean Christopherson 	int pending_vec, max_bits;
6412f5bb3feSSean Christopherson 	int mmu_reset_needed = 0;
6422f5bb3feSSean Christopherson 	int ret = __set_sregs_common(vcpu, sregs, &mmu_reset_needed, true);
6432f5bb3feSSean Christopherson 
6442f5bb3feSSean Christopherson 	if (ret)
6452f5bb3feSSean Christopherson 		return ret;
6462f5bb3feSSean Christopherson 
6472f5bb3feSSean Christopherson 	if (mmu_reset_needed) {
6482f5bb3feSSean Christopherson 		kvm_mmu_reset_context(vcpu);
6492f5bb3feSSean Christopherson 		kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
6502f5bb3feSSean Christopherson 	}
6512f5bb3feSSean Christopherson 
6522f5bb3feSSean Christopherson 	max_bits = KVM_NR_INTERRUPTS;
6532f5bb3feSSean Christopherson 	pending_vec = find_first_bit(
6542f5bb3feSSean Christopherson 		(const unsigned long *)sregs->interrupt_bitmap, max_bits);
6552f5bb3feSSean Christopherson 
6562f5bb3feSSean Christopherson 	if (pending_vec < max_bits) {
6572f5bb3feSSean Christopherson 		kvm_queue_interrupt(vcpu, pending_vec, false);
6582f5bb3feSSean Christopherson 		pr_debug("Set back pending irq %d\n", pending_vec);
6592f5bb3feSSean Christopherson 		kvm_make_request(KVM_REQ_EVENT, vcpu);
6602f5bb3feSSean Christopherson 	}
6612f5bb3feSSean Christopherson 	return 0;
6622f5bb3feSSean Christopherson }
6632f5bb3feSSean Christopherson 
6642f5bb3feSSean Christopherson int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
6652f5bb3feSSean Christopherson 				  struct kvm_sregs *sregs)
6662f5bb3feSSean Christopherson {
6672f5bb3feSSean Christopherson 	int ret;
6682f5bb3feSSean Christopherson 
6692f5bb3feSSean Christopherson 	if (vcpu->kvm->arch.has_protected_state &&
6702f5bb3feSSean Christopherson 	    vcpu->arch.guest_state_protected)
6712f5bb3feSSean Christopherson 		return -EINVAL;
6722f5bb3feSSean Christopherson 
6732f5bb3feSSean Christopherson 	vcpu_load(vcpu);
6742f5bb3feSSean Christopherson 	ret = __set_sregs(vcpu, sregs);
6752f5bb3feSSean Christopherson 	vcpu_put(vcpu);
6762f5bb3feSSean Christopherson 	return ret;
6772f5bb3feSSean Christopherson }
6782f5bb3feSSean Christopherson 
6792f5bb3feSSean Christopherson int kvm_vcpu_ioctl_x86_set_sregs2(struct kvm_vcpu *vcpu,
6802f5bb3feSSean Christopherson 				  struct kvm_sregs2 *sregs2)
6812f5bb3feSSean Christopherson {
6822f5bb3feSSean Christopherson 	int mmu_reset_needed = 0;
6832f5bb3feSSean Christopherson 	bool valid_pdptrs = sregs2->flags & KVM_SREGS2_FLAGS_PDPTRS_VALID;
6842f5bb3feSSean Christopherson 	bool pae = (sregs2->cr0 & X86_CR0_PG) && (sregs2->cr4 & X86_CR4_PAE) &&
6852f5bb3feSSean Christopherson 		!(sregs2->efer & EFER_LMA);
6862f5bb3feSSean Christopherson 	int i, ret;
6872f5bb3feSSean Christopherson 
6882f5bb3feSSean Christopherson 	if (sregs2->flags & ~KVM_SREGS2_FLAGS_PDPTRS_VALID)
6892f5bb3feSSean Christopherson 		return -EINVAL;
6902f5bb3feSSean Christopherson 
6912f5bb3feSSean Christopherson 	if (valid_pdptrs && (!pae || vcpu->arch.guest_state_protected))
6922f5bb3feSSean Christopherson 		return -EINVAL;
6932f5bb3feSSean Christopherson 
6942f5bb3feSSean Christopherson 	ret = __set_sregs_common(vcpu, (struct kvm_sregs *)sregs2,
6952f5bb3feSSean Christopherson 				 &mmu_reset_needed, !valid_pdptrs);
6962f5bb3feSSean Christopherson 	if (ret)
6972f5bb3feSSean Christopherson 		return ret;
6982f5bb3feSSean Christopherson 
6992f5bb3feSSean Christopherson 	if (valid_pdptrs) {
7002f5bb3feSSean Christopherson 		for (i = 0; i < 4 ; i++)
7012f5bb3feSSean Christopherson 			kvm_pdptr_write(vcpu, i, sregs2->pdptrs[i]);
7022f5bb3feSSean Christopherson 
7032f5bb3feSSean Christopherson 		kvm_register_mark_dirty(vcpu, VCPU_REG_PDPTR);
7042f5bb3feSSean Christopherson 		mmu_reset_needed = 1;
7052f5bb3feSSean Christopherson 		vcpu->arch.pdptrs_from_userspace = true;
7062f5bb3feSSean Christopherson 	}
7072f5bb3feSSean Christopherson 	if (mmu_reset_needed) {
7082f5bb3feSSean Christopherson 		kvm_mmu_reset_context(vcpu);
7092f5bb3feSSean Christopherson 		kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu);
7102f5bb3feSSean Christopherson 	}
7112f5bb3feSSean Christopherson 	return 0;
7122f5bb3feSSean Christopherson }
7132f5bb3feSSean Christopherson 
7142f5bb3feSSean Christopherson void kvm_run_sync_regs_to_user(struct kvm_vcpu *vcpu)
7152f5bb3feSSean Christopherson {
7162f5bb3feSSean Christopherson 	BUILD_BUG_ON(sizeof(struct kvm_sync_regs) > SYNC_REGS_SIZE_BYTES);
7172f5bb3feSSean Christopherson 
7182f5bb3feSSean Christopherson 	if (vcpu->run->kvm_valid_regs & KVM_SYNC_X86_REGS)
7192f5bb3feSSean Christopherson 		__get_regs(vcpu, &vcpu->run->s.regs.regs);
7202f5bb3feSSean Christopherson 
7212f5bb3feSSean Christopherson 	if (vcpu->run->kvm_valid_regs & KVM_SYNC_X86_SREGS)
7222f5bb3feSSean Christopherson 		__get_sregs(vcpu, &vcpu->run->s.regs.sregs);
7232f5bb3feSSean Christopherson }
7242f5bb3feSSean Christopherson 
7252f5bb3feSSean Christopherson int kvm_run_sync_regs_from_user(struct kvm_vcpu *vcpu)
7262f5bb3feSSean Christopherson {
7272f5bb3feSSean Christopherson 	if (vcpu->run->kvm_dirty_regs & KVM_SYNC_X86_REGS) {
7282f5bb3feSSean Christopherson 		__set_regs(vcpu, &vcpu->run->s.regs.regs);
7292f5bb3feSSean Christopherson 		vcpu->run->kvm_dirty_regs &= ~KVM_SYNC_X86_REGS;
7302f5bb3feSSean Christopherson 	}
7312f5bb3feSSean Christopherson 
7322f5bb3feSSean Christopherson 	if (vcpu->run->kvm_dirty_regs & KVM_SYNC_X86_SREGS) {
7332f5bb3feSSean Christopherson 		struct kvm_sregs sregs = vcpu->run->s.regs.sregs;
7342f5bb3feSSean Christopherson 
7352f5bb3feSSean Christopherson 		if (__set_sregs(vcpu, &sregs))
7362f5bb3feSSean Christopherson 			return -EINVAL;
7372f5bb3feSSean Christopherson 
7382f5bb3feSSean Christopherson 		vcpu->run->kvm_dirty_regs &= ~KVM_SYNC_X86_SREGS;
7392f5bb3feSSean Christopherson 	}
7402f5bb3feSSean Christopherson 
7412f5bb3feSSean Christopherson 	return 0;
7422f5bb3feSSean Christopherson }
7432f5bb3feSSean Christopherson 
7442f5bb3feSSean Christopherson void kvm_update_dr0123(struct kvm_vcpu *vcpu)
7452f5bb3feSSean Christopherson {
7462f5bb3feSSean Christopherson 	int i;
7472f5bb3feSSean Christopherson 
7482f5bb3feSSean Christopherson 	if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) {
7492f5bb3feSSean Christopherson 		for (i = 0; i < KVM_NR_DB_REGS; i++)
7502f5bb3feSSean Christopherson 			vcpu->arch.eff_db[i] = vcpu->arch.db[i];
7512f5bb3feSSean Christopherson 	}
7522f5bb3feSSean Christopherson }
7532f5bb3feSSean Christopherson 
7542f5bb3feSSean Christopherson void kvm_update_dr7(struct kvm_vcpu *vcpu)
7552f5bb3feSSean Christopherson {
7562f5bb3feSSean Christopherson 	unsigned long dr7;
7572f5bb3feSSean Christopherson 
7582f5bb3feSSean Christopherson 	if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
7592f5bb3feSSean Christopherson 		dr7 = vcpu->arch.guest_debug_dr7;
7602f5bb3feSSean Christopherson 	else
7612f5bb3feSSean Christopherson 		dr7 = vcpu->arch.dr7;
7622f5bb3feSSean Christopherson 	kvm_x86_call(set_dr7)(vcpu, dr7);
7632f5bb3feSSean Christopherson 	vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_BP_ENABLED;
7642f5bb3feSSean Christopherson 	if (dr7 & DR7_BP_EN_MASK)
7652f5bb3feSSean Christopherson 		vcpu->arch.switch_db_regs |= KVM_DEBUGREG_BP_ENABLED;
7662f5bb3feSSean Christopherson }
7672f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_update_dr7);
7682f5bb3feSSean Christopherson 
7692f5bb3feSSean Christopherson static u64 kvm_dr6_fixed(struct kvm_vcpu *vcpu)
7702f5bb3feSSean Christopherson {
7712f5bb3feSSean Christopherson 	u64 fixed = DR6_FIXED_1;
7722f5bb3feSSean Christopherson 
7732f5bb3feSSean Christopherson 	if (!guest_cpu_cap_has(vcpu, X86_FEATURE_RTM))
7742f5bb3feSSean Christopherson 		fixed |= DR6_RTM;
7752f5bb3feSSean Christopherson 
7762f5bb3feSSean Christopherson 	if (!guest_cpu_cap_has(vcpu, X86_FEATURE_BUS_LOCK_DETECT))
7772f5bb3feSSean Christopherson 		fixed |= DR6_BUS_LOCK;
7782f5bb3feSSean Christopherson 	return fixed;
7792f5bb3feSSean Christopherson }
7802f5bb3feSSean Christopherson 
7812f5bb3feSSean Christopherson int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
7822f5bb3feSSean Christopherson {
7832f5bb3feSSean Christopherson 	size_t size = ARRAY_SIZE(vcpu->arch.db);
7842f5bb3feSSean Christopherson 
7852f5bb3feSSean Christopherson 	switch (dr) {
7862f5bb3feSSean Christopherson 	case 0 ... 3:
7872f5bb3feSSean Christopherson 		vcpu->arch.db[array_index_nospec(dr, size)] = val;
7882f5bb3feSSean Christopherson 		if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
7892f5bb3feSSean Christopherson 			vcpu->arch.eff_db[dr] = val;
7902f5bb3feSSean Christopherson 		break;
7912f5bb3feSSean Christopherson 	case 4:
7922f5bb3feSSean Christopherson 	case 6:
7932f5bb3feSSean Christopherson 		if (!kvm_dr6_valid(val))
7942f5bb3feSSean Christopherson 			return 1; /* #GP */
7952f5bb3feSSean Christopherson 		vcpu->arch.dr6 = (val & DR6_VOLATILE) | kvm_dr6_fixed(vcpu);
7962f5bb3feSSean Christopherson 		break;
7972f5bb3feSSean Christopherson 	case 5:
7982f5bb3feSSean Christopherson 	default: /* 7 */
7992f5bb3feSSean Christopherson 		if (!kvm_dr7_valid(val))
8002f5bb3feSSean Christopherson 			return 1; /* #GP */
8012f5bb3feSSean Christopherson 		vcpu->arch.dr7 = (val & DR7_VOLATILE) | DR7_FIXED_1;
8022f5bb3feSSean Christopherson 		kvm_update_dr7(vcpu);
8032f5bb3feSSean Christopherson 		break;
8042f5bb3feSSean Christopherson 	}
8052f5bb3feSSean Christopherson 
8062f5bb3feSSean Christopherson 	return 0;
8072f5bb3feSSean Christopherson }
8082f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_dr);
8092f5bb3feSSean Christopherson 
8102f5bb3feSSean Christopherson unsigned long kvm_get_dr(struct kvm_vcpu *vcpu, int dr)
8112f5bb3feSSean Christopherson {
8122f5bb3feSSean Christopherson 	size_t size = ARRAY_SIZE(vcpu->arch.db);
8132f5bb3feSSean Christopherson 
8142f5bb3feSSean Christopherson 	switch (dr) {
8152f5bb3feSSean Christopherson 	case 0 ... 3:
8162f5bb3feSSean Christopherson 		return vcpu->arch.db[array_index_nospec(dr, size)];
8172f5bb3feSSean Christopherson 	case 4:
8182f5bb3feSSean Christopherson 	case 6:
8192f5bb3feSSean Christopherson 		return vcpu->arch.dr6;
8202f5bb3feSSean Christopherson 	case 5:
8212f5bb3feSSean Christopherson 	default: /* 7 */
8222f5bb3feSSean Christopherson 		return vcpu->arch.dr7;
8232f5bb3feSSean Christopherson 	}
8242f5bb3feSSean Christopherson }
8252f5bb3feSSean Christopherson EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_dr);
8262f5bb3feSSean Christopherson 
8272f5bb3feSSean Christopherson int kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
8282f5bb3feSSean Christopherson 				     struct kvm_debugregs *dbgregs)
8292f5bb3feSSean Christopherson {
8302f5bb3feSSean Christopherson 	unsigned int i;
8312f5bb3feSSean Christopherson 
8322f5bb3feSSean Christopherson 	if (vcpu->kvm->arch.has_protected_state &&
8332f5bb3feSSean Christopherson 	    vcpu->arch.guest_state_protected)
8342f5bb3feSSean Christopherson 		return -EINVAL;
8352f5bb3feSSean Christopherson 
8362f5bb3feSSean Christopherson 	kvm_handle_exception_payload_quirk(vcpu);
8372f5bb3feSSean Christopherson 
8382f5bb3feSSean Christopherson 	memset(dbgregs, 0, sizeof(*dbgregs));
8392f5bb3feSSean Christopherson 
8402f5bb3feSSean Christopherson 	BUILD_BUG_ON(ARRAY_SIZE(vcpu->arch.db) != ARRAY_SIZE(dbgregs->db));
8412f5bb3feSSean Christopherson 	for (i = 0; i < ARRAY_SIZE(vcpu->arch.db); i++)
8422f5bb3feSSean Christopherson 		dbgregs->db[i] = vcpu->arch.db[i];
8432f5bb3feSSean Christopherson 
8442f5bb3feSSean Christopherson 	dbgregs->dr6 = vcpu->arch.dr6;
8452f5bb3feSSean Christopherson 	dbgregs->dr7 = vcpu->arch.dr7;
8462f5bb3feSSean Christopherson 	return 0;
8472f5bb3feSSean Christopherson }
8482f5bb3feSSean Christopherson 
8492f5bb3feSSean Christopherson int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
8502f5bb3feSSean Christopherson 				     struct kvm_debugregs *dbgregs)
8512f5bb3feSSean Christopherson {
8522f5bb3feSSean Christopherson 	unsigned int i;
8532f5bb3feSSean Christopherson 
8542f5bb3feSSean Christopherson 	if (vcpu->kvm->arch.has_protected_state &&
8552f5bb3feSSean Christopherson 	    vcpu->arch.guest_state_protected)
8562f5bb3feSSean Christopherson 		return -EINVAL;
8572f5bb3feSSean Christopherson 
8582f5bb3feSSean Christopherson 	if (dbgregs->flags)
8592f5bb3feSSean Christopherson 		return -EINVAL;
8602f5bb3feSSean Christopherson 
8612f5bb3feSSean Christopherson 	if (!kvm_dr6_valid(dbgregs->dr6))
8622f5bb3feSSean Christopherson 		return -EINVAL;
8632f5bb3feSSean Christopherson 	if (!kvm_dr7_valid(dbgregs->dr7))
8642f5bb3feSSean Christopherson 		return -EINVAL;
8652f5bb3feSSean Christopherson 
8662f5bb3feSSean Christopherson 	for (i = 0; i < ARRAY_SIZE(vcpu->arch.db); i++)
8672f5bb3feSSean Christopherson 		vcpu->arch.db[i] = dbgregs->db[i];
8682f5bb3feSSean Christopherson 
8692f5bb3feSSean Christopherson 	kvm_update_dr0123(vcpu);
8702f5bb3feSSean Christopherson 	vcpu->arch.dr6 = dbgregs->dr6;
8712f5bb3feSSean Christopherson 	vcpu->arch.dr7 = dbgregs->dr7;
8722f5bb3feSSean Christopherson 	kvm_update_dr7(vcpu);
8732f5bb3feSSean Christopherson 
8742f5bb3feSSean Christopherson 	return 0;
8752f5bb3feSSean Christopherson }
876