aboutsummaryrefslogtreecommitdiffstats
path: root/tools/misc/mbootpack/mbootpack.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/misc/mbootpack/mbootpack.c')
-rw-r--r--tools/misc/mbootpack/mbootpack.c706
1 files changed, 0 insertions, 706 deletions
diff --git a/tools/misc/mbootpack/mbootpack.c b/tools/misc/mbootpack/mbootpack.c
deleted file mode 100644
index 3e4cd51a99..0000000000
--- a/tools/misc/mbootpack/mbootpack.c
+++ /dev/null
@@ -1,706 +0,0 @@
-/*
- * mbootpack.c
- *
- * Takes a multiboot image, command-line and modules, and repackages
- * them as if they were a linux kernel. Only supports a subset of
- * the multiboot info page options (enough to boot the Xen hypervisor).
- *
- * Copyright (C) 2003-2004 Tim Deegan (tjd21@cl.cam.ac.uk)
- *
- * Parts based on GNU GRUB, Copyright (C) 2000 Free Software Foundation, Inc
- *
- * 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; either version 2 of the
- * License, or (at your option) any later version.
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * $Id: mbootpack.c,v 1.3 2005/03/23 10:38:36 tjd21 Exp tjd21 $
- *
- */
-
-#define _GNU_SOURCE
-#include "mbootpack.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <getopt.h>
-#include <elf.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <asm/page.h>
-
-/* From GNU GRUB */
-#include "mb_header.h"
-#include "mb_info.h"
-
-
-/*
- * The plan: Marshal up the multiboot modules and strings as if we
- * were loading them into memory on a fresh ix86 PC. Attach
- * a linux bzImage header to the front, which sets up the machine
- * appropriately and then jumps to the kernel entry address.
- *
- * The memory map will be made up roughly like so:
- *
- * =============
- * multiboot information (mbi) struct
- * -------
- * kernel command line
- * -------
- * bootloader name
- * -------
- * module command lines
- * -------
- * module information structs
- * =============
- * (memory hole)
- * =============
- * kernel
- * -------------
- * module 1
- * -------------
- * module 2
- * -------------
- * .
- * .
- * .
- *
- * ==============
- *
- *
- * For allocation of memory we assume that the target machine has 'low'
- * memory from 0 to 640K and 'high' memory starting at 1M. We allocate
- * the kernel first, wherever it wants to be. After that, sections
- * are added at the next available aligned address, always in the order
- * given above, and skipping the memory hole at 640K. Allocated sections
- * are stored in a linked list of buffers.
- *
- * Re-packaging as a bzImage file happens in buildimage.c
- *
- */
-
-/* Version */
-static const char version_string[] = "mbootpack " MBOOTPACK_VERSION_STRING;
-
-/* Flags */
-int quiet = 0;
-
-/* How much of the start of a kernel we read looking for headers.
- * Must be >= MULTIBOOT_SEARCH */
-#define HEADERBUF_SIZE MULTIBOOT_SEARCH
-
-
-/* Linked list of loaded sections, and a pointer to the next
- * available space (i.e. just above the highest allocation so far). */
-static section_t *sections = NULL;
-static section_t *last_section = NULL;
-static address_t next_free_space = 0;
-
-static void usage(void)
-/* If we don't understand the command-line options */
-{
- printf(
-"Usage: mbpack [OPTIONS] kernel-image\n\n"
-" -h --help Print this text.\n"
-" -q --quiet Only output errors and warnings.\n"
-" -o --output=filename Output to filename (default \"bzImage\").\n"
-" -M --multiboot-output Produce a multiboot kernel, not a bzImage\n"
-" (sets default output file to \"mbImage\").\n"
-" -c --command-line=STRING Set the kernel command line (DEPRECATED!).\n"
-" -m --module=\"MOD arg1 arg2...\" Load module MOD with arguments \"arg1...\"\n"
-" (can be used multiple times).\n"
-"\n");
- exit(1);
-}
-
-
-static void place_kernel_section(address_t start, long int size)
-/* Place the kernel in memory, checking for the memory hole. */
-{
- if (start >= MEM_HOLE_END) {
- /* Above the memory hole: easy */
- next_free_space = MAX(next_free_space, start + size);
- if (!quiet) {
- printf("Placed kernel section (%p+%p)\n", start, size);
- }
- return;
- }
-
- if (start >= MEM_HOLE_START) {
- /* In the memory hole. Not so good */
- printf("Fatal: kernel load address (%p) is in the memory hole.\n",
- start);
- exit(1);
- }
-
- if (start + size > MEM_HOLE_START) {
- /* Too big for low memory */
- printf("Fatal: kernel (%p+%p) runs into the memory hole.\n",
- start, size);
- exit(1);
- }
-
- /* Kernel loads below the memory hole */
- next_free_space = MAX(next_free_space, start + size);
-
- if (!quiet) {
- printf("Placed kernel section (%p+%p)\n", start, size);
- }
-}
-
-
-static address_t place_section(long int size, int align)
-/* Find the next available place for this section.
- * "align" must be a power of 2 */
-{
- address_t start;
- assert(next_free_space != 0);
- assert(((~align + 1) & align) == align);
-
- start = ROUNDUP_P2(next_free_space, align);
-
- /* Check that we don't hit the memory hole */
- if (start < MEM_HOLE_END && (start + size) > MEM_HOLE_START)
- start = ROUNDUP_P2(MEM_HOLE_END, align);
-
- next_free_space = start + size;
-
- if (!quiet) {
- printf("Placed section (%p+%p), align=%p\n",
- start, size, align);
- }
- return start;
-}
-
-
-
-
-static address_t load_kernel(const char *filename)
-/* Load an elf32/multiboot kernel from this file
- * Returns the entry address for the kernel. */
-{
- unsigned int i;
- address_t start;
- size_t len;
- long int size, loadsize;
- FILE *fp;
- char *buffer;
- section_t *sec, *s;
- Elf32_Ehdr *ehdr;
- Elf32_Phdr *phdr;
- struct multiboot_header *mbh;
- struct stat sb;
-
- static char headerbuf[HEADERBUF_SIZE];
-
- /* Stat and open the file */
- if (stat(filename, &sb) != 0) {
- printf("Fatal: cannot stat %s: %s\n", filename, strerror(errno));
- exit(1);
- }
- if ((fp = fopen(filename, "r")) == NULL) {
- printf("Fatal: cannot open %s: %s\n", filename, strerror(errno));
- exit(1);
- }
-
- /* Load the first 8k of the file */
- if (fseek(fp, 0, SEEK_SET) < 0) {
- printf("Fatal: seek error in %s: %s\n", filename, strerror(errno));
- exit(1);
- }
- if ((len = fread(headerbuf, 1, HEADERBUF_SIZE, fp))
- < HEADERBUF_SIZE)
- {
- if (feof(fp)) /* Short file */
- {
- if (len < 12) {
- printf("Fatal: %s is too short to be a multiboot file.",
- filename);
- exit(1);
- }
- } else {
- printf("Fatal: read error in %s: %s\n", filename, strerror(errno));
- exit(1);
- }
- }
-
- /* Sanity-check: is this file compressed? */
- if ((headerbuf[0] == '\037' &&
- (headerbuf[1] == '\235' /* .Z */ ||
- headerbuf[1] == '\213' /* .gz */)) ||
- (headerbuf[0] == 'B' && headerbuf[1] == 'Z') /* .bz[2] */) {
- printf("Warning: %s looks like a compressed file.\n"
- " You should uncompress it first!\n", filename);
- }
-
- /* Now look for a multiboot header */
- for (i = 0; i <= MIN(len - 12, MULTIBOOT_SEARCH - 12); i += 4)
- {
- mbh = (struct multiboot_header *)(headerbuf + i);
- if (eswap(mbh->magic) != MULTIBOOT_MAGIC
- || ((eswap(mbh->magic)+eswap(mbh->flags)+eswap(mbh->checksum))
- & 0xffffffff))
- {
- /* Not a multiboot header */
- continue;
- }
- if (eswap(mbh->flags) & MULTIBOOT_UNSUPPORTED) {
- /* Requires options we don't support */
- printf("Fatal: found a multiboot header, but it "
- "requires multiboot options that I\n"
- "don't understand. Sorry.\n");
- exit(1);
- }
- if (eswap(mbh->flags) & MULTIBOOT_VIDEO_MODE) {
- /* Asked for screen mode information */
- /* XXX carry on regardless */
- printf("Warning: found a multiboot header which asks "
- "for screen mode information.\n"
- " This kernel will NOT be given valid"
- "screen mode information at boot time.\n");
- }
- /* This kernel will do: place and load it */
-
- if (eswap(mbh->flags) & MULTIBOOT_AOUT_KLUDGE) {
-
- /* Load using the offsets in the multiboot header */
- if(!quiet)
- printf("Loading %s using multiboot header.\n", filename);
-
- /* How much is there? */
- start = eswap(mbh->load_addr);
- if (eswap(mbh->load_end_addr) != 0)
- loadsize = eswap(mbh->load_end_addr) - eswap(mbh->load_addr);
- else
- loadsize = sb.st_size;
-
- /* How much memory will it take up? */
- if (eswap(mbh->bss_end_addr) != 0)
- size = eswap(mbh->bss_end_addr) - eswap(mbh->load_addr);
- else
- size = loadsize;
-
- if (loadsize > size) {
- printf("Fatal: can't load %i bytes of kernel into %i bytes "
- "of memory.\n", loadsize, size);
- exit(1);
- }
-
- /* Does it fit where it wants to be? */
- place_kernel_section(start, size);
-
- /* Load the kernel */
- if ((buffer = malloc(size)) == NULL) {
- printf("Fatal: malloc() for kernel load failed: %s\n",
- strerror(errno));
- exit(1);
- }
- if ((fread(buffer, loadsize, 1, fp)) != 1) {
- printf("Fatal: cannot read %s: %s\n",
- filename, strerror(errno));
- exit(1);
- }
- fclose(fp);
-
- /* Clear the kernel BSS */
- memset(buffer + loadsize, 0, size - loadsize);
-
- /* Start off the linked list of sections */
- if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) {
- printf("Fatal: malloc() for section_t failed: %s\n",
- strerror(errno));
- exit(1);
- }
- sec->buffer = buffer;
- sec->start = start;
- sec->size = size;
- sec->next = NULL;
- sec->prev = NULL;
- sections = sec;
- last_section = sec;
-
- /* Done. */
- if (!quiet) printf("Loaded kernel from %s\n", filename);
- return eswap(mbh->entry_addr);
-
- } else {
-
- /* Now look for an ELF32 header */
- ehdr = (Elf32_Ehdr *)headerbuf;
- if (*(unsigned long *)ehdr != eswap(0x464c457f)
- || ehdr->e_ident[EI_DATA] != ELFDATA2LSB
- || ehdr->e_ident[EI_CLASS] != ELFCLASS32
- || eswap(ehdr->e_machine) != EM_386)
- {
- printf("Fatal: kernel has neither ELF32/x86 nor multiboot load"
- " headers.\n");
- exit(1);
- }
- if (eswap(ehdr->e_phoff) + eswap(ehdr->e_phnum)*sizeof(*phdr)
- > HEADERBUF_SIZE) {
- /* Don't expect this will happen with sane kernels */
- printf("Fatal: too much ELF for me. Try increasing "
- "HEADERBUF_SIZE in mbootpack.\n");
- exit(1);
- }
- if (eswap(ehdr->e_phoff) + eswap(ehdr->e_phnum)*sizeof (*phdr)
- > len) {
- printf("Fatal: malformed ELF header overruns EOF.\n");
- exit(1);
- }
- if (eswap(ehdr->e_phnum) <= 0) {
- printf("Fatal: ELF kernel has no program headers.\n");
- exit(1);
- }
-
- if(!quiet)
- printf("Loading %s using ELF header.\n", filename);
-
- if (eswap(ehdr->e_type) != ET_EXEC
- || eswap(ehdr->e_version) != EV_CURRENT
- || eswap(ehdr->e_phentsize) != sizeof (Elf32_Phdr)) {
- printf("Warning: funny-looking ELF header.\n");
- }
- phdr = (Elf32_Phdr *)(headerbuf + eswap(ehdr->e_phoff));
-
- /* Obey the program headers to load the kernel */
- for(i = 0; i < eswap(ehdr->e_phnum); i++) {
-
- start = eswap(phdr[i].p_paddr);
- size = eswap(phdr[i].p_memsz);
- if (eswap(phdr[i].p_type) != PT_LOAD)
- loadsize = 0;
- else
- loadsize = MIN((long int)eswap(phdr[i].p_filesz), size);
-
- if ((buffer = malloc(size)) == NULL) {
- printf("Fatal: malloc() for kernel load failed: %s\n",
- strerror(errno));
- exit(1);
- }
-
- /* Place the section where it wants to be */
- place_kernel_section(start, size);
-
- /* Load section from file */
- if (loadsize > 0) {
- if (fseek(fp, eswap(phdr[i].p_offset), SEEK_SET) != 0) {
- printf("Fatal: seek failed in %s\n",
- strerror(errno));
- exit(1);
- }
- if ((fread(buffer, loadsize, 1, fp)) != 1) {
- printf("Fatal: cannot read %s: %s\n",
- filename, strerror(errno));
- exit(1);
- }
- }
-
- /* Clear the rest of the buffer */
- memset(buffer + loadsize, 0, size - loadsize);
-
- /* Add this section to the list (keeping it ordered) */
- if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) {
- printf("Fatal: malloc() for section_t failed: %s\n",
- strerror(errno));
- exit(1);
- }
- sec->buffer = buffer;
- sec->start = start;
- sec->size = size;
-
- for(s = sections; s; s = s->next) {
- if (s->start > start) {
- sec->next = s;
- if (s->prev == NULL) {
- /* sec becomes the new first item */
- s->prev = sec;
- sections = sec;
- } else {
- /* sec goes between s->prev and s */
- sec->prev = s->prev;
- sec->prev->next = sec;
- s->prev = sec;
- }
- break;
- }
- }
- if (s == NULL) {
- /* sec becomes the new last item */
- sec->next = NULL;
- sec->prev = last_section;
- if (last_section) {
- last_section->next = sec;
- } else {
- sections = sec;
- }
- last_section = sec;
- }
- }
-
- /* Done! */
- if (!quiet) printf("Loaded kernel from %s\n", filename);
- return eswap(ehdr->e_entry);
- }
-
- }
-
- /* This is not a multiboot kernel */
- printf("Fatal: %s is not a multiboot kernel.\n", filename);
- exit(1);
-}
-
-
-
-
-int main(int argc, char **argv)
-{
- char *buffer, *imagename, *command_line, *p;
- char *mod_filename, *mod_command_line, *mod_clp;
- char *out_filename;
- section_t *sec;
- FILE *fp;
- struct stat sb;
- struct multiboot_info *mbi;
- struct mod_list *modp;
- address_t start, kernel_entry;
- long int size, mod_command_line_space, command_line_len;
- int modules, opt, mbi_reloc_offset, make_multiboot;
-
- static const char short_options[] = "hc:m:o:qM";
- static const struct option options[] = {
- { "help", 0, 0, 'h' },
- { "command-line", 1, 0, 'c' },
- { "append", 1, 0, 'c' },
- { "module", 1, 0, 'm' },
- { "output", 1, 0, 'o' },
- { "quiet", 0, 0, 'q' },
- { 0, 0, 0, 0 },
- };
-
- /* Parse the command line */
- out_filename = NULL;
- command_line = "";
- command_line_len = 0;
- modules = 0;
- mod_command_line_space = 0;
- while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1)
- {
- switch(opt) {
- case 'c':
- command_line = optarg;
- break;
- case 'm':
- modules++;
- mod_command_line_space += strlen(optarg) + 1;
- break;
- case 'o':
- out_filename = optarg;
- break;
- case 'q':
- quiet = 1;
- break;
- case 'h':
- case '?':
- default:
- usage();
- }
- }
- imagename = argv[optind];
- if (!imagename || strlen(imagename) == 0) usage();
- command_line_len = strlen(command_line) + strlen(imagename) + 2;
- /* Leave space to overwritethe command-line at boot time */
- command_line_len = MAX(command_line_len, CMD_LINE_SPACE);
- if (!out_filename) out_filename = "bzImage";
-
- /* Place and load the kernel */
- kernel_entry = load_kernel(imagename);
- assert(sections != NULL);
- assert(last_section != NULL);
- assert(next_free_space != 0);
-
- /* Next section is all the metadata between kernel and modules */
- size = ((((sizeof (struct multiboot_info)
- + command_line_len
- + strlen(version_string) + 1
- + mod_command_line_space)
- + 3 ) & ~3)
- + modules * sizeof (struct mod_list));
- /* Locate this section after the setup sectors, in *low* memory */
- start = place_mbi(size);
-
- if ((buffer = malloc(size)) == NULL) {
- printf("Fatal: malloc() for boot metadata failed: %s\n",
- strerror(errno));
- exit(1);
- }
-
- if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) {
- printf("Fatal: malloc() for section_t failed: %s\n",
- strerror(errno));
- exit(1);
- }
- sec->buffer = buffer;
- sec->start = start;
- sec->size = size;
- sec->next = NULL;
- sec->prev = last_section;
- last_section->next = sec;
- last_section = sec;
-
- /* Multiboot info struct */
- mbi = (struct multiboot_info *)buffer;
- memset(buffer, 0, sizeof (struct multiboot_info));
- mbi_reloc_offset = start - (address_t)buffer;
-
- /* Command line */
- p = (char *)(mbi + 1);
- sprintf(p, "%s %s", imagename, command_line);
- mbi->cmdline = eswap(((address_t)p) + mbi_reloc_offset);
- p += command_line_len;
-
- /* Bootloader ID */
- sprintf(p, version_string);
- mbi->boot_loader_name = eswap(((address_t)p) + mbi_reloc_offset);
- p += strlen(version_string) + 1;
-
- /* Next is space for the module command lines */
- mod_clp = p;
-
- /* Last come the module info structs */
- modp = (struct mod_list *)
- ((((address_t)p + mod_command_line_space) + 3) & ~3);
- mbi->mods_count = eswap(modules);
- mbi->mods_addr = eswap(((address_t)modp) + mbi_reloc_offset);
-
- /* Memory information will be added at boot time, by setup.S
- * or trampoline.S. */
- mbi->flags = eswap(MB_INFO_CMDLINE | MB_INFO_BOOT_LOADER_NAME);
-
-
- /* Load the modules */
- if (modules) {
- mbi->flags = eswap(eswap(mbi->flags) | MB_INFO_MODS);
-
- /* Go back and parse the module command lines */
- optind = opterr = 1;
- while((opt = getopt_long(argc, argv,
- short_options, options, 0)) != -1)
- {
- if (opt != 'm') continue;
-
- /* Split module filename from command line */
- mod_command_line = mod_filename = optarg;
- if ((p = strchr(mod_filename, ' ')) != NULL) {
- /* See as I discard the 'const' modifier */
- *p = '\0';
- }
-
- /* Find space for it */
- if (stat(mod_filename, &sb) != 0) {
- printf("Fatal: cannot stat %s: %s\n",
- mod_filename, strerror(errno));
- exit(1);
- }
- size = sb.st_size;
- start = place_section(size, X86_PAGE_SIZE);
- /* XXX should be place_section(size, 4) if the MBH hasn't got
- * XXX MULTIBOOT_PAGE_ALIGN set, but that breaks Xen */
-
- /* Load it */
- if ((buffer = malloc(sb.st_size)) == NULL) {
- printf("Fatal: malloc failed for module load: %s\n",
- strerror(errno));
- exit(1);
- }
- if ((fp = fopen(mod_filename, "r")) == NULL) {
- printf("Fatal: cannot open %s: %s\n",
- mod_filename, strerror(errno));
- exit(1);
- }
- if ((fread(buffer, sb.st_size, 1, fp)) != 1) {
- printf("Fatal: cannot read %s: %s\n",
- mod_filename, strerror(errno));
- exit(1);
- }
- fclose(fp);
-
- /* Sanity-check: is this file compressed? */
- if ((buffer[0] == '\037' &&
- (buffer[1] == '\235' /* .Z */ ||
- buffer[1] == '\213' /* .gz */)) ||
- (buffer[0] == 'B' && buffer[1] == 'Z') /* .bz[2] */) {
- printf("Warning: %s looks like a compressed file.\n",
- mod_filename);
- }
-
- if (!quiet) printf("Loaded module from %s\n", mod_filename);
-
- /* Restore the command line to its former glory */
- if (p != NULL) *p = ' ';
-
- /* Fill in the module info struct */
- modp->mod_start = eswap(start);
- modp->mod_end = eswap(start + size);
- modp->cmdline = eswap((address_t)mod_clp + mbi_reloc_offset);
- modp->pad = eswap(0);
- modp++;
-
- /* Store the module command line */
- sprintf(mod_clp, "%s", mod_command_line);
- mod_clp += strlen(mod_clp) + 1;
-
- /* Add the section to the list */
- if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) {
- printf("Fatal: malloc() for section_t failed: %s\n",
- strerror(errno));
- exit(1);
- }
- sec->buffer = buffer;
- sec->start = start;
- sec->size = size;
- sec->next = NULL;
- sec->prev = last_section;
- last_section->next = sec;
- last_section = sec;
-
- }
-
- }
-
- /* Everything is placed and loaded. Now we package it all up
- * as a bzImage */
- if ((fp = fopen(out_filename, "w")) == NULL) {
- printf("Fatal: cannot open %s: %s\n", out_filename, strerror(errno));
- exit(1);
- }
- make_bzImage(sections,
- kernel_entry,
- ((address_t)mbi) + mbi_reloc_offset,
- fp);
- fclose(fp);
-
- /* Success! */
- if(!quiet) printf("Finished.\n");
- return 0;
-}
-
-/*
- * EOF (mbootpack.c)
- */
-