[U-Boot] [PATCH 7/7] Add primitive relocation to i386 port

Graeme Russ graeme.russ at gmail.com
Tue Feb 24 11:14:56 CET 2009


Add basic relocation to i386 port

Signed-off-by: Graeme Russ <graeme.russ at gmail.com>
---
This patch provides relocation of the text (code) segment of the i386
binary (in addition to already relocated sections). However, as discussed
previously on the mailing list, the relocation does not fix up references
to read-only data which is still referenced into Flash. Full relocation is
likely going to require some in-depth knowledge of ELF and the very
mysterious 'Global Offset Table'

 cpu/i386/interrupts.c         |    4 ++--
 cpu/i386/start.S              |   41 +++++++++++++++++++++++++++++++++++++++++
 include/configs/sc520_cdp.h   |    2 ++
 include/configs/sc520_spunk.h |    2 ++
 lib_i386/board.c              |   27 +++++++++++++++++++++++++++
 lib_i386/interrupts.c         |    4 ++--
 lib_i386/timer.c              |    2 +-
 7 files changed, 77 insertions(+), 5 deletions(-)

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 @@ asm ("idt_ptr:\n"
 
 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 @@ bss_fail:
 	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 @@ bss_ok:
 	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 1734f86..e3d3f06 100644
--- a/lib_i386/board.c
+++ b/lib_i386/board.c
@@ -225,6 +225,9 @@ void start_i386boot (void)
 	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 @@ void start_i386boot (void)
 
 	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 @@ void start_i386boot (void)
 	}
 	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 @@ void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg)
 
 	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 @@ int register_timer_isr (timer_fnc_t *isr_func)
 	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;
 
 	/*



More information about the U-Boot mailing list