]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/x86_64/idt64.s
xnu-3247.1.106.tar.gz
[apple/xnu.git] / osfmk / x86_64 / idt64.s
index a4a62feaaffb3c41e62616c28465bae9696bc879..0dc07f85020b2b1082e3ea3f663ee23987adc180 100644 (file)
@@ -27,6 +27,7 @@
  */
 #include <i386/asm.h>
 #include <assym.s>
  */
 #include <i386/asm.h>
 #include <assym.s>
+#include <debug.h>
 #include <i386/eflags.h>
 #include <i386/rtclock_asm.h>
 #include <i386/trap.h>
 #include <i386/eflags.h>
 #include <i386/rtclock_asm.h>
 #include <i386/trap.h>
 
 /* A trap with a special-case handler, hence we don't need to define anything */
 #define TRAP_SPC(n, f)
 
 /* A trap with a special-case handler, hence we don't need to define anything */
 #define TRAP_SPC(n, f)
-#define TRAP_IST(n, f)
+#define TRAP_IST1(n, f)
+#define TRAP_IST2(n, f)
 #define USER_TRAP_SPC(n, f)
 
 /* Generate all the stubs */
 #define USER_TRAP_SPC(n, f)
 
 /* Generate all the stubs */
 /*
  * Common dispatch point.
  * Determine what mode has been interrupted and save state accordingly.
 /*
  * Common dispatch point.
  * Determine what mode has been interrupted and save state accordingly.
+ * Here with:
+ *     rsp     from user-space:   interrupt state in PCB, or
+ *             from kernel-space: interrupt state in kernel or interrupt stack
+ *     GSBASE  from user-space:   pthread area, or
+ *             from kernel-space: cpu_data
  */
 L_dispatch:
        cmpl    $(KERNEL64_CS), ISF64_CS(%rsp)
  */
 L_dispatch:
        cmpl    $(KERNEL64_CS), ISF64_CS(%rsp)
-       je      L_64bit_dispatch
+       je      L_dispatch_kernel
 
        swapgs
 
 
        swapgs
 
-       /*
-        * Check for trap from EFI32, and restore cr3 and rsp if so.
-        * A trap from EFI32 is fatal.
-        */
-       cmpl    $(KERNEL32_CS), ISF64_CS(%rsp)
-       jne     L_dispatch_continue
-       push    %rcx
-       mov     EXT(pal_efi_saved_cr3)(%rip), %rcx
-       mov     %rcx, %cr3
-       leaq    (%rip), %rcx
-       shr     $32, %rcx               /* splice the upper 32-bits of rip */
-       shl     $32, %rsp               /* .. and the lower 32-bits of rsp */
-       shrd    $32, %rcx, %rsp         /* to recover the full 64-bits of rsp */
-       pop     %rcx
-
-L_dispatch_continue:
+L_dispatch_user:
        cmpl    $(TASK_MAP_32BIT), %gs:CPU_TASK_MAP
        cmpl    $(TASK_MAP_32BIT), %gs:CPU_TASK_MAP
-       je      L_32bit_dispatch        /* 32-bit user task */
-       /* fall through to 64bit user dispatch */
+       je      L_dispatch_U32          /* 32-bit user task */
+
+L_dispatch_U64:
+       subq    $(ISS64_OFFSET), %rsp
+       mov     %r15, R64_R15(%rsp)
+       mov     %rsp, %r15
+       mov     %gs:CPU_KERNEL_STACK, %rsp
+       jmp     L_dispatch_64bit
+
+L_dispatch_kernel:
+       subq    $(ISS64_OFFSET), %rsp
+       mov     %r15, R64_R15(%rsp)
+       mov     %rsp, %r15
 
 /*
  * Here for 64-bit user task or kernel
  */
 
 /*
  * Here for 64-bit user task or kernel
  */
-L_64bit_dispatch:
-       subq    $(ISS64_OFFSET), %rsp
-       movl    $(SS_64), SS_FLAVOR(%rsp)
+L_dispatch_64bit:
+       movl    $(SS_64), SS_FLAVOR(%r15)
 
 
-       cld
-       
        /*
         * Save segment regs - for completeness since theyre not used.
         */
        /*
         * Save segment regs - for completeness since theyre not used.
         */
-       movl    %fs, R64_FS(%rsp)
-       movl    %gs, R64_GS(%rsp)
+       movl    %fs, R64_FS(%r15)
+       movl    %gs, R64_GS(%r15)
 
        /* Save general-purpose registers */
 
        /* Save general-purpose registers */
-       mov     %rax, R64_RAX(%rsp)
-       mov     %rcx, R64_RCX(%rsp)
-       mov     %rbx, R64_RBX(%rsp)
-       mov     %rbp, R64_RBP(%rsp)
-       mov     %r11, R64_R11(%rsp)
-       mov     %r12, R64_R12(%rsp)
-       mov     %r13, R64_R13(%rsp)
-       mov     %r14, R64_R14(%rsp)
-       mov     %r15, R64_R15(%rsp)
+       mov     %rax, R64_RAX(%r15)
+       mov     %rbx, R64_RBX(%r15)
+       mov     %rcx, R64_RCX(%r15)
+       mov     %rdx, R64_RDX(%r15)
+       mov     %rbp, R64_RBP(%r15)
+       mov     %rdi, R64_RDI(%r15)
+       mov     %rsi, R64_RSI(%r15)
+       mov     %r8,  R64_R8(%r15)
+       mov     %r9,  R64_R9(%r15)
+       mov     %r10, R64_R10(%r15)
+       mov     %r11, R64_R11(%r15)
+       mov     %r12, R64_R12(%r15)
+       mov     %r13, R64_R13(%r15)
+       mov     %r14, R64_R14(%r15)
 
        /* cr2 is significant only for page-faults */
        mov     %cr2, %rax
 
        /* cr2 is significant only for page-faults */
        mov     %cr2, %rax
-       mov     %rax, R64_CR2(%rsp)
+       mov     %rax, R64_CR2(%r15)
 
 
-       /* Other registers (which may contain syscall args) */
-       mov     %rdi, R64_RDI(%rsp)     /* arg0 .. */
-       mov     %rsi, R64_RSI(%rsp)
-       mov     %rdx, R64_RDX(%rsp)
-       mov     %r10, R64_R10(%rsp)
-       mov     %r8, R64_R8(%rsp)
-       mov     %r9, R64_R9(%rsp)       /* .. arg5 */
+       mov     R64_TRAPNO(%r15), %ebx  /* %ebx := trapno for later */
+       mov     R64_TRAPFN(%r15), %rdx  /* %rdx := trapfn for later */
+       mov     R64_CS(%r15), %esi      /* %esi := cs for later */
 
 
-       mov     R64_TRAPNO(%rsp), %ebx  /* %ebx := trapno for later */
-       mov     R64_TRAPFN(%rsp), %rdx  /* %rdx := trapfn for later */
-       mov     R64_CS(%rsp), %esi      /* %esi := cs for later */
-
-       jmp L_common_dispatch
+       jmp     L_common_dispatch
 
 L_64bit_entry_reject:
        /*
 
 L_64bit_entry_reject:
        /*
@@ -220,7 +217,7 @@ L_64bit_entry_reject:
        movq    %rax, ISF64_TRAPFN+8(%rsp)
        popq    %rax
        movq    $(T_INVALID_OPCODE), ISF64_TRAPNO(%rsp)
        movq    %rax, ISF64_TRAPFN+8(%rsp)
        popq    %rax
        movq    $(T_INVALID_OPCODE), ISF64_TRAPNO(%rsp)
-       jmp     L_64bit_dispatch
+       jmp     L_dispatch_U64
        
 L_32bit_entry_check:
        /*
        
 L_32bit_entry_check:
        /*
@@ -230,56 +227,62 @@ L_32bit_entry_check:
        jne     L_64bit_entry_reject
        /* fall through to 32-bit handler: */
 
        jne     L_64bit_entry_reject
        /* fall through to 32-bit handler: */
 
-L_32bit_dispatch: /* 32-bit user task */
-       subq    $(ISC32_OFFSET), %rsp
-       movl    $(SS_32), SS_FLAVOR(%rsp)
+L_dispatch_U32: /* 32-bit user task */
+       subq    $(ISS64_OFFSET), %rsp
+       mov     %rsp, %r15
+       mov     %gs:CPU_KERNEL_STACK, %rsp
+       movl    $(SS_32), SS_FLAVOR(%r15)
 
 
-       cld
        /*
         * Save segment regs
         */
        /*
         * Save segment regs
         */
-       movl    %ds, R32_DS(%rsp)
-       movl    %es, R32_ES(%rsp)
-       movl    %fs, R32_FS(%rsp)
-       movl    %gs, R32_GS(%rsp)
+       movl    %ds, R32_DS(%r15)
+       movl    %es, R32_ES(%r15)
+       movl    %fs, R32_FS(%r15)
+       movl    %gs, R32_GS(%r15)
 
        /*
         * Save general 32-bit registers
         */
 
        /*
         * Save general 32-bit registers
         */
-       mov     %eax, R32_EAX(%rsp)
-       mov     %ebx, R32_EBX(%rsp)
-       mov     %ecx, R32_ECX(%rsp)
-       mov     %edx, R32_EDX(%rsp)
-       mov     %ebp, R32_EBP(%rsp)
-       mov     %esi, R32_ESI(%rsp)
-       mov     %edi, R32_EDI(%rsp)
+       mov     %eax, R32_EAX(%r15)
+       mov     %ebx, R32_EBX(%r15)
+       mov     %ecx, R32_ECX(%r15)
+       mov     %edx, R32_EDX(%r15)
+       mov     %ebp, R32_EBP(%r15)
+       mov     %esi, R32_ESI(%r15)
+       mov     %edi, R32_EDI(%r15)
 
        /* Unconditionally save cr2; only meaningful on page faults */
        mov     %cr2, %rax
 
        /* Unconditionally save cr2; only meaningful on page faults */
        mov     %cr2, %rax
-       mov     %eax, R32_CR2(%rsp)
+       mov     %eax, R32_CR2(%r15)
 
        /*
         * Copy registers already saved in the machine state 
         * (in the interrupt stack frame) into the compat save area.
         */
 
        /*
         * Copy registers already saved in the machine state 
         * (in the interrupt stack frame) into the compat save area.
         */
-       mov     ISC32_RIP(%rsp), %eax
-       mov     %eax, R32_EIP(%rsp)
-       mov     ISC32_RFLAGS(%rsp), %eax
-       mov     %eax, R32_EFLAGS(%rsp)
-       mov     ISC32_RSP(%rsp), %eax
-       mov     %eax, R32_UESP(%rsp)
-       mov     ISC32_SS(%rsp), %eax
-       mov     %eax, R32_SS(%rsp)
-L_32bit_dispatch_after_fault:
-       mov     ISC32_CS(%rsp), %esi            /* %esi := %cs for later */
-       mov     %esi, R32_CS(%rsp)
-       mov     ISC32_TRAPNO(%rsp), %ebx        /* %ebx := trapno for later */
-       mov     %ebx, R32_TRAPNO(%rsp)
-       mov     ISC32_ERR(%rsp), %eax
-       mov     %eax, R32_ERR(%rsp)
-       mov     ISC32_TRAPFN(%rsp), %rdx        /* %rdx := trapfn for later */
+       mov     R64_RIP(%r15), %eax
+       mov     %eax, R32_EIP(%r15)
+       mov     R64_RFLAGS(%r15), %eax
+       mov     %eax, R32_EFLAGS(%r15)
+       mov     R64_RSP(%r15), %eax
+       mov     %eax, R32_UESP(%r15)
+       mov     R64_SS(%r15), %eax
+       mov     %eax, R32_SS(%r15)
+L_dispatch_U32_after_fault:
+       mov     R64_CS(%r15), %esi              /* %esi := %cs for later */
+       mov     %esi, R32_CS(%r15)
+       mov     R64_TRAPNO(%r15), %ebx          /* %ebx := trapno for later */
+       mov     %ebx, R32_TRAPNO(%r15)
+       mov     R64_ERR(%r15), %eax
+       mov     %eax, R32_ERR(%r15)
+       mov     R64_TRAPFN(%r15), %rdx          /* %rdx := trapfn for later */
 
 L_common_dispatch:
 
 L_common_dispatch:
+       cld             /* Ensure the direction flag is clear in the kernel */
+       cmpl    $0, EXT(pmap_smap_enabled)(%rip)
+       je      1f
+       clac            /* Clear EFLAGS.AC if SMAP is present/enabled */
+1:
        /*
         * On entering the kernel, we don't need to switch cr3
         * because the kernel shares the user's address space.
        /*
         * On entering the kernel, we don't need to switch cr3
         * because the kernel shares the user's address space.
@@ -293,36 +296,37 @@ L_common_dispatch:
        mov     %gs:CPU_KERNEL_CR3, %rcx
        mov     %rcx, %gs:CPU_ACTIVE_CR3
        test    $3, %esi                        /* user/kernel? */
        mov     %gs:CPU_KERNEL_CR3, %rcx
        mov     %rcx, %gs:CPU_ACTIVE_CR3
        test    $3, %esi                        /* user/kernel? */
-       jz      1f                              /* skip cr3 reload from kernel */
+       jz      2f                              /* skip cr3 reload from kernel */
        xor     %rbp, %rbp
        cmpl    $0, EXT(no_shared_cr3)(%rip)
        xor     %rbp, %rbp
        cmpl    $0, EXT(no_shared_cr3)(%rip)
-       je      1f
+       je      2f
        mov     %rcx, %cr3                      /* load kernel cr3 */
        mov     %rcx, %cr3                      /* load kernel cr3 */
-       jmp     2f                              /* and skip tlb flush test */
-1:
+       jmp     4f                              /* and skip tlb flush test */
+2:
        mov     %gs:CPU_ACTIVE_CR3+4, %rcx
        shr     $32, %rcx
        testl   %ecx, %ecx
        mov     %gs:CPU_ACTIVE_CR3+4, %rcx
        shr     $32, %rcx
        testl   %ecx, %ecx
-       jz      2f
+       jz      4f
        movl    $0, %gs:CPU_TLB_INVALID
        testl   $(1<<16), %ecx                  /* Global? */
        movl    $0, %gs:CPU_TLB_INVALID
        testl   $(1<<16), %ecx                  /* Global? */
-       jz      11f
+       jz      3f
        mov     %cr4, %rcx      /* RMWW CR4, for lack of an alternative*/
        and     $(~CR4_PGE), %rcx
        mov     %rcx, %cr4
        or      $(CR4_PGE), %rcx
        mov     %rcx, %cr4
        mov     %cr4, %rcx      /* RMWW CR4, for lack of an alternative*/
        and     $(~CR4_PGE), %rcx
        mov     %rcx, %cr4
        or      $(CR4_PGE), %rcx
        mov     %rcx, %cr4
-       jmp     2f
-
-11:    mov     %cr3, %rcx
+       jmp     4f
+3:
+       mov     %cr3, %rcx
        mov     %rcx, %cr3
        mov     %rcx, %cr3
-2:
+4:
        mov     %gs:CPU_ACTIVE_THREAD, %rcx     /* Get the active thread */
        mov     %gs:CPU_ACTIVE_THREAD, %rcx     /* Get the active thread */
+       movl    $-1, TH_IOTIER_OVERRIDE(%rcx)   /* Reset IO tier override to -1 before handling trap */
        cmpq    $0, TH_PCB_IDS(%rcx)    /* Is there a debug register state? */
        cmpq    $0, TH_PCB_IDS(%rcx)    /* Is there a debug register state? */
-       je      3f
+       je      5f
        xor     %ecx, %ecx              /* If so, reset DR7 (the control) */
        mov     %rcx, %dr7
        xor     %ecx, %ecx              /* If so, reset DR7 (the control) */
        mov     %rcx, %dr7
-3:
+5:
        incl    %gs:hwIntCnt(,%ebx,4)           // Bump the trap/intr count
        /* Dispatch the designated handler */
        jmp     *%rdx
        incl    %gs:hwIntCnt(,%ebx,4)           // Bump the trap/intr count
        /* Dispatch the designated handler */
        jmp     *%rdx
@@ -384,49 +388,50 @@ Entry(ret_to_user)
        mov     %rax, %dr7              /* Set DR7 */
        movq    $0, %gs:CPU_DR7
 4:
        mov     %rax, %dr7              /* Set DR7 */
        movq    $0, %gs:CPU_DR7
 4:
-       cmpl    $(SS_64), SS_FLAVOR(%rsp)       /* 64-bit state? */
+       cmpl    $(SS_64), SS_FLAVOR(%r15)       /* 64-bit state? */
        je      L_64bit_return
 
 L_32bit_return:
 #if DEBUG_IDT64
        je      L_64bit_return
 
 L_32bit_return:
 #if DEBUG_IDT64
-       cmpl    $(SS_32), SS_FLAVOR(%rsp)       /* 32-bit state? */
+       cmpl    $(SS_32), SS_FLAVOR(%r15)       /* 32-bit state? */
        je      1f
        cli
        POSTCODE2(0x6432)
        je      1f
        cli
        POSTCODE2(0x6432)
-       CCALL1(panic_idt64, %rsp)
+       CCALL1(panic_idt64, %r15)
 1:
 #endif /* DEBUG_IDT64 */
 
        /*
         * Restore registers into the machine state for iret.
 1:
 #endif /* DEBUG_IDT64 */
 
        /*
         * Restore registers into the machine state for iret.
+        * Here on fault stack and PCB address in R11.
         */
         */
-       movl    R32_EIP(%rsp), %eax
-       movl    %eax, ISC32_RIP(%rsp)
-       movl    R32_EFLAGS(%rsp), %eax
-       movl    %eax, ISC32_RFLAGS(%rsp)
-       movl    R32_CS(%rsp), %eax
-       movl    %eax, ISC32_CS(%rsp)
-       movl    R32_UESP(%rsp), %eax
-       movl    %eax, ISC32_RSP(%rsp)
-       movl    R32_SS(%rsp), %eax
-       movl    %eax, ISC32_SS(%rsp)
+       movl    R32_EIP(%r15), %eax
+       movl    %eax, R64_RIP(%r15)
+       movl    R32_EFLAGS(%r15), %eax
+       movl    %eax, R64_RFLAGS(%r15)
+       movl    R32_CS(%r15), %eax
+       movl    %eax, R64_CS(%r15)
+       movl    R32_UESP(%r15), %eax
+       movl    %eax, R64_RSP(%r15)
+       movl    R32_SS(%r15), %eax
+       movl    %eax, R64_SS(%r15)
 
        /*
         * Restore general 32-bit registers
         */
 
        /*
         * Restore general 32-bit registers
         */
-       movl    R32_EAX(%rsp), %eax
-       movl    R32_EBX(%rsp), %ebx
-       movl    R32_ECX(%rsp), %ecx
-       movl    R32_EDX(%rsp), %edx
-       movl    R32_EBP(%rsp), %ebp
-       movl    R32_ESI(%rsp), %esi
-       movl    R32_EDI(%rsp), %edi
+       movl    R32_EAX(%r15), %eax
+       movl    R32_EBX(%r15), %ebx
+       movl    R32_ECX(%r15), %ecx
+       movl    R32_EDX(%r15), %edx
+       movl    R32_EBP(%r15), %ebp
+       movl    R32_ESI(%r15), %esi
+       movl    R32_EDI(%r15), %edi
 
        /*
 
        /*
-        * Restore segment registers. We make take an exception here but
-        * we've got enough space left in the save frame area to absorb
-         * a hardware frame plus the trapfn and trapno
+        * Restore segment registers. A segment exception taken here will
+        * push state on the IST1 stack and will not affect the "PCB stack".
         */
         */
+       mov     %r15, %rsp              /* Set the PCB as the stack */
        swapgs
 EXT(ret32_set_ds):     
        movl    R32_DS(%rsp), %ds
        swapgs
 EXT(ret32_set_ds):     
        movl    R32_DS(%rsp), %ds
@@ -438,7 +443,7 @@ EXT(ret32_set_gs):
        movl    R32_GS(%rsp), %gs
 
        /* pop compat frame + trapno, trapfn and error */       
        movl    R32_GS(%rsp), %gs
 
        /* pop compat frame + trapno, trapfn and error */       
-       add     $(ISC32_OFFSET)+8+8+8, %rsp
+       add     $(ISS64_OFFSET)+8+8+8, %rsp
        cmpl    $(SYSENTER_CS),ISF64_CS-8-8-8(%rsp)
                                        /* test for fast entry/exit */
        je      L_fast_exit
        cmpl    $(SYSENTER_CS),ISF64_CS-8-8-8(%rsp)
                                        /* test for fast entry/exit */
        je      L_fast_exit
@@ -452,53 +457,60 @@ L_fast_exit:
        popf                            /* flags - carry denotes failure */
        pop     %rcx                    /* user return esp */
        sti                             /* interrupts enabled after sysexit */
        popf                            /* flags - carry denotes failure */
        pop     %rcx                    /* user return esp */
        sti                             /* interrupts enabled after sysexit */
-       .byte 0x0f,0x35                 /* 32-bit sysexit */
+       sysexitl                        /* 32-bit sysexit */
 
 ret_to_kernel:
 #if DEBUG_IDT64
 
 ret_to_kernel:
 #if DEBUG_IDT64
-       cmpl    $(SS_64), SS_FLAVOR(%rsp)       /* 64-bit state? */
+       cmpl    $(SS_64), SS_FLAVOR(%r15)       /* 64-bit state? */
        je      1f
        cli
        POSTCODE2(0x6464)
        je      1f
        cli
        POSTCODE2(0x6464)
-       CCALL1(panic_idt64, %rsp)
+       CCALL1(panic_idt64, %r15)
        hlt
 1:
        hlt
 1:
-       cmpl    $(KERNEL64_CS), R64_CS(%rsp)
+       cmpl    $(KERNEL64_CS), R64_CS(%r15)
        je      2f
        je      2f
-       CCALL1(panic_idt64, %rsp)
+       CCALL1(panic_idt64, %r15)
        hlt
 2:
 #endif
 
 L_64bit_return:
        hlt
 2:
 #endif
 
 L_64bit_return:
-       testb   $3, R64_CS(%rsp)                /* returning to user-space? */
-       jz      1f
-       swapgs
-1:
+       /*
+        * Restore general 64-bit registers.
+        * Here on fault stack and PCB address in R15.
+        */
+       mov     R64_R14(%r15), %r14
+       mov     R64_R13(%r15), %r13
+       mov     R64_R12(%r15), %r12
+       mov     R64_R11(%r15), %r11
+       mov     R64_R10(%r15), %r10
+       mov     R64_R9(%r15),  %r9
+       mov     R64_R8(%r15),  %r8
+       mov     R64_RSI(%r15), %rsi
+       mov     R64_RDI(%r15), %rdi
+       mov     R64_RBP(%r15), %rbp
+       mov     R64_RDX(%r15), %rdx
+       mov     R64_RCX(%r15), %rcx
+       mov     R64_RBX(%r15), %rbx
+       mov     R64_RAX(%r15), %rax
 
        /*
 
        /*
-        * Restore general 64-bit registers
+        * We must swap GS base if we're returning to user-space,
+        * or we're returning from an NMI that occurred in a trampoline
+        * before the user GS had been swapped. In the latter case, the NMI
+        * handler will have flagged the high-order 32-bits of the CS.
         */
         */
-       mov     R64_R15(%rsp), %r15
-       mov     R64_R14(%rsp), %r14
-       mov     R64_R13(%rsp), %r13
-       mov     R64_R12(%rsp), %r12
-       mov     R64_R11(%rsp), %r11
-       mov     R64_R10(%rsp), %r10
-       mov     R64_R9(%rsp),  %r9
-       mov     R64_R8(%rsp),  %r8
-       mov     R64_RSI(%rsp), %rsi
-       mov     R64_RDI(%rsp), %rdi
-       mov     R64_RBP(%rsp), %rbp
-       mov     R64_RDX(%rsp), %rdx
-       mov     R64_RBX(%rsp), %rbx
-       mov     R64_RCX(%rsp), %rcx
-       mov     R64_RAX(%rsp), %rax
-
-       add     $(ISS64_OFFSET)+24, %rsp        /* pop saved state frame +
-                                                  trapno + trapfn and error */ 
+       cmpq    $(KERNEL64_CS), R64_CS(%r15)
+       jz      1f
+       swapgs
+1:
+       mov     R64_R15(%r15), %rsp
+       xchg    %r15, %rsp
+       add     $(ISS64_OFFSET)+24, %rsp        /* pop saved state       */
+                                               /* + trapno/trapfn/error */     
        cmpl    $(SYSCALL_CS),ISF64_CS-24(%rsp)
        cmpl    $(SYSCALL_CS),ISF64_CS-24(%rsp)
-                               /* test for fast entry/exit */
+                                               /* test for fast entry/exit */
        je      L_sysret
 .globl _dump_iretq
 EXT(ret64_iret):
        je      L_sysret
 .globl _dump_iretq
 EXT(ret64_iret):
@@ -508,7 +520,7 @@ L_sysret:
        /*
         * Here to load rcx/r11/rsp and perform the sysret back to user-space.
         *      rcx     user rip
        /*
         * Here to load rcx/r11/rsp and perform the sysret back to user-space.
         *      rcx     user rip
-        *      r1      user rflags
+        *      r11     user rflags
         *      rsp     user stack pointer
         */
        mov     ISF64_RIP-24(%rsp), %rcx
         *      rsp     user stack pointer
         */
        mov     ISF64_RIP-24(%rsp), %rcx
@@ -551,6 +563,7 @@ Entry(idt64_mdep_scall)
        pushq   $(MACHDEP_INT)
        jmp     L_32bit_entry_check
 
        pushq   $(MACHDEP_INT)
        jmp     L_32bit_entry_check
 
+/* Programmed into MSR_IA32_LSTAR by mp_desc.c */
 Entry(hi64_syscall)
 Entry(idt64_syscall)
 L_syscall_continue:
 Entry(hi64_syscall)
 Entry(idt64_syscall)
 L_syscall_continue:
@@ -572,8 +585,8 @@ L_syscall_continue:
        movq    $(T_SYSCALL), ISF64_TRAPNO(%rsp)        /* trapno */
        leaq    HNDL_SYSCALL(%rip), %r11;
        movq    %r11, ISF64_TRAPFN(%rsp)
        movq    $(T_SYSCALL), ISF64_TRAPNO(%rsp)        /* trapno */
        leaq    HNDL_SYSCALL(%rip), %r11;
        movq    %r11, ISF64_TRAPFN(%rsp)
-       mov     ISF64_RFLAGS(%rsp), %r11        /* Avoid info leak,restore R11 */
-       jmp     L_64bit_dispatch                /* this can only be a 64-bit task */
+       mov     ISF64_RFLAGS(%rsp), %r11        /* Avoid leak, restore R11 */
+       jmp     L_dispatch_U64                  /* this can only be 64-bit */
        
 /*
  * sysenter entry point
        
 /*
  * sysenter entry point
@@ -616,17 +629,11 @@ Entry(idt64_page_fault)
        PUSH_FUNCTION(HNDL_ALLTRAPS)
        push    $(T_PAGE_FAULT)
        push    %rax                    /* save %rax temporarily */
        PUSH_FUNCTION(HNDL_ALLTRAPS)
        push    $(T_PAGE_FAULT)
        push    %rax                    /* save %rax temporarily */
-       leaq    EXT(idt64_unix_scall_copy_args)(%rip), %rax
-       cmp     %rax, 8+ISF64_RIP(%rsp) /* fault during copy args? */
-       je      1f                      /* - yes, handle copy arg fault */
        testb   $3, 8+ISF64_CS(%rsp)    /* was trap from kernel? */
        jz      L_kernel_trap           /* - yes, handle with care */
        pop     %rax                    /* restore %rax, swapgs, and continue */
        swapgs
        testb   $3, 8+ISF64_CS(%rsp)    /* was trap from kernel? */
        jz      L_kernel_trap           /* - yes, handle with care */
        pop     %rax                    /* restore %rax, swapgs, and continue */
        swapgs
-       jmp     L_dispatch_continue
-1:
-       add     $(8+ISF64_SIZE), %rsp   /* remove entire intr stack frame */
-       jmp     L_copy_args_continue    /* continue system call entry */
+       jmp     L_dispatch_user
 
 
 /*
 
 
 /*
@@ -675,26 +682,20 @@ Entry(idt64_double_fault)
        leaq    EXT(idt64_syscall)(%rip), %rax
        cmp     %rax, ISF64_RIP+8(%rsp)
        pop     %rax
        leaq    EXT(idt64_syscall)(%rip), %rax
        cmp     %rax, ISF64_RIP+8(%rsp)
        pop     %rax
-       jne     L_64bit_dispatch
+       jne     L_dispatch_kernel
 
        mov     ISF64_RSP(%rsp), %rsp
        jmp     L_syscall_continue
        
 
 /*
 
        mov     ISF64_RSP(%rsp), %rsp
        jmp     L_syscall_continue
        
 
 /*
- * General protection or segment-not-present fault.
- * Check for a GP/NP fault in the kernel_return
- * sequence; if there, report it as a GP/NP fault on the user's instruction.
- *
- * rsp->     0 ISF64_TRAPNO:   trap code (NP or GP)
- *          8 ISF64_TRAPFN:    trap function
- *         16 ISF64_ERR:       segment number in error (error code)
- *         24 ISF64_RIP:       rip
- *         32 ISF64_CS:        cs
- *         40 ISF64_RFLAGS:    rflags 
- *         48 ISF64_RIP:       rsp
- *         56 ISF64_SS:        ss
- *         64:                 old registers (trap is from kernel)
+ * For GP/NP/SS faults, we use the IST1 stack.
+ * For faults from user-space, we have to copy the machine state to the
+ * PCB stack and then dispatch as normal.
+ * For faults in kernel-space, we need to scrub for kernel exit faults and
+ * treat these as user-space faults. But for all other kernel-space faults
+ * we continue to run on the IST1 stack and we dispatch to handle the fault
+ * as fatal.
  */
 Entry(idt64_gen_prot)
        PUSH_FUNCTION(HNDL_ALLTRAPS)
  */
 Entry(idt64_gen_prot)
        PUSH_FUNCTION(HNDL_ALLTRAPS)
@@ -711,14 +712,38 @@ Entry(idt64_segnp)
        pushq   $(T_SEGMENT_NOT_PRESENT)
                                        /* indicate fault type */
 trap_check_kernel_exit:
        pushq   $(T_SEGMENT_NOT_PRESENT)
                                        /* indicate fault type */
 trap_check_kernel_exit:
-       testb   $3,ISF64_CS(%rsp)
-       jnz     L_dispatch
-       /*
-        * trap was from kernel mode,
-        * so check for the kernel exit sequence
-        */
+       testb   $3,ISF64_CS(%rsp)
+       jz      L_kernel_gpf
+
+       /* Here for fault from user-space. Copy interrupt state to PCB. */
+       swapgs
        push    %rax
        push    %rax
+       mov     %rcx, %gs:CPU_UBER_TMP          /* save user RCX  */
+       mov     %gs:CPU_UBER_ISF, %rcx          /* PCB stack addr */
+       mov     ISF64_SS+8(%rsp), %rax
+       mov     %rax, ISF64_SS(%rcx)
+       mov     ISF64_RSP+8(%rsp), %rax
+       mov     %rax, ISF64_RSP(%rcx)
+       mov     ISF64_RFLAGS+8(%rsp), %rax
+       mov     %rax, ISF64_RFLAGS(%rcx)
+       mov     ISF64_CS+8(%rsp), %rax
+       mov     %rax, ISF64_CS(%rcx)
+       mov     ISF64_RIP+8(%rsp), %rax
+       mov     %rax, ISF64_RIP(%rcx)
+       mov     ISF64_ERR+8(%rsp), %rax
+       mov     %rax, ISF64_ERR(%rcx)
+       mov     ISF64_TRAPFN+8(%rsp), %rax
+       mov     %rax, ISF64_TRAPFN(%rcx)
+       mov     ISF64_TRAPNO+8(%rsp), %rax
+       mov     %rax, ISF64_TRAPNO(%rcx)
+       pop     %rax
+       mov     %gs:CPU_UBER_TMP, %rsp          /* user RCX into RSP */
+       xchg    %rcx, %rsp                      /* to PCB stack with user RCX */
+       jmp     L_dispatch_user
 
 
+L_kernel_gpf:
+       /* Here for GPF from kernel_space. Check for recoverable cases. */
+       push    %rax
        leaq    EXT(ret32_iret)(%rip), %rax
        cmp     %rax, 8+ISF64_RIP(%rsp)
        je      L_fault_iret
        leaq    EXT(ret32_iret)(%rip), %rax
        cmp     %rax, 8+ISF64_RIP(%rsp)
        je      L_fault_iret
@@ -738,12 +763,7 @@ trap_check_kernel_exit:
        cmp     %rax, 8+ISF64_RIP(%rsp)
        je      L_32bit_fault_set_seg
 
        cmp     %rax, 8+ISF64_RIP(%rsp)
        je      L_32bit_fault_set_seg
 
-       leaq    EXT(idt64_unix_scall_copy_args)(%rip), %rax
-       cmp     %rax, 8+ISF64_RIP(%rsp)
-       cmove   8+ISF64_RSP(%rsp), %rsp
-       je      L_copy_args_continue
-
-       /* fall through */
+       /* Fall through */
 
 L_kernel_trap:
        /*
 
 L_kernel_trap:
        /*
@@ -752,19 +772,25 @@ L_kernel_trap:
         * Note: %rax has been pushed on stack.
         * Make sure we're not on the PCB stack, if so move to the kernel stack.
         * This is likely a fatal condition.
         * Note: %rax has been pushed on stack.
         * Make sure we're not on the PCB stack, if so move to the kernel stack.
         * This is likely a fatal condition.
-        * But first, try to ensure we have the kernel gs base active...
+        * But first, ensure we have the kernel gs base active...
         */
         */
-       movq    %gs:CPU_THIS, %rax              /* get gs_base into %rax */
-       test    %rax, %rax                      /* test sign bit (MSB) */
-       js      1f                              /* -ve kernel addr, no swap */
-       swapgs                                  /* +ve user addr, swap */
+       push    %rcx
+       push    %rdx
+       mov     $(MSR_IA32_GS_BASE), %ecx
+       rdmsr                                   /* read kernel gsbase */
+       test    $0x80000000, %edx               /* test MSB of address */
+       jne     1f
+       swapgs                                  /* so swap */
 1:
 1:
+       pop     %rdx
+       pop     %rcx
+
        movq    %gs:CPU_UBER_ISF, %rax          /* PCB stack addr */
        subq    %rsp, %rax
        cmpq    $(PAGE_SIZE), %rax              /* current stack in PCB? */
        jb      2f                              /*  - yes, deal with it */
        pop     %rax                            /*  - no, restore %rax */
        movq    %gs:CPU_UBER_ISF, %rax          /* PCB stack addr */
        subq    %rsp, %rax
        cmpq    $(PAGE_SIZE), %rax              /* current stack in PCB? */
        jb      2f                              /*  - yes, deal with it */
        pop     %rax                            /*  - no, restore %rax */
-       jmp     L_64bit_dispatch
+       jmp     L_dispatch_kernel
 2:
        /*
         *  Here if %rsp is in the PCB
 2:
        /*
         *  Here if %rsp is in the PCB
@@ -781,49 +807,74 @@ L_kernel_trap:
        pushq   8+ISF64_TRAPFN(%rax)
        pushq   8+ISF64_TRAPNO(%rax)
        movq    (%rax), %rax
        pushq   8+ISF64_TRAPFN(%rax)
        pushq   8+ISF64_TRAPNO(%rax)
        movq    (%rax), %rax
-       jmp     L_64bit_dispatch
+       jmp     L_dispatch_kernel
+
 
 /*
  * GP/NP fault on IRET: CS or SS is in error.
 
 /*
  * GP/NP fault on IRET: CS or SS is in error.
- * Note that the user ss is originally 16-byte aligned, we'd popped the
- * stack back to contain just the rip/cs/rflags/rsp/ss before issuing the iret.
- * On taking the GP/NP fault on the iret instruction, the stack is 16-byte
- * aligned before pushed the interrupt frame. Hence, an 8-byte padding exists.
+ * User GSBASE is active.
+ * On IST1 stack containing:
+ *  (rax saved above, which is immediately popped)
+ *  0  ISF64_TRAPNO:   trap code (NP or GP)
+ *  8  ISF64_TRAPFN:   trap function
+ *  16 ISF64_ERR:      segment number in error (error code)
+ *  24 ISF64_RIP:      kernel RIP
+ *  32 ISF64_CS:       kernel CS
+ *  40 ISF64_RFLAGS:   kernel RFLAGS 
+ *  48 ISF64_RSP:      kernel RSP
+ *  56 ISF64_SS:       kernel SS
+ * On the PCB stack, pointed to by the kernel's RSP is:
+ *   0                 user RIP
+ *   8                 user CS
+ *  16                 user RFLAGS
+ *  24                 user RSP
+ *  32                         user SS
  *
  *
- * on SP is
- *  (-  rax saved above, which is immediately popped)
+ * We need to move the kernel's TRAPNO, TRAPFN and ERR to the PCB and handle
+ * as a user fault with:
  *  0  ISF64_TRAPNO:   trap code (NP or GP)
  *  8  ISF64_TRAPFN:   trap function
  *  16 ISF64_ERR:      segment number in error (error code)
  *  0  ISF64_TRAPNO:   trap code (NP or GP)
  *  8  ISF64_TRAPFN:   trap function
  *  16 ISF64_ERR:      segment number in error (error code)
- *  24 ISF64_RIP:      rip
- *  32 ISF64_CS:       cs
- *  40 ISF64_RFLAGS:   rflags 
- *  48 ISF64_RSP:      rsp  <-- new trapno
- *  56 ISF64_SS:       ss   <-- new trapfn
- *  64                 pad8 <-- new errcode
- *  72                 user rip
- *  80                 user cs
- *  88                 user rflags
- *  96                 user rsp
- * 104                         user ss (16-byte aligned)
+ *  24                 user RIP
+ *  32                 user CS
+ *  40                 user RFLAGS
+ *  48                 user RSP
+ *  56                         user SS
  */
 L_fault_iret:
        pop     %rax                    /* recover saved %rax */
        mov     %rax, ISF64_RIP(%rsp)   /* save rax (we don`t need saved rip) */
  */
 L_fault_iret:
        pop     %rax                    /* recover saved %rax */
        mov     %rax, ISF64_RIP(%rsp)   /* save rax (we don`t need saved rip) */
-       mov     ISF64_TRAPNO(%rsp), %rax
-       mov     %rax, ISF64_RSP(%rsp)   /* put in user trap number */
-       mov     ISF64_TRAPFN(%rsp), %rax
-       mov     %rax, ISF64_SS(%rsp)    /* put in user trap function */
-       mov     ISF64_ERR(%rsp), %rax   /* get error code */
-       mov     %rax, 8+ISF64_SS(%rsp)  /* put in user errcode */
-       mov     ISF64_RIP(%rsp), %rax   /* restore rax */
-       add     $(ISF64_RSP),%rsp       /* reset to new trapfn */
+       mov     ISF64_RSP(%rsp), %rax
+       xchg    %rax, %rsp              /* switch to PCB stack */
+       push    ISF64_ERR(%rax)
+       push    ISF64_TRAPFN(%rax)
+       push    ISF64_TRAPNO(%rax)
+       mov     ISF64_RIP(%rax), %rax   /* restore rax */
                                        /* now treat as fault from user */
        jmp     L_dispatch
 
 /*
  * Fault restoring a segment register.  All of the saved state is still
  * on the stack untouched since we haven't yet moved the stack pointer.
                                        /* now treat as fault from user */
        jmp     L_dispatch
 
 /*
  * Fault restoring a segment register.  All of the saved state is still
  * on the stack untouched since we haven't yet moved the stack pointer.
+ * On IST1 stack containing:
+ *  (rax saved above, which is immediately popped)
+ *  0  ISF64_TRAPNO:   trap code (NP or GP)
+ *  8  ISF64_TRAPFN:   trap function
+ *  16 ISF64_ERR:      segment number in error (error code)
+ *  24 ISF64_RIP:      kernel RIP
+ *  32 ISF64_CS:       kernel CS
+ *  40 ISF64_RFLAGS:   kernel RFLAGS 
+ *  48 ISF64_RSP:      kernel RSP
+ *  56 ISF64_SS:       kernel SS
+ * On the PCB stack, pointed to by the kernel's RSP is:
+ *  0                          user trap code
+ *  8                          user trap function
+ *  16                 user err 
+ *  24                 user RIP
+ *  32                 user CS
+ *  40                 user RFLAGS
+ *  48                 user RSP
+ *  56                         user SS
  */
 L_32bit_fault_set_seg:
        swapgs
  */
 L_32bit_fault_set_seg:
        swapgs
@@ -832,16 +883,15 @@ L_32bit_fault_set_seg:
        mov     ISF64_TRAPFN(%rsp), %rcx
        mov     ISF64_ERR(%rsp), %rdx
        mov     ISF64_RSP(%rsp), %rsp   /* reset stack to saved state */
        mov     ISF64_TRAPFN(%rsp), %rcx
        mov     ISF64_ERR(%rsp), %rdx
        mov     ISF64_RSP(%rsp), %rsp   /* reset stack to saved state */
-       mov     %rax,ISC32_TRAPNO(%rsp)
-       mov     %rcx,ISC32_TRAPFN(%rsp)
-       mov     %rdx,ISC32_ERR(%rsp)
+       mov     %rax,R64_TRAPNO(%rsp)
+       mov     %rcx,R64_TRAPFN(%rsp)
+       mov     %rdx,R64_ERR(%rsp)
                                        /* now treat as fault from user */
                                        /* except that all the state is */
                                        /* already saved - we just have to */
                                        /* move the trapno and error into */
                                        /* the compatibility frame */
                                        /* now treat as fault from user */
                                        /* except that all the state is */
                                        /* already saved - we just have to */
                                        /* move the trapno and error into */
                                        /* the compatibility frame */
-       jmp     L_32bit_dispatch_after_fault
-
+       jmp     L_dispatch_U32_after_fault
 
 /*
  * Fatal exception handlers:
 
 /*
  * Fatal exception handlers:
@@ -862,12 +912,101 @@ Entry(idt64_mc)
        pushq   $(T_MACHINE_CHECK)
        jmp     L_dispatch      
 
        pushq   $(T_MACHINE_CHECK)
        jmp     L_dispatch      
 
+/*
+ * NMI
+ * This may or may not be fatal but extreme care is required
+ * because it may fall when control was already in another trampoline.
+ *
+ * We get here on IST2 stack which is used for NMIs only.
+ * We must be aware of the interrupted state:
+ *  - from user-space, we
+ *    - copy state to the PCB and continue;
+ *  - from kernel-space, we
+ *    - copy state to the kernel stack and continue, but
+ *    - check what GSBASE was active, set the kernel base and
+ *    - ensure that the active state is restored when the NMI is dismissed.
+ */
+Entry(idt64_nmi)
+       push    %rax                            /* save RAX to ISF64_ERR */
+       push    %rcx                            /* save RCX to ISF64_TRAPFN */
+       push    %rdx                            /* save RDX to ISF64_TRAPNO */
+       testb   $3, ISF64_CS(%rsp)              /* NMI from user-space? */
+       je      1f
+
+       /* From user-space: copy interrupt state to user PCB */
+       swapgs
+       mov     %gs:CPU_UBER_ISF, %rcx          /* PCB stack addr */
+       add     $(ISF64_SIZE), %rcx             /* adjust to base of ISF */     
+       swapgs                                  /* swap back for L_dispatch */
+       jmp     4f                              /* Copy state to PCB */
+
+1:
+       /*
+       * From kernel-space:
+        * Determine whether the kernel or user GS is set.
+        * Set the kernel and ensure that we'll swap back correctly at IRET.
+        */
+       mov     $(MSR_IA32_GS_BASE), %ecx
+       rdmsr                                   /* read kernel gsbase */
+       test    $0x80000000, %edx               /* test MSB of address */
+       jne     2f
+       swapgs                                  /* so swap */
+       movl    $1, ISF64_CS+4(%rsp)            /* and set flag in CS slot */
+2:
+       /*
+        * Determine whether we're on the kernel or interrupt stack
+        * when the NMI hit.
+        */
+       mov     ISF64_RSP(%rsp), %rcx
+       mov     %gs:CPU_KERNEL_STACK, %rax
+       xor     %rcx, %rax
+       and     EXT(kernel_stack_mask)(%rip), %rax
+       test    %rax, %rax              /* are we on the kernel stack? */
+       je      3f                      /* yes */
+
+       mov     %gs:CPU_INT_STACK_TOP, %rax
+       dec     %rax                    /* intr stack top is byte above max */
+       xor     %rcx, %rax
+       and     EXT(kernel_stack_mask)(%rip), %rax
+       test    %rax, %rax              /* are we on the interrupt stack? */
+       je      3f                      /* yes */
+
+       mov    %gs:CPU_KERNEL_STACK, %rcx
+3:
+       /* 16-byte-align kernel/interrupt stack for state push */
+       and     $0xFFFFFFFFFFFFFFF0, %rcx
+
+4:
+       /*
+        * Copy state from NMI stack (RSP) to the save area (RCX) which is
+        * the PCB for user or kernel/interrupt stack from kernel.
+        * ISF64_ERR(RSP)    saved RAX
+        * ISF64_TRAPFN(RSP) saved RCX
+        * ISF64_TRAPNO(RSP) saved RDX
+        */
+       xchg    %rsp, %rcx                      /* set for pushes */
+       push    ISF64_SS(%rcx)
+       push    ISF64_RSP(%rcx)
+       push    ISF64_RFLAGS(%rcx)
+       push    ISF64_CS(%rcx)
+       push    ISF64_RIP(%rcx)
+       push    $(0)                            /* error code 0 */
+       lea     HNDL_ALLINTRS(%rip), %rax
+       push    %rax                            /* trapfn allintrs */
+       push    $(T_NMI)                        /* trapno T_NMI */
+       mov     ISF64_ERR(%rcx), %rax
+       mov     ISF64_TRAPNO(%rcx), %rdx
+       mov     ISF64_TRAPFN(%rcx), %rcx
+       jmp     L_dispatch
 
 
-/* All 'exceptions' enter hndl_alltraps:
- *     rsp     -> x86_saved_state_t
- *     esi        cs at trap
+
+/* All 'exceptions' enter hndl_alltraps, with:
+ *     r15     x86_saved_state_t address
+ *     rsp     kernel stack if user-space, otherwise interrupt or kernel stack
+ *     esi     cs at trap
  * 
  * The rest of the state is set up as: 
  * 
  * The rest of the state is set up as: 
+ *     both rsp and r15 are 16-byte aligned
  *     interrupts disabled
  *     direction flag cleared
  */
  *     interrupts disabled
  *     direction flag cleared
  */
@@ -880,61 +1019,60 @@ Entry(hndl_alltraps)
 
        /* Check for active vtimers in the current task */
        mov     %gs:CPU_ACTIVE_THREAD, %rcx
 
        /* Check for active vtimers in the current task */
        mov     %gs:CPU_ACTIVE_THREAD, %rcx
+       movl    $-1, TH_IOTIER_OVERRIDE(%rcx)   /* Reset IO tier override to -1 before handling trap/exception */
        mov     TH_TASK(%rcx), %rbx
        TASK_VTIMER_CHECK(%rbx, %rcx)
 
        mov     TH_TASK(%rcx), %rbx
        TASK_VTIMER_CHECK(%rbx, %rcx)
 
-       movq    %rsp, %rdi                      /* also pass it as arg0 */
-       movq    %gs:CPU_KERNEL_STACK,%rsp       /* switch to kernel stack */
-
-       CCALL(user_trap)                        /* call user trap routine */
+       CCALL1(user_trap, %r15)                 /* call user trap routine */
        /* user_trap() unmasks interrupts */
        cli                                     /* hold off intrs - critical section */
        xorl    %ecx, %ecx                      /* don't check if we're in the PFZ */
 
        /* user_trap() unmasks interrupts */
        cli                                     /* hold off intrs - critical section */
        xorl    %ecx, %ecx                      /* don't check if we're in the PFZ */
 
-#define CLI cli
-#define STI sti
 
 Entry(return_from_trap)
 
 Entry(return_from_trap)
-       movq    %gs:CPU_ACTIVE_THREAD,%rsp
-       movq    TH_PCB_ISS(%rsp), %rsp  /* switch back to PCB stack */
+       movq    %gs:CPU_ACTIVE_THREAD,%r15      /* Get current thread */
+       movl    $-1, TH_IOTIER_OVERRIDE(%r15)   /* Reset IO tier override to -1 before returning to userspace */
+       cmpl    $0, TH_RWLOCK_COUNT(%r15)       /* Check if current thread has pending RW locks held */
+       jz      1f
+       xorq    %rbp, %rbp              /* clear framepointer */
+       mov     %r15, %rdi              /* Set RDI to current thread */
+       CCALL(lck_rw_clear_promotions_x86)      /* Clear promotions if needed */
+1:     
+       movq    TH_PCB_ISS(%r15), %r15          /* PCB stack */
        movl    %gs:CPU_PENDING_AST,%eax
        testl   %eax,%eax
        movl    %gs:CPU_PENDING_AST,%eax
        testl   %eax,%eax
-       je      EXT(return_to_user)     /* branch if no AST */
+       je      EXT(return_to_user)             /* branch if no AST */
 
 L_return_from_trap_with_ast:
 
 L_return_from_trap_with_ast:
-       movq    %rsp, %r13
-       movq    %gs:CPU_KERNEL_STACK, %rsp
-
        testl   %ecx, %ecx              /* see if we need to check for an EIP in the PFZ */
        je      2f                      /* no, go handle the AST */
        testl   %ecx, %ecx              /* see if we need to check for an EIP in the PFZ */
        je      2f                      /* no, go handle the AST */
-       cmpl    $(SS_64), SS_FLAVOR(%r13)       /* are we a 64-bit task? */
+       cmpl    $(SS_64), SS_FLAVOR(%r15)       /* are we a 64-bit task? */
        je      1f
                                        /* no... 32-bit user mode */
        je      1f
                                        /* no... 32-bit user mode */
-       movl    R32_EIP(%r13), %edi
+       movl    R32_EIP(%r15), %edi
        xorq    %rbp, %rbp              /* clear framepointer */
        CCALL(commpage_is_in_pfz32)
        testl   %eax, %eax
        je      2f                      /* not in the PFZ... go service AST */
        xorq    %rbp, %rbp              /* clear framepointer */
        CCALL(commpage_is_in_pfz32)
        testl   %eax, %eax
        je      2f                      /* not in the PFZ... go service AST */
-       movl    %eax, R32_EBX(%r13)     /* let the PFZ know we've pended an AST */
-       movq    %r13, %rsp              /* switch back to PCB stack */
+       movl    %eax, R32_EBX(%r15)     /* let the PFZ know we've pended an AST */
        jmp     EXT(return_to_user)
 1:
        jmp     EXT(return_to_user)
 1:
-       movq    R64_RIP(%r13), %rdi
+       movq    R64_RIP(%r15), %rdi
        xorq    %rbp, %rbp              /* clear framepointer */
        CCALL(commpage_is_in_pfz64)
        testl   %eax, %eax
        je      2f                      /* not in the PFZ... go service AST */
        xorq    %rbp, %rbp              /* clear framepointer */
        CCALL(commpage_is_in_pfz64)
        testl   %eax, %eax
        je      2f                      /* not in the PFZ... go service AST */
-       movl    %eax, R64_RBX(%r13)     /* let the PFZ know we've pended an AST */
-       movq    %r13, %rsp              /* switch back to PCB stack */
+       movl    %eax, R64_RBX(%r15)     /* let the PFZ know we've pended an AST */
        jmp     EXT(return_to_user)
 2:     
        jmp     EXT(return_to_user)
 2:     
-       STI                             /* interrupts always enabled on return to user mode */
+       sti                             /* interrupts always enabled on return to user mode */
 
        xor     %edi, %edi              /* zero %rdi */
        xorq    %rbp, %rbp              /* clear framepointer */
        CCALL(i386_astintr)             /* take the AST */
 
 
        xor     %edi, %edi              /* zero %rdi */
        xorq    %rbp, %rbp              /* clear framepointer */
        CCALL(i386_astintr)             /* take the AST */
 
-       CLI
+       cli
+       mov     %rsp, %r15              /* AST changes stack, saved state */
        xorl    %ecx, %ecx              /* don't check if we're in the PFZ */
        jmp     EXT(return_from_trap)   /* and check again (rare) */
 
        xorl    %ecx, %ecx              /* don't check if we're in the PFZ */
        jmp     EXT(return_from_trap)   /* and check again (rare) */
 
@@ -942,25 +1080,25 @@ L_return_from_trap_with_ast:
  * Trap from kernel mode.  No need to switch stacks.
  * Interrupts must be off here - we will set them to state at time of trap
  * as soon as it's safe for us to do so and not recurse doing preemption
  * Trap from kernel mode.  No need to switch stacks.
  * Interrupts must be off here - we will set them to state at time of trap
  * as soon as it's safe for us to do so and not recurse doing preemption
+ * 
  */
  */
-hndl_kerntrap:
 trap_from_kernel:
 trap_from_kernel:
-       
-       movq    %rsp, %rdi              /* saved state addr */
-       pushq   R64_RIP(%rsp)           /* Simulate a CALL from fault point */
+       movq    %r15, %rdi              /* saved state addr */
+       pushq   R64_RIP(%r15)           /* Simulate a CALL from fault point */
        pushq   %rbp                    /* Extend framepointer chain */
        movq    %rsp, %rbp
        CCALLWITHSP(kernel_trap)        /* to kernel trap routine */
        popq    %rbp
        addq    $8, %rsp
        pushq   %rbp                    /* Extend framepointer chain */
        movq    %rsp, %rbp
        CCALLWITHSP(kernel_trap)        /* to kernel trap routine */
        popq    %rbp
        addq    $8, %rsp
+       mov     %rsp, %r15              /* DTrace slides stack/saved-state */
        cli
 
        movl    %gs:CPU_PENDING_AST,%eax        /* get pending asts */
        testl   $(AST_URGENT),%eax              /* any urgent preemption? */
        je      ret_to_kernel                   /* no, nothing to do */
        cli
 
        movl    %gs:CPU_PENDING_AST,%eax        /* get pending asts */
        testl   $(AST_URGENT),%eax              /* any urgent preemption? */
        je      ret_to_kernel                   /* no, nothing to do */
-       cmpl    $(T_PREEMPT),R64_TRAPNO(%rsp)
+       cmpl    $(T_PREEMPT),R64_TRAPNO(%r15)
        je      ret_to_kernel                   /* T_PREEMPT handled in kernel_trap() */
        je      ret_to_kernel                   /* T_PREEMPT handled in kernel_trap() */
-       testl   $(EFL_IF),R64_RFLAGS(%rsp)      /* interrupts disabled? */
+       testl   $(EFL_IF),R64_RFLAGS(%r15)      /* interrupts disabled? */
        je      ret_to_kernel
        cmpl    $0,%gs:CPU_PREEMPTION_LEVEL     /* preemption disabled? */
        jne     ret_to_kernel
        je      ret_to_kernel
        cmpl    $0,%gs:CPU_PREEMPTION_LEVEL     /* preemption disabled? */
        jne     ret_to_kernel
@@ -972,14 +1110,18 @@ trap_from_kernel:
        jne     ret_to_kernel           /* no, skip it */
 
        CCALL1(i386_astintr, $1)        /* take the AST */
        jne     ret_to_kernel           /* no, skip it */
 
        CCALL1(i386_astintr, $1)        /* take the AST */
+
+       mov     %rsp, %r15              /* AST changes stack, saved state */
        jmp     ret_to_kernel
 
 
 /*
  * All interrupts on all tasks enter here with:
        jmp     ret_to_kernel
 
 
 /*
  * All interrupts on all tasks enter here with:
- *     rsp->    x86_saved_state_t
+ *     r15      x86_saved_state_t
+ *     rsp      kernel or interrupt stack
  *     esi      cs at trap
  *
  *     esi      cs at trap
  *
+ *     both rsp and r15 are 16-byte aligned
  *     interrupts disabled
  *     direction flag cleared
  */
  *     interrupts disabled
  *     direction flag cleared
  */
@@ -1000,9 +1142,9 @@ Entry(hndl_allintrs)
        orl     $(CR0_TS),%eax          /* or in TS bit */
        mov     %rax,%cr0               /* set cr0 */
 
        orl     $(CR0_TS),%eax          /* or in TS bit */
        mov     %rax,%cr0               /* set cr0 */
 
-       subq    $8, %rsp                /* for 16-byte stack alignment */
        pushq   %rcx                    /* save pointer to old stack */
        pushq   %rcx                    /* save pointer to old stack */
-       movq    %rcx,%gs:CPU_INT_STATE  /* save intr state */
+       pushq   %gs:CPU_INT_STATE       /* save previous intr state */
+       movq    %r15,%gs:CPU_INT_STATE  /* set intr state */
        
        TIME_INT_ENTRY                  /* do timing */
 
        
        TIME_INT_ENTRY                  /* do timing */
 
@@ -1014,13 +1156,7 @@ Entry(hndl_allintrs)
        incl    %gs:CPU_PREEMPTION_LEVEL
        incl    %gs:CPU_INTERRUPT_LEVEL
 
        incl    %gs:CPU_PREEMPTION_LEVEL
        incl    %gs:CPU_INTERRUPT_LEVEL
 
-       movq    %gs:CPU_INT_STATE, %rdi
-
-       CCALL(interrupt)                /* call generic interrupt routine */
-
-       cli                             /* just in case we returned with intrs enabled */
-       xor     %rax,%rax
-       movq    %rax,%gs:CPU_INT_STATE  /* clear intr state pointer */
+       CCALL1(interrupt, %r15)         /* call generic interrupt routine */
 
        .globl  EXT(return_to_iret)
 LEXT(return_to_iret)                   /* (label for kdb_kintr and hardclock) */
 
        .globl  EXT(return_to_iret)
 LEXT(return_to_iret)                   /* (label for kdb_kintr and hardclock) */
@@ -1030,6 +1166,9 @@ LEXT(return_to_iret)                      /* (label for kdb_kintr and hardclock) */
 
        TIME_INT_EXIT                   /* do timing */
 
 
        TIME_INT_EXIT                   /* do timing */
 
+       popq    %gs:CPU_INT_STATE       /* reset/clear intr state pointer */
+       popq    %rsp                    /* switch back to old stack */
+
        movq    %gs:CPU_ACTIVE_THREAD,%rax
        movq    TH_PCB_FPS(%rax),%rax   /* get pcb's ifps */
        cmpq    $0,%rax                 /* Is there a context */
        movq    %gs:CPU_ACTIVE_THREAD,%rax
        movq    TH_PCB_FPS(%rax),%rax   /* get pcb's ifps */
        cmpq    $0,%rax                 /* Is there a context */
@@ -1044,24 +1183,22 @@ LEXT(return_to_iret)                    /* (label for kdb_kintr and hardclock) */
        orl     $(CR0_TS),%eax          /* or in TS bit */
        mov     %rax,%cr0               /* set cr0 */
 2:
        orl     $(CR0_TS),%eax          /* or in TS bit */
        mov     %rax,%cr0               /* set cr0 */
 2:
-       popq    %rsp                    /* switch back to old stack */
-
        /* Load interrupted code segment into %eax */
        /* Load interrupted code segment into %eax */
-       movl    R32_CS(%rsp),%eax               /* assume 32-bit state */
-       cmpl    $(SS_64),SS_FLAVOR(%rsp)/* 64-bit? */   
+       movl    R32_CS(%r15),%eax       /* assume 32-bit state */
+       cmpl    $(SS_64),SS_FLAVOR(%r15)/* 64-bit? */   
 #if DEBUG_IDT64
        jne     4f
 #if DEBUG_IDT64
        jne     4f
-       movl    R64_CS(%rsp),%eax       /* 64-bit user mode */
+       movl    R64_CS(%r15),%eax       /* 64-bit user mode */
        jmp     3f
 4:
        jmp     3f
 4:
-       cmpl    $(SS_32),SS_FLAVOR(%rsp)
+       cmpl    $(SS_32),SS_FLAVOR(%r15)
        je      3f
        POSTCODE2(0x6431)
        je      3f
        POSTCODE2(0x6431)
-       CCALL1(panic_idt64, %rsp)
+       CCALL1(panic_idt64, %r15)
        hlt
 #else
        jne     3f
        hlt
 #else
        jne     3f
-       movl    R64_CS(%rsp),%eax       /* 64-bit user mode */
+       movl    R64_CS(%r15),%eax       /* 64-bit user mode */
 #endif
 3:
        testb   $3,%al                  /* user mode, */
 #endif
 3:
        testb   $3,%al                  /* user mode, */
@@ -1078,13 +1215,6 @@ LEXT(return_to_iret)                     /* (label for kdb_kintr and hardclock) */
        cmpl    $0,%gs:CPU_PREEMPTION_LEVEL     /* preemption disabled? */
        jne     ret_to_kernel                   /* yes, skip it */
 
        cmpl    $0,%gs:CPU_PREEMPTION_LEVEL     /* preemption disabled? */
        jne     ret_to_kernel                   /* yes, skip it */
 
-       movq    %gs:CPU_KERNEL_STACK,%rax
-       movq    %rsp,%rcx
-       xorq    %rax,%rcx
-       andq    EXT(kernel_stack_mask)(%rip),%rcx
-       testq   %rcx,%rcx                       /* are we on the kernel stack? */
-       jne     ret_to_kernel                   /* no, skip it */
-
        /*
         * Take an AST from kernel space.  We don't need (and don't want)
         * to do as much as the case where the interrupt came from user
        /*
         * Take an AST from kernel space.  We don't need (and don't want)
         * to do as much as the case where the interrupt came from user
@@ -1092,6 +1222,7 @@ LEXT(return_to_iret)                      /* (label for kdb_kintr and hardclock) */
         */
        CCALL1(i386_astintr, $1)
 
         */
        CCALL1(i386_astintr, $1)
 
+       mov     %rsp, %r15              /* AST changes stack, saved state */
        jmp     ret_to_kernel
 
 
        jmp     ret_to_kernel
 
 
@@ -1102,17 +1233,18 @@ int_from_intstack:
        incl    %gs:CPU_PREEMPTION_LEVEL
        incl    %gs:CPU_INTERRUPT_LEVEL
        incl    %gs:CPU_NESTED_ISTACK
        incl    %gs:CPU_PREEMPTION_LEVEL
        incl    %gs:CPU_INTERRUPT_LEVEL
        incl    %gs:CPU_NESTED_ISTACK
-       mov     %rsp, %rdi              /* x86_saved_state */
-       CCALL(interrupt)
+
+       push    %gs:CPU_INT_STATE
+       mov     %r15, %gs:CPU_INT_STATE
+
+       CCALL1(interrupt, %r15)
+
+       pop     %gs:CPU_INT_STATE
 
        decl    %gs:CPU_INTERRUPT_LEVEL
        decl    %gs:CPU_PREEMPTION_LEVEL
        decl    %gs:CPU_NESTED_ISTACK
 
        decl    %gs:CPU_INTERRUPT_LEVEL
        decl    %gs:CPU_PREEMPTION_LEVEL
        decl    %gs:CPU_NESTED_ISTACK
-#if DEBUG_IDT64
-       CCALL1(panic_idt64, %rsp)
-       POSTCODE2(0x6411)
-       hlt
-#endif
+
        jmp     ret_to_kernel
 
 /*
        jmp     ret_to_kernel
 
 /*
@@ -1136,7 +1268,10 @@ ast_from_interrupt_user:
  * 32bit Tasks
  * System call entries via INTR_GATE or sysenter:
  *
  * 32bit Tasks
  * System call entries via INTR_GATE or sysenter:
  *
- *     rsp      -> x86_saved_state32_t
+ *     r15      x86_saved_state32_t
+ *     rsp      kernel stack
+ *
+ *     both rsp and r15 are 16-byte aligned
  *     interrupts disabled
  *     direction flag cleared
  */
  *     interrupts disabled
  *     direction flag cleared
  */
@@ -1146,38 +1281,15 @@ Entry(hndl_sysenter)
         * We can be here either for a mach syscall or a unix syscall,
         * as indicated by the sign of the code:
         */
         * We can be here either for a mach syscall or a unix syscall,
         * as indicated by the sign of the code:
         */
-       movl    R32_EAX(%rsp),%eax
+       movl    R32_EAX(%r15),%eax
        testl   %eax,%eax
        js      EXT(hndl_mach_scall)            /* < 0 => mach */
                                                /* > 0 => unix */
        
 Entry(hndl_unix_scall)
        testl   %eax,%eax
        js      EXT(hndl_mach_scall)            /* < 0 => mach */
                                                /* > 0 => unix */
        
 Entry(hndl_unix_scall)
-/* If the caller (typically LibSystem) has recorded the cumulative size of
- * the arguments in EAX, copy them over from the user stack directly.
- * We recover from exceptions inline--if the copy loop doesn't complete
- * due to an exception, we fall back to copyin from compatibility mode.
- * We can potentially extend this mechanism to mach traps as well (DRK).
- */
-       testl   $(I386_SYSCALL_ARG_BYTES_MASK), %eax
-       jz      L_copy_args_continue
-       movl    %eax, %ecx
-       mov     %gs:CPU_UBER_ARG_STORE_VALID, %rbx
-       shrl    $(I386_SYSCALL_ARG_DWORDS_SHIFT), %ecx
-       andl    $(I386_SYSCALL_ARG_DWORDS_MASK), %ecx
-       mov     %gs:CPU_UBER_ARG_STORE, %rdi
-       mov     ISC32_RSP(%rsp), %rsi
-       add     $4, %rsi
-       movl    $0, (%rbx)
-
-EXT(idt64_unix_scall_copy_args):
-       rep movsl
-       movl    $1, (%rbx)
-L_copy_args_continue:
 
         TIME_TRAP_UENTRY
 
 
         TIME_TRAP_UENTRY
 
-       movq    %gs:CPU_KERNEL_STACK,%rdi
-       xchgq   %rdi,%rsp                       /* switch to kernel stack */
        movq    %gs:CPU_ACTIVE_THREAD,%rcx      /* get current thread     */
        movq    TH_TASK(%rcx),%rbx              /* point to current task  */
        incl    TH_SYSCALLS_UNIX(%rcx)          /* increment call count   */
        movq    %gs:CPU_ACTIVE_THREAD,%rcx      /* get current thread     */
        movq    TH_TASK(%rcx),%rbx              /* point to current task  */
        incl    TH_SYSCALLS_UNIX(%rcx)          /* increment call count   */
@@ -1187,7 +1299,7 @@ L_copy_args_continue:
 
        sti
 
 
        sti
 
-       CCALL(unix_syscall)
+       CCALL1(unix_syscall, %r15)
        /*
         * always returns through thread_exception_return
         */
        /*
         * always returns through thread_exception_return
         */
@@ -1196,8 +1308,6 @@ L_copy_args_continue:
 Entry(hndl_mach_scall)
        TIME_TRAP_UENTRY
 
 Entry(hndl_mach_scall)
        TIME_TRAP_UENTRY
 
-       movq    %gs:CPU_KERNEL_STACK,%rdi
-       xchgq   %rdi,%rsp                       /* switch to kernel stack */
        movq    %gs:CPU_ACTIVE_THREAD,%rcx      /* get current thread     */
        movq    TH_TASK(%rcx),%rbx              /* point to current task  */
        incl    TH_SYSCALLS_MACH(%rcx)          /* increment call count   */
        movq    %gs:CPU_ACTIVE_THREAD,%rcx      /* get current thread     */
        movq    TH_TASK(%rcx),%rbx              /* point to current task  */
        incl    TH_SYSCALLS_MACH(%rcx)          /* increment call count   */
@@ -1207,7 +1317,7 @@ Entry(hndl_mach_scall)
 
        sti
 
 
        sti
 
-       CCALL(mach_call_munger)
+       CCALL1(mach_call_munger, %r15)
        /*
         * always returns through thread_exception_return
         */
        /*
         * always returns through thread_exception_return
         */
@@ -1216,9 +1326,6 @@ Entry(hndl_mach_scall)
 Entry(hndl_mdep_scall)
        TIME_TRAP_UENTRY
 
 Entry(hndl_mdep_scall)
        TIME_TRAP_UENTRY
 
-       movq    %gs:CPU_KERNEL_STACK,%rdi
-       xchgq   %rdi,%rsp                       /* switch to kernel stack */
-
        /* Check for active vtimers in the current task */
        movq    %gs:CPU_ACTIVE_THREAD,%rcx      /* get current thread     */
        movq    TH_TASK(%rcx),%rbx              /* point to current task  */
        /* Check for active vtimers in the current task */
        movq    %gs:CPU_ACTIVE_THREAD,%rcx      /* get current thread     */
        movq    TH_TASK(%rcx),%rbx              /* point to current task  */
@@ -1226,7 +1333,7 @@ Entry(hndl_mdep_scall)
 
        sti
 
 
        sti
 
-       CCALL(machdep_syscall)
+       CCALL1(machdep_syscall, %r15)
        /*
         * always returns through thread_exception_return
         */
        /*
         * always returns through thread_exception_return
         */
@@ -1235,7 +1342,10 @@ Entry(hndl_mdep_scall)
  * 64bit Tasks
  * System call entries via syscall only:
  *
  * 64bit Tasks
  * System call entries via syscall only:
  *
- *     rsp      -> x86_saved_state64_t
+ *     r15      x86_saved_state64_t
+ *     rsp      kernel stack
+ *
+ *     both rsp and r15 are 16-byte aligned
  *     interrupts disabled
  *     direction flag cleared
  */
  *     interrupts disabled
  *     direction flag cleared
  */
@@ -1243,9 +1353,8 @@ Entry(hndl_mdep_scall)
 Entry(hndl_syscall)
        TIME_TRAP_UENTRY
 
 Entry(hndl_syscall)
        TIME_TRAP_UENTRY
 
-       movq    %gs:CPU_KERNEL_STACK,%rdi
-       xchgq   %rdi,%rsp                       /* switch to kernel stack */
        movq    %gs:CPU_ACTIVE_THREAD,%rcx      /* get current thread     */
        movq    %gs:CPU_ACTIVE_THREAD,%rcx      /* get current thread     */
+       movl    $-1, TH_IOTIER_OVERRIDE(%rcx)   /* Reset IO tier override to -1 before handling syscall */
        movq    TH_TASK(%rcx),%rbx              /* point to current task  */
 
        /* Check for active vtimers in the current task */
        movq    TH_TASK(%rcx),%rbx              /* point to current task  */
 
        /* Check for active vtimers in the current task */
@@ -1255,7 +1364,7 @@ Entry(hndl_syscall)
         * We can be here either for a mach, unix machdep or diag syscall,
         * as indicated by the syscall class:
         */
         * We can be here either for a mach, unix machdep or diag syscall,
         * as indicated by the syscall class:
         */
-       movl    R64_RAX(%rdi), %eax             /* syscall number/class */
+       movl    R64_RAX(%r15), %eax             /* syscall number/class */
        movl    %eax, %edx
        andl    $(SYSCALL_CLASS_MASK), %edx     /* syscall class */
        cmpl    $(SYSCALL_CLASS_MACH<<SYSCALL_CLASS_SHIFT), %edx
        movl    %eax, %edx
        andl    $(SYSCALL_CLASS_MASK), %edx     /* syscall class */
        cmpl    $(SYSCALL_CLASS_MACH<<SYSCALL_CLASS_SHIFT), %edx
@@ -1277,7 +1386,7 @@ Entry(hndl_unix_scall64)
        incl    TH_SYSCALLS_UNIX(%rcx)          /* increment call count   */
        sti
 
        incl    TH_SYSCALLS_UNIX(%rcx)          /* increment call count   */
        sti
 
-       CCALL(unix_syscall64)
+       CCALL1(unix_syscall64, %r15)
        /*
         * always returns through thread_exception_return
         */
        /*
         * always returns through thread_exception_return
         */
@@ -1287,7 +1396,7 @@ Entry(hndl_mach_scall64)
        incl    TH_SYSCALLS_MACH(%rcx)          /* increment call count   */
        sti
 
        incl    TH_SYSCALLS_MACH(%rcx)          /* increment call count   */
        sti
 
-       CCALL(mach_call_munger64)
+       CCALL1(mach_call_munger64, %r15)
        /*
         * always returns through thread_exception_return
         */
        /*
         * always returns through thread_exception_return
         */
@@ -1297,18 +1406,15 @@ Entry(hndl_mach_scall64)
 Entry(hndl_mdep_scall64)
        sti
 
 Entry(hndl_mdep_scall64)
        sti
 
-       CCALL(machdep_syscall64)
+       CCALL1(machdep_syscall64, %r15)
        /*
         * always returns through thread_exception_return
         */
 
 Entry(hndl_diag_scall64)
        /*
         * always returns through thread_exception_return
         */
 
 Entry(hndl_diag_scall64)
-       pushq   %rdi                    // Push the previous stack
-       CCALL(diagCall64)               // Call diagnostics
-       cli                             // Disable interruptions just in case
+       CCALL1(diagCall64, %r15)        // Call diagnostics
        test    %eax, %eax              // What kind of return is this?
        je      1f                      // - branch if bad (zero)
        test    %eax, %eax              // What kind of return is this?
        je      1f                      // - branch if bad (zero)
-       popq    %rsp                    // Get back the pcb stack
        jmp     EXT(return_to_user)     // Normal return, do not check asts...
 1:
        sti
        jmp     EXT(return_to_user)     // Normal return, do not check asts...
 1:
        sti
@@ -1316,9 +1422,9 @@ Entry(hndl_diag_scall64)
        /* no return */
 
 Entry(hndl_machine_check)
        /* no return */
 
 Entry(hndl_machine_check)
-       CCALL1(panic_machine_check64, %rsp)
+       CCALL1(panic_machine_check64, %r15)
        hlt
 
 Entry(hndl_double_fault)
        hlt
 
 Entry(hndl_double_fault)
-       CCALL1(panic_double_fault64, %rsp)
+       CCALL1(panic_double_fault64, %r15)
        hlt
        hlt