Index: hexo/include/hexo/interrupt.h
===================================================================
--- hexo/include/hexo/interrupt.h	(revision 1308)
+++ hexo/include/hexo/interrupt.h	(working copy)
@@ -103,6 +103,13 @@
 
 /************************************************************ exceptions */
 
+#define CPU_EXCEPTION_ILLEGAL_INS  0x1
+#define CPU_EXCEPTION_DATA_ERROR   0x2
+#define CPU_EXCEPTION_INS_ERROR    0x3
+#define CPU_EXCEPTION_DATA_ALIGN   0x4
+#define CPU_EXCEPTION_OTHER        0x5
+
+
 /** CPU exception handler function template
     @see cpu_exception_handler_t
     @showcontent
Index: hexo/include/hexo/asm.h
===================================================================
--- hexo/include/hexo/asm.h	(revision 0)
+++ hexo/include/hexo/asm.h	(revision 0)
@@ -0,0 +1,38 @@
+/*
+ * This file is part of MutekH.
+ * 
+ * MutekH is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 of the License.
+ * 
+ * MutekH is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with MutekH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Copyright (c) UPMC, Lip6, SoC
+ *         Nicolas Pouillon <nipo@ssji.net>, 2010
+ */
+
+#ifndef HEXO_ASM_H_
+#define HEXO_ASM_H_
+
+#define ASM_STR_(x) #x
+#define ASM_STR(x) ASM_STR_(x)
+
+#define FUNC_START(x)                             \
+        "\t.globl " #x "            \n"           \
+        "\t.func " #x "             \n"           \
+        "\t.type " #x ", %function  \n"           \
+        #x ":                     \n"
+
+#define FUNC_END(x)                           \
+    "\t.endfunc               \n"             \
+    "\t.size " #x ", .-" #x " \n"
+
+#endif

Property changes on: hexo/include/hexo/asm.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + "Author Date Id Rev URL Revision"
Added: svn:eol-style
   + native

Index: hexo/user_mode.c
===================================================================
--- hexo/user_mode.c	(revision 0)
+++ hexo/user_mode.c	(revision 0)
@@ -0,0 +1,28 @@
+/*
+ * This file is part of MutekH.
+ * 
+ * MutekH is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 of the License.
+ * 
+ * MutekH is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with MutekH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Copyright (c) UPMC, Lip6, SoC
+ *         Nicolas Pouillon <nipo@ssji.net>, 2010
+ */
+
+#include <hexo/types.h>
+#include <hexo/local.h>
+
+/**
+   Pointer to base of kernel stack associated to a user-mode thread
+ */
+CONTEXT_LOCAL uintptr_t context_kstack;

Property changes on: hexo/user_mode.c
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + "Author Date Id Rev URL Revision"
Added: svn:eol-style
   + native

Index: hexo/Makefile
===================================================================
--- hexo/Makefile	(revision 1308)
+++ hexo/Makefile	(working copy)
@@ -8,6 +8,10 @@
 objs += ipi.o
 endif
 
+ifeq ($(CONFIG_CPU_USER), defined)
+objs += user_mode.o
+endif
+
 ifeq ($(CONFIG_HEXO_IRQ), defined)
 objs += interrupt.o
 endif
Index: cpu/ppc/exception.c
===================================================================
--- cpu/ppc/exception.c	(revision 1308)
+++ cpu/ppc/exception.c	(working copy)
@@ -15,290 +15,366 @@
     along with MutekH; if not, write to the Free Software Foundation,
     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 
-    Copyright (c) Nicolas Pouillon <nipo@ssji.net>, 2009
-
+    Copyright (c) 2009-2010, Nicolas Pouillon <nipo@ssji.net>
 */
 
+#include <hexo/asm.h>
+#include <hexo/interrupt.h>
+
+#define GET_SPRREL(name, rd, rt, spr)                                  \
+    "mfspr " #rt ", " #spr "             \n\t"                         \
+    "lwz   " #rd ", " name "(" #rt ")    \n\t"
+#define GET_ABS(name, rd, rt)                                          \
+    "lis   " #rt ", " name "@ha           \n\t"                        \
+    "lwz   " #rd ", " name "@l(" #rt ")   \n\t"
+#define LA(rd, name)                                                    \
+    "lis   " #rd ", (" #name ")@h         \n\t"                        \
+    "ori   " #rd ", " #rd ", (" #name ")@l\n\t"
+
+#ifdef CONFIG_SMP
+# define CPULOCAL_GET(name, rd, rt) GET_SPRREL(name, rd, rt, 0x105)
+#else
+# define CPULOCAL_GET(name, rd, rt) GET_ABS(name, rd)
+#endif
+
+#define CONTEXTLOCAL_GET(name, rd, rt) GET_SPRREL(name, rd, rt, 0x104)
+
+
+#define SPRG0 "0x110"
+#define SPRG1 "0x111"
+
+#define DO_REG_2_3(op, n, off)                                  \
+    #op "   2, " #off "+4* 0(" #n ")      \n\t"                 \
+    #op "   3, " #off "+4* 1(" #n ")      \n\t"
+
+#define DO_REG_4_12(op, n, off)                                 \
+    #op "   4, " #off "+4* 0(" #n ")      \n\t"                 \
+    #op "   5, " #off "+4* 1(" #n ")      \n\t"                 \
+    #op "   6, " #off "+4* 2(" #n ")      \n\t"                 \
+    #op "   7, " #off "+4* 3(" #n ")      \n\t"                 \
+    #op "   8, " #off "+4* 4(" #n ")      \n\t"                 \
+    #op "   9, " #off "+4* 5(" #n ")      \n\t"                 \
+    #op "  10, " #off "+4* 6(" #n ")      \n\t"                 \
+    #op "  11, " #off "+4* 7(" #n ")      \n\t"                 \
+    #op "  12, " #off "+4* 8(" #n ")      \n\t"
+
+#define DO_REG_2_12(op, n, off)                                        \
+    DO_REG_2_3(op, n, off)                                             \
+    DO_REG_4_12(op, n, off+8)
+
+
 /*
-	".section      \".ppc_special." #name "\",\"ax\",@progbits			\n\t"
-    ".globl ppc_special_" #name "_entry				\n\t"
-	".type  ppc_special_" #name "_entry, @function   \n"
-    "ppc_special_" #name "_entry:					\n\t"
-    "stwu 1, -16(1)					\n\t"
-    "stw 0, 8(1)					\n\t"
-    "mflr 0					\n\t"
-    "stw 0, 12(1)					\n\t"
-	"bl " #func "\n\t"
-    "lwz 0, 12(1)					\n\t"
-    "mtlr 0					\n\t"
-    "lwz 0, 8(1)					\n\t"
-    "addi 1, 1, 16					\n\t"
-	#ret_ins "\n\t"
-	".size ppc_special_" #name "_entry, .-ppc_special_" #name "_entry \n\t"
-*/
+  (cls / tls are r/o for user, no need to restore)
 
-#define SAVE_REG_2_12(n, off)									\
-    "stw   2, " #off "+4* 0(" #n ")      \n\t"					\
-    "stw   3, " #off "+4* 1(" #n ")      \n\t"					\
-    "stw   4, " #off "+4* 2(" #n ")      \n\t"					\
-    "stw   5, " #off "+4* 3(" #n ")      \n\t"					\
-    "stw   6, " #off "+4* 4(" #n ")      \n\t"					\
-    "stw   7, " #off "+4* 5(" #n ")      \n\t"					\
-    "stw   8, " #off "+4* 6(" #n ")      \n\t"					\
-    "stw   9, " #off "+4* 7(" #n ")      \n\t"					\
-    "stw  10, " #off "+4* 8(" #n ")      \n\t"					\
-    "stw  11, " #off "+4* 9(" #n ")      \n\t"					\
-    "stw  12, " #off "+4*10(" #n ")      \n\t"
+  Whatever the exception, we need to:
+  * copy r0, r1 -> sprg0, sprg1
+  * save cr to r0
+  * get cpu "previous" mode
+  * if from kernel
+    * copy back r1 from sprg1
+  * if from user
+    * get task's kernel stack to r1
+  * reserve 32+5 registers
+  * put cr (r0)
+  * put exception type in r0
+  * put srr0/2 (PC), srr1/3 (msr)
 
-#define RESTORE_REG_2_12(n, off)								\
-    "lwz   2, " #off "+4* 0(" #n ")      \n\t"					\
-    "lwz   3, " #off "+4* 1(" #n ")      \n\t"					\
-    "lwz   4, " #off "+4* 2(" #n ")      \n\t"					\
-    "lwz   5, " #off "+4* 3(" #n ")      \n\t"					\
-    "lwz   6, " #off "+4* 4(" #n ")      \n\t"					\
-    "lwz   7, " #off "+4* 5(" #n ")      \n\t"					\
-    "lwz   8, " #off "+4* 6(" #n ")      \n\t"					\
-    "lwz   9, " #off "+4* 7(" #n ")      \n\t"					\
-    "lwz  10, " #off "+4* 8(" #n ")      \n\t"					\
-    "lwz  11, " #off "+4* 9(" #n ")      \n\t"					\
-    "lwz  12, " #off "+4*10(" #n ")      \n\t"
+  Generic part:
+  * put ctr, lr
+  * put sprg[01] on stack
+  * put gpr 2-12 on stack
+  * (put gpr 13-31 on stack)
+  * handle exception
+  * restore ctr, cr, lr, srr0 (PC), srr1 (msr)
+  * (restore gpr 13-31)
+  * restore gpr 2-12
+  * load r0 from *sp
+  * load sp from *sp
+  * rfi
 
-#ifdef CONFIG_SMP
-# define GET_HANDLER_ADDRESS(name, rd, rt, spr)						   \
-	"mfspr " #rt ", " #spr "                \n\t"					   \
-    "lwz   " #rd ", " name "(" #rt ")    \n\t"
+  stack layout:
+   0     1    2    3    4         5          6      37
+  [sp] [ctr] [lr] [cr] [srr0/pc] [srr1/msr] [r0 .. r31] 
+ */
+
+#if defined(CONFIG_USER_MODE)
+# define GET_STACK_SAVE_CR                                             \
+    /* put msr in cr and do bit test (user mode) */                    \
+    "mf" #msr_srr " 1                     \n\t"                        \
+    "mtcr   1                             \n\t"                        \
+    "bt     17, 1f                        \n\t"                        \
+    /* from kernel */                                                  \
+    "mfspr 1, " SPRG1 "                   \n\t"                        \
+    "stwu  1, -38*4(1)                    \n\t"                        \
+    "stw   0,  3 *4(1)                    \n\t"                        \
+    "b 2f                                 \n\t"                        \
+    "1:                                   \n\t"                        \
+    CONTEXTLOCAL_GET("context_kstack", 1, 1)                           \
+    "addi  1, -38*4(1)                    \n\t"                        \
+    /* save cr */                                                      \
+    "stw   0,  3 *4(1)                    \n\t"                        \
+    /* save old sp */                                                  \
+    "mfspr 0,  " SPRG1 "                  \n\t"                        \
+    "stw   0,  0 *4(1)                    \n\t"                        \
+    "2:                                   \n\t"
 #else
-# define GET_HANDLER_ADDRESS(name, rd, rt, foo)						   \
-    "lis   " #rt ", " name "@ha           \n\t"						   \
-    "lwz   " #rd ", " name "@l(" #rt ")     \n\t"
+# define GET_STACK_SAVE_CR                                             \
+    "stwu  1, -38*4(1)                    \n\t"                        \
+    /* save cr */                                                      \
+    "stw   0,  3 *4(1)                    \n\t"
 #endif
 
-# define GET_CPULOCAL_HANDLER_ADDRESS(name, rd, rt) GET_HANDLER_ADDRESS(name, rd, rt, 0x105)
-# define GET_CONTEXTLOCAL_HANDLER_ADDRESS(name, rd, rt) GET_HANDLER_ADDRESS(name, rd, rt, 0x104)
+#define prepare_exception(pc_srr, msr_srr)                             \
+    "mtspr  " SPRG0 ", 0                  \n\t"                        \
+    "mtspr  " SPRG1 ", 1                  \n\t"                        \
+    "mfcr   0                             \n\t"                        \
+    GET_STACK_SAVE_CR                                                  \
+    /* pc */                                                           \
+    "mf" #pc_srr " 0                      \n\t"                        \
+    "stw    0, 4 *4(1)                    \n\t"                        \
+    /* srr1 */                                                         \
+    "mf" #msr_srr " 0                     \n\t"                        \
+    "stw    0, 5 *4(1)                    \n\t"                        \
+    /* ctr */                                                          \
+    "mfctr 0                              \n\t"                        \
+    "stw   0, 1 *4(1)                     \n\t"
 
-#define HANDLE_EXCEPTION(eno, srr02)								   \
-	/* r1 -> @0 */													   \
-    "stwu  1,-4*22(1)                      \n\t"					   \
-	/* r0 -> @3 */													   \
-    "stw   0, 4* 7(1)                      \n\t"					   \
-	/* lr -> @19 */													   \
-    "mflr  0                               \n\t"					   \
-    "stw   0, 4*19(1)                      \n\t"					   \
-	/* cr -> @21 */													   \
-    "mfcr  0                               \n\t"					   \
-    "stw   0, 4*21(1)                      \n\t"					   \
-	/* r2-r12 -> @8-18 */											   \
-	SAVE_REG_2_12(1, 32)											   \
-																	   \
-	/* ctr -> @20 */												   \
-	"mfctr 0                               \n\t"					   \
-    "stw   0, 4*20(1)                      \n\t"					   \
-																	   \
-	GET_CPULOCAL_HANDLER_ADDRESS("cpu_exception_handler", 0, 3)		   \
-	"mtctr 0                               \n\t"					   \
-																	   \
-	/* Put handler arguments: */									   \
-	/* a0: type */													   \
-	/* a1: execptr (srr) */											   \
-	/* a2: dataptr (dear) */										   \
-	/* a3: regtable (sp + 7*4) */									   \
-	/* a4: sp (sp + 22*4) */										   \
-	"li    3, " #eno "                     \n\t"					   \
-	"mfsrr" #srr02 " 4                     \n\t"					   \
-	"mfspr  5, 981                         \n\t"					   \
-	"addi   6, 1, 4* 7                     \n\t"					   \
-	"addi   7, 1, 4*22                     \n\t"					   \
-																	   \
-	"bctrl                                 \n\t"					   \
-																	   \
-	/* ctr -> @20 */												   \
-    "lwz   0, 4*20(1)                      \n\t"					   \
-	"mtctr 0                               \n\t"					   \
-																	   \
-	/* r2-r12 -> @8-18 */											   \
-	RESTORE_REG_2_12(1, 32)											   \
-																	   \
-	/* lr -> @19 */													   \
-    "lwz   0, 4*19(1)                      \n\t"					   \
-    "mtlr  0                               \n\t"					   \
-																	   \
-	/* cr -> @21 */													   \
-    "lwz   0, 4*21(1)                      \n\t"					   \
-    "mtcr  0                               \n\t"					   \
-																	   \
-	/* r0 -> @7 */													   \
-    "lwz  0, 4* 7(1)                         \n\t"					   \
-	/* r1 -> @0 */													   \
-    "addi 1, 1, 4*18                      \n\t"
+#define handle_exception(name)                                         \
+    LA(0, exception_common)                                            \
+    "mtctr 0                              \n\t"                        \
+    /* exc type */                                                     \
+    "li    0, " ASM_STR(name) "           \n\t"                        \
+    "bctr                                 \n\t"
 
-asm(
-    ".section        .excep,\"ax\",@progbits		\n"
+#define CRASH(x, y)                                                    \
+    prepare_exception(x, y)                                            \
+    handle_exception(CPU_EXCEPTION_OTHER)
 
-	/* critical interrupt (critical, async) */
-	".org 0x100\n"
+#define handle_interrupt(no)                                           \
+    LA(0, interrupt_common)                                            \
+    "mtctr 0                              \n\t"                        \
+    "li    0, " #no "                     \n\t"                        \
+    "bctr                                 \n\t"
 
-	/* machine check (critical, async, imprecise) */
-	".org 0x200\n"
-    ".globl ppc_special_machine_check_entry		      \n\t"
-	".type  ppc_special_machine_check_entry, @function  \n"
-    "ppc_special_machine_check_entry:		      \n\t"
-	HANDLE_EXCEPTION(3, 2)
-	"rfci                                  \n\t"
-	".size ppc_special_machine_check_entry, .-ppc_special_machine_check_entry \n\t"
+#define handle_syscall()                                               \
+    LA(0, syscall_common)                                              \
+    "mtctr 0                              \n\t"
 
-	/* data storage */
-	".org 0x300\n"
-    ".globl ppc_special_data_storage_entry		      \n\t"
-	".type  ppc_special_data_storage_entry, @function  \n"
-    "ppc_special_data_storage_entry:		      \n\t"
-	HANDLE_EXCEPTION(4, 0)
-	"rfi                                  \n\t"
-	".size ppc_special_data_storage_entry, .-ppc_special_data_storage_entry \n\t"
+asm(".section        .text,\"ax\",@progbits  \n"
 
-	/* instr storage */
-	".org 0x400\n"
-    ".globl ppc_special_instr_storage_entry		      \n\t"
-	".type  ppc_special_instr_storage_entry, @function  \n"
-    "ppc_special_instr_storage_entry:		      \n\t"
-	HANDLE_EXCEPTION(5, 0)
-	"rfi                                  \n\t"
-	".size ppc_special_instr_storage_entry, .-ppc_special_instr_storage_entry \n\t"
+    FUNC_START(exception_common)
+    DO_REG_2_12(stw, 1, 8*4)
+    /* lr */
+    "mflr  3                              \n\t"
+    "stw   3, 2 *4(1)                     \n\t"
+    /* r0 */
+    "mfspr 3, " SPRG0 "                   \n\t"
+    "stw   3, 6 *4(1)                     \n\t"
+    /* r1 */
+    "mfspr 3, " SPRG1 "                   \n\t"
+    "stw   3, 7 *4(1)                     \n\t"
+    /* Put handler arguments: */
+    /* a0: type */
+    /* a1: execptr (srr) */
+    /* a2: dataptr (dear) */
+    /* a3: regtable (sp + 6*4) */
+    /* a4: sp (sp + 22*4) */
+    "or    3, 0, 0                        \n\t"
+    "lwz   4, 4 *4(1)                     \n\t"
+    "addi  6, 1, 6*4                      \n\t"
+    "lwz   7, 7 *4(1)                     \n\t"
 
-	/* external (async) */
-	".org 0x500\n"
-    ".globl ppc_special_external_entry		      \n\t"
-	".type  ppc_special_external_entry, @function  \n"
-    "ppc_special_external_entry:           \n\t"
-	/* r1 -> @0 */
-    "stwu  1,-4*18(1)                      \n\t"
-	/* r0 -> @3 */
-    "stw   0, 4* 3(1)                      \n\t"
-	/* lr -> @15 */
-    "mflr  0                               \n\t"
-    "stw   0, 4*15(1)                      \n\t"
-	/* cr -> @17 */
-    "mfcr  0                               \n\t"
-    "stw   0, 4*17(1)                      \n\t"
-	/* r2-r12 -> @4-14 */
-	SAVE_REG_2_12(1, 16)
+    /*
+     * dont use 0 as 3rd arg, or you'll get crappy things,
+     * hijack r5 and do mfdear afterwards
+     */
+    CPULOCAL_GET("cpu_exception_handler", 0, 5)
+    "mtctr 0                               \n\t"
+    "mfdear 5                              \n\t"
 
-	/* ctr -> @16 */
-	"mfctr 0                               \n\t"
-    "stw   0, 4*16(1)                      \n\t"
+    /* Call the exception handler */
+    "bctrl                                 \n\t"
+    "b back_from_exception                 \n\t"
+    FUNC_END(exception_common)
 
-	GET_CPULOCAL_HANDLER_ADDRESS("cpu_interrupt_handler", 0, 3)
-	"mtctr 0                               \n\t"
 
-	GET_CPULOCAL_HANDLER_ADDRESS("cpu_interrupt_handler_arg", 3, 3)
 
-	/* interrupt line is 0 */
-	"li    4, 0                            \n\t"
+    FUNC_START(interrupt_common)
+    DO_REG_2_12(stw, 1, 8*4)
+    /* lr */
+    "mflr  3                              \n\t"
+    "stw   3, 2 *4(1)                     \n\t"
+    /* r0 */
+    "mfspr 3, " SPRG0 "                   \n\t"
+    "stw   3, 6 *4(1)                     \n\t"
+    /* r1 */
+    "mfspr 3, " SPRG1 "                   \n\t"
+    "stw   3, 7 *4(1)                     \n\t"
+    /* Put handler arguments: */
+    /* a0: priv */
+    /* a1: irq */
 
-	"bctrl                                 \n\t"
+    CPULOCAL_GET("cpu_interrupt_handler", 5, 5)
+    CPULOCAL_GET("cpu_interrupt_handler_arg", 3, 3)
+    "or    4, 0, 0                         \n\t"
+    "mtctr 5                               \n\t"
 
-	/* ctr -> @16 */
-    "lwz   0, 4*16(1)                      \n\t"
-	"mtctr 0                               \n\t"
+    /* Call the interrupt handler */
+    "bctrl                                 \n\t"
+    "b back_from_exception                 \n\t"
+    FUNC_END(interrupt_common)
 
-	/* r2-r12 -> @4-14 */
-	RESTORE_REG_2_12(1, 16)
 
-	/* lr -> @15 */
-    "lwz   0, 4*15(1)                      \n\t"
-    "mtlr  0                               \n\t"
 
-	/* cr -> @17 */
-    "lwz   0, 4*17(1)                      \n\t"
-    "mtcr  0                               \n\t"
+    FUNC_START(syscall_common)
+    DO_REG_2_12(stw, 1, 8*4)
+    /* ctr */
+    "mfctr 3                              \n\t"
+    "stw   3, 1 *4(1)                     \n\t"
+    /* lr */
+    "mflr  3                              \n\t"
+    "stw   3, 2 *4(1)                     \n\t"
+    /* r0 */
+    "mfspr 3, " SPRG0 "                   \n\t"
+    "stw   3, 6 *4(1)                     \n\t"
+    /* r1 */
+    "mfspr 3, " SPRG1 "                   \n\t"
+    "stw   3, 7 *4(1)                     \n\t"
+    /* Put handler arguments: */
+    /* a0: number */
+    /* a1: regtable */
 
-	/* r0 -> @3 */
-    "lwz  0, 4* 3(1)                         \n\t"
-	/* r1 -> @0 */
-    "addi 1, 1, 4*18                      \n\t"
+    CPULOCAL_GET("cpu_syscall_handler", 5, 5)
+    "mtctr 5                              \n\t"
 
-	"rfi                                  \n\t"
-	".size ppc_special_external_entry, .-ppc_special_external_entry \n\t"
+    "li    3, 0                           \n\t"
+    "addi  6, 1, 6*4                      \n\t"
 
+    /* Call the syscall handler */
+    "bctrl                                 \n\t"
+    "b back_from_syscall                   \n\t"
+    FUNC_END(syscall_common)
 
-	/* alignment */
-	".org 0x600\n"
-    ".globl ppc_special_alignment_entry		      \n\t"
-	".type  ppc_special_alignment_entry, @function  \n"
-    "ppc_special_alignment_entry:		      \n\t"
-	HANDLE_EXCEPTION(2, 0)
-	"rfi                                  \n\t"
-	".size ppc_special_alignment_entry, .-ppc_special_alignment_entry \n\t"
 
-	/* program */
-	".org 0x700\n"
-    ".globl ppc_special_program_entry		      \n\t"
-	".type  ppc_special_program_entry, @function  \n"
-    "ppc_special_program_entry:		      \n\t"
-	HANDLE_EXCEPTION(1, 0)
-	"rfi                                  \n\t"
-	".size ppc_special_program_entry, .-ppc_special_program_entry \n\t"
 
-	/* fpu unusable */
-	".org 0x800\n"
 
-	/* syscall */
-	".org 0xc00\n"
-    ".globl ppc_special_syscall_entry		      \n\t"
-	".type  ppc_special_syscall_entry, @function  \n"
-    "ppc_special_syscall_entry:           \n\t"
-    "stwu 1, -4*15(1)                     \n\t"
-    "stw   0, 4* 1(1)                      \n\t"
 
-	SAVE_REG_2_12(1, 16)
+    FUNC_START(back_from_exception)
+    DO_REG_4_12(lwz, 1, 10*4)
 
-    /* Put syscall number on first arg */
-	"or    3, 0, 0                         \n\t"
-    "mflr  0                               \n\t"
-    "stw   0, 4*13(1)                      \n\t"
+    /* Dont restore reg 4 to 12 for syscall return */
+    "back_from_syscall:                   \n\t"
+    DO_REG_2_3(lwz, 1, 8*4)
 
-	"mfctr 0                               \n\t"
-    "stw   0, 4*14(1)                      \n\t"
+    /* ctr */
+    "lwz   0, 1 *4(1)                     \n\t"
+    "mtctr 0                              \n\t"
+    /* lr */
+    "lwz   0, 2 *4(1)                     \n\t"
+    "mtlr  0                              \n\t"
+    /* cr */
+    "lwz    0,  3 *4(1)                   \n\t"
+    "mtcr   0                             \n\t"
+    /* srr0 */
+    "lwz    0, 4 *4(1)                    \n\t"
+    "mtsrr0 0                             \n\t"
+    /* srr1 */
+    "lwz    0, 5 *4(1)                    \n\t"
+    "mtsrr1 0                             \n\t"
+    /* r0 */
+    "lwz   0, 6 *4(1)                     \n\t"
+    /* r1 */
+    "lwz   1, 7 *4(1)                     \n\t"
+    "rfi                                  \n\t"
+    FUNC_END(back_from_exception)
+    );
 
-	GET_CONTEXTLOCAL_HANDLER_ADDRESS("cpu_syscall_handler", 0, 3)
-	"mtctr 0                               \n\t"
-	"bctrl                                 \n\t"
 
-    /* Put register table on second arg */
-	/* Table is: sp, r0, r2, r3, ..., r12 */
-	"or    4, 1, 1                         \n\t"
-    "lwz   0, 4*14(1)                      \n\t"
-	"mtctr 0                               \n\t"
 
-    "lwz   0, 4*13(1)                      \n\t"
-	RESTORE_REG_2_12(1, 16)
+asm(
+    ".section        .excep,\"ax\",@progbits        \n"
 
-    "mtlr 0                               \n\t"
-    "lwz  0, 4(1)                         \n\t"
-    "lwz  1, 0(1)                         \n\t"
+    /* critical interrupt (critical, async) */
+    ".org 0x100\n"
+    FUNC_START(ppc_critical_entry)
+    prepare_exception(srr2, srr3)
+    handle_interrupt(1)
+    FUNC_END(ppc_critical_entry)
 
-	"rfi                                  \n\t"
-	".size ppc_special_syscall_entry, .-ppc_special_syscall_entry \n\t"
+    /* machine check (critical, async, imprecise) */
+    ".org 0x200\n"
+    FUNC_START(ppc_machine_entry)
+    CRASH(srr2, srr3)
+    FUNC_END(ppc_machine_entry)
 
-	/* apu unavailable */
-	".org 0xf20\n"
+    /* data storage */
+    ".org 0x300\n"
+    FUNC_START(ppc_data_storage_entry)
+    prepare_exception(srr0, srr1)
+    handle_exception(CPU_EXCEPTION_DATA_ERROR)
+    FUNC_END(ppc_data_storage_entry)
 
-	/* programmable-interval timer (async) */
-	".org 0x1000\n"
+    /* instr storage */
+    ".org 0x400\n"
+    FUNC_START(ppc_instr_storage_entry)
+    prepare_exception(srr0, srr1)
+    handle_exception(CPU_EXCEPTION_INS_ERROR)
+    FUNC_END(ppc_instr_storage_entry)
 
-	/* fixed-interval timer (async) */
-	".org 0x1010\n"
+    /* external (async) */
+    ".org 0x500\n"
+    FUNC_START(ppc_external_entry)
+    prepare_exception(srr0, srr1)
+    handle_interrupt(0)
+    FUNC_END(ppc_external_entry)
 
-	/* watchdog (critical, async) */
-	".org 0x1020\n"
 
-	/* data tlb */
-	".org 0x1100\n"
+    /* alignment */
+    ".org 0x600\n"
+    FUNC_START(ppc_align_entry)
+    prepare_exception(srr0, srr1)
+    handle_exception(CPU_EXCEPTION_DATA_ALIGN)
+    FUNC_END(ppc_align_entry)
 
-	/* ins tlb */
-	".org 0x1200\n"
+    /* program */
+    ".org 0x700\n"
+    FUNC_START(ppc_program_entry)
+    prepare_exception(srr0, srr1)
+    handle_exception(CPU_EXCEPTION_ILLEGAL_INS)
+    FUNC_END(ppc_program_entry)
 
-	/* debug (critical, (a)sync) */
-	".org 0x2000\n"
+    /* fpu unusable */
+    ".org 0x800\n"
+    FUNC_START(ppc_fpu_entry)
+    CRASH(srr0, srr1)
+    FUNC_END(ppc_fpu_entry)
 
+    /* syscall */
+    ".org 0xc00\n"
+    FUNC_START(ppc_syscall_entry)
+    handle_syscall()
+    FUNC_END(ppc_syscall_entry)
+
+    /* apu unavailable */
+    ".org 0xf20\n"
+
+    /* programmable-interval timer (async) */
+    ".org 0x1000\n"
+
+    /* fixed-interval timer (async) */
+    ".org 0x1010\n"
+
+    /* watchdog (critical, async) */
+    ".org 0x1020\n"
+
+    /* data tlb */
+    ".org 0x1100\n"
+
+    /* ins tlb */
+    ".org 0x1200\n"
+
+    /* debug (critical, (a)sync) */
+    ".org 0x2000\n"
+
     );
 
Index: cpu/ppc/notes.rst
===================================================================
--- cpu/ppc/notes.rst	(revision 0)
+++ cpu/ppc/notes.rst	(revision 0)
@@ -0,0 +1,20 @@
+Special purpose register usage
+------------------------------
+
+===== ====== ======================= ==========
+reg   sprn   data                    attributes
+===== ====== ======================= ==========
+sprg0 0x110  exception handler r0    rw
+----- ------ ----------------------- ----------
+sprg1 0x111  exception handler r1    rw
+----- ------ ----------------------- ----------
+sprg2 0x112  exception handler r2    rw
+----- ------ ----------------------- ----------
+sprg4 0x104  task-local-storage base ro, user
+----- ------ ----------------------- ----------
+sprg4 0x114  task-local-storage base rw
+----- ------ ----------------------- ----------
+sprg5 0x105  cpu-local-storage base  ro, user
+----- ------ ----------------------- ----------
+sprg5 0x115  cpu-local-storage base  rw
+----- ------ ----------------------- ----------
Index: cpu/ppc/boot.c
===================================================================
--- cpu/ppc/boot.c	(revision 1308)
+++ cpu/ppc/boot.c	(working copy)
@@ -19,6 +19,8 @@
 
 */
 
+#include <hexo/asm.h>
+
 #ifdef CONFIG_SOCLIB_MEMCHECK
 # include <arch/mem_checker.h>
 #endif
@@ -26,8 +28,7 @@
 asm(
     ".section        .text,\"ax\",@progbits		\n"
 
-    ".globl cpu_boot					\n"
-    "cpu_boot:						\n"
+    FUNC_START(cpu_boot)
 
     /* get CPU id and adjust stack */
     "lis	9, __initial_stack - 8@ha    \n"
@@ -86,13 +87,13 @@
     "la         2, arch_init@l(2)			\n"
     "mtctr      2					\n"
     "bctr						\n"
+    FUNC_END(cpu_boot)
     );
 
 asm(
     ".section        .boot,\"ax\",@progbits     \n"
 
-    ".globl cpu_boot_pointer    \n\t"
-    "cpu_boot_pointer:          \n\t"
+    FUNC_START(cpu_boot_pointer)
 	"1:                         \n\t"
     "lis    3, cpu_boot@ha      \n\t"
     "la     3, cpu_boot@l(3)    \n\t"
@@ -100,5 +101,6 @@
     "bctr                       \n\t"
     ".org 0x80-4                \n\t"
     "b      1b                  \n\t"
+    FUNC_END(cpu_boot_pointer)
     );
 
Index: cpu/mips/interrupts.c
===================================================================
--- cpu/mips/interrupts.c	(revision 1308)
+++ cpu/mips/interrupts.c	(working copy)
@@ -16,26 +16,90 @@
     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 
     Copyright Alexandre Becoulet <alexandre.becoulet@lip6.fr> (c) 2006
+	Copyright (c) 2010, Nicolas Pouillon <nipo@ssji.net>
+*/
 
+#include <hexo/asm.h>
+
+#ifdef CONFIG_SMP
+# define CPU_LOCAL_GET(reg, name) "    lw " #reg ", " #name "($27) \n"
+#else
+# define CPU_LOCAL_GET(reg, name) "    lw " #reg ", " #name "\n"
+#endif
+
+#if __mips >= 32
+# define CPU_ID(reg)                                                   \
+    "   mfc0    " #reg ",    $15,    1           \n"                   \
+    "   andi    " #reg ",    " #reg ",    0x3ff  \n"
+# define STATUS_UM_BIT "0x10"
+#else
+# define CPU_ID(reg)                                                   \
+    "   mfc0    " #reg ",    $15                 \n"                   \
+    "   andi    " #reg ",    " #reg ",    0x3ff  \n"
+# define STATUS_UM_BIT "0x8"
+#endif
+
+// Not in macros: $0, $26 (k0), $27 (k1), $29 (sp)
+
+// 11 registers (but as we call ABI-compliant func, t* may not be saved)
+// so only gp and ra must be saved.
+// Even if we end-up switching threads, switch() will finally save them
+#define DO_CALLEE_SAVED(op, reg)                 \
+    "   " #op "  $28,   28 * 4(" #reg ") \n"     \
+    "   " #op "  $31,   31 * 4(" #reg ") \n"
+/*
+    "   " #op "  $16,   16 * 4(" #reg ") \n"     \
+    "   " #op "  $17,   17 * 4(" #reg ") \n"     \
+    "   " #op "  $18,   18 * 4(" #reg ") \n"     \
+    "   " #op "  $19,   19 * 4(" #reg ") \n"     \
+    "   " #op "  $20,   20 * 4(" #reg ") \n"     \
+    "   " #op "  $21,   21 * 4(" #reg ") \n"     \
+    "   " #op "  $22,   22 * 4(" #reg ") \n"     \
+    "   " #op "  $23,   23 * 4(" #reg ") \n"     \
+    "   " #op "  $30,   30 * 4(" #reg ") \n"     \
 */
 
+
+// 10 registers
+#define DO_TEMP_REGS(op, reg)                    \
+    "   " #op "   $8,    8 * 4(" #reg ") \n"     \
+    "   " #op "   $9,    9 * 4(" #reg ") \n"     \
+    "   " #op "  $10,   10 * 4(" #reg ") \n"     \
+    "   " #op "  $11,   11 * 4(" #reg ") \n"     \
+    "   " #op "  $12,   12 * 4(" #reg ") \n"     \
+    "   " #op "  $13,   13 * 4(" #reg ") \n"     \
+    "   " #op "  $14,   14 * 4(" #reg ") \n"     \
+    "   " #op "  $15,   15 * 4(" #reg ") \n"     \
+    "   " #op "  $24,   24 * 4(" #reg ") \n"     \
+    "   " #op "  $25,   25 * 4(" #reg ") \n"
+
+#define DO_AT_REG(op, reg)                       \
+    "   " #op "   $1,    1 * 4(" #reg ") \n"
+
+#define DO_RVAL_REGS(op, reg)                    \
+    "   " #op "   $2,    2 * 4(" #reg ") \n"     \
+    "   " #op "   $3,    3 * 4(" #reg ") \n"
+
+#define DO_ARG_REGS(op, reg)                     \
+    "   " #op "   $4,    4 * 4(" #reg ") \n"     \
+    "   " #op "   $5,    5 * 4(" #reg ") \n"     \
+    "   " #op "   $6,    6 * 4(" #reg ") \n"     \
+    "   " #op "   $7,    7 * 4(" #reg ") \n"
+
 asm(
         ".section        .excep,\"ax\",@progbits         \n"
 
         ".set push                                       \n"
         ".set noreorder                                  \n"
         "   b       1f                                   \n"
-# if __mips >= 32
+#if __mips >= 32
         ".space 0x17c                                    \n"
 #else
         ".space 0x7c                                     \n"
 #endif
         ".set pop                                        \n"
 
-        ".globl mips_interrupt_entry                     \n"
-        ".func mips_interrupt_entry                      \n"
-        ".type mips_interrupt_entry, %function           \n"
-        "mips_interrupt_entry:                           \n"
+        FUNC_START(mips_interrupt_entry)
         ".set push                                       \n"
         ".set noat                                       \n"
 
@@ -43,108 +107,102 @@
 
         /* restore cpu local storage */
 #if defined(CONFIG_CPU_USER)
-# if defined(CONFIG_SMP)
 
-#  if __mips >= 32
-        "   mfc0    $26,    $15,    1                    \n"
-#  else
-        "   mfc0    $26,    $15                          \n"
-#  endif
-
-        "   andi    $26,    $26,    0x3ff                \n"
-        "   sll     $26,    $26,    2                    \n"
-        "   lw      $27,    cpu_local_storage($26)       \n"
-# endif
-
         /* event from user mode ? */
         "   mfc0    $26,    $12                          \n"
-        "   andi    $26,    $26,    0x8                  \n"
+        "   andi    $26,    $26,  " STATUS_UM_BIT "      \n"
 
         ".set noreorder                                  \n"
-        "   blez    $26,    1f                           \n"
+        /* zero if from Kernel mode */
+        "   beqz    $26,    1f                           \n"
+        /* abuse the delay slot to get the current SP (sp_user_kernel) */
         "   move    $26,    $sp                          \n"
         ".set reorder                                    \n"
 
+# if defined(CONFIG_SMP)
+        /* Restore CLS if we are from user mode */
+        CPU_ID($26)
+        "   sll     $26,    $26,    2                    \n"
+        "   lw      $27,    cpu_local_storage($26)       \n"
+# endif
+
+        /* Get user's SP (sp_user_user) */
+        "   move    $26,    $sp                          \n"
+
         /* restore kernel stack ! */
-# ifdef CONFIG_SMP
-        "   lw      $sp,    __context_data_base($27) \n"
-# else
-        "   lw      $sp,    __context_data_base      \n"
-# endif
-        "   addiu   $sp,    %lo(context_kstack)          \n"
-        "   lw      $sp,    ($sp)                        \n"
+        CPU_LOCAL_GET($sp, __context_data_base)
+        "   lw      $sp,    %lo(context_kstack)($sp)     \n"
+        "1:                                              \n"
 #else  /* !defined(CONFIG_CPU_USER) */
+        /* Get current SP (sp_user_none) */
         "   move    $26,    $sp                          \n"
 #endif
 
-        /* save registers usefull to syscall */
-        "1:                                              \n"
-        "   addu    $sp,    -4*32                        \n"
+        /*
+          Either:
+          * We are not handling user mode and $26 is last known sp (sp_user_none)
+          * We are handling user mode
+           * From user mode, $26 is user's sp (sp_user_user)
+           * From kernel mode, $26 is last known sp (sp_user_kernel)
+         */
+
+        /* save registers useful to syscall */
 #if defined(CONFIG_LIBELF_RTLD_TLS)
         /* add room for hwrena and tls registers */
-        "   addu    $sp,    -4*2                         \n"
+        "   addu    $sp,    -4*35                        \n"
+#else
+        "   addu    $sp,    -4*33                        \n"
 #endif
         "   sw      $26,    29*4($sp)                    \n"
 
-        "   sw      $4,     4*4($sp)                     \n" /* Args regs */
-        "   sw      $5,     5*4($sp)                     \n" /* Args regs */
-        "   sw      $6,     6*4($sp)                     \n" /* Args regs */
-        "   sw      $7,     7*4($sp)                     \n" /* Args regs */
+        DO_ARG_REGS(sw, $sp)
 
-        "   sw      $31,    31*4($sp)                    \n" /* Return address regs */
-
         /* read and extract cause */
         "   mfc0    $4,     $13                          \n"
         "   andi    $6,     $4,     0x3c                 \n"
 
-        /* read & save EPC */
-        "   mfc0    $5,     $14                          \n"
-        "   sw      $5,     0*4($sp)                     \n"
+        "   mfc0    $5,     $12                          \n"
+        "   sb      $5,     32*4($sp)                    \n"
+        /* Let's say we are in kernel mode, no exception, no irq */
+# if __mips >= 32
+        "   ori     $5,     $5,     0x1f                 \n"
+        "   xori    $5,     $5,     0x1f                 \n"
+# else
+#  error Implement me
+# endif
+        "   mtc0    $5,     $12                          \n"
 
 #if defined(CONFIG_LIBELF_RTLD_TLS)
         /* read & save hwrena */
         "   mfc0    $7,     $7                           \n"
-        "   sw      $7,     32*4($sp)                    \n"
+        "   sw      $7,     33*4($sp)                    \n"
         /* read & save tls */
         "   mfc0    $7,     $4, 2                        \n"
-        "   sw      $7,     33*4($sp)                    \n"
+        "   sw      $7,     34*4($sp)                    \n"
 #endif
 
+#if defined(CONFIG_CPU_USER)
+        /* increment the user-mode counter */
+        CPU_LOCAL_GET($5, __context_data_base)
+        "   lw      $7,     %lo(usermode_counter)($5)    \n"
+        "   addui   $7,     $7, 1                        \n"
+        "   sw      $7,     %lo(usermode_counter)($5)    \n"
+#endif
+
         "   li      $7,     32                           \n"
         "   beq     $6,     $7,     interrupt_sys        \n"
 
         /* save extra registers for hw interrupts and exceptions only */
 
-        "   sw      $1,     1*4($sp)                     \n" /* AT reg */
+        DO_AT_REG(sw, $sp)
+        DO_RVAL_REGS(sw, $sp)
+        DO_TEMP_REGS(sw, $sp)
+        DO_CALLEE_SAVED(sw, $sp)
 
-        "   sw      $2,     2*4($sp)                     \n" /* Return value regs */
-        "   sw      $3,     3*4($sp)                     \n" /* Return value regs */
+        /* read & save EPC */
+        "   mfc0    $5,     $14                          \n"
+        "   sw      $5,     0*4($sp)                     \n"
 
-        "   sw      $8,     8*4($sp)                     \n" /* Temp regs */
-        "   sw      $9,     9*4($sp)                     \n" /* Temp regs */
-        "   sw      $10,    10*4($sp)                    \n" /* Temp regs */
-        "   sw      $11,    11*4($sp)                    \n" /* Temp regs */
-        "   sw      $12,    12*4($sp)                    \n" /* Temp regs */
-        "   sw      $13,    13*4($sp)                    \n" /* Temp regs */
-        "   sw      $14,    14*4($sp)                    \n" /* Temp regs */
-        "   sw      $15,    15*4($sp)                    \n" /* Temp regs */
-
-        "   sw      $16,    16*4($sp)                    \n" /* Callee saved */
-        "   sw      $17,    17*4($sp)                    \n" /* Callee saved */
-        "   sw      $18,    18*4($sp)                    \n" /* Callee saved */
-        "   sw      $19,    19*4($sp)                    \n" /* Callee saved */
-        "   sw      $20,    20*4($sp)                    \n" /* Callee saved */
-        "   sw      $21,    21*4($sp)                    \n" /* Callee saved */
-        "   sw      $22,    22*4($sp)                    \n" /* Callee saved */
-        "   sw      $23,    23*4($sp)                    \n" /* Callee saved */
-
-        "   sw      $30,    30*4($sp)                    \n" /* Callee saved */
-
-        "   sw      $24,    24*4($sp)                    \n" /* Temp regs */
-        "   sw      $25,    25*4($sp)                    \n" /* Temp regs */
-
-        "   sw      $28,    28*4($sp)                    \n" /* Save user GP */
-
         "   beq     $6,     $0,     interrupt_hw         \n"
 
         /*************************************************************
@@ -161,11 +219,7 @@
 
         "   addiu   $sp,    $sp,    -5*4                 \n"
         "   sw      $26,    4*4($sp)                     \n"
-#ifdef CONFIG_SMP
-        "   lw      $1,     cpu_exception_handler($27)   \n"
-#else
-        "   lw      $1,     cpu_exception_handler        \n"
-#endif
+        CPU_LOCAL_GET($1, cpu_exception_handler)
         "   jalr    $1                                   \n"
         "   addiu   $sp,    $sp,    5*4                  \n"
 
@@ -181,11 +235,7 @@
         "   move    $4,     $0                           \n" /* single trap on mips: id = 0 */
         "   addiu   $5,     $sp,    0                    \n" /* register table on stack */
         "   addiu   $sp,    $sp,    -4*4                 \n"
-#ifdef CONFIG_SMP
-        "   lw      $11,    __context_data_base($27) \n"
-#else
-        "   lw      $11,    __context_data_base      \n"
-#endif
+        CPU_LOCAL_GET($31, __context_data_base)
         "   lw      $1,     cpu_syscall_handler($11)     \n"
         "   jalr    $1                                   \n"
         "   addiu   $sp,    $sp,    4*4                  \n"
@@ -208,13 +258,8 @@
         "   andi    $5,     $5,     0xff                 \n"
 
         "   addiu   $sp,    $sp,    -4*4                 \n"
-#ifdef CONFIG_SMP
-        "   lw      $1,     cpu_interrupt_handler($27)   \n"
-        "   lw      $4,     cpu_interrupt_handler_arg($27)\n"
-#else
-        "   lw      $1,     cpu_interrupt_handler        \n"
-        "   lw      $4,     cpu_interrupt_handler_arg    \n"
-#endif
+        CPU_LOCAL_GET($1, cpu_interrupt_handler)
+        CPU_LOCAL_GET($4, cpu_interrupt_handler_arg)
         "   jalr    $1                                   \n"
         "   addiu   $sp,    $sp,    4*4                  \n"
 
@@ -225,52 +270,32 @@
         /* restore registers */
         "return:                                         \n"
 
-        "   lw      $1,     1*4($sp)                     \n"
+        DO_AT_REG(lw, $sp)
+        DO_ARG_REGS(lw, $sp)
+        DO_TEMP_REGS(lw, $sp)
 
-        "   lw      $4,     4*4($sp)                     \n"
-        "   lw      $5,     5*4($sp)                     \n"
-        "   lw      $6,     6*4($sp)                     \n"
-        "   lw      $7,     7*4($sp)                     \n"
+        "return_val:                                     \n"
 
-        "   lw      $8,     8*4($sp)                     \n"
-        "   lw      $9,     9*4($sp)                     \n"
-        "   lw      $10,    10*4($sp)                    \n"
-        "   lw      $11,    11*4($sp)                    \n"
-        "   lw      $12,    12*4($sp)                    \n"
-        "   lw      $13,    13*4($sp)                    \n"
-        "   lw      $14,    14*4($sp)                    \n"
-        "   lw      $15,    15*4($sp)                    \n"
+        DO_RVAL_REGS(lw, $sp)
 
-        "   lw      $16,    16*4($sp)                    \n"
-        "   lw      $17,    17*4($sp)                    \n"
-        "   lw      $18,    18*4($sp)                    \n"
-        "   lw      $19,    19*4($sp)                    \n"
-        "   lw      $20,    20*4($sp)                    \n"
-        "   lw      $21,    21*4($sp)                    \n"
-        "   lw      $22,    22*4($sp)                    \n"
-        "   lw      $23,    23*4($sp)                    \n"
+        /* reload lower byte of status */
+        "   lbu     $28,    32*4($sp)                    \n"
+        "   mfc0    $31,    $12                          \n"
+        "   ori     $31,    $31,    0xff                 \n"
+        "   xori    $31,    $31,    0xff                 \n"
+        "   or      $31,    $31,    $28                  \n"
+        "   mtc0    $31,    $12                          \n"
 
-        "   lw      $30,    30*4($sp)                    \n"
-
-        "   lw      $24,    24*4($sp)                    \n"
-        "   lw      $25,    25*4($sp)                    \n"
-
-        "return_val:                                     \n"
-
-        "   lw      $2,     2*4($sp)                     \n" /* Syscall return value */
-        "   lw      $3,     3*4($sp)                     \n" /* Syscall return value */
-
 #if defined(CONFIG_LIBELF_RTLD_TLS)
         /* reload hwrena */
-        "   lw      $31,    32*4($sp)                    \n"
+        "   lw      $31,    33*4($sp)                    \n"
         "   mtc0    $31,    $7                           \n"
         /* reload tls */
-        "   lw      $31,    33*4($sp)                    \n"
+        "   lw      $31,    34*4($sp)                    \n"
         "   mtc0    $31,    $4, 2                        \n"
 #endif
 
-        "   lw      $28,    28*4($sp)                    \n" /* restore user GP */
-        "   lw      $31,    31*4($sp)                    \n" /* restore return address */
+        DO_CALLEE_SAVED(lw, $sp)
 
         "   lw      $sp,    29*4($sp)                    \n" /* restore user stack */
 
@@ -285,8 +310,7 @@
 # endif
 
         ".set pop                                        \n"
-		".endfunc                                        \n"
-        ".size mips_interrupt_entry, .-mips_interrupt_entry \n"
+        FUNC_END(mips_interrupt_entry)
         );
 
         // Local Variables:
Index: cpu/mips/boot.c
===================================================================
--- cpu/mips/boot.c	(revision 1308)
+++ cpu/mips/boot.c	(working copy)
@@ -19,6 +19,8 @@
 
 */
 
+#include <hexo/asm.h>
+
 #ifdef CONFIG_SOCLIB_MEMCHECK
 # include <arch/mem_checker.h>
 #endif
@@ -26,10 +28,7 @@
 asm(
         ".section        .boot,\"ax\",@progbits                                            \n"
 
-        ".globl cpu_boot                                                                   \n"
-        ".func cpu_boot				    \n\t"
-        ".type   cpu_boot, %function    \n\t"
-        "cpu_boot:                                                                         \n"
+        FUNC_START(cpu_boot)
 
         ".set push                                                                         \n"
         ".set noreorder                                                                    \n"
@@ -122,8 +121,7 @@
 #endif
 
         ".set pop                                                                          \n"
-	".size   cpu_boot, .-cpu_boot   \n\t"
-	".endfunc \n\t"
+        FUNC_END(cpu_boot)
 );
 
 // Local Variables:
Index: cpu/mips/cpu_context.c
===================================================================
--- cpu/mips/cpu_context.c	(revision 1308)
+++ cpu/mips/cpu_context.c	(working copy)
@@ -7,10 +7,6 @@
 # include <arch/mem_checker.h>
 #endif
 
-#if defined(CONFIG_CPU_USER)
-CONTEXT_LOCAL uintptr_t context_kstack;
-#endif
-
 error_t
 cpu_context_bootstrap(struct context_s *context)
 {
