diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h index 3a68bb0bb3..f03ea809af 100644 --- a/arch/x86/include/asm/zimage.h +++ b/arch/x86/include/asm/zimage.h @@ -24,6 +24,7 @@ #ifndef _ASM_ZIMAGE_H_ #define _ASM_ZIMAGE_H_ +#include #include /* linux i386 zImage/bzImage header. Offsets relative to @@ -49,9 +50,10 @@ /* Implementation defined function to install an e820 map. */ unsigned install_e820_map(unsigned max_entries, struct e820entry *); -void *load_zimage(char *image, unsigned long kernel_size, - unsigned long initrd_addr, unsigned long initrd_size, - int auto_boot, void **load_address); +struct boot_params *load_zimage(char *image, unsigned long kernel_size, + void **load_address); +int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, + unsigned long initrd_addr, unsigned long initrd_size); void boot_zimage(void *setup_base, void *load_address); diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index ba3875b1bc..83caf6bdbd 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -28,17 +28,20 @@ #include #include #include +#include #include #include +#define COMMAND_LINE_OFFSET 0x9000 + /*cmd_boot.c*/ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images) { - void *base_ptr = NULL; - ulong os_data, os_len; - image_header_t *hdr; - void *load_address; + struct boot_params *base_ptr = NULL; + ulong os_data, os_len; + image_header_t *hdr; + void *load_address; #if defined(CONFIG_FIT) const void *data; @@ -75,15 +78,19 @@ int do_bootm_linux(int flag, int argc, char * const argv[], } #ifdef CONFIG_CMD_ZBOOT - base_ptr = load_zimage((void *)os_data, os_len, - images->rd_start, images->rd_end - images->rd_start, - 0, &load_address); + base_ptr = load_zimage((void *)os_data, os_len, &load_address); #endif if (NULL == base_ptr) { printf("## Kernel loading failed ...\n"); goto error; + } + if (setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET, + 0, images->rd_start, + images->rd_end - images->rd_start)) { + printf("## Setting up boot parameters failed ...\n"); + goto error; } #ifdef DEBUG diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index b5597ecd74..0cbb57101b 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -89,9 +89,33 @@ static void build_command_line(char *command_line, int auto_boot) printf("Kernel command line: \"%s\"\n", command_line); } -void *load_zimage(char *image, unsigned long kernel_size, - unsigned long initrd_addr, unsigned long initrd_size, - int auto_boot, void **load_address) +static int kernel_magic_ok(struct setup_header *hdr) +{ + 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"); + return 1; + } +} + +static int get_boot_protocol(struct setup_header *hdr) +{ + if (hdr->header == KERNEL_V2_MAGIC) { + printf("Magic signature found\n"); + return hdr->version; + } else { + /* Very old kernel */ + printf("Magic signature not found\n"); + return 0x0100; + } +} + +struct boot_params *load_zimage(char *image, unsigned long kernel_size, + void **load_address) { struct boot_params *setup_base; int setup_size; @@ -104,25 +128,8 @@ void *load_zimage(char *image, unsigned long kernel_size, /* base address for real-mode segment */ setup_base = (struct boot_params *)DEFAULT_SETUP_BASE; - if (KERNEL_MAGIC != hdr->boot_flag) { - printf("Error: Invalid Boot Flag " - "(found 0x%04x, expected 0x%04x)\n", - hdr->boot_flag, KERNEL_MAGIC); + if (!kernel_magic_ok(hdr)) return 0; - } else { - printf("Valid Boot Flag\n"); - } - - /* determine boot protocol version */ - 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 == hdr->setup_sects) { @@ -137,6 +144,23 @@ void *load_zimage(char *image, unsigned long kernel_size, if (setup_size > SETUP_MAX_SIZE) printf("Error: Setup is too large (%d bytes)\n", setup_size); + /* determine boot protocol version */ + bootproto = get_boot_protocol(hdr); + + printf("Using boot protocol version %x.%02x\n", + (bootproto & 0xff00) >> 8, bootproto & 0xff); + + if (bootproto >= 0x0200) { + if (hdr->setup_sects >= 15) { + printf("Linux kernel version %s\n", + (char *)params + + hdr->kernel_version + 0x200); + } else { + printf("Setup Sectors < 15 - " + "Cannot print kernel version.\n"); + } + } + /* Determine image type */ big_image = (bootproto >= 0x0200) && (hdr->loadflags & BIG_KERNEL_FLAG); @@ -151,9 +175,6 @@ void *load_zimage(char *image, unsigned long kernel_size, printf("Building boot_params at 0x%8.8lx\n", (ulong)setup_base); memset(setup_base, 0, sizeof(*setup_base)); setup_base->hdr = params->hdr; - - setup_base->e820_entries = install_e820_map( - ARRAY_SIZE(setup_base->e820_map), setup_base->e820_map); #else /* load setup */ printf("Moving Real-Mode Code to 0x%8.8lx (%d bytes)\n", @@ -161,13 +182,12 @@ void *load_zimage(char *image, unsigned long kernel_size, memmove(setup_base, image, setup_size); #endif - printf("Using boot protocol version %x.%02x\n", - (bootproto & 0xff00) >> 8, bootproto & 0xff); + if (bootproto >= 0x0204) + kernel_size = hdr->syssize * 16; + else + kernel_size -= setup_size; if (bootproto == 0x0100) { - setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC; - setup_base->screen_info.cl_offset = COMMAND_LINE_OFFSET; - /* * A very old kernel MUST have its real-mode code * loaded at 0x90000 @@ -190,21 +210,45 @@ void *load_zimage(char *image, unsigned long kernel_size, SETUP_MAX_SIZE - setup_size); } - /* We are now setting up the real-mode version of the header */ - hdr = &setup_base->hdr; + if (big_image) { + if (kernel_size > BZIMAGE_MAX_SIZE) { + printf("Error: bzImage kernel too big! " + "(size: %ld, max: %d)\n", + kernel_size, BZIMAGE_MAX_SIZE); + return 0; + } + } else if ((kernel_size) > ZIMAGE_MAX_SIZE) { + printf("Error: zImage kernel too big! (size: %ld, max: %d)\n", + kernel_size, ZIMAGE_MAX_SIZE); + return 0; + } + printf("Loading %s at address %p (%ld bytes)\n", + big_image ? "bzImage" : "zImage", *load_address, kernel_size); + + memmove(*load_address, image + setup_size, kernel_size); + + return setup_base; +} + +int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, + unsigned long initrd_addr, unsigned long initrd_size) +{ + struct setup_header *hdr = &setup_base->hdr; + int bootproto = get_boot_protocol(hdr); + +#if defined CONFIG_ZBOOT_32 + setup_base->e820_entries = install_e820_map( + ARRAY_SIZE(setup_base->e820_map), setup_base->e820_map); +#endif + + if (bootproto == 0x0100) { + setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC; + setup_base->screen_info.cl_offset = COMMAND_LINE_OFFSET; + } if (bootproto >= 0x0200) { hdr->type_of_loader = 8; - if (hdr->setup_sects >= 15) { - printf("Linux kernel version %s\n", - (char *)params + - 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", @@ -221,44 +265,18 @@ void *load_zimage(char *image, unsigned long kernel_size, } if (bootproto >= 0x0202) { - hdr->cmd_line_ptr = - (uintptr_t)setup_base + COMMAND_LINE_OFFSET; + hdr->cmd_line_ptr = (uintptr_t)cmd_line; } else if (bootproto >= 0x0200) { setup_base->screen_info.cl_magic = COMMAND_LINE_MAGIC; - setup_base->screen_info.cl_offset = COMMAND_LINE_OFFSET; + setup_base->screen_info.cl_offset = + (uintptr_t)cmd_line - (uintptr_t)setup_base; hdr->setup_move_size = 0x9100; } - if (bootproto >= 0x0204) - kernel_size = hdr->syssize * 16; - else - kernel_size -= setup_size; - - - if (big_image) { - if ((kernel_size) > BZIMAGE_MAX_SIZE) { - printf("Error: bzImage kernel too big! " - "(size: %ld, max: %d)\n", - kernel_size, BZIMAGE_MAX_SIZE); - return 0; - } - } else if ((kernel_size) > ZIMAGE_MAX_SIZE) { - printf("Error: zImage kernel too big! (size: %ld, max: %d)\n", - kernel_size, ZIMAGE_MAX_SIZE); - return 0; - } - /* build command line at COMMAND_LINE_OFFSET */ - build_command_line((char *)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); - - memmove(*load_address, image + setup_size, kernel_size); - - /* ready for booting */ - return setup_base; + build_command_line(cmd_line, auto_boot); + return 0; } void boot_zimage(void *setup_base, void *load_address) @@ -298,7 +316,7 @@ void boot_zimage(void *setup_base, void *load_address) int do_zboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - void *base_ptr; + struct boot_params *base_ptr; void *bzImage_addr = NULL; void *load_address; char *s; @@ -324,20 +342,25 @@ int do_zboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) bzImage_size = simple_strtoul(argv[2], NULL, 16); /* Lets look for */ - base_ptr = load_zimage(bzImage_addr, bzImage_size, 0, 0, 0, - &load_address); + base_ptr = load_zimage(bzImage_addr, bzImage_size, &load_address); if (!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 */ - boot_zimage(base_ptr, load_address); - /* does not return */ + return -1; } + if (setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET, + 0, 0, 0)) { + printf("Setting up boot parameters failed ...\n"); + return -1; + } + + printf("## Transferring control to Linux " + "(at address %08x) ...\n", + (u32)base_ptr); + + /* we assume that the kernel is in place */ + boot_zimage(base_ptr, load_address); + /* does not return */ return -1; }