linux_load.c revision 677833bc953b6cb418c701facbdcf4aa18d6c44e
/*
* Supports bzImage, zImage and Image format.
*
* Based on work by Steve Gehlbach.
* Portions are taken from mkelfImage.
*
* 2003-09 by SONE Takeshi
*/
#include <etherboot.h>
#include <lib.h>
#include <fs.h>
#include <sys_info.h>
#include "context.h"
#include "segment.h"
#define DEBUG_THIS DEBUG_LINUXLOAD
#include <debug.h>
#define LINUX_PARAM_LOC 0x90000
#define COMMAND_LINE_LOC 0x91000
#define GDT_LOC 0x92000
#define STACK_LOC 0x93000
struct linux_header {
/* 2.00+ */
/* 2.01+ */
/* 2.02+ */
/* 2.03+ */
} __attribute__ ((packed));
/* Paramters passed to 32-bit part of Linux
* This is another view of the structure above.. */
struct linux_params {
/* VESA graphic mode -- linear frame buffer */
#define CL_MAGIC_VALUE 0xA33F
//struct apm_bios_info apm_bios_info; /* 0x40 */
//struct drive_info_struct drive_info; /* 0x80 */
//struct sys_desc_table sys_desc_table; /* 0xa0 */
#define RAMDISK_IMAGE_START_MASK 0x07FF
#define RAMDISK_PROMPT_FLAG 0x8000
#define RAMDISK_LOAD_FLAG 0x4000
#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
#define COMMAND_LINE_SIZE 256
* So I will follow the boot protocol, rather than putting it
* directly here. --ts1 */
};
/* Load the first part the file and check if it's Linux */
{
int load_high;
debug("Can't read Linux header\n");
return 0;
}
debug("Not a Linux kernel image\n");
return 0;
}
/* Linux is found. Print some information */
/* This may be floppy disk image or something.
* Perform a simple (incomplete) sanity check. */
debug("This looks like a bootdisk image but not like Linux...\n");
return 0;
}
debugx("Possible very old Linux");
/* This kernel does not even have a protocol version.
* Force the value. */
} else
printf("Found Linux");
char kver[256];
kver[255] = 0;
}
}
load_high = 0;
}
if (load_high) {
printf(" bzImage");
kern_addr = 0x100000;
} else {
printf(" zImage or Image");
kern_addr = 0x1000;
}
printf(".\n");
return kern_addr;
}
/* Set up parameters for 32-bit kernel */
static void
{
/* Copy some useful values from header */
/* Video parameters.
* This assumes we have VGA in standard 80x25 text mode,
* just like our vga.c does.
* Cursor position is filled later to allow some more printf's. */
}
/* Memory map */
static void
{
uint32_t i;
if (i < E820MAX) {
/* Convert to BIOS e820 style */
// debug("%016Lx - %016Lx\n", linux_map->addr,linux_map->addr + linux_map->size);
}
}
/* Size of memory above 1MB in KB */
/* old style, 64MB max */
else
}
/*
* Parse command line
* Some parameters, like initrd=<file>, are not passed to kernel,
* we are responsible to process them.
* Parameters for kernel are copied to kern_cmdline. Returns name of initrd.
*/
{
char name[64];
int len;
int k_len;
int to_kern;
char *initrd = 0;
int toolong = 0;
forced_memsize = 0;
if (!orig_cmdline) {
*kern_cmdline = 0;
return 0;
}
k_len = 0;
while (*start == ' ')
start++;
while (*start) {
if (!end)
if (*sep == '=') {
} else {
val = 0;
len = 0;
}
/* Only initrd= and mem= are handled here. vga= is not,
* which I believe is a paramter to the realmode part of Linux,
* which we don't execute. */
if (!val)
printf("Missing filename to initrd parameter\n");
else {
}
/* Don't pass this to kernel */
to_kern = 0;
if (!val)
printf("Missing value for mem parameter\n");
else {
if (forced_memsize == 0)
printf("Invalid mem option, ignored\n");
printf("Garbage after mem=<size>, ignored\n");
forced_memsize = 0;
}
// debug("mem=%Lu\n", forced_memsize);
}
/* mem= is for both loader and kernel */
to_kern = 1;
} else
to_kern = 1;
if (to_kern) {
/* Copy to kernel command line buffer */
if (k_len != 0)
if (!toolong) {
printf("Kernel command line is too long; truncated to "
toolong = 1;
}
}
}
while (*start == ' ')
start++;
}
kern_cmdline[k_len] = 0;
return initrd;
}
/* Set command line location */
struct linux_header *hdr)
{
/* new style */
} else {
/* old style */
}
}
/* Load 32-bit part of kernel */
{
if (hdr->setup_sects == 0)
if (using_devsize) {
printf("Attempt to load up to end of device as kernel; "
"specify the image size\n");
return 0;
}
printf("Loading kernel... ");
printf("Can't read kernel\n");
return 0;
}
printf("ok\n");
return kern_size;
}
{
extern char _virt_start[], _end[];
if (!file_open(initrd_file)) {
return -1;
}
if (using_devsize) {
printf("Attempt to load up to end of device as initrd; "
"specify the image size\n");
return -1;
}
/* Find out the kernel's restriction on how high the initrd can be
* placed */
else
/* FILO itself is at the top of RAM. (relocated)
* So, try putting initrd just below us. */
/* If "mem=" option is given, we have to put the initrd within
* the specified range. */
if (forced_memsize) {
/* If the "mem=" is lower, it's easy */
else {
/* Otherwise, see if we can put it above us */
}
}
printf("Initrd is too big\n");
return -1;
}
printf("Loading initrd... ");
printf("Can't read initrd\n");
return -1;
}
printf("ok\n");
return 0;
}
static void hardware_setup(void)
{
/* Disable nmi */
/* Make sure any coprocessor is properly reset.. */
outb(0, 0xf0);
outb(0, 0xf1);
/* we're getting screwed again and again by this problem of the 8259.
* so we're going to leave this lying around for inclusion into
* crt0.S on an as-needed basis.
*
* well, that went ok, I hope. Now we have to reprogram the interrupts :-(
* we put them right after the intel-reserved hardware interrupts, at
* int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
* messed this up with the original PC, and they haven't been able to
* rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
* which is used for the internal hardware interrupts as well. We just
* have to reprogram the 8259's, and it isn't fun.
*/
}
/* Start Linux */
{
struct segment_desc *linux_gdt;
#if 0
#endif
/* Linux expects GDT being in low memory */
/* 2.6 kernel uses 12 and 13, but head.S uses backward-compatible
* segments (2 and 3), so it SHOULD not be a problem.
* However, some distro kernels (eg. RH9) with backported threading
* patch use 12 and 13 also when booting... */
/* Parameter location */
/* Entry point */
printf("Jumping to entry point...\n");
#ifdef VGA_CONSOLE
/* Update VGA cursor position.
* This must be here because the printf changes the value! */
#if 0
#endif
#endif
/* Go... */
/* It's impossible but... */
}
{
struct linux_header hdr;
struct linux_params *params;
char *initrd_file = 0;
return -1;
if (kern_addr == 0)
return LOADER_NOT_SUPPORT;
if (kern_size == 0) {
if (initrd_file)
return -1;
}
if (initrd_file) {
!= 0) {
return -1;
}
}
return 0;
}