github.com/lzhfromustc/gofuzz@v0.0.0-20211116160056-151b3108bbd1/runtime/sys_windows_arm.s (about)

     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  	// On entry, the trampoline in zcallback_windows_arm.s left
   318  	// the callback index in R12 (which is volatile in the C ABI).
   319  
   320  	// Push callback register arguments r0-r3. We do this first so
   321  	// they're contiguous with stack arguments.
   322  	MOVM.DB.W [R0-R3], (R13)
   323  	// Push C callee-save registers r4-r11 and lr.
   324  	MOVM.DB.W [R4-R11, R14], (R13)
   325  	SUB	$(16 + callbackArgs__size), R13	// space for locals
   326  
   327  	// Create a struct callbackArgs on our stack.
   328  	MOVW	R12, (16+callbackArgs_index)(R13)	// callback index
   329  	MOVW	$(16+callbackArgs__size+4*9)(R13), R0
   330  	MOVW	R0, (16+callbackArgs_args)(R13)		// address of args vector
   331  	MOVW	$0, R0
   332  	MOVW	R0, (16+callbackArgs_result)(R13)	// result
   333  
   334  	// Prepare for entry to Go.
   335  	BL	runtime·load_g(SB)
   336  
   337  	// Call cgocallback, which will call callbackWrap(frame).
   338  	MOVW	$0, R0
   339  	MOVW	R0, 12(R13)	// context
   340  	MOVW	$16(R13), R1	// R1 = &callbackArgs{...}
   341  	MOVW	R1, 8(R13)	// frame (address of callbackArgs)
   342  	MOVW	$·callbackWrap(SB), R1
   343  	MOVW	R1, 4(R13)	// PC of function to call
   344  	BL	runtime·cgocallback(SB)
   345  
   346  	// Get callback result.
   347  	MOVW	(16+callbackArgs_result)(R13), R0
   348  
   349  	ADD	$(16 + callbackArgs__size), R13	// free locals
   350  	MOVM.IA.W (R13), [R4-R11, R12]	// pop {r4-r11, lr=>r12}
   351  	ADD	$(4*4), R13	// skip r0-r3
   352  	B	(R12)	// return
   353  
   354  // uint32 tstart_stdcall(M *newm);
   355  TEXT runtime·tstart_stdcall(SB),NOSPLIT|NOFRAME,$0
   356  	MOVM.DB.W [R4-R11, R14], (R13)		// push {r4-r11, lr}
   357  
   358  	MOVW	m_g0(R0), g
   359  	MOVW	R0, g_m(g)
   360  	BL	runtime·save_g(SB)
   361  
   362  	// do per-thread TLS initialization
   363  	BL	init_thread_tls<>(SB)
   364  
   365  	// Layout new m scheduler stack on os stack.
   366  	MOVW	R13, R0
   367  	MOVW	R0, g_stack+stack_hi(g)
   368  	SUB	$(64*1024), R0
   369  	MOVW	R0, (g_stack+stack_lo)(g)
   370  	MOVW	R0, g_stackguard0(g)
   371  	MOVW	R0, g_stackguard1(g)
   372  
   373  	BL	runtime·emptyfunc(SB)	// fault if stack check is wrong
   374  	BL	runtime·mstart(SB)
   375  
   376  	// Exit the thread.
   377  	MOVW	$0, R0
   378  	MOVM.IA.W (R13), [R4-R11, R15]		// pop {r4-r11, pc}
   379  
   380  // onosstack calls fn on OS stack.
   381  // adapted from asm_arm.s : systemstack
   382  // func onosstack(fn unsafe.Pointer, arg uint32)
   383  TEXT runtime·onosstack(SB),NOSPLIT,$0
   384  	MOVW	fn+0(FP), R5		// R5 = fn
   385  	MOVW	arg+4(FP), R6		// R6 = arg
   386  
   387  	// This function can be called when there is no g,
   388  	// for example, when we are handling a callback on a non-go thread.
   389  	// In this case we're already on the system stack.
   390  	CMP	$0, g
   391  	BEQ	noswitch
   392  
   393  	MOVW	g_m(g), R1		// R1 = m
   394  
   395  	MOVW	m_gsignal(R1), R2	// R2 = gsignal
   396  	CMP	g, R2
   397  	B.EQ	noswitch
   398  
   399  	MOVW	m_g0(R1), R2		// R2 = g0
   400  	CMP	g, R2
   401  	B.EQ	noswitch
   402  
   403  	MOVW	m_curg(R1), R3
   404  	CMP	g, R3
   405  	B.EQ	switch
   406  
   407  	// Bad: g is not gsignal, not g0, not curg. What is it?
   408  	// Hide call from linker nosplit analysis.
   409  	MOVW	$runtime·badsystemstack(SB), R0
   410  	BL	(R0)
   411  	B	runtime·abort(SB)
   412  
   413  switch:
   414  	// save our state in g->sched. Pretend to
   415  	// be systemstack_switch if the G stack is scanned.
   416  	MOVW	$runtime·systemstack_switch(SB), R3
   417  	ADD	$4, R3, R3 // get past push {lr}
   418  	MOVW	R3, (g_sched+gobuf_pc)(g)
   419  	MOVW	R13, (g_sched+gobuf_sp)(g)
   420  	MOVW	LR, (g_sched+gobuf_lr)(g)
   421  	MOVW	g, (g_sched+gobuf_g)(g)
   422  
   423  	// switch to g0
   424  	MOVW	R2, g
   425  	MOVW	(g_sched+gobuf_sp)(R2), R3
   426  	// make it look like mstart called systemstack on g0, to stop traceback
   427  	SUB	$4, R3, R3
   428  	MOVW	$runtime·mstart(SB), R4
   429  	MOVW	R4, 0(R3)
   430  	MOVW	R3, R13
   431  
   432  	// call target function
   433  	MOVW	R6, R0		// arg
   434  	BL	(R5)
   435  
   436  	// switch back to g
   437  	MOVW	g_m(g), R1
   438  	MOVW	m_curg(R1), g
   439  	MOVW	(g_sched+gobuf_sp)(g), R13
   440  	MOVW	$0, R3
   441  	MOVW	R3, (g_sched+gobuf_sp)(g)
   442  	RET
   443  
   444  noswitch:
   445  	// Using a tail call here cleans up tracebacks since we won't stop
   446  	// at an intermediate systemstack.
   447  	MOVW.P	4(R13), R14	// restore LR
   448  	MOVW	R6, R0		// arg
   449  	B	(R5)
   450  
   451  // Runs on OS stack. Duration (in 100ns units) is in R0.
   452  TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$0
   453  	MOVM.DB.W [R4, R14], (R13)	// push {r4, lr}
   454  	MOVW	R13, R4			// Save SP
   455  	SUB	$8, R13			// R13 = R13 - 8
   456  	BIC	$0x7, R13		// Align SP for ABI
   457  	RSB	$0, R0, R3		// R3 = -R0
   458  	MOVW	$0, R1			// R1 = FALSE (alertable)
   459  	MOVW	$-1, R0			// R0 = handle
   460  	MOVW	R13, R2			// R2 = pTime
   461  	MOVW	R3, 0(R2)		// time_lo
   462  	MOVW	R0, 4(R2)		// time_hi
   463  	MOVW	runtime·_NtWaitForSingleObject(SB), R3
   464  	BL	(R3)
   465  	MOVW	R4, R13			// Restore SP
   466  	MOVM.IA.W (R13), [R4, R15]	// pop {R4, pc}
   467  
   468  // Runs on OS stack. Duration (in 100ns units) is in R0.
   469  // TODO: neeeds to be implemented properly.
   470  TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$0
   471  	B	runtime·abort(SB)
   472  
   473  // Runs on OS stack.
   474  TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
   475  	MOVM.DB.W [R4, R14], (R13)  	// push {R4, lr}
   476  	MOVW    R13, R4
   477  	BIC	$0x7, R13		// alignment for ABI
   478  	MOVW	runtime·_SwitchToThread(SB), R0
   479  	BL	(R0)
   480  	MOVW 	R4, R13			// restore stack pointer
   481  	MOVM.IA.W (R13), [R4, R15]	// pop {R4, pc}
   482  
   483  TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0
   484  	B	runtime·armPublicationBarrier(SB)
   485  
   486  // never called (cgo not supported)
   487  TEXT runtime·read_tls_fallback(SB),NOSPLIT|NOFRAME,$0
   488  	MOVW	$0xabcd, R0
   489  	MOVW	R0, (R0)
   490  	RET
   491  
   492  // See http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
   493  // Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
   494  #define _INTERRUPT_TIME 0x7ffe0008
   495  #define _SYSTEM_TIME 0x7ffe0014
   496  #define time_lo 0
   497  #define time_hi1 4
   498  #define time_hi2 8
   499  
   500  TEXT runtime·nanotime1(SB),NOSPLIT,$0-8
   501  	MOVW	$0, R0
   502  	MOVB	runtime·useQPCTime(SB), R0
   503  	CMP	$0, R0
   504  	BNE	useQPC
   505  	MOVW	$_INTERRUPT_TIME, R3
   506  loop:
   507  	MOVW	time_hi1(R3), R1
   508  	MOVW	time_lo(R3), R0
   509  	MOVW	time_hi2(R3), R2
   510  	CMP	R1, R2
   511  	BNE	loop
   512  
   513  	// wintime = R1:R0, multiply by 100
   514  	MOVW	$100, R2
   515  	MULLU	R0, R2, (R4, R3)    // R4:R3 = R1:R0 * R2
   516  	MULA	R1, R2, R4, R4
   517  
   518  	// wintime*100 = R4:R3
   519  	MOVW	R3, ret_lo+0(FP)
   520  	MOVW	R4, ret_hi+4(FP)
   521  	RET
   522  useQPC:
   523  	B	runtime·nanotimeQPC(SB)		// tail call
   524  	RET
   525  
   526  TEXT time·now(SB),NOSPLIT,$0-20
   527  	MOVW    $0, R0
   528  	MOVB    runtime·useQPCTime(SB), R0
   529  	CMP	$0, R0
   530  	BNE	useQPC
   531  	MOVW	$_INTERRUPT_TIME, R3
   532  loop:
   533  	MOVW	time_hi1(R3), R1
   534  	MOVW	time_lo(R3), R0
   535  	MOVW	time_hi2(R3), R2
   536  	CMP	R1, R2
   537  	BNE	loop
   538  
   539  	// wintime = R1:R0, multiply by 100
   540  	MOVW	$100, R2
   541  	MULLU	R0, R2, (R4, R3)    // R4:R3 = R1:R0 * R2
   542  	MULA	R1, R2, R4, R4
   543  
   544  	// wintime*100 = R4:R3
   545  	MOVW	R3, mono+12(FP)
   546  	MOVW	R4, mono+16(FP)
   547  
   548  	MOVW	$_SYSTEM_TIME, R3
   549  wall:
   550  	MOVW	time_hi1(R3), R1
   551  	MOVW	time_lo(R3), R0
   552  	MOVW	time_hi2(R3), R2
   553  	CMP	R1, R2
   554  	BNE	wall
   555  
   556  	// w = R1:R0 in 100ns untis
   557  	// convert to Unix epoch (but still 100ns units)
   558  	#define delta 116444736000000000
   559  	SUB.S   $(delta & 0xFFFFFFFF), R0
   560  	SBC     $(delta >> 32), R1
   561  
   562  	// Convert to nSec
   563  	MOVW    $100, R2
   564  	MULLU   R0, R2, (R4, R3)    // R4:R3 = R1:R0 * R2
   565  	MULA    R1, R2, R4, R4
   566  	// w = R2:R1 in nSec
   567  	MOVW    R3, R1	      // R4:R3 -> R2:R1
   568  	MOVW    R4, R2
   569  
   570  	// multiply nanoseconds by reciprocal of 10**9 (scaled by 2**61)
   571  	// to get seconds (96 bit scaled result)
   572  	MOVW	$0x89705f41, R3		// 2**61 * 10**-9
   573  	MULLU	R1,R3,(R6,R5)		// R7:R6:R5 = R2:R1 * R3
   574  	MOVW	$0,R7
   575  	MULALU	R2,R3,(R7,R6)
   576  
   577  	// unscale by discarding low 32 bits, shifting the rest by 29
   578  	MOVW	R6>>29,R6		// R7:R6 = (R7:R6:R5 >> 61)
   579  	ORR	R7<<3,R6
   580  	MOVW	R7>>29,R7
   581  
   582  	// subtract (10**9 * sec) from nsec to get nanosecond remainder
   583  	MOVW	$1000000000, R5	// 10**9
   584  	MULLU	R6,R5,(R9,R8)   // R9:R8 = R7:R6 * R5
   585  	MULA	R7,R5,R9,R9
   586  	SUB.S	R8,R1		// R2:R1 -= R9:R8
   587  	SBC	R9,R2
   588  
   589  	// because reciprocal was a truncated repeating fraction, quotient
   590  	// may be slightly too small -- adjust to make remainder < 10**9
   591  	CMP	R5,R1	// if remainder > 10**9
   592  	SUB.HS	R5,R1   //    remainder -= 10**9
   593  	ADD.HS	$1,R6	//    sec += 1
   594  
   595  	MOVW	R6,sec_lo+0(FP)
   596  	MOVW	R7,sec_hi+4(FP)
   597  	MOVW	R1,nsec+8(FP)
   598  	RET
   599  useQPC:
   600  	B	runtime·nanotimeQPC(SB)		// tail call
   601  	RET
   602  
   603  // save_g saves the g register (R10) into thread local memory
   604  // so that we can call externally compiled
   605  // ARM code that will overwrite those registers.
   606  // NOTE: runtime.gogo assumes that R1 is preserved by this function.
   607  //       runtime.mcall assumes this function only clobbers R0 and R11.
   608  // Returns with g in R0.
   609  // Save the value in the _TEB->TlsSlots array.
   610  // Effectively implements TlsSetValue().
   611  // tls_g stores the TLS slot allocated TlsAlloc().
   612  TEXT runtime·save_g(SB),NOSPLIT|NOFRAME,$0
   613  	MRC	15, 0, R0, C13, C0, 2
   614  	ADD	$0xe10, R0
   615  	MOVW 	$runtime·tls_g(SB), R11
   616  	MOVW	(R11), R11
   617  	MOVW	g, R11<<2(R0)
   618  	MOVW	g, R0	// preserve R0 across call to setg<>
   619  	RET
   620  
   621  // load_g loads the g register from thread-local memory,
   622  // for use after calling externally compiled
   623  // ARM code that overwrote those registers.
   624  // Get the value from the _TEB->TlsSlots array.
   625  // Effectively implements TlsGetValue().
   626  TEXT runtime·load_g(SB),NOSPLIT|NOFRAME,$0
   627  	MRC	15, 0, R0, C13, C0, 2
   628  	ADD	$0xe10, R0
   629  	MOVW 	$runtime·tls_g(SB), g
   630  	MOVW	(g), g
   631  	MOVW	g<<2(R0), g
   632  	RET
   633  
   634  // This is called from rt0_go, which runs on the system stack
   635  // using the initial stack allocated by the OS.
   636  // It calls back into standard C using the BL below.
   637  // To do that, the stack pointer must be 8-byte-aligned.
   638  TEXT runtime·_initcgo(SB),NOSPLIT|NOFRAME,$0
   639  	MOVM.DB.W [R4, R14], (R13)	// push {r4, lr}
   640  
   641  	// Ensure stack is 8-byte aligned before calling C code
   642  	MOVW	R13, R4
   643  	BIC	$0x7, R13
   644  
   645  	// Allocate a TLS slot to hold g across calls to external code
   646  	MOVW 	$runtime·_TlsAlloc(SB), R0
   647  	MOVW	(R0), R0
   648  	BL	(R0)
   649  
   650  	// Assert that slot is less than 64 so we can use _TEB->TlsSlots
   651  	CMP	$64, R0
   652  	MOVW	$runtime·abort(SB), R1
   653  	BL.GE	(R1)
   654  
   655  	// Save Slot into tls_g
   656  	MOVW 	$runtime·tls_g(SB), R1
   657  	MOVW	R0, (R1)
   658  
   659  	BL	init_thread_tls<>(SB)
   660  
   661  	MOVW	R4, R13
   662  	MOVM.IA.W (R13), [R4, R15]	// pop {r4, pc}
   663  
   664  // void init_thread_tls()
   665  //
   666  // Does per-thread TLS initialization. Saves a pointer to the TLS slot
   667  // holding G, in the current m.
   668  //
   669  //     g->m->tls[0] = &_TEB->TlsSlots[tls_g]
   670  //
   671  // The purpose of this is to enable the profiling handler to get the
   672  // current g associated with the thread. We cannot use m->curg because curg
   673  // only holds the current user g. If the thread is executing system code or
   674  // external code, m->curg will be NULL. The thread's TLS slot always holds
   675  // the current g, so save a reference to this location so the profiling
   676  // handler can get the real g from the thread's m.
   677  //
   678  // Clobbers R0-R3
   679  TEXT init_thread_tls<>(SB),NOSPLIT|NOFRAME,$0
   680  	// compute &_TEB->TlsSlots[tls_g]
   681  	MRC	15, 0, R0, C13, C0, 2
   682  	ADD	$0xe10, R0
   683  	MOVW 	$runtime·tls_g(SB), R1
   684  	MOVW	(R1), R1
   685  	MOVW	R1<<2, R1
   686  	ADD	R1, R0
   687  
   688  	// save in g->m->tls[0]
   689  	MOVW	g_m(g), R1
   690  	MOVW	R0, m_tls(R1)
   691  	RET
   692  
   693  // Holds the TLS Slot, which was allocated by TlsAlloc()
   694  GLOBL runtime·tls_g+0(SB), NOPTR, $4