summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/platform/kvm/testutil
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2021-07-12 07:59:47 -0700
committergVisor bot <gvisor-bot@google.com>2021-07-12 08:01:53 -0700
commit36a17a814bf90bad33eac25ddbb7a416143a4be7 (patch)
treefaa4d72267f1efc227cd56d0e8f8cb23c5dacb16 /pkg/sentry/platform/kvm/testutil
parentd78713e2da5331a22fc51fb9a9ad33cc1873879c (diff)
Go 1.17 support for the KVM platform
Go 1.17 adds a new register-based calling convention. While transparent for most applications, the KVM platform needs special work in a few cases. First of all, we need the actual address of some assembly functions, rather than the address of a wrapper. See http://gvisor.dev/pr/5832 for complete discussion of this. More relevant to this CL is that ABI0-to-ABIInternal wrappers (i.e., calls from assembly to Go) access the G via FS_BASE. The KVM quite fast-and-loose about the Go environment, often calling into (nosplit) Go functions with uninitialized FS_BASE. That will no longer work in Go 1.17, so this CL changes the platform to consistently restore FS_BASE before calling into Go code. This CL does not affect arm64 code. Go 1.17 does not support the register-based calling convention for arm64 (it will come in 1.18), but arm64 also does not use a non-standard register like FS_BASE for TLS, so it may not require any changes. PiperOrigin-RevId: 384234305
Diffstat (limited to 'pkg/sentry/platform/kvm/testutil')
-rw-r--r--pkg/sentry/platform/kvm/testutil/testutil.go42
-rw-r--r--pkg/sentry/platform/kvm/testutil/testutil_amd64.go10
-rw-r--r--pkg/sentry/platform/kvm/testutil/testutil_amd64.s57
3 files changed, 83 insertions, 26 deletions
diff --git a/pkg/sentry/platform/kvm/testutil/testutil.go b/pkg/sentry/platform/kvm/testutil/testutil.go
index 5c1efa0fd..d8c273796 100644
--- a/pkg/sentry/platform/kvm/testutil/testutil.go
+++ b/pkg/sentry/platform/kvm/testutil/testutil.go
@@ -23,23 +23,41 @@ import (
// Getpid executes a trivial system call.
func Getpid()
-// Touch touches the value in the first register.
-func Touch()
+// AddrOfGetpid returns the address of Getpid.
+//
+// In Go 1.17+, Go references to assembly functions resolve to an ABIInternal
+// wrapper function rather than the function itself. We must reference from
+// assembly to get the ABI0 (i.e., primary) address.
+func AddrOfGetpid() uintptr
+
+// AddrOfTouch returns the address of a function that touches the value in the
+// first register.
+func AddrOfTouch() uintptr
+func touch()
-// SyscallLoop executes a syscall and loops.
-func SyscallLoop()
+// AddrOfSyscallLoop returns the address of a function that executes a syscall
+// and loops.
+func AddrOfSyscallLoop() uintptr
+func syscallLoop()
-// SpinLoop spins on the CPU.
-func SpinLoop()
+// AddrOfSpinLoop returns the address of a function that spins on the CPU.
+func AddrOfSpinLoop() uintptr
+func spinLoop()
-// HaltLoop immediately halts and loops.
-func HaltLoop()
+// AddrOfHaltLoop returns the address of a function that immediately halts and
+// loops.
+func AddrOfHaltLoop() uintptr
+func haltLoop()
-// TwiddleRegsFault twiddles registers then faults.
-func TwiddleRegsFault()
+// AddrOfTwiddleRegsFault returns the address of a function that twiddles
+// registers then faults.
+func AddrOfTwiddleRegsFault() uintptr
+func twiddleRegsFault()
-// TwiddleRegsSyscall twiddles registers then executes a syscall.
-func TwiddleRegsSyscall()
+// AddrOfTwiddleRegsSyscall returns the address of a function that twiddles
+// registers then executes a syscall.
+func AddrOfTwiddleRegsSyscall() uintptr
+func twiddleRegsSyscall()
// FloatingPointWorks is a floating point test.
//
diff --git a/pkg/sentry/platform/kvm/testutil/testutil_amd64.go b/pkg/sentry/platform/kvm/testutil/testutil_amd64.go
index 8048eedec..7c19b6a8f 100644
--- a/pkg/sentry/platform/kvm/testutil/testutil_amd64.go
+++ b/pkg/sentry/platform/kvm/testutil/testutil_amd64.go
@@ -22,12 +22,14 @@ import (
"gvisor.dev/gvisor/pkg/sentry/arch"
)
-// TwiddleSegments reads segments into known registers.
-func TwiddleSegments()
+// AddrOfTwiddleSegments return the address of a function that reads segments
+// into known registers.
+func AddrOfTwiddleSegments() uintptr
+func twiddleSegments()
// SetTestTarget sets the rip appropriately.
-func SetTestTarget(regs *arch.Registers, fn func()) {
- regs.Rip = uint64(reflect.ValueOf(fn).Pointer())
+func SetTestTarget(regs *arch.Registers, fn uintptr) {
+ regs.Rip = uint64(fn)
}
// SetTouchTarget sets rax appropriately.
diff --git a/pkg/sentry/platform/kvm/testutil/testutil_amd64.s b/pkg/sentry/platform/kvm/testutil/testutil_amd64.s
index 491ec0c2a..65e7c05ea 100644
--- a/pkg/sentry/platform/kvm/testutil/testutil_amd64.s
+++ b/pkg/sentry/platform/kvm/testutil/testutil_amd64.s
@@ -25,27 +25,46 @@ TEXT ·Getpid(SB),NOSPLIT,$0
SYSCALL
RET
-TEXT ·Touch(SB),NOSPLIT,$0
+// func AddrOfGetpid() uintptr
+TEXT ·AddrOfGetpid(SB), $0-8
+ MOVQ $·Getpid(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+TEXT ·touch(SB),NOSPLIT,$0
start:
MOVQ 0(AX), BX // deref AX
MOVQ $39, AX // getpid
SYSCALL
JMP start
-TEXT ·HaltLoop(SB),NOSPLIT,$0
-start:
- HLT
- JMP start
+// func AddrOfTouch() uintptr
+TEXT ·AddrOfTouch(SB), $0-8
+ MOVQ $·touch(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
-TEXT ·SyscallLoop(SB),NOSPLIT,$0
+TEXT ·syscallLoop(SB),NOSPLIT,$0
start:
SYSCALL
JMP start
-TEXT ·SpinLoop(SB),NOSPLIT,$0
+// func AddrOfSyscallLoop() uintptr
+TEXT ·AddrOfSyscallLoop(SB), $0-8
+ MOVQ $·syscallLoop(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+TEXT ·spinLoop(SB),NOSPLIT,$0
start:
JMP start
+// func AddrOfSpinLoop() uintptr
+TEXT ·AddrOfSpinLoop(SB), $0-8
+ MOVQ $·spinLoop(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
TEXT ·FloatingPointWorks(SB),NOSPLIT,$0-8
NO_LOCAL_POINTERS
MOVQ $1, AX
@@ -75,20 +94,32 @@ TEXT ·FloatingPointWorks(SB),NOSPLIT,$0-8
NOTQ DI; \
NOTQ SP;
-TEXT ·TwiddleRegsSyscall(SB),NOSPLIT,$0
+TEXT ·twiddleRegsSyscall(SB),NOSPLIT,$0
TWIDDLE_REGS()
SYSCALL
RET // never reached
-TEXT ·TwiddleRegsFault(SB),NOSPLIT,$0
+// func AddrOfTwiddleRegsSyscall() uintptr
+TEXT ·AddrOfTwiddleRegsSyscall(SB), $0-8
+ MOVQ $·twiddleRegsSyscall(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
+TEXT ·twiddleRegsFault(SB),NOSPLIT,$0
TWIDDLE_REGS()
JMP AX // must fault
RET // never reached
+// func AddrOfTwiddleRegsFault() uintptr
+TEXT ·AddrOfTwiddleRegsFault(SB), $0-8
+ MOVQ $·twiddleRegsFault(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET
+
#define READ_FS() BYTE $0x64; BYTE $0x48; BYTE $0x8b; BYTE $0x00;
#define READ_GS() BYTE $0x65; BYTE $0x48; BYTE $0x8b; BYTE $0x00;
-TEXT ·TwiddleSegments(SB),NOSPLIT,$0
+TEXT ·twiddleSegments(SB),NOSPLIT,$0
MOVQ $0x0, AX
READ_GS()
MOVQ AX, BX
@@ -96,3 +127,9 @@ TEXT ·TwiddleSegments(SB),NOSPLIT,$0
READ_FS()
SYSCALL
RET // never reached
+
+// func AddrOfTwiddleSegments() uintptr
+TEXT ·AddrOfTwiddleSegments(SB), $0-8
+ MOVQ $·twiddleSegments(SB), AX
+ MOVQ AX, ret+0(FP)
+ RET