Skip to content

Commit 60d880b

Browse files
committed
platform: add SlimVM platform
SlimVM is a lightweight VMX-based platform for gVisor that accelerates sentry system calls by eliminating unnecessary user/kernel context switches. In a traditional gVisor + KVM setup, every guest syscall triggers a full VM exit to userspace, then re-enters the kernel via a regular syscall: gr0 -> hr0 (vm_exit) -> hr3 (ioctl return) -> hr0 (re-invoke syscall) SlimVM eliminates this overhead. When the guest executes a VMCALL, the VM exits into VMX root mode where SlimVM directly invokes the host kernel's syscall handler, then immediately resumes the guest: gr0 -> hr0 (vmcall + direct function call) SlimVM requires a companion kernel module that provides the /dev/slimvm device interface. See https://github.com/antgroup/slimvm for the kernel module and full documentation. Co-developed-by: Chenggang <chenggang.qcg@antfin.com> Co-developed-by: Robin Luk <lubin.lu@antgroup.com> Co-developed-by: Tiwei Bie <tiwei.btw@antgroup.com> Co-developed-by: Jianfeng Tan <henry.tjf@antgroup.com> Co-developed-by: liushi.ls <liushi.ls@antfin.com> Co-developed-by: Yong He <chenglang.hy@antgroup.com> Co-developed-by: Aaron Lu <ziqian.lzq@antfin.com> Co-developed-by: chris.zn <chris.zn@alibaba-inc.com> Co-developed-by: Lai Jiangshan <jiangshan.ljs@antfin.com> Co-developed-by: Lingfu <yupeng.chenyp@alibaba-inc.com> Co-developed-by: Min Le <lemin.lm@antgroup.com> Co-developed-by: Quan Xu <wutu.xq@alibaba-inc.com> Co-developed-by: Zhang Haoyu <zhanghaoyu.zhy@alibaba-inc.com> Co-developed-by: Dawei Shen <shendawei.sdw@antgroup.com> Signed-off-by: Tianyu Zhou <albert.zty@antgroup.com>
1 parent 50af291 commit 60d880b

59 files changed

Lines changed: 4793 additions & 12 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

pkg/hostarch/hostarch_arm64.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,15 @@ const (
2929
// HugePageSize is the system huge page size.
3030
HugePageSize = 1 << HugePageShift
3131

32+
// JumboPageSize is the 1GB jumbo page size.
33+
JumboPageSize = 1 << JumboPageShift
34+
3235
// CacheLineSize is the size of the cache line.
3336
CacheLineSize = 1 << CacheLineShift
3437

38+
// JumboPageShift is the binary log of jumbo page whose size is 1GB.
39+
JumboPageShift = 30
40+
3541
// CacheLineShift is the binary log of the cache line size.
3642
CacheLineShift = 6
3743
)

pkg/hostarch/hostarch_x86.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ const (
2626
// HugePageSize is the system huge page size.
2727
HugePageSize = 1 << HugePageShift
2828

29+
// JumboPageSize is the 1GB jumbo page size.
30+
JumboPageSize = 1 << JumboPageShift
31+
2932
// CacheLineSize is the size of the cache line.
3033
CacheLineSize = 1 << CacheLineShift
3134

@@ -35,6 +38,9 @@ const (
3538
// HugePageShift is the binary log of the system huge page size.
3639
HugePageShift = 21
3740

41+
// JumboPageShift is the binary log of jumbo page whose size is 1GB.
42+
JumboPageShift = 30
43+
3844
// CacheLineShift is the binary log of the cache line size.
3945
CacheLineShift = 6
4046
)

pkg/hostarch/sizes_util.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const (
1111
PageMask = PageSize - 1
1212
HugePageMask = HugePageSize - 1
1313
CacheLineMask = CacheLineSize - 1
14+
JumboPageMask = ^uintptr(JumboPageSize - 1)
1415
)
1516

1617
type bytecount interface {

pkg/ring0/aarch64.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,5 +102,6 @@ const (
102102
const (
103103
Syscall Vector = El0SyncSVC
104104
PageFault Vector = El0SyncDa
105+
OOMException Vector = El0Fiq
105106
VirtualizationException Vector = El0ErrBounce
106107
)

pkg/ring0/defs.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ import (
2020
"gvisor.dev/gvisor/pkg/sentry/arch/fpu"
2121
)
2222

23+
const (
24+
// CPUIntel is Intel CPU.
25+
CPUIntel uint64 = iota
26+
27+
// CPUAMD is AMD (and compatible) CPU.
28+
CPUAMD
29+
)
30+
31+
var (
32+
CPUVendor uint64
33+
)
34+
2335
// Kernel is a global kernel object.
2436
//
2537
// This contains global state, shared by multiple CPUs.

pkg/ring0/defs_amd64.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ type kernelEntry struct {
108108
// kernelCR3 is the cr3 used for sentry kernel.
109109
kernelCR3 uintptr
110110

111+
// whether enable VMCALL
112+
enableVMCALL uint64
113+
111114
// gdt is the CPU's descriptor table.
112115
gdt descriptorTable
113116

@@ -180,6 +183,14 @@ func (c *CPU) FaultAddr() uintptr {
180183
return c.faultAddr
181184
}
182185

186+
func (c *CPU) EnableVMCALL() {
187+
c.enableVMCALL = 1
188+
}
189+
190+
func (c *CPU) DisableVMCALL() {
191+
c.enableVMCALL = 0
192+
}
193+
183194
// SwitchArchOpts are embedded in SwitchOpts.
184195
type SwitchArchOpts struct {
185196
// UserPCID indicates that the application PCID to be used on switch,

pkg/ring0/entry_amd64.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ func machineCheck()
117117
func simdFloatingPointException()
118118
func virtualizationException()
119119
func securityException()
120+
func oomException()
120121
func syscallInt80()
121122

122123
// These returns the start address of the functions above.
@@ -145,6 +146,7 @@ func addrOfMachineCheck() uintptr
145146
func addrOfSimdFloatingPointException() uintptr
146147
func addrOfVirtualizationException() uintptr
147148
func addrOfSecurityException() uintptr
149+
func addrOfOOMException() uintptr
148150
func addrOfSyscallInt80() uintptr
149151

150152
// Exception handler index.
@@ -170,5 +172,6 @@ var handlers = map[Vector]uintptr{
170172
SIMDFloatingPointException: addrOfSimdFloatingPointException(),
171173
VirtualizationException: addrOfVirtualizationException(),
172174
SecurityException: addrOfSecurityException(),
175+
OOMException: addrOfOOMException(),
173176
SyscallInt80: addrOfSyscallInt80(),
174177
}

pkg/ring0/entry_amd64.s

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#define ENTRY_STACK_TOP 264 // +checkoffset . kernelEntry.stackTop
3434
#define ENTRY_CPU_SELF 272 // +checkoffset . kernelEntry.cpuSelf
3535
#define ENTRY_KERNEL_CR3 280 // +checkoffset . kernelEntry.kernelCR3
36+
#define ENTRY_ENABLE_VMCALL 288 // +checkoffset . kernelEntry.enableVMCALL
3637

3738
// Bits.
3839
#define _RFLAGS_IF 512 // +checkconst . _RFLAGS_IF
@@ -61,9 +62,16 @@
6162
#define SIMDFloatingPointException 19 // +checkconst . SIMDFloatingPointException
6263
#define VirtualizationException 20 // +checkconst . VirtualizationException
6364
#define SecurityException 30 // +checkconst . SecurityException
65+
#define OOMException 32 // +checkconst . OOMException
6466
#define SyscallInt80 128 // +checkconst . SyscallInt80
6567
#define Syscall 256 // +checkconst . Syscall
6668

69+
#define SyscallExit 60 // +checkconst . SyscallExit
70+
#define SyscallExitGroup 231 // +checkconst . SyscallExitGroup
71+
#define SyscallRedPill 4294967295 // +checkconst . SyscallRedPill
72+
73+
#define CPUIntel 0 // +checkconst . CPUIntel
74+
6775
#define PTRACE_R15 0 // +checkoffset linux PtraceRegs.R15
6876
#define PTRACE_R14 8 // +checkoffset linux PtraceRegs.R14
6977
#define PTRACE_R13 16 // +checkoffset linux PtraceRegs.R13
@@ -160,6 +168,15 @@
160168
#define LOAD_KERNEL_STACK(entry) \
161169
MOVQ ENTRY_STACK_TOP(entry), SP;
162170

171+
// VMCALL do vmcall/vmmcal instruction
172+
#define VMCALL() \
173+
CMPQ ·CPUVendor(SB), $CPUIntel; \
174+
JE 2(PC); \
175+
JMP 5(PC); \ // vmmcall and vmcall will be treated as 3 independent instructions
176+
BYTE $0x0F; BYTE $0x01; BYTE $0xC1; \
177+
JMP 4(PC); \ // vmmcall and vmcall will be treated as 3 independent instructions
178+
BYTE $0x0F; BYTE $0x01; BYTE $0xD9;
179+
163180
// ADDR_OF_FUNC defines a function named 'name' that returns the address of
164181
// 'symbol'.
165182
#define ADDR_OF_FUNC(name, symbol) \
@@ -488,6 +505,45 @@ sysenter_skip_gs:
488505
RET
489506

490507
kernel:
508+
// Handle any syscalls from GR0 in HR3 when EnableVMCALL is false.
509+
// Currently there are 2 use cases:
510+
// 1. Using KVM platform.
511+
// 2. Upgrading SlimVM platform. This is one such method to return M to
512+
// user mode (HR3) for upgrading platform.
513+
CMPQ ENTRY_ENABLE_VMCALL(GS), $0
514+
JE hr3_do_syscall
515+
516+
CMPQ AX, $SyscallRedPill
517+
JE hr3_do_syscall
518+
519+
CMPQ AX, $SyscallExit
520+
JE hr3_do_syscall
521+
522+
CMPQ AX, $SyscallExitGroup
523+
JE hr3_do_syscall
524+
525+
vmcall:
526+
// handle syscall from GR0 in host kernel
527+
// copy from "handle system calls from G0" part of __dune_syscall in libdune/dune.S
528+
PUSHQ R11
529+
POPFQ
530+
531+
CMPQ AX, $158 // arch_prctl syscall
532+
JNE 3(PC)
533+
CMPQ DI, $0x1002 //ARCH_SET_FS
534+
JE arch_prctl_vmcall
535+
536+
VMCALL()
537+
JMP *CX
538+
539+
arch_prctl_vmcall:
540+
VMCALL()
541+
CMPQ AX, $0
542+
JNE 2(PC)
543+
MOVQ SI, CPU_REGISTERS+PTRACE_FS_BASE(GS)
544+
JMP *CX
545+
546+
hr3_do_syscall:
491547
// We can't restore the original stack, but we can access the registers
492548
// in the CPU state directly. No need for temporary juggling.
493549
MOVQ AX, ENTRY_SCRATCH0(GS)
@@ -705,4 +761,5 @@ EXCEPTION_WITHOUT_ERROR(MachineCheck, ·machineCheck(SB), ·addrOfMachineCheck(S
705761
EXCEPTION_WITHOUT_ERROR(SIMDFloatingPointException, ·simdFloatingPointException(SB), ·addrOfSimdFloatingPointException(SB))
706762
EXCEPTION_WITHOUT_ERROR(VirtualizationException, ·virtualizationException(SB), ·addrOfVirtualizationException(SB))
707763
EXCEPTION_WITH_ERROR(SecurityException, ·securityException(SB), ·addrOfSecurityException(SB))
764+
EXCEPTION_WITH_ERROR(OOMException, ·oomException(SB), ·addrOfOOMException(SB))
708765
EXCEPTION_WITHOUT_ERROR(SyscallInt80, ·syscallInt80(SB), ·addrOfSyscallInt80(SB))

pkg/ring0/entry_arm64.s

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#define El0ErrNMI 34 // +checkconst . El0ErrNMI
6565
#define PageFault 23 // +checkconst . PageFault
6666
#define Syscall 22 // +checkconst . Syscall
67+
#define OOMException 10 // +checkconst . OOMException
6768
#define VirtualizationException 35 // +checkconst . VirtualizationException
6869

6970
#define PTRACE_REGS 0 // +checkoffset linux PtraceRegs.Regs
@@ -765,7 +766,10 @@ TEXT ·El0_irq(SB),NOSPLIT,$0
765766
B ·Shutdown(SB)
766767

767768
TEXT ·El0_fiq(SB),NOSPLIT,$0
768-
B ·Shutdown(SB)
769+
KERNEL_ENTRY_FROM_EL0
770+
MOVD $0x8400000a, R8
771+
HVC $0
772+
EXCEPTION_EL0(OOMException)
769773

770774
TEXT ·El0_error(SB),NOSPLIT,$0
771775
KERNEL_ENTRY_FROM_EL0

pkg/ring0/kernel_amd64.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,3 +324,30 @@ func startGo(c *CPU) {
324324
func ReadCR2() uintptr {
325325
return readCR2()
326326
}
327+
328+
//go:noinline
329+
//go:nosplit
330+
func (c *CPU) PrefaultIDT() uint32 {
331+
return c.kernel.globalIDT[0].bits[0] + c.kernel.globalIDT[_NR_INTERRUPTS-1].bits[3]
332+
}
333+
334+
// SetCPUIDFaulting sets CPUID faulting per the boolean value.
335+
//
336+
// True is returned if faulting could be set.
337+
//
338+
//go:nosplit
339+
func SetCPUIDFaulting(on bool) bool {
340+
// Per the SDM (Vol 3, Table 2-43), PLATFORM_INFO bit 31 denotes support
341+
// for CPUID faulting, and we enable and disable via the MISC_FEATURES MSR.
342+
if rdmsr(_MSR_PLATFORM_INFO)&_PLATFORM_INFO_CPUID_FAULT != 0 {
343+
features := rdmsr(_MSR_MISC_FEATURES)
344+
if on {
345+
features |= _MISC_FEATURE_CPUID_TRAP
346+
} else {
347+
features &^= _MISC_FEATURE_CPUID_TRAP
348+
}
349+
wrmsr(_MSR_MISC_FEATURES, features)
350+
return true // Setting successful.
351+
}
352+
return false
353+
}

0 commit comments

Comments
 (0)