Aram Hăvărneanu | 50df136 | 2014-02-24 22:31:01 -0500 | [diff] [blame] | 1 | // Copyright 2014 The Go Authors. All rights reserved. |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | // |
| 5 | // System calls and other sys.stuff for AMD64, SunOS |
| 6 | // /usr/include/sys/syscall.h for syscall numbers. |
| 7 | // |
| 8 | |
Russ Cox | 15ced2d | 2014-11-11 17:06:22 -0500 | [diff] [blame] | 9 | #include "go_asm.h" |
| 10 | #include "go_tls.h" |
Russ Cox | cb040d5 | 2014-09-04 23:05:18 -0400 | [diff] [blame] | 11 | #include "textflag.h" |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 12 | |
| 13 | // This is needed by asm_amd64.s |
| 14 | TEXT runtime·settls(SB),NOSPLIT,$8 |
| 15 | RET |
| 16 | |
Aram Hăvărneanu | e088e16 | 2014-11-13 16:07:10 +0100 | [diff] [blame] | 17 | // void libc_miniterrno(void *(*___errno)(void)); |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 18 | // |
| 19 | // Set the TLS errno pointer in M. |
| 20 | // |
| 21 | // Called using runtime·asmcgocall from os_solaris.c:/minit. |
Russ Cox | 997809c | 2014-08-27 14:52:25 -0400 | [diff] [blame] | 22 | // NOT USING GO CALLING CONVENTION. |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 23 | TEXT runtime·miniterrno(SB),NOSPLIT,$0 |
| 24 | // asmcgocall will put first argument into DI. |
| 25 | CALL DI // SysV ABI so returns in AX |
| 26 | get_tls(CX) |
Russ Cox | 89f185f | 2014-06-26 11:54:39 -0400 | [diff] [blame] | 27 | MOVQ g(CX), BX |
| 28 | MOVQ g_m(BX), BX |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 29 | MOVQ AX, m_perrno(BX) |
| 30 | RET |
| 31 | |
| 32 | // int64 runtime·nanotime1(void); |
| 33 | // |
| 34 | // clock_gettime(3c) wrapper because Timespec is too large for |
| 35 | // runtime·nanotime stack. |
| 36 | // |
| 37 | // Called using runtime·sysvicall6 from os_solaris.c:/nanotime. |
Russ Cox | 997809c | 2014-08-27 14:52:25 -0400 | [diff] [blame] | 38 | // NOT USING GO CALLING CONVENTION. |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 39 | TEXT runtime·nanotime1(SB),NOSPLIT,$0 |
| 40 | // need space for the timespec argument. |
| 41 | SUBQ $64, SP // 16 bytes will do, but who knows in the future? |
| 42 | MOVQ $3, DI // CLOCK_REALTIME from <sys/time_impl.h> |
| 43 | MOVQ SP, SI |
Aram Hăvărneanu | c94f1f7 | 2015-03-30 13:52:07 +0200 | [diff] [blame] | 44 | LEAQ libc_clock_gettime(SB), AX |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 45 | CALL AX |
| 46 | MOVQ (SP), AX // tv_sec from struct timespec |
| 47 | IMULQ $1000000000, AX // multiply into nanoseconds |
| 48 | ADDQ 8(SP), AX // tv_nsec, offset should be stable. |
| 49 | ADDQ $64, SP |
| 50 | RET |
| 51 | |
| 52 | // pipe(3c) wrapper that returns fds in AX, DX. |
Russ Cox | 997809c | 2014-08-27 14:52:25 -0400 | [diff] [blame] | 53 | // NOT USING GO CALLING CONVENTION. |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 54 | TEXT runtime·pipe1(SB),NOSPLIT,$0 |
| 55 | SUBQ $16, SP // 8 bytes will do, but stack has to be 16-byte alligned |
| 56 | MOVQ SP, DI |
Aram Hăvărneanu | c94f1f7 | 2015-03-30 13:52:07 +0200 | [diff] [blame] | 57 | LEAQ libc_pipe(SB), AX |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 58 | CALL AX |
| 59 | MOVL 0(SP), AX |
| 60 | MOVL 4(SP), DX |
| 61 | ADDQ $16, SP |
| 62 | RET |
| 63 | |
| 64 | // Call a library function with SysV calling conventions. |
| 65 | // The called function can take a maximum of 6 INTEGER class arguments, |
| 66 | // see |
| 67 | // Michael Matz, Jan Hubicka, Andreas Jaeger, and Mark Mitchell |
| 68 | // System V Application Binary Interface |
| 69 | // AMD64 Architecture Processor Supplement |
| 70 | // section 3.2.3. |
| 71 | // |
| 72 | // Called by runtime·asmcgocall or runtime·cgocall. |
Russ Cox | 997809c | 2014-08-27 14:52:25 -0400 | [diff] [blame] | 73 | // NOT USING GO CALLING CONVENTION. |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 74 | TEXT runtime·asmsysvicall6(SB),NOSPLIT,$0 |
| 75 | // asmcgocall will put first argument into DI. |
| 76 | PUSHQ DI // save for later |
| 77 | MOVQ libcall_fn(DI), AX |
| 78 | MOVQ libcall_args(DI), R11 |
| 79 | MOVQ libcall_n(DI), R10 |
| 80 | |
| 81 | get_tls(CX) |
Russ Cox | 89f185f | 2014-06-26 11:54:39 -0400 | [diff] [blame] | 82 | MOVQ g(CX), BX |
| 83 | MOVQ g_m(BX), BX |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 84 | MOVQ m_perrno(BX), DX |
| 85 | CMPQ DX, $0 |
| 86 | JEQ skiperrno1 |
| 87 | MOVL $0, 0(DX) |
| 88 | |
| 89 | skiperrno1: |
| 90 | CMPQ R11, $0 |
| 91 | JEQ skipargs |
| 92 | // Load 6 args into correspondent registers. |
| 93 | MOVQ 0(R11), DI |
| 94 | MOVQ 8(R11), SI |
| 95 | MOVQ 16(R11), DX |
| 96 | MOVQ 24(R11), CX |
| 97 | MOVQ 32(R11), R8 |
| 98 | MOVQ 40(R11), R9 |
| 99 | skipargs: |
| 100 | |
| 101 | // Call SysV function |
| 102 | CALL AX |
| 103 | |
| 104 | // Return result |
| 105 | POPQ DI |
| 106 | MOVQ AX, libcall_r1(DI) |
| 107 | MOVQ DX, libcall_r2(DI) |
| 108 | |
| 109 | get_tls(CX) |
Russ Cox | 89f185f | 2014-06-26 11:54:39 -0400 | [diff] [blame] | 110 | MOVQ g(CX), BX |
| 111 | MOVQ g_m(BX), BX |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 112 | MOVQ m_perrno(BX), AX |
| 113 | CMPQ AX, $0 |
| 114 | JEQ skiperrno2 |
| 115 | MOVL 0(AX), AX |
| 116 | MOVQ AX, libcall_err(DI) |
| 117 | |
| 118 | skiperrno2: |
| 119 | RET |
| 120 | |
| 121 | // uint32 tstart_sysvicall(M *newm); |
| 122 | TEXT runtime·tstart_sysvicall(SB),NOSPLIT,$0 |
| 123 | // DI contains first arg newm |
| 124 | MOVQ m_g0(DI), DX // g |
| 125 | |
| 126 | // Make TLS entries point at g and m. |
| 127 | get_tls(BX) |
| 128 | MOVQ DX, g(BX) |
Russ Cox | 89f185f | 2014-06-26 11:54:39 -0400 | [diff] [blame] | 129 | MOVQ DI, g_m(DX) |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 130 | |
| 131 | // Layout new m scheduler stack on os stack. |
| 132 | MOVQ SP, AX |
Russ Cox | 8ac35be | 2014-09-09 14:02:37 -0400 | [diff] [blame] | 133 | MOVQ AX, (g_stack+stack_hi)(DX) |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 134 | SUBQ $(0x100000), AX // stack size |
Russ Cox | 8ac35be | 2014-09-09 14:02:37 -0400 | [diff] [blame] | 135 | MOVQ AX, (g_stack+stack_lo)(DX) |
Aram Hăvărneanu | e088e16 | 2014-11-13 16:07:10 +0100 | [diff] [blame] | 136 | ADDQ $const__StackGuard, AX |
Russ Cox | e6d3511 | 2015-01-05 16:29:21 +0000 | [diff] [blame] | 137 | MOVQ AX, g_stackguard0(DX) |
| 138 | MOVQ AX, g_stackguard1(DX) |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 139 | |
| 140 | // Someday the convention will be D is always cleared. |
| 141 | CLD |
| 142 | |
| 143 | CALL runtime·stackcheck(SB) // clobbers AX,CX |
| 144 | CALL runtime·mstart(SB) |
| 145 | |
| 146 | XORL AX, AX // return 0 == success |
Russ Cox | 25f6b02 | 2014-08-27 11:32:17 -0400 | [diff] [blame] | 147 | MOVL AX, ret+8(FP) |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 148 | RET |
| 149 | |
| 150 | // Careful, this is called by __sighndlr, a libc function. We must preserve |
| 151 | // registers as per AMD 64 ABI. |
| 152 | TEXT runtime·sigtramp(SB),NOSPLIT,$0 |
| 153 | // Note that we are executing on altsigstack here, so we have |
| 154 | // more stack available than NOSPLIT would have us believe. |
| 155 | // To defeat the linker, we make our own stack frame with |
| 156 | // more space: |
| 157 | SUBQ $184, SP |
| 158 | |
| 159 | // save registers |
| 160 | MOVQ BX, 32(SP) |
| 161 | MOVQ BP, 40(SP) |
| 162 | MOVQ R12, 48(SP) |
| 163 | MOVQ R13, 56(SP) |
| 164 | MOVQ R14, 64(SP) |
| 165 | MOVQ R15, 72(SP) |
| 166 | |
| 167 | get_tls(BX) |
Russ Cox | 89f185f | 2014-06-26 11:54:39 -0400 | [diff] [blame] | 168 | // check that g exists |
| 169 | MOVQ g(BX), R10 |
| 170 | CMPQ R10, $0 |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 171 | JNE allgood |
| 172 | MOVQ DI, 0(SP) |
| 173 | MOVQ $runtime·badsignal(SB), AX |
| 174 | CALL AX |
Aram Hăvărneanu | d7b678b | 2014-07-02 09:34:06 +1000 | [diff] [blame] | 175 | JMP exit |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 176 | |
| 177 | allgood: |
| 178 | // save g |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 179 | MOVQ R10, 80(SP) |
| 180 | |
| 181 | // Save m->libcall and m->scratch. We need to do this because we |
| 182 | // might get interrupted by a signal in runtime·asmcgocall. |
| 183 | |
| 184 | // save m->libcall |
Russ Cox | 89f185f | 2014-06-26 11:54:39 -0400 | [diff] [blame] | 185 | MOVQ g_m(R10), BP |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 186 | LEAQ m_libcall(BP), R11 |
| 187 | MOVQ libcall_fn(R11), R10 |
| 188 | MOVQ R10, 88(SP) |
| 189 | MOVQ libcall_args(R11), R10 |
| 190 | MOVQ R10, 96(SP) |
| 191 | MOVQ libcall_n(R11), R10 |
| 192 | MOVQ R10, 104(SP) |
| 193 | MOVQ libcall_r1(R11), R10 |
| 194 | MOVQ R10, 168(SP) |
| 195 | MOVQ libcall_r2(R11), R10 |
| 196 | MOVQ R10, 176(SP) |
| 197 | |
| 198 | // save m->scratch |
| 199 | LEAQ m_scratch(BP), R11 |
| 200 | MOVQ 0(R11), R10 |
| 201 | MOVQ R10, 112(SP) |
| 202 | MOVQ 8(R11), R10 |
| 203 | MOVQ R10, 120(SP) |
| 204 | MOVQ 16(R11), R10 |
| 205 | MOVQ R10, 128(SP) |
| 206 | MOVQ 24(R11), R10 |
| 207 | MOVQ R10, 136(SP) |
| 208 | MOVQ 32(R11), R10 |
| 209 | MOVQ R10, 144(SP) |
| 210 | MOVQ 40(R11), R10 |
| 211 | MOVQ R10, 152(SP) |
| 212 | |
| 213 | // save errno, it might be EINTR; stuff we do here might reset it. |
| 214 | MOVQ m_perrno(BP), R10 |
| 215 | MOVL 0(R10), R10 |
| 216 | MOVQ R10, 160(SP) |
| 217 | |
| 218 | MOVQ g(BX), R10 |
| 219 | // g = m->gsignal |
| 220 | MOVQ m_gsignal(BP), BP |
| 221 | MOVQ BP, g(BX) |
| 222 | |
| 223 | // prepare call |
| 224 | MOVQ DI, 0(SP) |
| 225 | MOVQ SI, 8(SP) |
| 226 | MOVQ DX, 16(SP) |
| 227 | MOVQ R10, 24(SP) |
| 228 | CALL runtime·sighandler(SB) |
| 229 | |
| 230 | get_tls(BX) |
Russ Cox | 89f185f | 2014-06-26 11:54:39 -0400 | [diff] [blame] | 231 | MOVQ g(BX), BP |
| 232 | MOVQ g_m(BP), BP |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 233 | // restore libcall |
| 234 | LEAQ m_libcall(BP), R11 |
| 235 | MOVQ 88(SP), R10 |
| 236 | MOVQ R10, libcall_fn(R11) |
| 237 | MOVQ 96(SP), R10 |
| 238 | MOVQ R10, libcall_args(R11) |
| 239 | MOVQ 104(SP), R10 |
| 240 | MOVQ R10, libcall_n(R11) |
| 241 | MOVQ 168(SP), R10 |
| 242 | MOVQ R10, libcall_r1(R11) |
| 243 | MOVQ 176(SP), R10 |
| 244 | MOVQ R10, libcall_r2(R11) |
| 245 | |
| 246 | // restore scratch |
| 247 | LEAQ m_scratch(BP), R11 |
| 248 | MOVQ 112(SP), R10 |
| 249 | MOVQ R10, 0(R11) |
| 250 | MOVQ 120(SP), R10 |
| 251 | MOVQ R10, 8(R11) |
| 252 | MOVQ 128(SP), R10 |
| 253 | MOVQ R10, 16(R11) |
| 254 | MOVQ 136(SP), R10 |
| 255 | MOVQ R10, 24(R11) |
| 256 | MOVQ 144(SP), R10 |
| 257 | MOVQ R10, 32(R11) |
| 258 | MOVQ 152(SP), R10 |
| 259 | MOVQ R10, 40(R11) |
| 260 | |
| 261 | // restore errno |
| 262 | MOVQ m_perrno(BP), R11 |
| 263 | MOVQ 160(SP), R10 |
| 264 | MOVL R10, 0(R11) |
| 265 | |
| 266 | // restore g |
| 267 | MOVQ 80(SP), R10 |
| 268 | MOVQ R10, g(BX) |
| 269 | |
Aram Hăvărneanu | d7b678b | 2014-07-02 09:34:06 +1000 | [diff] [blame] | 270 | exit: |
Aram Hăvărneanu | a46b434 | 2014-01-17 17:58:10 +1300 | [diff] [blame] | 271 | // restore registers |
| 272 | MOVQ 32(SP), BX |
| 273 | MOVQ 40(SP), BP |
| 274 | MOVQ 48(SP), R12 |
| 275 | MOVQ 56(SP), R13 |
| 276 | MOVQ 64(SP), R14 |
| 277 | MOVQ 72(SP), R15 |
| 278 | |
| 279 | ADDQ $184, SP |
| 280 | RET |
Aram Hăvărneanu | df75f08 | 2014-07-03 11:36:05 +1000 | [diff] [blame] | 281 | |
| 282 | // Called from runtime·usleep (Go). Can be called on Go stack, on OS stack, |
| 283 | // can also be called in cgo callback path without a g->m. |
| 284 | TEXT runtime·usleep1(SB),NOSPLIT,$0 |
Russ Cox | 25f6b02 | 2014-08-27 11:32:17 -0400 | [diff] [blame] | 285 | MOVL usec+0(FP), DI |
Aram Hăvărneanu | df75f08 | 2014-07-03 11:36:05 +1000 | [diff] [blame] | 286 | MOVQ $runtime·usleep2(SB), AX // to hide from 6l |
| 287 | |
| 288 | // Execute call on m->g0. |
| 289 | get_tls(R15) |
| 290 | CMPQ R15, $0 |
Russ Cox | b55791e | 2014-10-28 21:50:16 -0400 | [diff] [blame] | 291 | JE noswitch |
Aram Hăvărneanu | df75f08 | 2014-07-03 11:36:05 +1000 | [diff] [blame] | 292 | |
| 293 | MOVQ g(R15), R13 |
| 294 | CMPQ R13, $0 |
Russ Cox | b55791e | 2014-10-28 21:50:16 -0400 | [diff] [blame] | 295 | JE noswitch |
Aram Hăvărneanu | df75f08 | 2014-07-03 11:36:05 +1000 | [diff] [blame] | 296 | MOVQ g_m(R13), R13 |
| 297 | CMPQ R13, $0 |
Russ Cox | b55791e | 2014-10-28 21:50:16 -0400 | [diff] [blame] | 298 | JE noswitch |
Aram Hăvărneanu | df75f08 | 2014-07-03 11:36:05 +1000 | [diff] [blame] | 299 | // TODO(aram): do something about the cpu profiler here. |
| 300 | |
| 301 | MOVQ m_g0(R13), R14 |
| 302 | CMPQ g(R15), R14 |
Russ Cox | b55791e | 2014-10-28 21:50:16 -0400 | [diff] [blame] | 303 | JNE switch |
Aram Hăvărneanu | df75f08 | 2014-07-03 11:36:05 +1000 | [diff] [blame] | 304 | // executing on m->g0 already |
| 305 | CALL AX |
| 306 | RET |
| 307 | |
Russ Cox | b55791e | 2014-10-28 21:50:16 -0400 | [diff] [blame] | 308 | switch: |
Aram Hăvărneanu | df75f08 | 2014-07-03 11:36:05 +1000 | [diff] [blame] | 309 | // Switch to m->g0 stack and back. |
| 310 | MOVQ (g_sched+gobuf_sp)(R14), R14 |
| 311 | MOVQ SP, -8(R14) |
| 312 | LEAQ -8(R14), SP |
| 313 | CALL AX |
| 314 | MOVQ 0(SP), SP |
| 315 | RET |
| 316 | |
Russ Cox | b55791e | 2014-10-28 21:50:16 -0400 | [diff] [blame] | 317 | noswitch: |
Aram Hăvărneanu | df75f08 | 2014-07-03 11:36:05 +1000 | [diff] [blame] | 318 | // Not a Go-managed thread. Do not switch stack. |
| 319 | CALL AX |
| 320 | RET |
| 321 | |
| 322 | // Runs on OS stack. duration (in µs units) is in DI. |
| 323 | TEXT runtime·usleep2(SB),NOSPLIT,$0 |
Aram Hăvărneanu | c94f1f7 | 2015-03-30 13:52:07 +0200 | [diff] [blame] | 324 | LEAQ libc_usleep(SB), AX |
Aram Hăvărneanu | df75f08 | 2014-07-03 11:36:05 +1000 | [diff] [blame] | 325 | CALL AX |
| 326 | RET |
| 327 | |
| 328 | // Runs on OS stack, called from runtime·osyield. |
| 329 | TEXT runtime·osyield1(SB),NOSPLIT,$0 |
Aram Hăvărneanu | c94f1f7 | 2015-03-30 13:52:07 +0200 | [diff] [blame] | 330 | LEAQ libc_sched_yield(SB), AX |
Aram Hăvărneanu | df75f08 | 2014-07-03 11:36:05 +1000 | [diff] [blame] | 331 | CALL AX |
| 332 | RET |
Russ Cox | 13d0b82 | 2014-09-07 23:40:59 -0400 | [diff] [blame] | 333 | |
| 334 | // func now() (sec int64, nsec int32) |
| 335 | TEXT time·now(SB),NOSPLIT,$8-12 |
| 336 | CALL runtime·nanotime(SB) |
| 337 | MOVQ 0(SP), AX |
| 338 | |
| 339 | // generated code for |
| 340 | // func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 } |
| 341 | // adapted to reduce duplication |
| 342 | MOVQ AX, CX |
| 343 | MOVQ $1360296554856532783, AX |
| 344 | MULQ CX |
| 345 | ADDQ CX, DX |
| 346 | RCRQ $1, DX |
| 347 | SHRQ $29, DX |
| 348 | MOVQ DX, sec+0(FP) |
| 349 | IMULQ $1000000000, DX |
| 350 | SUBQ DX, CX |
| 351 | MOVL CX, nsec+8(FP) |
| 352 | RET |