Elide WriteGS if the GS is already correct.

This caches the GS value in the ring0.CPU struct, in order to avoid a
full pipeline flush in the switch path.

Fixes #2010

Co-authored-by: Adin Scannell <adin@scannell.ca>
Co-authored-by: Lai Jiangshan <jiangshan.ljs@antfin.com>
PiperOrigin-RevId: 578919437
This commit is contained in:
Andrei Vagin
2023-11-02 11:21:42 -07:00
committed by gVisor bot
co-authored by Adin Scannell Lai Jiangshan
parent 8f9211abca
commit 9aca9a7429
3 changed files with 35 additions and 5 deletions
+3
View File
@@ -137,10 +137,13 @@ type CPUArchState struct {
*kernelEntry
appGsBase uint64
// Copies of global variables, stored in CPU so that they can be used by
// syscall and exception handlers (in the upper address space).
hasXSAVE bool
hasXSAVEOPT bool
hasFSGSBASE bool
}
// ErrorCode returns the last error code.
+31 -5
View File
@@ -16,16 +16,18 @@
#include "textflag.h"
// CPU offsets.
#define CPU_REGISTERS 64 // +checkoffset . CPU.registers
#define CPU_FPU_STATE 280 // +checkoffset . CPU.floatingPointState
#define CPU_REGISTERS 72 // +checkoffset . CPU.registers
#define CPU_FPU_STATE 288 // +checkoffset . CPU.floatingPointState
#define CPU_ARCH_STATE 16 // +checkoffset . CPU.CPUArchState
#define CPU_ERROR_CODE CPU_ARCH_STATE+0 // +checkoffset . CPUArchState.errorCode
#define CPU_ERROR_TYPE CPU_ARCH_STATE+8 // +checkoffset . CPUArchState.errorType
#define CPU_VECTOR CPU_ARCH_STATE+16 // +checkoffset . CPUArchState.vector
#define CPU_FAULT_ADDR CPU_ARCH_STATE+24 // +checkoffset . CPUArchState.faultAddr
#define CPU_ENTRY CPU_ARCH_STATE+32 // +checkoffset . CPUArchState.kernelEntry
#define CPU_HAS_XSAVE CPU_ARCH_STATE+40 // +checkoffset . CPUArchState.hasXSAVE
#define CPU_HAS_XSAVEOPT CPU_ARCH_STATE+41 // +checkoffset . CPUArchState.hasXSAVEOPT
#define CPU_APP_GS_BASE CPU_ARCH_STATE+40 // +checkoffset . CPUArchState.appGsBase
#define CPU_HAS_XSAVE CPU_ARCH_STATE+48 // +checkoffset . CPUArchState.hasXSAVE
#define CPU_HAS_XSAVEOPT CPU_ARCH_STATE+49 // +checkoffset . CPUArchState.hasXSAVEOPT
#define CPU_HAS_FSGSBASE CPU_ARCH_STATE+50 // +checkoffset . CPUArchState.hasFSGSBASE
#define ENTRY_SCRATCH0 256 // +checkoffset . kernelEntry.scratch0
#define ENTRY_STACK_TOP 264 // +checkoffset . kernelEntry.stackTop
@@ -240,10 +242,13 @@ fprestore_done:
MOVQ regs+8(FP), R8
SWAP_GS()
MOVQ PTRACE_GS_BASE(R8), AX
CMPQ AX, CPU_APP_GS_BASE(SI)
JE skip_gs
MOVQ AX, CPU_APP_GS_BASE(SI)
PUSHQ AX
CALL ·writeGS(SB)
POPQ AX
skip_gs:
// Call sysret() or iret().
MOVQ userCR3+24(FP), CX
MOVQ needIRET+32(FP), R9
@@ -411,6 +416,12 @@ TEXT ·start(SB),NOSPLIT|NOFRAME,$0
CALL ·writeFS(SB)
POPQ BX
MOVQ CPU_APP_GS_BASE(AX),BX
PUSHQ BX
CALL ·writeGS(SB)
POPQ BX
SWAP_GS()
// First argument (CPU) already at bottom of stack.
CALL ·startGo(SB) // Call Go hook.
JMP ·resume(SB) // Restore to registers.
@@ -439,6 +450,14 @@ user:
MOVQ CX, PTRACE_RAX(AX) // Save everything else.
MOVQ CX, PTRACE_ORIGRAX(AX)
CMPB CPU_HAS_FSGSBASE(GS), $1
JNE sysenter_skip_gs
SWAP_GS()
BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xae; BYTE $0xcb; // rdgsbase rbx
MOVQ BX, PTRACE_GS_BASE(AX)
SWAP_GS()
sysenter_skip_gs:
MOVQ ENTRY_CPU_SELF(GS), AX // Load vCPU.
MOVQ CPU_REGISTERS+PTRACE_RSP(AX), SP // Get stacks.
MOVQ $0, CPU_ERROR_CODE(AX) // Clear error code.
@@ -561,6 +580,13 @@ user:
POPQ BX // Restore original AX.
MOVQ BX, PTRACE_RAX(AX) // Save it.
MOVQ BX, PTRACE_ORIGRAX(AX)
CMPB CPU_HAS_FSGSBASE(GS), $1
JNE exception_skip_gs
SWAP_GS()
BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xae; BYTE $0xcb; // rdgsbase rbx
MOVQ BX, PTRACE_GS_BASE(AX)
SWAP_GS()
exception_skip_gs:
MOVQ 16(SP), BX; MOVQ BX, PTRACE_RIP(AX)
MOVQ 24(SP), CX; MOVQ CX, PTRACE_CS(AX)
MOVQ 32(SP), DX; MOVQ DX, PTRACE_FLAGS(AX)
+1
View File
@@ -144,6 +144,7 @@ func (c *CPU) init(cpuID int) {
c.hasXSAVE = hasXSAVE
c.hasXSAVEOPT = hasXSAVEOPT
c.hasFSGSBASE = hasFSGSBASE
}
// StackTop returns the kernel's stack address.