[coreboot-gerrit] Patch set updated for coreboot: 22d025c Add a (b)zImage parser to cbfstool

Patrick Georgi (patrick@georgi-clan.de) gerrit at coreboot.org
Fri Aug 30 18:41:01 CEST 2013


Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3302

-gerrit

commit 22d025caca2322bc9d05a9c3d70e701fe2563f1a
Author: Patrick Georgi <patrick at georgi-clan.de>
Date:   Tue Aug 27 20:22:21 2013 +0200

    Add a (b)zImage parser to cbfstool
    
    In the great tradition of LinuxBIOS this allows adding
    a kernel as payload. add-payload is extended to also
    allow adding an initial ramdisk (-I filename) and a
    command line (-C console=ttyS0).
    
    Change-Id: Iaca499a98b0adf0134e78d6bf020b6531a626aaa
    Signed-off-by: Patrick Georgi <patrick.georgi at secunet.com>
    Signed-off-by: Patrick Georgi <patrick at georgi-clan.de>
---
 util/cbfstool/Makefile             |   2 +
 util/cbfstool/Makefile.inc         |   3 +
 util/cbfstool/cbfs-mkpayload.c     |   1 +
 util/cbfstool/cbfs-payload-linux.c | 238 +++++++++++++++++++++++++++++++++++++
 util/cbfstool/cbfstool.c           |  19 ++-
 util/cbfstool/common.h             |   3 +
 util/cbfstool/linux.h              | 191 +++++++++++++++++++++++++++++
 util/cbfstool/linux_trampoline.c   | 141 ++++++++++++++++++++++
 8 files changed, 597 insertions(+), 1 deletion(-)

diff --git a/util/cbfstool/Makefile b/util/cbfstool/Makefile
index a0de08d..3aa5edc 100644
--- a/util/cbfstool/Makefile
+++ b/util/cbfstool/Makefile
@@ -12,6 +12,8 @@ COMMON+=cbfs-mkstage.o cbfs-mkpayload.o
 COMMON+=lzma/lzma.o
 COMMON+=lzma/C/LzFind.o  lzma/C/LzmaDec.o  lzma/C/LzmaEnc.o
 
+COMMON+=linux_trampoline.o cbfs-payload-linux.o
+
 COMMON:=$(addprefix $(obj)/,$(COMMON))
 
 all: dep $(BINARY)
diff --git a/util/cbfstool/Makefile.inc b/util/cbfstool/Makefile.inc
index 970620d..fc120f3 100644
--- a/util/cbfstool/Makefile.inc
+++ b/util/cbfstool/Makefile.inc
@@ -11,6 +11,9 @@ cbfsobj += lzma.o
 cbfsobj += LzFind.o
 cbfsobj += LzmaDec.o
 cbfsobj += LzmaEnc.o
+# linux as payload
+cbfsobj += linux_trampoline.o
+cbfsobj += cbfs-payload-linux.o
 
 CBFSTOOLFLAGS=-D_7ZIP_ST -g
 
diff --git a/util/cbfstool/cbfs-mkpayload.c b/util/cbfstool/cbfs-mkpayload.c
index 9f3dabf..78988a0 100644
--- a/util/cbfstool/cbfs-mkpayload.c
+++ b/util/cbfstool/cbfs-mkpayload.c
@@ -377,3 +377,4 @@ int parse_fv_to_payload(const struct buffer *input,
 	return 0;
 
 }
+
diff --git a/util/cbfstool/cbfs-payload-linux.c b/util/cbfstool/cbfs-payload-linux.c
new file mode 100644
index 0000000..149265c
--- /dev/null
+++ b/util/cbfstool/cbfs-payload-linux.c
@@ -0,0 +1,238 @@
+/*
+ * cbfs-payload-linux
+ *
+ * Copyright (C) 2013 Patrick Georgi <patrick at georgi-clan.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common.h"
+#include "cbfs.h"
+#include "linux.h"
+
+/* TODO:
+ *   handle special arguments
+ *     mem= argument - only affects loading decisions (kernel + initrd), not e820 -> build time
+ *     vga= argument (FILO ignores this)
+ *   add support for more parameters to trampoline:
+ *     alt_mem_k, ext_mem_k (not strictly necessary since e820 takes precedence)
+ *     framebuffer/console values
+ *
+ *  larger work:
+ *     is compress() safe to use in a size constrained buffer? ie. do(es) the
+ *     compression algorithm(s) stop once the compression result reaches input
+ *     size (ie. incompressible data)?
+ */
+int parse_bzImage_to_payload(const struct buffer *input,
+			     struct buffer *output, const char *initrd_name,
+			     char *cmdline, comp_algo algo)
+{
+	int cur_len = 0;
+	int num_segments = 3; /* parameter block, real kernel, and trampoline */
+
+	comp_func_ptr compress = compression_function(algo);
+	if (!compress)
+		return -1;
+
+	unsigned int initrd_base = 64*1024*1024;
+	unsigned int initrd_size = 0;
+	void *initrd_data = NULL;
+	if (initrd_name != NULL) {
+		/* TODO: load initrd, set initrd_size */
+		num_segments++;
+		FILE *initrd_file = fopen(initrd_name, "rb");
+		if (!initrd_file) {
+			ERROR("could not open initrd.\n");
+			return -1;
+		}
+		fseek(initrd_file, 0, SEEK_END);
+		initrd_size = ftell(initrd_file);
+		fseek(initrd_file, 0, SEEK_SET);
+		initrd_data = malloc(initrd_size);
+		if (!initrd_data) {
+			ERROR("could not allocate memory for initrd.\n");
+			return -1;
+		}
+		if (fread(initrd_data, initrd_size, 1, initrd_file) != 1) {
+			ERROR("could not load initrd.\n");
+			return -1;
+		}
+		fclose(initrd_file);
+	}
+
+	unsigned int cmdline_size = 0;
+	if (cmdline != NULL) {
+		num_segments++;
+		cmdline_size = strlen(cmdline) + 1;
+	}
+
+	struct linux_header *hdr = (struct linux_header *)input->data;
+	unsigned int setup_size = 4 * 512;
+	if (hdr->setup_sects != 0) {
+		setup_size = (hdr->setup_sects + 1) * 512;
+	}
+
+	/* Setup parameter block. Imitate FILO. */
+	struct linux_params params;
+	params.mount_root_rdonly = hdr->root_flags;
+	params.orig_root_dev = hdr->root_dev;
+	/* Sensible video defaults. Might be overridden on runtime by coreboot tables. */
+	params.orig_video_mode = 3;
+	params.orig_video_cols = 80;
+	params.orig_video_lines = 25;
+	params.orig_video_isVGA = 1;
+	params.orig_video_points = 16;
+
+	params.loader_type = 0xff; /* Unregistered Linux loader */
+
+	if (cmdline != NULL) {
+		if (hdr->protocol_version < 0x202) {
+			params.cl_magic = CL_MAGIC_VALUE;
+			params.cl_offset = COMMAND_LINE_LOC - LINUX_PARAM_LOC;
+		} else {
+			params.cmd_line_ptr = COMMAND_LINE_LOC;
+		}
+	}
+
+	unsigned long kernel_base = 0x100000;
+	if ((hdr->protocol_version >= 0x200) && (!hdr->loadflags & 1)) {
+		kernel_base = 0x1000; /* zImage kernel */
+	}
+	/* kernel prefers an address, so listen */
+	if ((hdr->protocol_version >= 0x20a) && (!(hdr->pref_address >> 32))) {
+		kernel_base = hdr->pref_address;
+	}
+	if (hdr->protocol_version >= 0x205) {
+		params.relocatable_kernel = hdr->relocatable_kernel;
+		params.kernel_alignment = hdr->kernel_alignment;
+		if (hdr->relocatable_kernel != 0) {
+			/* 16 MB should be way outside coreboot's playground,
+			 * so if possible (relocatable kernel) use that to
+			 * avoid a trampoline copy. */
+			kernel_base = ALIGN(16*1024*1024, params.kernel_alignment);
+		}
+	}
+
+	/* We have a trampoline and use that, but it can simply use
+	 * this information for its jump to real Linux. */
+	params.kernel_start = kernel_base;
+
+	void *kernel_data = input->data + setup_size;
+	unsigned int kernel_size = input->size - setup_size;
+
+	if (initrd_data != NULL) {
+		/* TODO: this is a bit of a hack. Linux recommends to store
+		 * initrd near to end-of-mem, but that's hard to do on build
+		 * time. It definitely fails to read the image if it's too
+		 * close to the kernel, so give it some room.
+		 */
+		initrd_base = ALIGN(kernel_base + kernel_size, 16*1024*1024);
+
+		params.initrd_start = initrd_base;
+		params.initrd_size = initrd_size;
+	}
+
+	struct cbfs_payload_segment *segs;
+	unsigned long doffset = (num_segments + 1) * sizeof(*segs);
+
+	/* Allocate a block of memory to store the data in */
+	int isize = sizeof(params) + kernel_size + cmdline_size + initrd_size;
+	if (buffer_create(output, doffset + isize, input->name) != 0)
+		return -1;
+	memset(output->data, 0, output->size);
+
+	segs = (struct cbfs_payload_segment *)output->data;
+
+	/* parameter block */
+	segs[0].type = PAYLOAD_SEGMENT_DATA;
+	segs[0].load_addr = htonll(LINUX_PARAM_LOC);
+	segs[0].mem_len = htonl(sizeof(params));
+	segs[0].offset = htonl(doffset);
+
+	compress((void*)&params, sizeof(params), output->data + doffset, &cur_len);
+	segs[0].compression = htonl(algo);
+	segs[0].len = htonl(cur_len);
+
+	doffset += cur_len;
+
+	/* code block */
+	segs[1].type = PAYLOAD_SEGMENT_CODE;
+	segs[1].load_addr = htonll(kernel_base);
+	segs[1].mem_len = htonl(kernel_size);
+	segs[1].offset = htonl(doffset);
+
+	compress(kernel_data, kernel_size, output->data + doffset, &cur_len);
+	segs[1].compression = htonl(algo);
+	segs[1].len = htonl(cur_len);
+
+	doffset += cur_len;
+
+	/* trampoline */
+	extern void *trampoline_start;
+	extern long trampoline_size;
+
+	unsigned int entrypoint = 0x40000; /* TODO: any better place? */
+
+	segs[2].type = PAYLOAD_SEGMENT_CODE;
+	segs[2].load_addr = htonll(entrypoint);
+	segs[2].mem_len = htonl(trampoline_size);
+	segs[2].offset = htonl(doffset);
+
+	compress(trampoline_start, trampoline_size, output->data + doffset, &cur_len);
+	segs[2].compression = htonl(algo);
+	segs[2].len = htonl(cur_len);
+
+	doffset += cur_len;
+
+	if (cmdline_size > 0) {
+		/* command line block */
+		segs[3].type = PAYLOAD_SEGMENT_DATA;
+		segs[3].load_addr = htonll(COMMAND_LINE_LOC);
+		segs[3].mem_len = htonl(cmdline_size);
+		segs[3].offset = htonl(doffset);
+
+		compress(cmdline, cmdline_size, output->data + doffset, &cur_len);
+		segs[3].compression = htonl(algo);
+		segs[3].len = htonl(cur_len);
+
+		doffset += cur_len;
+	}
+
+	if (initrd_size > 0) {
+		/* setup block */
+		segs[num_segments-1].type = PAYLOAD_SEGMENT_DATA;
+		segs[num_segments-1].load_addr = htonll(initrd_base);
+		segs[num_segments-1].mem_len = htonl(initrd_size);
+		segs[num_segments-1].offset = htonl(doffset);
+
+		compress(initrd_data, initrd_size, output->data + doffset, &cur_len);
+		segs[num_segments-1].compression = htonl(algo);
+		segs[num_segments-1].len = htonl(cur_len);
+
+		doffset += cur_len;
+	}
+
+	/* prepare entry point segment */
+	segs[num_segments].type = PAYLOAD_SEGMENT_ENTRY;
+	segs[num_segments].load_addr = htonll(entrypoint);
+	output->size = doffset;
+
+	return 0;
+}
+
+
diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c
index fc49ed2..34002a9 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -57,6 +57,9 @@ static struct param {
 	uint32_t top_aligned;
 	int fit_empty_entries;
 	comp_algo algo;
+	/* for linux payloads */
+	char *initrd;
+	char *cmdline;
 } param = {
 	/* All variables not listed are initialized as zero. */
 	.algo = CBFS_COMPRESS_NONE,
@@ -194,6 +197,11 @@ static int cbfstool_convert_mkpayload(struct buffer *buffer, uint32_t *offset) {
 	if (ret != 0)
 		ret = parse_fv_to_payload(buffer, &output, param.algo);
 
+	/* If it's neither ELF nor UEFI Fv, try bzImage */
+	if (ret != 0)
+		ret = parse_bzImage_to_payload(buffer, &output,
+				param.initrd, param.cmdline, param.algo);
+
 	/* Not a supported payload type */
 	if (ret != 0) {
 		ERROR("Not a supported payload type (ELF / FV).\n");
@@ -502,7 +510,7 @@ static int cbfs_update_fit(void)
 
 static const struct command commands[] = {
 	{"add", "f:n:t:b:vh?", cbfs_add},
-	{"add-payload", "f:n:t:c:b:vh?", cbfs_add_payload},
+	{"add-payload", "f:n:t:c:b:vh?C:I:", cbfs_add_payload},
 	{"add-stage", "f:n:t:c:b:vh?", cbfs_add_stage},
 	{"add-flat-binary", "f:n:l:e:c:b:vh?", cbfs_add_flat_binary},
 	{"add-int", "i:n:b:vh?", cbfs_add_integer},
@@ -531,6 +539,8 @@ static struct option long_options[] = {
 	{"int",          required_argument, 0, 'i' },
 	{"machine",      required_argument, 0, 'm' },
 	{"empty-fits",   required_argument, 0, 'x' },
+	{"initrd",       required_argument, 0, 'I' },
+	{"cmdline",      required_argument, 0, 'C' },
 	{"verbose",      no_argument,       0, 'v' },
 	{"help",         no_argument,       0, 'h' },
 	{NULL,           0,                 0,  0  }
@@ -550,6 +560,7 @@ static void usage(char *name)
 			"Add a component\n"
 	     " add-payload -f FILE -n NAME [-c compression] [-b base]      "
 			"Add a payload to the ROM\n"
+	     "        (linux specific: [-C cmdline] [-I initrd])\n"
 	     " add-stage -f FILE -n NAME [-c compression] [-b base]        "
 			"Add a stage to the ROM\n"
 	     " add-flat-binary -f FILE -n NAME -l load-address \\\n"
@@ -691,6 +702,12 @@ int main(int argc, char **argv)
 			case 'm':
 				arch = string_to_arch(optarg);
 				break;
+			case 'I':
+				param.initrd = optarg;
+				break;
+			case 'C':
+				param.cmdline = optarg;
+				break;
 			case 'h':
 			case '?':
 				usage(argv[0]);
diff --git a/util/cbfstool/common.h b/util/cbfstool/common.h
index e197143..6e12fcb 100644
--- a/util/cbfstool/common.h
+++ b/util/cbfstool/common.h
@@ -102,6 +102,9 @@ int parse_elf_to_payload(const struct buffer *input,
 			 struct buffer *output, comp_algo algo);
 int parse_fv_to_payload(const struct buffer *input,
 			 struct buffer *output, comp_algo algo);
+int parse_bzImage_to_payload(const struct buffer *input,
+			     struct buffer *output, const char *initrd,
+			     char *cmdline, comp_algo algo);
 int parse_flat_binary_to_payload(const struct buffer *input,
 				 struct buffer *output,
 				 uint32_t loadaddress,
diff --git a/util/cbfstool/linux.h b/util/cbfstool/linux.h
new file mode 100644
index 0000000..20837e3
--- /dev/null
+++ b/util/cbfstool/linux.h
@@ -0,0 +1,191 @@
+/*
+ * This file is part of coreboot..
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Linux/i386 loader
+ * Supports bzImage, zImage and Image format.
+ *
+ * Based on work by Steve Gehlbach.
+ * Portions are taken from mkelfImage.
+ *
+ * 2003-09 by SONE Takeshi
+ */
+
+#include <stdint.h>
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+#define LINUX_PARAM_LOC 0x90000
+#define COMMAND_LINE_LOC 0x91000
+#define GDT_LOC 0x92000
+#define STACK_LOC 0x93000
+
+#define E820MAX	32		/* number of entries in E820MAP */
+struct e820entry {
+	unsigned long long addr;	/* start of memory segment */
+	unsigned long long size;	/* size of memory segment */
+	unsigned long type;	/* type of memory segment */
+#define E820_RAM	1
+#define E820_RESERVED	2
+#define E820_ACPI	3	/* usable as RAM once ACPI tables have been read */
+#define E820_NVS	4
+};
+
+/* The header of Linux/i386 kernel */
+struct linux_header {
+	u8 reserved1[0x1f1];	/* 0x000 */
+	u8 setup_sects;		/* 0x1f1 */
+	u16 root_flags;		/* 0x1f2 */
+	u32 syssize;		/* 0x1f4 (2.04+) */
+	u8 reserved2[2];	/* 0x1f8 */
+	u16 vid_mode;		/* 0x1fa */
+	u16 root_dev;		/* 0x1fc */
+	u16 boot_sector_magic;	/* 0x1fe */
+	/* 2.00+ */
+	u8 reserved3[2];	/* 0x200 */
+	u8 header_magic[4];	/* 0x202 */
+	u16 protocol_version;	/* 0x206 */
+	u32 realmode_swtch;	/* 0x208 */
+	u16 start_sys;		/* 0x20c */
+	u16 kver_addr;		/* 0x20e */
+	u8 type_of_loader;	/* 0x210 */
+	u8 loadflags;		/* 0x211 */
+	u16 setup_move_size;	/* 0x212 */
+	u32 code32_start;	/* 0x214 */
+	u32 ramdisk_image;	/* 0x218 */
+	u32 ramdisk_size;	/* 0x21c */
+	u8 reserved4[4];	/* 0x220 */
+	/* 2.01+ */
+	u16 heap_end_ptr;	/* 0x224 */
+	u8 reserved5[2];	/* 0x226 */
+	/* 2.02+ */
+	u32 cmd_line_ptr;	/* 0x228 */
+	/* 2.03+ */
+	u32 initrd_addr_max;	/* 0x22c */
+	/* 2.05+ */
+	u32 kernel_alignment;	/* 0x230 */
+	u8 relocatable_kernel;	/* 0x234 */
+	u8 min_alignment;	/* 0x235 (2.10+) */
+	u8 reserved6[2];	/* 0x236 */
+	/* 2.06+ */
+	u32 cmdline_size;	/* 0x238 */
+	/* 2.07+ */
+	u32 hardware_subarch;	/* 0x23c */
+	u64 hardware_subarch_data;/* 0x240 */
+	/* 2.08+ */
+	u32 payload_offset;	/* 0x248 */
+	u32 payload_length;	/* 0x24c */
+	/* 2.09+ */
+	u64 setup_data;		/* 0x250 */
+	/* 2.10+ */
+	u64 pref_address;	/* 0x258 */
+	u32 init_size;		/* 0x260 */
+} __attribute__ ((packed));
+
+/* Paramters passed to 32-bit part of Linux
+ * This is another view of the structure above.. */
+struct linux_params {
+	u8 orig_x;		/* 0x00 */
+	u8 orig_y;		/* 0x01 */
+	u16 ext_mem_k;		/* 0x02 -- EXT_MEM_K sits here */
+	u16 orig_video_page;	/* 0x04 */
+	u8 orig_video_mode;	/* 0x06 */
+	u8 orig_video_cols;	/* 0x07 */
+	u16 unused2;		/* 0x08 */
+	u16 orig_video_ega_bx;	/* 0x0a */
+	u16 unused3;		/* 0x0c */
+	u8 orig_video_lines;	/* 0x0e */
+	u8 orig_video_isVGA;	/* 0x0f */
+	u16 orig_video_points;	/* 0x10 */
+
+	/* VESA graphic mode -- linear frame buffer */
+	u16 lfb_width;		/* 0x12 */
+	u16 lfb_height;		/* 0x14 */
+	u16 lfb_depth;		/* 0x16 */
+	u32 lfb_base;		/* 0x18 */
+	u32 lfb_size;		/* 0x1c */
+	u16 cl_magic;		/* 0x20 */
+#define CL_MAGIC_VALUE 0xA33F
+	u16 cl_offset;		/* 0x22 */
+	u16 lfb_linelength;	/* 0x24 */
+	u8 red_size;		/* 0x26 */
+	u8 red_pos;		/* 0x27 */
+	u8 green_size;		/* 0x28 */
+	u8 green_pos;		/* 0x29 */
+	u8 blue_size;		/* 0x2a */
+	u8 blue_pos;		/* 0x2b */
+	u8 rsvd_size;		/* 0x2c */
+	u8 rsvd_pos;		/* 0x2d */
+	u16 vesapm_seg;		/* 0x2e */
+	u16 vesapm_off;		/* 0x30 */
+	u16 pages;		/* 0x32 */
+	u8 reserved4[12];	/* 0x34 -- 0x3f reserved for future expansion */
+
+	//struct apm_bios_info apm_bios_info;   /* 0x40 */
+	u8 apm_bios_info[0x40];
+	//struct drive_info_struct drive_info;  /* 0x80 */
+	u8 drive_info[0x20];
+	//struct sys_desc_table sys_desc_table; /* 0xa0 */
+	u8 sys_desc_table[0x140];
+	u32 alt_mem_k;		/* 0x1e0 */
+	u8 reserved5[4];	/* 0x1e4 */
+	u8 e820_map_nr;		/* 0x1e8 */
+	u8 reserved6[9];	/* 0x1e9 */
+	u16 mount_root_rdonly;	/* 0x1f2 */
+	u8 reserved7[4];	/* 0x1f4 */
+	u16 ramdisk_flags;	/* 0x1f8 */
+#define RAMDISK_IMAGE_START_MASK  	0x07FF
+#define RAMDISK_PROMPT_FLAG		0x8000
+#define RAMDISK_LOAD_FLAG		0x4000
+	u8 reserved8[2];	/* 0x1fa */
+	u16 orig_root_dev;	/* 0x1fc */
+	u8 reserved9[1];	/* 0x1fe */
+	u8 aux_device_info;	/* 0x1ff */
+	u8 reserved10[2];	/* 0x200 */
+	u8 param_block_signature[4];	/* 0x202 */
+	u16 param_block_version;	/* 0x206 */
+	u8 reserved11[8];	/* 0x208 */
+	u8 loader_type;		/* 0x210 */
+#define LOADER_TYPE_LOADLIN         1
+#define LOADER_TYPE_BOOTSECT_LOADER 2
+#define LOADER_TYPE_SYSLINUX        3
+#define LOADER_TYPE_ETHERBOOT       4
+#define LOADER_TYPE_KERNEL          5
+	u8 loader_flags;	/* 0x211 */
+	u8 reserved12[2];	/* 0x212 */
+	u32 kernel_start;	/* 0x214 */
+	u32 initrd_start;	/* 0x218 */
+	u32 initrd_size;	/* 0x21c */
+	u8 reserved12_5[8];	/* 0x220 */
+	u32 cmd_line_ptr;	/* 0x228 */
+	u32 initrd_addr_max;	/* 0x22c */
+	u32 kernel_alignment;	/* 0x230 */
+	u8 relocatable_kernel;	/* 0x234 */
+	u8 reserved13[155];		/* 0x22c */
+	struct e820entry e820_map[E820MAX];	/* 0x2d0 */
+	u8 reserved16[688];	/* 0x550 */
+#define COMMAND_LINE_SIZE 256
+	/* Command line is copied here by 32-bit i386/kernel/head.S.
+	 * So I will follow the boot protocol, rather than putting it
+	 * directly here. --ts1 */
+	u8 command_line[COMMAND_LINE_SIZE];	/* 0x800 */
+	u8 reserved17[1792];	/* 0x900 - 0x1000 */
+};
+
diff --git a/util/cbfstool/linux_trampoline.c b/util/cbfstool/linux_trampoline.c
new file mode 100644
index 0000000..79d1576
--- /dev/null
+++ b/util/cbfstool/linux_trampoline.c
@@ -0,0 +1,141 @@
+/*
+ * linux_trampoline
+ *
+ * Copyright (C) 2013 Patrick Georgi <patrick at georgi-clan.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
+ */
+
+#if 0
+/* NOTE: THIS CODE MUST REMAIN POSITION INDEPENDENT
+ *       IT SHOULDN'T USE THE STACK
+ *       AND IN GENERAL EXPECT NOTHING BUT RAM TO WORK
+ */
+.code32
+.data
+#define HEADER_SIG 0x4f49424c // LBIO little endian
+#define CB_TAG_FORWARD 0x11
+#define CB_TAG_MEMORY 0x1
+#define CB_TAG_FRAMEBUFFER 0x12
+
+#define LINUX_PARAM_LOC 0x90000
+#define E820_NR_OFFSET 0x1e8
+#define LINUX_ENTRY_OFFSET 0x214
+#define E820_OFFSET 0x2d0
+
+.trampoline_start:
+
+cld
+xor %edx, %edx
+mov $0, %ecx
+
+.headerSearch:
+mov $0x10000, %ebx
+add %ecx, %ebx
+mov (%ecx), %eax
+cmp $HEADER_SIG, %eax
+je .headerSearchDone // found the header
+add $16, %ecx
+cmp %ecx, %ebx
+jne .headerSearch
+
+.headerSearchDone:
+cmp %ecx, %ebx // reached the end == not found anything?
+je 2f // give up
+
+// we assume the checksum is okay, no test
+mov 4(%ecx), %ebx
+add %ecx, %ebx // ebx = cb_header + header_bytes
+mov 20(%ecx), %ecx // ecx = table_entries
+
+.tableScan:
+cmp $CB_TAG_FORWARD, (%ebx)
+jne .testMemory
+
+/* forward tag: assume 32bit pointer */
+mov 8(%ebx), %ecx
+jmp .headerSearch
+
+.testMemory:
+cmp $CB_TAG_MEMORY, (%ebx)
+jne .testFramebuffer
+
+/* memory tag: copy e820 map and entry count. also determine alt_mem_k */
+mov 4(%ebx), %eax
+sub $8, %eax
+shr $2, %eax /* eax = number of dwords of e820 data */
+cmp $(32 * 5), %eax /* linux wants at most 32 entries of 5 dwords */
+jng 1f
+mov $(32 * 5), %eax /* only copy 32 entries */
+1:
+mov %eax, %esi
+mov $5, %edi
+div %edi
+mov %eax, (LINUX_PARAM_LOC + E820_NR_OFFSET)
+mov %esi, %eax
+xchg %eax, %ecx
+lea 8(%ebx), %esi /* e820 data source */
+mov $(LINUX_PARAM_LOC + E820_OFFSET), %edi
+rep movsl
+xchg %eax, %ecx
+jmp .endScan
+
+.testFramebuffer:
+cmp $CB_TAG_FRAMEBUFFER, (%ebx)
+jne .endScan
+/* TODO: handle framebuffer tag */
+
+.endScan:
+add 4(%ebx), %ebx
+dec %ecx
+jnz .tableScan
+
+/* finally: jump to kernel */
+mov $LINUX_PARAM_LOC, %esi
+jmp *(LINUX_PARAM_LOC + LINUX_ENTRY_OFFSET)
+
+
+2:
+hlt
+jmp 2b
+
+.trampoline_end:
+
+.global trampoline_start, trampoline_size
+trampoline_start:
+.long .trampoline_start
+trampoline_size:
+.long .trampoline_end - .trampoline_start
+#endif
+
+/* The code above is hand-crafted to fit various contraints.
+ * To simplify porting, the below matches the above.
+ * When changing any code in here, compile the above as a .S
+ * file, objcopy it to binary and paste the result below (minus
+ * the last 8 bytes which are trampoline_start and trampoline_size).
+ */
+const unsigned char trampoline[] = {
+0xfc, 0x31, 0xd2, 0xb9, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x01, 0x00, 0x01, 0xcb, 0x8b,
+0x01, 0x3d, 0x4c, 0x42, 0x49, 0x4f, 0x74, 0x07, 0x83, 0xc1, 0x10, 0x39, 0xcb, 0x75, 0xe9, 0x39,
+0xcb, 0x74, 0x60, 0x8b, 0x59, 0x04, 0x01, 0xcb, 0x8b, 0x49, 0x14, 0x83, 0x3b, 0x11, 0x75, 0x05,
+0x8b, 0x4b, 0x08, 0xeb, 0xd3, 0x83, 0x3b, 0x01, 0x75, 0x33, 0x8b, 0x43, 0x04, 0x83, 0xe8, 0x08,
+0xc1, 0xe8, 0x02, 0x3d, 0xa0, 0x00, 0x00, 0x00, 0x7e, 0x05, 0xb8, 0xa0, 0x00, 0x00, 0x00, 0x89,
+0xc6, 0xbf, 0x05, 0x00, 0x00, 0x00, 0xf7, 0xf7, 0xa3, 0xe8, 0x01, 0x09, 0x00, 0x89, 0xf0, 0x91,
+0x8d, 0x73, 0x08, 0xbf, 0xd0, 0x02, 0x09, 0x00, 0xf3, 0xa5, 0x91, 0xeb, 0x05, 0x83, 0x3b, 0x12,
+0x75, 0x00, 0x03, 0x5b, 0x04, 0x49, 0x75, 0xb3, 0xbe, 0x00, 0x00, 0x09, 0x00, 0xff, 0x25, 0x14,
+0x02, 0x09, 0x00, 0xf4, 0xeb, 0xfd
+};
+
+void * const trampoline_start = &trampoline;
+const unsigned long trampoline_size = sizeof trampoline;



More information about the coreboot-gerrit mailing list