summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86/cpu/Makefile4
-rw-r--r--arch/x86/cpu/start16.S2
-rw-r--r--arch/x86/include/asm/bootm.h12
-rw-r--r--arch/x86/include/asm/config.h3
-rw-r--r--arch/x86/lib/bootm.c151
-rw-r--r--arch/x86/lib/zimage.c41
-rw-r--r--common/bootm.c23
-rw-r--r--common/cmd_bootm.c1
-rw-r--r--common/image-fit.c24
-rw-r--r--common/image.c11
-rw-r--r--doc/uImage.FIT/kernel.its50
-rw-r--r--doc/uImage.FIT/source_file_format.txt19
-rw-r--r--doc/uImage.FIT/x86-fit-boot.txt276
-rw-r--r--include/bootstage.h3
-rw-r--r--include/image.h13
15 files changed, 557 insertions, 76 deletions
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile
index 415bc24..e7bb3e3 100644
--- a/arch/x86/cpu/Makefile
+++ b/arch/x86/cpu/Makefile
@@ -9,5 +9,5 @@
#
extra-y = start.o
-extra-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o
-obj-y = interrupts.o cpu.o
+obj-$(CONFIG_X86_RESET_VECTOR) += resetvec.o start16.o
+obj-y += interrupts.o cpu.o
diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S
index 8b9b327..6968fda 100644
--- a/arch/x86/cpu/start16.S
+++ b/arch/x86/cpu/start16.S
@@ -70,7 +70,7 @@ idt_ptr:
* GDT is setup in a safe location in RAM
*/
gdt_ptr:
- .word 0x20 /* limit (32 bytes = 4 GDT entries) */
+ .word 0x1f /* limit (31 bytes = 4 GDT entries - 1) */
.long BOOT_SEG + gdt /* base */
/* Some CPUs are picky about GDT alignment... */
diff --git a/arch/x86/include/asm/bootm.h b/arch/x86/include/asm/bootm.h
new file mode 100644
index 0000000..033ab79
--- /dev/null
+++ b/arch/x86/include/asm/bootm.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef ARM_BOOTM_H
+#define ARM_BOOTM_H
+
+void bootm_announce_and_cleanup(void);
+
+#endif
diff --git a/arch/x86/include/asm/config.h b/arch/x86/include/asm/config.h
index f06a15c..ff15828 100644
--- a/arch/x86/include/asm/config.h
+++ b/arch/x86/include/asm/config.h
@@ -8,4 +8,7 @@
#define _ASM_CONFIG_H_
#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_LMB
+#define CONFIG_SYS_BOOT_RAMDISK_HIGH
+
#endif
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c
index ff158dd..4c5c7f5 100644
--- a/arch/x86/lib/bootm.c
+++ b/arch/x86/lib/bootm.c
@@ -10,80 +10,161 @@
#include <common.h>
#include <command.h>
+#include <fdt_support.h>
#include <image.h>
#include <u-boot/zlib.h>
#include <asm/bootparam.h>
#include <asm/byteorder.h>
#include <asm/zimage.h>
+#ifdef CONFIG_SYS_COREBOOT
+#include <asm/arch/timestamp.h>
+#endif
#define COMMAND_LINE_OFFSET 0x9000
-/*cmd_boot.c*/
-int do_bootm_linux(int flag, int argc, char * const argv[],
- bootm_headers_t *images)
+/*
+ * Implement a weak default function for boards that optionally
+ * need to clean up the system before jumping to the kernel.
+ */
+__weak void board_final_cleanup(void)
{
- 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;
- size_t len;
+void bootm_announce_and_cleanup(void)
+{
+ printf("\nStarting kernel ...\n\n");
+
+#ifdef CONFIG_SYS_COREBOOT
+ timestamp_add_now(TS_U_BOOT_START_KERNEL);
+#endif
+ bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
+#ifdef CONFIG_BOOTSTAGE_REPORT
+ bootstage_report();
#endif
+ board_final_cleanup();
+}
- if (flag & BOOTM_STATE_OS_PREP)
- return 0;
- if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
- return 1;
+#if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL)
+int arch_fixup_memory_node(void *blob)
+{
+ bd_t *bd = gd->bd;
+ int bank;
+ u64 start[CONFIG_NR_DRAM_BANKS];
+ u64 size[CONFIG_NR_DRAM_BANKS];
+
+ for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
+ start[bank] = bd->bi_dram[bank].start;
+ size[bank] = bd->bi_dram[bank].size;
+ }
+
+ return fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS);
+}
+#endif
+/* Subcommand: PREP */
+static int boot_prep_linux(bootm_headers_t *images)
+{
+ char *cmd_line_dest = NULL;
+ image_header_t *hdr;
+ int is_zimage = 0;
+ void *data = NULL;
+ size_t len;
+ int ret;
+
+#ifdef CONFIG_OF_LIBFDT
+ if (images->ft_len) {
+ debug("using: FDT\n");
+ if (image_setup_linux(images)) {
+ puts("FDT creation failed! hanging...");
+ hang();
+ }
+ }
+#endif
if (images->legacy_hdr_valid) {
hdr = images->legacy_hdr_os;
if (image_check_type(hdr, IH_TYPE_MULTI)) {
+ ulong os_data, os_len;
+
/* if multi-part image, we need to get first subimage */
image_multi_getimg(hdr, 0, &os_data, &os_len);
+ data = (void *)os_data;
+ len = os_len;
} else {
/* otherwise get image data */
- os_data = image_get_data(hdr);
- os_len = image_get_data_size(hdr);
+ data = (void *)image_get_data(hdr);
+ len = image_get_data_size(hdr);
}
+ is_zimage = 1;
#if defined(CONFIG_FIT)
- } else if (images->fit_uname_os) {
- int ret;
-
+ } else if (images->fit_uname_os && is_zimage) {
ret = fit_image_get_data(images->fit_hdr_os,
- images->fit_noffset_os, &data, &len);
+ images->fit_noffset_os,
+ (const void **)&data, &len);
if (ret) {
puts("Can't get image data/size!\n");
goto error;
}
- os_data = (ulong)data;
- os_len = (ulong)len;
+ is_zimage = 1;
#endif
- } else {
- puts("Could not find kernel image!\n");
- goto error;
}
-#ifdef CONFIG_CMD_ZBOOT
- base_ptr = load_zimage((void *)os_data, os_len, &load_address);
-#endif
+ if (is_zimage) {
+ void *load_address;
+ char *base_ptr;
- if (NULL == base_ptr) {
- printf("## Kernel loading failed ...\n");
+ base_ptr = (char *)load_zimage(data, len, &load_address);
+ images->os.load = (ulong)load_address;
+ cmd_line_dest = base_ptr + COMMAND_LINE_OFFSET;
+ images->ep = (ulong)base_ptr;
+ } else if (images->ep) {
+ cmd_line_dest = (void *)images->ep + COMMAND_LINE_OFFSET;
+ } else {
+ printf("## Kernel loading failed (no setup) ...\n");
goto error;
}
- if (setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET,
+ printf("Setup at %#08lx\n", images->ep);
+ ret = setup_zimage((void *)images->ep, cmd_line_dest,
0, images->rd_start,
- images->rd_end - images->rd_start)) {
+ images->rd_end - images->rd_start);
+
+ if (ret) {
printf("## Setting up boot parameters failed ...\n");
- goto error;
+ return 1;
}
- boot_zimage(base_ptr, load_address);
- /* does not return */
+ return 0;
error:
return 1;
}
+
+/* Subcommand: GO */
+static int boot_jump_linux(bootm_headers_t *images)
+{
+ debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n",
+ images->ep, images->os.load);
+
+ boot_zimage((struct boot_params *)images->ep, (void *)images->os.load);
+ /* does not return */
+
+ return 1;
+}
+
+int do_bootm_linux(int flag, int argc, char * const argv[],
+ bootm_headers_t *images)
+{
+ /* No need for those on x86 */
+ if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
+ return -1;
+
+ if (flag & BOOTM_STATE_OS_PREP)
+ return boot_prep_linux(images);
+
+ if (flag & BOOTM_STATE_OS_GO) {
+ boot_jump_linux(images);
+ return 0;
+ }
+
+ return boot_jump_linux(images);
+}
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c
index 1dab3cc..2f0e92f 100644
--- a/arch/x86/lib/zimage.c
+++ b/arch/x86/lib/zimage.c
@@ -18,6 +18,7 @@
#include <asm/ptrace.h>
#include <asm/zimage.h>
#include <asm/byteorder.h>
+#include <asm/bootm.h>
#include <asm/bootparam.h>
#ifdef CONFIG_SYS_COREBOOT
#include <asm/arch/timestamp.h>
@@ -242,41 +243,27 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot,
hdr->loadflags |= HEAP_FLAG;
}
- if (bootproto >= 0x0202) {
- 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 =
- (uintptr_t)cmd_line - (uintptr_t)setup_base;
+ if (cmd_line) {
+ if (bootproto >= 0x0202) {
+ 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 =
+ (uintptr_t)cmd_line - (uintptr_t)setup_base;
+
+ hdr->setup_move_size = 0x9100;
+ }
- hdr->setup_move_size = 0x9100;
+ /* build command line at COMMAND_LINE_OFFSET */
+ build_command_line(cmd_line, auto_boot);
}
- /* build command line at COMMAND_LINE_OFFSET */
- build_command_line(cmd_line, auto_boot);
return 0;
}
-/*
- * Implement a weak default function for boards that optionally
- * need to clean up the system before jumping to the kernel.
- */
-__weak void board_final_cleanup(void)
-{
-}
-
void boot_zimage(void *setup_base, void *load_address)
{
- debug("## Transferring control to Linux (at address %08x) ...\n",
- (u32)setup_base);
-
- bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
-#ifdef CONFIG_BOOTSTAGE_REPORT
- bootstage_report();
-#endif
- board_final_cleanup();
-
- printf("\nStarting kernel ...\n\n");
+ bootm_announce_and_cleanup();
#ifdef CONFIG_SYS_COREBOOT
timestamp_add_now(TS_U_BOOT_START_KERNEL);
diff --git a/common/bootm.c b/common/bootm.c
index ff81a27..17ed389 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -9,6 +9,7 @@
#include <common.h>
#include <bootstage.h>
#include <bzlib.h>
+#include <errno.h>
#include <fdt_support.h>
#include <lmb.h>
#include <malloc.h>
@@ -83,6 +84,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
{
const void *os_hdr;
bool ep_found = false;
+ int ret;
/* get kernel image header, start address and length */
os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
@@ -102,6 +104,7 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
images.os.end = image_get_image_end(os_hdr);
images.os.load = image_get_load(os_hdr);
+ images.os.arch = image_get_arch(os_hdr);
break;
#endif
#if defined(CONFIG_FIT)
@@ -129,6 +132,13 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
return 1;
}
+ if (fit_image_get_arch(images.fit_hdr_os,
+ images.fit_noffset_os,
+ &images.os.arch)) {
+ puts("Can't get image ARCH!\n");
+ return 1;
+ }
+
images.os.end = fit_get_end(images.fit_hdr_os);
if (fit_image_get_load(images.fit_hdr_os, images.fit_noffset_os,
@@ -156,8 +166,17 @@ static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
return 1;
}
- /* find kernel entry point */
- if (images.legacy_hdr_valid) {
+ /* If we have a valid setup.bin, we will use that for entry (x86) */
+ if (images.os.arch == IH_ARCH_I386) {
+ ulong len;
+
+ ret = boot_get_setup(&images, IH_ARCH_I386, &images.ep, &len);
+ if (ret < 0 && ret != -ENOENT) {
+ puts("Could not find a valid setup.bin for x86\n");
+ return 1;
+ }
+ /* Kernel entry point is the setup.bin */
+ } else if (images.legacy_hdr_valid) {
images.ep = image_get_ep(&images.legacy_hdr_os_copy);
#if defined(CONFIG_FIT)
} else if (images.fit_uname_os) {
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 843ec6e..6723360 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -12,6 +12,7 @@
#include <bootm.h>
#include <command.h>
#include <environment.h>
+#include <errno.h>
#include <image.h>
#include <lmb.h>
#include <malloc.h>
diff --git a/common/image-fit.c b/common/image-fit.c
index 255c4ca..2016d1e 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -1497,6 +1497,8 @@ static const char *fit_get_image_type_property(int type)
return FIT_KERNEL_PROP;
case IH_TYPE_RAMDISK:
return FIT_RAMDISK_PROP;
+ case IH_TYPE_X86_SETUP:
+ return FIT_SETUP_PROP;
}
return "unknown";
@@ -1591,7 +1593,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
}
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH);
-#ifndef USE_HOSTCC
+#if !defined(USE_HOSTCC) && !defined(CONFIG_SANDBOX)
if (!fit_image_check_target_arch(fit, noffset)) {
puts("Unsupported Architecture\n");
bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH);
@@ -1693,3 +1695,23 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
return noffset;
}
+
+int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
+ ulong *setup_start, ulong *setup_len)
+{
+ int noffset;
+ ulong addr;
+ ulong len;
+ int ret;
+
+ addr = map_to_sysmem(images->fit_hdr_os);
+ noffset = fit_get_node_from_config(images, FIT_SETUP_PROP, addr);
+ if (noffset < 0)
+ return noffset;
+
+ ret = fit_image_load(images, addr, NULL, NULL, arch,
+ IH_TYPE_X86_SETUP, BOOTSTAGE_ID_FIT_SETUP_START,
+ FIT_LOAD_REQUIRED, setup_start, &len);
+
+ return ret;
+}
diff --git a/common/image.c b/common/image.c
index 085771c..640e83b 100644
--- a/common/image.c
+++ b/common/image.c
@@ -143,6 +143,7 @@ static const table_entry_t uimage_type[] = {
{ IH_TYPE_UBLIMAGE, "ublimage", "Davinci UBL image",},
{ IH_TYPE_MXSIMAGE, "mxsimage", "Freescale MXS Boot Image",},
{ IH_TYPE_ATMELIMAGE, "atmelimage", "ATMEL ROM-Boot Image",},
+ { IH_TYPE_X86_SETUP, "x86_setup", "x86 setup.bin", },
{ -1, "", "", },
};
@@ -1136,6 +1137,16 @@ error:
}
#endif /* CONFIG_SYS_BOOT_RAMDISK_HIGH */
+int boot_get_setup(bootm_headers_t *images, uint8_t arch,
+ ulong *setup_start, ulong *setup_len)
+{
+#if defined(CONFIG_FIT)
+ return boot_get_setup_fit(images, arch, setup_start, setup_len);
+#else
+ return -ENOENT;
+#endif
+}
+
#ifdef CONFIG_SYS_BOOT_GET_CMDLINE
/**
* boot_get_cmdline - allocate and initialize kernel cmdline
diff --git a/doc/uImage.FIT/kernel.its b/doc/uImage.FIT/kernel.its
index ef3ab8f..539cdbf 100644
--- a/doc/uImage.FIT/kernel.its
+++ b/doc/uImage.FIT/kernel.its
@@ -35,3 +35,53 @@
};
};
};
+
+
+
+For x86 a setup node is also required: see x86-fit-boot.txt.
+
+/dts-v1/;
+
+/ {
+ description = "Simple image with single Linux kernel on x86";
+ #address-cells = <1>;
+
+ images {
+ kernel@1 {
+ description = "Vanilla Linux kernel";
+ data = /incbin/("./image.bin.lzo");
+ type = "kernel";
+ arch = "x86";
+ os = "linux";
+ compression = "lzo";
+ load = <0x01000000>;
+ entry = <0x00000000>;
+ hash@2 {
+ algo = "sha1";
+ };
+ };
+
+ setup@1 {
+ description = "Linux setup.bin";
+ data = /incbin/("./setup.bin");
+ type = "x86_setup";
+ arch = "x86";
+ os = "linux";
+ compression = "none";
+ load = <0x00090000>;
+ entry = <0x00090000>;
+ hash@2 {
+ algo = "sha1";
+ };
+ };
+ };
+
+ configurations {
+ default = "config@1";
+ config@1 {
+ description = "Boot Linux kernel";
+ kernel = "kernel@1";
+ setup = "setup@1";
+ };
+ };
+};
diff --git a/doc/uImage.FIT/source_file_format.txt b/doc/uImage.FIT/source_file_format.txt
index 9ed6f65..b47ce73 100644
--- a/doc/uImage.FIT/source_file_format.txt
+++ b/doc/uImage.FIT/source_file_format.txt
@@ -55,7 +55,7 @@ FIT is formally a flattened device tree (in the libfdt meaning), which
conforms to bindings defined in this document.
.its - image tree source
-.itb - image tree blob
+.fit - flattened image tree blob
c) Image building procedure
@@ -101,15 +101,15 @@ Root node of the uImage Tree should have the following layout:
|
o images
| |
- | o img@1 {...}
- | o img@2 {...}
+ | o image@1 {...}
+ | o image@2 {...}
| ...
|
o configurations
- |- default = "cfg@1"
+ |- default = "conf@1"
|
- o cfg@1 {...}
- o cfg@2 {...}
+ o conf@1 {...}
+ o conf@2 {...}
...
@@ -159,7 +159,7 @@ the '/images' node should have the following layout:
- description : Textual description of the component sub-image
- type : Name of component sub-image type, supported types are:
"standalone", "kernel", "ramdisk", "firmware", "script", "filesystem",
- "flat_dt".
+ "flat_dt" and others (see uimage_type in common/images.c).
- data : Path to the external file which contains this node's binary data.
- compression : Compression used by included data. Supported compressions
are "gzip" and "bzip2". If no compression is used compression property
@@ -173,7 +173,8 @@ the '/images' node should have the following layout:
- arch : Architecture name, mandatory for types: "standalone", "kernel",
"firmware", "ramdisk" and "fdt". Valid architecture names are: "alpha",
"arm", "i386", "ia64", "mips", "mips64", "ppc", "s390", "sh", "sparc",
- "sparc64", "m68k", "microblaze", "nios2", "blackfin", "avr32", "st200".
+ "sparc64", "m68k", "microblaze", "nios2", "blackfin", "avr32", "st200",
+ "sandbox".
- entry : entry point address, address size is determined by
'#address-cells' property of the root node. Mandatory for for types:
"standalone" and "kernel".
@@ -246,6 +247,8 @@ o config@1
node of a "ramdisk" type).
- fdt : Unit name of the corresponding fdt blob (component image node of a
"fdt type").
+ - setup : Unit name of the corresponding setup binary (used for booting
+ an x86 kernel). This contains the setup.bin file built by the kernel.
The FDT blob is required to properly boot FDT based kernel, so the minimal
configuration for 2.6 FDT kernel is (kernel, fdt) pair.
diff --git a/doc/uImage.FIT/x86-fit-boot.txt b/doc/uImage.FIT/x86-fit-boot.txt
new file mode 100644
index 0000000..61c10ff
--- /dev/null
+++ b/doc/uImage.FIT/x86-fit-boot.txt
@@ -0,0 +1,276 @@
+Booting Linux on x86 with FIT
+=============================
+
+Background
+----------
+
+(corrections to the text below are welcome)
+
+Generally Linux x86 uses its own very complex booting method. There is a setup
+binary which contains all sorts of parameters and a compressed self-extracting
+binary for the kernel itself, often with a small built-in serial driver to
+display decompression progress.
+
+The x86 CPU has various processor modes. I am no expert on these, but my
+understanding is that an x86 CPU (even a really new one) starts up in a 16-bit
+'real' mode where only 1MB of memory is visible, moves to 32-bit 'protected'
+mode where 4GB is visible (or more with special memory access techniques) and
+then to 64-bit 'long' mode if 64-bit execution is required.
+
+Partly the self-extracting nature of Linux was introduced to cope with boot
+loaders that were barely capable of loading anything. Even changing to 32-bit
+mode was something of a challenge, so putting this logic in the kernel seemed
+to make sense.
+
+Bit by bit more and more logic has been added to this post-boot pre-Linux
+wrapper:
+
+- Changing to 32-bit mode
+- Decompression
+- Serial output (with drivers for various chips)
+- Load address randomisation
+- Elf loader complete with relocation (for the above)
+- Random number generator via 3 methods (again for the above)
+- Some sort of EFI mini-loader (1000+ glorious lines of code)
+- Locating and tacking on a device tree and ramdisk
+
+To my mind, if you sit back and look at things from first principles, this
+doesn't make a huge amount of sense. Any boot loader worth its salts already
+has most of the above features and more besides. The boot loader already knows
+the layout of memory, has a serial driver, can decompress things, includes an
+ELF loader and supports device tree and ramdisks. The decision to duplicate
+all these features in a Linux wrapper caters for the lowest common
+denominator: a boot loader which consists of a BIOS call to load something off
+disk, followed by a jmp instruction.
+
+(Aside: On ARM systems, we worry that the boot loader won't know where to load
+the kernel. It might be easier to just provide that information in the image,
+or in the boot loader rather than adding a self-relocator to put it in the
+right place. Or just use ELF?
+
+As a result, the x86 kernel boot process is needlessly complex. The file
+format is also complex, and obfuscates the contents to a degree that it is
+quite a challenge to extract anything from it. This bzImage format has become
+so prevalent that is actually isn't possible to produce the 'raw' kernel build
+outputs with the standard Makefile (as it is on ARM for example, at least at
+the time of writing).
+
+This document describes an alternative boot process which uses simple raw
+images which are loaded into the right place by the boot loader and then
+executed.
+
+
+Build the kernel
+----------------
+
+Note: these instructions assume a 32-bit kernel. U-Boot does not currently
+support booting a 64-bit kernel as it has no way of going into 64-bit mode on
+x86.
+
+You can build the kernel as normal with 'make'. This will create a file called
+'vmlinux'. This is a standard ELF file and you can look at it if you like:
+
+$ objdump -h vmlinux
+
+vmlinux: file format elf32-i386
+
+Sections:
+Idx Name Size VMA LMA File off Algn
+ 0 .text 00416850 81000000 01000000 00001000 2**5
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+ 1 .notes 00000024 81416850 01416850 00417850 2**2
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 2 __ex_table 00000c50 81416880 01416880 00417880 2**3
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 3 .rodata 00154b9e 81418000 01418000 00419000 2**5
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 4 __bug_table 0000597c 8156cba0 0156cba0 0056dba0 2**0
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 5 .pci_fixup 00001b80 8157251c 0157251c 0057351c 2**2
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 6 .tracedata 00000024 8157409c 0157409c 0057509c 2**0
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 7 __ksymtab 00007ec0 815740c0 015740c0 005750c0 2**2
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 8 __ksymtab_gpl 00004a28 8157bf80 0157bf80 0057cf80 2**2
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 9 __ksymtab_strings 0001d6fc 815809a8 015809a8 005819a8 2**0
+ CONTENTS, ALLOC, LOAD, READONLY, DATA
+ 10 __init_rodata 00001c3c 8159e0a4 0159e0a4 0059f0a4 2**2
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 11 __param 00000ff0 8159fce0 0159fce0 005a0ce0 2**2
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 12 __modver 00000330 815a0cd0 015a0cd0 005a1cd0 2**2
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 13 .data 00063000 815a1000 015a1000 005a2000 2**12
+ CONTENTS, ALLOC, LOAD, RELOC, DATA
+ 14 .init.text 0002f104 81604000 01604000 00605000 2**2
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+ 15 .init.data 00040cdc 81634000 01634000 00635000 2**12
+ CONTENTS, ALLOC, LOAD, RELOC, DATA
+ 16 .x86_cpu_dev.init 0000001c 81674cdc 01674cdc 00675cdc 2**2
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 17 .altinstructions 0000267c 81674cf8 01674cf8 00675cf8 2**0
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 18 .altinstr_replacement 00000942 81677374 01677374 00678374 2**0
+ CONTENTS, ALLOC, LOAD, READONLY, CODE
+ 19 .iommu_table 00000014 81677cb8 01677cb8 00678cb8 2**2
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 20 .apicdrivers 00000004 81677cd0 01677cd0 00678cd0 2**2
+ CONTENTS, ALLOC, LOAD, RELOC, DATA
+ 21 .exit.text 00001a80 81677cd8 01677cd8 00678cd8 2**0
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
+ 22 .data..percpu 00007880 8167a000 0167a000 0067b000 2**12
+ CONTENTS, ALLOC, LOAD, RELOC, DATA
+ 23 .smp_locks 00003000 81682000 01682000 00683000 2**2
+ CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
+ 24 .bss 000a1000 81685000 01685000 00686000 2**12
+ ALLOC
+ 25 .brk 00424000 81726000 01726000 00686000 2**0
+ ALLOC
+ 26 .comment 00000049 00000000 00000000 00686000 2**0
+ CONTENTS, READONLY
+ 27 .GCC.command.line 0003e055 00000000 00000000 00686049 2**0
+ CONTENTS, READONLY
+ 28 .debug_aranges 0000f4c8 00000000 00000000 006c40a0 2**3
+ CONTENTS, RELOC, READONLY, DEBUGGING
+ 29 .debug_info 0440b0df 00000000 00000000 006d3568 2**0
+ CONTENTS, RELOC, READONLY, DEBUGGING
+ 30 .debug_abbrev 0022a83b 00000000 00000000 04ade647 2**0
+ CONTENTS, READONLY, DEBUGGING
+ 31 .debug_line 004ead0d 00000000 00000000 04d08e82 2**0
+ CONTENTS, RELOC, READONLY, DEBUGGING
+ 32 .debug_frame 0010a960 00000000 00000000 051f3b90 2**2
+ CONTENTS, RELOC, READONLY, DEBUGGING
+ 33 .debug_str 001b442d 00000000 00000000 052fe4f0 2**0
+ CONTENTS, READONLY, DEBUGGING
+ 34 .debug_loc 007c7fa9 00000000 00000000 054b291d 2**0
+ CONTENTS, RELOC, READONLY, DEBUGGING
+ 35 .debug_ranges 00098828 00000000 00000000 05c7a8c8 2**3
+ CONTENTS, RELOC, READONLY, DEBUGGING
+
+There is also the setup binary mentioned earlier. This is at
+arch/x86/boot/setup.bin and is about 12KB in size. It includes the command
+line and various settings need by the kernel. Arguably the boot loader should
+provide all of this also, but setting it up is some complex that the kernel
+helps by providing a head start.
+
+As you can see the code loads to address 0x01000000 and everything else
+follows after that. We could load this image using the 'bootelf' command but
+we would still need to provide the setup binary. This is not supported by
+U-Boot although I suppose you could mostly script it. This would permit the
+use of a relocatable kernel.
+
+All we need to boot is the vmlinux file and the setup.bin file.
+
+
+Create a FIT
+------------
+
+To create a FIT you will need a source file describing what should go in the
+FIT. See kernel.its for an example for x86. Put this into a file called
+image.its.
+
+Note that setup is loaded to the special address of 0x90000 (a special address
+you just have to know) and the kernel is loaded to 0x01000000 (the address you
+saw above). This means that you will need to load your FIT to a different
+address so that U-Boot doesn't overwrite it when decompressing. Something like
+0x02000000 will do so you can set CONFIG_SYS_LOAD_ADDR to that.
+
+In that example the kernel is compressed with lzo. Also we need to provide a
+flat binary, not an ELF. So the steps needed to set things are are:
+
+ # Create a flat binary
+ objcopy -O binary vmlinux vmlinux.bin
+
+ # Compress it into LZO format
+ lzop vmlinux.bin
+
+ # Build a FIT image
+ mkimage -f image.its image.fit
+
+(be careful to run the mkimage from your U-Boot tools directory since it
+will have x86_setup support.)
+
+You can take a look at the resulting fit file if you like:
+
+$ dumpimage -l image.fit
+FIT description: Simple image with single Linux kernel on x86
+Created: Tue Oct 7 10:57:24 2014
+ Image 0 (kernel@1)
+ Description: Vanilla Linux kernel
+ Created: Tue Oct 7 10:57:24 2014
+ Type: Kernel Image
+ Compression: lzo compressed
+ Data Size: 4591767 Bytes = 4484.15 kB = 4.38 MB
+ Architecture: Intel x86
+ OS: Linux
+ Load Address: 0x01000000
+ Entry Point: 0x00000000
+ Hash algo: sha1
+ Hash value: 446b5163ebfe0fb6ee20cbb7a8501b263cd92392
+ Image 1 (setup@1)
+ Description: Linux setup.bin
+ Created: Tue Oct 7 10:57:24 2014
+ Type: x86 setup.bin
+ Compression: uncompressed
+ Data Size: 12912 Bytes = 12.61 kB = 0.01 MB
+ Hash algo: sha1
+ Hash value: a1f2099cf47ff9816236cd534c77af86e713faad
+ Default Configuration: 'config@1'
+ Configuration 0 (config@1)
+ Description: Boot Linux kernel
+ Kernel: kernel@1
+
+
+Booting the FIT
+---------------
+
+To make it boot you need to load it and then use 'bootm' to boot it. A
+suitable script to do this from a network server is:
+
+ bootp
+ tftp image.fit
+ bootm
+
+This will load the image from the network and boot it. The command line (from
+the 'bootargs' environment variable) will be passed to the kernel.
+
+If you want a ramdisk you can add it as normal with FIT. If you want a device
+tree then x86 doesn't normally use those - it has ACPI instead.
+
+
+Why Bother?
+-----------
+
+1. It demystifies the process of booting an x86 kernel
+2. It allows use of the standard U-Boot boot file format
+3. It allows U-Boot to perform decompression - problems will provide an error
+message and you are still in the boot loader. It is possible to investigate.
+4. It avoids all the pre-loader code in the kernel which is quite complex to
+follow
+5. You can use verified/secure boot and other features which haven't yet been
+added to the pre-Linux
+6. It makes x86 more like other architectures in the way it boots a kernel.
+You can potentially use the same file format for the kernel, and the same
+procedure for building and packaging it.
+
+
+References
+----------
+
+In the Linux kernel, Documentation/x86/boot.txt defines the boot protocol for
+the kernel including the setup.bin format. This is handled in U-Boot in
+arch/x86/lib/zimage.c and arch/x86/lib/bootm.c.
+
+The procedure for entering 64-bit mode on x86 seems to be described here:
+
+ http://wiki.osdev.org/64-bit_Higher_Half_Kernel_with_GRUB_2
+
+Various files in the same directory as this file describe the FIT format.
+
+
+--
+Simon Glass
+sjg@chromium.org
+7-Oct-2014
diff --git a/include/bootstage.h b/include/bootstage.h
index 87bf906..df13ab2 100644
--- a/include/bootstage.h
+++ b/include/bootstage.h
@@ -159,6 +159,9 @@ enum bootstage_id {
/* Next 10 IDs used by BOOTSTAGE_SUB_... */
BOOTSTAGE_ID_FIT_RD_START = 120, /* Ramdisk stages */
+ /* Next 10 IDs used by BOOTSTAGE_SUB_... */
+ BOOTSTAGE_ID_FIT_SETUP_START = 130, /* x86 setup stages */
+
BOOTSTAGE_ID_IDE_FIT_READ = 140,
BOOTSTAGE_ID_IDE_FIT_READ_OK,
diff --git a/include/image.h b/include/image.h
index 4347532..a13a302 100644
--- a/include/image.h
+++ b/include/image.h
@@ -233,6 +233,7 @@ struct lmb;
#define IH_TYPE_GPIMAGE 17 /* TI Keystone GPHeader Image */
#define IH_TYPE_ATMELIMAGE 18 /* ATMEL ROM bootable Image */
#define IH_TYPE_SOCFPGAIMAGE 19 /* Altera SOCFPGA Preloader */
+#define IH_TYPE_X86_SETUP 20 /* x86 setup.bin Image */
/*
* Compression Types
@@ -273,6 +274,7 @@ typedef struct image_info {
ulong image_start, image_len; /* start of image within blob, len of image */
ulong load; /* load addr for the image */
uint8_t comp, type, os; /* compression, type of image, os type */
+ uint8_t arch; /* CPU architecture */
} image_info_t;
/*
@@ -303,6 +305,10 @@ typedef struct bootm_headers {
void *fit_hdr_fdt; /* FDT blob FIT image header */
const char *fit_uname_fdt; /* FDT blob subimage node unit name */
int fit_noffset_fdt;/* FDT blob subimage node offset */
+
+ void *fit_hdr_setup; /* x86 setup FIT image header */
+ const char *fit_uname_setup; /* x86 setup subimage node name */
+ int fit_noffset_setup;/* x86 setup subimage node offset */
#endif
#ifndef USE_HOSTCC
@@ -417,6 +423,9 @@ enum fit_load_op {
FIT_LOAD_REQUIRED, /* Must be provided */
};
+int boot_get_setup(bootm_headers_t *images, uint8_t arch, ulong *setup_start,
+ ulong *setup_len);
+
#ifndef USE_HOSTCC
/* Image format types, returned by _get_format() routine */
#define IMAGE_FORMAT_INVALID 0x00
@@ -438,6 +447,9 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images,
uint8_t arch, ulong *rd_start, ulong *rd_end);
#endif
+int boot_get_setup_fit(bootm_headers_t *images, uint8_t arch,
+ ulong *setup_start, ulong *setup_len);
+
/**
* fit_image_load() - load an image from a FIT
*
@@ -721,6 +733,7 @@ int bootz_setup(ulong image, ulong *start, ulong *end);
#define FIT_RAMDISK_PROP "ramdisk"
#define FIT_FDT_PROP "fdt"
#define FIT_DEFAULT_PROP "default"
+#define FIT_SETUP_PROP "setup"
#define FIT_MAX_HASH_LEN HASH_MAX_DIGEST_SIZE