]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/x86_64/idt64.s
xnu-3789.51.2.tar.gz
[apple/xnu.git] / osfmk / x86_64 / idt64.s
index a4ca1cecd6b930c544cfe9a9865f4305c7f2c126..3ab3d89bc4f1bf3968e4f8d7b49a20b3a5f81e33 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -27,9 +27,9 @@
  */
 #include <i386/asm.h>
 #include <assym.s>
-#include <mach_kdb.h>
+#include <debug.h>
 #include <i386/eflags.h>
-#include <i386/rtclock.h>
+#include <i386/rtclock_asm.h>
 #include <i386/trap.h>
 #define _ARCH_I386_ASM_HELP_H_ /* Prevent inclusion of user header */
 #include <mach/i386/syscall_sw.h>
 #define        HNDL_UNIX_SCALL         EXT(hndl_unix_scall)
 #define        HNDL_MACH_SCALL         EXT(hndl_mach_scall)
 #define        HNDL_MDEP_SCALL         EXT(hndl_mdep_scall)
-#define        HNDL_DIAG_SCALL         EXT(hndl_diag_scall)
 #define        HNDL_DOUBLE_FAULT       EXT(hndl_double_fault)
 #define        HNDL_MACHINE_CHECK      EXT(hndl_machine_check)
 
-/*
- * Nanosecond timing.
- */
-
-/*
- * Nanotime returned in %rax.
- * Computed from tsc based on the scale factor and an implicit 32 bit shift.
- * This code must match what _rtc_nanotime_read does in
- * machine_routines_asm.s.  Failure to do so can
- * result in "weird" timing results.
- *
- * Uses: %rsi, %rdi, %rdx, %rcx
- */
-#define NANOTIME                                                         \
-       movq    %gs:CPU_NANOTIME,%rdi                                   ; \
-       RTC_NANOTIME_READ_FAST()
-
-/*
- * Add 64-bit delta in register reg to timer pointed to by register treg.
- */
-#define TIMER_UPDATE(treg,reg,offset)                                            \
-       addq    reg,(offset)+TIMER_ALL(treg)            /* add timer */
-
-/*
- * Add time delta to old timer and start new.
- * Uses: %rsi, %rdi, %rdx, %rcx, %rax
- */
-#define TIMER_EVENT(old,new)                                             \
-       NANOTIME                                /* %rax := nanosecs */  ; \
-       movq    %rax,%rsi                       /* save timestamp */    ; \
-       movq    %gs:CPU_ACTIVE_THREAD,%rcx              /* get thread */        ; \
-       subq    (old##_TIMER)+TIMER_TSTAMP(%rcx),%rax   /* compute elapsed */   ; \
-       TIMER_UPDATE(%rcx,%rax,old##_TIMER)     /* update timer */      ; \
-       leaq    (new##_TIMER)(%rcx),%rcx        /* point to new timer */; \
-       movq    %rsi,TIMER_TSTAMP(%rcx)         /* set timestamp */     ; \
-       movq    %gs:CPU_PROCESSOR,%rdx          /* get processor */     ; \
-       movq    %rcx,THREAD_TIMER(%rdx)         /* set current timer */ ; \
-       movq    %rsi,%rax                       /* restore timestamp */ ; \
-       subq    (old##_STATE)+TIMER_TSTAMP(%rdx),%rax   /* compute elapsed */   ; \
-       TIMER_UPDATE(%rdx,%rax,old##_STATE)     /* update timer */      ; \
-       leaq    (new##_STATE)(%rdx),%rcx        /* point to new state */; \
-       movq    %rcx,CURRENT_STATE(%rdx)        /* set current state */ ; \
-       movq    %rsi,TIMER_TSTAMP(%rcx)         /* set timestamp */
-
-/*
- * Update time on user trap entry.
- * Uses: %rsi, %rdi, %rdx, %rcx, %rax
- */
-#define        TIME_TRAP_UENTRY        TIMER_EVENT(USER,SYSTEM)
-
-/*
- * update time on user trap exit.
- * Uses: %rsi, %rdi, %rdx, %rcx, %rax
- */
-#define        TIME_TRAP_UEXIT         TIMER_EVENT(SYSTEM,USER)
-
-/*
- * update time on interrupt entry.
- * Uses: %rsi, %rdi, %rdx, %rcx, %rax
- * Saves processor state info on stack.
- */
-#define        TIME_INT_ENTRY                                                    \
-       NANOTIME                                /* %rax := nanosecs */  ; \
-       movq    %rax,%gs:CPU_INT_EVENT_TIME     /* save in cpu data */  ; \
-       movq    %rax,%rsi                       /* save timestamp */    ; \
-       movq    %gs:CPU_PROCESSOR,%rdx          /* get processor */     ; \
-       movq    THREAD_TIMER(%rdx),%rcx         /* get current timer */ ; \
-       subq    TIMER_TSTAMP(%rcx),%rax         /* compute elapsed */   ; \
-       TIMER_UPDATE(%rcx,%rax,0)                       /* update timer */      ; \
-       movq    KERNEL_TIMER(%rdx),%rcx         /* get kernel timer */  ; \
-       movq    %rsi,TIMER_TSTAMP(%rcx)         /* set timestamp */     ; \
-       movq    %rsi,%rax                       /* restore timestamp */ ; \
-       movq    CURRENT_STATE(%rdx),%rcx        /* get current state */ ; \
-       pushq   %rcx                            /* save state */        ; \
-       subq    TIMER_TSTAMP(%rcx),%rax         /* compute elapsed */   ; \
-       TIMER_UPDATE(%rcx,%rax,0)                       /* update timer */      ; \
-       leaq    IDLE_STATE(%rdx),%rax           /* get idle state */    ; \
-       cmpq    %rax,%rcx                       /* compare current */   ; \
-       je      0f                              /* skip if equal */     ; \
-       leaq    SYSTEM_STATE(%rdx),%rcx         /* get system state */  ; \
-       movq    %rcx,CURRENT_STATE(%rdx)        /* set current state */ ; \
-0:     movq    %rsi,TIMER_TSTAMP(%rcx)         /* set timestamp */
-
-/*
- * update time on interrupt exit.
- * Uses: %rsi, %rdi, %rdx, %rcx, %rax
- * Restores processor state info from stack.
- */
-#define        TIME_INT_EXIT                                                     \
-       NANOTIME                                /* %rax := nanosecs */  ; \
-       movq    %rax,%gs:CPU_INT_EVENT_TIME     /* save in cpu data */  ; \
-       movq    %rax,%rsi                       /* save timestamp */    ; \
-       movq    %gs:CPU_PROCESSOR,%rdx          /* get processor */     ; \
-       movq    KERNEL_TIMER(%rdx),%rcx         /* get kernel timer */  ; \
-       subq    TIMER_TSTAMP(%rcx),%rax         /* compute elapsed */   ; \
-       TIMER_UPDATE(%rcx,%rax,0)                       /* update timer */      ; \
-       movq    THREAD_TIMER(%rdx),%rcx         /* interrupted timer */ ; \
-       movq    %rsi,TIMER_TSTAMP(%rcx)         /* set timestamp */     ; \
-       movq    %rsi,%rax                       /* restore timestamp */ ; \
-       movq    CURRENT_STATE(%rdx),%rcx        /* get current state */ ; \
-       subq    TIMER_TSTAMP(%rcx),%rax         /* compute elapsed */   ; \
-       TIMER_UPDATE(%rcx,%rax,0)                       /* update timer */      ; \
-       popq    %rcx                            /* restore state */     ; \
-       movq    %rcx,CURRENT_STATE(%rdx)        /* set current state */ ; \
-       movq    %rsi,TIMER_TSTAMP(%rcx)         /* set timestamp */
-
-/*
- * Check for vtimers for task.
- *   task_reg   is register pointing to current task
- *   thread_reg is register pointing to current thread
- */
-#define TASK_VTIMER_CHECK(task_reg,thread_reg)                           \
-       cmpl    $0,TASK_VTIMERS(task_reg)                               ; \
-       jz      1f                                                      ; \
-       orl     $(AST_BSD),%gs:CPU_PENDING_AST  /* Set pending AST */   ; \
-       lock                                                            ; \
-       orl     $(AST_BSD),ACT_AST(thread_reg)  /* Set thread AST  */   ; \
-1:                                                                     ; \
-
-
-/*
- * Macros for calling into C functions.
- * The stack is 16-byte aligned by masking.
- */
-#define CCALL(fn)                               \
-       mov     %rsp, %r12                      ;\
-       and     $0xFFFFFFFFFFFFFFF0, %rsp       ;\
-       call    EXT(fn)                         ;\
-       mov     %r12, %rsp
-
-#define CCALL1(fn, arg1)                        \
-       mov     arg1, %rdi                      ;\
-       CCALL(fn)
-
-#define CCALL2(fn, arg1, arg2)                  \
-       mov     arg1, %rdi                      ;\
-       CCALL(fn)
-
-#define CCALL3(fn, arg1, arg2, arg3)            \
-       mov     arg1, %rdi                      ;\
-       mov     arg2, %rsi                      ;\
-       mov     arg3, %rdx                      ;\
-       CCALL(fn)
 
 #if 1
 #define PUSH_FUNCTION(func)                     \
 
 /* 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 */
 /*
  * 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:
-       cmpq    $(KERNEL64_CS), ISF64_CS(%rsp)
-       je      L_64bit_dispatch
+       cmpl    $(KERNEL64_CS), ISF64_CS(%rsp)
+       je      L_dispatch_kernel
 
        swapgs
 
+L_dispatch_user:
        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
  */
-L_64bit_dispatch:
-       subq    $(ISS64_OFFSET), %rsp
-       movl    $(SS_64), SS_FLAVOR(%rsp)
+L_dispatch_64bit:
+       movl    $(SS_64), SS_FLAVOR(%r15)
 
        /*
         * Save segment regs - for completeness since theyre not used.
         */
-       mov     %fs, R64_FS(%rsp)
-       mov     %gs, R64_GS(%rsp)
+       movl    %fs, R64_FS(%r15)
+       movl    %gs, R64_GS(%r15)
 
        /* 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
-       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:
        /*
@@ -347,7 +217,7 @@ L_64bit_entry_reject:
        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:
        /*
@@ -357,91 +227,117 @@ L_32bit_entry_check:
        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)
 
        /*
         * Save segment regs
         */
-       mov     %ds, R32_DS(%rsp)
-       mov     %es, R32_ES(%rsp)
-       mov     %fs, R32_FS(%rsp)
-       mov     %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
         */
-       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
-       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.
         */
-       mov     ISC32_RIP(%rsp), %eax
-       mov     %eax, R32_EIP(%rsp)
-       mov     ISC32_RFLAGS(%rsp), %eax
-       mov     %eax, R32_EFLAGS(%rsp)
-       mov     ISC32_CS(%rsp), %esi            /* %esi := %cs for later */
-
-       mov     %esi, R32_CS(%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_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:
+       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
+        * On entering the kernel, we typically don't switch CR3
         * because the kernel shares the user's address space.
-        * But we mark the kernel's cr3 as "active".
-        * If, however, the invalid cr3 flag is set, we have to flush tlbs
-        * since the kernel's mapping was changed while we were in userspace.
+        * But we mark the kernel's cr3 as "active" for TLB coherency evaluation
+        * If, however, the CPU's invalid TLB flag is set, we have to invalidate the TLB
+        * since the kernel pagetables were changed while we were in userspace.
         *
-        * But: if global no_shared_cr3 is TRUE we do switch to the kernel's cr3
+        * For threads with a mapped pagezero (some WINE games) on non-SMAP platforms,
+        * we switch to the kernel's address space on entry. Also, 
+        * if the global no_shared_cr3 is TRUE we do switch to the kernel's cr3
         * so that illicit accesses to userspace can be trapped.
         */
        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, %gs:CPU_PAGEZERO_MAPPED
+       jnz     11f
        cmpl    $0, EXT(no_shared_cr3)(%rip)
-       je      1f
+       je      2f
+11:
+       xor     %eax, %eax
+       movw    %gs:CPU_KERNEL_PCID, %ax
+       or      %rax, %rcx
        mov     %rcx, %cr3                      /* load kernel cr3 */
-       jmp     2f                              /* and skip tlb flush test */
-1:     
-       cmpl    $0, %gs:CPU_TLB_INVALID         /* flush needed? */
-       je      2f                              /* - no */
-       movl    $0, %gs:CPU_TLB_INVALID 
+       jmp     4f                              /* and skip tlb flush test */
+2:
+       mov     %gs:CPU_ACTIVE_CR3+4, %rcx
+       shr     $32, %rcx
+       testl   %ecx, %ecx
+       jz      4f
+       testl   $(1<<16), %ecx                  /* Global? */
+       jz      3f
+       movl    $0, %gs:CPU_TLB_INVALID
+       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     4f
+3:
+       movb    $0, %gs:CPU_TLB_INVALID_LOCAL
        mov     %cr3, %rcx
        mov     %rcx, %cr3
-2:
+4:
        mov     %gs:CPU_ACTIVE_THREAD, %rcx     /* Get the active thread */
-       cmpq    $0, ACT_PCB_IDS(%rcx)   /* Is there a debug register state? */
-       je      3f
-       mov     $0, %rcx                /* If so, reset DR7 (the control) */
+       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? */
+       je      5f
+       xor     %ecx, %ecx              /* If so, reset DR7 (the control) */
        mov     %rcx, %dr7
-3:
-       addl    $1,%gs:hwIntCnt(,%ebx,4)        // Bump the trap/intr count
+5:
+       incl    %gs:hwIntCnt(,%ebx,4)           // Bump the trap/intr count
        /* Dispatch the designated handler */
-       mov     %rsp, %rdi              /* rsp points to saved state */
        jmp     *%rdx
 
 /*
@@ -453,9 +349,9 @@ Entry(return_to_user)
 Entry(ret_to_user)
 // XXX 'Be nice to tidy up this debug register restore sequence...
        mov     %gs:CPU_ACTIVE_THREAD, %rdx
-       movq    ACT_PCB_IDS(%rdx),%rax  /* Obtain this thread's debug state */
+       movq    TH_PCB_IDS(%rdx),%rax   /* Obtain this thread's debug state */
        
-       cmpq    $0,%rax                 /* Is there a debug register context? */
+       test    %rax, %rax              /* Is there a debug register context? */
        je      2f                      /* branch if not */
        cmpl    $(TASK_MAP_32BIT), %gs:CPU_TASK_MAP /* Are we a 32-bit task? */
        jne     1f
@@ -483,91 +379,90 @@ Entry(ret_to_user)
        mov     %rcx, %gs:CPU_DR7
 2:
        /*
-        * On exiting the kernel there's no need to switch cr3 since we're
+        * On exiting the kernel there's typically no need to switch cr3 since we're
         * already running in the user's address space which includes the
-        * kernel. Nevertheless, we now mark the task's cr3 as active.
-        * However, there may be a defered tlb flush to deal with.
-        * This is a case where another cpu modified this task's address 
-        * space while this thread was in the kernel.
-        * But, if no_shared_cr3 is set, we do need to switch cr3 at this point.
+        * kernel. We now mark the task's cr3 as active, for TLB coherency.
+        * If the target address space has a pagezero mapping present, or
+        * if no_shared_cr3 is set, we do need to switch cr3 at this point.
         */
        mov     %gs:CPU_TASK_CR3, %rcx
        mov     %rcx, %gs:CPU_ACTIVE_CR3
-       movl    %gs:CPU_TLB_INVALID, %eax
-       orl     EXT(no_shared_cr3)(%rip), %eax
-       test    %eax, %eax              /* -no_shered_cr3 or flush required? */
-       jz      3f
-       movl    $0, %gs:CPU_TLB_INVALID
-       mov     %rcx, %cr3
-3:
+       cmpl    $0, %gs:CPU_PAGEZERO_MAPPED
+       jnz     L_cr3_switch_island
+       movl    EXT(no_shared_cr3)(%rip), %eax
+       test    %eax, %eax              /* -no_shared_cr3 */
+       jnz     L_cr3_switch_island
 
+L_cr3_switch_return:
        mov     %gs:CPU_DR7, %rax       /* Is there a debug control register?*/
        cmp     $0, %rax
        je      4f
        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
-       cmpl    $(SS_32), SS_FLAVOR(%rsp)       /* 32-bit state? */
+       cmpl    $(SS_32), SS_FLAVOR(%r15)       /* 32-bit state? */
        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.
+        * 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
         */
-       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):     
-       movw    R32_DS(%rsp), %ds
+       movl    R32_DS(%rsp), %ds
 EXT(ret32_set_es):
-       movw    R32_ES(%rsp), %es
+       movl    R32_ES(%rsp), %es
 EXT(ret32_set_fs):
-       movw    R32_FS(%rsp), %fs
+       movl    R32_FS(%rsp), %fs
 EXT(ret32_set_gs):
-       movw    R32_GS(%rsp), %gs
+       movl    R32_GS(%rsp), %gs
 
        /* pop compat frame + trapno, trapfn and error */       
-       add     $(ISC32_OFFSET)+8+8+8, %rsp
-        cmp    $(SYSENTER_CS),ISF64_CS-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
+       je      L_fast_exit
 EXT(ret32_iret):
-        iretq                          /* return from interrupt */
+       iretq                           /* return from interrupt */
 
+       
 L_fast_exit:
        pop     %rdx                    /* user return eip */
        pop     %rcx                    /* pop and toss cs */
@@ -575,53 +470,67 @@ L_fast_exit:
        popf                            /* flags - carry denotes failure */
        pop     %rcx                    /* user return esp */
        sti                             /* interrupts enabled after sysexit */
-       sysexit                         /* 32-bit sysexit */
+       sysexitl                        /* 32-bit sysexit */
+
+L_cr3_switch_island:
+       xor     %eax, %eax
+       movw    %gs:CPU_ACTIVE_PCID, %ax
+       or      %rax, %rcx
+       mov     %rcx, %cr3
+       jmp     L_cr3_switch_return
 
 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)
-       CCALL1(panic_idt64, %rsp)
+       CCALL1(panic_idt64, %r15)
        hlt
 1:
-       cmpq    $(KERNEL64_CS), R64_CS(%rsp)
+       cmpl    $(KERNEL64_CS), R64_CS(%r15)
        je      2f
-       CCALL1(panic_idt64, %rsp)
+       CCALL1(panic_idt64, %r15)
        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)
-                               /* test for fast entry/exit */
+                                               /* test for fast entry/exit */
        je      L_sysret
 .globl _dump_iretq
 EXT(ret64_iret):
@@ -631,7 +540,7 @@ L_sysret:
        /*
         * 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
@@ -653,7 +562,6 @@ L_sysret:
 #endif
 Entry(idt64_unix_scall)
        swapgs                          /* switch to kernel gs (cpu_data) */
-L_unix_scall_continue:
        pushq   %rax                    /* save system call number */
        PUSH_FUNCTION(HNDL_UNIX_SCALL)
        pushq   $(UNIX_INT)
@@ -662,7 +570,6 @@ L_unix_scall_continue:
        
 Entry(idt64_mach_scall)
        swapgs                          /* switch to kernel gs (cpu_data) */
-L_mach_scall_continue:
        pushq   %rax                    /* save system call number */
        PUSH_FUNCTION(HNDL_MACH_SCALL)
        pushq   $(MACH_INT)
@@ -671,25 +578,16 @@ L_mach_scall_continue:
        
 Entry(idt64_mdep_scall)
        swapgs                          /* switch to kernel gs (cpu_data) */
-L_mdep_scall_continue:
        pushq   %rax                    /* save system call number */
        PUSH_FUNCTION(HNDL_MDEP_SCALL)
        pushq   $(MACHDEP_INT)
        jmp     L_32bit_entry_check
 
-       
-Entry(idt64_diag_scall)
-       swapgs                          /* switch to kernel gs (cpu_data) */
-L_diag_scall_continue:
-       push    %rax                    /* save system call number */
-       PUSH_FUNCTION(HNDL_DIAG_SCALL)
-       pushq   $(DIAG_INT)
-       jmp     L_32bit_entry_check
-
+/* Programmed into MSR_IA32_LSTAR by mp_desc.c */
 Entry(hi64_syscall)
 Entry(idt64_syscall)
-       swapgs                          /* Kapow! get per-cpu data area */
 L_syscall_continue:
+       swapgs                          /* Kapow! get per-cpu data area */
        mov     %rsp, %gs:CPU_UBER_TMP  /* save user stack */
        mov     %gs:CPU_UBER_ISF, %rsp  /* switch stack to pcb */
 
@@ -707,7 +605,8 @@ L_syscall_continue:
        movq    $(T_SYSCALL), ISF64_TRAPNO(%rsp)        /* trapno */
        leaq    HNDL_SYSCALL(%rip), %r11;
        movq    %r11, ISF64_TRAPFN(%rsp)
-       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
@@ -729,9 +628,15 @@ Entry(idt64_sysenter)
        push    $(USER_DS)              /* ss */
        push    %rcx                    /* uesp */
        pushf                           /* flags */
+       /*
+        * Clear, among others, the Nested Task (NT) flags bit;
+        * this is zeroed by INT, but not by SYSENTER.
+        */
+       push    $0
+       popf
        push    $(SYSENTER_CS)          /* cs */ 
-       swapgs                          /* switch to kernel gs (cpu_data) */
 L_sysenter_continue:
+       swapgs                          /* switch to kernel gs (cpu_data) */
        push    %rdx                    /* eip */
        push    %rax                    /* err/eax - syscall code */
        PUSH_FUNCTION(HNDL_SYSENTER)
@@ -742,16 +647,13 @@ L_sysenter_continue:
 
 Entry(idt64_page_fault)
        PUSH_FUNCTION(HNDL_ALLTRAPS)
-       push    %rax                    /* save %rax temporarily in trap slot */
-       leaq    EXT(idt64_unix_scall_copy_args)(%rip), %rax
-       cmp     %rax, ISF64_RIP(%rsp)
-       jne     1f
-       add     $(ISF64_SIZE), %rsp     /* remove entire intr stack frame */
-       jmp     L_copy_args_continue    /* continue system call entry */
-1:
-       mov     (%rsp), %rax            /* restore %rax from trap slot */
-       movq    $(T_PAGE_FAULT), (%rsp) /* set trap code */
-       jne     L_dispatch
+       push    $(T_PAGE_FAULT)
+       push    %rax                    /* save %rax temporarily */
+       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_user
 
 
 /*
@@ -773,80 +675,39 @@ Entry(idt64_debug)
         */
 
        push    %rax                    /* save %rax temporarily */
-
-       leaq    EXT(idt64_mach_scall)(%rip), %rax
-       cmp     %rax, ISF64_RIP(%rsp)
-       jne     1f
-       pop     %rax
-       add     $(ISF64_SIZE),%rsp      /* remove entire intr stack frame */
-       jmp     L_mach_scall_continue   /* continue system call entry */
-1:
-       leaq    EXT(idt64_mdep_scall)(%rip), %rax
-       cmp     %rax, ISF64_RIP(%rsp)
-       jne     2f
-       pop     %rax
-       add     $(ISF64_SIZE),%rsp      /* remove entire intr stack frame */
-       jmp     L_mdep_scall_continue   /* continue system call entry */
-2:
-       leaq    EXT(idt64_unix_scall)(%rip), %rax
-       cmp     %rax, ISF64_RIP(%rsp)
-       jne     3f
-       pop     %rax
-       add     $(ISF64_SIZE),%rsp      /* remove entire intr stack frame */
-       jmp     L_unix_scall_continue   /* continue system call entry */
-3:
        lea     EXT(idt64_sysenter)(%rip), %rax
-       cmp     %rax, ISF64_RIP(%rsp)
-       je      4f
-       pop     %rax
-       jmp     L_dispatch
-4:
+       cmp     %rax, ISF64_RIP+8(%rsp)
        pop     %rax
+       jne     L_dispatch
        /*
         * Interrupt stack frame has been pushed on the temporary stack.
-        * We have to switch to pcb stack and copy eflags.
+        * We have to switch to pcb stack and patch up the saved state.
         */ 
-       add     $40,%rsp                /* remove trapno/trapfn/err/rip/cs */
-       push    %rcx                    /* save %rcx - user stack pointer */
-       mov     40(%rsp),%rcx           /* top of intr stack -> pcb stack */
+       mov     %rcx, ISF64_ERR(%rsp)   /* save %rcx in error slot */
+       mov     ISF64_SS+8(%rsp), %rcx  /* top of temp stack -> pcb stack */
        xchg    %rcx,%rsp               /* switch to pcb stack */
        push    $(USER_DS)              /* ss */
-       push    (%rcx)                  /* saved %rcx into rsp slot */
-       push    8(%rcx)                 /* rflags */
-       mov     (%rcx),%rcx             /* restore %rcx */
+       push    ISF64_ERR(%rcx)         /* saved %rcx into rsp slot */
+       push    ISF64_RFLAGS(%rcx)      /* rflags */
        push    $(SYSENTER_TF_CS)       /* cs - not SYSENTER_CS for iret path */
+       mov     ISF64_ERR(%rcx),%rcx    /* restore %rcx */
        jmp     L_sysenter_continue     /* continue sysenter entry */
-
        
 
 Entry(idt64_double_fault)
        PUSH_FUNCTION(HNDL_DOUBLE_FAULT)
        pushq   $(T_DOUBLE_FAULT)
+       jmp     L_dispatch_kernel
 
-       push    %rax
-       leaq    EXT(idt64_syscall)(%rip), %rax
-       cmp     %rax, ISF64_RIP(%rsp)
-       pop     %rax
-       jne     L_dispatch
-
-       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:        trap function
- *          8: trap code (NP or GP)
- *         16: segment number in error (error code)
- *         24: rip
- *         32: cs
- *         40: rflags 
- *         48: rsp
- *         56: 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)
@@ -863,100 +724,186 @@ Entry(idt64_segnp)
        pushq   $(T_SEGMENT_NOT_PRESENT)
                                        /* indicate fault type */
 trap_check_kernel_exit:
-       testb   $3,32(%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
+       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, 24+8(%rsp)
+       cmp     %rax, 8+ISF64_RIP(%rsp)
        je      L_fault_iret
        leaq    EXT(ret64_iret)(%rip), %rax
-       cmp     %rax, 24+8(%rsp)
+       cmp     %rax, 8+ISF64_RIP(%rsp)
        je      L_fault_iret
        leaq    EXT(ret32_set_ds)(%rip), %rax
-       cmp     %rax, 24+8(%rsp)
+       cmp     %rax, 8+ISF64_RIP(%rsp)
        je      L_32bit_fault_set_seg
        leaq    EXT(ret32_set_es)(%rip), %rax
-       cmp     %rax, 24+8(%rsp)
+       cmp     %rax, 8+ISF64_RIP(%rsp)
        je      L_32bit_fault_set_seg
        leaq    EXT(ret32_set_fs)(%rip), %rax
-       cmp     %rax, 24+8(%rsp)
+       cmp     %rax, 8+ISF64_RIP(%rsp)
        je      L_32bit_fault_set_seg
        leaq    EXT(ret32_set_gs)(%rip), %rax
-       cmp     %rax, 24+8(%rsp)
+       cmp     %rax, 8+ISF64_RIP(%rsp)
        je      L_32bit_fault_set_seg
 
-       leaq    EXT(idt64_unix_scall_copy_args)(%rip), %rax
-       cmp     %rax, 24+8(%rsp)
-       add     $(ISF64_SIZE)+8, (%rsp)
-       je      L_copy_args_continue
+       /* Fall through */
+
+L_kernel_trap:
+       /*
+        * Here after taking an unexpected trap from kernel mode - perhaps
+        * while running in the trampolines hereabouts.
+        * 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, ensure we have the kernel gs base active...
+        */
+       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:
+       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 */
+       jmp     L_dispatch_kernel
+2:
+       /*
+        *  Here if %rsp is in the PCB
+        *  Copy the interrupt stack frame from PCB stack to kernel stack
+        */
+       movq    %gs:CPU_KERNEL_STACK, %rax
+       xchgq   %rax, %rsp
+       pushq   8+ISF64_SS(%rax)
+       pushq   8+ISF64_RSP(%rax)
+       pushq   8+ISF64_RFLAGS(%rax)
+       pushq   8+ISF64_CS(%rax)
+       pushq   8+ISF64_RIP(%rax)
+       pushq   8+ISF64_ERR(%rax)
+       pushq   8+ISF64_TRAPFN(%rax)
+       pushq   8+ISF64_TRAPNO(%rax)
+       movq    (%rax), %rax
+       jmp     L_dispatch_kernel
 
-       pop %rax
-       jmp     L_dispatch
 
-               
 /*
  * 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)
- *   0 function
- *   8 trap number
- *  16 errcode
- *  24 rip
- *  32 cs
- *  40 rflags
- *  48 rsp             --> new trapfn
- *  56 ss              --> new trapno
- *  64 pad             --> new errcode
- *  72 user rip
- *  80 user cs
- *  88 user rflags
- *  96 user rsp
- * 104  user ss        (16-byte aligned)
+ * 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)
+ *  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, 24(%rsp)          /* save rax (we don`t need saved rip) */
-       mov     0(%rsp), %rax           /* get trap func */
-       mov     %rax, 48(%rsp)          /* put in user trap func */
-       mov     8(%rsp), %rax           /* get trap number */
-       mov     %rax, 56(%rsp)          /* put in user trap number */
-       mov     16(%rsp), %rax          /* get error code */
-       mov     %rax, 64(%rsp)          /* put in user errcode */
-       mov     24(%rsp), %rax          /* restore rax */
-       add     $48,%rsp                /* reset to new trapfn */
+       mov     %rax, ISF64_RIP(%rsp)   /* save rax (we don`t need saved rip) */
+       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.
+ * 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:
-       pop     %rax                    /* recover %rax from stack */
-       mov     0(%rsp), %rax           /* get trap function */
-       mov     8(%rsp), %rcx           /* get trap number */
-       mov     16(%rsp), %rdx          /* get error code */
-       mov     48(%rsp), %rsp          /* reset stack to saved state */
-       mov     %rax,ISC32_TRAPFN(%rsp)
-       mov     %rcx,ISC32_TRAPNO(%rsp)
-       mov     %rdx,ISC32_ERR(%rsp)
+       swapgs
+       pop     %rax                    /* toss saved %rax from stack */
+       mov     ISF64_TRAPNO(%rsp), %rax
+       mov     ISF64_TRAPFN(%rsp), %rcx
+       mov     ISF64_ERR(%rsp), %rdx
+       mov     ISF64_RSP(%rsp), %rsp   /* reset stack to saved state */
+       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 */
-       jmp     L_32bit_dispatch_after_fault
-
+       jmp     L_dispatch_U32_after_fault
 
 /*
  * Fatal exception handlers:
@@ -977,12 +924,101 @@ Entry(idt64_mc)
        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
 
-/* All 'exceptions' enter hndl_alltraps:
- *     rsp     -> x86_saved_state_t
- *     esi        cs at trap
+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, 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: 
+ *     both rsp and r15 are 16-byte aligned
  *     interrupts disabled
  *     direction flag cleared
  */
@@ -993,59 +1029,62 @@ Entry(hndl_alltraps)
 
        TIME_TRAP_UENTRY
 
-       movq    %gs:CPU_ACTIVE_THREAD,%rdi
-       movq    %rsp, ACT_PCB_ISS(%rdi)         /* stash the PCB stack */
-       movq    %rsp, %rdi                      /* also pass it as arg0 */
-       movq    %gs:CPU_KERNEL_STACK,%rsp       /* switch to kernel stack */
-       sti
+       /* 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)
 
-       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 */
-       movq    %gs:CPU_ACTIVE_THREAD,%rsp
-       movq    ACT_PCB_ISS(%rsp), %rsp         /* switch back to PCB stack */
        xorl    %ecx, %ecx                      /* don't check if we're in the PFZ */
 
-#define CLI cli
-#define STI sti
 
 Entry(return_from_trap)
+       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
-       je      EXT(return_to_user)     /* branch if no AST */
+       je      EXT(return_to_user)             /* branch if no 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 */
-       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 */
-       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 */
-       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:
-       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 */
-       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:     
-       STI                             /* interrupts always enabled on return to user mode */
-
-       xor     %edi, %edi                      /* zero %rdi */
-       CCALL(i386_astintr)     /* take the AST */
+       sti                             /* interrupts always enabled on return to user mode */
 
-       CLI
-       movq    %r13, %rsp                      /* switch back to PCB stack */
+       xor     %edi, %edi              /* zero %rdi */
+       xorq    %rbp, %rbp              /* clear framepointer */
+       CCALL(i386_astintr)             /* take the AST */
 
+       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) */
 
@@ -1053,25 +1092,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
+ * 
  */
-hndl_kerntrap:
 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
-       CCALL(kernel_trap)              /* to kernel trap routine */
+       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 */
-       cmpl    $(T_PREEMPT),R64_TRAPNO(%rsp)
+       cmpl    $(T_PREEMPT),R64_TRAPNO(%r15)
        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
@@ -1083,14 +1122,18 @@ trap_from_kernel:
        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:
- *     rsp->    x86_saved_state_t
+ *     r15      x86_saved_state_t
+ *     rsp      kernel or interrupt stack
  *     esi      cs at trap
  *
+ *     both rsp and r15 are 16-byte aligned
  *     interrupts disabled
  *     direction flag cleared
  */
@@ -1111,22 +1154,21 @@ Entry(hndl_allintrs)
        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 */
-       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 */
 
+       /* Check for active vtimers in the current task */
+       mov     %gs:CPU_ACTIVE_THREAD, %rcx
+       mov     TH_TASK(%rcx), %rbx
+       TASK_VTIMER_CHECK(%rbx, %rcx)
+
        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) */
@@ -1136,9 +1178,11 @@ LEXT(return_to_iret)                     /* (label for kdb_kintr and hardclock) */
 
        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    ACT_PCB(%rax),%rax      /* get act`s PCB */
-       movq    PCB_FPS(%rax),%rax      /* get pcb's ims.ifps */
+       movq    TH_PCB_FPS(%rax),%rax   /* get pcb's ifps */
        cmpq    $0,%rax                 /* Is there a context */
        je      1f                      /* Branch if not */
        movl    FP_VALID(%rax),%eax     /* Load fp_valid */
@@ -1151,24 +1195,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:
-       popq    %rsp                    /* switch back to old stack */
-
        /* 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
-       movl    R64_CS(%rsp),%eax       /* 64-bit user mode */
+       movl    R64_CS(%r15),%eax       /* 64-bit user mode */
        jmp     3f
 4:
-       cmpl    $(SS_32),SS_FLAVOR(%rsp)
+       cmpl    $(SS_32),SS_FLAVOR(%r15)
        je      3f
        POSTCODE2(0x6431)
-       CCALL1(panic_idt64, %rsp)
+       CCALL1(panic_idt64, %r15)
        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, */
@@ -1185,13 +1227,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 */
 
-       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
@@ -1199,6 +1234,7 @@ LEXT(return_to_iret)                      /* (label for kdb_kintr and hardclock) */
         */
        CCALL1(i386_astintr, $1)
 
+       mov     %rsp, %r15              /* AST changes stack, saved state */
        jmp     ret_to_kernel
 
 
@@ -1209,17 +1245,18 @@ int_from_intstack:
        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
-#if DEBUG_IDT64
-       CCALL1(panic_idt64, %rsp)
-       POSTCODE2(0x6411)
-       hlt
-#endif
+
        jmp     ret_to_kernel
 
 /*
@@ -1243,7 +1280,10 @@ ast_from_interrupt_user:
  * 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
  */
@@ -1253,49 +1293,25 @@ Entry(hndl_sysenter)
         * 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)
-/* 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
 
-       movq    %gs:CPU_KERNEL_STACK,%rdi
-       xchgq   %rdi,%rsp                       /* switch to kernel stack */
        movq    %gs:CPU_ACTIVE_THREAD,%rcx      /* get current thread     */
-       movq    %rdi,ACT_PCB_ISS(%rcx)
-       movq    ACT_TASK(%rcx),%rbx             /* point to current task  */
-       addl    $1,TASK_SYSCALLS_UNIX(%rbx)     /* increment call count   */
+       movq    TH_TASK(%rcx),%rbx              /* point to current task  */
+       incl    TH_SYSCALLS_UNIX(%rcx)          /* increment call count   */
 
        /* Check for active vtimers in the current task */
        TASK_VTIMER_CHECK(%rbx,%rcx)
 
        sti
 
-       CCALL(unix_syscall)
+       CCALL1(unix_syscall, %r15)
        /*
         * always returns through thread_exception_return
         */
@@ -1304,19 +1320,16 @@ L_copy_args_continue:
 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    %rdi,ACT_PCB_ISS(%rcx)
-       movq    ACT_TASK(%rcx),%rbx             /* point to current task  */
-       addl    $1,TASK_SYSCALLS_MACH(%rbx)     /* increment call count   */
+       movq    TH_TASK(%rcx),%rbx              /* point to current task  */
+       incl    TH_SYSCALLS_MACH(%rcx)          /* increment call count   */
 
        /* Check for active vtimers in the current task */
        TASK_VTIMER_CHECK(%rbx,%rcx)
 
        sti
 
-       CCALL(mach_call_munger)
+       CCALL1(mach_call_munger, %r15)
        /*
         * always returns through thread_exception_return
         */
@@ -1325,55 +1338,26 @@ Entry(hndl_mach_scall)
 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    ACT_TASK(%rcx),%rbx             /* point to current task  */
+       movq    TH_TASK(%rcx),%rbx              /* point to current task  */
        TASK_VTIMER_CHECK(%rbx,%rcx)
 
        sti
 
-       CCALL(machdep_syscall)
+       CCALL1(machdep_syscall, %r15)
        /*
         * always returns through thread_exception_return
         */
 
-
-Entry(hndl_diag_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    ACT_TASK(%rcx),%rbx             /* point to current task  */
-       TASK_VTIMER_CHECK(%rbx,%rcx)
-
-       pushq   %rdi                    /* push pcb stack */
-
-       CCALL(diagCall)                 // Call diagnostics
-
-       cli                             // Disable interruptions just in case
-       cmpl    $0,%eax                 // What kind of return is this?
-       je      1f                      // - branch if bad (zero)
-       popq    %rsp                    // Get back the original stack
-       jmp     EXT(return_to_user)     // Normal return, do not check asts...
-1:
-       CCALL3(i386_exception, $EXC_SYSCALL, $0x6000, $1)
-               // pass what would be the diag syscall
-               // error return - cause an exception
-       /* no return */
-       
-
-
 /*
  * 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
  */
@@ -1381,11 +1365,9 @@ Entry(hndl_diag_scall)
 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    %rdi, ACT_PCB_ISS(%rcx)
-       movq    ACT_TASK(%rcx),%rbx             /* point to current task  */
+       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 */
        TASK_VTIMER_CHECK(%rbx,%rcx)
@@ -1394,7 +1376,7 @@ Entry(hndl_syscall)
         * 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
@@ -1407,25 +1389,26 @@ Entry(hndl_syscall)
        je      EXT(hndl_diag_scall64)
 
        /* Syscall class unknown */
+       sti
        CCALL3(i386_exception, $(EXC_SYSCALL), %rax, $1)
        /* no return */
 
 
 Entry(hndl_unix_scall64)
-       addl    $1,TASK_SYSCALLS_UNIX(%rbx)     /* increment call count   */
+       incl    TH_SYSCALLS_UNIX(%rcx)          /* increment call count   */
        sti
 
-       CCALL(unix_syscall64)
+       CCALL1(unix_syscall64, %r15)
        /*
         * always returns through thread_exception_return
         */
 
 
 Entry(hndl_mach_scall64)
-       addl    $1,TASK_SYSCALLS_MACH(%rbx)     /* increment call count   */
+       incl    TH_SYSCALLS_MACH(%rcx)          /* increment call count   */
        sti
 
-       CCALL(mach_call_munger64)
+       CCALL1(mach_call_munger64, %r15)
        /*
         * always returns through thread_exception_return
         */
@@ -1435,30 +1418,25 @@ Entry(hndl_mach_scall64)
 Entry(hndl_mdep_scall64)
        sti
 
-       CCALL(machdep_syscall64)
+       CCALL1(machdep_syscall64, %r15)
        /*
         * 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
-       cmpl    $0,%eax                 // What kind of return is this?
+       CCALL1(diagCall64, %r15)        // Call diagnostics
+       test    %eax, %eax              // What kind of return is this?
        je      1f                      // - branch if bad (zero)
-       popq    %rsp                    // Get back the original stack
        jmp     EXT(return_to_user)     // Normal return, do not check asts...
 1:
+       sti
        CCALL3(i386_exception, $EXC_SYSCALL, $0x6000, $1)
        /* no return */
 
 Entry(hndl_machine_check)
-       CCALL1(panic_machine_check64, %rsp)
+       CCALL1(panic_machine_check64, %r15)
        hlt
 
 Entry(hndl_double_fault)
-       CCALL1(panic_double_fault64, %rsp)
+       CCALL1(panic_double_fault64, %r15)
        hlt