Add basic relocation to i386 port

Signed-off-by: Graeme Russ <graeme.russ@gmail.com>
diff --git a/cpu/i386/interrupts.c b/cpu/i386/interrupts.c
index 026a21b..063ea42 100644
--- a/cpu/i386/interrupts.c
+++ b/cpu/i386/interrupts.c
@@ -53,8 +53,8 @@
 
 void set_vector(u8 intnum, void *routine)
 {
-	idt[intnum].base_high = (u16)((u32)(routine)>>16);
-	idt[intnum].base_low = (u16)((u32)(routine)&0xffff);
+	idt[intnum].base_high = (u16)((u32)(routine + gd->reloc_off) >> 16);
+	idt[intnum].base_low = (u16)((u32)(routine + gd->reloc_off) & 0xffff);
 }
 
 
diff --git a/cpu/i386/start.S b/cpu/i386/start.S
index b6175b1..59089ef 100644
--- a/cpu/i386/start.S
+++ b/cpu/i386/start.S
@@ -173,7 +173,41 @@
 	jmp	die
 
 bss_ok:
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+	/* indicate progress */
+	movw	$0x06, %ax
+	movl	$.progress6, %ebp
+	jmp	show_boot_progress_asm
+.progress6:
 
+	/* copy text section to ram, size must be 4-byte aligned */
+	movl	$CONFIG_SYS_BL_START_RAM, %edi		/* destination address */
+	movl	$TEXT_BASE, %esi		/* source address */
+	movl	$_i386boot_text_size, %ecx	/* number of bytes to copy */
+	movl	%ecx, %eax
+	andl	$3, %eax
+	jz	text_copy			/* Already 4-byte aligned */
+	subl    $4, %eax			/* Add extra bytes to size */
+	addl	%eax, %ecx
+text_copy:
+	shrl	$2, %ecx			/* copy 4 byte each time */
+	cld
+	cmpl	$0, %ecx
+	je	text_ok
+text_segment:
+	movsl
+	loop	text_segment
+	jmp	text_ok
+text_fail:
+	/* indicate (lack of) progress */
+	movw	$0x86, %ax
+	movl	$.progress5a, %ebp
+	jmp	show_boot_progress_asm
+.progress5a:
+	jmp	die
+
+text_ok:
+#endif
 	wbinvd
 
 
@@ -183,7 +217,14 @@
 	jmp	show_boot_progress_asm
 .progress4:
 
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+	/* Jump to the RAM copy of start_i386boot */
+	movl	$start_i386boot, %ebp
+	addl	$(CONFIG_SYS_BL_START_RAM - TEXT_BASE), %ebp
+	call	*%ebp		/* Enter, U-boot! */
+#else
 	call	start_i386boot  /* Enter, U-boot! */
+#endif
 
 	/* indicate (lack of) progress */
 	movw	$0x85, %ax
diff --git a/include/configs/sc520_cdp.h b/include/configs/sc520_cdp.h
index 19e5889..82faca8 100644
--- a/include/configs/sc520_cdp.h
+++ b/include/configs/sc520_cdp.h
@@ -28,6 +28,8 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
+#define CONFIG_SKIP_RELOCATE_UBOOT
+
 #define GRUSS_TESTING
 /*
  * High Level Configuration Options
diff --git a/include/configs/sc520_spunk.h b/include/configs/sc520_spunk.h
index 20481bd..3644169 100644
--- a/include/configs/sc520_spunk.h
+++ b/include/configs/sc520_spunk.h
@@ -28,6 +28,8 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
+#define CONFIG_SKIP_RELOCATE_UBOOT
+
 /*
  * High Level Configuration Options
  * (easy to change)
diff --git a/lib_i386/board.c b/lib_i386/board.c
index 29683ee..e18dfa5 100644
--- a/lib_i386/board.c
+++ b/lib_i386/board.c
@@ -225,6 +225,9 @@
 	static bd_t bd_data;
 	init_fnc_t **init_fnc_ptr;
 
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+	cmd_tbl_t *p;
+#endif
 	show_boot_progress(0x21);
 
 	gd = &gd_data;
@@ -238,6 +241,10 @@
 
 	gd->baudrate =  CONFIG_BAUDRATE;
 
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+	/* Need to set relocation offset here for interrupt initialization */
+	gd->reloc_off =  CONFIG_SYS_BL_START_RAM - TEXT_BASE;
+#endif
 	for (init_fnc_ptr = init_sequence, i=0; *init_fnc_ptr; ++init_fnc_ptr, i++) {
 		show_boot_progress(0xa130|i);
 
@@ -247,6 +254,26 @@
 	}
 	show_boot_progress(0x23);
 
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+	for (p = &__u_boot_cmd_start; p != &__u_boot_cmd_end; p++) {
+		ulong addr;
+		addr = (ulong) (p->cmd) + gd->reloc_off;
+		p->cmd = (int (*)(struct cmd_tbl_s *, int, int, char *[]))addr;
+		addr = (ulong)(p->name) + gd->reloc_off;
+		p->name = (char *)addr;
+
+		if (p->usage != NULL) {
+			addr = (ulong)(p->usage) + gd->reloc_off;
+			p->usage = (char *)addr;
+		}
+	#ifdef	CONFIG_SYS_LONGHELP
+		if (p->help != NULL) {
+			addr = (ulong)(p->help) + gd->reloc_off;
+			p->help = (char *)addr;
+		}
+	#endif
+	}
+#endif
 	/* configure available FLASH banks */
 	size = flash_init();
 	display_flash_config(size);
diff --git a/lib_i386/interrupts.c b/lib_i386/interrupts.c
index b0f84de..3f3613a 100644
--- a/lib_i386/interrupts.c
+++ b/lib_i386/interrupts.c
@@ -70,12 +70,12 @@
 
 	if (irq_handlers[irq].handler != NULL)
 		printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
-		       (ulong) handler,
+		       (ulong) handler + gd->reloc_off,
 		       (ulong) irq_handlers[irq].handler);
 
 	status = disable_interrupts ();
 
-	irq_handlers[irq].handler = handler;
+	irq_handlers[irq].handler = handler + gd->reloc_off;
 	irq_handlers[irq].arg = arg;
 	irq_handlers[irq].count = 0;
 
diff --git a/lib_i386/timer.c b/lib_i386/timer.c
index 5cb1f54..58a0212 100644
--- a/lib_i386/timer.c
+++ b/lib_i386/timer.c
@@ -51,7 +51,7 @@
 	if (new_func == NULL)
 		return 1;
 
-	new_func->isr_func = isr_func;
+	new_func->isr_func = isr_func + gd->reloc_off;
 	new_func->next = NULL;
 
 	/*