// The body of kern_ap_stub (kernel.c, "asynchronous preemption"), included once per register width with AP_NAME the // function's name, AP_VMOV and AP_V the move and the register prefix that save the vector registers, and AP_VZEROUPPER // the instruction that ends the use of the upper halves (or nothing). No include guard: kernel.c includes it twice. #ifdef _WIN32 __asm__(".text\n" ".globl " AP_NAME "\n" ".def " AP_NAME "; .scl 2; .type 32; .endef\n" ".p2align 4\n" AP_NAME ":\n" ".seh_proc " AP_NAME "\n" " leaq -8(%rsp), %rsp\n" // not sub: the flags are still the interrupted code's until pushfq ".seh_stackalloc 8\n" " pushfq\n" ".seh_stackalloc 8\n" " pushq %rax\n" ".seh_pushreg %rax\n" " pushq %rcx\n" ".seh_pushreg %rcx\n" " pushq %rdx\n" ".seh_pushreg %rdx\n" " pushq %r8\n" ".seh_pushreg %r8\n" " pushq %r9\n" ".seh_pushreg %r9\n" " pushq %r10\n" ".seh_pushreg %r10\n" " pushq %r11\n" ".seh_pushreg %r11\n" " pushq %rbp\n" ".seh_pushreg %rbp\n" " movq %rsp, %rbp\n" ".seh_setframe %rbp, 0\n" ".seh_endprologue\n" " andq $-32, %rsp\n" " subq $576, %rsp\n" // 0: shadow space, 32: MXCSR saved, 36: MXCSR default, 64: YMM0-15 (XMM0-15 without AVX) " " AP_VMOV " " AP_V "0, 64(%rsp)\n" " " AP_VMOV " " AP_V "1, 96(%rsp)\n" " " AP_VMOV " " AP_V "2, 128(%rsp)\n" " " AP_VMOV " " AP_V "3, 160(%rsp)\n" " " AP_VMOV " " AP_V "4, 192(%rsp)\n" " " AP_VMOV " " AP_V "5, 224(%rsp)\n" " " AP_VMOV " " AP_V "6, 256(%rsp)\n" " " AP_VMOV " " AP_V "7, 288(%rsp)\n" " " AP_VMOV " " AP_V "8, 320(%rsp)\n" " " AP_VMOV " " AP_V "9, 352(%rsp)\n" " " AP_VMOV " " AP_V "10, 384(%rsp)\n" " " AP_VMOV " " AP_V "11, 416(%rsp)\n" " " AP_VMOV " " AP_V "12, 448(%rsp)\n" " " AP_VMOV " " AP_V "13, 480(%rsp)\n" " " AP_VMOV " " AP_V "14, 512(%rsp)\n" " " AP_VMOV " " AP_V "15, 544(%rsp)\n" " stmxcsr 32(%rsp)\n" " movl $0x1f80, 36(%rsp)\n" " ldmxcsr 36(%rsp)\n" " cld\n" AP_VZEROUPPER " call kern_ap_rip\n" " movq %rax, 72(%rbp)\n" // the return slot: rbp + 8 pushes + pushfq " call kern_ap_yield\n" " ldmxcsr 32(%rsp)\n" " " AP_VMOV " 64(%rsp), " AP_V "0\n" " " AP_VMOV " 96(%rsp), " AP_V "1\n" " " AP_VMOV " 128(%rsp), " AP_V "2\n" " " AP_VMOV " 160(%rsp), " AP_V "3\n" " " AP_VMOV " 192(%rsp), " AP_V "4\n" " " AP_VMOV " 224(%rsp), " AP_V "5\n" " " AP_VMOV " 256(%rsp), " AP_V "6\n" " " AP_VMOV " 288(%rsp), " AP_V "7\n" " " AP_VMOV " 320(%rsp), " AP_V "8\n" " " AP_VMOV " 352(%rsp), " AP_V "9\n" " " AP_VMOV " 384(%rsp), " AP_V "10\n" " " AP_VMOV " 416(%rsp), " AP_V "11\n" " " AP_VMOV " 448(%rsp), " AP_V "12\n" " " AP_VMOV " 480(%rsp), " AP_V "13\n" " " AP_VMOV " 512(%rsp), " AP_V "14\n" " " AP_VMOV " 544(%rsp), " AP_V "15\n" " movq %rbp, %rsp\n" " popq %rbp\n" " popq %r11\n" " popq %r10\n" " popq %r9\n" " popq %r8\n" " popq %rdx\n" " popq %rcx\n" " popq %rax\n" " popfq\n" " leaq 8(%rsp), %rsp\n" " jmpq *-8(%rsp)\n" ".seh_endproc\n"); #else // The System V version: rsi and rdi are volatile there too, and the interrupted code may keep data in the 128 bytes // below its stack pointer (the red zone), so the return slot and the saves go below that. Without a red zone in the // way the slot is at entry - 136; the exit restores rsp to the entry value and jumps through the slot. __asm__(".text\n" ".globl " AP_NAME "\n" ".type " AP_NAME ", @function\n" ".p2align 4\n" AP_NAME ":\n" " .cfi_startproc\n" " leaq -136(%rsp), %rsp\n" // not sub: the flags are still the interrupted code's until pushfq " pushfq\n" " pushq %rax\n" " pushq %rcx\n" " pushq %rdx\n" " pushq %rsi\n" " pushq %rdi\n" " pushq %r8\n" " pushq %r9\n" " pushq %r10\n" " pushq %r11\n" " pushq %rbp\n" " movq %rsp, %rbp\n" " andq $-32, %rsp\n" " subq $576, %rsp\n" // 32: MXCSR saved, 36: MXCSR default, 64: YMM0-15 (XMM0-15 without AVX) " " AP_VMOV " " AP_V "0, 64(%rsp)\n" " " AP_VMOV " " AP_V "1, 96(%rsp)\n" " " AP_VMOV " " AP_V "2, 128(%rsp)\n" " " AP_VMOV " " AP_V "3, 160(%rsp)\n" " " AP_VMOV " " AP_V "4, 192(%rsp)\n" " " AP_VMOV " " AP_V "5, 224(%rsp)\n" " " AP_VMOV " " AP_V "6, 256(%rsp)\n" " " AP_VMOV " " AP_V "7, 288(%rsp)\n" " " AP_VMOV " " AP_V "8, 320(%rsp)\n" " " AP_VMOV " " AP_V "9, 352(%rsp)\n" " " AP_VMOV " " AP_V "10, 384(%rsp)\n" " " AP_VMOV " " AP_V "11, 416(%rsp)\n" " " AP_VMOV " " AP_V "12, 448(%rsp)\n" " " AP_VMOV " " AP_V "13, 480(%rsp)\n" " " AP_VMOV " " AP_V "14, 512(%rsp)\n" " " AP_VMOV " " AP_V "15, 544(%rsp)\n" " stmxcsr 32(%rsp)\n" " movl $0x1f80, 36(%rsp)\n" " ldmxcsr 36(%rsp)\n" " cld\n" AP_VZEROUPPER " call kern_ap_rip\n" " movq %rax, 88(%rbp)\n" // the return slot: rbp + 10 pushes + pushfq " call kern_ap_yield\n" " ldmxcsr 32(%rsp)\n" " " AP_VMOV " 64(%rsp), " AP_V "0\n" " " AP_VMOV " 96(%rsp), " AP_V "1\n" " " AP_VMOV " 128(%rsp), " AP_V "2\n" " " AP_VMOV " 160(%rsp), " AP_V "3\n" " " AP_VMOV " 192(%rsp), " AP_V "4\n" " " AP_VMOV " 224(%rsp), " AP_V "5\n" " " AP_VMOV " 256(%rsp), " AP_V "6\n" " " AP_VMOV " 288(%rsp), " AP_V "7\n" " " AP_VMOV " 320(%rsp), " AP_V "8\n" " " AP_VMOV " 352(%rsp), " AP_V "9\n" " " AP_VMOV " 384(%rsp), " AP_V "10\n" " " AP_VMOV " 416(%rsp), " AP_V "11\n" " " AP_VMOV " 448(%rsp), " AP_V "12\n" " " AP_VMOV " 480(%rsp), " AP_V "13\n" " " AP_VMOV " 512(%rsp), " AP_V "14\n" " " AP_VMOV " 544(%rsp), " AP_V "15\n" " movq %rbp, %rsp\n" " popq %rbp\n" " popq %r11\n" " popq %r10\n" " popq %r9\n" " popq %r8\n" " popq %rdi\n" " popq %rsi\n" " popq %rdx\n" " popq %rcx\n" " popq %rax\n" " popfq\n" " leaq 136(%rsp), %rsp\n" " jmpq *-136(%rsp)\n" " .cfi_endproc\n" ".size " AP_NAME ", .-" AP_NAME "\n"); #endif