summaryrefslogtreecommitdiff
path: root/arch/x86
diff options
context:
space:
mode:
authorGabe Black <gabeblack@chromium.org>2011-06-24 20:30:01 -0700
committerSimon Glass <sjg@chromium.org>2011-08-29 10:39:41 -0700
commit6240561f3448165af9b544c09977653d94ce5ff7 (patch)
tree570e9e16ec0d77c4cad8d93e87ad5b403a43e147 /arch/x86
parent15791c5932dfcf6a9d3b672f1f205dff9ea32e27 (diff)
Add support for booting Linux using the 32 bit boot protocol.
This change conditionally modifies the zboot command so that it can use the 32 bit boot protocol. This is necessary because the 16 bit realmode entry point assumes that it can call BIOS services which neither coreboot nor u-boot provide. BUG=chrome-os-partner:4700 TEST=Built and booted using the legacy and 32 bit boot protocols. Used dmesg to verify that the e820 memory map was successfully picked up by the kernel when using the 32 bit protocol. Change-Id: Ibd7d0989a2bef16affb1c3dd268ef9a72461597f Signed-off-by: Gabe Black <gabeblack@google.com> Reviewed-on: http://gerrit.chromium.org/gerrit/3220 Reviewed-by: Stefan Reinauer <reinauer@google.com> Reviewed-by: Simon Glass <sjg@chromium.org> Tested-by: Gabe Black <gabeblack@chromium.org>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/include/asm/zimage.h4
-rw-r--r--arch/x86/lib/bootm.c6
-rw-r--r--arch/x86/lib/zimage.c48
3 files changed, 44 insertions, 14 deletions
diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h
index 6a8f7b3588b..129fbb507b5 100644
--- a/arch/x86/include/asm/zimage.h
+++ b/arch/x86/include/asm/zimage.h
@@ -51,8 +51,8 @@ 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);
+ int auto_boot, void **load_address);
-void boot_zimage(void *setup_base);
+void boot_zimage(void *setup_base, void *load_address);
#endif
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c
index a21a21f1f7f..22843e62e88 100644
--- a/arch/x86/lib/bootm.c
+++ b/arch/x86/lib/bootm.c
@@ -37,6 +37,7 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima
void *base_ptr;
ulong os_data, os_len;
image_header_t *hdr;
+ void *load_address;
#if defined(CONFIG_FIT)
const void *data;
@@ -73,7 +74,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima
}
base_ptr = load_zimage ((void*)os_data, os_len,
- images->rd_start, images->rd_end - images->rd_start, 0);
+ images->rd_start, images->rd_end - images->rd_start,
+ 0, &load_address);
if (NULL == base_ptr) {
printf ("## Kernel loading failed ...\n");
@@ -89,7 +91,7 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima
/* we assume that the kernel is in place */
printf("\nStarting kernel ...\n\n");
- boot_zimage(base_ptr);
+ boot_zimage(base_ptr, load_address);
/* does not return */
error:
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c
index f5e758e3a1e..c28bfcb434c 100644
--- a/arch/x86/lib/zimage.c
+++ b/arch/x86/lib/zimage.c
@@ -95,13 +95,12 @@ static void build_command_line(char *command_line, int auto_boot)
void *load_zimage(char *image, unsigned long kernel_size,
unsigned long initrd_addr, unsigned long initrd_size,
- int auto_boot)
+ int auto_boot, void **load_address)
{
struct boot_params *setup_base;
int setup_size;
int bootproto;
int big_image;
- void *load_address;
struct boot_params *params = (struct boot_params *)image;
struct setup_header *hdr = &params->hdr;
@@ -148,15 +147,24 @@ void *load_zimage(char *image, unsigned long kernel_size,
/* Determine load address */
if (big_image) {
- load_address = (void *)BZIMAGE_LOAD_ADDR;
+ *load_address = (void *)BZIMAGE_LOAD_ADDR;
} else {
- load_address = (void *)ZIMAGE_LOAD_ADDR;
+ *load_address = (void *)ZIMAGE_LOAD_ADDR;
}
+#if defined CONFIG_ZBOOT_32
+ 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",
(ulong)setup_base, setup_size);
memmove(setup_base, image, setup_size);
+#endif
printf("Using boot protocol version %x.%02x\n",
(bootproto & 0xff00) >> 8, bootproto & 0xff);
@@ -193,7 +201,7 @@ void *load_zimage(char *image, unsigned long kernel_size,
if (hdr->setup_sects >= 15) {
printf("Linux kernel version %s\n",
- (char *)setup_base +
+ (char *)params +
hdr->kernel_version + 0x200);
} else {
printf("Setup Sectors < 15 - "
@@ -248,16 +256,33 @@ void *load_zimage(char *image, unsigned long kernel_size,
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);
+ big_image ? 'b' : ' ', (u32)*load_address, kernel_size);
- memmove(load_address, image + setup_size, kernel_size);
+ memmove(*load_address, image + setup_size, kernel_size);
/* ready for booting */
return setup_base;
}
-void boot_zimage(void *setup_base)
+void boot_zimage(void *setup_base, void *load_address)
{
+#if defined CONFIG_ZBOOT_32
+ /*
+ * Set %ebx, %ebp, and %edi to 0, %esi to point to the boot_params
+ * structure, and then jump to the kernel. We assume that %cs is
+ * 0x10, 4GB flat, and read/execute, and the data segments are 0x18,
+ * 4GB flat, and read/write. U-boot is setting them up that way for
+ * itself in arch/i386/cpu/cpu.c.
+ */
+ __asm__ __volatile__ (
+ "movl $0, %%ebp \n"
+ "cli \n"
+ "jmp %[kernel_entry] \n"
+ :: [kernel_entry]"r"(load_address),
+ [boot_params] "S"(setup_base),
+ "b"(0), "D"(0)
+ );
+#else
struct pt_regs regs;
memset(&regs, 0, sizeof(struct pt_regs));
@@ -268,12 +293,14 @@ void boot_zimage(void *setup_base)
regs.eflags = 0;
enter_realmode(((u32)setup_base + SETUP_START_OFFSET) >> 4, 0,
&regs, &regs);
+#endif
}
int do_zboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
void *base_ptr;
void *bzImage_addr = NULL;
+ void *load_address;
char *s;
ulong bzImage_size = 0;
@@ -297,7 +324,8 @@ 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);
+ base_ptr = load_zimage(bzImage_addr, bzImage_size, 0, 0, 0,
+ &load_address);
if (!base_ptr) {
printf ("## Kernel loading failed ...\n");
@@ -309,7 +337,7 @@ int do_zboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
/* we assume that the kernel is in place */
printf("\nStarting kernel ...\n\n");
- boot_zimage(base_ptr);
+ boot_zimage(base_ptr, load_address);
/* does not return */
}