summaryrefslogtreecommitdiff
path: root/arch/i386/lib
diff options
context:
space:
mode:
authorMinkyu Kang <mk7.kang@samsung.com>2010-05-31 09:13:11 +0900
committerMinkyu Kang <mk7.kang@samsung.com>2010-05-31 09:13:11 +0900
commit922d27b596c179c5a7d68abe45ede5adb1b6589c (patch)
treec5ef3d5dc70bf51646a7fd7a379f6c2b2588cc2e /arch/i386/lib
parentde200874fb9ecac51d74b4e9783ebb5d2e94c449 (diff)
parent39c209546ab5b11ca6410c5cc57dcbf457e50800 (diff)
Merge branch 'master' of git://git.denx.de/u-boot-arm
Conflicts: arch/arm/include/asm/mach-types.h Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
Diffstat (limited to 'arch/i386/lib')
-rw-r--r--arch/i386/lib/bios_setup.c2
-rw-r--r--arch/i386/lib/board.c85
-rw-r--r--arch/i386/lib/realmode.c2
-rw-r--r--arch/i386/lib/zimage.c127
4 files changed, 150 insertions, 66 deletions
diff --git a/arch/i386/lib/bios_setup.c b/arch/i386/lib/bios_setup.c
index 6491e522ec4..a92b77ea237 100644
--- a/arch/i386/lib/bios_setup.c
+++ b/arch/i386/lib/bios_setup.c
@@ -141,7 +141,7 @@ static void setvector(int vector, u16 segment, void *handler)
int bios_setup(void)
{
- ulong i386boot_bios = (ulong)&_i386boot_bios;
+ ulong i386boot_bios = (ulong)&_i386boot_bios + gd->reloc_off;
ulong i386boot_bios_size = (ulong)&_i386boot_bios_size;
static int done=0;
diff --git a/arch/i386/lib/board.c b/arch/i386/lib/board.c
index f3b6348551e..3f849f6542d 100644
--- a/arch/i386/lib/board.c
+++ b/arch/i386/lib/board.c
@@ -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>
@@ -52,7 +53,9 @@ 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 *);
+
+void ram_bootstrap (void *, ulong);
+
const char version_string[] =
U_BOOT_VERSION" (" U_BOOT_DATE " - " U_BOOT_TIME ")";
@@ -147,7 +150,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 */
@@ -162,6 +164,7 @@ init_fnc_t *init_sequence[] = {
NULL,
};
+static gd_t gd_data;
gd_t *gd;
/*
@@ -174,21 +177,18 @@ void board_init_f (ulong stack_limit)
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;
+ ulong bss_size = (ulong)&_i386boot_bss_size;
- size_t uboot_size;
- void *ram_start;
+ ulong uboot_size;
+ void *dest_addr;
ulong rel_offset;
Elf32_Rel *re;
- void (*start_func)(void *);
-
- /* compiler optimization barrier needed for GCC >= 3.4 */
- __asm__ __volatile__("": : :"memory");
+ void (*start_func)(void *, ulong);
- 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;
+ uboot_size = (ulong)u_boot_cmd_end - (ulong)text_start;
+ dest_addr = (void *)stack_limit - (uboot_size + (ulong)bss_size);
+ rel_offset = text_start - dest_addr;
start_func = ram_bootstrap - rel_offset;
/* First stage CPU initialization */
@@ -200,10 +200,10 @@ void board_init_f (ulong stack_limit)
hang();
/* Copy U-Boot into RAM */
- memcpy(ram_start, text_start, (size_t)uboot_size);
+ memcpy(dest_addr, text_start, uboot_size);
/* Clear BSS */
- memset(bss_start - rel_offset, 0, (size_t)bss_size);
+ memset(bss_start - rel_offset, 0, bss_size);
/* Perform relocation adjustments */
for (re = rel_dyn_start; re < rel_dyn_end; re++)
@@ -213,27 +213,39 @@ void board_init_f (ulong stack_limit)
*(ulong *)(re->r_offset - rel_offset) -= (Elf32_Addr)rel_offset;
}
- start_func(ram_start);
-
- /* NOTREACHED - relocate_code() does not return */
+ /* Enter the relocated U-Boot! */
+ start_func(dest_addr, rel_offset);
+ /* NOTREACHED - board_init_f() 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.
+ * 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 *ram_start)
+void ram_bootstrap (void *dest_addr, ulong rel_offset)
{
- static gd_t gd_data;
-
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
- board_init_r(&gd_data, (ulong)ram_start);
+ /* tell others: relocation done */
+ gd_data.reloc_off = rel_offset;
+ gd_data.flags |= GD_FLG_RELOC;
+
+ board_init_r(&gd_data, (ulong)dest_addr);
}
-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 +259,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 +277,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 +292,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)
/*
@@ -420,10 +434,17 @@ void hang (void)
unsigned long do_go_exec (ulong (*entry)(int, char *[]), int argc, char *argv[])
{
/*
- * 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
*/
+ argv[-1] = (char *)gd;
+
return (entry) (argc, argv);
}
+
+void setup_pcat_compatibility(void)
+ __attribute__((weak, alias("__setup_pcat_compatibility")));
+
+void __setup_pcat_compatibility(void)
+{
+}
diff --git a/arch/i386/lib/realmode.c b/arch/i386/lib/realmode.c
index 3c3c1fc961f..b3f51230a5b 100644
--- a/arch/i386/lib/realmode.c
+++ b/arch/i386/lib/realmode.c
@@ -37,7 +37,7 @@ extern char realmode_enter;
int realmode_setup(void)
{
- ulong i386boot_realmode = (ulong)&_i386boot_realmode;
+ ulong i386boot_realmode = (ulong)&_i386boot_realmode + gd->reloc_off;
ulong i386boot_realmode_size = (ulong)&_i386boot_realmode_size;
/* copy the realmode switch code */
diff --git a/arch/i386/lib/zimage.c b/arch/i386/lib/zimage.c
index c3b4e597aab..b39615a3e25 100644
--- a/arch/i386/lib/zimage.c
+++ b/arch/i386/lib/zimage.c
@@ -34,6 +34,8 @@
#include <asm/zimage.h>
#include <asm/realmode.h>
#include <asm/byteorder.h>
+#include <asm/bootparam.h>
+#include <asm/ic/sc520.h>
/*
* Memory lay-out:
@@ -90,48 +92,56 @@ void *load_zimage(char *image, unsigned long kernel_size,
int big_image;
void *load_address;
+ struct setup_header *hdr = (struct setup_header *)(image + SETUP_SECTS_OFF);
setup_base = (void*)DEFAULT_SETUP_BASE; /* base address for real-mode segment */
- if (KERNEL_MAGIC != *(u16*)(image + BOOT_FLAG_OFF)) {
- printf("Error: Invalid kernel magic (found 0x%04x, expected 0xaa55)\n",
- *(u16*)(image + BOOT_FLAG_OFF));
+ if (KERNEL_MAGIC != hdr->boot_flag) {
+ printf("Error: Invalid Boot Flag (found 0x%04x, expected 0x%04x)\n",
+ hdr->boot_flag, KERNEL_MAGIC);
return 0;
+ } else {
+ printf("Valid Boot Flag\n");
}
-
/* determine boot protocol version */
- if (KERNEL_V2_MAGIC == *(u32*)(image+HEADER_OFF)) {
- bootproto = *(u16*)(image+VERSION_OFF);
+ if (KERNEL_V2_MAGIC == hdr->header) {
+ printf("Magic signature found\n");
+
+ bootproto = hdr->version;
} else {
/* Very old kernel */
+ printf("Magic signature not found\n");
bootproto = 0x0100;
}
/* determine size of setup */
- if (0 == *(u8*)(image + SETUP_SECTS_OFF)) {
+ if (0 == hdr->setup_sects) {
+ printf("Setup Sectors = 0 (defaulting to 4)\n");
setup_size = 5 * 512;
} else {
- setup_size = (*(u8*)(image + SETUP_SECTS_OFF) + 1) * 512;
+ setup_size = (hdr->setup_sects + 1) * 512;
}
+ printf("Setup Size = 0x%8.8lx\n", (ulong)setup_size);
+
if (setup_size > SETUP_MAX_SIZE) {
printf("Error: Setup is too large (%d bytes)\n", setup_size);
}
/* Determine image type */
- big_image = (bootproto >= 0x0200) && (*(u8*)(image + LOADFLAGS_OFF) & BIG_KERNEL_FLAG);
+ big_image = (bootproto >= 0x0200) && (hdr->loadflags & BIG_KERNEL_FLAG);
- /* Derermine load address */
- load_address = (void*)(big_image ? BZIMAGE_LOAD_ADDR:ZIMAGE_LOAD_ADDR);
+ /* Determine load address */
+ load_address = (void*)(big_image ? BZIMAGE_LOAD_ADDR : ZIMAGE_LOAD_ADDR);
/* load setup */
+ printf("Moving Real-Mode Code to 0x%8.8lx (%d bytes)\n", (ulong)setup_base, setup_size);
memmove(setup_base, image, setup_size);
printf("Using boot protocol version %x.%02x\n",
(bootproto & 0xff00) >> 8, bootproto & 0xff);
-
if (bootproto == 0x0100) {
*(u16*)(setup_base + CMD_LINE_MAGIC_OFF) = COMMAND_LINE_MAGIC;
@@ -154,48 +164,58 @@ void *load_zimage(char *image, unsigned long kernel_size,
memset((void*)0x90000 + setup_size, 0, SETUP_MAX_SIZE-setup_size);
}
+ /* We are now setting up the real-mode version of the header */
+ hdr = (struct setup_header *)(setup_base + SETUP_SECTS_OFF);
+
if (bootproto >= 0x0200) {
- *(u8*)(setup_base + TYPE_OF_LOADER_OFF) = 0xff;
- printf("Linux kernel version %s\n",
- (char*)(setup_base + SETUP_START_OFFSET +
- *(u16*)(setup_base + START_SYS_OFF + 2)));
+ hdr->type_of_loader = 8;
+
+ if (hdr->setup_sects >= 15)
+ printf("Linux kernel version %s\n", (char *)
+ (setup_base + (hdr->kernel_version + 0x200)));
+ else
+ printf("Setup Sectors < 15 - Cannot print kernel version.\n");
if (initrd_addr) {
printf("Initial RAM disk at linear address 0x%08lx, size %ld bytes\n",
initrd_addr, initrd_size);
- *(u32*)(setup_base + RAMDISK_IMAGE_OFF) = initrd_addr;
- *(u32*)(setup_base + RAMDISK_SIZE_OFF)=initrd_size;
+ hdr->ramdisk_image = initrd_addr;
+ hdr->ramdisk_size = initrd_size;
}
}
if (bootproto >= 0x0201) {
- *(u16*)(setup_base + HEAP_END_PTR_OFF) = HEAP_END_OFFSET;
-
- /* CAN_USE_HEAP */
- *(u8*)(setup_base + LOADFLAGS_OFF) =
- *(u8*)(setup_base + LOADFLAGS_OFF) | HEAP_FLAG;
+ hdr->heap_end_ptr = HEAP_END_OFFSET;
+ hdr->loadflags |= HEAP_FLAG;
}
if (bootproto >= 0x0202) {
- *(u32*)(setup_base + CMD_LINE_PTR_OFF) = (u32)setup_base + COMMAND_LINE_OFFSET;
+ hdr->cmd_line_ptr = (u32)setup_base + COMMAND_LINE_OFFSET;
} else if (bootproto >= 0x0200) {
+
*(u16*)(setup_base + CMD_LINE_MAGIC_OFF) = COMMAND_LINE_MAGIC;
*(u16*)(setup_base + CMD_LINE_OFFSET_OFF) = COMMAND_LINE_OFFSET;
- *(u16*)(setup_base + SETUP_MOVE_SIZE_OFF) = 0x9100;
+
+ hdr->setup_move_size = 0x9100;
}
+ if (bootproto >= 0x0204)
+ kernel_size = hdr->syssize * 16;
+ else
+ kernel_size -= setup_size;
+
if (big_image) {
- if ((kernel_size - setup_size) > BZIMAGE_MAX_SIZE) {
+ if ((kernel_size) > BZIMAGE_MAX_SIZE) {
printf("Error: bzImage kernel too big! (size: %ld, max: %d)\n",
- kernel_size - setup_size, BZIMAGE_MAX_SIZE);
+ kernel_size, BZIMAGE_MAX_SIZE);
return 0;
}
- } else if ((kernel_size - setup_size) > ZIMAGE_MAX_SIZE) {
+ } else if ((kernel_size) > ZIMAGE_MAX_SIZE) {
printf("Error: zImage kernel too big! (size: %ld, max: %d)\n",
- kernel_size - setup_size, ZIMAGE_MAX_SIZE);
+ kernel_size, ZIMAGE_MAX_SIZE);
return 0;
}
@@ -203,10 +223,10 @@ void *load_zimage(char *image, unsigned long kernel_size,
build_command_line(setup_base + COMMAND_LINE_OFFSET, auto_boot);
printf("Loading %czImage at address 0x%08x (%ld bytes)\n", big_image ? 'b' : ' ',
- (u32)load_address, kernel_size - setup_size);
+ (u32)load_address, kernel_size);
- memmove(load_address, image + setup_size, kernel_size - setup_size);
+ memmove(load_address, image + setup_size, kernel_size);
/* ready for booting */
return setup_base;
@@ -218,8 +238,51 @@ void boot_zimage(void *setup_base)
memset(&regs, 0, sizeof(struct pt_regs));
regs.xds = (u32)setup_base >> 4;
- regs.xss = 0x9000;
+ regs.xes = regs.xds;
+ regs.xss = regs.xds;
regs.esp = 0x9000;
regs.eflags = 0;
enter_realmode(((u32)setup_base+SETUP_START_OFFSET)>>4, 0, &regs, &regs);
}
+
+int do_zboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ void *base_ptr;
+ void *bzImage_addr;
+ ulong bzImage_size = 0;
+
+ disable_interrupts();
+
+ /* Setup board for maximum PC/AT Compatibility */
+ setup_pcat_compatibility();
+
+ /* argv[1] holds the address of the bzImage */
+ bzImage_addr = (void *)simple_strtoul(argv[1], NULL, 16);
+
+ if (argc == 3)
+ bzImage_size = simple_strtoul(argv[2], NULL, 16);
+
+ /* Lets look for*/
+ base_ptr = load_zimage (bzImage_addr, bzImage_size, 0, 0, 0);
+
+ if (NULL == base_ptr) {
+ printf ("## Kernel loading failed ...\n");
+ } else {
+ printf ("## Transferring control to Linux (at address %08x) ...\n",
+ (u32)base_ptr);
+
+ /* we assume that the kernel is in place */
+ printf("\nStarting kernel ...\n\n");
+
+ boot_zimage(base_ptr);
+ /* does not return */
+ }
+
+ return -1;
+}
+
+U_BOOT_CMD(
+ zboot, 3, 0, do_zboot,
+ "Boot bzImage",
+ ""
+);