# This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/03/20 16:10:07-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx # Support being booted by arbitrary boot-loaders with bzImage code from Linux. # Wrap xen with Linux's bzImage code, either through support in Makefiles or via # the mkzen script. Both methods require that one specify the location # of a linux i386 build tree, from which we extract the necessary bits. # # Booting with the bzImage code requires that xen recognize parameters in the format # that vmlinux expects. Have __setup_xen be able to recognize both kinds of parameter # formats. # # Using non-grub boot-loaders means that we'll only see one module loaded in addition # to the "kernel" image. # # Add a "mkmetard" tool to create "meta-ramdisks" which can include multiple modules with # parameters, all packaged into one ramdisk image. # # Support decomposition of meta-ramdisks in xen. # # xen/arch/x86/mkzen # 2005/03/20 16:10:06-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +76 -0 # # xen/tools/Makefile # 2005/03/20 16:10:06-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +3 -1 # Built the mkmetard tool. # # xen/include/xen/multiboot.h # 2005/03/20 16:10:06-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +4 -0 # Reasonable max number of MBI modules. # # xen/arch/x86/setup.c # 2005/03/20 16:10:06-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +190 -44 # Support being booted by arbitrary boot-loaders with bzImage code from Linux. # Thus, parameters may be passed via pointer in %esi. Add appropriate checks to # detect parameters of this form vs. multi-boot. # # Add code to extract parameter and system data (e820 memory maps) from either multi-boot # or Linux parameter formats. # # If using Linux parameter format, it is possible that the single ramdisk is a "meta-ramdisk", # with a multi-boot-like record that describes multiple module images and parameter # strings. # # xen/arch/x86/mkzen # 2005/03/20 16:10:06-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +0 -0 # BitKeeper file /home/mostrows/xen/xeno-unstable.bk/xen/arch/x86/mkzen # # xen/arch/x86/boot/x86_32.S # 2005/03/20 16:10:06-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +9 -7 # Support being booted by arbitrary boot-loaders with bzImage code from Linux. # Thus, parameters may be passed via pointer in %esi. Add appropriate checks to # detect parameters of this form vs. multi-boot. # # xen/arch/x86/Makefile # 2005/03/20 16:10:06-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +42 -0 # Add target to build zenImg -- xen wrapped with Linux's bzImage machinery. # # xen/Makefile # 2005/03/20 16:10:06-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +3 -1 # Build mkmetard. # # xen/tools/mkmetard/mkmetard.c # 2005/03/20 15:01:15-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +225 -0 # # xen/tools/mkmetard/Makefile # 2005/03/20 15:01:15-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +10 -0 # # xen/tools/mkmetard/mkmetard.c # 2005/03/20 15:01:15-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +0 -0 # BitKeeper file /home/mostrows/xen/xeno-unstable.bk/xen/tools/mkmetard/mkmetard.c # # xen/tools/mkmetard/Makefile # 2005/03/20 15:01:15-05:00 mostrows@xxxxxxxxxxxxxxxxxxxxx +0 -0 # BitKeeper file /home/mostrows/xen/xeno-unstable.bk/xen/tools/mkmetard/Makefile # diff -Nru a/xen/Makefile b/xen/Makefile --- a/xen/Makefile 2005-03-20 16:15:16 -05:00 +++ b/xen/Makefile 2005-03-20 16:15:16 -05:00 @@ -27,7 +27,7 @@ dist: install build: $(TARGET).gz - + install: $(TARGET).gz [ -d $(DESTDIR)/boot ] || $(INSTALL_DIR) $(DESTDIR)/boot $(INSTALL_DATA) $(TARGET).gz $(DESTDIR)/boot @@ -52,9 +52,11 @@ [ -e include/asm ] || ln -sf asm-$(TARGET_ARCH) include/asm $(MAKE) -C arch/$(TARGET_ARCH) asm-offsets.s $(MAKE) include/asm-$(TARGET_ARCH)/asm-offsets.h + $(MAKE) -C tools/mkmetard $(MAKE) -C common $(MAKE) -C drivers $(MAKE) -C arch/$(TARGET_ARCH) + # drivers/char/console.o may contain static banner/compile info. Blow it away. delete-unfresh-files: diff -Nru a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile --- a/xen/arch/x86/Makefile 2005-03-20 16:15:16 -05:00 +++ b/xen/arch/x86/Makefile 2005-03-20 16:15:16 -05:00 @@ -15,7 +15,11 @@ OBJS := $(patsubst cdb%.o,,$(OBJS)) endif +ifdef LINUX_BUILD +default: $(TARGET) zenImg +else default: $(TARGET) +endif $(TARGET): $(TARGET)-syms boot/mkelf32 ./boot/mkelf32 $(TARGET)-syms $(TARGET) 0x100000 @@ -32,6 +36,44 @@ boot/mkelf32: boot/mkelf32.c $(HOSTCC) $(HOSTCFLAGS) -o $@ $< + + +ifdef LINUX_BUILD + +# +# Check Makefile in Linux build dir. If it contains KERNELSRC, then use +# that as source dir, otherwise build==source dir +LINUX_SRC:= $(shell if grep -q KERNELSRC $(LINUX_BUILD)/Makefile ; then \ + sed -e '/^KERNELSRC/!d' $(LINUX_BUILD)/Makefile | \ + bash -c '( read A B C ; echo -n $$C)' ; \ + else \ + echo -n $(LINUX_BUILD); \ + fi ) + +$(TARGET).bin: $(TARGET) + $(OBJCOPY) -O binary -R .note -R .comment -S $^ $@ + +$(TARGET).bin.gz: $(TARGET).bin + gzip -f -9 < $< > $@ + +piggy.o: $(TARGET).bin.gz + $(LD) -m elf_i386 -r --format binary --oformat elf32-i386 \ + -T $(LINUX_SRC)/arch/i386/boot/compressed/vmlinux.scr $< -o $@ + +zen: $(LINUX_BUILD)/arch/i386/boot/compressed/head.o \ + $(LINUX_BUILD)/arch/i386/boot/compressed/misc.o \ + piggy.o + $(LD) -m elf_i386 -Ttext 0x100000 -e startup_32 $^ -o $@ + +zenImg: zen + $(OBJCOPY) -O binary -R .note -R .comment -S $^ $@.tmp + $(LINUX_BUILD)/arch/i386/boot/tools/build \ + -b $(LINUX_BUILD)/arch/i386/boot/bootsect \ + $(LINUX_BUILD)/arch/i386/boot/setup $@.tmp > $@ + + +endif + clean: rm -f *.o *.s *~ core boot/*.o boot/*~ boot/core boot/mkelf32 diff -Nru a/xen/arch/x86/boot/x86_32.S b/xen/arch/x86/boot/x86_32.S --- a/xen/arch/x86/boot/x86_32.S 2005-03-20 16:15:16 -05:00 +++ b/xen/arch/x86/boot/x86_32.S 2005-03-20 16:15:16 -05:00 @@ -55,7 +55,7 @@ mov %ecx,%gs ljmp $(__HYPERVISOR_CS),$(1f)-__PAGE_OFFSET 1: lss stack_start-__PAGE_OFFSET,%esp - + /* Reset EFLAGS (subsumes CLI and CLD). */ pushl $0 popf @@ -82,15 +82,17 @@ and $0x7f,%cl # CR4.PGE (global enable) mov %ecx,%cr4 + /* Check for Multiboot bootloader */ + cmp $0x2BADB002,%eax + je 1f + /* No multi-boot? Hope that we've got a Linux boot-params */ + /* stashed in esi. Save in %ebx until stack is ready. */ + movl %esi, %ebx +1: cmp $(SECONDARY_CPU_FLAG),%ebx je start_paging - /* Check for Multiboot bootloader */ - cmp $0x2BADB002,%eax - jne not_multiboot - - /* Save the Multiboot info structure for later use. */ - add $__PAGE_OFFSET,%ebx + /* Stack is now ready, so store boot parameter pointer */ push %ebx /* Initialize BSS (no nasty surprises!) */ diff -Nru a/xen/arch/x86/mkzen b/xen/arch/x86/mkzen --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/xen/arch/x86/mkzen 2005-03-20 16:15:16 -05:00 @@ -0,0 +1,76 @@ +#!/bin/bash +# +# Copyright (C) 2005 Michal Ostrowski , +# IBM Corporation +# +# 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 +# + + +# Reaches into a Linux build tree and uses objects and scripts from +# linux to wrap a Xen ELF image in the Linuz bzImage machinery, +# allowing the resulting "zen" image to be booted using any +# boot-loader thant can load a Linux bzImage. + +# +# Usage: mkzen + +set -e +LINUX_BUILD=$1 +XEN=$2 +ZEN=$3 + +: ${CROSS_COMPILE:=} +: ${OBJCOPY:=${CROSS_COMPILE}objcopy} +: ${LD:=${CROSS_COMPILE}ld} + +function cleanup(){ + rm -f ${XEN}.bin.$$ ${XEN}.bin.gz.$$ ${XEN}.piggy.o.$$ + rm -f ${ZEN}.1.$$ ${ZEN}.2.$$ +} + +trap cleanup ERR + +# +# Check Makefile in Linux build dir. If it contains KERNELSRC, then use +# that as source dir, otherwise build==source dir +# +LINUX_SRC=`sed -e '/^KERNELSRC/!d;s/^.*:=[ ]*//' <${LINUX_BUILD}/Makefile` +if [ -z "${LINUX_SRC}" ]; then + LINUX_SRC=${LINUX_BUILD}; +fi + +${OBJCOPY} -O binary -R .note -R .comment -S ${XEN} ${XEN}.bin.$$ + +gzip -f -9 < ${XEN}.bin.$$ > ${XEN}.bin.gz.$$ + +${LD} -m elf_i386 -r --format binary --oformat elf32-i386 \ + -T ${LINUX_SRC}/arch/i386/boot/compressed/vmlinux.scr \ + ${XEN}.bin.gz -o ${XEN}.piggy.o.$$ + + +${LD} -m elf_i386 -Ttext 0x100000 -e startup_32 \ + ${LINUX_BUILD}/arch/i386/boot/compressed/head.o \ + ${LINUX_BUILD}/arch/i386/boot/compressed/misc.o ${XEN}.piggy.o.$$ \ + -o ${ZEN}.1.$$ + +${OBJCOPY} -O binary -R .note -R .comment -S ${ZEN}.1.$$ ${ZEN}.2.$$ + +${LINUX_BUILD}/arch/i386/boot/tools/build \ + -b ${LINUX_BUILD}/arch/i386/boot/bootsect \ + ${LINUX_BUILD}/arch/i386/boot/setup ${ZEN}.2.$$ > ${ZEN} + + +cleanup \ No newline at end of file diff -Nru a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c --- a/xen/arch/x86/setup.c 2005-03-20 16:15:16 -05:00 +++ b/xen/arch/x86/setup.c 2005-03-20 16:15:16 -05:00 @@ -86,6 +86,24 @@ int phys_proc_id[NR_CPUS]; int logical_proc_id[NR_CPUS]; + +/* Details about what is found where in the Linux boot parameters area. */ +/* Put into a seperate header if it grows much more. */ +#define PARAM_SIZE 2048 +#define COMMAND_LINE_SIZE 256 +#define NEW_CL_POINTER 0x228 +#define E820NR 0x1e8 +#define E820MAP 0x2d0 +#define INITRD_START 0x218 +#define INITRD_SIZE 0x21c + +static unsigned char boot_params[PARAM_SIZE]; +static unsigned char cmd_line_buf[COMMAND_LINE_SIZE]; +static unsigned char dom0_cmd_line_buf[COMMAND_LINE_SIZE]; +static module_t boot_modules[MAX_MBI_MODULES]; + + + /* Standard macro to see if a specific flag is changeable. */ static inline int flag_is_changeable_p(unsigned long flag) { @@ -453,36 +471,19 @@ #endif } -void __init __start_xen(multiboot_info_t *mbi) +static int __init boot_param_e820_setup(unsigned char *boot_params, + struct e820entry *e820raw) { - char *cmdline; - module_t *mod = (module_t *)__va(mbi->mods_addr); - void *heap_start; - unsigned long firsthole_start, nr_pages; - unsigned long initial_images_start, initial_images_end; - struct e820entry e820_raw[E820MAX]; - int i, e820_raw_nr = 0, bytes = 0; - - /* Parse the command-line options. */ - if ( (mbi->flags & MBI_CMDLINE) && (mbi->cmdline != 0) ) - cmdline_parse(__va(mbi->cmdline)); - - /* Must do this early -- e.g., spinlocks rely on get_current(). */ - set_current(&idle0_exec_domain); - - /* We initialise the serial devices very early so we can get debugging. */ - serial_init_stage1(); - - init_console(); - - /* Check that we have at least one Multiboot module. */ - if ( !(mbi->flags & MBI_MODULES) || (mbi->mods_count == 0) ) - { - printk("FATAL ERROR: Require at least one Multiboot module.\n"); - for ( ; ; ) ; - } + int e820_raw_nr = *(int*)&boot_params[E820NR]; + memcpy(e820raw, boot_params + E820MAP, e820_raw_nr * sizeof(*e820raw)); + return e820_raw_nr; +} - xenheap_phys_end = opt_xenheap_megabytes << 20; +static int __init mbi_e820_setup(multiboot_info_t *mbi, + struct e820entry *e820_raw) +{ + int bytes = 0; + int e820_raw_nr = 0; if ( mbi->flags & MBI_MEMMAP ) { @@ -509,14 +510,154 @@ e820_raw[1].type = E820_RAM; e820_raw_nr = 2; } + return e820_raw_nr; +} + +int __init mbi_boot_modules(multiboot_info_t *mbi) +{ + /* Check that we have at least one Multiboot module. */ + if ( !(mbi->flags & MBI_MODULES) || (mbi->mods_count == 0) ) + { + printk("FATAL ERROR: Require at least one Multiboot module.\n"); + for ( ; ; ) ; + } + + memcpy(&boot_modules, __va(mbi->mods_addr), + sizeof(module_t) * mbi->mods_count); + return mbi->mods_count; +} + +int __init boot_param_modules(unsigned char *params) +{ + u32 rd = *(u32*)&boot_params[INITRD_START]; + int size = *(int*)&boot_params[INITRD_SIZE]; + + boot_modules[0].mod_start = rd; + boot_modules[0].mod_end = rd + size; + boot_modules[0].string = 0; + boot_modules[0].reserved = 0; + + u32 *magic = (u32*)boot_modules[0].mod_start; + u32 num_modules = magic[1]; + u32 base = boot_modules[0].mod_start; + + printf("Multi-module: %x %d %x\n", *magic, num_modules, base); + printf("Module: %x %x %x\n", + boot_modules[0].mod_start, boot_modules[0].mod_end, + boot_modules[0].string); + + + if ( *magic != MULTIBOOT_BOOTLOADER_MAGIC ) + { + return 1; + } + + memcpy(&boot_modules[0], (void*)(base + sizeof(u32) * 2), + num_modules * sizeof(module_t)); + printf("Module: %x %x %x\n", + boot_modules[0].mod_start, boot_modules[0].mod_end, + boot_modules[0].string); + + int i = 0; + for ( ; i < num_modules; ++i) + { + boot_modules[i].mod_start += base; + boot_modules[i].mod_end += base; + boot_modules[i].string += base; + } + printf("Module: %x %x %x\n", + boot_modules[0].mod_start, boot_modules[0].mod_end, + boot_modules[0].string); + return num_modules; +} + +void __init __start_xen(void *params) +{ + char *cmdline = NULL; + void *heap_start; + unsigned long firsthole_start, nr_pages; + unsigned long initial_images_start, initial_images_end; + struct e820entry e820_raw[E820MAX]; + int i, e820_raw_nr = 0; + int num_mods = 0; + multiboot_info_t *mbi = NULL; + + if (MULTIBOOT_BOOTLOADER_MAGIC == *(u32*)params ) + { + mbi = (struct multiboot_info_t*)__va(mbi); + if ( (mbi->flags & MBI_CMDLINE) && (mbi->cmdline != 0) ) + { + cmdline = __va(mbi->cmdline); + } + } + else + { + /* Hope it is a Linux boot parameters area. */ + unsigned char* orig_cmd_line; + memcpy(boot_params, __va(((char*)params)), PARAM_SIZE); + + orig_cmd_line = __va(*(unsigned char**)&boot_params[NEW_CL_POINTER]); + + memcpy(cmd_line_buf, orig_cmd_line, COMMAND_LINE_SIZE); + cmdline = cmd_line_buf; + } + + /* Parse the command-line options. */ + cmdline_parse(cmdline); + + /* Must do this early -- e.g., spinlocks rely on get_current(). */ + set_current(&idle0_exec_domain); + + /* We initialise the serial devices very early so we can get debugging. */ + serial_init_stage1(); + + init_console(); + + xenheap_phys_end = opt_xenheap_megabytes << 20; + + if ( mbi != NULL ) + { + e820_raw_nr = mbi_e820_setup(mbi, e820_raw); + } else { + e820_raw_nr = boot_param_e820_setup(boot_params, e820_raw); + } + + if (e820_raw_nr == 0) + { printk("FATAL ERROR: Bootloader provided no memory information.\n"); for ( ; ; ) ; } max_page = init_e820(e820_raw, e820_raw_nr); + if (mbi != NULL) + { + num_mods = mbi_boot_modules(mbi); + } + else + { + num_mods = boot_param_modules(boot_params); + } + + /* Save dom0 cmd line to a known place. */ + if ( boot_modules[0].string ) + { + +#if defined(__i386__) + memcpy(dom0_cmd_line_buf, (void*)boot_modules[0].string, + COMMAND_LINE_SIZE); +#elif defined(__x86_64__) + memcpy(dom0_cmd_line_buf, __va(boot_modules[0].string), + COMMAND_LINE_SIZE); +#endif + } + else + { + dom0_cmd_line_buf[0] = 0; + } + /* Find the first high-memory RAM hole. */ for ( i = 0; i < e820.nr_map; i++ ) if ( (e820.map[i].type == E820_RAM) && @@ -527,7 +668,7 @@ /* Relocate the Multiboot modules. */ initial_images_start = xenheap_phys_end; initial_images_end = initial_images_start + - (mod[mbi->mods_count-1].mod_end - mod[0].mod_start); + (boot_modules[num_mods - 1].mod_end - boot_modules[0].mod_start); if ( initial_images_end > firsthole_start ) { printk("Not enough memory to stash the DOM0 kernel image.\n"); @@ -535,14 +676,14 @@ } #if defined(__i386__) memmove((void *)initial_images_start, /* use low mapping */ - (void *)mod[0].mod_start, /* use low mapping */ - mod[mbi->mods_count-1].mod_end - mod[0].mod_start); + (void *)boot_modules[0].mod_start, /* use low mapping */ + boot_modules[num_mods - 1].mod_end - boot_modules[0].mod_start); #elif defined(__x86_64__) memmove(__va(initial_images_start), - __va(mod[0].mod_start), - mod[mbi->mods_count-1].mod_end - mod[0].mod_start); + __va(boot_modules[0].mod_start), + boot_modules[num_mods-1].mod_end - boot_modules[0].mod_start); #endif - + /* Initialise boot-time allocator with all RAM situated after modules. */ heap_start = memguard_init(&_end); heap_start = __va(init_boot_allocator(__pa(heap_start))); @@ -587,7 +728,8 @@ set_bit(DF_PRIVILEGED, &dom0->d_flags); /* Grab the DOM0 command line. Skip past the image name. */ - cmdline = (char *)(mod[0].string ? __va(mod[0].string) : NULL); + cmdline = (dom0_cmd_line_buf[0] ? dom0_cmd_line_buf : NULL); + if ( cmdline != NULL ) { while ( *cmdline == ' ' ) cmdline++; @@ -599,15 +741,19 @@ * We're going to setup domain0 using the module(s) that we stashed safely * above our heap. The second module, if present, is an initrd ramdisk. */ - if ( construct_dom0(dom0, - initial_images_start, - mod[0].mod_end-mod[0].mod_start, - (mbi->mods_count == 1) ? 0 : - initial_images_start + - (mod[1].mod_start-mod[0].mod_start), - (mbi->mods_count == 1) ? 0 : - mod[mbi->mods_count-1].mod_end - mod[1].mod_start, - cmdline) != 0) + u32 img_size = boot_modules[0].mod_end - boot_modules[0].mod_start; + u32 rd_start = 0; + u32 rd_size = 0; + if ( num_mods > 1 ) + { + rd_start = initial_images_start + + boot_modules[1].mod_start - boot_modules[0].mod_start; + + rd_size = boot_modules[num_mods-1].mod_end - boot_modules[1].mod_start; + } + + if ( construct_dom0(dom0, initial_images_start, img_size, + rd_start, rd_size, cmdline) != 0) panic("Could not set up DOM0 guest OS\n"); /* Scrub RAM that is still free and so may go to an unprivileged domain. */ diff -Nru a/xen/include/xen/multiboot.h b/xen/include/xen/multiboot.h --- a/xen/include/xen/multiboot.h 2005-03-20 16:15:16 -05:00 +++ b/xen/include/xen/multiboot.h 2005-03-20 16:15:16 -05:00 @@ -28,6 +28,10 @@ #define MBI_MEMMAP (1<<6) #define MBI_LOADERNAME (1<<9) +/* Make up some reasonable maximum that we support. */ +#define MAX_MBI_MODULES 4 + + /* The symbol table for a.out. */ typedef struct { u32 tabsize; diff -Nru a/xen/tools/Makefile b/xen/tools/Makefile --- a/xen/tools/Makefile 2005-03-20 16:15:16 -05:00 +++ b/xen/tools/Makefile 2005-03-20 16:15:16 -05:00 @@ -1,6 +1,8 @@ default: $(MAKE) -C figlet + $(MAKE) -C mkmetard clean: - $(MAKE) -C figlet clean \ No newline at end of file + $(MAKE) -C figlet clean + $(MAKE) -C mkmetard clean \ No newline at end of file diff -Nru a/xen/tools/mkmetard/Makefile b/xen/tools/mkmetard/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/xen/tools/mkmetard/Makefile 2005-03-20 16:15:16 -05:00 @@ -0,0 +1,10 @@ + +include ../../../Config.mk + +CFLAGS += -DBUILD_ARCH=$(XEN_COMPILE_ARCH) -DTARGET_ARCH=$(XEN_TARGET_ARCH) +CFLAGS += -I$(BASEDIR)/include +mkmetard: mkmetard.c + $(HOSTCC) $(CFLAGS) -o $@ $< + +clean: + rm -f *.o mkmetard diff -Nru a/xen/tools/mkmetard/mkmetard.c b/xen/tools/mkmetard/mkmetard.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/xen/tools/mkmetard/mkmetard.c 2005-03-20 16:15:16 -05:00 @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2005 Michal Ostrowski , + * IBM Corporation + * + * 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 + * + */ + +/* Combines several images and cmdlines into one meta-ramdisk image. + * For use with non-grub boot-loader that don't do "multi-boot" as + * grub does. + * + * Usage: mkmetard ... \ + * --- ... + * + * Allows up to 4 module images. + */ + +#include +#include +#include +#include +#include +#include +#include + + + +/* We need to know whether build platform endianness matches that of target */ +#define LITTLE_ENDIAN_ppc 0 +#define LITTLE_ENDIAN_x86_32 1 +#define LITTLE_ENDIAN_x86_64 1 +#define LITTLE_ENDIAN_ia64 1 + +#define __CAT(a,b) a##b +#define IS_LITTLE_ENDIAN(arch) __CAT(LITTLE_ENDIAN_,arch) + +#if IS_LITTLE_ENDIAN(BUILD_ARCH) == IS_LITTLE_ENDIAN(TARGET_ARCH) +#define ENDIAN_MATCH 1 +#else +#define ENDIAN_MATCH 0 +#endif + + +#if ENDIAN_MATCH == 0 +#define byteswap(x) \ + ({ \ + typeof(x) tmp = x; \ + switch(sizeof(tmp)) \ + { \ + case 1: \ + break; \ + case 2: \ + tmp = bswap_16(tmp); \ + break; \ + case 4: \ + tmp = bswap_32(tmp); \ + break; \ + case 8: \ + tmp = bswap_64(tmp); \ + break; \ + default: \ + printf("no valid byteswap for " #x); \ + tmp = 0; \ + break; \ + } \ + tmp; \ + }) +#else /* ENDIAN_MATCH == 0 */ +#define byteswap(x) (x) +#endif /* ENDIAN_MATCH == 0 */ + + + +/* We cannot use types.h, since we may be cross-compiling and thus + * don't want to pick up an asm header that doesn't match the + * architecture we're building for */ +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +/* See if we are 32 or 64-bit */ +#if 2147483647L == __LONG_MAX__ +typedef signed long long s64; +typedef unsigned long long u64; +#define BITS_PER_LONG 32 +#else +typedef signed long s64; +typedef unsigned long u64; +#define BITS_PER_LONG 64 +#endif + +#include + +int curr_offset = 0; +int rd_fd; + +static inline void +write_to_file(void* buf, int len) +{ + int ret = write(rd_fd, buf, len); + if (ret == len) + { + curr_offset += ret; + } + else + { + perror("Incomplete write to ramdisk file."); + exit(-1); + } +} + + +module_t mods[MAX_MBI_MODULES]; + +int main(int argc, char** argv) +{ + char* rdname = argv[1]; + argv += 2; + argc -= 2; + + int mod = 0; + int x = 0; + + int parts[MAX_MBI_MODULES + 1] = { -1, }; + + parts[mod] = 0; + + /* Identify cmdlines for each module */ + while ( x < argc && mod < MAX_MBI_MODULES) + { + if ( strcmp(argv[x],"---") == 0 ) + { + ++x; + if (x < argc && mod < MAX_MBI_MODULES) + { + ++mod; + parts[mod] = x; + } + + } + else + { + ++x; + } + } + ++mod; + + rd_fd = open(rdname, O_RDWR | O_CREAT | O_TRUNC, 0644); + if ( rd_fd < 0 ) perror("Can't open meta-ramdisk image file\n"); + + /* Use the multi-boot magic number, can't see why not to. */ + u32 magic = byteswap(MULTIBOOT_BOOTLOADER_MAGIC); + write_to_file(&magic, sizeof(magic)); + + magic = byteswap(mod); + write_to_file(&magic, sizeof(magic)); + + /* We'll come back and re-write this later, but we just need + * filler for now */ + write_to_file(&mods, sizeof(module_t) * mod); + + for ( x = 0; x < mod; ++x ) + { + int fd = open(argv[parts[x]], O_RDONLY); + if ( fd < 0 ) + { + perror("Can't open image file"); + exit(-1); + } + + char string[1024]; + char buf[1024]; + int size = 0; + int ret; + + /* Copy cmdline component */ + string[0] = 0; + + int y = parts[x]; + while(y < argc && strcmp(argv[y], "---")!=0 ) + { + strcpy(string + size, argv[y]); + size += strlen(argv[y]); + string[size++] = ' '; + ++y; + } + string[size++] = 0; + + mods[x].string = byteswap(curr_offset); + write_to_file(string, size); + + /* Now copy module image */ + mods[x].mod_start = byteswap(curr_offset); + while ( (ret = read(fd, buf, 1024)) > 0) + { + write_to_file(buf, ret); + } + mods[x].mod_end = byteswap(curr_offset); + } + + /* Re-write the modules structs at the start of the file */ + lseek(rd_fd, sizeof(magic) * 2, SEEK_SET); + write(rd_fd, &mods, sizeof(module_t) * mod); + + return 0; + +}