diff --git a/lib/powerpc/asm/hcall.h b/lib/powerpc/asm/hcall.h
index f6f9ea8..99bce79 100644
--- a/lib/powerpc/asm/hcall.h
+++ b/lib/powerpc/asm/hcall.h
@@ -20,6 +20,7 @@
 #define H_PAGE_INIT		0x2c
 #define H_PUT_TERM_CHAR		0x58
 #define H_RANDOM		0x300
+#define H_SET_MODE		0x31C
 
 #ifndef __ASSEMBLY__
 /*
diff --git a/lib/powerpc/asm/ppc_asm.h b/lib/powerpc/asm/ppc_asm.h
index f18100e..39620a3 100644
--- a/lib/powerpc/asm/ppc_asm.h
+++ b/lib/powerpc/asm/ppc_asm.h
@@ -1,6 +1,11 @@
 #ifndef _ASMPOWERPC_PPC_ASM_H
 #define _ASMPOWERPC_PPC_ASM_H
 
+#include <asm/asm-offsets.h>
+
+#define SAVE_GPR(n, base)	std	n,GPR0+8*(n)(base)
+#define REST_GPR(n, base)	ld	n,GPR0+8*(n)(base)
+
 #define LOAD_REG_IMMEDIATE(reg,expr)		\
 	lis	reg,(expr)@highest;		\
 	ori	reg,reg,(expr)@higher;		\
diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
new file mode 100644
index 0000000..09692bd
--- /dev/null
+++ b/lib/powerpc/asm/processor.h
@@ -0,0 +1,11 @@
+#ifndef _ASMPOWERPC_PROCESSOR_H_
+#define _ASMPOWERPC_PROCESSOR_H_
+
+#include <asm/ptrace.h>
+
+#ifndef __ASSEMBLY__
+void handle_exception(int trap, void (*func)(struct pt_regs *, void *), void *);
+void do_handle_exception(struct pt_regs *regs);
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASMPOWERPC_PROCESSOR_H_ */
diff --git a/lib/powerpc/processor.c b/lib/powerpc/processor.c
new file mode 100644
index 0000000..a78bc3c
--- /dev/null
+++ b/lib/powerpc/processor.c
@@ -0,0 +1,38 @@
+/*
+ * processor control and status function
+ */
+
+#include <libcflat.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+
+static struct {
+	void (*func)(struct pt_regs *, void *data);
+	void *data;
+} handlers[16];
+
+void handle_exception(int trap, void (*func)(struct pt_regs *, void *),
+		      void * data)
+{
+	trap >>= 8;
+
+	if (trap < 16) {
+		handlers[trap].func = func;
+		handlers[trap].data = data;
+	}
+}
+
+void do_handle_exception(struct pt_regs *regs)
+{
+	unsigned char v;
+
+	v = regs->trap >> 8;
+
+	if (v < 16 && handlers[v].func) {
+		handlers[v].func(regs, handlers[v].data);
+		return;
+	}
+
+	printf("unhandled cpu exception 0x%lx\n", regs->trap);
+	abort();
+}
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 0c0c882..e3cf952 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -16,6 +16,8 @@
 #include <alloc.h>
 #include <asm/setup.h>
 #include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/hcall.h>
 
 extern unsigned long stacktop;
 extern void io_init(void);
@@ -33,6 +35,10 @@ struct cpu_set_params {
 	unsigned dcache_bytes;
 };
 
+#define EXCEPTION_STACK_SIZE	(32*1024) /* 32kB */
+
+static char exception_stack[NR_CPUS][EXCEPTION_STACK_SIZE];
+
 static void cpu_set(int fdtnode, u32 regval, void *info)
 {
 	static bool read_common_info = false;
@@ -46,6 +52,11 @@ static void cpu_set(int fdtnode, u32 regval, void *info)
 	}
 	cpus[cpu] = regval;
 
+	/* set exception stack address for this CPU (in SPGR0) */
+
+	asm volatile ("mtsprg0 %[addr]" ::
+		      [addr] "r" (exception_stack[cpu + 1]));
+
 	if (!read_common_info) {
 		const struct fdt_property *prop;
 		u32 *data;
@@ -76,6 +87,14 @@ static void cpu_init(void)
 	assert(ret == 0);
 	__icache_bytes = params.icache_bytes;
 	__dcache_bytes = params.dcache_bytes;
+
+	/* Interrupt Endianness */
+
+#if  __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+        hcall(H_SET_MODE, 1, 4, 0, 0);
+#else
+        hcall(H_SET_MODE, 0, 4, 0, 0);
+#endif
 }
 
 static void mem_init(phys_addr_t freemem_start)
diff --git a/lib/ppc64/asm-offsets.c b/lib/ppc64/asm-offsets.c
index 2d38a71..7843a20 100644
--- a/lib/ppc64/asm-offsets.c
+++ b/lib/ppc64/asm-offsets.c
@@ -5,8 +5,50 @@
  */
 #include <libcflat.h>
 #include <kbuild.h>
+#include <asm/ptrace.h>
 
 int main(void)
 {
+	DEFINE(INT_FRAME_SIZE, STACK_INT_FRAME_SIZE);
+
+	DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
+	DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
+	DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
+	DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3]));
+	DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4]));
+	DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5]));
+	DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6]));
+	DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]));
+	DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]));
+	DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]));
+	DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10]));
+	DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11]));
+	DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12]));
+	DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13]));
+	DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14]));
+	DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15]));
+	DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16]));
+	DEFINE(GPR17, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[17]));
+	DEFINE(GPR18, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[18]));
+	DEFINE(GPR19, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[19]));
+	DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20]));
+	DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
+	DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
+	DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
+	DEFINE(GPR24, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[24]));
+	DEFINE(GPR25, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[25]));
+	DEFINE(GPR26, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[26]));
+	DEFINE(GPR27, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[27]));
+	DEFINE(GPR28, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[28]));
+	DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29]));
+	DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30]));
+	DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31]));
+	DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
+	DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr));
+	DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr));
+	DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link));
+	DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
+	DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr));
+	DEFINE(_TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
 	return 0;
 }
diff --git a/lib/ppc64/asm/processor.h b/lib/ppc64/asm/processor.h
new file mode 100644
index 0000000..066a51a
--- /dev/null
+++ b/lib/ppc64/asm/processor.h
@@ -0,0 +1 @@
+#include "../../powerpc/asm/processor.h"
diff --git a/lib/ppc64/asm/ptrace.h b/lib/ppc64/asm/ptrace.h
new file mode 100644
index 0000000..076c9d9
--- /dev/null
+++ b/lib/ppc64/asm/ptrace.h
@@ -0,0 +1,24 @@
+#ifndef _ASMPPC64_PTRACE_H_
+#define _ASMPPC64_PTRACE_H_
+
+#define KERNEL_REDZONE_SIZE	288
+#define STACK_FRAME_OVERHEAD    112     /* size of minimum stack frame */
+
+#ifndef __ASSEMBLY__
+struct pt_regs {
+	unsigned long gpr[32];
+	unsigned long nip;
+	unsigned long msr;
+	unsigned long ctr;
+	unsigned long link;
+	unsigned long xer;
+	unsigned long ccr;
+	unsigned long trap;
+};
+
+#define STACK_INT_FRAME_SIZE    (sizeof(struct pt_regs) + \
+				 STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASMPPC64_PTRACE_H_ */
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 424983e..ab2caf6 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -31,6 +31,7 @@ cflatobjs += lib/powerpc/io.o
 cflatobjs += lib/powerpc/hcall.o
 cflatobjs += lib/powerpc/setup.o
 cflatobjs += lib/powerpc/rtas.o
+cflatobjs += lib/powerpc/processor.o
 
 FLATLIBS = $(libcflat) $(LIBFDT_archive)
 %.elf: CFLAGS += $(arch_CFLAGS)
diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S
index c87e3d6..ceb6397 100644
--- a/powerpc/cstart64.S
+++ b/powerpc/cstart64.S
@@ -9,6 +9,7 @@
 #include <asm/hcall.h>
 #include <asm/ppc_asm.h>
 #include <asm/rtas.h>
+#include <asm/ptrace.h>
 
 .section .init
 
@@ -45,6 +46,34 @@ start:
 	add	r4, r4, r31
 	bl	relocate
 
+	/* relocate vector table to base address 0x0 (MSR_IP = 0) */
+
+	/* source: r4, dest end: r5, destination: r6 */
+
+	LOAD_REG_ADDR(r4, __start_interrupts)
+	LOAD_REG_ADDR(r5, __end_interrupts)
+	sub	r5,r5,r4
+	li	r6,0x100
+
+	sub	r4,r4,r6
+	add	r5,r5,r6
+	addi	r6,r6,-8
+2:	li	r0,8
+	mtctr	r0
+	/* copy a cache line size */
+3:	addi	r6,r6,8
+	ldx	r0,r6,r4
+	stdx	r0,0,r6
+	bdnz	3b
+	dcbst	0,r6
+	/* flush icache */
+	sync
+	icbi	0,r6
+	cmpld	0,r6,r5
+	blt	2b
+	sync
+	isync
+
 	/* patch sc1 if needed */
 	bl	hcall_have_broken_sc1
 	cmpwi	r3, 0
@@ -105,3 +134,114 @@ rtas_return_loc:
 	ld	r0, 16(r1)
 	mtlr	r0
 	blr
+
+call_handler:
+	/* save context */
+
+	/* GPRs */
+
+	.irp i, 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
+		SAVE_GPR(\i, r1)
+	.endr
+	mfsprg1	r0
+	std	r0,GPR1(r1)
+
+	/* lr, xer, ccr */
+
+	mflr	r0
+	std	r0,_LINK(r1)
+
+	mfxer	r0
+	std	r0,_XER(r1)
+
+	mfcr	r0
+	std	r0,_CCR(r1)
+
+	/* nip and msr */
+
+	mfsrr0	r0
+	std	r0, _NIP(r1)
+
+	mfsrr1	r0
+	std	r0, _MSR(r1)
+
+	/* FIXME: build stack frame */
+
+	/* call generic handler */
+
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	do_handle_exception
+
+	/* restore context */
+
+	ld	r0,_CTR(r1)
+	mtctr	r0
+
+	ld	r0,_LINK(r1)
+	mtlr	r0
+
+	ld	r0,_XER(r1)
+	mtxer	r0
+
+	ld	r0,_CCR(r1)
+	mtcr	r0
+
+	ld	r0, _NIP(r1)
+	mtsrr0	r0
+
+	ld	r0, _MSR(r1)
+	mtsrr1	r0
+
+	.irp i, 0, 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
+		REST_GPR(\i, r1)
+	.endr
+
+	/* restore r1, as we don't need it anymore */
+
+	REST_GPR(1,r1)
+
+	rfid
+	b .
+
+.section .text.ex
+
+.macro VECTOR vec
+	. = \vec
+
+	mtsprg1	r1	/* save r1 */
+	mfsprg0	r1	/* get exception stack address */
+	subi	r1,r1, INT_FRAME_SIZE
+
+	/* save r0 and ctr to call generic handler */
+
+	SAVE_GPR(0,r1)
+
+	mfctr	r0
+	std	r0,_CTR(r1)
+
+	LOAD_REG_ADDR(r0, call_handler)
+	mtctr	r0
+
+	li	r0,\vec
+	std	r0,_TRAP(r1)
+
+	bctr
+.endm
+
+	. = 0x100
+	.globl __start_interrupts
+__start_interrupts:
+
+VECTOR(0x300)
+VECTOR(0x400)
+VECTOR(0x500)
+VECTOR(0x600)
+VECTOR(0x700)
+VECTOR(0x800)
+VECTOR(0x900)
+
+	.align 7
+	.globl __end_interrupts
+__end_interrupts:
