summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/asm_arm.s
diff options
context:
space:
mode:
authorMichael Stapelberg <stapelberg@debian.org>2013-03-04 21:27:36 +0100
committerMichael Stapelberg <michael@stapelberg.de>2013-03-04 21:27:36 +0100
commit04b08da9af0c450d645ab7389d1467308cfc2db8 (patch)
treedb247935fa4f2f94408edc3acd5d0d4f997aa0d8 /src/pkg/runtime/asm_arm.s
parent917c5fb8ec48e22459d77e3849e6d388f93d3260 (diff)
downloadgolang-upstream/1.1_hg20130304.tar.gz
Imported Upstream version 1.1~hg20130304upstream/1.1_hg20130304
Diffstat (limited to 'src/pkg/runtime/asm_arm.s')
-rw-r--r--src/pkg/runtime/asm_arm.s265
1 files changed, 217 insertions, 48 deletions
diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s
index 423fda7a0..45b53541b 100644
--- a/src/pkg/runtime/asm_arm.s
+++ b/src/pkg/runtime/asm_arm.s
@@ -31,6 +31,13 @@ TEXT _rt0_arm(SB),7,$-4
MOVW R13, g_stackbase(g)
BL runtime·emptyfunc(SB) // fault if stack check is wrong
+ // if there is an _cgo_init, call it.
+ MOVW _cgo_init(SB), R2
+ CMP $0, R2
+ MOVW.NE g, R0 // first argument of _cgo_init is g
+ BL.NE (R2) // will clobber R0-R3
+
+ BL runtime·checkgoarm(SB)
BL runtime·check(SB)
// saved argc, argv
@@ -43,7 +50,7 @@ TEXT _rt0_arm(SB),7,$-4
BL runtime·schedinit(SB)
// create a new goroutine to start program
- MOVW $runtime·main(SB), R0
+ MOVW $runtime·main·f(SB), R0
MOVW.W R0, -4(R13)
MOVW $8, R0
MOVW.W R0, -4(R13)
@@ -58,24 +65,25 @@ TEXT _rt0_arm(SB),7,$-4
MOVW $1234, R0
MOVW $1000, R1
MOVW R0, (R1) // fail hard
- B runtime·_dep_dummy(SB) // Never reached
-
-// TODO(kaib): remove these once i actually understand how the linker removes symbols
-// pull in dummy dependencies
-TEXT runtime·_dep_dummy(SB),7,$0
- BL _div(SB)
- BL _divu(SB)
- BL _mod(SB)
- BL _modu(SB)
- BL _modu(SB)
- BL _sfloat(SB)
+
+DATA runtime·main·f+0(SB)/4,$runtime·main(SB)
+GLOBL runtime·main·f(SB),8,$4
TEXT runtime·breakpoint(SB),7,$0
- // no breakpoint yet; let program exit
+ // gdb won't skip this breakpoint instruction automatically,
+ // so you must manually "set $pc+=4" to skip it and continue.
+ WORD $0xe1200071 // BKPT 0x0001
RET
+GLOBL runtime·goarm(SB), $4
TEXT runtime·asminit(SB),7,$0
- // No per-thread init.
+ // disable runfast (flush-to-zero) mode of vfp if runtime.goarm > 5
+ MOVW runtime·goarm(SB), R11
+ CMP $5, R11
+ BLE 4(PC)
+ WORD $0xeef1ba10 // vmrs r11, fpscr
+ BIC $(1<<24), R11
+ WORD $0xeee1ba10 // vmsr fpscr, r11
RET
/*
@@ -95,26 +103,49 @@ TEXT runtime·gosave(SB), 7, $-4
// restore state from Gobuf; longjmp
TEXT runtime·gogo(SB), 7, $-4
MOVW 0(FP), R1 // gobuf
- MOVW 4(FP), R0 // return 2nd arg
MOVW gobuf_g(R1), g
MOVW 0(g), R2 // make sure g != nil
+ MOVW _cgo_save_gm(SB), R2
+ CMP $0, R2 // if in Cgo, we have to save g and m
+ BL.NE (R2) // this call will clobber R0
+ MOVW 4(FP), R0 // return 2nd arg
MOVW gobuf_sp(R1), SP // restore SP
MOVW gobuf_pc(R1), PC
-// void gogocall(Gobuf*, void (*fn)(void))
+// void gogocall(Gobuf*, void (*fn)(void), uintptr r7)
// restore state from Gobuf but then call fn.
// (call fn, returning to state in Gobuf)
// using frame size $-4 means do not save LR on stack.
TEXT runtime·gogocall(SB), 7, $-4
- MOVW 0(FP), R0 // gobuf
+ MOVW 0(FP), R3 // gobuf
MOVW 4(FP), R1 // fn
- MOVW 8(FP), R2 // fp offset
- MOVW gobuf_g(R0), g
- MOVW 0(g), R3 // make sure g != nil
- MOVW gobuf_sp(R0), SP // restore SP
- MOVW gobuf_pc(R0), LR
+ MOVW gobuf_g(R3), g
+ MOVW 0(g), R0 // make sure g != nil
+ MOVW _cgo_save_gm(SB), R0
+ CMP $0, R0 // if in Cgo, we have to save g and m
+ BL.NE (R0) // this call will clobber R0
+ MOVW 8(FP), R7 // context
+ MOVW gobuf_sp(R3), SP // restore SP
+ MOVW gobuf_pc(R3), LR
MOVW R1, PC
+// void gogocallfn(Gobuf*, FuncVal*)
+// restore state from Gobuf but then call fn.
+// (call fn, returning to state in Gobuf)
+// using frame size $-4 means do not save LR on stack.
+TEXT runtime·gogocallfn(SB), 7, $-4
+ MOVW 0(FP), R3 // gobuf
+ MOVW 4(FP), R1 // fn
+ MOVW gobuf_g(R3), g
+ MOVW 0(g), R0 // make sure g != nil
+ MOVW _cgo_save_gm(SB), R0
+ CMP $0, R0 // if in Cgo, we have to save g and m
+ BL.NE (R0) // this call will clobber R0
+ MOVW gobuf_sp(R3), SP // restore SP
+ MOVW gobuf_pc(R3), LR
+ MOVW R1, R7
+ MOVW 0(R1), PC
+
// void mcall(void (*fn)(G*))
// Switch to m->g0's stack, call fn(g).
// Fn must never return. It should gogo(&g->sched)
@@ -157,6 +188,7 @@ TEXT runtime·morestack(SB),7,$-4
BL.EQ runtime·abort(SB)
// Save in m.
+ MOVW R7, m_cret(m) // function context
MOVW R1, m_moreframesize(m)
MOVW R2, m_moreargsize(m)
@@ -228,28 +260,175 @@ TEXT runtime·lessstack(SB), 7, $-4
TEXT runtime·jmpdefer(SB), 7, $0
MOVW 0(SP), LR
MOVW $-4(LR), LR // BL deferreturn
- MOVW fn+0(FP), R0
+ MOVW fn+0(FP), R7
MOVW argp+4(FP), SP
MOVW $-4(SP), SP // SP is 4 below argp, due to saved LR
- B (R0)
+ MOVW 0(R7), R1
+ B (R1)
+
+// Dummy function to use in saved gobuf.PC,
+// to match SP pointing at a return address.
+// The gobuf.PC is unused by the contortions here
+// but setting it to return will make the traceback code work.
+TEXT return<>(SB),7,$0
+ RET
+// asmcgocall(void(*fn)(void*), void *arg)
+// Call fn(arg) on the scheduler stack,
+// aligned appropriately for the gcc ABI.
+// See cgocall.c for more details.
TEXT runtime·asmcgocall(SB),7,$0
- B runtime·cgounimpl(SB)
+ MOVW fn+0(FP), R1
+ MOVW arg+4(FP), R0
+ MOVW R13, R2
+ MOVW g, R5
+
+ // Figure out if we need to switch to m->g0 stack.
+ // We get called to create new OS threads too, and those
+ // come in on the m->g0 stack already.
+ MOVW m_g0(m), R3
+ CMP R3, g
+ BEQ 7(PC)
+ MOVW R13, (g_sched + gobuf_sp)(g)
+ MOVW $return<>(SB), R4
+ MOVW R4, (g_sched+gobuf_pc)(g)
+ MOVW g, (g_sched+gobuf_g)(g)
+ MOVW R3, g
+ MOVW (g_sched+gobuf_sp)(g), R13
+
+ // Now on a scheduling stack (a pthread-created stack).
+ SUB $24, R13
+ BIC $0x7, R13 // alignment for gcc ABI
+ MOVW R5, 20(R13) // save old g
+ MOVW R2, 16(R13) // save old SP
+ // R0 already contains the first argument
+ BL (R1)
+
+ // Restore registers, g, stack pointer.
+ MOVW 20(R13), g
+ MOVW 16(R13), R13
+ RET
-TEXT runtime·cgocallback(SB),7,$0
- B runtime·cgounimpl(SB)
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// Turn the fn into a Go func (by taking its address) and call
+// cgocallback_gofunc.
+TEXT runtime·cgocallback(SB),7,$12
+ MOVW $fn+0(FP), R0
+ MOVW R0, 4(R13)
+ MOVW frame+4(FP), R0
+ MOVW R0, 8(R13)
+ MOVW framesize+8(FP), R0
+ MOVW R0, 12(R13)
+ MOVW $runtime·cgocallback_gofunc(SB), R0
+ BL (R0)
+ RET
+
+// cgocallback_gofunc(void (*fn)(void*), void *frame, uintptr framesize)
+// See cgocall.c for more details.
+TEXT runtime·cgocallback_gofunc(SB),7,$16
+ // Load m and g from thread-local storage.
+ MOVW _cgo_load_gm(SB), R0
+ CMP $0, R0
+ BL.NE (R0)
+
+ // If m is nil, Go did not create the current thread.
+ // Call needm to obtain one for temporary use.
+ // In this case, we're running on the thread stack, so there's
+ // lots of space, but the linker doesn't know. Hide the call from
+ // the linker analysis by using an indirect call.
+ MOVW m, savedm-16(SP)
+ CMP $0, m
+ B.NE havem
+ MOVW $runtime·needm(SB), R0
+ BL (R0)
+
+havem:
+ // Now there's a valid m, and we're running on its m->g0.
+ // Save current m->g0->sched.sp on stack and then set it to SP.
+ // Save current sp in m->g0->sched.sp in preparation for
+ // switch back to m->curg stack.
+ MOVW fn+0(FP), R0
+ MOVW frame+4(FP), R1
+ MOVW framesize+8(FP), R2
+
+ MOVW m_g0(m), R3
+ MOVW (g_sched+gobuf_sp)(R3), R4
+ MOVW.W R4, -4(R13)
+ MOVW R13, (g_sched+gobuf_sp)(R3)
+
+ // Switch to m->curg stack and call runtime.cgocallbackg
+ // with the three arguments. Because we are taking over
+ // the execution of m->curg but *not* resuming what had
+ // been running, we need to save that information (m->curg->gobuf)
+ // so that we can restore it when we're done.
+ // We can restore m->curg->gobuf.sp easily, because calling
+ // runtime.cgocallbackg leaves SP unchanged upon return.
+ // To save m->curg->gobuf.pc, we push it onto the stack.
+ // This has the added benefit that it looks to the traceback
+ // routine like cgocallbackg is going to return to that
+ // PC (because we defined cgocallbackg to have
+ // a frame size of 16, the same amount that we use below),
+ // so that the traceback will seamlessly trace back into
+ // the earlier calls.
+
+ // Save current m->g0->sched.sp on stack and then set it to SP.
+ MOVW m_curg(m), g
+ MOVW (g_sched+gobuf_sp)(g), R4 // prepare stack as R4
+
+ // Push gobuf.pc
+ MOVW (g_sched+gobuf_pc)(g), R5
+ SUB $4, R4
+ MOVW R5, 0(R4)
+
+ // Push arguments to cgocallbackg.
+ // Frame size here must match the frame size above
+ // to trick traceback routines into doing the right thing.
+ SUB $16, R4
+ MOVW R0, 4(R4)
+ MOVW R1, 8(R4)
+ MOVW R2, 12(R4)
+
+ // Switch stack and make the call.
+ MOVW R4, R13
+ BL runtime·cgocallbackg(SB)
+
+ // Restore g->gobuf (== m->curg->gobuf) from saved values.
+ MOVW 16(R13), R5
+ MOVW R5, (g_sched+gobuf_pc)(g)
+ ADD $(16+4), R13 // SP clobbered! It is ok!
+ MOVW R13, (g_sched+gobuf_sp)(g)
+
+ // Switch back to m->g0's stack and restore m->g0->sched.sp.
+ // (Unlike m->curg, the g0 goroutine never uses sched.pc,
+ // so we do not have to restore it.)
+ MOVW m_g0(m), g
+ MOVW (g_sched+gobuf_sp)(g), R13
+ // POP R6
+ MOVW 0(R13), R6
+ ADD $4, R13
+ MOVW R6, (g_sched+gobuf_sp)(g)
+
+ // If the m on entry was nil, we called needm above to borrow an m
+ // for the duration of the call. Since the call is over, return it with dropm.
+ MOVW savedm-16(SP), R6
+ CMP $0, R6
+ B.NE 3(PC)
+ MOVW $runtime·dropm(SB), R0
+ BL (R0)
+
+ // Done!
+ RET
+
+// void setmg(M*, G*); set m and g. for use by needm.
+TEXT runtime·setmg(SB), 7, $-4
+ MOVW mm+0(FP), m
+ MOVW gg+4(FP), g
+
+ // Save m and g to thread-local storage.
+ MOVW _cgo_save_gm(SB), R0
+ CMP $0, R0
+ BL.NE (R0)
-TEXT runtime·memclr(SB),7,$20
- MOVW 0(FP), R0
- MOVW $0, R1 // c = 0
- MOVW R1, -16(SP)
- MOVW 4(FP), R1 // n
- MOVW R1, -12(SP)
- MOVW m, -8(SP) // Save m and g
- MOVW g, -4(SP)
- BL runtime·memset(SB)
- MOVW -8(SP), m // Restore m and g, memset clobbers them
- MOVW -4(SP), g
RET
TEXT runtime·getcallerpc(SB),7,$-4
@@ -269,16 +448,6 @@ TEXT runtime·getcallersp(SB),7,$-4
TEXT runtime·emptyfunc(SB),0,$0
RET
-// int64 runtime·cputicks(), so really
-// void runtime·cputicks(int64 *ticks)
-// stubbed: return int64(0)
-TEXT runtime·cputicks(SB),7,$0
- MOVW 0(FP), R1
- MOVW $0, R0
- MOVW R0, 0(R1)
- MOVW R0, 4(R1)
- RET
-
TEXT runtime·abort(SB),7,$-4
MOVW $0, R0
MOVW (R0), R1