Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 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 | |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 5 | #include "386/asm.h" |
| 6 | |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 7 | TEXT _rt0_386(SB),7,$0 |
| 8 | // copy arguments forward on an even stack |
| 9 | MOVL 0(SP), AX // argc |
| 10 | LEAL 4(SP), BX // argv |
| 11 | SUBL $128, SP // plenty of scratch |
Russ Cox | 133a158 | 2009-10-03 10:37:12 -0700 | [diff] [blame^] | 12 | ANDL $~15, SP |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 13 | MOVL AX, 120(SP) // save argc, argv away |
| 14 | MOVL BX, 124(SP) |
| 15 | |
Russ Cox | 133a158 | 2009-10-03 10:37:12 -0700 | [diff] [blame^] | 16 | // if there is an initcgo, call it to let it |
| 17 | // initialize and to set up GS. if not, |
| 18 | // we set up GS ourselves. |
| 19 | MOVL initcgo(SB), AX |
| 20 | TESTL AX, AX |
| 21 | JZ 3(PC) |
| 22 | CALL AX |
| 23 | JMP ok |
| 24 | |
Russ Cox | 1b14bdb | 2009-09-22 16:28:32 -0700 | [diff] [blame] | 25 | // set up %gs |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 26 | CALL ldt0setup(SB) |
| 27 | |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 28 | // store through it, to make sure it works |
Russ Cox | bbcb91a | 2009-09-21 15:46:50 -0700 | [diff] [blame] | 29 | MOVL $0x123, 0(GS) |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 30 | MOVL tls0(SB), AX |
| 31 | CMPL AX, $0x123 |
| 32 | JEQ ok |
Russ Cox | 133a158 | 2009-10-03 10:37:12 -0700 | [diff] [blame^] | 33 | MOVL AX, 0 // abort |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 34 | ok: |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 35 | // set up m and g "registers" |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 36 | LEAL g0(SB), CX |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 37 | MOVL CX, g |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 38 | LEAL m0(SB), AX |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 39 | MOVL AX, m |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 40 | |
| 41 | // save m->g0 = g0 |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 42 | MOVL CX, m_g0(AX) |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 43 | |
| 44 | // create istack out of the OS stack |
| 45 | LEAL (-8192+104)(SP), AX // TODO: 104? |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 46 | MOVL AX, g_stackguard(CX) |
| 47 | MOVL SP, g_stackbase(CX) |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 48 | CALL emptyfunc(SB) // fault if stack check is wrong |
| 49 | |
| 50 | // convention is D is always cleared |
| 51 | CLD |
| 52 | |
| 53 | CALL check(SB) |
| 54 | |
| 55 | // saved argc, argv |
| 56 | MOVL 120(SP), AX |
| 57 | MOVL AX, 0(SP) |
| 58 | MOVL 124(SP), AX |
| 59 | MOVL AX, 4(SP) |
| 60 | CALL args(SB) |
| 61 | CALL osinit(SB) |
| 62 | CALL schedinit(SB) |
| 63 | |
| 64 | // create a new goroutine to start program |
| 65 | PUSHL $mainstart(SB) // entry |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 66 | PUSHL $0 // arg size |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 67 | CALL sys·newproc(SB) |
| 68 | POPL AX |
| 69 | POPL AX |
| 70 | |
| 71 | // start this M |
| 72 | CALL mstart(SB) |
| 73 | |
| 74 | INT $3 |
| 75 | RET |
| 76 | |
| 77 | TEXT mainstart(SB),7,$0 |
| 78 | CALL main·init(SB) |
| 79 | CALL initdone(SB) |
| 80 | CALL main·main(SB) |
| 81 | PUSHL $0 |
Russ Cox | 918afd94 | 2009-05-08 15:21:41 -0700 | [diff] [blame] | 82 | CALL exit(SB) |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 83 | POPL AX |
| 84 | INT $3 |
| 85 | RET |
| 86 | |
Russ Cox | 918afd94 | 2009-05-08 15:21:41 -0700 | [diff] [blame] | 87 | TEXT breakpoint(SB),7,$0 |
Russ Cox | 1b14bdb | 2009-09-22 16:28:32 -0700 | [diff] [blame] | 88 | INT $3 |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 89 | RET |
| 90 | |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 91 | /* |
| 92 | * go-routine |
| 93 | */ |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 94 | |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 95 | // uintptr gosave(Gobuf*) |
| 96 | // save state in Gobuf; setjmp |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 97 | TEXT gosave(SB), 7, $0 |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 98 | MOVL 4(SP), AX // gobuf |
| 99 | LEAL 4(SP), BX // caller's SP |
| 100 | MOVL BX, gobuf_sp(AX) |
| 101 | MOVL 0(SP), BX // caller's PC |
| 102 | MOVL BX, gobuf_pc(AX) |
| 103 | MOVL g, BX |
| 104 | MOVL BX, gobuf_g(AX) |
| 105 | MOVL $0, AX // return 0 |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 106 | RET |
| 107 | |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 108 | // void gogo(Gobuf*, uintptr) |
| 109 | // restore state from Gobuf; longjmp |
| 110 | TEXT gogo(SB), 7, $0 |
| 111 | MOVL 8(SP), AX // return 2nd arg |
| 112 | MOVL 4(SP), BX // gobuf |
| 113 | MOVL gobuf_g(BX), DX |
| 114 | MOVL 0(DX), CX // make sure g != nil |
| 115 | MOVL DX, g |
| 116 | MOVL gobuf_sp(BX), SP // restore SP |
| 117 | MOVL gobuf_pc(BX), BX |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 118 | JMP BX |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 119 | |
| 120 | // void gogocall(Gobuf*, void (*fn)(void)) |
| 121 | // restore state from Gobuf but then call fn. |
| 122 | // (call fn, returning to state in Gobuf) |
| 123 | TEXT gogocall(SB), 7, $0 |
| 124 | MOVL 8(SP), AX // fn |
| 125 | MOVL 4(SP), BX // gobuf |
| 126 | MOVL gobuf_g(BX), DX |
| 127 | MOVL DX, g |
| 128 | MOVL 0(DX), CX // make sure g != nil |
| 129 | MOVL gobuf_sp(BX), SP // restore SP |
| 130 | MOVL gobuf_pc(BX), BX |
| 131 | PUSHL BX |
| 132 | JMP AX |
| 133 | POPL BX // not reached |
| 134 | |
| 135 | /* |
| 136 | * support for morestack |
| 137 | */ |
| 138 | |
| 139 | // Called during function prolog when more stack is needed. |
| 140 | TEXT sys·morestack(SB),7,$0 |
| 141 | // Cannot grow scheduler stack (m->g0). |
| 142 | MOVL m, BX |
| 143 | MOVL m_g0(BX), SI |
| 144 | CMPL g, SI |
| 145 | JNE 2(PC) |
| 146 | INT $3 |
| 147 | |
| 148 | // frame size in DX |
| 149 | // arg size in AX |
| 150 | // Save in m. |
| 151 | MOVL DX, m_moreframe(BX) |
| 152 | MOVL AX, m_moreargs(BX) |
| 153 | |
| 154 | // Called from f. |
| 155 | // Set m->morebuf to f's caller. |
| 156 | MOVL 4(SP), DI // f's caller's PC |
| 157 | MOVL DI, (m_morebuf+gobuf_pc)(BX) |
| 158 | LEAL 8(SP), CX // f's caller's SP |
| 159 | MOVL CX, (m_morebuf+gobuf_sp)(BX) |
Russ Cox | bba278a | 2009-07-08 18:16:09 -0700 | [diff] [blame] | 160 | MOVL CX, (m_morefp)(BX) |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 161 | MOVL g, SI |
| 162 | MOVL SI, (m_morebuf+gobuf_g)(BX) |
| 163 | |
| 164 | // Set m->morepc to f's PC. |
| 165 | MOVL 0(SP), AX |
| 166 | MOVL AX, m_morepc(BX) |
| 167 | |
| 168 | // Call newstack on m's scheduling stack. |
| 169 | MOVL m_g0(BX), BP |
| 170 | MOVL BP, g |
| 171 | MOVL (m_sched+gobuf_sp)(BX), SP |
| 172 | CALL newstack(SB) |
| 173 | MOVL $0, 0x1003 // crash if newstack returns |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 174 | RET |
| 175 | |
Russ Cox | bba278a | 2009-07-08 18:16:09 -0700 | [diff] [blame] | 176 | // Called from reflection library. Mimics morestack, |
| 177 | // reuses stack growth code to create a frame |
| 178 | // with the desired args running the desired function. |
| 179 | // |
| 180 | // func call(fn *byte, arg *byte, argsize uint32). |
| 181 | TEXT reflect·call(SB), 7, $0 |
| 182 | MOVL m, BX |
| 183 | |
| 184 | // Save our caller's state as the PC and SP to |
| 185 | // restore when returning from f. |
| 186 | MOVL 0(SP), AX // our caller's PC |
| 187 | MOVL AX, (m_morebuf+gobuf_pc)(BX) |
| 188 | LEAL 4(SP), AX // our caller's SP |
| 189 | MOVL AX, (m_morebuf+gobuf_sp)(BX) |
| 190 | MOVL g, AX |
| 191 | MOVL AX, (m_morebuf+gobuf_g)(BX) |
| 192 | |
| 193 | // Set up morestack arguments to call f on a new stack. |
| 194 | // We set f's frame size to zero, meaning |
| 195 | // allocate a standard sized stack segment. |
| 196 | // If it turns out that f needs a larger frame than this, |
| 197 | // f's usual stack growth prolog will allocate |
| 198 | // a new segment (and recopy the arguments). |
| 199 | MOVL 4(SP), AX // fn |
| 200 | MOVL 8(SP), DX // arg frame |
| 201 | MOVL 12(SP), CX // arg size |
| 202 | |
| 203 | MOVL AX, m_morepc(BX) // f's PC |
| 204 | MOVL DX, m_morefp(BX) // argument frame pointer |
| 205 | MOVL CX, m_moreargs(BX) // f's argument size |
| 206 | MOVL $0, m_moreframe(BX) // f's frame size |
| 207 | |
| 208 | // Call newstack on m's scheduling stack. |
| 209 | MOVL m_g0(BX), BP |
| 210 | MOVL BP, g |
| 211 | MOVL (m_sched+gobuf_sp)(BX), SP |
| 212 | CALL newstack(SB) |
| 213 | MOVL $0, 0x1103 // crash if newstack returns |
| 214 | RET |
| 215 | |
| 216 | |
Russ Cox | 8522a47 | 2009-06-17 15:15:55 -0700 | [diff] [blame] | 217 | // Return point when leaving stack. |
| 218 | TEXT sys·lessstack(SB), 7, $0 |
| 219 | // Save return value in m->cret |
| 220 | MOVL m, BX |
| 221 | MOVL AX, m_cret(BX) |
| 222 | |
| 223 | // Call oldstack on m's scheduling stack. |
| 224 | MOVL m_g0(BX), DX |
| 225 | MOVL DX, g |
| 226 | MOVL (m_sched+gobuf_sp)(BX), SP |
| 227 | CALL oldstack(SB) |
| 228 | MOVL $0, 0x1004 // crash if oldstack returns |
| 229 | RET |
| 230 | |
| 231 | |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 232 | // bool cas(int32 *val, int32 old, int32 new) |
| 233 | // Atomically: |
| 234 | // if(*val == old){ |
| 235 | // *val = new; |
| 236 | // return 1; |
| 237 | // }else |
| 238 | // return 0; |
| 239 | TEXT cas(SB), 7, $0 |
| 240 | MOVL 4(SP), BX |
| 241 | MOVL 8(SP), AX |
| 242 | MOVL 12(SP), CX |
| 243 | LOCK |
| 244 | CMPXCHGL CX, 0(BX) |
| 245 | JZ 3(PC) |
| 246 | MOVL $0, AX |
| 247 | RET |
| 248 | MOVL $1, AX |
| 249 | RET |
| 250 | |
Russ Cox | aa3222d8 | 2009-06-02 23:02:12 -0700 | [diff] [blame] | 251 | // void jmpdefer(fn, sp); |
| 252 | // called from deferreturn. |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 253 | // 1. pop the caller |
| 254 | // 2. sub 5 bytes from the callers return |
| 255 | // 3. jmp to the argument |
| 256 | TEXT jmpdefer(SB), 7, $0 |
Russ Cox | aa3222d8 | 2009-06-02 23:02:12 -0700 | [diff] [blame] | 257 | MOVL 4(SP), AX // fn |
| 258 | MOVL 8(SP), BX // caller sp |
| 259 | LEAL -4(BX), SP // caller sp after CALL |
| 260 | SUBL $5, (SP) // return to CALL again |
| 261 | JMP AX // but first run the deferred function |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 262 | |
| 263 | TEXT sys·memclr(SB),7,$0 |
| 264 | MOVL 4(SP), DI // arg 1 addr |
| 265 | MOVL 8(SP), CX // arg 2 count |
| 266 | ADDL $3, CX |
| 267 | SHRL $2, CX |
| 268 | MOVL $0, AX |
| 269 | CLD |
| 270 | REP |
| 271 | STOSL |
| 272 | RET |
| 273 | |
| 274 | TEXT sys·getcallerpc+0(SB),7,$0 |
| 275 | MOVL x+0(FP),AX // addr of first arg |
| 276 | MOVL -4(AX),AX // get calling pc |
| 277 | RET |
| 278 | |
| 279 | TEXT sys·setcallerpc+0(SB),7,$0 |
| 280 | MOVL x+0(FP),AX // addr of first arg |
| 281 | MOVL x+4(FP), BX |
| 282 | MOVL BX, -4(AX) // set calling pc |
| 283 | RET |
| 284 | |
| 285 | TEXT ldt0setup(SB),7,$16 |
| 286 | // set up ldt 7 to point at tls0 |
| 287 | // ldt 1 would be fine on Linux, but on OS X, 7 is as low as we can go. |
Russ Cox | 1b14bdb | 2009-09-22 16:28:32 -0700 | [diff] [blame] | 288 | // the entry number is just a hint. setldt will set up GS with what it used. |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 289 | MOVL $7, 0(SP) |
| 290 | LEAL tls0(SB), AX |
| 291 | MOVL AX, 4(SP) |
| 292 | MOVL $32, 8(SP) // sizeof(tls array) |
| 293 | CALL setldt(SB) |
| 294 | RET |
| 295 | |
Russ Cox | 0d3a043 | 2009-03-30 00:01:07 -0700 | [diff] [blame] | 296 | TEXT emptyfunc(SB),0,$0 |
| 297 | RET |
| 298 | |
| 299 | TEXT abort(SB),7,$0 |
| 300 | INT $0x3 |
Russ Cox | 133a158 | 2009-10-03 10:37:12 -0700 | [diff] [blame^] | 301 | |
| 302 | // runcgo(void(*fn)(void*), void *arg) |
| 303 | // Just call fn(arg), but first align the stack |
| 304 | // appropriately for the gcc ABI. |
| 305 | TEXT runcgo(SB),7,$16 |
| 306 | MOVL fn+0(FP), AX |
| 307 | MOVL arg+4(FP), BX |
| 308 | MOVL SP, CX |
| 309 | ANDL $~15, SP // alignment for gcc ABI |
| 310 | MOVL CX, 4(SP) |
| 311 | MOVL BX, 0(SP) |
| 312 | CALL AX |
| 313 | MOVL 4(SP), SP |
| 314 | RET |
| 315 | |
| 316 | |
| 317 | GLOBL m0(SB), $1024 |
| 318 | GLOBL g0(SB), $1024 |
| 319 | GLOBL tls0(SB), $32 |
| 320 | GLOBL initcgo(SB), $4 |
| 321 | |