]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - arch/i386/lib/board.c
x86: Use loops instead of memcpy/memset in board_init_f
[karo-tx-uboot.git] / arch / i386 / lib / board.c
index 3f849f6542d3e155d0b9711115de60d8e663158d..9c2f77fd5446bc4ff4444f861ef62254f3aac25b 100644 (file)
 DECLARE_GLOBAL_DATA_PTR;
 
 /* Exports from the Linker Script */
-extern ulong _i386boot_text_start;
-extern ulong _i386boot_rel_dyn_start;
-extern ulong _i386boot_rel_dyn_end;
-extern ulong _i386boot_bss_start;
-extern ulong _i386boot_bss_size;
-
-void ram_bootstrap (void *, ulong);
+extern ulong __text_start;
+extern ulong __data_end;
+extern ulong __rel_dyn_start;
+extern ulong __rel_dyn_end;
+extern ulong __bss_start;
+extern ulong __bss_end;
 
 const char version_string[] =
        U_BOOT_VERSION" (" U_BOOT_DATE " - " U_BOOT_TIME ")";
@@ -69,7 +68,7 @@ const char version_string[] =
 static int init_baudrate (void)
 {
        char tmp[64];   /* long enough for environment variables */
-       int i = getenv_r("baudrate", tmp, 64);
+       int i = getenv_f("baudrate", tmp, 64);
 
        gd->baudrate = (i != 0)
                        ? (int) simple_strtoul (tmp, NULL, 10)
@@ -164,32 +163,32 @@ init_fnc_t *init_sequence[] = {
        NULL,
 };
 
-static gd_t gd_data;
 gd_t *gd;
 
 /*
  * Load U-Boot into RAM, initialize BSS, perform relocation adjustments
  */
-void board_init_f (ulong stack_limit)
+void board_init_f (ulong gdp)
 {
-       void *text_start = &_i386boot_text_start;
-       void *u_boot_cmd_end = &__u_boot_cmd_end;
-       Elf32_Rel *rel_dyn_start = (Elf32_Rel *)&_i386boot_rel_dyn_start;
-       Elf32_Rel *rel_dyn_end = (Elf32_Rel *)&_i386boot_rel_dyn_end;
-       void *bss_start = &_i386boot_bss_start;
-       ulong bss_size = (ulong)&_i386boot_bss_size;
-
-       ulong uboot_size;
+       void *text_start = &__text_start;
+       void *data_end = &__data_end;
+       void *rel_dyn_start = &__rel_dyn_start;
+       void *rel_dyn_end = &__rel_dyn_end;
+       void *bss_start = &__bss_start;
+       void *bss_end = &__bss_end;
+
+       ulong *dst_addr;
+       ulong *src_addr;
+       ulong *end_addr;
+
        void *dest_addr;
        ulong rel_offset;
-       Elf32_Rel *re;
-
-       void (*start_func)(void *, ulong);
+       Elf32_Rel *re_src;
+       Elf32_Rel *re_end;
 
-       uboot_size = (ulong)u_boot_cmd_end - (ulong)text_start;
-       dest_addr  = (void *)stack_limit - (uboot_size + (ulong)bss_size);
+       /* Calculate destination RAM Address and relocation offset */
+       dest_addr  = (void *)gdp - (bss_end - text_start);
        rel_offset = text_start - dest_addr;
-       start_func = ram_bootstrap - rel_offset;
 
        /* First stage CPU initialization */
        if (cpu_init_f() != 0)
@@ -200,49 +199,38 @@ void board_init_f (ulong stack_limit)
                hang();
 
        /* Copy U-Boot into RAM */
-       memcpy(dest_addr, text_start, uboot_size);
+       dst_addr = (ulong *)dest_addr;
+       src_addr = (ulong *)text_start;
+       end_addr = (ulong *)data_end;
+
+       while (src_addr < end_addr)
+               *dst_addr++ = *src_addr++;
 
        /* Clear BSS */
-       memset(bss_start - rel_offset,  0, bss_size);
+       dst_addr = (ulong *)(bss_start - rel_offset);
+       end_addr = (ulong *)(bss_end - rel_offset);
+
+       while (dst_addr < end_addr)
+               *dst_addr++ = 0x00000000;
 
        /* Perform relocation adjustments */
-       for (re = rel_dyn_start; re < rel_dyn_end; re++)
-       {
-               if (re->r_offset >= TEXT_BASE)
-                       if (*(ulong *)re->r_offset >= TEXT_BASE)
-                               *(ulong *)(re->r_offset - rel_offset) -= (Elf32_Addr)rel_offset;
-       }
+       re_src = (Elf32_Rel *)rel_dyn_start;
+       re_end = (Elf32_Rel *)rel_dyn_end;
 
-       /* Enter the relocated U-Boot! */
-       start_func(dest_addr, rel_offset);
-       /* NOTREACHED - board_init_f() does not return */
-       while(1);
-}
+       do {
+               if (re_src->r_offset >= TEXT_BASE)
+                       if (*(Elf32_Addr *)(re_src->r_offset - rel_offset) >= TEXT_BASE)
+                               *(Elf32_Addr *)(re_src->r_offset - rel_offset) -= rel_offset;
+       } while (re_src++ < re_end);
 
-/*
- * We cannot initialize gd_data in board_init_f() because we would be
- * attempting to write to flash (I have even tried using manual relocation
- * adjustments on pointers but it just won't work) and board_init_r() does
- * not have enough arguments to allow us to pass the relocation offset
- * straight up. This bootstrap function (which runs in RAM) is used to
- * setup gd_data in order to pass the relocation offset to the rest of
- * U-Boot.
- *
- * TODO: The compiler optimization barrier is intended to stop GCC from
- * optimizing this function into board_init_f(). It seems to work without
- * it, but I've left it in to be sure. I think also that the barrier in
- * board_init_r() is no longer needed, but left it in 'just in case'
- */
-void ram_bootstrap (void *dest_addr, ulong rel_offset)
-{
-       /* compiler optimization barrier needed for GCC >= 3.4 */
-       __asm__ __volatile__("": : :"memory");
+       ((gd_t *)gdp)->reloc_off = rel_offset;
+       ((gd_t *)gdp)->flags |= GD_FLG_RELOC;
 
-       /* tell others: relocation done */
-       gd_data.reloc_off = rel_offset;
-       gd_data.flags |= GD_FLG_RELOC;
+       /* Enter the relocated U-Boot! */
+       (board_init_r - rel_offset)((gd_t *)gdp, (ulong)dest_addr);
 
-       board_init_r(&gd_data, (ulong)dest_addr);
+       /* NOTREACHED - board_init_f() does not return */
+       while(1);
 }
 
 void board_init_r(gd_t *id, ulong dest_addr)
@@ -335,13 +323,6 @@ void board_init_r(gd_t *id, ulong dest_addr)
        enable_interrupts();
        show_boot_progress(0x28);
 
-       /* Must happen after interrupts are initialized since
-        * an irq handler gets installed
-        */
-#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
-       serial_buffered_init();
-#endif
-
 #ifdef CONFIG_STATUS_LED
        status_led_set (STATUS_LED_BOOT, STATUS_LED_BLINKING);
 #endif
@@ -431,15 +412,30 @@ void hang (void)
        for (;;);
 }
 
-unsigned long do_go_exec (ulong (*entry)(int, char *[]), int argc, char *argv[])
+unsigned long do_go_exec (ulong (*entry)(int, char * const []), int argc, char * const argv[])
 {
+       unsigned long ret = 0;
+       char **argv_tmp;
+
        /*
-        * x86 does not use a dedicated register to pass the pointer
-        * to the global_data
+        * x86 does not use a dedicated register to pass the pointer to
+        * the global_data, so it is instead passed as argv[-1]. By using
+        * argv[-1], the called 'Application' can use the contents of
+        * argv natively. However, to safely use argv[-1] a new copy of
+        * argv is needed with the extra element
         */
-       argv[-1] = (char *)gd;
+       argv_tmp = malloc(sizeof(char *) * (argc + 1));
+
+       if (argv_tmp) {
+               argv_tmp[0] = (char *)gd;
+
+               memcpy(&argv_tmp[1], argv, (size_t)(sizeof(char *) * argc));
+
+               ret = (entry) (argc, &argv_tmp[1]);
+               free(argv_tmp);
+       }
 
-       return (entry) (argc, argv);
+       return ret;
 }
 
 void setup_pcat_compatibility(void)