...

Text file src/pkg/runtime/sys_windows_arm.s

     1	// Copyright 2018 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	#include "go_asm.h"
     6	#include "go_tls.h"
     7	#include "textflag.h"
     8	
     9	// void runtime·asmstdcall(void *c);
    10	TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0
    11		MOVM.DB.W [R4, R5, R14], (R13)	// push {r4, r5, lr}
    12		MOVW	R0, R4			// put libcall * in r4
    13		MOVW	R13, R5			// save stack pointer in r5
    14	
    15		// SetLastError(0)
    16		MOVW	$0, R0
    17		MRC	15, 0, R1, C13, C0, 2
    18		MOVW	R0, 0x34(R1)
    19	
    20		MOVW	8(R4), R12	// libcall->args
    21	
    22		// Do we have more than 4 arguments?
    23		MOVW	4(R4), R0	// libcall->n
    24		SUB.S	$4, R0, R2
    25		BLE	loadregs
    26	
    27		// Reserve stack space for remaining args
    28		SUB	R2<<2, R13
    29		BIC	$0x7, R13	// alignment for ABI
    30	
    31		// R0: count of arguments
    32		// R1:
    33		// R2: loop counter, from 0 to (n-4)
    34		// R3: scratch
    35		// R4: pointer to libcall struct
    36		// R12: libcall->args
    37		MOVW	$0, R2
    38	stackargs:
    39		ADD	$4, R2, R3		// r3 = args[4 + i]
    40		MOVW	R3<<2(R12), R3
    41		MOVW	R3, R2<<2(R13)		// stack[i] = r3
    42	
    43		ADD	$1, R2			// i++
    44		SUB	$4, R0, R3		// while (i < (n - 4))
    45		CMP	R3, R2
    46		BLT	stackargs
    47	
    48	loadregs:
    49		CMP	$3, R0
    50		MOVW.GT 12(R12), R3
    51	
    52		CMP	$2, R0
    53		MOVW.GT 8(R12), R2
    54	
    55		CMP	$1, R0
    56		MOVW.GT 4(R12), R1
    57	
    58		CMP	$0, R0
    59		MOVW.GT 0(R12), R0
    60	
    61		BIC	$0x7, R13		// alignment for ABI
    62		MOVW	0(R4), R12		// branch to libcall->fn
    63		BL	(R12)
    64	
    65		MOVW	R5, R13			// free stack space
    66		MOVW	R0, 12(R4)		// save return value to libcall->r1
    67		MOVW	R1, 16(R4)
    68	
    69		// GetLastError
    70		MRC	15, 0, R1, C13, C0, 2
    71		MOVW	0x34(R1), R0
    72		MOVW	R0, 20(R4)		// store in libcall->err
    73	
    74		MOVM.IA.W (R13), [R4, R5, R15]
    75	
    76	TEXT runtime·badsignal2(SB),NOSPLIT|NOFRAME,$0
    77		MOVM.DB.W [R4, R14], (R13)	// push {r4, lr}
    78		MOVW	R13, R4			// save original stack pointer
    79		SUB	$8, R13			// space for 2 variables
    80		BIC	$0x7, R13		// alignment for ABI
    81	
    82		// stderr
    83		MOVW	runtime·_GetStdHandle(SB), R1
    84		MOVW	$-12, R0
    85		BL	(R1)
    86	
    87		MOVW	$runtime·badsignalmsg(SB), R1	// lpBuffer
    88		MOVW	$runtime·badsignallen(SB), R2	// lpNumberOfBytesToWrite
    89		MOVW	(R2), R2
    90		ADD	$0x4, R13, R3		// lpNumberOfBytesWritten
    91		MOVW	$0, R12			// lpOverlapped
    92		MOVW	R12, (R13)
    93	
    94		MOVW	runtime·_WriteFile(SB), R12
    95		BL	(R12)
    96	
    97		MOVW	R4, R13			// restore SP
    98		MOVM.IA.W (R13), [R4, R15]	// pop {r4, pc}
    99	
   100	TEXT runtime·getlasterror(SB),NOSPLIT,$0
   101		MRC	15, 0, R0, C13, C0, 2
   102		MOVW	0x34(R0), R0
   103		MOVW	R0, ret+0(FP)
   104		RET
   105	
   106	TEXT runtime·setlasterror(SB),NOSPLIT|NOFRAME,$0
   107		MRC	15, 0, R1, C13, C0, 2
   108		MOVW	R0, 0x34(R1)
   109		RET
   110	
   111	// Called by Windows as a Vectored Exception Handler (VEH).
   112	// First argument is pointer to struct containing
   113	// exception record and context pointers.
   114	// Handler function is stored in R1
   115	// Return 0 for 'not handled', -1 for handled.
   116	// int32_t sigtramp(
   117	//     PEXCEPTION_POINTERS ExceptionInfo,
   118	//     func *GoExceptionHandler);
   119	TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0
   120		MOVM.DB.W [R0, R4-R11, R14], (R13)	// push {r0, r4-r11, lr} (SP-=40)
   121		SUB	$(8+20), R13		// reserve space for g, sp, and
   122						// parameters/retval to go call
   123	
   124		MOVW	R0, R6			// Save param0
   125		MOVW	R1, R7			// Save param1
   126	
   127		BL      runtime·load_g(SB)
   128		CMP	$0, g			// is there a current g?
   129		BL.EQ	runtime·badsignal2(SB)
   130	
   131		// save g and SP in case of stack switch
   132		MOVW	R13, 24(R13)
   133		MOVW	g, 20(R13)
   134	
   135		// do we need to switch to the g0 stack?
   136		MOVW	g, R5			// R5 = g
   137		MOVW	g_m(R5), R2		// R2 = m
   138		MOVW	m_g0(R2), R4		// R4 = g0
   139		CMP	R5, R4			// if curg == g0
   140		BEQ	g0
   141	
   142		// switch to g0 stack
   143		MOVW	R4, g				// g = g0
   144		MOVW	(g_sched+gobuf_sp)(g), R3	// R3 = g->gobuf.sp
   145		BL      runtime·save_g(SB)
   146	
   147		// traceback will think that we've done PUSH and SUB
   148		// on this stack, so subtract them here to match.
   149		// (we need room for sighandler arguments anyway).
   150		// and re-save old SP for restoring later.
   151		SUB	$(40+8+20), R3
   152		MOVW	R13, 24(R3)		// save old stack pointer
   153		MOVW	R3, R13			// switch stack
   154	
   155	g0:
   156		MOVW	0(R6), R2	// R2 = ExceptionPointers->ExceptionRecord
   157		MOVW	4(R6), R3	// R3 = ExceptionPointers->ContextRecord
   158	
   159		// make it look like mstart called us on g0, to stop traceback
   160		MOVW    $runtime·mstart(SB), R4
   161	
   162		MOVW	R4, 0(R13)	// Save link register for traceback
   163		MOVW	R2, 4(R13)	// Move arg0 (ExceptionRecord) into position
   164		MOVW	R3, 8(R13)	// Move arg1 (ContextRecord) into position
   165		MOVW	R5, 12(R13)	// Move arg2 (original g) into position
   166		BL	(R7)		// Call the go routine
   167		MOVW	16(R13), R4	// Fetch return value from stack
   168	
   169		// Compute the value of the g0 stack pointer after deallocating
   170		// this frame, then allocating 8 bytes. We may need to store
   171		// the resume SP and PC on the g0 stack to work around
   172		// control flow guard when we resume from the exception.
   173		ADD	$(40+20), R13, R12
   174	
   175		// switch back to original stack and g
   176		MOVW	24(R13), R13
   177		MOVW	20(R13), g
   178		BL      runtime·save_g(SB)
   179	
   180	done:
   181		MOVW	R4, R0				// move retval into position
   182		ADD	$(8 + 20), R13			// free locals
   183		MOVM.IA.W (R13), [R3, R4-R11, R14]	// pop {r3, r4-r11, lr}
   184	
   185		// if return value is CONTINUE_SEARCH, do not set up control
   186		// flow guard workaround
   187		CMP	$0, R0
   188		BEQ	return
   189	
   190		// Check if we need to set up the control flow guard workaround.
   191		// On Windows/ARM, the stack pointer must lie within system
   192		// stack limits when we resume from exception.
   193		// Store the resume SP and PC on the g0 stack,
   194		// and return to returntramp on the g0 stack. returntramp
   195		// pops the saved PC and SP from the g0 stack, resuming execution
   196		// at the desired location.
   197		// If returntramp has already been set up by a previous exception
   198		// handler, don't clobber the stored SP and PC on the stack.
   199		MOVW	4(R3), R3			// PEXCEPTION_POINTERS->Context
   200		MOVW	0x40(R3), R2			// load PC from context record
   201		MOVW	$returntramp<>(SB), R1
   202		CMP	R1, R2
   203		B.EQ	return				// do not clobber saved SP/PC
   204	
   205		// Save resume SP and PC on g0 stack
   206		MOVW	0x38(R3), R2			// load SP from context record
   207		MOVW	R2, 0(R12)			// Store resume SP on g0 stack
   208		MOVW	0x40(R3), R2			// load PC from context record
   209		MOVW	R2, 4(R12)			// Store resume PC on g0 stack
   210	
   211		// Set up context record to return to returntramp on g0 stack
   212		MOVW	R12, 0x38(R3)			// save g0 stack pointer
   213							// in context record
   214		MOVW	$returntramp<>(SB), R2	// save resume address
   215		MOVW	R2, 0x40(R3)			// in context record
   216	
   217	return:
   218		B	(R14)				// return
   219	
   220	//
   221	// Trampoline to resume execution from exception handler.
   222	// This is part of the control flow guard workaround.
   223	// It switches stacks and jumps to the continuation address.
   224	//
   225	TEXT returntramp<>(SB),NOSPLIT|NOFRAME,$0
   226		MOVM.IA	(R13), [R13, R15]		// ldm sp, [sp, pc]
   227	
   228	TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0
   229		MOVW	$runtime·exceptionhandler(SB), R1
   230		B	sigtramp<>(SB)
   231	
   232	TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0
   233		MOVW	$runtime·firstcontinuehandler(SB), R1
   234		B	sigtramp<>(SB)
   235	
   236	TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0
   237		MOVW	$runtime·lastcontinuehandler(SB), R1
   238		B	sigtramp<>(SB)
   239	
   240	TEXT runtime·ctrlhandler(SB),NOSPLIT|NOFRAME,$0
   241		MOVW	$runtime·ctrlhandler1(SB), R1
   242		B	runtime·externalthreadhandler(SB)
   243	
   244	TEXT runtime·profileloop(SB),NOSPLIT|NOFRAME,$0
   245		MOVW	$runtime·profileloop1(SB), R1
   246		B	runtime·externalthreadhandler(SB)
   247	
   248	// int32 externalthreadhandler(uint32 arg, int (*func)(uint32))
   249	// stack layout:
   250	//   +----------------+
   251	//   | callee-save    |
   252	//   | registers      |
   253	//   +----------------+
   254	//   | m              |
   255	//   +----------------+
   256	// 20| g              |
   257	//   +----------------+
   258	// 16| func ptr (r1)  |
   259	//   +----------------+
   260	// 12| argument (r0)  |
   261	//---+----------------+
   262	// 8 | param1         |
   263	//   +----------------+
   264	// 4 | param0         |
   265	//   +----------------+
   266	// 0 | retval         |
   267	//   +----------------+
   268	//
   269	TEXT runtime·externalthreadhandler(SB),NOSPLIT|NOFRAME,$0
   270		MOVM.DB.W [R4-R11, R14], (R13)		// push {r4-r11, lr}
   271		SUB	$(m__size + g__size + 20), R13	// space for locals
   272		MOVW	R0, 12(R13)
   273		MOVW	R1, 16(R13)
   274	
   275		// zero out m and g structures
   276		ADD	$20, R13, R0			// compute pointer to g
   277		MOVW	R0, 4(R13)
   278		MOVW	$(m__size + g__size), R0
   279		MOVW	R0, 8(R13)
   280		BL	runtime·memclrNoHeapPointers(SB)
   281	
   282		// initialize m and g structures
   283		ADD	$20, R13, R2			// R2 = g
   284		ADD	$(20 + g__size), R13, R3	// R3 = m
   285		MOVW	R2, m_g0(R3)			// m->g0 = g
   286		MOVW	R3, g_m(R2)			// g->m = m
   287		MOVW	R2, m_curg(R3)			// m->curg = g
   288	
   289		MOVW	R2, g
   290		BL	runtime·save_g(SB)
   291	
   292		// set up stackguard stuff
   293		MOVW	R13, R0
   294		MOVW	R0, g_stack+stack_hi(g)
   295		SUB	$(32*1024), R0
   296		MOVW	R0, (g_stack+stack_lo)(g)
   297		MOVW	R0, g_stackguard0(g)
   298		MOVW	R0, g_stackguard1(g)
   299	
   300		// move argument into position and call function
   301		MOVW	12(R13), R0
   302		MOVW	R0, 4(R13)
   303		MOVW	16(R13), R1
   304		BL	(R1)
   305	
   306		// clear g
   307		MOVW	$0, g
   308		BL	runtime·save_g(SB)
   309	
   310		MOVW	0(R13), R0			// load return value
   311		ADD	$(m__size + g__size + 20), R13	// free locals
   312		MOVM.IA.W (R13), [R4-R11, R15]		// pop {r4-r11, pc}
   313	
   314	GLOBL runtime·cbctxts(SB), NOPTR, $4
   315	
   316	TEXT runtime·callbackasm1(SB),NOSPLIT|NOFRAME,$0
   317		MOVM.DB.W [R4-R11, R14], (R13)	// push {r4-r11, lr}
   318		SUB	$36, R13		// space for locals
   319	
   320		// save callback arguments to stack. We currently support up to 4 arguments
   321		ADD	$16, R13, R4
   322		MOVM.IA	[R0-R3], (R4)
   323	
   324		// load cbctxts[i]. The trampoline in zcallback_windows.s puts the callback
   325		// index in R12
   326		MOVW	runtime·cbctxts(SB), R4
   327		MOVW	R12<<2(R4), R4		// R4 holds pointer to wincallbackcontext structure
   328	
   329		// extract callback context
   330		MOVW	wincallbackcontext_argsize(R4), R5
   331		MOVW	wincallbackcontext_gobody(R4), R4
   332	
   333		// we currently support up to 4 arguments
   334		CMP	$(4 * 4), R5
   335		BL.GT	runtime·abort(SB)
   336	
   337		// extend argsize by size of return value
   338		ADD	$4, R5
   339	
   340		// Build 'type args struct'
   341		MOVW	R4, 4(R13)		// fn
   342		ADD	$16, R13, R0		// arg (points to r0-r3, ret on stack)
   343		MOVW	R0, 8(R13)
   344		MOVW	R5, 12(R13)		// argsize
   345	
   346		BL	runtime·load_g(SB)
   347		BL	runtime·cgocallback_gofunc(SB)
   348	
   349		ADD	$16, R13, R0		// load arg
   350		MOVW	12(R13), R1		// load argsize
   351		SUB	$4, R1			// offset to return value
   352		MOVW	R1<<0(R0), R0		// load return value
   353	
   354		ADD	$36, R13		// free locals
   355		MOVM.IA.W (R13), [R4-R11, R15]	// pop {r4-r11, pc}
   356	
   357	// uint32 tstart_stdcall(M *newm);
   358	TEXT runtime·tstart_stdcall(SB),NOSPLIT|NOFRAME,$0
   359		MOVM.DB.W [R4-R11, R14], (R13)		// push {r4-r11, lr}
   360	
   361		MOVW	m_g0(R0), g
   362		MOVW	R0, g_m(g)
   363		BL	runtime·save_g(SB)
   364	
   365		// do per-thread TLS initialization
   366		BL	init_thread_tls<>(SB)
   367	
   368		// Layout new m scheduler stack on os stack.
   369		MOVW	R13, R0
   370		MOVW	R0, g_stack+stack_hi(g)
   371		SUB	$(64*1024), R0
   372		MOVW	R0, (g_stack+stack_lo)(g)
   373		MOVW	R0, g_stackguard0(g)
   374		MOVW	R0, g_stackguard1(g)
   375	
   376		BL	runtime·emptyfunc(SB)	// fault if stack check is wrong
   377		BL	runtime·mstart(SB)
   378	
   379		// Exit the thread.
   380		MOVW	$0, R0
   381		MOVM.IA.W (R13), [R4-R11, R15]		// pop {r4-r11, pc}
   382	
   383	// onosstack calls fn on OS stack.
   384	// adapted from asm_arm.s : systemstack
   385	// func onosstack(fn unsafe.Pointer, arg uint32)
   386	TEXT runtime·onosstack(SB),NOSPLIT,$0
   387		MOVW	fn+0(FP), R5		// R5 = fn
   388		MOVW	arg+4(FP), R6		// R6 = arg
   389	
   390		// This function can be called when there is no g,
   391		// for example, when we are handling a callback on a non-go thread.
   392		// In this case we're already on the system stack.
   393		CMP	$0, g
   394		BEQ	noswitch
   395	
   396		MOVW	g_m(g), R1		// R1 = m
   397	
   398		MOVW	m_gsignal(R1), R2	// R2 = gsignal
   399		CMP	g, R2
   400		B.EQ	noswitch
   401	
   402		MOVW	m_g0(R1), R2		// R2 = g0
   403		CMP	g, R2
   404		B.EQ	noswitch
   405	
   406		MOVW	m_curg(R1), R3
   407		CMP	g, R3
   408		B.EQ	switch
   409	
   410		// Bad: g is not gsignal, not g0, not curg. What is it?
   411		// Hide call from linker nosplit analysis.
   412		MOVW	$runtime·badsystemstack(SB), R0
   413		BL	(R0)
   414		B	runtime·abort(SB)
   415	
   416	switch:
   417		// save our state in g->sched. Pretend to
   418		// be systemstack_switch if the G stack is scanned.
   419		MOVW	$runtime·systemstack_switch(SB), R3
   420		ADD	$4, R3, R3 // get past push {lr}
   421		MOVW	R3, (g_sched+gobuf_pc)(g)
   422		MOVW	R13, (g_sched+gobuf_sp)(g)
   423		MOVW	LR, (g_sched+gobuf_lr)(g)
   424		MOVW	g, (g_sched+gobuf_g)(g)
   425	
   426		// switch to g0
   427		MOVW	R2, g
   428		MOVW	(g_sched+gobuf_sp)(R2), R3
   429		// make it look like mstart called systemstack on g0, to stop traceback
   430		SUB	$4, R3, R3
   431		MOVW	$runtime·mstart(SB), R4
   432		MOVW	R4, 0(R3)
   433		MOVW	R3, R13
   434	
   435		// call target function
   436		MOVW	R6, R0		// arg
   437		BL	(R5)
   438	
   439		// switch back to g
   440		MOVW	g_m(g), R1
   441		MOVW	m_curg(R1), g
   442		MOVW	(g_sched+gobuf_sp)(g), R13
   443		MOVW	$0, R3
   444		MOVW	R3, (g_sched+gobuf_sp)(g)
   445		RET
   446	
   447	noswitch:
   448		// Using a tail call here cleans up tracebacks since we won't stop
   449		// at an intermediate systemstack.
   450		MOVW.P	4(R13), R14	// restore LR
   451		MOVW	R6, R0		// arg
   452		B	(R5)
   453	
   454	// Runs on OS stack. Duration (in 100ns units) is in R0.
   455	TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$0
   456		MOVM.DB.W [R4, R14], (R13)	// push {r4, lr}
   457		MOVW	R13, R4			// Save SP
   458		SUB	$8, R13			// R13 = R13 - 8
   459		BIC	$0x7, R13		// Align SP for ABI
   460		RSB	$0, R0, R3		// R3 = -R0
   461		MOVW	$0, R1			// R1 = FALSE (alertable)
   462		MOVW	$-1, R0			// R0 = handle
   463		MOVW	R13, R2			// R2 = pTime
   464		MOVW	R3, 0(R2)		// time_lo
   465		MOVW	R0, 4(R2)		// time_hi
   466		MOVW	runtime·_NtWaitForSingleObject(SB), R3
   467		BL	(R3)
   468		MOVW	R4, R13			// Restore SP
   469		MOVM.IA.W (R13), [R4, R15]	// pop {R4, pc}
   470	
   471	// Runs on OS stack.
   472	TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
   473		MOVM.DB.W [R4, R14], (R13)  	// push {R4, lr}
   474		MOVW    R13, R4
   475		BIC	$0x7, R13		// alignment for ABI
   476		MOVW	runtime·_SwitchToThread(SB), R0
   477		BL	(R0)
   478		MOVW 	R4, R13			// restore stack pointer
   479		MOVM.IA.W (R13), [R4, R15]	// pop {R4, pc}
   480	
   481	TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0
   482		B	runtime·armPublicationBarrier(SB)
   483	
   484	// never called (cgo not supported)
   485	TEXT runtime·read_tls_fallback(SB),NOSPLIT|NOFRAME,$0
   486		MOVW	$0xabcd, R0
   487		MOVW	R0, (R0)
   488		RET
   489	
   490	// See http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
   491	// Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
   492	#define _INTERRUPT_TIME 0x7ffe0008
   493	#define _SYSTEM_TIME 0x7ffe0014
   494	#define time_lo 0
   495	#define time_hi1 4
   496	#define time_hi2 8
   497	
   498	TEXT runtime·nanotime(SB),NOSPLIT,$0-8
   499		MOVW	$0, R0
   500		MOVB	runtime·useQPCTime(SB), R0
   501		CMP	$0, R0
   502		BNE	useQPC
   503		MOVW	$_INTERRUPT_TIME, R3
   504	loop:
   505		MOVW	time_hi1(R3), R1
   506		MOVW	time_lo(R3), R0
   507		MOVW	time_hi2(R3), R2
   508		CMP	R1, R2
   509		BNE	loop
   510	
   511		// wintime = R1:R0, multiply by 100
   512		MOVW	$100, R2
   513		MULLU	R0, R2, (R4, R3)    // R4:R3 = R1:R0 * R2
   514		MULA	R1, R2, R4, R4
   515	
   516		// wintime*100 = R4:R3
   517		MOVW	R3, ret_lo+0(FP)
   518		MOVW	R4, ret_hi+4(FP)
   519		RET
   520	useQPC:
   521		B	runtime·nanotimeQPC(SB)		// tail call
   522		RET
   523	
   524	TEXT time·now(SB),NOSPLIT,$0-20
   525		MOVW    $0, R0
   526		MOVB    runtime·useQPCTime(SB), R0
   527		CMP	$0, R0
   528		BNE	useQPC
   529		MOVW	$_INTERRUPT_TIME, R3
   530	loop:
   531		MOVW	time_hi1(R3), R1
   532		MOVW	time_lo(R3), R0
   533		MOVW	time_hi2(R3), R2
   534		CMP	R1, R2
   535		BNE	loop
   536	
   537		// wintime = R1:R0, multiply by 100
   538		MOVW	$100, R2
   539		MULLU	R0, R2, (R4, R3)    // R4:R3 = R1:R0 * R2
   540		MULA	R1, R2, R4, R4
   541	
   542		// wintime*100 = R4:R3
   543		MOVW	R3, mono+12(FP)
   544		MOVW	R4, mono+16(FP)
   545	
   546		MOVW	$_SYSTEM_TIME, R3
   547	wall:
   548		MOVW	time_hi1(R3), R1
   549		MOVW	time_lo(R3), R0
   550		MOVW	time_hi2(R3), R2
   551		CMP	R1, R2
   552		BNE	wall
   553	
   554		// w = R1:R0 in 100ns untis
   555		// convert to Unix epoch (but still 100ns units)
   556		#define delta 116444736000000000
   557		SUB.S   $(delta & 0xFFFFFFFF), R0
   558		SBC     $(delta >> 32), R1
   559	
   560		// Convert to nSec
   561		MOVW    $100, R2
   562		MULLU   R0, R2, (R4, R3)    // R4:R3 = R1:R0 * R2
   563		MULA    R1, R2, R4, R4
   564		// w = R2:R1 in nSec
   565		MOVW    R3, R1	      // R4:R3 -> R2:R1
   566		MOVW    R4, R2
   567	
   568		// multiply nanoseconds by reciprocal of 10**9 (scaled by 2**61)
   569		// to get seconds (96 bit scaled result)
   570		MOVW	$0x89705f41, R3		// 2**61 * 10**-9
   571		MULLU	R1,R3,(R6,R5)		// R7:R6:R5 = R2:R1 * R3
   572		MOVW	$0,R7
   573		MULALU	R2,R3,(R7,R6)
   574	
   575		// unscale by discarding low 32 bits, shifting the rest by 29
   576		MOVW	R6>>29,R6		// R7:R6 = (R7:R6:R5 >> 61)
   577		ORR	R7<<3,R6
   578		MOVW	R7>>29,R7
   579	
   580		// subtract (10**9 * sec) from nsec to get nanosecond remainder
   581		MOVW	$1000000000, R5	// 10**9
   582		MULLU	R6,R5,(R9,R8)   // R9:R8 = R7:R6 * R5
   583		MULA	R7,R5,R9,R9
   584		SUB.S	R8,R1		// R2:R1 -= R9:R8
   585		SBC	R9,R2
   586	
   587		// because reciprocal was a truncated repeating fraction, quotient
   588		// may be slightly too small -- adjust to make remainder < 10**9
   589		CMP	R5,R1	// if remainder > 10**9
   590		SUB.HS	R5,R1   //    remainder -= 10**9
   591		ADD.HS	$1,R6	//    sec += 1
   592	
   593		MOVW	R6,sec_lo+0(FP)
   594		MOVW	R7,sec_hi+4(FP)
   595		MOVW	R1,nsec+8(FP)
   596		RET
   597	useQPC:
   598		B	runtime·nanotimeQPC(SB)		// tail call
   599		RET
   600	
   601	// save_g saves the g register (R10) into thread local memory
   602	// so that we can call externally compiled
   603	// ARM code that will overwrite those registers.
   604	// NOTE: runtime.gogo assumes that R1 is preserved by this function.
   605	//       runtime.mcall assumes this function only clobbers R0 and R11.
   606	// Returns with g in R0.
   607	// Save the value in the _TEB->TlsSlots array.
   608	// Effectively implements TlsSetValue().
   609	// tls_g stores the TLS slot allocated TlsAlloc().
   610	TEXT runtime·save_g(SB),NOSPLIT|NOFRAME,$0
   611		MRC	15, 0, R0, C13, C0, 2
   612		ADD	$0xe10, R0
   613		MOVW 	$runtime·tls_g(SB), R11
   614		MOVW	(R11), R11
   615		MOVW	g, R11<<2(R0)
   616		MOVW	g, R0	// preserve R0 across call to setg<>
   617		RET
   618	
   619	// load_g loads the g register from thread-local memory,
   620	// for use after calling externally compiled
   621	// ARM code that overwrote those registers.
   622	// Get the value from the _TEB->TlsSlots array.
   623	// Effectively implements TlsGetValue().
   624	TEXT runtime·load_g(SB),NOSPLIT|NOFRAME,$0
   625		MRC	15, 0, R0, C13, C0, 2
   626		ADD	$0xe10, R0
   627		MOVW 	$runtime·tls_g(SB), g
   628		MOVW	(g), g
   629		MOVW	g<<2(R0), g
   630		RET
   631	
   632	// This is called from rt0_go, which runs on the system stack
   633	// using the initial stack allocated by the OS.
   634	// It calls back into standard C using the BL below.
   635	// To do that, the stack pointer must be 8-byte-aligned.
   636	TEXT runtime·_initcgo(SB),NOSPLIT|NOFRAME,$0
   637		MOVM.DB.W [R4, R14], (R13)	// push {r4, lr}
   638	
   639		// Ensure stack is 8-byte aligned before calling C code
   640		MOVW	R13, R4
   641		BIC	$0x7, R13
   642	
   643		// Allocate a TLS slot to hold g across calls to external code
   644		MOVW 	$runtime·_TlsAlloc(SB), R0
   645		MOVW	(R0), R0
   646		BL	(R0)
   647	
   648		// Assert that slot is less than 64 so we can use _TEB->TlsSlots
   649		CMP	$64, R0
   650		MOVW	$runtime·abort(SB), R1
   651		BL.GE	(R1)
   652	
   653		// Save Slot into tls_g
   654		MOVW 	$runtime·tls_g(SB), R1
   655		MOVW	R0, (R1)
   656	
   657		BL	init_thread_tls<>(SB)
   658	
   659		MOVW	R4, R13
   660		MOVM.IA.W (R13), [R4, R15]	// pop {r4, pc}
   661	
   662	// void init_thread_tls()
   663	//
   664	// Does per-thread TLS initialization. Saves a pointer to the TLS slot
   665	// holding G, in the current m.
   666	//
   667	//     g->m->tls[0] = &_TEB->TlsSlots[tls_g]
   668	//
   669	// The purpose of this is to enable the profiling handler to get the
   670	// current g associated with the thread. We cannot use m->curg because curg
   671	// only holds the current user g. If the thread is executing system code or
   672	// external code, m->curg will be NULL. The thread's TLS slot always holds
   673	// the current g, so save a reference to this location so the profiling
   674	// handler can get the real g from the thread's m.
   675	//
   676	// Clobbers R0-R3
   677	TEXT init_thread_tls<>(SB),NOSPLIT|NOFRAME,$0
   678		// compute &_TEB->TlsSlots[tls_g]
   679		MRC	15, 0, R0, C13, C0, 2
   680		ADD	$0xe10, R0
   681		MOVW 	$runtime·tls_g(SB), R1
   682		MOVW	(R1), R1
   683		MOVW	R1<<2, R1
   684		ADD	R1, R0
   685	
   686		// save in g->m->tls[0]
   687		MOVW	g_m(g), R1
   688		MOVW	R0, m_tls(R1)
   689		RET
   690	
   691	// Holds the TLS Slot, which was allocated by TlsAlloc()
   692	GLOBL runtime·tls_g+0(SB), NOPTR, $4

View as plain text