diff -Nur -x autom4te.cache grub2_cvspull.bak/conf/i386-pc.rmk grub2_cvspull/conf/i386-pc.rmk
--- grub2_cvspull.bak/conf/i386-pc.rmk 2006-07-31 08:21:35.000000000 -0600
+++ grub2_cvspull/conf/i386-pc.rmk 2006-08-03 00:18:02.000000000 -0600
@@ -112,7 +112,7 @@
pkgdata_MODULES = _chain.mod _linux.mod linux.mod normal.mod \
_multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \
vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \
- videotest.mod play.mod bitmap.mod tga.mod
+ videotest.mod play.mod bitmap.mod tga.mod vmlinux.mod
# For _chain.mod.
_chain_mod_SOURCES = loader/i386/pc/chainloader.c
@@ -164,6 +164,11 @@
_multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
_multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For vmlinux.mod.
+vmlinux_mod_SOURCES = loader/i386/pc/vmlinux.c
+vmlinux_mod_CFLAGS = $(COMMON_CFLAGS)
+vmlinux_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
# For multiboot.mod.
multiboot_mod_SOURCES = loader/i386/pc/multiboot_normal.c
multiboot_mod_CFLAGS = $(COMMON_CFLAGS)
diff -Nur -x autom4te.cache grub2_cvspull.bak/include/grub/i386/pc/init.h grub2_cvspull/include/grub/i386/pc/init.h
--- grub2_cvspull.bak/include/grub/i386/pc/init.h 2005-01-31 14:40:25.000000000 -0700
+++ grub2_cvspull/include/grub/i386/pc/init.h 2006-08-03 00:21:47.000000000 -0600
@@ -48,8 +48,11 @@
/* Get a memory map entry. Return next continuation value. Zero means
the end. */
-grub_uint32_t grub_get_mmap_entry (struct grub_machine_mmap_entry *entry,
- grub_uint32_t cont);
+/*grub_uint32_t grub_get_mmap_entry (struct grub_machine_mmap_entry *entry,
+ grub_uint32_t cont);*/
+/* exporting for loader/i386/pc/vmlinux.c */
+grub_uint32_t EXPORT_FUNC (grub_get_mmap_entry)
+ (struct grub_machine_mmap_entry *entry, grub_uint32_t cont);
/* Turn on/off Gate A20. */
void grub_gate_a20 (int on);
diff -Nur -x autom4te.cache grub2_cvspull.bak/loader/i386/pc/vmlinux.c grub2_cvspull/loader/i386/pc/vmlinux.c
--- grub2_cvspull.bak/loader/i386/pc/vmlinux.c 1969-12-31 17:00:00.000000000 -0700
+++ grub2_cvspull/loader/i386/pc/vmlinux.c 2006-08-03 00:08:10.000000000 -0600
@@ -0,0 +1,416 @@
+/* vmlinux.c - load a Linux i386/x86_64 vmlinux.bin kernel image */
+/* August 3 2006, Maciek Nowacki
*/
+
+/*
+ * notes:
+ *
+ * grub leaks memory. This is apparent even with the stock Linux bzImage
+ * loader (repeat a command like 'linux /bzImage' about twenty times), and it
+ * seems to be worse with this loader. I am new to grub, but I could not find
+ * any obvious leakage here.
+ */
+
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2003 NIIBE Yutaka
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+static grub_dl_t this_mod;
+
+#define STATE_ADDRESS 0
+#define STATE_MAJOR 1
+#define STATE_MINOR 2
+#define STATE_RDONLY 3
+
+/* include/asm-x86_64/setup.h:#define COMMAND_LINE_SIZE 256
+ */
+#define COMMAND_LINE_SIZE 256
+
+/* linux/include/asm-x86_64/bootsetup.h:
+ * #define BOOT_PARAM_SIZE 4096
+ */
+#define BOOT_PARAM_SIZE 4096
+
+static const struct grub_arg_option options[] =
+ {
+ {"address", 'a', 0, "specify address to load kernel (default: -a 0x200000)", 0, ARG_TYPE_STRING},
+ {"major", 'M', 0, "set root device major", 0, ARG_TYPE_INT},
+ {"minor", 'm', 0, "set root device minor", 0, ARG_TYPE_INT},
+ {"ro", 'r', 0, "set root read-only flag", 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+/*
+ * linux/include/asm-x86_64/bootsetup.h:
+ * #define PARAM ((unsigned char *)x86_boot_params)
+ *
+ * This block constitutes the data that GRUB will pass to Linux. It is safely
+ * outside of the area defined by grub_os_area_addr and grub_os_area_size, and
+ * will persist until the 'boot' command is given; however, it is past the
+ * grub_os_area, and Linux cannot deal with this information being past itself
+ * in physical memory. This will be taken care of in grub_vmlinux_boot().
+ */
+static unsigned char x86_boot_params[COMMAND_LINE_SIZE + BOOT_PARAM_SIZE];
+
+static grub_err_t
+grub_vmlinux_boot (void)
+{
+ /* declare another boot block here, where it will be on the stack and
+ * thus in the first megabyte of memory:
+ */
+ unsigned char x86_boot_params_first_meg[COMMAND_LINE_SIZE +
+ BOOT_PARAM_SIZE];
+
+ grub_memmove(&x86_boot_params_first_meg,&x86_boot_params,
+ COMMAND_LINE_SIZE + BOOT_PARAM_SIZE);
+
+ char *cmdline = (char *)&x86_boot_params_first_meg;
+ struct linux_kernel_header *lh =
+ (struct linux_kernel_header *)(COMMAND_LINE_SIZE + cmdline);
+
+ grub_addr_t begin = lh->code32_start;
+
+ if(begin < (grub_addr_t)cmdline)
+ {
+ grub_printf("Sorry, I can't boot the kernel: the parameter block occurs past the kernel.\n");
+ return GRUB_ERR_OUT_OF_RANGE;
+ }
+
+ lh->cmd_line_ptr=cmdline;
+
+ grub_printf("cmdline relocated to %08x, lh to %08x\n",
+ (unsigned int)lh->cmd_line_ptr, (unsigned int)lh);
+
+ asm( "movl %0,%%esi" :: "m" (lh) );
+ asm("jmp *%0" :: "m" (begin));
+
+ /* Not reached. */
+ return GRUB_ERR_NONE;
+}
+static grub_err_t
+grub_vmlinux_unload (void)
+{
+ grub_dl_unref(this_mod);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_vmlinux (struct grub_arg_list *state, int argc, char **args)
+{
+ grub_dl_ref(this_mod);
+ if(!argc)
+ {
+ grub_printf("Please specify a vmlinux.bin-style kernel image.\n");
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ int i=argc, cl=0;
+ while(--i)
+ cl += 1 + grub_strlen(args[i]);
+
+ if(cl > 1 + COMMAND_LINE_SIZE) // Linux has an implicit '\0' at max length +1
+ {
+ grub_printf("Command line is too long by %u characters\n",
+ cl - (1 + COMMAND_LINE_SIZE));
+
+ /* truncation doesn't make much sense - let the user handle it */
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ /* Handle the cmdline first and as one block along with the
+ * linux_kernel_header struct (lh), since the cmdline code might scribble
+ * past its bounds by one byte.
+ */
+
+ char *cmdline=(char *)&x86_boot_params;
+
+ // a little bit of poison never hurt anyone (XXX replace with memset())
+ for(i=COMMAND_LINE_SIZE; i; cmdline[--i]=0x8f);
+
+ /* A note on cmdline, the commandline buffer:
+ * Potentially, 257 characters could be copied into the commandline buffer.
+ * However, the last character is always a space, which the statement after
+ * the loop would overwrite with '\0'. That character therefore never
+ * contains user data, as it serves only to delineate the end of the buffer.
+ * Linux will only use at most 256 characters from the buffer. By using an
+ * extra byte, the code becomes no more complex despite allowing the entire
+ * buffer to be used for commandline user data.
+ */
+
+ grub_uint32_t cont=argc;
+ i=cl;
+ while(i)
+ {
+ i -= 1 + grub_strlen(args[--cont]);
+ *grub_stpcpy(i + cmdline, args[cont])=' ';
+ }
+ /* cl is 0 if there isn't a commandline; otherwise, cl is the length of the
+ * commandline plus 1.
+ */
+ cmdline[ cl - (cl?1:0) ] = '\0';
+
+ /* deal with lh only once the commandline has been sorted out
+ * Note that the struct linux_kernel_header only describes part of the data
+ * defined by BOOT_PARAM_SIZE. It's used as a convenience, and since it is
+ * smaller than BOOT_PARAM_SIZE, it is not always appropriate.
+ */
+ struct linux_kernel_header *lh =
+ (struct linux_kernel_header *)(cmdline + COMMAND_LINE_SIZE);
+
+ /* XXX replace with memset() */
+ for(i = BOOT_PARAM_SIZE; i; ((char *)lh)[--i] = 0xf8);
+
+ if(state[STATE_ADDRESS].set)
+ {
+ for(i = grub_strlen(state[STATE_ADDRESS].arg);
+ i && 'x' !=state[STATE_ADDRESS].arg[--i]
+ && 'X'!=state[STATE_ADDRESS].arg[i]
+ ;
+ );
+
+ /* Maybe bail if 0 is returned? Or other preposturous addresses? */
+ if(i)
+ lh->code32_start = (grub_addr_t) grub_strtoul(
+ 1 + i + state[STATE_ADDRESS].arg, 0, 16);
+ }
+ else
+ {
+ grub_printf("Please specify a load address (see 'vmlinux -h')\n");
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ /* here is another struct that overlays the BOOT_PARAM region */
+ struct linux_kernel_params *lp = (struct linux_kernel_params *) lh;
+
+ /* Without these two at least, console initialization will get stuck.
+ * This took me a _long_ time to figure out.
+ * It would be more correct to obtain this information from GRUB.
+ */
+ lp->video_height = 25;
+ lp->video_width = 80;
+ lp->have_vga = 1;
+
+ /* This method is probably going away soon - but it's elegant, in my
+ * opinion, and it avoids string parsing in the kernel. It allows the
+ * bootloader to refuse data that doesn't describe a device in acceptable
+ * notation.
+ */
+ if(state[STATE_MAJOR].set && state[STATE_MINOR].set)
+ lh->root_dev= (grub_strtoul(state[STATE_MAJOR].arg,NULL,0) << 8)
+ | grub_strtoul(state[STATE_MINOR].arg,NULL,0);
+
+ /* As above. Regardless, here it is. */
+ if(state[STATE_RDONLY].set)
+ lh->root_flags=1;
+
+ /* Don't set the cmdline pointer, since the boot function will move it. */
+ /* lh->cmd_line_ptr=cmdline; */
+
+ /* these need to be set when initrd support is implemented */
+ lh->ramdisk_image=0;
+ lh->ramdisk_size=0;
+
+ /* useless, but shows up /proc/sys/kernel/bootloader_type */
+ lh->type_of_loader=GRUB_LINUX_BOOT_LOADER_TYPE;
+
+ /* I have delayed opening and reading the kernel into memory for as long as
+ * possible, to allow the code to cleanly abort. While it is still possible
+ * to bail out here without having touched the grub_os_area, it won't be
+ * for long.
+ */
+
+ grub_file_t file = 0;
+
+ file = grub_file_open(args[0]);
+
+ if(!file)
+ {
+ grub_printf("Problem during grub_file_open()... aborting.\n");
+ return GRUB_ERR_FILE_READ_ERROR;
+ }
+
+ // XXX clean this up - obsolete #defines
+#define OS_AREA_ADDR grub_os_area_addr
+#define OS_AREA_SIZE grub_os_area_size
+#define LOAD_ADDRESS lh->code32_start
+
+ if(grub_os_area_addr > lh->code32_start)
+ {
+ grub_printf("Error: 0x%08x is too low in memory by 0x%08x bytes\n",
+ lh->code32_start, grub_os_area_addr - lh->code32_start);
+ grub_file_close(file);
+ return GRUB_ERR_OUT_OF_RANGE;
+ }
+
+ if(grub_os_area_addr+grub_os_area_size < lh->code32_start)
+ {
+ grub_printf("Error: 0x%08x exceeds the highest available memory location by 0x%08x bytes\n",
+ lh->code32_start, lh->code32_start -
+ (grub_os_area_addr + grub_os_area_size) );
+ grub_file_close(file);
+ return GRUB_ERR_OUT_OF_RANGE;
+ }
+ if(grub_os_area_addr + grub_os_area_size <
+ lh->code32_start + (grub_addr_t) grub_file_size(file))
+ {
+ grub_printf("Error: to load at location 0x%08x, 0x%08x more bytes are needed\n",
+ lh->code32_start, lh->code32_start +
+ (grub_addr_t) grub_file_size(file) -
+ (grub_os_area_addr + grub_os_area_size));
+
+ grub_file_close(file);
+ return GRUB_ERR_OUT_OF_MEMORY;
+ }
+
+ /* Now that the grub_os_area is going to be overwritten (everything else
+ * should be recoverable with no change in state, to this point):
+ */
+ grub_loader_unset();
+
+ /* I think it is appropriate to cast the result of grub_file_read() since it
+ * is a signed value, while grub_file_size() returns grub_off_t (unsigned)
+ * and thus could represent a value that could be too large to be stored as
+ * a same-sized signed value.
+ */
+ if(grub_file_size(file) != (grub_off_t) grub_file_read(file,
+ (char *)lh->code32_start, grub_file_size(file)))
+ {
+ grub_printf("Error reading %s into memory.\n", args[0]);
+ grub_file_close(file);
+ return GRUB_ERR_READ_ERROR;
+ }
+
+ grub_file_close(file);
+
+ /* Now that the kernel image has been loaded, let's muck about with some
+ real-mode BIOS calls to dig out the E820 memory maps.
+
+ Note that I had to export grub_get_mmap_entry() for this.
+
+ I'm putting this as close to the end as possible since I don't know how
+ the grub_get_mmap_entry() calls might affect everything else. Who can
+ tell? We are at the mercy of the BIOS! (yes, this is a plea to make the
+ memory map information available...) */
+
+ /* from linux/include/asm-x86_64/e820.h - seems to be the same for i386 */
+ struct e820entry {
+ grub_uint64_t addr; /* start of memory segment */
+ grub_uint64_t size; /* size of memory segment */
+ grub_uint32_t type; /* type of memory segment */
+ } __attribute__((packed));
+
+ /* linux/include/asm-x86_64/e820.h: */
+ // #define E820MAP 0x2d0 /* our map */
+
+ struct e820entry *e820map = ((struct e820entry *) ((char *)lh + 0x2d0));
+
+ struct grub_machine_mmap_entry entry;
+ lp->mmap_size=0; /* number of e820 regions */
+ cont=0;
+ do
+ {
+ cont = grub_get_mmap_entry (&entry,cont);
+ e820map[lp->mmap_size].addr = entry.addr;
+ e820map[lp->mmap_size].size = entry.len;
+ e820map[lp->mmap_size].type = entry.type;
+ lp->mmap_size++;
+ }
+ while(cont);
+
+
+ /* Well, that's about it. Let's make it official. */
+
+ grub_loader_set (grub_vmlinux_boot, grub_vmlinux_unload, 1);
+ return GRUB_ERR_NONE;
+}
+
+GRUB_MOD_INIT(vmlinux)
+{
+ this_mod = mod; /* To stop warning. */
+ grub_register_command ("vmlinux", grub_cmd_vmlinux, GRUB_COMMAND_FLAG_BOTH,
+ "vmlinux", "Load a Linux vmlinux.bin kernel image", options);
+}
+
+GRUB_MOD_FINI(vmlinux)
+{
+ grub_unregister_command ("vmlinux");
+}
+
+#if 0
+
+Some notes on boot parameter offsets.
+
+ // include/asm-x86_64/bootsetup.h contains a wealth of information about
+ // what needs to go into real_mode_data. A *wealth*!
+ // It also explains that the first 0x200 bytes of real_mode_data are
+ // defined by the contents of boot/bootsect.S, and the next 0xcff - which
+ // takes us to 0xfff, or 4k (0x1000) - are defined in boot/setup.S.
+ //
+ // So the layout goes, roughly:
+ // 0-0x200: bootsect.S - obviously, many of these are obsolete
+ // 0 _start
+ // 8 _start2
+ // 0x18 msg_loop
+ // 0x26 die
+ // 0x31 bugger_off_msg - I think the first real one follows
+ // ** everything before this point is part of struct screen_info
+ // 0x1f1 setup_sects // appears to be unused
+ // 0x1f2 root_flags
+ // 0x1f4 syssize
+ // 0x1f6 swap_dev
+ // 0x1f8 ram_size
+ // 0x1fa vid_mode
+ // 0x1fc root_dev
+ // 0x1fe boot_flag // AUX_DEVICE_INFO - obsolete PS/2 mouse info
+ // 0x200-0xfff : hmm, this is not all used. The last 0x100 bytes particularly
+ // (0xf00-0xfff) appear to just be setup.S code. Oh, add 0x200 to each item.
+ // 0 begtext
+ // 8 realmode_switch
+ // 0xc start_sys_seg
+ // 0x10 type_of_loader // possibly signal multiboot info here?
+ // 0x11 loadflags
+ // 0x12 setup_move_size
+ // 0x14 code32_start // not used by the kernel
+ // 0x18 ramdisk_image
+ // 0x1c ramdisk_size
+ // 0x20 bootsect_kludge // I wonder what the heck this was
+ // 0x24 heap_end_ptr
+ // 0x26 padl
+ // 0x28 cmd_line_ptr
+ // 0x2c ramdisk_max // seems obsolete
+ // 0x30 trampoline
+ // 0xd00 start_of_setup // ok, the last defined thing is 0x230,
+ // // 'trampoline'. Since the end of our space
+ // // is 0x1000, that leaves 0xdd0 for memory
+ // // maps and such.
+ // 0x228 : NEW_CL_POINTER, defined in arch/x86_64/kernel/head64.c
+ // also COMMAND_LINE_SIZE is defined as 256 bytes so... hmm.
+#endif