| // Copyright 2013 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| #include "go_asm.h" | |
| #include "go_tls.h" | |
| #include "textflag.h" | |
| #include "syscall_nacl.h" | |
| #define NACL_SYSCALL(code) \ | |
| MOVL $(0x10000 + ((code)<<5)), AX; CALL AX | |
| TEXT runtime·settls(SB),NOSPLIT,$0 | |
| MOVL DI, TLS // really BP | |
| RET | |
| TEXT runtime·exit(SB),NOSPLIT,$0 | |
| MOVL code+0(FP), DI | |
| NACL_SYSCALL(SYS_exit) | |
| RET | |
| TEXT runtime·exit1(SB),NOSPLIT,$0 | |
| MOVL code+0(FP), DI | |
| NACL_SYSCALL(SYS_thread_exit) | |
| RET | |
| TEXT runtime·open(SB),NOSPLIT,$0 | |
| MOVL name+0(FP), DI | |
| MOVL mode+4(FP), SI | |
| MOVL perm+8(FP), DX | |
| NACL_SYSCALL(SYS_open) | |
| MOVL AX, ret+16(FP) | |
| RET | |
| TEXT runtime·closefd(SB),NOSPLIT,$0 | |
| MOVL fd+0(FP), DI | |
| NACL_SYSCALL(SYS_close) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·read(SB),NOSPLIT,$0 | |
| MOVL fd+0(FP), DI | |
| MOVL p+4(FP), SI | |
| MOVL n+8(FP), DX | |
| NACL_SYSCALL(SYS_read) | |
| MOVL AX, ret+16(FP) | |
| RET | |
| TEXT syscall·naclWrite(SB), NOSPLIT, $24-20 | |
| MOVL arg1+0(FP), DI | |
| MOVL arg2+4(FP), SI | |
| MOVL arg3+8(FP), DX | |
| MOVL DI, 0(SP) | |
| MOVL SI, 4(SP) | |
| MOVL DX, 8(SP) | |
| CALL runtime·write(SB) | |
| MOVL 16(SP), AX | |
| MOVL AX, ret+16(FP) | |
| RET | |
| TEXT runtime·write(SB),NOSPLIT,$16-20 | |
| // If using fake time and writing to stdout or stderr, | |
| // emit playback header before actual data. | |
| MOVQ runtime·faketime(SB), AX | |
| CMPQ AX, $0 | |
| JEQ write | |
| MOVL fd+0(FP), DI | |
| CMPL DI, $1 | |
| JEQ playback | |
| CMPL DI, $2 | |
| JEQ playback | |
| write: | |
| // Ordinary write. | |
| MOVL fd+0(FP), DI | |
| MOVL p+4(FP), SI | |
| MOVL n+8(FP), DX | |
| NACL_SYSCALL(SYS_write) | |
| MOVL AX, ret+16(FP) | |
| RET | |
| // Write with playback header. | |
| // First, lock to avoid interleaving writes. | |
| playback: | |
| MOVL $1, BX | |
| XCHGL runtime·writelock(SB), BX | |
| CMPL BX, $0 | |
| JNE playback | |
| // Playback header: 0 0 P B <8-byte time> <4-byte data length> | |
| MOVL $(('B'<<24) | ('P'<<16)), 0(SP) | |
| BSWAPQ AX | |
| MOVQ AX, 4(SP) | |
| MOVL n+8(FP), DX | |
| BSWAPL DX | |
| MOVL DX, 12(SP) | |
| MOVL fd+0(FP), DI | |
| MOVL SP, SI | |
| MOVL $16, DX | |
| NACL_SYSCALL(SYS_write) | |
| // Write actual data. | |
| MOVL fd+0(FP), DI | |
| MOVL p+4(FP), SI | |
| MOVL n+8(FP), DX | |
| NACL_SYSCALL(SYS_write) | |
| // Unlock. | |
| MOVL $0, runtime·writelock(SB) | |
| MOVL AX, ret+16(FP) | |
| RET | |
| TEXT runtime·nacl_exception_stack(SB),NOSPLIT,$0 | |
| MOVL p+0(FP), DI | |
| MOVL size+4(FP), SI | |
| NACL_SYSCALL(SYS_exception_stack) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_exception_handler(SB),NOSPLIT,$0 | |
| MOVL fn+0(FP), DI | |
| MOVL arg+4(FP), SI | |
| NACL_SYSCALL(SYS_exception_handler) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_sem_create(SB),NOSPLIT,$0 | |
| MOVL flag+0(FP), DI | |
| NACL_SYSCALL(SYS_sem_create) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_sem_wait(SB),NOSPLIT,$0 | |
| MOVL sem+0(FP), DI | |
| NACL_SYSCALL(SYS_sem_wait) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_sem_post(SB),NOSPLIT,$0 | |
| MOVL sem+0(FP), DI | |
| NACL_SYSCALL(SYS_sem_post) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_mutex_create(SB),NOSPLIT,$0 | |
| MOVL flag+0(FP), DI | |
| NACL_SYSCALL(SYS_mutex_create) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_mutex_lock(SB),NOSPLIT,$0 | |
| MOVL mutex+0(FP), DI | |
| NACL_SYSCALL(SYS_mutex_lock) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_mutex_trylock(SB),NOSPLIT,$0 | |
| MOVL mutex+0(FP), DI | |
| NACL_SYSCALL(SYS_mutex_trylock) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_mutex_unlock(SB),NOSPLIT,$0 | |
| MOVL mutex+0(FP), DI | |
| NACL_SYSCALL(SYS_mutex_unlock) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_cond_create(SB),NOSPLIT,$0 | |
| MOVL flag+0(FP), DI | |
| NACL_SYSCALL(SYS_cond_create) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_cond_wait(SB),NOSPLIT,$0 | |
| MOVL cond+0(FP), DI | |
| MOVL n+4(FP), SI | |
| NACL_SYSCALL(SYS_cond_wait) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_cond_signal(SB),NOSPLIT,$0 | |
| MOVL cond+0(FP), DI | |
| NACL_SYSCALL(SYS_cond_signal) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_cond_broadcast(SB),NOSPLIT,$0 | |
| MOVL cond+0(FP), DI | |
| NACL_SYSCALL(SYS_cond_broadcast) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nacl_cond_timed_wait_abs(SB),NOSPLIT,$0 | |
| MOVL cond+0(FP), DI | |
| MOVL lock+4(FP), SI | |
| MOVL ts+8(FP), DX | |
| NACL_SYSCALL(SYS_cond_timed_wait_abs) | |
| MOVL AX, ret+16(FP) | |
| RET | |
| TEXT runtime·nacl_thread_create(SB),NOSPLIT,$0 | |
| MOVL fn+0(FP), DI | |
| MOVL stk+4(FP), SI | |
| MOVL tls+8(FP), DX | |
| MOVL xx+12(FP), CX | |
| NACL_SYSCALL(SYS_thread_create) | |
| MOVL AX, ret+16(FP) | |
| RET | |
| TEXT runtime·mstart_nacl(SB),NOSPLIT,$0 | |
| NACL_SYSCALL(SYS_tls_get) | |
| SUBL $8, AX | |
| MOVL AX, TLS | |
| JMP runtime·mstart(SB) | |
| TEXT runtime·nacl_nanosleep(SB),NOSPLIT,$0 | |
| MOVL ts+0(FP), DI | |
| MOVL extra+4(FP), SI | |
| NACL_SYSCALL(SYS_nanosleep) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·osyield(SB),NOSPLIT,$0 | |
| NACL_SYSCALL(SYS_sched_yield) | |
| RET | |
| TEXT runtime·mmap(SB),NOSPLIT,$8 | |
| MOVL addr+0(FP), DI | |
| MOVL n+4(FP), SI | |
| MOVL prot+8(FP), DX | |
| MOVL flags+12(FP), CX | |
| MOVL fd+16(FP), R8 | |
| MOVL off+20(FP), AX | |
| MOVQ AX, 0(SP) | |
| MOVL SP, R9 | |
| NACL_SYSCALL(SYS_mmap) | |
| CMPL AX, $-4095 | |
| JNA 2(PC) | |
| NEGL AX | |
| MOVL AX, ret+24(FP) | |
| RET | |
| TEXT time·now(SB),NOSPLIT,$16 | |
| MOVQ runtime·faketime(SB), AX | |
| CMPQ AX, $0 | |
| JEQ realtime | |
| MOVQ $0, DX | |
| MOVQ $1000000000, CX | |
| DIVQ CX | |
| MOVQ AX, sec+0(FP) | |
| MOVL DX, nsec+8(FP) | |
| RET | |
| realtime: | |
| MOVL $0, DI // real time clock | |
| LEAL 0(SP), AX | |
| MOVL AX, SI // timespec | |
| NACL_SYSCALL(SYS_clock_gettime) | |
| MOVL 0(SP), AX // low 32 sec | |
| MOVL 4(SP), CX // high 32 sec | |
| MOVL 8(SP), BX // nsec | |
| // sec is in AX, nsec in BX | |
| MOVL AX, sec+0(FP) | |
| MOVL CX, sec+4(FP) | |
| MOVL BX, nsec+8(FP) | |
| RET | |
| TEXT syscall·now(SB),NOSPLIT,$0 | |
| JMP time·now(SB) | |
| TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0 | |
| MOVL arg1+0(FP), DI | |
| MOVL arg2+4(FP), SI | |
| NACL_SYSCALL(SYS_clock_gettime) | |
| MOVL AX, ret+8(FP) | |
| RET | |
| TEXT runtime·nanotime(SB),NOSPLIT,$16 | |
| MOVQ runtime·faketime(SB), AX | |
| CMPQ AX, $0 | |
| JEQ 3(PC) | |
| MOVQ AX, ret+0(FP) | |
| RET | |
| MOVL $0, DI // real time clock | |
| LEAL 0(SP), AX | |
| MOVL AX, SI // timespec | |
| NACL_SYSCALL(SYS_clock_gettime) | |
| MOVQ 0(SP), AX // sec | |
| MOVL 8(SP), DX // nsec | |
| // sec is in AX, nsec in DX | |
| // return nsec in AX | |
| IMULQ $1000000000, AX | |
| ADDQ DX, AX | |
| MOVQ AX, ret+0(FP) | |
| RET | |
| TEXT runtime·sigtramp(SB),NOSPLIT,$80 | |
| // restore TLS register at time of execution, | |
| // in case it's been smashed. | |
| // the TLS register is really BP, but for consistency | |
| // with non-NaCl systems it is referred to here as TLS. | |
| // NOTE: Cannot use SYS_tls_get here (like we do in mstart_nacl), | |
| // because the main thread never calls tls_set. | |
| LEAL ctxt+0(FP), AX | |
| MOVL (16*4+5*8)(AX), AX | |
| MOVL AX, TLS | |
| // check that g exists | |
| get_tls(CX) | |
| MOVL g(CX), DI | |
| CMPL DI, $0 | |
| JEQ nog | |
| // save g | |
| MOVL DI, 20(SP) | |
| // g = m->gsignal | |
| MOVL g_m(DI), BX | |
| MOVL m_gsignal(BX), BX | |
| MOVL BX, g(CX) | |
| //JMP debughandler | |
| // copy arguments for sighandler | |
| MOVL $11, 0(SP) // signal | |
| MOVL $0, 4(SP) // siginfo | |
| LEAL ctxt+0(FP), AX | |
| MOVL AX, 8(SP) // context | |
| MOVL DI, 12(SP) // g | |
| CALL runtime·sighandler(SB) | |
| // restore g | |
| get_tls(CX) | |
| MOVL 20(SP), BX | |
| MOVL BX, g(CX) | |
| // Enable exceptions again. | |
| NACL_SYSCALL(SYS_exception_clear_flag) | |
| // Restore registers as best we can. Impossible to do perfectly. | |
| // See comment in sys_nacl_386.s for extended rationale. | |
| LEAL ctxt+0(FP), SI | |
| ADDL $64, SI | |
| MOVQ 0(SI), AX | |
| MOVQ 8(SI), CX | |
| MOVQ 16(SI), DX | |
| MOVQ 24(SI), BX | |
| MOVL 32(SI), SP // MOVL for SP sandboxing | |
| // 40(SI) is saved BP aka TLS, already restored above | |
| // 48(SI) is saved SI, never to be seen again | |
| MOVQ 56(SI), DI | |
| MOVQ 64(SI), R8 | |
| MOVQ 72(SI), R9 | |
| MOVQ 80(SI), R10 | |
| MOVQ 88(SI), R11 | |
| MOVQ 96(SI), R12 | |
| MOVQ 104(SI), R13 | |
| MOVQ 112(SI), R14 | |
| // 120(SI) is R15, which is owned by Native Client and must not be modified | |
| MOVQ 128(SI), SI // saved PC | |
| // 136(SI) is saved EFLAGS, never to be seen again | |
| JMP SI | |
| debughandler: | |
| // print basic information | |
| LEAL ctxt+0(FP), DI | |
| MOVL $runtime·sigtrampf(SB), AX | |
| MOVL AX, 0(SP) | |
| MOVQ (16*4+16*8)(DI), BX // rip | |
| MOVQ BX, 8(SP) | |
| MOVQ (16*4+0*8)(DI), BX // rax | |
| MOVQ BX, 16(SP) | |
| MOVQ (16*4+1*8)(DI), BX // rcx | |
| MOVQ BX, 24(SP) | |
| MOVQ (16*4+2*8)(DI), BX // rdx | |
| MOVQ BX, 32(SP) | |
| MOVQ (16*4+3*8)(DI), BX // rbx | |
| MOVQ BX, 40(SP) | |
| MOVQ (16*4+7*8)(DI), BX // rdi | |
| MOVQ BX, 48(SP) | |
| MOVQ (16*4+15*8)(DI), BX // r15 | |
| MOVQ BX, 56(SP) | |
| MOVQ (16*4+4*8)(DI), BX // rsp | |
| MOVQ 0(BX), BX | |
| MOVQ BX, 64(SP) | |
| CALL runtime·printf(SB) | |
| LEAL ctxt+0(FP), DI | |
| MOVQ (16*4+16*8)(DI), BX // rip | |
| MOVL BX, 0(SP) | |
| MOVQ (16*4+4*8)(DI), BX // rsp | |
| MOVL BX, 4(SP) | |
| MOVL $0, 8(SP) // lr | |
| get_tls(CX) | |
| MOVL g(CX), BX | |
| MOVL BX, 12(SP) // gp | |
| CALL runtime·traceback(SB) | |
| notls: | |
| MOVL 0, AX | |
| RET | |
| nog: | |
| MOVL 0, AX | |
| RET | |
| // cannot do real signal handling yet, because gsignal has not been allocated. | |
| MOVL $1, DI; NACL_SYSCALL(SYS_exit) | |
| // func getRandomData([]byte) | |
| TEXT runtime·getRandomData(SB),NOSPLIT,$0-12 | |
| MOVL buf+0(FP), DI | |
| MOVL len+4(FP), SI | |
| NACL_SYSCALL(SYS_get_random_bytes) | |
| RET | |
| TEXT runtime·nacl_sysinfo(SB),NOSPLIT,$16 | |
| /* | |
| MOVL di+0(FP), DI | |
| LEAL 12(DI), BX | |
| MOVL 8(DI), AX | |
| ADDL 4(DI), AX | |
| ADDL $2, AX | |
| LEAL (BX)(AX*4), BX | |
| MOVL BX, runtime·nacl_irt_query(SB) | |
| auxloop: | |
| MOVL 0(BX), DX | |
| CMPL DX, $0 | |
| JNE 2(PC) | |
| RET | |
| CMPL DX, $32 | |
| JEQ auxfound | |
| ADDL $8, BX | |
| JMP auxloop | |
| auxfound: | |
| MOVL 4(BX), BX | |
| MOVL BX, runtime·nacl_irt_query(SB) | |
| LEAL runtime·nacl_irt_basic_v0_1_str(SB), DI | |
| LEAL runtime·nacl_irt_basic_v0_1(SB), SI | |
| MOVL runtime·nacl_irt_basic_v0_1_size(SB), DX | |
| MOVL runtime·nacl_irt_query(SB), BX | |
| CALL BX | |
| LEAL runtime·nacl_irt_memory_v0_3_str(SB), DI | |
| LEAL runtime·nacl_irt_memory_v0_3(SB), SI | |
| MOVL runtime·nacl_irt_memory_v0_3_size(SB), DX | |
| MOVL runtime·nacl_irt_query(SB), BX | |
| CALL BX | |
| LEAL runtime·nacl_irt_thread_v0_1_str(SB), DI | |
| LEAL runtime·nacl_irt_thread_v0_1(SB), SI | |
| MOVL runtime·nacl_irt_thread_v0_1_size(SB), DX | |
| MOVL runtime·nacl_irt_query(SB), BX | |
| CALL BX | |
| // TODO: Once we have a NaCl SDK with futex syscall support, | |
| // try switching to futex syscalls and here load the | |
| // nacl-irt-futex-0.1 table. | |
| */ | |
| RET |