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:
Haibo Xu 2020-01-13 07:44:58 +00:00
parent ddfc7239be
commit c04958e2fa
7 changed files with 104 additions and 6 deletions

View File

@ -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
)

View File

@ -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.

View File

@ -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.

View File

@ -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",

View File

@ -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
}

View File

@ -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
}

View File

@ -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) {