mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
kvm-tls-2:add the preservation of user-TLS in the Arm64 kvm platform
This patch load/save TLS for the container application. Related issue: full context-switch supporting for Arm64 #1238 COPYBARA_INTEGRATE_REVIEW=https://github.com/google/gvisor/pull/2761 from lubinszARM:pr_tls_2 cb5dbca1c9c3f378002406da7a58887f9b5032b3 PiperOrigin-RevId: 322887044
This commit is contained in:
@@ -28,7 +28,14 @@ import (
|
||||
)
|
||||
|
||||
// Registers represents the CPU registers for this architecture.
|
||||
type Registers = linux.PtraceRegs
|
||||
//
|
||||
// +stateify savable
|
||||
type Registers struct {
|
||||
linux.PtraceRegs
|
||||
|
||||
// TPIDR_EL0 is the EL0 Read/Write Software Thread ID Register.
|
||||
TPIDR_EL0 uint64
|
||||
}
|
||||
|
||||
const (
|
||||
// SyscallWidth is the width of insturctions.
|
||||
@@ -101,9 +108,6 @@ type State struct {
|
||||
// Our floating point state.
|
||||
aarch64FPState `state:"wait"`
|
||||
|
||||
// TLS pointer
|
||||
TPValue uint64
|
||||
|
||||
// FeatureSet is a pointer to the currently active feature set.
|
||||
FeatureSet *cpuid.FeatureSet
|
||||
|
||||
@@ -157,7 +161,6 @@ func (s *State) Fork() State {
|
||||
return State{
|
||||
Regs: s.Regs,
|
||||
aarch64FPState: s.aarch64FPState.fork(),
|
||||
TPValue: s.TPValue,
|
||||
FeatureSet: s.FeatureSet,
|
||||
OrigR0: s.OrigR0,
|
||||
}
|
||||
@@ -241,18 +244,18 @@ func (s *State) ptraceGetRegs() Registers {
|
||||
return s.Regs
|
||||
}
|
||||
|
||||
var registersSize = (*Registers)(nil).SizeBytes()
|
||||
var ptraceRegistersSize = (*linux.PtraceRegs)(nil).SizeBytes()
|
||||
|
||||
// PtraceSetRegs implements Context.PtraceSetRegs.
|
||||
func (s *State) PtraceSetRegs(src io.Reader) (int, error) {
|
||||
var regs Registers
|
||||
buf := make([]byte, registersSize)
|
||||
buf := make([]byte, ptraceRegistersSize)
|
||||
if _, err := io.ReadFull(src, buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
regs.UnmarshalUnsafe(buf)
|
||||
s.Regs = regs
|
||||
return registersSize, nil
|
||||
return ptraceRegistersSize, nil
|
||||
}
|
||||
|
||||
// PtraceGetFPRegs implements Context.PtraceGetFPRegs.
|
||||
@@ -278,7 +281,7 @@ const (
|
||||
func (s *State) PtraceGetRegSet(regset uintptr, dst io.Writer, maxlen int) (int, error) {
|
||||
switch regset {
|
||||
case _NT_PRSTATUS:
|
||||
if maxlen < registersSize {
|
||||
if maxlen < ptraceRegistersSize {
|
||||
return 0, syserror.EFAULT
|
||||
}
|
||||
return s.PtraceGetRegs(dst)
|
||||
@@ -291,7 +294,7 @@ func (s *State) PtraceGetRegSet(regset uintptr, dst io.Writer, maxlen int) (int,
|
||||
func (s *State) PtraceSetRegSet(regset uintptr, src io.Reader, maxlen int) (int, error) {
|
||||
switch regset {
|
||||
case _NT_PRSTATUS:
|
||||
if maxlen < registersSize {
|
||||
if maxlen < ptraceRegistersSize {
|
||||
return 0, syserror.EFAULT
|
||||
}
|
||||
return s.PtraceSetRegs(src)
|
||||
|
||||
@@ -300,7 +300,7 @@ func (c *context64) PtracePeekUser(addr uintptr) (interface{}, error) {
|
||||
// PTRACE_PEEKUSER and PTRACE_POKEUSER are only effective on regs and
|
||||
// u_debugreg, returning 0 or silently no-oping for other fields
|
||||
// respectively.
|
||||
if addr < uintptr(registersSize) {
|
||||
if addr < uintptr(ptraceRegistersSize) {
|
||||
regs := c.ptraceGetRegs()
|
||||
buf := make([]byte, regs.SizeBytes())
|
||||
regs.MarshalUnsafe(buf)
|
||||
@@ -315,7 +315,7 @@ func (c *context64) PtracePokeUser(addr, data uintptr) error {
|
||||
if addr&7 != 0 || addr >= userStructSize {
|
||||
return syscall.EIO
|
||||
}
|
||||
if addr < uintptr(registersSize) {
|
||||
if addr < uintptr(ptraceRegistersSize) {
|
||||
regs := c.ptraceGetRegs()
|
||||
buf := make([]byte, regs.SizeBytes())
|
||||
regs.MarshalUnsafe(buf)
|
||||
|
||||
@@ -142,7 +142,7 @@ func (c *context64) SetStack(value uintptr) {
|
||||
|
||||
// TLS returns the current TLS pointer.
|
||||
func (c *context64) TLS() uintptr {
|
||||
return uintptr(c.TPValue)
|
||||
return uintptr(c.Regs.TPIDR_EL0)
|
||||
}
|
||||
|
||||
// SetTLS sets the current TLS pointer. Returns false if value is invalid.
|
||||
@@ -151,7 +151,7 @@ func (c *context64) SetTLS(value uintptr) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
c.TPValue = uint64(value)
|
||||
c.Regs.TPIDR_EL0 = uint64(value)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,11 @@ import (
|
||||
)
|
||||
|
||||
// Registers represents the CPU registers for this architecture.
|
||||
type Registers = linux.PtraceRegs
|
||||
//
|
||||
// +stateify savable
|
||||
type Registers struct {
|
||||
linux.PtraceRegs
|
||||
}
|
||||
|
||||
// System-related constants for x86.
|
||||
const (
|
||||
@@ -311,12 +315,12 @@ func (s *State) ptraceGetRegs() Registers {
|
||||
return regs
|
||||
}
|
||||
|
||||
var registersSize = (*Registers)(nil).SizeBytes()
|
||||
var ptraceRegistersSize = (*linux.PtraceRegs)(nil).SizeBytes()
|
||||
|
||||
// PtraceSetRegs implements Context.PtraceSetRegs.
|
||||
func (s *State) PtraceSetRegs(src io.Reader) (int, error) {
|
||||
var regs Registers
|
||||
buf := make([]byte, registersSize)
|
||||
buf := make([]byte, ptraceRegistersSize)
|
||||
if _, err := io.ReadFull(src, buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -374,7 +378,7 @@ func (s *State) PtraceSetRegs(src io.Reader) (int, error) {
|
||||
}
|
||||
regs.Eflags = (s.Regs.Eflags &^ eflagsPtraceMutable) | (regs.Eflags & eflagsPtraceMutable)
|
||||
s.Regs = regs
|
||||
return registersSize, nil
|
||||
return ptraceRegistersSize, nil
|
||||
}
|
||||
|
||||
// isUserSegmentSelector returns true if the given segment selector specifies a
|
||||
@@ -543,7 +547,7 @@ const (
|
||||
func (s *State) PtraceGetRegSet(regset uintptr, dst io.Writer, maxlen int) (int, error) {
|
||||
switch regset {
|
||||
case _NT_PRSTATUS:
|
||||
if maxlen < registersSize {
|
||||
if maxlen < ptraceRegistersSize {
|
||||
return 0, syserror.EFAULT
|
||||
}
|
||||
return s.PtraceGetRegs(dst)
|
||||
@@ -563,7 +567,7 @@ func (s *State) PtraceGetRegSet(regset uintptr, dst io.Writer, maxlen int) (int,
|
||||
func (s *State) PtraceSetRegSet(regset uintptr, src io.Reader, maxlen int) (int, error) {
|
||||
switch regset {
|
||||
case _NT_PRSTATUS:
|
||||
if maxlen < registersSize {
|
||||
if maxlen < ptraceRegistersSize {
|
||||
return 0, syserror.EFAULT
|
||||
}
|
||||
return s.PtraceSetRegs(src)
|
||||
|
||||
@@ -58,7 +58,13 @@ func (c *CPU) SwitchToUser(switchOpts SwitchOpts) (vector Vector) {
|
||||
|
||||
regs.Pstate &= ^uint64(UserFlagsClear)
|
||||
regs.Pstate |= UserFlagsSet
|
||||
|
||||
SetTLS(regs.TPIDR_EL0)
|
||||
|
||||
kernelExitToEl0()
|
||||
|
||||
regs.TPIDR_EL0 = GetTLS()
|
||||
|
||||
vector = c.vecCode
|
||||
|
||||
// Perform the switch.
|
||||
|
||||
Reference in New Issue
Block a user