x86: Implement fully relocatable image
authorGraeme Russ <graeme.russ@gmail.com>
Thu, 7 Oct 2010 09:03:33 +0000 (20:03 +1100)
committerGraeme Russ <graeme.russ@gmail.com>
Thu, 7 Oct 2010 09:03:33 +0000 (20:03 +1100)
u-boot.bin can be loaded at any 4-byte aligned memory location and directly
'jumped' to using the 'go' command using the load address as the start
address. Doing so performs a 'warm boot' which skips memory initialisation
and other low-level initialisations, relocates U-Boot to upper memory and
starts U-Boot in RAM as per normal 'cold boot'

arch/i386/cpu/start.S
arch/i386/include/asm/global_data.h
arch/i386/lib/board.c

index 8fdcd81c1ea6306ad21286264c6f80f86795c8f6..829468fe7ed4dea0a8479c9b023840a9fb91b388 100644 (file)
@@ -118,6 +118,11 @@ mem_ok:
 
        wbinvd
 
+       /* Determine our load offset */
+       call    1f
+1:     popl    %ecx
+       subl    $1b, %ecx
+
        /* Set the upper memory limit parameter */
        subl    $CONFIG_SYS_STACK_SIZE, %eax
 
@@ -127,6 +132,7 @@ mem_ok:
        /* %eax points to the global data structure */
        movl    %esp, (GD_RAM_SIZE * 4)(%eax)
        movl    %ebx, (GD_FLAGS * 4)(%eax)
+       movl    %ecx, (GD_LOAD_OFF * 4)(%eax)
 
        call    board_init_f    /* Enter, U-boot! */
 
index a15c5981c6baa17c4e75c8ce022cbb9f422d52d4..597112318f567d373d2d85df459f66ff8b9df208 100644 (file)
@@ -41,6 +41,7 @@ typedef       struct {
        unsigned long   baudrate;
        unsigned long   have_console;   /* serial_init() was called */
        unsigned long   reloc_off;      /* Relocation Offset */
+       unsigned long   load_off;       /* Load Offset */
        unsigned long   env_addr;       /* Address  of Environment struct */
        unsigned long   env_valid;      /* Checksum of Environment valid? */
        unsigned long   cpu_clk;        /* CPU clock in Hz!             */
@@ -56,20 +57,21 @@ extern gd_t *gd;
 #endif
 
 /* Word Offsets into Global Data - MUST match struct gd_t */
-#define GD_BD    0
-#define GD_FLAGS 1
-#define GD_BAUDRATE  2
-#define GD_HAVE_CONSOLE  3
-#define GD_RELOC_OFF 4
-#define GD_ENV_ADDR  5
-#define GD_ENV_VALID 6
-#define GD_CPU_CLK 7
-#define GD_BUS_CLK 8
-#define GD_RAM_SIZE  9
-#define GD_RESET_STATUS  10
-#define GD_JT    11
+#define GD_BD          0
+#define GD_FLAGS       1
+#define GD_BAUDRATE    2
+#define GD_HAVE_CONSOLE        3
+#define GD_RELOC_OFF   4
+#define GD_LOAD_OFF    5
+#define GD_ENV_ADDR    6
+#define GD_ENV_VALID   7
+#define GD_CPU_CLK     8
+#define GD_BUS_CLK     9
+#define GD_RAM_SIZE    10
+#define GD_RESET_STATUS        11
+#define GD_JT          12
 
-#define GD_SIZE    12
+#define GD_SIZE                13
 
 /*
  * Global Data Flags
index 9c2f77fd5446bc4ff4444f861ef62254f3aac25b..1129918fe2d4aa7b61be198b93e5be6cb012b4b4 100644 (file)
@@ -190,18 +190,21 @@ void board_init_f (ulong gdp)
        dest_addr  = (void *)gdp - (bss_end - text_start);
        rel_offset = text_start - dest_addr;
 
-       /* First stage CPU initialization */
-       if (cpu_init_f() != 0)
-               hang();
-
-       /* First stage Board initialization */
-       if (board_early_init_f() != 0)
-               hang();
+       /* Perform low-level initialization only when cold booted */
+       if (((gd_t *)gdp)->flags & GD_FLG_COLD_BOOT) {
+               /* First stage CPU initialization */
+               if (cpu_init_f() != 0)
+                       hang();
+
+               /* First stage Board initialization */
+               if (board_early_init_f() != 0)
+                       hang();
+       }
 
        /* Copy U-Boot into RAM */
        dst_addr = (ulong *)dest_addr;
-       src_addr = (ulong *)text_start;
-       end_addr = (ulong *)data_end;
+       src_addr = (ulong *)(text_start + ((gd_t *)gdp)->load_off);
+       end_addr = (ulong *)(data_end  + ((gd_t *)gdp)->load_off);
 
        while (src_addr < end_addr)
                *dst_addr++ = *src_addr++;
@@ -214,8 +217,8 @@ void board_init_f (ulong gdp)
                *dst_addr++ = 0x00000000;
 
        /* Perform relocation adjustments */
-       re_src = (Elf32_Rel *)rel_dyn_start;
-       re_end = (Elf32_Rel *)rel_dyn_end;
+       re_src = (Elf32_Rel *)(rel_dyn_start + ((gd_t *)gdp)->load_off);
+       re_end = (Elf32_Rel *)(rel_dyn_end + ((gd_t *)gdp)->load_off);
 
        do {
                if (re_src->r_offset >= TEXT_BASE)