diff -uNr linux-2.6.8-rc1-eb1/arch/ppc/Kconfig linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/Kconfig
--- linux-2.6.8-rc1-eb1/arch/ppc/Kconfig	Wed Jul 14 19:27:52 2004
+++ linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/Kconfig	Wed Jul 14 19:55:29 2004
@@ -1243,6 +1243,26 @@
 	depends on SERIAL_SICC && UART0_TTYS1
 	default y
 
+config KEXEC
+	bool "kexec system call (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  kexec is a system call that implements the ability to shutdown your
+	  current kernel, and to start another kernel.  It is like a reboot
+	  but it is indepedent of the system firmware.   And like a reboot
+	  you can start any kernel with it, not just Linux.
+	  
+	  The name comes from the similiarity to the exec system call.
+	  
+	  It is an ongoing process to be certain the hardware in a machine
+	  is properly shutdown, so do not be surprised if this code does not
+	  initially work for you.  It may help to enable device hotplugging
+	  support.  As of this writing the exact hardware interface is
+	  strongly in flux, so no good recommendation can be made.
+	  
+	  In the GAMECUBE implementation, kexec allows you to load and
+	  run DOL files, including kernel and homebrew DOLs.
+
 endmenu
 
 source "lib/Kconfig"
diff -uNr linux-2.6.8-rc1-eb1/arch/ppc/boot/simple/relocate.S linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/boot/simple/relocate.S
--- linux-2.6.8-rc1-eb1/arch/ppc/boot/simple/relocate.S	Tue Jun 15 23:19:17 2004
+++ linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/boot/simple/relocate.S	Wed Jul 14 19:55:29 2004
@@ -18,6 +18,7 @@
 #include <linux/config.h>
 #include <asm/cache.h>
 #include <asm/ppc_asm.h>
+#include <asm/kexec.h>
 
 #define GETSYM(reg, sym)	\
 	lis	reg, sym@h; ori	reg, reg, sym@l
@@ -174,6 +175,26 @@
 	subi	r1,r1,256
 	li	r2,0x000F	/* Mask pointer to 16-byte boundary */
 	andc	r1,r1,r2
+
+#if defined(CONFIG_KEXEC) && defined(CONFIG_GAMECUBE)
+
+/* Save DolphinOS state, including perhaps Costis psoload reloader,  */
+/* to a temporary location (we will save it later to a safer place) */
+
+	lis	r4, KEXEC_GC_SAVED_STATE_FROM@ha
+	ori	r4, r4, KEXEC_GC_SAVED_STATE_FROM@l
+	lis	r5, KEXEC_GC_SAVED_STATE_TEMP_TO@ha
+	ori	r5, r5, KEXEC_GC_SAVED_STATE_TEMP_TO@l
+	li	r3, KEXEC_GC_SAVED_STATE_SIZE / 4
+	mtctr	r3
+	subi	r4, r4, 4
+	subi	r5, r5, 4
+9:	lwzu	r3, 4(r4)
+	stwu	r3, 4(r5)
+	dcbf	0, r5
+	bdnz	9b
+
+#endif /* CONFIG_KEXEC && CONFIG_GAMECUBE */
 
 	/*
 	 * Exec kernel loader
diff -uNr linux-2.6.8-rc1-eb1/arch/ppc/kernel/Makefile linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/kernel/Makefile
--- linux-2.6.8-rc1-eb1/arch/ppc/kernel/Makefile	Wed Jul 14 19:27:52 2004
+++ linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/kernel/Makefile	Wed Jul 14 19:55:29 2004
@@ -34,6 +34,7 @@
 obj-$(CONFIG_SMP)		+= smp.o smp-tbsync.o
 obj-$(CONFIG_TAU)		+= temp.o
 obj-$(CONFIG_ALTIVEC)		+= vecemu.o vector.o
+obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 
 ifdef CONFIG_MATH_EMULATION
 obj-$(CONFIG_8xx)		+= softemu8xx.o
diff -uNr linux-2.6.8-rc1-eb1/arch/ppc/kernel/machine_kexec.c linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/kernel/machine_kexec.c
--- linux-2.6.8-rc1-eb1/arch/ppc/kernel/machine_kexec.c	Wed Dec 31 17:00:00 1969
+++ linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/kernel/machine_kexec.c	Wed Jul 14 19:55:29 2004
@@ -0,0 +1,69 @@
+/*
+ * machine_kexec.c - handle transition of Linux booting another kernel
+ * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
+ *
+ * GAMECUBE/PPC32 port Copyright (C) 2004 Albert Herranz
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/hw_irq.h>
+#include <asm/cacheflush.h>
+
+#ifdef CONFIG_GAMECUBE
+u32 kexec_gc_saved_state[KEXEC_GC_SAVED_STATE_SIZE/sizeof(u32)] = { 
+	0xDEADC0DE
+};
+#endif /* CONFIG_GAMECUBE */
+
+typedef void (*relocate_new_kernel_t)(
+	unsigned long indirection_page, unsigned long reboot_code_buffer,
+	unsigned long start_address);
+
+const extern unsigned char relocate_new_kernel[];
+const extern unsigned int relocate_new_kernel_size;
+extern void use_mm(struct mm_struct *mm);
+
+/*
+ * Do not allocate memory (or fail in any way) in machine_kexec().
+ * We are past the point of no return, committed to rebooting now. 
+ */
+void machine_kexec(struct kimage *image)
+{
+	unsigned long indirection_page;
+	unsigned long reboot_code_buffer;
+	relocate_new_kernel_t rnk;
+
+	/* switch to an mm where the reboot_code_buffer is identity mapped */
+	use_mm(&init_mm);
+
+	/* Interrupts aren't acceptable while we reboot */
+	local_irq_disable();
+
+	reboot_code_buffer = page_to_pfn(image->reboot_code_pages) <<PAGE_SHIFT;
+	indirection_page = image->head & PAGE_MASK;
+
+	/* copy it out */
+	memcpy((void *)reboot_code_buffer, 
+		relocate_new_kernel, relocate_new_kernel_size);
+
+#ifdef CONFIG_GAMECUBE
+	memcpy((void *)reboot_code_buffer + relocate_new_kernel_size,
+		kexec_gc_saved_state, KEXEC_GC_SAVED_STATE_SIZE);
+#endif /* CONFIG_GAMECUBE */
+
+	flush_icache_range(reboot_code_buffer, reboot_code_buffer + KEXEC_REBOOT_CODE_SIZE);
+
+	printk(KERN_INFO "Bye!\n");
+	/* now call it */
+	rnk = (relocate_new_kernel_t) reboot_code_buffer;
+	(*rnk)(indirection_page, reboot_code_buffer, image->start);
+}
diff -uNr linux-2.6.8-rc1-eb1/arch/ppc/kernel/misc.S linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/kernel/misc.S
--- linux-2.6.8-rc1-eb1/arch/ppc/kernel/misc.S	Wed Jul 14 19:27:52 2004
+++ linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/kernel/misc.S	Wed Jul 14 19:55:29 2004
@@ -1449,4 +1449,4 @@
 	.long sys_mq_timedreceive	/* 265 */
 	.long sys_mq_notify
 	.long sys_mq_getsetattr
-	.long sys_ni_syscall		/* 268 reserved for sys_kexec_load */
+	.long sys_kexec_load		/* 268 reserved for sys_kexec_load */
diff -uNr linux-2.6.8-rc1-eb1/arch/ppc/kernel/relocate_kernel.S linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/kernel/relocate_kernel.S
--- linux-2.6.8-rc1-eb1/arch/ppc/kernel/relocate_kernel.S	Wed Dec 31 17:00:00 1969
+++ linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/kernel/relocate_kernel.S	Wed Jul 14 19:55:29 2004
@@ -0,0 +1,152 @@
+/*
+ * relocate_kernel.S - put the kernel image in place to boot
+ * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
+ *
+ * GAMECUBE/PPC32 port Copyright (C) 2004 Albert Herranz
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+#include <asm/kexec.h>
+                                                                                
+#define PAGE_SIZE      4096 /* must be same value as in <asm/page.h> */
+
+/* returns  r3 = relocated address of sym */
+/* modifies r0 */
+#define RELOC_SYM(sym) \
+	mflr	r3; \
+	bl	1f; \
+1:	mflr	r0; \
+	mtlr	r3; \
+	lis	r3, 1b@ha; \
+	ori	r3, r3, 1b@l; \
+	subf	r0, r3, r0; \
+	lis	r3, sym@ha; \
+	ori	r3, r3, sym@l; \
+	add	r3, r3, r0
+
+	/*
+	 * Must be relocatable PIC code callable as a C function.
+	 */
+	.globl relocate_new_kernel
+relocate_new_kernel:
+	/* r3 = indirection_page   */
+	/* r4 = reboot_code_buffer */
+	/* r5 = start_address      */
+
+	li	r0, 0
+
+	/* Set Machine Status Register to a known status */
+	mr	r8, r0
+	ori     r8, r8, MSR_RI|MSR_ME
+	mtmsr	r8
+	isync
+
+	/* from this point address translation is turned off */
+	/* and interrupts are disabled */
+
+	/* set a new stack at the bottom of our page... */
+	/* (not really needed now) */
+	addi	r1, r4, KEXEC_REBOOT_CODE_SIZE - 8 /* for LR Save+Back Chain */
+	stw	r0, 0(r1)
+
+	/* Do the copies */
+	li	r6, 0 /* checksum */
+	subi	r3, r3, 4
+
+0:	/* top, read another word for the indirection page */
+	lwzu	r0, 4(r3)
+
+	/* is it a destination page? (r8) */
+	rlwinm.	r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
+	beq	1f
+ 
+	rlwinm	r8, r0, 0, 0, 19 /* clear kexec flags, page align */
+	b	0b
+
+1:	/* is it an indirection page? (r3) */
+	rlwinm.	r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
+	beq	1f
+
+	rlwinm	r3, r0, 0, 0, 19 /* clear kexec flags, page align */
+	subi	r3, r3, 4
+	b	0b
+
+1:	/* are we done? */
+	rlwinm.	r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
+	beq	1f
+	b	2f
+
+1:	/* is it a source page? (r9) */
+	rlwinm.	r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
+	beq	0b
+
+	rlwinm	r9, r0, 0, 0, 19 /* clear kexec flags, page align */
+
+	li	r7, PAGE_SIZE / 4
+	mtctr   r7
+	subi    r9, r9, 4
+	subi    r8, r8, 4
+9:
+	lwzu    r0, 4(r9)  /* do the copy */
+	xor	r6, r6, r0
+	stwu    r0, 4(r8)
+	dcbst	0, r8
+	sync
+	icbi	0, r8
+	bdnz    9b
+
+	addi    r9, r9, 4
+	addi    r8, r8, 4
+	b	0b
+
+2:
+
+#ifdef CONFIG_GAMECUBE
+
+	/* Copy back saved state to original location. */
+
+	li      r3, KEXEC_GC_SAVED_STATE_SIZE / 4
+	mtctr   r3
+	RELOC_SYM(kexec_gc_saved_state_temporary_buffer)
+	mr	r9, r3
+	lis	r8, KEXEC_GC_SAVED_STATE_FROM@ha /* in fact, it is TO now ;) */
+	oris	r8, r8, KEXEC_GC_SAVED_STATE_FROM@l
+	subi    r9, r9, 4
+	subi    r8, r8, 4
+9:	lwzu    r3, 4(r9)
+	stwu    r3, 4(r8)
+	dcbst   0, r8
+	sync
+	icbi    0, r8
+	bdnz    9b
+
+#endif /* CONFIG_GAMECUBE */
+
+	/* To be certain of avoiding problems with self-modifying code
+	 * execute a serializing instruction here.
+	 */
+	isync
+	sync
+
+	/* jump to the entry point, usually the setup routine */
+	mtlr	r5
+	blrl
+
+1:	b	1b
+
+relocate_new_kernel_end:
+
+#ifdef CONFIG_GAMECUBE
+kexec_gc_saved_state_temporary_buffer:
+#endif
+
+	.globl relocate_new_kernel_size
+relocate_new_kernel_size:	
+	.long relocate_new_kernel_end - relocate_new_kernel
+
diff -uNr linux-2.6.8-rc1-eb1/arch/ppc/kernel/setup.c linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/kernel/setup.c
--- linux-2.6.8-rc1-eb1/arch/ppc/kernel/setup.c	Wed Jul 14 19:27:52 2004
+++ linux-2.6.8-rc1-ppc-gc-kexec/arch/ppc/kernel/setup.c	Wed Jul 14 20:07:16 2004
@@ -17,6 +17,7 @@
 #include <linux/root_dev.h>
 #include <linux/cpu.h>
 #include <linux/console.h>
+#include <linux/kexec.h>
 
 #include <asm/residual.h>
 #include <asm/io.h>
@@ -291,6 +292,12 @@
 	/* First zero the BSS -- use memset, some arches don't have
 	 * caches on yet */
 	memset_io(PTRRELOC(&__bss_start), 0, _end - __bss_start);
+
+#if defined(CONFIG_KEXEC) && defined(CONFIG_GAMECUBE)
+	memcpy(PTRRELOC(&kexec_gc_saved_state[0]),
+		(void *)KEXEC_GC_SAVED_STATE_TEMP_TO,
+		KEXEC_GC_SAVED_STATE_SIZE);
+#endif /* CONFIG_KEXEC && CONFIG_GAMECUBE */
 
 	/*
 	 * Identify the CPU type and fix up code sections
diff -uNr linux-2.6.8-rc1-eb1/include/asm-ppc/kexec.h linux-2.6.8-rc1-ppc-gc-kexec/include/asm-ppc/kexec.h
--- linux-2.6.8-rc1-eb1/include/asm-ppc/kexec.h	Wed Dec 31 17:00:00 1969
+++ linux-2.6.8-rc1-ppc-gc-kexec/include/asm-ppc/kexec.h	Wed Jul 14 20:05:44 2004
@@ -0,0 +1,37 @@
+#ifndef _PPC_KEXEC_H
+#define _PPC_KEXEC_H
+
+#ifdef CONFIG_KEXEC
+/*
+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
+ * I.e. Maximum page that is mapped directly into kernel memory,
+ * and kmap is not required.
+ *
+ * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct
+ * calculation for the amount of memory directly mappable into the
+ * kernel memory space.
+ */
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+
+#define KEXEC_REBOOT_CODE_SIZE	4096
+
+#ifdef CONFIG_GAMECUBE
+
+#define KEXEC_GC_SAVED_STATE_FROM	(0x00000000)
+#define KEXEC_GC_SAVED_STATE_TEMP_TO	(0x00f00000)
+#define KEXEC_GC_SAVED_STATE_SIZE	(3*4096) /* bytes */
+
+#undef  KEXEC_REBOOT_CODE_SIZE
+#define KEXEC_REBOOT_CODE_SIZE		(4096+KEXEC_GC_SAVED_STATE_SIZE)
+
+extern u32 kexec_gc_saved_state[];
+
+#endif /* CONFIG_GAMECUBE */
+
+#endif /* CONFIG_KEXEC */
+
+#endif /* _PPC_KEXEC_H */
