x86: Refactor the zboot innards 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.

Signed-off-by: Gabe Black <gabeblack@chromium.org>
This commit is contained in:
Gabe Black 2011-12-05 12:09:26 +00:00 committed by Graeme Russ
parent f08fa7a201
commit 69370d144a
3 changed files with 124 additions and 92 deletions

View file

@ -24,6 +24,7 @@
#ifndef _ASM_ZIMAGE_H_
#define _ASM_ZIMAGE_H_
#include <asm/bootparam.h>
#include <asm/e820.h>
/* 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);

View file

@ -28,17 +28,20 @@
#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 = 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

View file

@ -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;
}