Index: kernel/arch/amd64/include/asm.h
===================================================================
--- kernel/arch/amd64/include/asm.h	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/amd64/include/asm.h	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -435,10 +435,72 @@
 GEN_WRITE_REG(dr7)
 
-extern size_t interrupt_handler_size;
-extern void interrupt_handlers(void);
-
 extern void asm_delay_loop(uint32_t);
 extern void asm_fake_loop(uint32_t);
 
+extern uintptr_t int_0;
+extern uintptr_t int_1;
+extern uintptr_t int_2;
+extern uintptr_t int_3;
+extern uintptr_t int_4;
+extern uintptr_t int_5;
+extern uintptr_t int_6;
+extern uintptr_t int_7;
+extern uintptr_t int_8;
+extern uintptr_t int_9;
+extern uintptr_t int_10;
+extern uintptr_t int_11;
+extern uintptr_t int_12;
+extern uintptr_t int_13;
+extern uintptr_t int_14;
+extern uintptr_t int_15;
+extern uintptr_t int_16;
+extern uintptr_t int_17;
+extern uintptr_t int_18;
+extern uintptr_t int_19;
+extern uintptr_t int_20;
+extern uintptr_t int_21;
+extern uintptr_t int_22;
+extern uintptr_t int_23;
+extern uintptr_t int_24;
+extern uintptr_t int_25;
+extern uintptr_t int_26;
+extern uintptr_t int_27;
+extern uintptr_t int_28;
+extern uintptr_t int_29;
+extern uintptr_t int_30;
+extern uintptr_t int_31;
+extern uintptr_t int_32;
+extern uintptr_t int_33;
+extern uintptr_t int_34;
+extern uintptr_t int_35;
+extern uintptr_t int_36;
+extern uintptr_t int_37;
+extern uintptr_t int_38;
+extern uintptr_t int_39;
+extern uintptr_t int_40;
+extern uintptr_t int_41;
+extern uintptr_t int_42;
+extern uintptr_t int_43;
+extern uintptr_t int_44;
+extern uintptr_t int_45;
+extern uintptr_t int_46;
+extern uintptr_t int_47;
+extern uintptr_t int_48;
+extern uintptr_t int_49;
+extern uintptr_t int_50;
+extern uintptr_t int_51;
+extern uintptr_t int_52;
+extern uintptr_t int_53;
+extern uintptr_t int_54;
+extern uintptr_t int_55;
+extern uintptr_t int_56;
+extern uintptr_t int_57;
+extern uintptr_t int_58;
+extern uintptr_t int_59;
+extern uintptr_t int_60;
+extern uintptr_t int_61;
+extern uintptr_t int_62;
+extern uintptr_t int_63;
+
 #endif
 
Index: kernel/arch/amd64/include/cpu.h
===================================================================
--- kernel/arch/amd64/include/cpu.h	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/amd64/include/cpu.h	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -45,4 +45,5 @@
 #define RFLAGS_DF	(1 << 10)
 #define RFLAGS_OF	(1 << 11)
+#define RFLAGS_NT	(1 << 14)
 #define RFLAGS_RF	(1 << 16)
 
Index: kernel/arch/amd64/include/interrupt.h
===================================================================
--- kernel/arch/amd64/include/interrupt.h	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/amd64/include/interrupt.h	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -74,18 +74,27 @@
 typedef struct istate {
 	uint64_t rax;
+	uint64_t rbx;
 	uint64_t rcx;
 	uint64_t rdx;
 	uint64_t rsi;
 	uint64_t rdi;
+	uint64_t rbp;
 	uint64_t r8;
 	uint64_t r9;
 	uint64_t r10;
 	uint64_t r11;
-	uint64_t rbp;
-	uint64_t error_word;
+	uint64_t r12;
+	uint64_t r13;
+	uint64_t r14;
+	uint64_t r15;
+	uint64_t alignment;	/* align rbp_frame on multiple of 16 */
+	uint64_t rbp_frame;	/* imitation of frame pointer linkage */
+	uint64_t rip_frame;	/* imitation of return address linkage */
+	uint64_t error_word;	/* real or fake error word */
 	uint64_t rip;
 	uint64_t cs;
 	uint64_t rflags;
-	uint64_t stack[];  /* Additional data on stack */
+	uint64_t rsp;		/* only if istate_t is from uspace */
+	uint64_t ss;		/* only if istate_t is from uspace */
 } istate_t;
 
Index: kernel/arch/amd64/src/asm.S
===================================================================
--- kernel/arch/amd64/src/asm.S	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/amd64/src/asm.S	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -26,24 +26,4 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
-#define IREGISTER_SPACE  80
-
-#define IOFFSET_RAX  0x00
-#define IOFFSET_RCX  0x08
-#define IOFFSET_RDX  0x10
-#define IOFFSET_RSI  0x18
-#define IOFFSET_RDI  0x20
-#define IOFFSET_R8   0x28
-#define IOFFSET_R9   0x30
-#define IOFFSET_R10  0x38
-#define IOFFSET_R11  0x40
-#define IOFFSET_RBP  0x48
-
-/**
- * Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int
- * has no error word  and 1 means interrupt with error word
- *
- */
-#define ERROR_WORD_INTERRUPT_LIST  0x00027D00
 
 #include <arch/pm.h>
@@ -174,52 +154,49 @@
 	ret
 
-/** Push all volatile general purpose registers on stack
- *
+#define ISTATE_OFFSET_RAX		0
+#define ISTATE_OFFSET_RBX		8
+#define ISTATE_OFFSET_RCX		16
+#define ISTATE_OFFSET_RDX		24
+#define ISTATE_OFFSET_RSI		32
+#define ISTATE_OFFSET_RDI		40
+#define ISTATE_OFFSET_RBP		48
+#define ISTATE_OFFSET_R8		56
+#define ISTATE_OFFSET_R9		64
+#define ISTATE_OFFSET_R10		72
+#define ISTATE_OFFSET_R11		80
+#define ISTATE_OFFSET_R12		88	
+#define ISTATE_OFFSET_R13 		96
+#define ISTATE_OFFSET_R14		104
+#define ISTATE_OFFSET_R15		112
+#define ISTATE_OFFSET_ALIGNMENT		120
+#define ISTATE_OFFSET_RBP_FRAME		128
+#define ISTATE_OFFSET_RIP_FRAME		136
+#define ISTATE_OFFSET_ERROR_WORD	144
+#define ISTATE_OFFSET_RIP		152
+#define ISTATE_OFFSET_CS		160
+#define ISTATE_OFFSET_RFLAGS		168
+#define ISTATE_OFFSET_RSP		176
+#define ISTATE_OFFSET_SS		184
+
+/*
+ * Size of the istate structure without the hardware-saved part and without the
+ * error word.
  */
-.macro save_all_gpr
-	movq %rax, IOFFSET_RAX(%rsp)
-	movq %rcx, IOFFSET_RCX(%rsp)
-	movq %rdx, IOFFSET_RDX(%rsp)
-	movq %rsi, IOFFSET_RSI(%rsp)
-	movq %rdi, IOFFSET_RDI(%rsp)
-	movq %r8, IOFFSET_R8(%rsp)
-	movq %r9, IOFFSET_R9(%rsp)
-	movq %r10, IOFFSET_R10(%rsp)
-	movq %r11, IOFFSET_R11(%rsp)
-	movq %rbp, IOFFSET_RBP(%rsp)
-.endm
-
-.macro restore_all_gpr
-	movq IOFFSET_RAX(%rsp), %rax
-	movq IOFFSET_RCX(%rsp), %rcx
-	movq IOFFSET_RDX(%rsp), %rdx
-	movq IOFFSET_RSI(%rsp), %rsi
-	movq IOFFSET_RDI(%rsp), %rdi
-	movq IOFFSET_R8(%rsp), %r8
-	movq IOFFSET_R9(%rsp), %r9
-	movq IOFFSET_R10(%rsp), %r10
-	movq IOFFSET_R11(%rsp), %r11
-	movq IOFFSET_RBP(%rsp), %rbp
-.endm
-
-#define INTERRUPT_ALIGN  128
-
-/** Declare interrupt handlers
- *
- * Declare interrupt handlers for n interrupt
- * vectors starting at vector i.
- *
- * The handlers call exc_dispatch().
+#define ISTATE_SOFT_SIZE	144
+
+/**
+ * Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int
+ * has no error word  and 1 means interrupt with error word
  *
  */
-.macro handler i n
-	
+#define ERROR_WORD_INTERRUPT_LIST  0x00027D00
+
+.macro handler i
+.global int_\i
+int_\i:
+
 	/*
 	 * Choose between version with error code and version without error
-	 * code. Both versions have to be of the same size. amd64 assembly is,
-	 * however, a little bit tricky. For instance, subq $0x80, %rsp and
-	 * subq $0x78, %rsp can result in two instructions with different
-	 * op-code lengths.
-	 * Therefore we align the interrupt handlers.
+	 * code.
 	 */
 	
@@ -229,52 +206,87 @@
 			 * Version with error word.
 			 */
-			subq $IREGISTER_SPACE, %rsp
+			subq $ISTATE_SOFT_SIZE, %rsp
 		.else
 			/*
-			 * Version without error word,
+			 * Version without error word.
 			 */
-			subq $(IREGISTER_SPACE + 8), %rsp
+			subq $(ISTATE_SOFT_SIZE + 8), %rsp
 		.endif
 	.else
 		/*
-		 * Version without error word,
+		 * Version without error word.
 		 */
-		subq $(IREGISTER_SPACE + 8), %rsp
+		subq $(ISTATE_SOFT_SIZE + 8), %rsp
 	.endif
 	
-	save_all_gpr
+	/*
+	 * Save the general purpose registers.
+	 */
+	movq %rax, ISTATE_OFFSET_RAX(%rsp)
+	movq %rbx, ISTATE_OFFSET_RBX(%rsp)
+	movq %rcx, ISTATE_OFFSET_RCX(%rsp)
+	movq %rdx, ISTATE_OFFSET_RDX(%rsp)
+	movq %rsi, ISTATE_OFFSET_RSI(%rsp)
+	movq %rdi, ISTATE_OFFSET_RDI(%rsp)
+	movq %rbp, ISTATE_OFFSET_RBP(%rsp)
+	movq %r8, ISTATE_OFFSET_R8(%rsp)
+	movq %r9, ISTATE_OFFSET_R9(%rsp)
+	movq %r10, ISTATE_OFFSET_R10(%rsp)
+	movq %r11, ISTATE_OFFSET_R11(%rsp)
+	movq %r12, ISTATE_OFFSET_R12(%rsp)
+	movq %r13, ISTATE_OFFSET_R13(%rsp)
+	movq %r14, ISTATE_OFFSET_R14(%rsp)
+	movq %r15, ISTATE_OFFSET_R15(%rsp)
+
+	/*
+	 * Imitate a regular stack frame linkage.
+	 * Stop stack traces here if we came from userspace.
+	 */
+	xorq %rdx, %rdx
+	cmpq $(gdtselector(KTEXT_DES)), ISTATE_OFFSET_CS(%rsp)
+	cmovnzq %rdx, %rbp
+
+	movq %rbp, ISTATE_OFFSET_RBP_FRAME(%rsp)
+	movq ISTATE_OFFSET_RIP(%rsp), %rax
+	movq %rax, ISTATE_OFFSET_RIP_FRAME(%rsp)
+	leaq ISTATE_OFFSET_RBP_FRAME(%rsp), %rbp
+
+	movq $(\i), %rdi   /* pass intnum in the first argument */
+	movq %rsp, %rsi    /* pass istate address in the second argument */
+	
 	cld
-	
-	/*
-	 * Stop stack traces here if we came from userspace.
-	 */
-	movq %cs, %rax
-	xorq %rdx, %rdx
-	cmpq %rax, IREGISTER_SPACE+16(%rsp)
-	cmovneq %rdx, %rbp
-
-	movq $(\i), %rdi   /* %rdi - first argument */
-	movq %rsp, %rsi    /* %rsi - pointer to istate */
-	
+
 	/* Call exc_dispatch(i, istate) */
 	call exc_dispatch
-	
-	restore_all_gpr
+
+	/*
+	 * Restore all scratch registers and the preserved registers we have
+	 * clobbered in this handler (i.e. RBP).
+	 */
+	movq ISTATE_OFFSET_RAX(%rsp), %rax
+	movq ISTATE_OFFSET_RCX(%rsp), %rcx
+	movq ISTATE_OFFSET_RDX(%rsp), %rdx
+	movq ISTATE_OFFSET_RSI(%rsp), %rsi
+	movq ISTATE_OFFSET_RDI(%rsp), %rdi
+	movq ISTATE_OFFSET_RBP(%rsp), %rbp
+	movq ISTATE_OFFSET_R8(%rsp), %r8
+	movq ISTATE_OFFSET_R9(%rsp), %r9
+	movq ISTATE_OFFSET_R10(%rsp), %r10
+	movq ISTATE_OFFSET_R11(%rsp), %r11
 	
 	/* $8 = Skip error word */
-	addq $(IREGISTER_SPACE + 8), %rsp
+	addq $(ISTATE_SOFT_SIZE + 8), %rsp
 	iretq
-	
-	.align INTERRUPT_ALIGN
-	.if (\n - \i) - 1
-		handler "(\i + 1)", \n
-	.endif
 .endm
 
-.align INTERRUPT_ALIGN
+#define LIST_0_63 \
+	0, 1, 2, 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,\
+	28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,\
+	53,54,55,56,57,58,59,60,61,62,63
+
 interrupt_handlers:
-	h_start:
-		handler 0 IDT_ITEMS
-	h_end:
+.irp cnt, LIST_0_63
+	handler \cnt 
+.endr
 
 /** Low-level syscall handler
@@ -309,33 +321,69 @@
 	movq %gs:8, %rsp  /* set this thread's kernel RSP */
 	
-	/* Switch back to remain consistent */
+	/*
+	 * Note that the space needed for the imitated istate structure has been
+	 * preallocated for us in thread_create_arch() and set in
+	 * before_thread_runs_arch().
+	 */
+
+	/*
+	 * Save the general purpose registers and push the 7th argument (syscall
+	 * number) onto the stack. Note that the istate structure has a layout
+	 * which supports this.
+	 */
+	movq %rax, ISTATE_OFFSET_RAX(%rsp)  /* 7th argument, passed on stack */
+	movq %rbx, ISTATE_OFFSET_RBX(%rsp)  /* observability */
+	movq %rcx, ISTATE_OFFSET_RCX(%rsp)  /* userspace RIP */
+	movq %rdx, ISTATE_OFFSET_RDX(%rsp)  /* 3rd argument, observability */
+	movq %rsi, ISTATE_OFFSET_RSI(%rsp)  /* 2nd argument, observability */ 
+	movq %rdi, ISTATE_OFFSET_RDI(%rsp)  /* 1st argument, observability */
+	movq %rbp, ISTATE_OFFSET_RBP(%rsp)  /* need to preserve userspace RBP */
+	movq %r8, ISTATE_OFFSET_R8(%rsp)    /* 5th argument, observability */
+	movq %r9, ISTATE_OFFSET_R9(%rsp)    /* 6th argument, observability */
+	movq %r10, ISTATE_OFFSET_R10(%rsp)  /* 4th argument, observability */
+	movq %r11, ISTATE_OFFSET_R11(%rsp)  /* low 32 bits userspace RFLAGS */
+	movq %r12, ISTATE_OFFSET_R12(%rsp)  /* observability */
+	movq %r13, ISTATE_OFFSET_R13(%rsp)  /* observability */
+	movq %r14, ISTATE_OFFSET_R14(%rsp)  /* observability */
+	movq %r15, ISTATE_OFFSET_R15(%rsp)  /* observability */
+
+	/*
+	 * Save the return address and the userspace stack on locations that
+	 * would normally be taken by them.
+	 */
+	movq %gs:0, %rax
+	movq %rax, ISTATE_OFFSET_RSP(%rsp)
+	movq %rcx, ISTATE_OFFSET_RIP(%rsp)
+
+	/*
+	 * Imitate a regular stack frame linkage.
+	 */
+	movq $0, ISTATE_OFFSET_RBP_FRAME(%rsp)
+	movq %rcx, ISTATE_OFFSET_RIP_FRAME(%rsp)
+	leaq ISTATE_OFFSET_RBP_FRAME(%rsp), %rbp
+
+	/* Switch back to normal %gs */
 	swapgs
 	sti
 	
-	pushq %rcx
-	pushq %r11
-	pushq %rbp
-	
-	xorq %rbp, %rbp  /* stop the stack traces here */
-	
 	/* Copy the 4th argument where it is expected  */
 	movq %r10, %rcx
-	pushq %rax
-	
+
+	/*
+	 * Call syscall_handler() with the 7th argument passed on stack.
+	 */
 	call syscall_handler
 	
-	addq $8, %rsp
-	
-	popq %rbp
-	popq %r11
-	popq %rcx
-	
 	cli
-	swapgs
-	
-	/* Restore the user RSP */
-	movq %gs:0, %rsp
-	swapgs
-	
+	
+	/*
+	 * Restore registers needed for return via the SYSRET instruction and
+	 * the clobbered preserved registers (i.e. RBP).
+	 */
+	movq ISTATE_OFFSET_RBP(%rsp), %rbp
+	movq ISTATE_OFFSET_RCX(%rsp), %rcx
+	movq ISTATE_OFFSET_R11(%rsp), %r11
+	movq ISTATE_OFFSET_RSP(%rsp), %rsp
+
 	sysretq
 
@@ -484,6 +532,2 @@
 	ret
 
-.data
-.global interrupt_handler_size
-
-interrupt_handler_size: .quad (h_end - h_start) / IDT_ITEMS
Index: kernel/arch/amd64/src/interrupt.c
===================================================================
--- kernel/arch/amd64/src/interrupt.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/amd64/src/interrupt.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -65,13 +65,19 @@
 void istate_decode(istate_t *istate)
 {
-	printf("error_word=%#llx\n", istate->error_word);
-	printf("cs =%#0.16llx\trflags=%#0.16llx\n", istate->cs,
-	    istate->rflags);
-	printf("rax=%#0.16llx\trbx=%#0.16llx\trcx=%#0.16llx\n", istate->rax,
-	    istate->rcx, istate->rdx);
-	printf("rsi=%#0.16llx\trdi=%#0.16llx\tr8 =%#0.16llx\n", istate->rsi,
-	    istate->rdi, istate->r8);
-	printf("r9 =%#0.16llx\tr10=%#0.16llx\tr11=%#0.16llx\n", istate->r9,
-	    istate->r10, istate->r11);
+	printf("cs =%p\trip=%p\trfl=%p\terr=%p\n",
+	    istate->cs, istate->rip, istate->rflags, istate->error_word);
+
+	if (istate_from_uspace(istate))
+		printf("ss =%p\n", istate->ss);
+	
+	printf("rax=%p\trbx=%p\trcx=%p\trdx=%p\n",
+	    istate->rax, istate->rbx, istate->rcx, istate->rdx);
+	printf("rsi=%p\trdi=%p\trbp=%p\trsp=%p\n",
+	    istate->rsi, istate->rdi, istate->rbp,
+	    istate_from_uspace(istate) ? istate->rsp : (uintptr_t)&istate->rsp);
+	printf("r8 =%p\tr9 =%p\tr10=%p\tr11=%p\n",
+	    istate->r8, istate->r9, istate->r10, istate->r11);
+	printf("r12=%p\tr13=%p\tr14=%p\tr15=%p\n",
+	    istate->r12, istate->r13, istate->r14, istate->r15);
 }
 
Index: kernel/arch/amd64/src/mm/page.c
===================================================================
--- kernel/arch/amd64/src/mm/page.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/amd64/src/mm/page.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -90,5 +90,5 @@
 	if (as_page_fault(page, access, istate) == AS_PF_FAULT) {
 		fault_if_from_uspace(istate, "Page fault: %#x.", page);
-		panic_memtrap(istate, access, page, "Page fault.");
+		panic_memtrap(istate, access, page, NULL);
 	}
 }
Index: kernel/arch/amd64/src/pm.c
===================================================================
--- kernel/arch/amd64/src/pm.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/amd64/src/pm.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -175,8 +175,71 @@
 		d->present = 1;
 		d->type = AR_INTERRUPT;	/* masking interrupt */
-
-		idt_setoffset(d, ((uintptr_t) interrupt_handlers) +
-		    i * interrupt_handler_size);
 	}
+
+	d = &idt[0];
+	idt_setoffset(d++, (uintptr_t) &int_0);
+	idt_setoffset(d++, (uintptr_t) &int_1);
+	idt_setoffset(d++, (uintptr_t) &int_2);
+	idt_setoffset(d++, (uintptr_t) &int_3);
+	idt_setoffset(d++, (uintptr_t) &int_4);
+	idt_setoffset(d++, (uintptr_t) &int_5);
+	idt_setoffset(d++, (uintptr_t) &int_6);
+	idt_setoffset(d++, (uintptr_t) &int_7);
+	idt_setoffset(d++, (uintptr_t) &int_8);
+	idt_setoffset(d++, (uintptr_t) &int_9);
+	idt_setoffset(d++, (uintptr_t) &int_10);
+	idt_setoffset(d++, (uintptr_t) &int_11);
+	idt_setoffset(d++, (uintptr_t) &int_12);
+	idt_setoffset(d++, (uintptr_t) &int_13);
+	idt_setoffset(d++, (uintptr_t) &int_14);
+	idt_setoffset(d++, (uintptr_t) &int_15);
+	idt_setoffset(d++, (uintptr_t) &int_16);
+	idt_setoffset(d++, (uintptr_t) &int_17);
+	idt_setoffset(d++, (uintptr_t) &int_18);
+	idt_setoffset(d++, (uintptr_t) &int_19);
+	idt_setoffset(d++, (uintptr_t) &int_20);
+	idt_setoffset(d++, (uintptr_t) &int_21);
+	idt_setoffset(d++, (uintptr_t) &int_22);
+	idt_setoffset(d++, (uintptr_t) &int_23);
+	idt_setoffset(d++, (uintptr_t) &int_24);
+	idt_setoffset(d++, (uintptr_t) &int_25);
+	idt_setoffset(d++, (uintptr_t) &int_26);
+	idt_setoffset(d++, (uintptr_t) &int_27);
+	idt_setoffset(d++, (uintptr_t) &int_28);
+	idt_setoffset(d++, (uintptr_t) &int_29);
+	idt_setoffset(d++, (uintptr_t) &int_30);
+	idt_setoffset(d++, (uintptr_t) &int_31);
+	idt_setoffset(d++, (uintptr_t) &int_32);
+	idt_setoffset(d++, (uintptr_t) &int_33);
+	idt_setoffset(d++, (uintptr_t) &int_34);
+	idt_setoffset(d++, (uintptr_t) &int_35);
+	idt_setoffset(d++, (uintptr_t) &int_36);
+	idt_setoffset(d++, (uintptr_t) &int_37);
+	idt_setoffset(d++, (uintptr_t) &int_38);
+	idt_setoffset(d++, (uintptr_t) &int_39);
+	idt_setoffset(d++, (uintptr_t) &int_40);
+	idt_setoffset(d++, (uintptr_t) &int_41);
+	idt_setoffset(d++, (uintptr_t) &int_42);
+	idt_setoffset(d++, (uintptr_t) &int_43);
+	idt_setoffset(d++, (uintptr_t) &int_44);
+	idt_setoffset(d++, (uintptr_t) &int_45);
+	idt_setoffset(d++, (uintptr_t) &int_46);
+	idt_setoffset(d++, (uintptr_t) &int_47);
+	idt_setoffset(d++, (uintptr_t) &int_48);
+	idt_setoffset(d++, (uintptr_t) &int_49);
+	idt_setoffset(d++, (uintptr_t) &int_50);
+	idt_setoffset(d++, (uintptr_t) &int_51);
+	idt_setoffset(d++, (uintptr_t) &int_52);
+	idt_setoffset(d++, (uintptr_t) &int_53);
+	idt_setoffset(d++, (uintptr_t) &int_54);
+	idt_setoffset(d++, (uintptr_t) &int_55);
+	idt_setoffset(d++, (uintptr_t) &int_56);
+	idt_setoffset(d++, (uintptr_t) &int_57);
+	idt_setoffset(d++, (uintptr_t) &int_58);
+	idt_setoffset(d++, (uintptr_t) &int_59);
+	idt_setoffset(d++, (uintptr_t) &int_60);
+	idt_setoffset(d++, (uintptr_t) &int_61);
+	idt_setoffset(d++, (uintptr_t) &int_62);
+	idt_setoffset(d++, (uintptr_t) &int_63);
 }
 
Index: kernel/arch/amd64/src/proc/scheduler.c
===================================================================
--- kernel/arch/amd64/src/proc/scheduler.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/amd64/src/proc/scheduler.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -38,5 +38,4 @@
 #include <proc/thread.h>
 #include <arch.h>
-#include <arch/context.h>
 #include <arch/asm.h>
 #include <print.h>
@@ -57,5 +56,5 @@
 {
 	CPU->arch.tss->rsp0 =
-	    (uintptr_t) &THREAD->kstack[THREAD_STACK_SIZE - SP_DELTA];
+	    (uintptr_t) &THREAD->kstack[THREAD_STACK_SIZE];
 	
 	/*
Index: kernel/arch/amd64/src/proc/thread.c
===================================================================
--- kernel/arch/amd64/src/proc/thread.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/amd64/src/proc/thread.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -34,4 +34,5 @@
 
 #include <proc/thread.h>
+#include <arch/interrupt.h>
 
 /** Perform amd64 specific thread initialization.
@@ -49,5 +50,5 @@
 	 */
 	thread->arch.syscall_rsp[SYSCALL_KSTACK_RSP] =
-	    (uintptr_t) &thread->kstack[PAGE_SIZE - sizeof(uint64_t)];
+	    (uintptr_t) &thread->kstack[PAGE_SIZE - sizeof(istate_t)];
 }
 
Index: kernel/arch/amd64/src/syscall.c
===================================================================
--- kernel/arch/amd64/src/syscall.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/amd64/src/syscall.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -66,6 +66,7 @@
 	 * - clear DF so that the string instructions operate in
 	 *   the right direction
+	 * - clear NT to prevent a #GP should the flag proliferate to an IRET
 	 */
-	write_msr(AMD_MSR_SFMASK, RFLAGS_IF | RFLAGS_DF);
+	write_msr(AMD_MSR_SFMASK, RFLAGS_IF | RFLAGS_DF | RFLAGS_NT);
 }
 
Index: kernel/arch/arm32/src/mm/page_fault.c
===================================================================
--- kernel/arch/arm32/src/mm/page_fault.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/arm32/src/mm/page_fault.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -183,5 +183,5 @@
 	if (ret == AS_PF_FAULT) {
 		fault_if_from_uspace(istate, "Page fault: %#x.", badvaddr);
-		panic_memtrap(istate, access, badvaddr, "Page fault.");
+		panic_memtrap(istate, access, badvaddr, NULL);
 	}
 }
@@ -198,6 +198,7 @@
 
 	if (ret == AS_PF_FAULT) {
-		panic_memtrap(istate, PF_ACCESS_EXEC, istate->pc,
-		    "Page fault - prefetch_abort.");
+		fault_if_from_uspace(istate,
+		    "Page fault - prefetch_abort: %#x.", istate->pc);
+		panic_memtrap(istate, PF_ACCESS_EXEC, istate->pc, NULL);
 	}
 }
Index: kernel/arch/ia32/include/asm.h
===================================================================
--- kernel/arch/ia32/include/asm.h	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/ia32/include/asm.h	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -43,6 +43,4 @@
 #include <trace.h>
 
-extern uint32_t interrupt_handler_size;
-
 /** Halt CPU
  *
@@ -429,4 +427,6 @@
 extern void asm_delay_loop(uint32_t);
 extern void asm_fake_loop(uint32_t);
+
+extern uintptr_t int_syscall;
 
 extern uintptr_t int_0;
Index: kernel/arch/ia32/include/cpu.h
===================================================================
--- kernel/arch/ia32/include/cpu.h	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/ia32/include/cpu.h	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -37,4 +37,6 @@
 
 #define EFLAGS_IF       (1 << 9)
+#define EFLAGS_DF       (1 << 10)
+#define EFLAGS_NT       (1 << 14)
 #define EFLAGS_RF       (1 << 16)
 
Index: kernel/arch/ia32/include/pm.h
===================================================================
--- kernel/arch/ia32/include/pm.h	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/ia32/include/pm.h	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -67,6 +67,7 @@
 #define AR_CODE       (3 << 3)
 #define AR_WRITABLE   (1 << 1)
-#define AR_INTERRUPT  (0x0e)
-#define AR_TSS        (0x09)
+#define AR_INTERRUPT  (0xe)
+#define AR_TRAP       (0xf)
+#define AR_TSS        (0x9)
 
 #define DPL_KERNEL  (PL_KERNEL << 5)
Index: kernel/arch/ia32/src/asm.S
===================================================================
--- kernel/arch/ia32/src/asm.S	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/ia32/src/asm.S	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2001 Jakub Jermar
+ * Copyright (c) 2010 Jakub Jermar
  * All rights reserved.
  *
@@ -31,12 +31,6 @@
  */
 
-/**
- * Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int
- * has no error word  and 1 means interrupt with error word
- *
- */
-#define ERROR_WORD_INTERRUPT_LIST  0x00027d00
-
 #include <arch/pm.h>
+#include <arch/cpu.h>
 #include <arch/mm/page.h>
 
@@ -153,13 +147,4 @@
 	wrmsr
 	ret
-
-/** Clear nested flag
- *
- */
-.macro CLEAR_NT_FLAG
-	pushfl
-	andl $0xffffbfff, (%esp)
-	popfl
-.endm
 
 #define ISTATE_OFFSET_EDX         0
@@ -190,10 +175,4 @@
 
 /*
- * Size of the entire istate structure including the error word and the
- * hardware-saved part.
- */
-#define ISTATE_REAL_SIZE  (ISTATE_SOFT_SIZE + 24)
-
-/*
  * The SYSENTER syscall mechanism can be used for syscalls with
  * four or fewer arguments. To pass these four arguments, we
@@ -206,6 +185,9 @@
 .global sysenter_handler
 sysenter_handler:
-	sti
-	subl $(ISTATE_REAL_SIZE), %esp
+
+	/*
+	 * Note that the space needed for the istate structure has been
+	 * preallocated on the stack by before_thread_runs_arch().
+	 */
 
 	/*
@@ -243,9 +225,23 @@
 	 * Switch to kernel selectors.
 	 */
-	movw $16, %ax
+	movw $(gdtselector(KDATA_DES)), %ax
 	movw %ax, %ds
 	movw %ax, %es
 	
-	cld
+	/*
+	 * Sanitize EFLAGS.
+	 *
+	 * SYSENTER does not clear the NT flag, which could thus proliferate
+	 * from here to the IRET instruction via a context switch and result
+	 * in crash.
+	 *
+	 * SYSENTER does not clear DF, which the ABI assumes to be cleared.
+	 *
+	 * SYSENTER clears IF, which we would like to be set for syscalls.
+	 *
+	 */
+	pushl $(EFLAGS_IF)  /* specify EFLAGS bits that we want to set */
+	popfl	            /* set bits from the mask, clear or ignore others */
+
 	call syscall_handler
 	
@@ -262,214 +258,207 @@
 	movl ISTATE_OFFSET_ESP(%esp), %ecx
 
-	addl $(ISTATE_REAL_SIZE), %esp
-	
 	sysexit   /* return to userspace */
 
-/** Declare interrupt handlers
- *
- * Declare interrupt handlers for n interrupt
- * vectors starting at vector i.
- *
- */
+/*
+ * This is the legacy syscall handler using the interrupt mechanism.
+ */
+.global int_syscall
+int_syscall:
+	subl $(ISTATE_SOFT_SIZE + 4), %esp
+
+	/*
+	 * Push syscall arguments onto the stack
+	 *
+	 * NOTE: The idea behind the order of arguments passed
+	 *       in registers is to use all scratch registers
+	 *       first and preserved registers next. An optimized
+	 *       libc syscall wrapper can make use of this setup.
+	 *       The istate structure is arranged in the way to support
+	 *       this idea.
+	 *
+	 */
+	movl %eax, ISTATE_OFFSET_EAX(%esp)
+	movl %ebx, ISTATE_OFFSET_EBX(%esp)
+	movl %ecx, ISTATE_OFFSET_ECX(%esp)
+	movl %edx, ISTATE_OFFSET_EDX(%esp)
+	movl %edi, ISTATE_OFFSET_EDI(%esp)
+	movl %esi, ISTATE_OFFSET_ESI(%esp)
+	movl %ebp, ISTATE_OFFSET_EBP(%esp)
+
+	/*
+	 * Save the selector registers.
+	 */
+	movl %gs, %ecx
+	movl %fs, %edx
+
+	movl %ecx, ISTATE_OFFSET_GS(%esp)
+	movl %edx, ISTATE_OFFSET_FS(%esp)
+
+	movl %es, %ecx
+	movl %ds, %edx
+		
+	movl %ecx, ISTATE_OFFSET_ES(%esp)
+	movl %edx, ISTATE_OFFSET_DS(%esp)
+
+	/*
+	 * Switch to kernel selectors.
+	 */
+	movl $(gdtselector(KDATA_DES)), %eax
+	movl %eax, %ds
+	movl %eax, %es
+		
+	movl $0, ISTATE_OFFSET_EBP_FRAME(%esp)
+	movl ISTATE_OFFSET_EIP(%esp), %eax
+	movl %eax, ISTATE_OFFSET_EIP_FRAME(%esp)
+	leal ISTATE_OFFSET_EBP_FRAME(%esp), %ebp
+		
+	cld
+		
+	/* Call syscall_handler(edx, ecx, ebx, esi, edi, ebp, eax) */
+	call syscall_handler
+			
+	/*
+	 * Restore the selector registers.
+	 */
+	movl ISTATE_OFFSET_GS(%esp), %ecx
+	movl ISTATE_OFFSET_FS(%esp), %edx
+
+	movl %ecx, %gs
+	movl %edx, %fs
+
+	movl ISTATE_OFFSET_ES(%esp), %ecx
+	movl ISTATE_OFFSET_DS(%esp), %edx
+			
+	movl %ecx, %es
+	movl %edx, %ds
+			
+	/*
+	 * Restore the preserved registers the handler cloberred itself
+	 * (i.e. EBP).
+	 */
+	movl ISTATE_OFFSET_EBP(%esp), %ebp
+			
+	addl $(ISTATE_SOFT_SIZE + 4), %esp
+	iret
+		
+/**
+ * Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int
+ * has no error word  and 1 means interrupt with error word
+ *
+ */
+#define ERROR_WORD_INTERRUPT_LIST  0x00027d00
 
 .macro handler i
 .global int_\i
 int_\i:
-	.ifeq \i - 0x30
-		/* Syscall handler */
-		subl $(ISTATE_SOFT_SIZE + 4), %esp
-
-		/*
-		 * Push syscall arguments onto the stack
-		 *
-		 * NOTE: The idea behind the order of arguments passed
-		 *       in registers is to use all scratch registers
-		 *       first and preserved registers next. An optimized
-		 *       libc syscall wrapper can make use of this setup.
-		 *       The istate structure is arranged in the way to support
-		 *       this idea.
-		 *
-		 */
-		movl %eax, ISTATE_OFFSET_EAX(%esp)
-		movl %ebx, ISTATE_OFFSET_EBX(%esp)
-		movl %ecx, ISTATE_OFFSET_ECX(%esp)
-		movl %edx, ISTATE_OFFSET_EDX(%esp)
-		movl %edi, ISTATE_OFFSET_EDI(%esp)
-		movl %esi, ISTATE_OFFSET_ESI(%esp)
-		movl %ebp, ISTATE_OFFSET_EBP(%esp)
-
-		/*
-		 * Save the selector registers.
-		 */
-		movl %gs, %ecx
-		movl %fs, %edx
-
-		movl %ecx, ISTATE_OFFSET_GS(%esp)
-		movl %edx, ISTATE_OFFSET_FS(%esp)
-
-		movl %es, %ecx
-		movl %ds, %edx
-		
-		movl %ecx, ISTATE_OFFSET_ES(%esp)
-		movl %edx, ISTATE_OFFSET_DS(%esp)
-
-		/*
-		 * Switch to kernel selectors.
-		 */
-		movl $16, %eax
-		movl %eax, %ds
-		movl %eax, %es
-		
-		movl $0, ISTATE_OFFSET_EBP_FRAME(%esp)
-		movl ISTATE_OFFSET_EIP(%esp), %eax
-		movl %eax, ISTATE_OFFSET_EIP_FRAME(%esp)
-		leal ISTATE_OFFSET_EBP_FRAME(%esp), %ebp
-		
-		cld
-		sti
-		
-		/* Call syscall_handler(edx, ecx, ebx, esi, edi, ebp, eax) */
-		call syscall_handler
-			
-		CLEAR_NT_FLAG
-
-		/*
-		 * Restore the selector registers.
-		 */
-		movl ISTATE_OFFSET_GS(%esp), %ecx
-		movl ISTATE_OFFSET_FS(%esp), %edx
-
-		movl %ecx, %gs
-		movl %edx, %fs
-
-		movl ISTATE_OFFSET_ES(%esp), %ecx
-		movl ISTATE_OFFSET_DS(%esp), %edx
-			
-		movl %ecx, %es
-		movl %edx, %ds
-			
-		/*
-		 * Restore the preserved registers the handler cloberred itself
-		 * (i.e. EBP).
-		 */
-		movl ISTATE_OFFSET_EBP(%esp), %ebp
-			
-		addl $(ISTATE_SOFT_SIZE + 4), %esp
-		iret
-		
+	/*
+	 * This macro distinguishes between two versions of ia32
+	 * exceptions. One version has error word and the other
+	 * does not have it. The latter version fakes the error
+	 * word on the stack so that the handlers and istate_t
+	 * can be the same for both types.
+	 */
+	.iflt \i - 32
+		.if (1 << \i) & ERROR_WORD_INTERRUPT_LIST
+			/*
+			 * Exception with error word.
+			 */
+			subl $ISTATE_SOFT_SIZE, %esp
+		.else
+			/*
+			 * Exception without error word: fake up one
+			 */
+			subl $(ISTATE_SOFT_SIZE + 4), %esp
+		.endif
 	.else
 		/*
-		 * This macro distinguishes between two versions of ia32
-		 * exceptions. One version has error word and the other
-		 * does not have it. The latter version fakes the error
-		 * word on the stack so that the handlers and istate_t
-		 * can be the same for both types.
+		 * Interrupt: fake up an error word 
 		 */
-		.iflt \i - 32
-			.if (1 << \i) & ERROR_WORD_INTERRUPT_LIST
-				/*
-				 * Exception with error word: do nothing
-				 */
-			.else
-				/*
-				 * Exception without error word: fake up one
-				 */
-				pushl $0
-			.endif
-		.else
-			/*
-			 * Interrupt: fake up one
-			 */
-			pushl $0
-		.endif
-		
-		subl $ISTATE_SOFT_SIZE, %esp
-		
-		/*
-		 * Save the general purpose registers.
-		 */
-		movl %eax, ISTATE_OFFSET_EAX(%esp)
-		movl %ebx, ISTATE_OFFSET_EBX(%esp)
-		movl %ecx, ISTATE_OFFSET_ECX(%esp)
-		movl %edx, ISTATE_OFFSET_EDX(%esp)
-		movl %edi, ISTATE_OFFSET_EDI(%esp)
-		movl %esi, ISTATE_OFFSET_ESI(%esp)
-		movl %ebp, ISTATE_OFFSET_EBP(%esp)
-		
-		/*
-		 * Save the selector registers.
-		 */
-		movl %gs, %eax
-		movl %fs, %ebx
-		movl %es, %ecx
-		movl %ds, %edx
-		
-		movl %eax, ISTATE_OFFSET_GS(%esp)
-		movl %ebx, ISTATE_OFFSET_FS(%esp)
-		movl %ecx, ISTATE_OFFSET_ES(%esp)
-		movl %edx, ISTATE_OFFSET_DS(%esp)
-		
-		/*
-		 * Switch to kernel selectors.
-		 */
-		movl $16, %eax
-		movl %eax, %ds
-		movl %eax, %es
-		
-		/*
-		 * Imitate a regular stack frame linkage.
-		 * Stop stack traces here if we came from userspace.
-		 */
-		cmpl $8, ISTATE_OFFSET_CS(%esp)
-		jz 0f
-		xorl %ebp, %ebp
-		
-		0:
-		
-			movl %ebp, ISTATE_OFFSET_EBP_FRAME(%esp)
-			movl ISTATE_OFFSET_EIP(%esp), %eax
-			movl %eax, ISTATE_OFFSET_EIP_FRAME(%esp)
-			leal ISTATE_OFFSET_EBP_FRAME(%esp), %ebp
-			
-			cld
-			
-			pushl %esp   /* pass istate address */
-			pushl $(\i)  /* pass intnum */
-			
-			/* Call exc_dispatch(intnum, istate) */
-			call exc_dispatch
-			
-			addl $8, %esp  /* clear arguments from the stack */
-			
-			CLEAR_NT_FLAG
-			
-			/*
-			 * Restore the selector registers.
-			 */
-			movl ISTATE_OFFSET_GS(%esp), %eax
-			movl ISTATE_OFFSET_FS(%esp), %ebx
-			movl ISTATE_OFFSET_ES(%esp), %ecx
-			movl ISTATE_OFFSET_DS(%esp), %edx
-			
-			movl %eax, %gs
-			movl %ebx, %fs
-			movl %ecx, %es
-			movl %edx, %ds
-			
-			/*
-			 * Restore the scratch registers and the preserved
-			 * registers the handler cloberred itself
-			 * (i.e. EBX and EBP).
-			 */
-			movl ISTATE_OFFSET_EAX(%esp), %eax
-			movl ISTATE_OFFSET_EBX(%esp), %ebx
-			movl ISTATE_OFFSET_ECX(%esp), %ecx
-			movl ISTATE_OFFSET_EDX(%esp), %edx
-			movl ISTATE_OFFSET_EBP(%esp), %ebp
-			
-			addl $(ISTATE_SOFT_SIZE + 4), %esp
-			iret
-		
+		subl $(ISTATE_SOFT_SIZE + 4), %esp
 	.endif
+	
+	/*
+	 * Save the general purpose registers.
+	 */
+	movl %eax, ISTATE_OFFSET_EAX(%esp)
+	movl %ebx, ISTATE_OFFSET_EBX(%esp)
+	movl %ecx, ISTATE_OFFSET_ECX(%esp)
+	movl %edx, ISTATE_OFFSET_EDX(%esp)
+	movl %edi, ISTATE_OFFSET_EDI(%esp)
+	movl %esi, ISTATE_OFFSET_ESI(%esp)
+	movl %ebp, ISTATE_OFFSET_EBP(%esp)
+	
+	/*
+	 * Save the selector registers.
+	 */
+	movl %gs, %ecx
+	movl %fs, %edx
+
+	movl %ecx, ISTATE_OFFSET_GS(%esp)
+	movl %edx, ISTATE_OFFSET_FS(%esp)
+
+	movl %es, %ecx
+	movl %ds, %edx
+	
+	movl %ecx, ISTATE_OFFSET_ES(%esp)
+	movl %edx, ISTATE_OFFSET_DS(%esp)
+	
+	/*
+	 * Switch to kernel selectors.
+	 */
+	movl $(gdtselector(KDATA_DES)), %eax
+	movl %eax, %ds
+	movl %eax, %es
+	
+	/*
+	 * Imitate a regular stack frame linkage.
+	 * Stop stack traces here if we came from userspace.
+	 */
+	xorl %eax, %eax
+	cmpl $(gdtselector(KTEXT_DES)), ISTATE_OFFSET_CS(%esp)
+	cmovnzl %eax, %ebp
+
+	movl %ebp, ISTATE_OFFSET_EBP_FRAME(%esp)
+	movl ISTATE_OFFSET_EIP(%esp), %eax
+	movl %eax, ISTATE_OFFSET_EIP_FRAME(%esp)
+	leal ISTATE_OFFSET_EBP_FRAME(%esp), %ebp
+		
+	cld
+		
+	pushl %esp   /* pass istate address */
+	pushl $(\i)  /* pass intnum */
+		
+	/* Call exc_dispatch(intnum, istate) */
+	call exc_dispatch
+		
+	addl $8, %esp  /* clear arguments from the stack */
+		
+	/*
+	 * Restore the selector registers.
+	 */
+	movl ISTATE_OFFSET_GS(%esp), %ecx
+	movl ISTATE_OFFSET_FS(%esp), %edx
+
+	movl %ecx, %gs
+	movl %edx, %fs
+
+	movl ISTATE_OFFSET_ES(%esp), %ecx
+	movl ISTATE_OFFSET_DS(%esp), %edx
+		
+	movl %ecx, %es
+	movl %edx, %ds
+		
+	/*
+	 * Restore the scratch registers and the preserved
+	 * registers the handler cloberred itself
+	 * (i.e. EBP).
+	 */
+	movl ISTATE_OFFSET_EAX(%esp), %eax
+	movl ISTATE_OFFSET_ECX(%esp), %ecx
+	movl ISTATE_OFFSET_EDX(%esp), %edx
+	movl ISTATE_OFFSET_EBP(%esp), %ebp
+		
+	addl $(ISTATE_SOFT_SIZE + 4), %esp
+	iret
 .endm
 
Index: kernel/arch/ia32/src/interrupt.c
===================================================================
--- kernel/arch/ia32/src/interrupt.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/ia32/src/interrupt.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -65,21 +65,17 @@
 void istate_decode(istate_t *istate)
 {
-	printf("error_word=%p\n", istate->error_word);
-	printf("eflags=%p\n", istate->eflags);
-
-	printf("cs =%p\tds =%p\tes =%p\n", istate->cs, istate->ds, istate->es);
-	printf("fs =%p\tgs =%p", istate->fs, istate->gs);
+	printf("cs =%p\teip=%p\tefl=%p\terr=%p\n",
+	    istate->cs, istate->eip, istate->eflags, istate->error_word);
+
+	printf("ds =%p\tes =%p\tfs =%p\tgs =%p\n",
+	    istate->ds, istate->es, istate->fs, istate->gs);
 	if (istate_from_uspace(istate))
-		printf("\tss =%p\n", istate->ss);
-	else
-		printf("\n");
-
-	printf("eax=%p\tebx=%p\tecx=%p\n", istate->eax, istate->ebx,
-	    istate->ecx);
-	printf("edx=%p\tedi=%p\tesi=%p\n", istate->edx, istate->edi,
-	    istate->esi);
-	printf("ebp=%p\tesp=%p\teip=%p\n", istate->ebp,
-	    istate_from_uspace(istate) ? istate->esp : (uintptr_t) &istate->esp,
-	    istate->eip);
+		printf("ss =%p\n", istate->ss);
+
+	printf("eax=%p\tebx=%p\tecx=%p\tedx=%p\n",
+	    istate->eax, istate->ebx, istate->ecx, istate->edx);
+	printf("esi=%p\tedi=%p\tebp=%p\tesp=%p\n",
+	    istate->esi, istate->edi, istate->ebp,
+	    istate_from_uspace(istate) ? istate->esp : (uintptr_t)&istate->esp);
 }
 
Index: kernel/arch/ia32/src/mm/page.c
===================================================================
--- kernel/arch/ia32/src/mm/page.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/ia32/src/mm/page.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -115,5 +115,5 @@
 	if (as_page_fault(page, access, istate) == AS_PF_FAULT) {
 		fault_if_from_uspace(istate, "Page fault: %#x.", page);
-		panic_memtrap(istate, access, page, "Page fault.");
+		panic_memtrap(istate, access, page, NULL);
 	}
 }
Index: kernel/arch/ia32/src/pm.c
===================================================================
--- kernel/arch/ia32/src/pm.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/ia32/src/pm.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -130,12 +130,16 @@
 		d->selector = gdtselector(KTEXT_DES);
 
-		d->access = AR_PRESENT | AR_INTERRUPT;	/* masking interrupt */
-
 		if (i == VECTOR_SYSCALL) {
 			/*
-			 * The syscall interrupt gate must be calleable from
-			 * userland.
+			 * The syscall trap gate must be callable from
+			 * userland. Interrupts will remain enabled.
 			 */
-			d->access |= DPL_USER;
+			d->access = AR_PRESENT | AR_TRAP | DPL_USER;
+		} else {
+			/*
+			 * Other interrupts use interrupt gates which
+			 * disable interrupts.
+			 */
+			d->access = AR_PRESENT | AR_INTERRUPT;
 		}
 	}
@@ -206,4 +210,6 @@
 	idt_setoffset(d++, (uintptr_t) &int_62);
 	idt_setoffset(d++, (uintptr_t) &int_63);
+
+	idt_setoffset(&idt[VECTOR_SYSCALL], (uintptr_t) &int_syscall);
 }
 
Index: kernel/arch/ia32/src/proc/scheduler.c
===================================================================
--- kernel/arch/ia32/src/proc/scheduler.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/ia32/src/proc/scheduler.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -38,5 +38,5 @@
 #include <proc/thread.h>
 #include <arch.h>
-#include <arch/context.h>  /* SP_DELTA */
+#include <arch/interrupt.h>
 #include <arch/pm.h>
 #include <arch/asm.h>
@@ -58,10 +58,9 @@
 void before_thread_runs_arch(void)
 {
-	uintptr_t kstk = (uintptr_t) &THREAD->kstack[THREAD_STACK_SIZE -
-	    SP_DELTA];
+	uintptr_t kstk = (uintptr_t) &THREAD->kstack[THREAD_STACK_SIZE];
 	
 	if (CPU->arch.fi.bits.sep) {
 		/* Set kernel stack for CP3 -> CPL0 switch via SYSENTER */
-		write_msr(IA32_MSR_SYSENTER_ESP, kstk);
+		write_msr(IA32_MSR_SYSENTER_ESP, kstk - sizeof(istate_t));
 	}
 	
Index: kernel/arch/ia64/src/mm/tlb.c
===================================================================
--- kernel/arch/ia64/src/mm/tlb.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/ia64/src/mm/tlb.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -500,6 +500,5 @@
 		if (as_page_fault(va, PF_ACCESS_EXEC, istate) == AS_PF_FAULT) {
 			fault_if_from_uspace(istate, "Page fault at %p.", va);
-			panic_memtrap(istate, PF_ACCESS_EXEC, va,
-			    "Page fault.");
+			panic_memtrap(istate, PF_ACCESS_EXEC, va, NULL);
 		}
 	}
@@ -622,6 +621,5 @@
 		if (as_page_fault(va, PF_ACCESS_READ, istate) == AS_PF_FAULT) {
 			fault_if_from_uspace(istate, "Page fault at %p.", va);
-			panic_memtrap(istate, PF_ACCESS_READ, va,
-			    "Page fault.");
+			panic_memtrap(istate, PF_ACCESS_UNKNOWN, va, NULL);
 		}
 	}
@@ -671,6 +669,5 @@
 		if (as_page_fault(va, PF_ACCESS_WRITE, istate) == AS_PF_FAULT) {
 			fault_if_from_uspace(istate, "Page fault at %p.", va);
-			panic_memtrap(istate, PF_ACCESS_WRITE, va,
-			    "Page fault.");
+			panic_memtrap(istate, PF_ACCESS_WRITE, va, NULL);
 		}
 	}
@@ -708,6 +705,5 @@
 		if (as_page_fault(va, PF_ACCESS_EXEC, istate) == AS_PF_FAULT) {
 			fault_if_from_uspace(istate, "Page fault at %p.", va);
-			panic_memtrap(istate, PF_ACCESS_EXEC, va,
-			    "Page fault.");
+			panic_memtrap(istate, PF_ACCESS_EXEC, va, NULL);
 		}
 	}
@@ -745,6 +741,5 @@
 		if (as_page_fault(va, PF_ACCESS_READ, istate) == AS_PF_FAULT) {
 			fault_if_from_uspace(istate, "Page fault at %p.", va);
-			panic_memtrap(istate, PF_ACCESS_READ, va,
-			    "Page fault.");
+			panic_memtrap(istate, PF_ACCESS_UNKNOWN, va, NULL);
 		}
 	}
@@ -778,5 +773,5 @@
 	if (as_page_fault(va, PF_ACCESS_WRITE, istate) == AS_PF_FAULT) {
 		fault_if_from_uspace(istate, "Page fault at %p.", va);
-		panic_memtrap(istate, PF_ACCESS_WRITE, va, "Page fault.");
+		panic_memtrap(istate, PF_ACCESS_WRITE, va, NULL);
 	}
 	page_table_unlock(AS, true);
@@ -818,6 +813,5 @@
 		if (as_page_fault(va, PF_ACCESS_READ, istate) == AS_PF_FAULT) {
 			fault_if_from_uspace(istate, "Page fault at %p.", va);
-			panic_memtrap(istate, PF_ACCESS_READ, va,
-			    "Page fault.");
+			panic_memtrap(istate, PF_ACCESS_UNKNOWN, va, NULL);
 		}
 	}
Index: kernel/arch/mips32/src/mm/tlb.c
===================================================================
--- kernel/arch/mips32/src/mm/tlb.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/mips32/src/mm/tlb.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -324,5 +324,5 @@
 	
 	fault_if_from_uspace(istate, "TLB Refill Exception on %p.", va);
-	panic_memtrap(istate, PF_ACCESS_READ, va, "TLB Refill Exception.");
+	panic_memtrap(istate, PF_ACCESS_UNKNOWN, va, "TLB Refill Exception.");
 }
 
@@ -333,5 +333,5 @@
 	
 	fault_if_from_uspace(istate, "TLB Invalid Exception on %p.", va);
-	panic_memtrap(istate, PF_ACCESS_READ, va, "TLB Invalid Exception.");
+	panic_memtrap(istate, PF_ACCESS_UNKNOWN, va, "TLB Invalid Exception.");
 }
 
Index: kernel/arch/ppc32/src/mm/tlb.c
===================================================================
--- kernel/arch/ppc32/src/mm/tlb.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/ppc32/src/mm/tlb.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -112,5 +112,5 @@
 {
 	fault_if_from_uspace(istate, "PHT Refill Exception on %p.", badvaddr);
-	panic_memtrap(istate, PF_ACCESS_READ, badvaddr,
+	panic_memtrap(istate, PF_ACCESS_UNKNOWN, badvaddr,
 	    "PHT Refill Exception.");
 }
Index: kernel/arch/sparc64/src/mm/sun4u/tlb.c
===================================================================
--- kernel/arch/sparc64/src/mm/sun4u/tlb.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/sparc64/src/mm/sun4u/tlb.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -259,5 +259,5 @@
 			/* NULL access in kernel */
 			do_fast_data_access_mmu_miss_fault(istate, tag,
-			    "Dereferencing NULL pointer");
+			    "Dereferencing NULL pointer.");
 		} else if (page_8k >= end_of_identity) {
 			/*
@@ -442,5 +442,5 @@
 {
 	fault_if_from_uspace(istate, "%s, Address=%p.", str, va);
-	panic_memtrap(istate, PF_ACCESS_EXEC, va, "%s.", str);
+	panic_memtrap(istate, PF_ACCESS_EXEC, va, str);
 }
 
@@ -453,5 +453,5 @@
 	fault_if_from_uspace(istate, "%s, Page=%p (ASID=%d).", str, va,
 	    tag.context);
-	panic_memtrap(istate, PF_ACCESS_READ, va, "%s.", str);
+	panic_memtrap(istate, PF_ACCESS_UNKNOWN, va, str);
 }
 
@@ -464,5 +464,5 @@
 	fault_if_from_uspace(istate, "%s, Page=%p (ASID=%d).", str, va,
 	    tag.context);
-	panic_memtrap(istate, PF_ACCESS_WRITE, va, "%s.", str);
+	panic_memtrap(istate, PF_ACCESS_WRITE, va, str);
 }
 
Index: kernel/arch/sparc64/src/mm/sun4v/tlb.c
===================================================================
--- kernel/arch/sparc64/src/mm/sun4v/tlb.c	(revision 41ce4d90d8c47b133bd70c5513dcbf39004b6833)
+++ kernel/arch/sparc64/src/mm/sun4v/tlb.c	(revision 074c9bdaa46f546f90e5f877f4ee0fc2294d246e)
@@ -359,5 +359,5 @@
 {
 	fault_if_from_uspace(istate, "%s, Address=%p.", str, va);
-	panic_memtrap(istate, PF_ACCESS_EXEC, va, "%s.", str);
+	panic_memtrap(istate, PF_ACCESS_EXEC, va, str);
 }
 
@@ -367,6 +367,6 @@
 	fault_if_from_uspace(istate, "%s, Page=%p (ASID=%d).", str,
 	    DMISS_ADDRESS(page_and_ctx), DMISS_CONTEXT(page_and_ctx));
-	panic_memtrap(istate, PF_ACCESS_READ, DMISS_ADDRESS(page_and_ctx),
-	    "%s.");
+	panic_memtrap(istate, PF_ACCESS_UNKNOWN, DMISS_ADDRESS(page_and_ctx),
+	    str);
 }
 
@@ -377,5 +377,5 @@
 	    DMISS_ADDRESS(page_and_ctx), DMISS_CONTEXT(page_and_ctx));
 	panic_memtrap(istate, PF_ACCESS_WRITE, DMISS_ADDRESS(page_and_ctx),
-	    "%s.");
+	    str);
 }
 
