]> 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 f3b6348551ea7058b68b72229c008a1985d6235b..9c2f77fd5446bc4ff4444f861ef62254f3aac25b 100644 (file)
@@ -37,6 +37,7 @@
 #include <malloc.h>
 #include <net.h>
 #include <ide.h>
+#include <serial.h>
 #include <asm/u-boot-i386.h>
 #include <elf.h>
 
 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 *);
+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 ")";
 
@@ -66,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)
@@ -147,7 +149,6 @@ static void display_flash_config (ulong size)
 typedef int (init_fnc_t) (void);
 
 init_fnc_t *init_sequence[] = {
-       serial_init,
        cpu_init_r,             /* basic cpu dependent setup */
        board_early_init_r,     /* basic board dependent setup */
        dram_init,              /* configure available RAM banks */
@@ -167,29 +168,27 @@ 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;
-       void *bss_size = &_i386boot_bss_size;
-
-       size_t uboot_size;
-       void *ram_start;
+       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 *);
-
-       /* compiler optimization barrier needed for GCC >= 3.4 */
-       __asm__ __volatile__("": : :"memory");
+       Elf32_Rel *re_src;
+       Elf32_Rel *re_end;
 
-       uboot_size = (size_t)u_boot_cmd_end - (size_t)text_start;
-       ram_start  = (void *)stack_limit - (uboot_size + (ulong)bss_size);
-       rel_offset = text_start - ram_start;
-       start_func = ram_bootstrap - rel_offset;
+       /* Calculate destination RAM Address and relocation offset */
+       dest_addr  = (void *)gdp - (bss_end - text_start);
+       rel_offset = text_start - dest_addr;
 
        /* First stage CPU initialization */
        if (cpu_init_f() != 0)
@@ -200,40 +199,41 @@ void board_init_f (ulong stack_limit)
                hang();
 
        /* Copy U-Boot into RAM */
-       memcpy(ram_start, text_start, (size_t)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, (size_t)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;
 
-       start_func(ram_start);
+       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);
 
-       /* NOTREACHED - relocate_code() does not return */
-       while(1);
-}
-
-/*
- * All attempts to jump straight from board_init_f() to board_init_r()
- * have failed, hence this special 'bootstrap' function.
- */
-void ram_bootstrap (void *ram_start)
-{
-       static gd_t gd_data;
+       ((gd_t *)gdp)->reloc_off = rel_offset;
+       ((gd_t *)gdp)->flags |= GD_FLG_RELOC;
 
-       /* compiler optimization barrier needed for GCC >= 3.4 */
-       __asm__ __volatile__("": : :"memory");
+       /* Enter the relocated U-Boot! */
+       (board_init_r - rel_offset)((gd_t *)gdp, (ulong)dest_addr);
 
-       board_init_r(&gd_data, (ulong)ram_start);
+       /* NOTREACHED - board_init_f() does not return */
+       while(1);
 }
 
-void board_init_r(gd_t *id, ulong ram_start)
+void board_init_r(gd_t *id, ulong dest_addr)
 {
        char *s;
        int i;
@@ -247,16 +247,13 @@ void board_init_r(gd_t *id, ulong ram_start)
        /* compiler optimization barrier needed for GCC >= 3.4 */
        __asm__ __volatile__("": : :"memory");
 
-       memset (gd, 0, sizeof (gd_t));
        gd->bd = &bd_data;
        memset (gd->bd, 0, sizeof (bd_t));
        show_boot_progress(0x22);
 
        gd->baudrate =  CONFIG_BAUDRATE;
 
-       gd->flags |= GD_FLG_RELOC;      /* tell others: relocation done */
-
-       mem_malloc_init((((ulong)ram_start - CONFIG_SYS_MALLOC_LEN)+3)&~3,
+       mem_malloc_init((((ulong)dest_addr - CONFIG_SYS_MALLOC_LEN)+3)&~3,
                        CONFIG_SYS_MALLOC_LEN);
 
        for (init_fnc_ptr = init_sequence, i=0; *init_fnc_ptr; ++init_fnc_ptr, i++) {
@@ -268,6 +265,9 @@ void board_init_r(gd_t *id, ulong ram_start)
        }
        show_boot_progress(0x23);
 
+#ifdef CONFIG_SERIAL_MULTI
+       serial_initialize();
+#endif
        /* configure available FLASH banks */
        size = flash_init();
        display_flash_config(size);
@@ -280,8 +280,10 @@ void board_init_r(gd_t *id, ulong ram_start)
        show_boot_progress(0x26);
 
 
+#ifdef CONFIG_CMD_NET
        /* IP Address */
        bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr");
+#endif
 
 #if defined(CONFIG_PCI)
        /*
@@ -321,13 +323,6 @@ void board_init_r(gd_t *id, ulong ram_start)
        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
@@ -417,13 +412,35 @@ 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;
+
        /*
-        * TODO: Test this function - changed to fix compiler error.
-        * Original code was:
-        *   return (entry >> 1) (argc, argv);
-        * with a comment about Nios function pointers are address >> 1
+        * 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
         */
-       return (entry) (argc, argv);
+       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 ret;
+}
+
+void setup_pcat_compatibility(void)
+       __attribute__((weak, alias("__setup_pcat_compatibility")));
+
+void __setup_pcat_compatibility(void)
+{
 }