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); 10TEXT 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 43TEXT 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 64TEXT runtime·getlasterror(SB),NOSPLIT,$0 65 MOVL 0x34(FS), AX 66 MOVL AX, ret+0(FP) 67 RET 68 69TEXT 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. 79TEXT 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 127g0: 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 144done: 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 156TEXT runtime·exceptiontramp(SB),NOSPLIT,$0 157 MOVL $runtime·exceptionhandler(SB), AX 158 JMP sigtramp<>(SB) 159 160TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0 161 // is never called 162 INT $3 163 164TEXT 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). 169TEXT 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*). 178TEXT 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 186TEXT 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 237GLOBL runtime·cbctxts(SB), NOPTR, $4 238 239TEXT 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); 315TEXT 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); 343TEXT 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) 360TEXT 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) 367TEXT 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 400switch: 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 408ret: 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. 416TEXT 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. 432TEXT 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 447TEXT runtime·nanotime1(SB),NOSPLIT,$0-8 448 CMPB runtime·useQPCTime(SB), $0 449 JNE useQPC 450loop: 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 466useQPC: 467 JMP runtime·nanotimeQPC(SB) 468 RET 469 470TEXT time·now(SB),NOSPLIT,$0-20 471 CMPB runtime·useQPCTime(SB), $0 472 JNE useQPC 473loop: 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 490wall: 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 541useQPC: 542 JMP runtime·nowQPC(SB) 543 RET 544