Skip to content

Commit 98da818

Browse files
mdouchapevik
authored andcommitted
KVM: Add helper functions for nested Intel VMX virtualization
Link: https://lore.kernel.org/ltp/[email protected]/ Acked-by: Petr Vorel <[email protected]> Signed-off-by: Martin Doucha <[email protected]>
1 parent c3a4555 commit 98da818

File tree

4 files changed

+807
-0
lines changed

4 files changed

+807
-0
lines changed

testcases/kernel/kvm/bootstrap_x86.S

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
.set MSR_VM_HSAVE_PA, 0xc0010117
1313

14+
.set VMX_VMCS_HOST_RSP, 0x6c14
15+
.set VMX_VMCS_HOST_RIP, 0x6c16
16+
1417
/*
1518
* This section will be allocated at address 0x1000 and
1619
* jumped to from the reset stub provided by kvm_run.
@@ -451,6 +454,67 @@ kvm_svm_vmrun:
451454
pop %edi
452455
ret
453456

457+
.global kvm_vmx_vmlaunch
458+
kvm_vmx_vmlaunch:
459+
push %edi
460+
mov 8(%esp), %edi
461+
push %ebx
462+
push %esi
463+
push %ebp
464+
push %edi
465+
466+
mov $VMX_VMCS_HOST_RSP, %eax
467+
vmwrite %esp, %eax
468+
jna vmx_vmwrite_error
469+
mov $VMX_VMCS_HOST_RIP, %eax
470+
lea vmx_vm_exit, %ebx
471+
vmwrite %ebx, %eax
472+
jna vmx_vmwrite_error
473+
474+
load_vcpu_regs
475+
vmlaunch
476+
jmp vmx_vm_exit
477+
478+
.global kvm_vmx_vmresume
479+
kvm_vmx_vmresume:
480+
push %edi
481+
mov 8(%esp), %edi
482+
push %ebx
483+
push %esi
484+
push %ebp
485+
push %edi
486+
487+
mov $VMX_VMCS_HOST_RSP, %eax
488+
vmwrite %esp, %eax
489+
jna vmx_vmwrite_error
490+
mov $VMX_VMCS_HOST_RIP, %eax
491+
lea vmx_vm_exit, %ebx
492+
vmwrite %ebx, %eax
493+
jna vmx_vmwrite_error
494+
495+
load_vcpu_regs
496+
vmresume
497+
498+
vmx_vm_exit:
499+
jna vmx_vmentry_error
500+
save_vcpu_regs
501+
xorl %eax, %eax
502+
503+
vmx_vm_ret:
504+
pop %edi
505+
pop %ebp
506+
pop %esi
507+
pop %ebx
508+
pop %edi
509+
ret
510+
511+
vmx_vmwrite_error:
512+
movl $2, %eax
513+
jmp vmx_vm_ret
514+
515+
vmx_vmentry_error:
516+
movl $1, %eax
517+
jmp vmx_vm_ret
454518

455519
.section .bss.pgtables, "aw", @nobits
456520
.global kvm_pagetable

testcases/kernel/kvm/bootstrap_x86_64.S

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212

1313
.set MSR_VM_HSAVE_PA, 0xc0010117
1414

15+
.set VMX_VMCS_HOST_RSP, 0x6c14
16+
.set VMX_VMCS_HOST_RIP, 0x6c16
17+
1518
/*
1619
* This section will be allocated at address 0x1000 and
1720
* jumped to from the reset stub provided by kvm_run.
@@ -587,6 +590,57 @@ kvm_svm_vmrun:
587590
pop_local
588591
retq
589592

593+
.global kvm_vmx_vmlaunch
594+
kvm_vmx_vmlaunch:
595+
push_local
596+
pushq %rdi
597+
598+
mov $VMX_VMCS_HOST_RSP, %rax
599+
vmwrite %rsp, %rax
600+
jna vmx_vmwrite_error
601+
mov $VMX_VMCS_HOST_RIP, %rax
602+
lea vmx_vm_exit, %rbx
603+
vmwrite %rbx, %rax
604+
jna vmx_vmwrite_error
605+
606+
load_vcpu_regs
607+
vmlaunch
608+
jmp vmx_vm_exit
609+
610+
.global kvm_vmx_vmresume
611+
kvm_vmx_vmresume:
612+
push_local
613+
pushq %rdi
614+
615+
movq $VMX_VMCS_HOST_RSP, %rax
616+
vmwrite %rsp, %rax
617+
jna vmx_vmwrite_error
618+
movq $VMX_VMCS_HOST_RIP, %rax
619+
lea vmx_vm_exit, %rbx
620+
vmwrite %rbx, %rax
621+
jna vmx_vmwrite_error
622+
623+
load_vcpu_regs
624+
vmresume
625+
626+
vmx_vm_exit:
627+
jna vmx_vmentry_error
628+
save_vcpu_regs
629+
xorq %rax, %rax
630+
631+
vmx_vm_ret:
632+
popq %rdi
633+
pop_local
634+
retq
635+
636+
vmx_vmwrite_error:
637+
movq $2, %rax
638+
jmp vmx_vm_ret
639+
640+
vmx_vmentry_error:
641+
movq $1, %rax
642+
jmp vmx_vm_ret
643+
590644
.section .bss.pgtables, "aw", @nobits
591645
.global kvm_pagetable
592646
kvm_pagetable:
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* Copyright (C) 2024 SUSE LLC <[email protected]>
4+
*
5+
* x86-specific KVM helper functions and structures for Intel VMX
6+
*/
7+
8+
#ifndef KVM_X86_VMX_H_
9+
#define KVM_X86_VMX_H_
10+
11+
#include "kvm_x86.h"
12+
13+
/* CPUID_GET_MODEL_INFO flags returned in ECX */
14+
#define CPUID_MODEL_VMX (1 << 5)
15+
#define CPUID_MODEL_SMX (1 << 6)
16+
17+
#define MSR_IA32_VMX_BASIC 0x480
18+
#define MSR_IA32_VMX_PINX_MASK 0x481
19+
#define MSR_IA32_VMX_EXECCTL_MASK 0x482
20+
#define MSR_IA32_VMX_EXITCTL_MASK 0x483
21+
#define MSR_IA32_VMX_ENTRYCTL_MASK 0x484
22+
#define MSR_IA32_VMX_CR0_FIXED0 0x486
23+
#define MSR_IA32_VMX_CR0_FIXED1 0x487
24+
#define MSR_IA32_VMX_CR4_FIXED0 0x488
25+
#define MSR_IA32_VMX_CR4_FIXED1 0x489
26+
#define MSR_IA32_VMX_EXECCTL2_MASK 0x48b
27+
#define MSR_IA32_VMX_PINX_MASK2 0x48d
28+
#define MSR_IA32_VMX_EXECCTL_MASK2 0x48e
29+
#define MSR_IA32_VMX_EXITCTL_MASK2 0x48f
30+
#define MSR_IA32_VMX_ENTRYCTL_MASK2 0x490
31+
32+
#define IA32FC_LOCK (1 << 0)
33+
#define IA32FC_VMXON_SMX (1 << 1)
34+
#define IA32FC_VMXON_NORMAL (1 << 2)
35+
36+
#define IA32_VMXBASIC_USELESS_CTL_MASKS (1ULL << 55)
37+
38+
#define VMX_VMCS_GUEST_ES 0x800
39+
#define VMX_VMCS_GUEST_CS 0x802
40+
#define VMX_VMCS_GUEST_SS 0x804
41+
#define VMX_VMCS_GUEST_DS 0x806
42+
#define VMX_VMCS_GUEST_FS 0x808
43+
#define VMX_VMCS_GUEST_GS 0x80a
44+
#define VMX_VMCS_GUEST_LDTR 0x80c
45+
#define VMX_VMCS_GUEST_TR 0x80e
46+
#define VMX_VMCS_GUEST_INTR 0x810
47+
#define VMX_VMCS_HOST_ES 0xc00
48+
#define VMX_VMCS_HOST_CS 0xc02
49+
#define VMX_VMCS_HOST_SS 0xc04
50+
#define VMX_VMCS_HOST_DS 0xc06
51+
#define VMX_VMCS_HOST_FS 0xc08
52+
#define VMX_VMCS_HOST_GS 0xc0a
53+
#define VMX_VMCS_HOST_TR 0xc0c
54+
55+
#define VMX_VMCS_LINK_POINTER 0x2800
56+
57+
#define VMX_VMCS_GUEST_ES_LIMIT 0x4800
58+
#define VMX_VMCS_GUEST_CS_LIMIT 0x4802
59+
#define VMX_VMCS_GUEST_SS_LIMIT 0x4804
60+
#define VMX_VMCS_GUEST_DS_LIMIT 0x4806
61+
#define VMX_VMCS_GUEST_FS_LIMIT 0x4808
62+
#define VMX_VMCS_GUEST_GS_LIMIT 0x480a
63+
#define VMX_VMCS_GUEST_LDTR_LIMIT 0x480c
64+
#define VMX_VMCS_GUEST_TR_LIMIT 0x480e
65+
#define VMX_VMCS_GUEST_GDTR_LIMIT 0x4810
66+
#define VMX_VMCS_GUEST_IDTR_LIMIT 0x4812
67+
#define VMX_VMCS_GUEST_ES_ACCESS 0x4814
68+
#define VMX_VMCS_GUEST_CS_ACCESS 0x4816
69+
#define VMX_VMCS_GUEST_SS_ACCESS 0x4818
70+
#define VMX_VMCS_GUEST_DS_ACCESS 0x481a
71+
#define VMX_VMCS_GUEST_FS_ACCESS 0x481c
72+
#define VMX_VMCS_GUEST_GS_ACCESS 0x481e
73+
#define VMX_VMCS_GUEST_LDTR_ACCESS 0x4820
74+
#define VMX_VMCS_GUEST_TR_ACCESS 0x4822
75+
#define VMX_VMCS_GUEST_INTR_STATE 0x4824
76+
#define VMX_VMCS_GUEST_ACT_STATE 0x4826
77+
#define VMX_VMCS_GUEST_SMBASE 0x4828
78+
#define VMX_VMCS_GUEST_SYSENTER_CS 0x482a
79+
#define VMX_VMCS_HOST_SYSENTER_CS 0x4c00
80+
81+
#define VMX_VMCS_GUEST_CR0 0x6800
82+
#define VMX_VMCS_GUEST_CR3 0x6802
83+
#define VMX_VMCS_GUEST_CR4 0x6804
84+
#define VMX_VMCS_GUEST_ES_BASE 0x6806
85+
#define VMX_VMCS_GUEST_CS_BASE 0x6808
86+
#define VMX_VMCS_GUEST_SS_BASE 0x680a
87+
#define VMX_VMCS_GUEST_DS_BASE 0x680c
88+
#define VMX_VMCS_GUEST_FS_BASE 0x680e
89+
#define VMX_VMCS_GUEST_GS_BASE 0x6810
90+
#define VMX_VMCS_GUEST_LDTR_BASE 0x6812
91+
#define VMX_VMCS_GUEST_TR_BASE 0x6814
92+
#define VMX_VMCS_GUEST_GDTR_BASE 0x6816
93+
#define VMX_VMCS_GUEST_IDTR_BASE 0x6818
94+
#define VMX_VMCS_GUEST_DR7 0x681a
95+
#define VMX_VMCS_GUEST_RSP 0x681c
96+
#define VMX_VMCS_GUEST_RIP 0x681e
97+
#define VMX_VMCS_GUEST_RFLAGS 0x6820
98+
#define VMX_VMCS_GUEST_DEBUG_EXC 0x6822
99+
#define VMX_VMCS_GUEST_SYSENTER_ESP 0x6824
100+
#define VMX_VMCS_GUEST_SYSENTER_EIP 0x6826
101+
#define VMX_VMCS_HOST_CR0 0x6c00
102+
#define VMX_VMCS_HOST_CR3 0x6c02
103+
#define VMX_VMCS_HOST_CR4 0x6c04
104+
#define VMX_VMCS_HOST_FS_BASE 0x6c06
105+
#define VMX_VMCS_HOST_GS_BASE 0x6c08
106+
#define VMX_VMCS_HOST_TR_BASE 0x6c0a
107+
#define VMX_VMCS_HOST_GDTR_BASE 0x6c0c
108+
#define VMX_VMCS_HOST_IDTR_BASE 0x6c0e
109+
#define VMX_VMCS_HOST_SYSENTER_ESP 0x6c10
110+
#define VMX_VMCS_HOST_SYSENTER_EIP 0x6c12
111+
#define VMX_VMCS_HOST_RSP 0x6c14
112+
#define VMX_VMCS_HOST_RIP 0x6c16
113+
114+
#define VMX_VMCS_VMPINX_CTL 0x4000
115+
#define VMX_VMCS_VMEXEC_CTL 0x4002
116+
#define VMX_VMCS_VMEXIT_CTL 0x400c
117+
#define VMX_VMCS_VMEXIT_MSR_STORE 0x400e
118+
#define VMX_VMCS_VMEXIT_MSR_LOAD 0x4010
119+
#define VMX_VMCS_VMENTRY_CTL 0x4012
120+
#define VMX_VMCS_VMENTRY_MSR_LOAD 0x4014
121+
#define VMX_VMCS_VMENTRY_INTR 0x4016
122+
#define VMX_VMCS_VMENTRY_EXC 0x4018
123+
#define VMX_VMCS_VMENTRY_INST_LEN 0x401a
124+
#define VMX_VMCS_VMEXEC_CTL2 0x401e
125+
126+
#define VMX_VMCS_VMINST_ERROR 0x4400
127+
#define VMX_VMCS_EXIT_REASON 0x4402
128+
#define VMX_VMCS_VMEXIT_INTR_INFO 0x4404
129+
#define VMX_VMCS_VMEXIT_INTR_ERRNO 0x4406
130+
#define VMX_VMCS_IDTVEC_INFO 0x4408
131+
#define VMX_VMCS_IDTVEC_ERRNO 0x440a
132+
#define VMX_VMCS_VMEXIT_INST_LEN 0x440c
133+
#define VMX_VMCS_VMEXIT_INST_INFO 0x440e
134+
#define VMX_VMCS_EXIT_QUALIFICATION 0x6400
135+
136+
#define VMX_INTERCEPT_HLT (1 << 7)
137+
#define VMX_EXECCTL_ENABLE_CTL2 (1 << 31)
138+
139+
#define VMX_EXECCTL2_SHADOW_VMCS (1 << 14)
140+
141+
#define VMX_EXITCTL_SAVE_DR (1 << 2)
142+
#define VMX_EXITCTL_X64 (1 << 9)
143+
144+
#define VMX_ENTRYCTL_LOAD_DR (1 << 2)
145+
#define VMX_ENTRYCTL_X64 (1 << 9)
146+
147+
#define VMX_SHADOW_VMCS 0x80000000
148+
#define VMX_VMCSFIELD_64BIT 0x2000
149+
#define VMX_VMCSFIELD_SIZE_MASK 0x6000
150+
151+
#define VMX_INVALID_VMCS 0xffffffffffffffffULL
152+
153+
#define VMX_EXIT_HLT 12
154+
#define VMX_EXIT_FAILED_ENTRY 0x80000000
155+
156+
struct kvm_vmcs {
157+
uint32_t version;
158+
uint32_t abort;
159+
uint8_t data[4088];
160+
};
161+
162+
struct kvm_vmx_vcpu {
163+
struct kvm_vmcs *vmcs;
164+
struct kvm_regs64 regs;
165+
int launched;
166+
};
167+
168+
/* Intel VMX virtualization helper functions */
169+
int kvm_is_vmx_supported(void);
170+
void kvm_set_vmx_state(int enabled);
171+
struct kvm_vmcs *kvm_alloc_vmcs(void);
172+
173+
/* Copy GDT entry to given fields of the current VMCS */
174+
void kvm_vmcs_copy_gdt_descriptor(unsigned int gdt_id,
175+
unsigned long vmcs_selector, unsigned long vmcs_flags,
176+
unsigned long vmcs_limit, unsigned long vmcs_baseaddr);
177+
void kvm_init_vmx_vcpu(struct kvm_vmx_vcpu *cpu, uint16_t ss, void *rsp,
178+
int (*guest_main)(void));
179+
struct kvm_vmx_vcpu *kvm_create_vmx_vcpu(int (*guest_main)(void),
180+
int alloc_stack);
181+
182+
/* Set the VMCS as current and update the host state fields */
183+
void kvm_vmx_activate_vcpu(struct kvm_vmx_vcpu *cpu);
184+
void kvm_vmx_vmrun(struct kvm_vmx_vcpu *cpu);
185+
186+
void kvm_vmx_vmclear(struct kvm_vmcs *buf);
187+
void kvm_vmx_vmptrld(struct kvm_vmcs *buf);
188+
uint64_t kvm_vmx_vmptrst(void);
189+
uint64_t kvm_vmx_vmread(unsigned long var_id);
190+
void kvm_vmx_vmwrite(unsigned long var_id, uint64_t value);
191+
int kvm_vmx_vmlaunch(struct kvm_vmx_vcpu *buf);
192+
int kvm_vmx_vmresume(struct kvm_vmx_vcpu *buf);
193+
194+
/* Read last VMX instruction error from current VMCS */
195+
int kvm_vmx_inst_errno(void);
196+
/* Get VMX instruction error description */
197+
const char *kvm_vmx_inst_strerr(int vmx_errno);
198+
/* Get description of last VMX instruction error in current VMCS */
199+
const char *kvm_vmx_inst_err(void);
200+
201+
#endif /* KVM_X86_VMX_H_ */

0 commit comments

Comments
 (0)