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@secunet.com> Signed-off-by: Patrick Georgi <patrick@georgi-clan.de> Reviewed-on: http://review.coreboot.org/3302 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
@ -12,6 +12,8 @@ COMMON+=cbfs-mkstage.o cbfs-mkpayload.o
|
|||||||
COMMON+=lzma/lzma.o
|
COMMON+=lzma/lzma.o
|
||||||
COMMON+=lzma/C/LzFind.o lzma/C/LzmaDec.o lzma/C/LzmaEnc.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))
|
COMMON:=$(addprefix $(obj)/,$(COMMON))
|
||||||
|
|
||||||
all: dep $(BINARY)
|
all: dep $(BINARY)
|
||||||
|
@ -11,6 +11,9 @@ cbfsobj += lzma.o
|
|||||||
cbfsobj += LzFind.o
|
cbfsobj += LzFind.o
|
||||||
cbfsobj += LzmaDec.o
|
cbfsobj += LzmaDec.o
|
||||||
cbfsobj += LzmaEnc.o
|
cbfsobj += LzmaEnc.o
|
||||||
|
# linux as payload
|
||||||
|
cbfsobj += linux_trampoline.o
|
||||||
|
cbfsobj += cbfs-payload-linux.o
|
||||||
|
|
||||||
CBFSTOOLFLAGS=-D_7ZIP_ST -g
|
CBFSTOOLFLAGS=-D_7ZIP_ST -g
|
||||||
|
|
||||||
|
@ -377,3 +377,4 @@ int parse_fv_to_payload(const struct buffer *input,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
238
util/cbfstool/cbfs-payload-linux.c
Normal file
238
util/cbfstool/cbfs-payload-linux.c
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
* cbfs-payload-linux
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Patrick Georgi <patrick@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*)¶ms, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -57,6 +57,9 @@ static struct param {
|
|||||||
uint32_t top_aligned;
|
uint32_t top_aligned;
|
||||||
int fit_empty_entries;
|
int fit_empty_entries;
|
||||||
comp_algo algo;
|
comp_algo algo;
|
||||||
|
/* for linux payloads */
|
||||||
|
char *initrd;
|
||||||
|
char *cmdline;
|
||||||
} param = {
|
} param = {
|
||||||
/* All variables not listed are initialized as zero. */
|
/* All variables not listed are initialized as zero. */
|
||||||
.algo = CBFS_COMPRESS_NONE,
|
.algo = CBFS_COMPRESS_NONE,
|
||||||
@ -194,6 +197,11 @@ static int cbfstool_convert_mkpayload(struct buffer *buffer, uint32_t *offset) {
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
ret = parse_fv_to_payload(buffer, &output, param.algo);
|
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 */
|
/* Not a supported payload type */
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
ERROR("Not a supported payload type (ELF / FV).\n");
|
ERROR("Not a supported payload type (ELF / FV).\n");
|
||||||
@ -502,7 +510,7 @@ static int cbfs_update_fit(void)
|
|||||||
|
|
||||||
static const struct command commands[] = {
|
static const struct command commands[] = {
|
||||||
{"add", "f:n:t:b:vh?", cbfs_add},
|
{"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-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-flat-binary", "f:n:l:e:c:b:vh?", cbfs_add_flat_binary},
|
||||||
{"add-int", "i:n:b:vh?", cbfs_add_integer},
|
{"add-int", "i:n:b:vh?", cbfs_add_integer},
|
||||||
@ -531,6 +539,8 @@ static struct option long_options[] = {
|
|||||||
{"int", required_argument, 0, 'i' },
|
{"int", required_argument, 0, 'i' },
|
||||||
{"machine", required_argument, 0, 'm' },
|
{"machine", required_argument, 0, 'm' },
|
||||||
{"empty-fits", required_argument, 0, 'x' },
|
{"empty-fits", required_argument, 0, 'x' },
|
||||||
|
{"initrd", required_argument, 0, 'I' },
|
||||||
|
{"cmdline", required_argument, 0, 'C' },
|
||||||
{"verbose", no_argument, 0, 'v' },
|
{"verbose", no_argument, 0, 'v' },
|
||||||
{"help", no_argument, 0, 'h' },
|
{"help", no_argument, 0, 'h' },
|
||||||
{NULL, 0, 0, 0 }
|
{NULL, 0, 0, 0 }
|
||||||
@ -550,6 +560,7 @@ static void usage(char *name)
|
|||||||
"Add a component\n"
|
"Add a component\n"
|
||||||
" add-payload -f FILE -n NAME [-c compression] [-b base] "
|
" add-payload -f FILE -n NAME [-c compression] [-b base] "
|
||||||
"Add a payload to the ROM\n"
|
"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-stage -f FILE -n NAME [-c compression] [-b base] "
|
||||||
"Add a stage to the ROM\n"
|
"Add a stage to the ROM\n"
|
||||||
" add-flat-binary -f FILE -n NAME -l load-address \\\n"
|
" add-flat-binary -f FILE -n NAME -l load-address \\\n"
|
||||||
@ -691,6 +702,12 @@ int main(int argc, char **argv)
|
|||||||
case 'm':
|
case 'm':
|
||||||
arch = string_to_arch(optarg);
|
arch = string_to_arch(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'I':
|
||||||
|
param.initrd = optarg;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
param.cmdline = optarg;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
|
@ -102,6 +102,9 @@ int parse_elf_to_payload(const struct buffer *input,
|
|||||||
struct buffer *output, comp_algo algo);
|
struct buffer *output, comp_algo algo);
|
||||||
int parse_fv_to_payload(const struct buffer *input,
|
int parse_fv_to_payload(const struct buffer *input,
|
||||||
struct buffer *output, comp_algo algo);
|
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,
|
int parse_flat_binary_to_payload(const struct buffer *input,
|
||||||
struct buffer *output,
|
struct buffer *output,
|
||||||
uint32_t loadaddress,
|
uint32_t loadaddress,
|
||||||
|
191
util/cbfstool/linux.h
Normal file
191
util/cbfstool/linux.h
Normal file
@ -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 */
|
||||||
|
};
|
||||||
|
|
141
util/cbfstool/linux_trampoline.c
Normal file
141
util/cbfstool/linux_trampoline.c
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* linux_trampoline
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Patrick Georgi <patrick@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;
|
Reference in New Issue
Block a user