summaryrefslogtreecommitdiff
path: root/arch/x86/lib
diff options
context:
space:
mode:
authorGabe Black <gabeblack@chromium.org>2011-08-08 23:56:46 -0700
committerSimon Glass <sjg@chromium.org>2011-08-29 10:59:35 -0700
commitc13a7dafd73cdce4a65f3ef332267e832ad1080c (patch)
tree90447c529c95ab4be8118eefc29414456e07bae7 /arch/x86/lib
parent3461048d5af6f909151e23d51384e50e25e035a5 (diff)
Refactor the zboot underpinnings so they can be reused with a vboot image
If vboot successfully verifies a kernel, it will leave it in place and basically ready to boot. The zeropage table which is part of the x86 boot protocol is at the end of the kernel, though, instead of the beginning, and because the image is already in place there's no need to copy it around. This change refactors the code which implements the zboot command so that the configuration of the zeropage table and loading the pieces of the kernel into memory are done separately. Also, because the command line goes before the zeropage table in vboot which is somewhat incompatible with the normal protocol, where to put the command line is a now a parameter instead of being hard coded. BUG=chrome-os-partner:4552 TEST=Built and booted a legacy kernel with both the 32 bit and 16 bit boot protocols. Like other, earlier changes to this code only a current kernel which doesn't exercise old protocol features was tested. This change is more significant than the others and so may break booting old kernels. Also, the bootm command was not tested on x86. We need to decide if that command makes any sense to keep/support. Signed-off-by: Gabe Black <gabeblack@google.com> Change-Id: I09f6d0e2d46b4ce499f31c8073571968dba51b8a Reviewed-on: http://gerrit.chromium.org/gerrit/5545 Reviewed-by: Simon Glass <sjg@chromium.org> Tested-by: Gabe Black <gabeblack@chromium.org>
Diffstat (limited to 'arch/x86/lib')
-rw-r--r--arch/x86/lib/bootm.c26
-rw-r--r--arch/x86/lib/zimage.c187
2 files changed, 122 insertions, 91 deletions
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c
index 22843e62e8..51209b2e5e 100644
--- a/arch/x86/lib/bootm.c
+++ b/arch/x86/lib/bootm.c
@@ -28,16 +28,19 @@
#include <command.h>
#include <image.h>
#include <u-boot/zlib.h>
+#include <asm/bootparam.h>
#include <asm/byteorder.h>
#include <asm/zimage.h>
+#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;
- ulong os_data, os_len;
- image_header_t *hdr;
- void *load_address;
+ struct boot_params *base_ptr;
+ ulong os_data, os_len;
+ image_header_t *hdr;
+ void *load_address;
#if defined(CONFIG_FIT)
const void *data;
@@ -73,16 +76,21 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima
goto error;
}
- 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);
- if (NULL == base_ptr) {
- printf ("## Kernel loading failed ...\n");
+ if (base_ptr == NULL) {
+ 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
printf ("## Transferring control to Linux (at address %08x) ...\n",
(u32)base_ptr);
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c
index 4252c2313c..80022d6b95 100644
--- a/arch/x86/lib/zimage.c
+++ b/arch/x86/lib/zimage.c
@@ -93,21 +93,8 @@ 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)
{
- struct boot_params *setup_base;
- int setup_size;
- int bootproto;
- int big_image;
-
- struct boot_params *params = (struct boot_params *)image;
- struct setup_header *hdr = &params->hdr;
-
- /* 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",
@@ -115,18 +102,38 @@ void *load_zimage(char *image, unsigned long kernel_size,
return 0;
} else {
printf("Valid Boot Flag\n");
+ return 1;
}
+}
- /* determine boot protocol version */
- if (KERNEL_V2_MAGIC == hdr->header) {
+static int get_boot_protocol(struct setup_header *hdr)
+{
+ if (hdr->header == KERNEL_V2_MAGIC) {
printf("Magic signature found\n");
-
- bootproto = hdr->version;
+ return hdr->version;
} else {
/* Very old kernel */
printf("Magic signature not found\n");
- bootproto = 0x0100;
+ return 0x0100;
}
+}
+
+struct boot_params *load_zimage(char *image, unsigned long kernel_size,
+ void **load_address)
+{
+ struct boot_params *setup_base;
+ int setup_size;
+ int bootproto;
+ int big_image;
+
+ struct boot_params *params = (struct boot_params *)image;
+ struct setup_header *hdr = &params->hdr;
+
+ /* base address for real-mode segment */
+ setup_base = (struct boot_params *)DEFAULT_SETUP_BASE;
+
+ if (!kernel_magic_ok(hdr))
+ return 0;
/* determine size of setup */
if (0 == hdr->setup_sects) {
@@ -142,6 +149,23 @@ void *load_zimage(char *image, unsigned long kernel_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);
@@ -156,9 +180,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",
@@ -166,13 +187,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 */
@@ -193,21 +213,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_NO_REALMODE_CODE || 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",
@@ -224,44 +268,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,22 +342,27 @@ 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);
+ printf("## Kernel loading failed ...\n");
+ 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;
+ }
- /* we assume that the kernel is in place */
- printf("\nStarting kernel ...\n\n");
+ printf ("## Transferring control to Linux "
+ "(at address %08x) ...\n",
+ (u32)base_ptr);
- boot_zimage(base_ptr, load_address);
- /* does not return */
- }
+ /* we assume that the kernel is in place */
+ printf("\nStarting kernel ...\n\n");
+
+ boot_zimage(base_ptr, load_address);
+ /* does not return */
return -1;
}