Commit d24ec86e authored by Jordan Rhee's avatar Jordan Rhee Committed by Ian Lance Taylor

runtime: support windows/arm

Updates #26148

Change-Id: I8f68b2c926c7b11dc86c9664ed7ff2d2f78b64b4
Reviewed-on: https://go-review.googlesource.com/128715
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 37db664c
......@@ -3,7 +3,6 @@
runtime/sys_windows_386.s: [386] profileloop: use of 4(SP) points beyond argument frame
runtime/sys_windows_386.s: [386] ctrlhandler: 4(SP) should be _type+0(FP)
runtime/sys_windows_386.s: [386] setldt: function setldt missing Go declaration
runtime/zcallback_windows.s: [386] callbackasm: function callbackasm missing Go declaration
runtime/sys_windows_386.s: [386] callbackasm1+0: function callbackasm1+0 missing Go declaration
runtime/sys_windows_386.s: [386] tstart: function tstart missing Go declaration
runtime/sys_windows_386.s: [386] tstart_stdcall: RET without writing to 4-byte ret+4(FP)
......
......@@ -6,4 +6,3 @@ runtime/sys_windows_amd64.s: [amd64] callbackasm1: function callbackasm1 missing
runtime/sys_windows_amd64.s: [amd64] tstart_stdcall: RET without writing to 4-byte ret+8(FP)
runtime/sys_windows_amd64.s: [amd64] settls: function settls missing Go declaration
runtime/sys_windows_amd64.s: [amd64] cannot check cross-package assembly function: now is in package time
runtime/zcallback_windows.s: [amd64] callbackasm: function callbackasm missing Go declaration
......@@ -784,6 +784,9 @@ TEXT setg<>(SB),NOSPLIT|NOFRAME,$0-0
MOVW R0, g
// Save g to thread-local storage.
#ifdef GOOS_windows
B runtime·save_g(SB)
#else
MOVB runtime·iscgo(SB), R0
CMP $0, R0
B.EQ 2(PC)
......@@ -791,6 +794,7 @@ TEXT setg<>(SB),NOSPLIT|NOFRAME,$0-0
MOVW g, R0
RET
#endif
TEXT runtime·emptyfunc(SB),0,$0-0
RET
......
......@@ -104,6 +104,9 @@ type context struct {
func (c *context) ip() uintptr { return uintptr(c.eip) }
func (c *context) sp() uintptr { return uintptr(c.esp) }
// 386 does not have link register, so this returns 0.
func (c *context) lr() uintptr { return 0 }
func (c *context) setip(x uintptr) { c.eip = uint32(x) }
func (c *context) setsp(x uintptr) { c.esp = uint32(x) }
......
......@@ -119,6 +119,9 @@ type context struct {
func (c *context) ip() uintptr { return uintptr(c.rip) }
func (c *context) sp() uintptr { return uintptr(c.rsp) }
// Amd64 does not have link register, so this returns 0.
func (c *context) lr() uintptr { return 0 }
func (c *context) setip(x uintptr) { c.rip = uint64(x) }
func (c *context) setsp(x uintptr) { c.rsp = uint64(x) }
......
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
const (
_PROT_NONE = 0
_PROT_READ = 1
_PROT_WRITE = 2
_PROT_EXEC = 4
_MAP_ANON = 1
_MAP_PRIVATE = 2
_DUPLICATE_SAME_ACCESS = 0x2
_THREAD_PRIORITY_HIGHEST = 0x2
_SIGINT = 0x2
_CTRL_C_EVENT = 0x0
_CTRL_BREAK_EVENT = 0x1
_CONTEXT_CONTROL = 0x10001
_CONTEXT_FULL = 0x10007
_EXCEPTION_ACCESS_VIOLATION = 0xc0000005
_EXCEPTION_BREAKPOINT = 0x80000003
_EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d
_EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e
_EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f
_EXCEPTION_FLT_OVERFLOW = 0xc0000091
_EXCEPTION_FLT_UNDERFLOW = 0xc0000093
_EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094
_EXCEPTION_INT_OVERFLOW = 0xc0000095
_INFINITE = 0xffffffff
_WAIT_TIMEOUT = 0x102
_EXCEPTION_CONTINUE_EXECUTION = -0x1
_EXCEPTION_CONTINUE_SEARCH = 0x0
)
type systeminfo struct {
anon0 [4]byte
dwpagesize uint32
lpminimumapplicationaddress *byte
lpmaximumapplicationaddress *byte
dwactiveprocessormask uint32
dwnumberofprocessors uint32
dwprocessortype uint32
dwallocationgranularity uint32
wprocessorlevel uint16
wprocessorrevision uint16
}
type exceptionrecord struct {
exceptioncode uint32
exceptionflags uint32
exceptionrecord *exceptionrecord
exceptionaddress *byte
numberparameters uint32
exceptioninformation [15]uint32
}
type neon128 struct {
low uint64
high int64
}
type context struct {
contextflags uint32
r0 uint32
r1 uint32
r2 uint32
r3 uint32
r4 uint32
r5 uint32
r6 uint32
r7 uint32
r8 uint32
r9 uint32
r10 uint32
r11 uint32
r12 uint32
spr uint32
lrr uint32
pc uint32
cpsr uint32
fpscr uint32
padding uint32
floatNeon [16]neon128
bvr [8]uint32
bcr [8]uint32
wvr [1]uint32
wcr [1]uint32
padding2 [2]uint32
}
func (c *context) ip() uintptr { return uintptr(c.pc) }
func (c *context) sp() uintptr { return uintptr(c.spr) }
func (c *context) lr() uintptr { return uintptr(c.lrr) }
func (c *context) setip(x uintptr) { c.pc = uint32(x) }
func (c *context) setsp(x uintptr) { c.spr = uint32(x) }
func dumpregs(r *context) {
print("r0 ", hex(r.r0), "\n")
print("r1 ", hex(r.r1), "\n")
print("r2 ", hex(r.r2), "\n")
print("r3 ", hex(r.r3), "\n")
print("r4 ", hex(r.r4), "\n")
print("r5 ", hex(r.r5), "\n")
print("r6 ", hex(r.r6), "\n")
print("r7 ", hex(r.r7), "\n")
print("r8 ", hex(r.r8), "\n")
print("r9 ", hex(r.r9), "\n")
print("r10 ", hex(r.r10), "\n")
print("r11 ", hex(r.r11), "\n")
print("r12 ", hex(r.r12), "\n")
print("sp ", hex(r.spr), "\n")
print("lr ", hex(r.lrr), "\n")
print("pc ", hex(r.pc), "\n")
print("cpsr ", hex(r.cpsr), "\n")
}
type overlapped struct {
internal uint32
internalhigh uint32
anon0 [8]byte
hevent *byte
}
type memoryBasicInformation struct {
baseAddress uintptr
allocationBase uintptr
allocationProtect uint32
regionSize uintptr
state uint32
protect uint32
type_ uint32
}
func stackcheck() {
// TODO: not implemented on ARM
}
......@@ -43,6 +43,7 @@ const (
//go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer%6 "kernel32.dll"
//go:cgo_import_dynamic runtime._SuspendThread SuspendThread%1 "kernel32.dll"
//go:cgo_import_dynamic runtime._SwitchToThread SwitchToThread%0 "kernel32.dll"
//go:cgo_import_dynamic runtime._TlsAlloc TlsAlloc%0 "kernel32.dll"
//go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc%4 "kernel32.dll"
//go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll"
//go:cgo_import_dynamic runtime._VirtualQuery VirtualQuery%3 "kernel32.dll"
......@@ -91,6 +92,7 @@ var (
_SetWaitableTimer,
_SuspendThread,
_SwitchToThread,
_TlsAlloc,
_VirtualAlloc,
_VirtualFree,
_VirtualQuery,
......@@ -860,14 +862,34 @@ func profilem(mp *m) {
var r *context
rbuf := make([]byte, unsafe.Sizeof(*r)+15)
tls := &mp.tls[0]
gp := *((**g)(unsafe.Pointer(tls)))
// align Context to 16 bytes
r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15))
r.contextflags = _CONTEXT_CONTROL
stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r)))
var gp *g
switch GOARCH {
default:
panic("unsupported architecture")
case "arm":
// TODO(jordanrh1): this is incorrect when Go is executing
// on the system or signal stacks because curg returns
// the current user g. The true g is stored in thread
// local storage, which we cannot access from another CPU.
// We cannot pull R10 from the thread context because
// it might be executing C code, in which case R10
// would not be g.
gp = mp.curg
case "386", "amd64":
tls := &mp.tls[0]
gp = *((**g)(unsafe.Pointer(tls)))
}
if gp == nil {
sigprofNonGoPC(r.ip())
} else {
sigprof(r.ip(), r.sp(), 0, gp, mp)
}
}
func profileloop1(param uintptr) uint32 {
......
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
//go:nosplit
func cputicks() int64 {
return nanotime()
}
func checkgoarm() {
if goarm < 7 {
print("Need atomic synchronization instructions, coprocessor ",
"access instructions. Recompile using GOARM=7.\n")
exit(1)
}
}
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go_asm.h"
#include "go_tls.h"
#include "textflag.h"
// This is the entry point for the program from the
// kernel for an ordinary -buildmode=exe program.
TEXT _rt0_arm_windows(SB),NOSPLIT|NOFRAME,$0
B ·rt0_go(SB)
......@@ -27,7 +27,7 @@ func lastcontinuetramp()
func initExceptionHandler() {
stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
if _AddVectoredContinueHandler == nil || unsafe.Sizeof(&_AddVectoredContinueHandler) == 4 {
if _AddVectoredContinueHandler == nil || GOARCH == "386" {
// use SetUnhandledExceptionFilter for windows-386 or
// if VectoredContinueHandler is unavailable.
// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
......@@ -177,9 +177,15 @@ func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
}
print("\n")
// TODO(jordanrh1): This may be needed for 386/AMD64 as well.
if GOARCH == "arm" {
_g_.m.throwing = 1
_g_.m.caughtsig.set(gp)
}
level, _, docrash := gotraceback()
if level > 0 {
tracebacktrap(r.ip(), r.sp(), 0, gp)
tracebacktrap(r.ip(), r.sp(), r.lr(), gp)
tracebackothers(gp)
dumpregs(r)
}
......
This diff is collapsed.
......@@ -25,18 +25,32 @@ func (c *wincallbackcontext) setCleanstack(cleanstack bool) {
var (
cbs callbacks
cbctxts **wincallbackcontext = &cbs.ctxt[0] // to simplify access to cbs.ctxt in sys_windows_*.s
callbackasm byte // type isn't really byte, it's code in runtime
)
func callbackasm()
// callbackasmAddr returns address of runtime.callbackasm
// function adjusted by i.
// runtime.callbackasm is just a series of CALL instructions
// (each is 5 bytes long), and we want callback to arrive at
// On x86 and amd64, runtime.callbackasm is a series of CALL instructions,
// and we want callback to arrive at
// correspondent call instruction instead of start of
// runtime.callbackasm.
// On ARM, runtime.callbackasm is a series of mov and branch instructions.
// R12 is loaded with the callback index. Each entry is two instructions,
// hence 8 bytes.
func callbackasmAddr(i int) uintptr {
return uintptr(add(unsafe.Pointer(&callbackasm), uintptr(i*5)))
var entrySize int
switch GOARCH {
default:
panic("unsupported architecture")
case "386", "amd64":
entrySize = 5
case "arm":
// On ARM, each entry is a MOV instruction
// followed by a branch instruction
entrySize = 8
}
return funcPC(callbackasm) + uintptr(i*entrySize)
}
//go:linkname compileCallback syscall.compileCallback
......
......@@ -23,6 +23,9 @@
#ifdef GOOS_darwin
#define TLSG_IS_VARIABLE
#endif
#ifdef GOOS_windows
#define TLSG_IS_VARIABLE
#endif
// save_g saves the g register into pthread-provided
// thread-local memory, so that we can call externally compiled
......@@ -35,6 +38,17 @@ TEXT runtime·save_g(SB),NOSPLIT|NOFRAME,$0
// nothing to do as nacl/arm does not use TLS at all.
MOVW g, R0 // preserve R0 across call to setg<>
RET
#else
#ifdef GOOS_windows
// Save the value in the _TEB->TlsSlots array.
// Effectively implements TlsSetValue().
MRC 15, 0, R0, C13, C0, 2
ADD $0xe10, R0
MOVW $runtime·tls_g(SB), R11
MOVW (R11), R11
MOVW g, R11<<2(R0)
MOVW g, R0 // preserve R0 accross call to setg<>
RET
#else
// If the host does not support MRC the linker will replace it with
// a call to runtime.read_tls_fallback which jumps to __kuser_get_tls.
......@@ -47,6 +61,7 @@ TEXT runtime·save_g(SB),NOSPLIT|NOFRAME,$0
MOVW g, R0 // preserve R0 across call to setg<>
RET
#endif
#endif
// load_g loads the g register from pthread-provided
// thread-local memory, for use after calling externally compiled
......@@ -55,6 +70,16 @@ TEXT runtime·load_g(SB),NOSPLIT,$0
#ifdef GOOS_nacl
// nothing to do as nacl/arm does not use TLS at all.
RET
#else
#ifdef GOOS_windows
// Get the value from the _TEB->TlsSlots array.
// Effectively implements TlsGetValue().
MRC 15, 0, R0, C13, C0, 2
ADD $0xe10, R0
MOVW $runtime·tls_g(SB), g
MOVW (g), g
MOVW g<<2(R0), g
RET
#else
// See save_g
MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer
......@@ -64,6 +89,7 @@ TEXT runtime·load_g(SB),NOSPLIT,$0
MOVW 0(R0), g
RET
#endif
#endif
// This is called from rt0_go, which runs on the system stack
// using the initial stack allocated by the OS.
......@@ -76,6 +102,20 @@ TEXT runtime·load_g(SB),NOSPLIT,$0
// Declare a dummy word ($4, not $0) to make sure the
// frame is 8 bytes and stays 8-byte-aligned.
TEXT runtime·_initcgo(SB),NOSPLIT,$4
#ifdef GOOS_windows
MOVW R13, R4
BIC $0x7, R13
MOVW $runtime·_TlsAlloc(SB), R0
MOVW (R0), R0
BL (R0)
// Assert that slot is less than 64 so we can use _TEB->TlsSlots
CMP $64, R0
MOVW $runtime·abort(SB), R1
BL.GE (R1)
MOVW $runtime·tls_g(SB), R1
MOVW R0, (R1)
MOVW R4, R13
#else
#ifndef GOOS_nacl
// if there is an _cgo_init, call it.
MOVW _cgo_init(SB), R4
......@@ -91,7 +131,8 @@ TEXT runtime·_initcgo(SB),NOSPLIT,$4
MOVW $setg_gcc<>(SB), R1 // arg 1: setg
MOVW g, R0 // arg 0: G
BL (R4) // will clobber R0-R3
#endif
#endif // GOOS_nacl
#endif // GOOS_windows
nocgo:
RET
......
......@@ -17,11 +17,12 @@ import (
const maxCallback = 2000
func genasm() {
func genasm386Amd64() {
var buf bytes.Buffer
buf.WriteString(`// generated by wincallback.go; run go generate
buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
// +build 386 amd64
// runtime·callbackasm is called by external code to
// execute Go implemented callback function. It is not
// called from the start, instead runtime·compilecallback
......@@ -29,13 +30,43 @@ func genasm() {
// appropriately so different callbacks start with different
// CALL instruction in runtime·callbackasm. This determines
// which Go callback function is executed later on.
TEXT runtime·callbackasm(SB),7,$0
`)
for i := 0; i < maxCallback; i++ {
buf.WriteString("\tCALL\truntime·callbackasm1(SB)\n")
}
err := ioutil.WriteFile("zcallback_windows.s", buf.Bytes(), 0666)
filename := fmt.Sprintf("zcallback_windows.s")
err := ioutil.WriteFile(filename, buf.Bytes(), 0666)
if err != nil {
fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
os.Exit(2)
}
}
func genasmArm() {
var buf bytes.Buffer
buf.WriteString(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
// External code calls into callbackasm at an offset corresponding
// to the callback index. Callbackasm is a table of MOV and B instructions.
// The MOV instruction loads R12 with the callback index, and the
// B instruction branches to callbackasm1.
// callbackasm1 takes the callback index from R12 and
// indexes into an array that stores information about each callback.
// It then calls the Go implementation for that callback.
#include "textflag.h"
TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0
`)
for i := 0; i < maxCallback; i++ {
buf.WriteString(fmt.Sprintf("\tMOVW\t$%d, R12\n", i))
buf.WriteString("\tB\truntime·callbackasm1(SB)\n")
}
err := ioutil.WriteFile("zcallback_windows_arm.s", buf.Bytes(), 0666)
if err != nil {
fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
os.Exit(2)
......@@ -45,7 +76,7 @@ TEXT runtime·callbackasm(SB),7,$0
func gengo() {
var buf bytes.Buffer
buf.WriteString(fmt.Sprintf(`// generated by wincallback.go; run go generate
buf.WriteString(fmt.Sprintf(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
package runtime
......@@ -59,6 +90,7 @@ const cb_max = %d // maximum number of windows callbacks allowed
}
func main() {
genasm()
genasm386Amd64()
genasmArm()
gengo()
}
// generated by wincallback.go; run go generate
// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
package runtime
......
// generated by wincallback.go; run go generate
// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
// +build 386 amd64
// runtime·callbackasm is called by external code to
// execute Go implemented callback function. It is not
// called from the start, instead runtime·compilecallback
......@@ -7,6 +8,7 @@
// appropriately so different callbacks start with different
// CALL instruction in runtime·callbackasm. This determines
// which Go callback function is executed later on.
TEXT runtime·callbackasm(SB),7,$0
CALL runtime·callbackasm1(SB)
CALL runtime·callbackasm1(SB)
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment