Enable thread local storage support on arm64.
Linux use the task.thread.uw.tp_value field to store the TLS pointer on arm64 platform, and we use a similar way in gvisor to store it in the arch/State struct. Signed-off-by: Haibo Xu <haibo.xu@arm.com> Change-Id: Ie76b5c6d109bc27ccfd594008a96753806db7764
This commit is contained in:
parent
ddfc7239be
commit
c04958e2fa
|
@ -102,4 +102,7 @@ const (
|
|||
|
||||
// NT_X86_XSTATE is for x86 extended state using xsave.
|
||||
NT_X86_XSTATE = 0x202
|
||||
|
||||
// NT_ARM_TLS is for ARM TLS register.
|
||||
NT_ARM_TLS = 0x401
|
||||
)
|
||||
|
|
|
@ -95,6 +95,9 @@ 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
|
||||
}
|
||||
|
@ -145,6 +148,7 @@ func (s *State) Fork() State {
|
|||
return State{
|
||||
Regs: s.Regs,
|
||||
aarch64FPState: s.aarch64FPState.fork(),
|
||||
TPValue: s.TPValue,
|
||||
FeatureSet: s.FeatureSet,
|
||||
}
|
||||
}
|
||||
|
@ -255,6 +259,7 @@ func (s *State) PtraceSetFPRegs(src io.Reader) (int, error) {
|
|||
const (
|
||||
_NT_PRSTATUS = 1
|
||||
_NT_PRFPREG = 2
|
||||
_NT_ARM_TLS = 0x401
|
||||
)
|
||||
|
||||
// PtraceGetRegSet implements Context.PtraceGetRegSet.
|
||||
|
|
|
@ -140,16 +140,17 @@ func (c *context64) SetStack(value uintptr) {
|
|||
|
||||
// TLS returns the current TLS pointer.
|
||||
func (c *context64) TLS() uintptr {
|
||||
// TODO(gvisor.dev/issue/1238): TLS is not supported.
|
||||
// MRS_TPIDR_EL0
|
||||
return 0
|
||||
return uintptr(c.TPValue)
|
||||
}
|
||||
|
||||
// SetTLS sets the current TLS pointer. Returns false if value is invalid.
|
||||
func (c *context64) SetTLS(value uintptr) bool {
|
||||
// TODO(gvisor.dev/issue/1238): TLS is not supported.
|
||||
// MSR_TPIDR_EL0
|
||||
return false
|
||||
if value >= uintptr(maxAddr64) {
|
||||
return false
|
||||
}
|
||||
|
||||
c.TPValue = uint64(value)
|
||||
return true
|
||||
}
|
||||
|
||||
// SetOldRSeqInterruptedIP implements Context.SetOldRSeqInterruptedIP.
|
||||
|
|
|
@ -9,6 +9,7 @@ go_library(
|
|||
"ptrace.go",
|
||||
"ptrace_amd64.go",
|
||||
"ptrace_arm64.go",
|
||||
"ptrace_arm64_unsafe.go",
|
||||
"ptrace_unsafe.go",
|
||||
"stub_amd64.s",
|
||||
"stub_arm64.s",
|
||||
|
|
|
@ -31,3 +31,17 @@ func fpRegSet(useXsave bool) uintptr {
|
|||
func stackPointer(r *syscall.PtraceRegs) uintptr {
|
||||
return uintptr(r.Rsp)
|
||||
}
|
||||
|
||||
// x86 use the fs_base register to store the TLS pointer which can be
|
||||
// get/set in "func (t *thread) get/setRegs(regs *syscall.PtraceRegs)".
|
||||
// So both of the get/setTLS() operations are noop here.
|
||||
|
||||
// getTLS gets the thread local storage register.
|
||||
func (t *thread) getTLS(tls *uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// setTLS sets the thread local storage register.
|
||||
func (t *thread) setTLS(tls *uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2020 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build arm64
|
||||
|
||||
package ptrace
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
)
|
||||
|
||||
// getTLS gets the thread local storage register.
|
||||
func (t *thread) getTLS(tls *uint64) error {
|
||||
iovec := syscall.Iovec{
|
||||
Base: (*byte)(unsafe.Pointer(tls)),
|
||||
Len: uint64(unsafe.Sizeof(*tls)),
|
||||
}
|
||||
_, _, errno := syscall.RawSyscall6(
|
||||
syscall.SYS_PTRACE,
|
||||
syscall.PTRACE_GETREGSET,
|
||||
uintptr(t.tid),
|
||||
linux.NT_ARM_TLS,
|
||||
uintptr(unsafe.Pointer(&iovec)),
|
||||
0, 0)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setTLS sets the thread local storage register.
|
||||
func (t *thread) setTLS(tls *uint64) error {
|
||||
iovec := syscall.Iovec{
|
||||
Base: (*byte)(unsafe.Pointer(tls)),
|
||||
Len: uint64(unsafe.Sizeof(*tls)),
|
||||
}
|
||||
_, _, errno := syscall.RawSyscall6(
|
||||
syscall.SYS_PTRACE,
|
||||
syscall.PTRACE_SETREGSET,
|
||||
uintptr(t.tid),
|
||||
linux.NT_ARM_TLS,
|
||||
uintptr(unsafe.Pointer(&iovec)),
|
||||
0, 0)
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -506,6 +506,9 @@ func (s *subprocess) switchToApp(c *context, ac arch.Context) bool {
|
|||
regs := &ac.StateData().Regs
|
||||
t.resetSysemuRegs(regs)
|
||||
|
||||
// Extract TLS register
|
||||
tls := uint64(ac.TLS())
|
||||
|
||||
// Check for interrupts, and ensure that future interrupts will signal t.
|
||||
if !c.interrupt.Enable(t) {
|
||||
// Pending interrupt; simulate.
|
||||
|
@ -526,6 +529,9 @@ func (s *subprocess) switchToApp(c *context, ac arch.Context) bool {
|
|||
if err := t.setFPRegs(fpState, uint64(fpLen), useXsave); err != nil {
|
||||
panic(fmt.Sprintf("ptrace set fpregs (%+v) failed: %v", fpState, err))
|
||||
}
|
||||
if err := t.setTLS(&tls); err != nil {
|
||||
panic(fmt.Sprintf("ptrace set tls (%+v) failed: %v", tls, err))
|
||||
}
|
||||
|
||||
for {
|
||||
// Start running until the next system call.
|
||||
|
@ -555,6 +561,12 @@ func (s *subprocess) switchToApp(c *context, ac arch.Context) bool {
|
|||
if err := t.getFPRegs(fpState, uint64(fpLen), useXsave); err != nil {
|
||||
panic(fmt.Sprintf("ptrace get fpregs failed: %v", err))
|
||||
}
|
||||
if err := t.getTLS(&tls); err != nil {
|
||||
panic(fmt.Sprintf("ptrace get tls failed: %v", err))
|
||||
}
|
||||
if !ac.SetTLS(uintptr(tls)) {
|
||||
panic(fmt.Sprintf("tls value %v is invalid", tls))
|
||||
}
|
||||
|
||||
// Is it a system call?
|
||||
if sig == (syscallEvent | syscall.SIGTRAP) {
|
||||
|
|
Loading…
Reference in New Issue