aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/mkpreempt.go65
-rw-r--r--src/runtime/preempt_386.s4
-rw-r--r--src/runtime/preempt_arm.s79
-rw-r--r--src/runtime/signal_arm.go14
-rw-r--r--src/runtime/traceback.go5
5 files changed, 151 insertions, 16 deletions
diff --git a/src/runtime/mkpreempt.go b/src/runtime/mkpreempt.go
index c28f89581d..78b1707f1b 100644
--- a/src/runtime/mkpreempt.go
+++ b/src/runtime/mkpreempt.go
@@ -78,7 +78,7 @@ var out io.Writer
var arches = map[string]func(){
"386": gen386,
"amd64": genAMD64,
- "arm": notImplemented,
+ "arm": genARM,
"arm64": notImplemented,
"mips64x": notImplemented,
"mipsx": notImplemented,
@@ -133,9 +133,14 @@ func p(f string, args ...interface{}) {
fmt.Fprintf(out, "\t%s\n", strings.Replace(fmted, "\n", "\n\t", -1))
}
+func label(l string) {
+ fmt.Fprintf(out, "%s\n", l)
+}
+
type layout struct {
stack int
regs []regPos
+ sp string // stack pointer register
}
type regPos struct {
@@ -165,7 +170,7 @@ func (l *layout) save() {
if reg.save != "" {
p(reg.save, reg.pos)
} else {
- p("%s %s, %d(SP)", reg.op, reg.reg, reg.pos)
+ p("%s %s, %d(%s)", reg.op, reg.reg, reg.pos, l.sp)
}
}
}
@@ -176,7 +181,7 @@ func (l *layout) restore() {
if reg.restore != "" {
p(reg.restore, reg.pos)
} else {
- p("%s %d(SP), %s", reg.op, reg.pos, reg.reg)
+ p("%s %d(%s), %s", reg.op, reg.pos, l.sp, reg.reg)
}
}
}
@@ -185,7 +190,7 @@ func gen386() {
p("PUSHFL")
// Save general purpose registers.
- var l layout
+ var l = layout{sp: "SP"}
for _, reg := range regNames386 {
if reg == "SP" || strings.HasPrefix(reg, "X") {
continue
@@ -200,7 +205,7 @@ func gen386() {
108)
// Save SSE state only if supported.
- lSSE := layout{stack: l.stack}
+ lSSE := layout{stack: l.stack, sp: "SP"}
for i := 0; i < 8; i++ {
lSSE.add("MOVUPS", fmt.Sprintf("X%d", i), 16)
}
@@ -210,11 +215,11 @@ func gen386() {
l.save()
p("CMPB internal∕cpu·X86+const_offsetX86HasSSE2(SB), $1\nJNE nosse")
lSSE.save()
- p("nosse:")
+ label("nosse:")
p("CALL ·asyncPreempt2(SB)")
p("CMPB internal∕cpu·X86+const_offsetX86HasSSE2(SB), $1\nJNE nosse2")
lSSE.restore()
- p("nosse2:")
+ label("nosse2:")
l.restore()
p("ADJSP $%d", -lSSE.stack)
@@ -224,7 +229,7 @@ func gen386() {
func genAMD64() {
// Assign stack offsets.
- var l layout
+ var l = layout{sp: "SP"}
for _, reg := range regNamesAMD64 {
if reg == "SP" || reg == "BP" {
continue
@@ -255,6 +260,50 @@ func genAMD64() {
p("RET")
}
+func genARM() {
+ // Add integer registers R0-R12.
+ // R13 (SP), R14 (LR), R15 (PC) are special and not saved here.
+ var l = layout{sp: "R13", stack: 4} // add LR slot
+ for i := 0; i <= 12; i++ {
+ reg := fmt.Sprintf("R%d", i)
+ if i == 10 {
+ continue // R10 is g register, no need to save/restore
+ }
+ l.add("MOVW", reg, 4)
+ }
+ // Add flag register.
+ l.addSpecial(
+ "MOVW CPSR, R0\nMOVW R0, %d(R13)",
+ "MOVW %d(R13), R0\nMOVW R0, CPSR",
+ 4)
+
+ // Add floating point registers F0-F15 and flag register.
+ var lfp = layout{stack: l.stack, sp: "R13"}
+ lfp.addSpecial(
+ "MOVW FPCR, R0\nMOVW R0, %d(R13)",
+ "MOVW %d(R13), R0\nMOVW R0, FPCR",
+ 4)
+ for i := 0; i <= 15; i++ {
+ reg := fmt.Sprintf("F%d", i)
+ lfp.add("MOVD", reg, 8)
+ }
+
+ p("MOVW.W R14, -%d(R13)", lfp.stack) // allocate frame, save LR
+ l.save()
+ p("MOVB ·goarm(SB), R0\nCMP $6, R0\nBLT nofp") // test goarm, and skip FP registers if goarm=5.
+ lfp.save()
+ label("nofp:")
+ p("CALL ·asyncPreempt2(SB)")
+ p("MOVB ·goarm(SB), R0\nCMP $6, R0\nBLT nofp2") // test goarm, and skip FP registers if goarm=5.
+ lfp.restore()
+ label("nofp2:")
+ l.restore()
+
+ p("MOVW %d(R13), R14", lfp.stack) // sigctxt.pushCall pushes LR on stack, restore it
+ p("MOVW.P %d(R13), R15", lfp.stack+4) // load PC, pop frame (including the space pushed by sigctxt.pushCall)
+ p("UNDEF") // shouldn't get here
+}
+
func genWasm() {
p("// No async preemption on wasm")
p("UNDEF")
diff --git a/src/runtime/preempt_386.s b/src/runtime/preempt_386.s
index a7961e02ce..a00ac8f385 100644
--- a/src/runtime/preempt_386.s
+++ b/src/runtime/preempt_386.s
@@ -26,7 +26,7 @@ TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0
MOVUPS X5, 216(SP)
MOVUPS X6, 232(SP)
MOVUPS X7, 248(SP)
- nosse:
+nosse:
CALL ·asyncPreempt2(SB)
CMPB internal∕cpu·X86+const_offsetX86HasSSE2(SB), $1
JNE nosse2
@@ -38,7 +38,7 @@ TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0
MOVUPS 168(SP), X2
MOVUPS 152(SP), X1
MOVUPS 136(SP), X0
- nosse2:
+nosse2:
FRSTOR 28(SP)
MOVL 24(SP), DI
MOVL 20(SP), SI
diff --git a/src/runtime/preempt_arm.s b/src/runtime/preempt_arm.s
index 5697268ce1..8f243c0dcd 100644
--- a/src/runtime/preempt_arm.s
+++ b/src/runtime/preempt_arm.s
@@ -4,5 +4,80 @@
#include "textflag.h"
TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0
- // Not implemented yet
- JMP ·abort(SB)
+ MOVW.W R14, -188(R13)
+ MOVW R0, 4(R13)
+ MOVW R1, 8(R13)
+ MOVW R2, 12(R13)
+ MOVW R3, 16(R13)
+ MOVW R4, 20(R13)
+ MOVW R5, 24(R13)
+ MOVW R6, 28(R13)
+ MOVW R7, 32(R13)
+ MOVW R8, 36(R13)
+ MOVW R9, 40(R13)
+ MOVW R11, 44(R13)
+ MOVW R12, 48(R13)
+ MOVW CPSR, R0
+ MOVW R0, 52(R13)
+ MOVB ·goarm(SB), R0
+ CMP $6, R0
+ BLT nofp
+ MOVW FPCR, R0
+ MOVW R0, 56(R13)
+ MOVD F0, 60(R13)
+ MOVD F1, 68(R13)
+ MOVD F2, 76(R13)
+ MOVD F3, 84(R13)
+ MOVD F4, 92(R13)
+ MOVD F5, 100(R13)
+ MOVD F6, 108(R13)
+ MOVD F7, 116(R13)
+ MOVD F8, 124(R13)
+ MOVD F9, 132(R13)
+ MOVD F10, 140(R13)
+ MOVD F11, 148(R13)
+ MOVD F12, 156(R13)
+ MOVD F13, 164(R13)
+ MOVD F14, 172(R13)
+ MOVD F15, 180(R13)
+nofp:
+ CALL ·asyncPreempt2(SB)
+ MOVB ·goarm(SB), R0
+ CMP $6, R0
+ BLT nofp2
+ MOVD 180(R13), F15
+ MOVD 172(R13), F14
+ MOVD 164(R13), F13
+ MOVD 156(R13), F12
+ MOVD 148(R13), F11
+ MOVD 140(R13), F10
+ MOVD 132(R13), F9
+ MOVD 124(R13), F8
+ MOVD 116(R13), F7
+ MOVD 108(R13), F6
+ MOVD 100(R13), F5
+ MOVD 92(R13), F4
+ MOVD 84(R13), F3
+ MOVD 76(R13), F2
+ MOVD 68(R13), F1
+ MOVD 60(R13), F0
+ MOVW 56(R13), R0
+ MOVW R0, FPCR
+nofp2:
+ MOVW 52(R13), R0
+ MOVW R0, CPSR
+ MOVW 48(R13), R12
+ MOVW 44(R13), R11
+ MOVW 40(R13), R9
+ MOVW 36(R13), R8
+ MOVW 32(R13), R7
+ MOVW 28(R13), R6
+ MOVW 24(R13), R5
+ MOVW 20(R13), R4
+ MOVW 16(R13), R3
+ MOVW 12(R13), R2
+ MOVW 8(R13), R1
+ MOVW 4(R13), R0
+ MOVW 188(R13), R14
+ MOVW.P 192(R13), R15
+ UNDEF
diff --git a/src/runtime/signal_arm.go b/src/runtime/signal_arm.go
index 1b3e53d01c..ff952b8b60 100644
--- a/src/runtime/signal_arm.go
+++ b/src/runtime/signal_arm.go
@@ -63,8 +63,18 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
c.set_pc(uint32(funcPC(sigpanic)))
}
-const pushCallSupported = false
+const pushCallSupported = true
func (c *sigctxt) pushCall(targetPC uintptr) {
- throw("not implemented")
+ // Push the LR to stack, as we'll clobber it in order to
+ // push the call. The function being pushed is responsible
+ // for restoring the LR and setting the SP back.
+ // This extra slot is known to gentraceback.
+ sp := c.sp() - 4
+ c.set_sp(sp)
+ *(*uint32)(unsafe.Pointer(uintptr(sp))) = c.lr()
+ // Set up PC and LR to pretend the function being signaled
+ // calls targetPC at the faulting PC.
+ c.set_lr(c.pc())
+ c.set_pc(uint32(targetPC))
}
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 9be7d739d1..dc2a7a3693 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -462,6 +462,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
}
waspanic = f.funcID == funcID_sigpanic
+ injectedCall := waspanic || f.funcID == funcID_asyncPreempt
// Do not unwind past the bottom of the stack.
if !flr.valid() {
@@ -477,8 +478,8 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
frame.argmap = nil
// On link register architectures, sighandler saves the LR on stack
- // before faking a call to sigpanic.
- if usesLR && waspanic {
+ // before faking a call.
+ if usesLR && injectedCall {
x := *(*uintptr)(unsafe.Pointer(frame.sp))
frame.sp += sys.MinFrameSize
if GOARCH == "arm64" {