Text file src/pkg/runtime/sys_windows_386.s
1 // Copyright 2009 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,$0
11 MOVL fn+0(FP), BX
12
13 // SetLastError(0).
14 MOVL $0, 0x34(FS)
15
16 // Copy args to the stack.
17 MOVL SP, BP
18 MOVL libcall_n(BX), CX // words
19 MOVL CX, AX
20 SALL $2, AX
21 SUBL AX, SP // room for args
22 MOVL SP, DI
23 MOVL libcall_args(BX), SI
24 CLD
25 REP; MOVSL
26
27 // Call stdcall or cdecl function.
28 // DI SI BP BX are preserved, SP is not
29 CALL libcall_fn(BX)
30 MOVL BP, SP
31
32 // Return result.
33 MOVL fn+0(FP), BX
34 MOVL AX, libcall_r1(BX)
35 MOVL DX, libcall_r2(BX)
36
37 // GetLastError().
38 MOVL 0x34(FS), AX
39 MOVL AX, libcall_err(BX)
40
41 RET
42
43 TEXT runtime·badsignal2(SB),NOSPLIT,$24
44 // stderr
45 MOVL $-12, 0(SP)
46 MOVL SP, BP
47 CALL *runtime·_GetStdHandle(SB)
48 MOVL BP, SP
49
50 MOVL AX, 0(SP) // handle
51 MOVL $runtime·badsignalmsg(SB), DX // pointer
52 MOVL DX, 4(SP)
53 MOVL runtime·badsignallen(SB), DX // count
54 MOVL DX, 8(SP)
55 LEAL 20(SP), DX // written count
56 MOVL $0, 0(DX)
57 MOVL DX, 12(SP)
58 MOVL $0, 16(SP) // overlapped
59 CALL *runtime·_WriteFile(SB)
60 MOVL BP, SI
61 RET
62
63 // faster get/set last error
64 TEXT runtime·getlasterror(SB),NOSPLIT,$0
65 MOVL 0x34(FS), AX
66 MOVL AX, ret+0(FP)
67 RET
68
69 TEXT runtime·setlasterror(SB),NOSPLIT,$0
70 MOVL err+0(FP), AX
71 MOVL AX, 0x34(FS)
72 RET
73
74 // Called by Windows as a Vectored Exception Handler (VEH).
75 // First argument is pointer to struct containing
76 // exception record and context pointers.
77 // Handler function is stored in AX.
78 // Return 0 for 'not handled', -1 for handled.
79 TEXT sigtramp<>(SB),NOSPLIT,$0-0
80 MOVL ptrs+0(FP), CX
81 SUBL $40, SP
82
83 // save callee-saved registers
84 MOVL BX, 28(SP)
85 MOVL BP, 16(SP)
86 MOVL SI, 20(SP)
87 MOVL DI, 24(SP)
88
89 MOVL AX, SI // save handler address
90
91 // find g
92 get_tls(DX)
93 CMPL DX, $0
94 JNE 3(PC)
95 MOVL $0, AX // continue
96 JMP done
97 MOVL g(DX), DX
98 CMPL DX, $0
99 JNE 2(PC)
100 CALL runtime·badsignal2(SB)
101
102 // save g and SP in case of stack switch
103 MOVL DX, 32(SP) // g
104 MOVL SP, 36(SP)
105
106 // do we need to switch to the g0 stack?
107 MOVL g_m(DX), BX
108 MOVL m_g0(BX), BX
109 CMPL DX, BX
110 JEQ g0
111
112 // switch to the g0 stack
113 get_tls(BP)
114 MOVL BX, g(BP)
115 MOVL (g_sched+gobuf_sp)(BX), DI
116 // make it look like mstart called us on g0, to stop traceback
117 SUBL $4, DI
118 MOVL $runtime·mstart(SB), 0(DI)
119 // traceback will think that we've done SUBL
120 // on this stack, so subtract them here to match.
121 // (we need room for sighandler arguments anyway).
122 // and re-save old SP for restoring later.
123 SUBL $40, DI
124 MOVL SP, 36(DI)
125 MOVL DI, SP
126
127 g0:
128 MOVL 0(CX), BX // ExceptionRecord*
129 MOVL 4(CX), CX // Context*
130 MOVL BX, 0(SP)
131 MOVL CX, 4(SP)
132 MOVL DX, 8(SP)
133 CALL SI // call handler
134 // AX is set to report result back to Windows
135 MOVL 12(SP), AX
136
137 // switch back to original stack and g
138 // no-op if we never left.
139 MOVL 36(SP), SP
140 MOVL 32(SP), DX
141 get_tls(BP)
142 MOVL DX, g(BP)
143
144 done:
145 // restore callee-saved registers
146 MOVL 24(SP), DI
147 MOVL 20(SP), SI
148 MOVL 16(SP), BP
149 MOVL 28(SP), BX
150
151 ADDL $40, SP
152 // RET 4 (return and pop 4 bytes parameters)
153 BYTE $0xC2; WORD $4
154 RET // unreached; make assembler happy
155
156 TEXT runtime·exceptiontramp(SB),NOSPLIT,$0
157 MOVL $runtime·exceptionhandler(SB), AX
158 JMP sigtramp<>(SB)
159
160 TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0
161 // is never called
162 INT $3
163
164 TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0
165 MOVL $runtime·lastcontinuehandler(SB), AX
166 JMP sigtramp<>(SB)
167
168 // Called by OS using stdcall ABI: bool ctrlhandler(uint32).
169 TEXT runtime·ctrlhandler(SB),NOSPLIT,$0
170 PUSHL $runtime·ctrlhandler1(SB)
171 NOP SP // tell vet SP changed - stop checking offsets
172 CALL runtime·externalthreadhandler(SB)
173 MOVL 4(SP), CX
174 ADDL $12, SP
175 JMP CX
176
177 // Called by OS using stdcall ABI: uint32 profileloop(void*).
178 TEXT runtime·profileloop(SB),NOSPLIT,$0
179 PUSHL $runtime·profileloop1(SB)
180 NOP SP // tell vet SP changed - stop checking offsets
181 CALL runtime·externalthreadhandler(SB)
182 MOVL 4(SP), CX
183 ADDL $12, SP
184 JMP CX
185
186 TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
187 PUSHL BP
188 MOVL SP, BP
189 PUSHL BX
190 PUSHL SI
191 PUSHL DI
192 PUSHL 0x14(FS)
193 MOVL SP, DX
194
195 // setup dummy m, g
196 SUBL $m__size, SP // space for M
197 MOVL SP, 0(SP)
198 MOVL $m__size, 4(SP)
199 CALL runtime·memclrNoHeapPointers(SB) // smashes AX,BX,CX
200
201 LEAL m_tls(SP), CX
202 MOVL CX, 0x14(FS)
203 MOVL SP, BX
204 SUBL $g__size, SP // space for G
205 MOVL SP, g(CX)
206 MOVL SP, m_g0(BX)
207
208 MOVL SP, 0(SP)
209 MOVL $g__size, 4(SP)
210 CALL runtime·memclrNoHeapPointers(SB) // smashes AX,BX,CX
211 LEAL g__size(SP), BX
212 MOVL BX, g_m(SP)
213
214 LEAL -32768(SP), CX // must be less than SizeOfStackReserve set by linker
215 MOVL CX, (g_stack+stack_lo)(SP)
216 ADDL $const__StackGuard, CX
217 MOVL CX, g_stackguard0(SP)
218 MOVL CX, g_stackguard1(SP)
219 MOVL DX, (g_stack+stack_hi)(SP)
220
221 PUSHL AX // room for return value
222 PUSHL 16(BP) // arg for handler
223 CALL 8(BP)
224 POPL CX
225 POPL AX // pass return value to Windows in AX
226
227 get_tls(CX)
228 MOVL g(CX), CX
229 MOVL (g_stack+stack_hi)(CX), SP
230 POPL 0x14(FS)
231 POPL DI
232 POPL SI
233 POPL BX
234 POPL BP
235 RET
236
237 GLOBL runtime·cbctxts(SB), NOPTR, $4
238
239 TEXT runtime·callbackasm1(SB),NOSPLIT,$0
240 MOVL 0(SP), AX // will use to find our callback context
241
242 // remove return address from stack, we are not returning there
243 ADDL $4, SP
244
245 // address to callback parameters into CX
246 LEAL 4(SP), CX
247
248 // save registers as required for windows callback
249 PUSHL DI
250 PUSHL SI
251 PUSHL BP
252 PUSHL BX
253
254 // determine index into runtime·cbctxts table
255 SUBL $runtime·callbackasm(SB), AX
256 MOVL $0, DX
257 MOVL $5, BX // divide by 5 because each call instruction in runtime·callbacks is 5 bytes long
258 DIVL BX
259
260 // find correspondent runtime·cbctxts table entry
261 MOVL runtime·cbctxts(SB), BX
262 MOVL -4(BX)(AX*4), BX
263
264 // extract callback context
265 MOVL wincallbackcontext_gobody(BX), AX
266 MOVL wincallbackcontext_argsize(BX), DX
267
268 // preserve whatever's at the memory location that
269 // the callback will use to store the return value
270 PUSHL 0(CX)(DX*1)
271
272 // extend argsize by size of return value
273 ADDL $4, DX
274
275 // remember how to restore stack on return
276 MOVL wincallbackcontext_restorestack(BX), BX
277 PUSHL BX
278
279 // call target Go function
280 PUSHL DX // argsize (including return value)
281 PUSHL CX // callback parameters
282 PUSHL AX // address of target Go function
283 CLD
284 CALL runtime·cgocallback_gofunc(SB)
285 POPL AX
286 POPL CX
287 POPL DX
288
289 // how to restore stack on return
290 POPL BX
291
292 // return value into AX (as per Windows spec)
293 // and restore previously preserved value
294 MOVL -4(CX)(DX*1), AX
295 POPL -4(CX)(DX*1)
296
297 MOVL BX, CX // cannot use BX anymore
298
299 // restore registers as required for windows callback
300 POPL BX
301 POPL BP
302 POPL SI
303 POPL DI
304
305 // remove callback parameters before return (as per Windows spec)
306 POPL DX
307 ADDL CX, SP
308 PUSHL DX
309
310 CLD
311
312 RET
313
314 // void tstart(M *newm);
315 TEXT tstart<>(SB),NOSPLIT,$0
316 MOVL newm+0(FP), CX // m
317 MOVL m_g0(CX), DX // g
318
319 // Layout new m scheduler stack on os stack.
320 MOVL SP, AX
321 MOVL AX, (g_stack+stack_hi)(DX)
322 SUBL $(64*1024), AX // initial stack size (adjusted later)
323 MOVL AX, (g_stack+stack_lo)(DX)
324 ADDL $const__StackGuard, AX
325 MOVL AX, g_stackguard0(DX)
326 MOVL AX, g_stackguard1(DX)
327
328 // Set up tls.
329 LEAL m_tls(CX), SI
330 MOVL SI, 0x14(FS)
331 MOVL CX, g_m(DX)
332 MOVL DX, g(SI)
333
334 // Someday the convention will be D is always cleared.
335 CLD
336
337 CALL runtime·stackcheck(SB) // clobbers AX,CX
338 CALL runtime·mstart(SB)
339
340 RET
341
342 // uint32 tstart_stdcall(M *newm);
343 TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
344 MOVL newm+0(FP), BX
345
346 PUSHL BX
347 CALL tstart<>(SB)
348 POPL BX
349
350 // Adjust stack for stdcall to return properly.
351 MOVL (SP), AX // save return address
352 ADDL $4, SP // remove single parameter
353 MOVL AX, (SP) // restore return address
354
355 XORL AX, AX // return 0 == success
356
357 RET
358
359 // setldt(int entry, int address, int limit)
360 TEXT runtime·setldt(SB),NOSPLIT,$0
361 MOVL base+4(FP), CX
362 MOVL CX, 0x14(FS)
363 RET
364
365 // onosstack calls fn on OS stack.
366 // func onosstack(fn unsafe.Pointer, arg uint32)
367 TEXT runtime·onosstack(SB),NOSPLIT,$0
368 MOVL fn+0(FP), AX // to hide from 8l
369 MOVL arg+4(FP), BX
370
371 // Execute call on m->g0 stack, in case we are not actually
372 // calling a system call wrapper, like when running under WINE.
373 get_tls(CX)
374 CMPL CX, $0
375 JNE 3(PC)
376 // Not a Go-managed thread. Do not switch stack.
377 CALL AX
378 RET
379
380 MOVL g(CX), BP
381 MOVL g_m(BP), BP
382
383 // leave pc/sp for cpu profiler
384 MOVL (SP), SI
385 MOVL SI, m_libcallpc(BP)
386 MOVL g(CX), SI
387 MOVL SI, m_libcallg(BP)
388 // sp must be the last, because once async cpu profiler finds
389 // all three values to be non-zero, it will use them
390 LEAL fn+0(FP), SI
391 MOVL SI, m_libcallsp(BP)
392
393 MOVL m_g0(BP), SI
394 CMPL g(CX), SI
395 JNE switch
396 // executing on m->g0 already
397 CALL AX
398 JMP ret
399
400 switch:
401 // Switch to m->g0 stack and back.
402 MOVL (g_sched+gobuf_sp)(SI), SI
403 MOVL SP, -4(SI)
404 LEAL -4(SI), SP
405 CALL AX
406 MOVL 0(SP), SP
407
408 ret:
409 get_tls(CX)
410 MOVL g(CX), BP
411 MOVL g_m(BP), BP
412 MOVL $0, m_libcallsp(BP)
413 RET
414
415 // Runs on OS stack. duration (in 100ns units) is in BX.
416 TEXT runtime·usleep2(SB),NOSPLIT,$20
417 // Want negative 100ns units.
418 NEGL BX
419 MOVL $-1, hi-4(SP)
420 MOVL BX, lo-8(SP)
421 LEAL lo-8(SP), BX
422 MOVL BX, ptime-12(SP)
423 MOVL $0, alertable-16(SP)
424 MOVL $-1, handle-20(SP)
425 MOVL SP, BP
426 MOVL runtime·_NtWaitForSingleObject(SB), AX
427 CALL AX
428 MOVL BP, SP
429 RET
430
431 // Runs on OS stack.
432 TEXT runtime·switchtothread(SB),NOSPLIT,$0
433 MOVL SP, BP
434 MOVL runtime·_SwitchToThread(SB), AX
435 CALL AX
436 MOVL BP, SP
437 RET
438
439 // See https://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
440 // Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
441 #define _INTERRUPT_TIME 0x7ffe0008
442 #define _SYSTEM_TIME 0x7ffe0014
443 #define time_lo 0
444 #define time_hi1 4
445 #define time_hi2 8
446
447 TEXT runtime·nanotime(SB),NOSPLIT,$0-8
448 CMPB runtime·useQPCTime(SB), $0
449 JNE useQPC
450 loop:
451 MOVL (_INTERRUPT_TIME+time_hi1), AX
452 MOVL (_INTERRUPT_TIME+time_lo), CX
453 MOVL (_INTERRUPT_TIME+time_hi2), DI
454 CMPL AX, DI
455 JNE loop
456
457 // wintime = DI:CX, multiply by 100
458 MOVL $100, AX
459 MULL CX
460 IMULL $100, DI
461 ADDL DI, DX
462 // wintime*100 = DX:AX
463 MOVL AX, ret_lo+0(FP)
464 MOVL DX, ret_hi+4(FP)
465 RET
466 useQPC:
467 JMP runtime·nanotimeQPC(SB)
468 RET
469
470 TEXT time·now(SB),NOSPLIT,$0-20
471 CMPB runtime·useQPCTime(SB), $0
472 JNE useQPC
473 loop:
474 MOVL (_INTERRUPT_TIME+time_hi1), AX
475 MOVL (_INTERRUPT_TIME+time_lo), CX
476 MOVL (_INTERRUPT_TIME+time_hi2), DI
477 CMPL AX, DI
478 JNE loop
479
480 // w = DI:CX
481 // multiply by 100
482 MOVL $100, AX
483 MULL CX
484 IMULL $100, DI
485 ADDL DI, DX
486 // w*100 = DX:AX
487 MOVL AX, mono+12(FP)
488 MOVL DX, mono+16(FP)
489
490 wall:
491 MOVL (_SYSTEM_TIME+time_hi1), CX
492 MOVL (_SYSTEM_TIME+time_lo), AX
493 MOVL (_SYSTEM_TIME+time_hi2), DX
494 CMPL CX, DX
495 JNE wall
496
497 // w = DX:AX
498 // convert to Unix epoch (but still 100ns units)
499 #define delta 116444736000000000
500 SUBL $(delta & 0xFFFFFFFF), AX
501 SBBL $(delta >> 32), DX
502
503 // nano/100 = DX:AX
504 // split into two decimal halves by div 1e9.
505 // (decimal point is two spots over from correct place,
506 // but we avoid overflow in the high word.)
507 MOVL $1000000000, CX
508 DIVL CX
509 MOVL AX, DI
510 MOVL DX, SI
511
512 // DI = nano/100/1e9 = nano/1e11 = sec/100, DX = SI = nano/100%1e9
513 // split DX into seconds and nanoseconds by div 1e7 magic multiply.
514 MOVL DX, AX
515 MOVL $1801439851, CX
516 MULL CX
517 SHRL $22, DX
518 MOVL DX, BX
519 IMULL $10000000, DX
520 MOVL SI, CX
521 SUBL DX, CX
522
523 // DI = sec/100 (still)
524 // BX = (nano/100%1e9)/1e7 = (nano/1e9)%100 = sec%100
525 // CX = (nano/100%1e9)%1e7 = (nano%1e9)/100 = nsec/100
526 // store nsec for return
527 IMULL $100, CX
528 MOVL CX, nsec+8(FP)
529
530 // DI = sec/100 (still)
531 // BX = sec%100
532 // construct DX:AX = 64-bit sec and store for return
533 MOVL $0, DX
534 MOVL $100, AX
535 MULL DI
536 ADDL BX, AX
537 ADCL $0, DX
538 MOVL AX, sec+0(FP)
539 MOVL DX, sec+4(FP)
540 RET
541 useQPC:
542 JMP runtime·nowQPC(SB)
543 RET
View as plain text