diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index a03f721..1a0e54b 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -152,7 +152,8 @@ pkglib_MODULES = biosdisk.mod _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 cpuid.mod serial.mod \
- ata.mod vga.mod memdisk.mod jpeg.mod png.mod pci.mod lspci.mod
+ ata.mod vga.mod memdisk.mod jpeg.mod png.mod pci.mod lspci.mod \
+ aout.mod _bsd.mod bsd.mod
# For biosdisk.mod.
biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
@@ -304,4 +305,19 @@ lspci_mod_SOURCES = commands/lspci.c
lspci_mod_CFLAGS = $(COMMON_CFLAGS)
lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For aout.mod
+aout_mod_SOURCES = loader/aout.c
+aout_mod_CFLAGS = $(COMMON_CFLAGS)
+aout_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For _bsd.mod
+_bsd_mod_SOURCES = loader/i386/bsd.c
+_bsd_mod_CFLAGS = $(COMMON_CFLAGS)
+_bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For bsd.mod
+bsd_mod_SOURCES = loader/i386/bsd_normal.c
+bsd_mod_CFLAGS = $(COMMON_CFLAGS)
+bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
include $(srcdir)/conf/common.mk
diff --git a/include/grub/aout.h b/include/grub/aout.h
new file mode 100755
index 0000000..3243b82
--- /dev/null
+++ b/include/grub/aout.h
@@ -0,0 +1,91 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see .
+ */
+
+#ifndef GRUB_AOUT_HEADER
+#define GRUB_AOUT_HEADER 1
+
+#include
+
+struct grub_aout32_header
+{
+ grub_uint32_t a_midmag; /* htonl(flags<<26 | mid<<16 | magic) */
+ grub_uint32_t a_text; /* text segment size */
+ grub_uint32_t a_data; /* initialized data size */
+ grub_uint32_t a_bss; /* uninitialized data size */
+ grub_uint32_t a_syms; /* symbol table size */
+ grub_uint32_t a_entry; /* entry point */
+ grub_uint32_t a_trsize; /* text relocation size */
+ grub_uint32_t a_drsize; /* data relocation size */
+};
+
+struct grub_aout64_header
+{
+ grub_uint32_t a_midmag; /* htonl(flags<<26 | mid<<16 | magic) */
+ grub_uint64_t a_text; /* text segment size */
+ grub_uint64_t a_data; /* initialized data size */
+ grub_uint64_t a_bss; /* uninitialized data size */
+ grub_uint64_t a_syms; /* symbol table size */
+ grub_uint64_t a_entry; /* entry point */
+ grub_uint64_t a_trsize; /* text relocation size */
+ grub_uint64_t a_drsize; /* data relocation size */
+};
+
+union grub_aout_header
+{
+ struct grub_aout32_header aout32;
+ struct grub_aout64_header aout64;
+};
+
+#define AOUT_TYPE_NONE 0
+#define AOUT_TYPE_AOUT32 1
+#define AOUT_TYPE_AOUT64 6
+
+#define AOUT32_OMAGIC 0x107 /* 0407 old impure format */
+#define AOUT32_NMAGIC 0x108 /* 0410 read-only text */
+#define AOUT32_ZMAGIC 0x10b /* 0413 demand load format */
+#define AOUT32_QMAGIC 0xcc /* 0314 "compact" demand load format */
+
+#define AOUT64_OMAGIC 0x1001
+#define AOUT64_ZMAGIC 0x1002
+#define AOUT64_NMAGIC 0x1003
+
+#define AOUT_MID_ZERO 0 /* unknown - implementation dependent */
+#define AOUT_MID_SUN010 1 /* sun 68010/68020 binary */
+#define AOUT_MID_SUN020 2 /* sun 68020-only binary */
+#define AOUT_MID_I386 134 /* i386 BSD binary */
+#define AOUT_MID_SPARC 138 /* sparc */
+#define AOUT_MID_HP200 200 /* hp200 (68010) BSD binary */
+#define AOUT_MID_HP300 300 /* hp300 (68020+68881) BSD binary */
+#define AOUT_MID_HPUX 0x20C /* hp200/300 HP-UX binary */
+#define AOUT_MID_HPUX800 0x20B /* hp800 HP-UX binary */
+
+#define AOUT_FLAG_PIC 0x10 /* contains position independant code */
+#define AOUT_FLAG_DYNAMIC 0x20 /* contains run-time link-edit info */
+#define AOUT_FLAG_DPMASK 0x30 /* mask for the above */
+
+#define AOUT_GETMAGIC(header) ((header).a_midmag & 0xffff)
+#define AOUT_GETMID(header) ((header).a_midmag >> 16) & 0x03ff)
+#define AOUT_GETFLAG(header) ((header).a_midmag >> 26) & 0x3f)
+
+int EXPORT_FUNC(grub_aout_get_type) (union grub_aout_header *header);
+
+grub_err_t EXPORT_FUNC(grub_aout_load) (grub_file_t file, int offset,
+ grub_addr_t load_addr, int load_size,
+ grub_addr_t bss_end_addr);
+
+#endif /* ! GRUB_AOUT_HEADER */
diff --git a/include/grub/i386/bsd.h b/include/grub/i386/bsd.h
new file mode 100755
index 0000000..f88c694
--- /dev/null
+++ b/include/grub/i386/bsd.h
@@ -0,0 +1,232 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see .
+ */
+
+#ifndef GRUB_BSD_CPU_HEADER
+#define GRUB_BSD_CPU_HEADER 1
+
+#include
+
+#define KERNEL_TYPE_NONE 0
+#define KERNEL_TYPE_FREEBSD 1
+#define KERNEL_TYPE_OPENBSD 2
+#define KERNEL_TYPE_NETBSD 3
+
+#define GRUB_BSD_TEMP_BUFFER 0x68000
+
+#define FREEBSD_RB_ASKNAME (1 << 0) /* ask for file name to reboot from */
+#define FREEBSD_RB_SINGLE (1 << 1) /* reboot to single user only */
+#define FREEBSD_RB_NOSYNC (1 << 2) /* dont sync before reboot */
+#define FREEBSD_RB_HALT (1 << 3) /* don't reboot, just halt */
+#define FREEBSD_RB_INITNAME (1 << 4) /* name given for /etc/init (unused) */
+#define FREEBSD_RB_DFLTROOT (1 << 5) /* use compiled-in rootdev */
+#define FREEBSD_RB_KDB (1 << 6) /* give control to kernel debugger */
+#define FREEBSD_RB_RDONLY (1 << 7) /* mount root fs read-only */
+#define FREEBSD_RB_DUMP (1 << 8) /* dump kernel memory before reboot */
+#define FREEBSD_RB_MINIROOT (1 << 9) /* mini-root present in memory at boot time */
+#define FREEBSD_RB_CONFIG (1 << 10) /* invoke user configuration routing */
+#define FREEBSD_RB_VERBOSE (1 << 11) /* print all potentially useful info */
+#define FREEBSD_RB_SERIAL (1 << 12) /* user serial port as console */
+#define FREEBSD_RB_CDROM (1 << 13) /* use cdrom as root */
+#define FREEBSD_RB_GDB (1 << 15) /* use GDB remote debugger instead of DDB */
+#define FREEBSD_RB_MUTE (1 << 16) /* Come up with the console muted */
+#define FREEBSD_RB_PAUSE (1 << 20)
+#define FREEBSD_RB_QUIET (1 << 21)
+#define FREEBSD_RB_NOINTR (1 << 28)
+#define FREENSD_RB_MULTIPLE (1 << 29) /* Use multiple consoles */
+#define FREEBSD_RB_DUAL FREENSD_RB_MULTIPLE
+#define FREEBSD_RB_BOOTINFO (1 << 31) /* have `struct bootinfo *' arg */
+
+#define FREEBSD_B_DEVMAGIC 0xa0000000
+#define FREEBSD_B_SLICESHIFT 20
+#define FREEBSD_B_UNITSHIFT 16
+#define FREEBSD_B_PARTSHIFT 8
+#define FREEBSD_B_TYPESHIFT 0
+
+#define FREEBSD_BOOTINFO_VERSION 1
+#define FREEBSD_N_BIOS_GEOM 8
+
+#define FREEBSD_MODINFO_END 0x0000 /* End of list */
+#define FREEBSD_MODINFO_NAME 0x0001 /* Name of module (string) */
+#define FREEBSD_MODINFO_TYPE 0x0002 /* Type of module (string) */
+#define FREEBSD_MODINFO_ADDR 0x0003 /* Loaded address */
+#define FREEBSD_MODINFO_SIZE 0x0004 /* Size of module */
+#define FREEBSD_MODINFO_EMPTY 0x0005 /* Has been deleted */
+#define FREEBSD_MODINFO_ARGS 0x0006 /* Parameters string */
+#define FREEBSD_MODINFO_METADATA 0x8000 /* Module-specfic */
+
+#define FREEBSD_MODINFOMD_AOUTEXEC 0x0001 /* a.out exec header */
+#define FREEBSD_MODINFOMD_ELFHDR 0x0002 /* ELF header */
+#define FREEBSD_MODINFOMD_SSYM 0x0003 /* start of symbols */
+#define FREEBSD_MODINFOMD_ESYM 0x0004 /* end of symbols */
+#define FREEBSD_MODINFOMD_DYNAMIC 0x0005 /* _DYNAMIC pointer */
+#define FREEBSD_MODINFOMD_ENVP 0x0006 /* envp[] */
+#define FREEBSD_MODINFOMD_HOWTO 0x0007 /* boothowto */
+#define FREEBSD_MODINFOMD_KERNEND 0x0008 /* kernend */
+#define FREEBSD_MODINFOMD_SHDR 0x0009 /* section header table */
+#define FREEBSD_MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */
+
+#define FREEBSD_MODINFOMD_DEPLIST (0x4001 | FREEBSD_MODINFOMD_NOCOPY) /* depends on */
+
+#define FREEBSD_MODTYPE_KERNEL "elf kernel"
+#define FREEBSD_MODTYPE_MODULE "elf module"
+#define FREEBSD_MODTYPE_RAW "raw"
+
+struct grub_freebsd_bootinfo
+{
+ grub_uint32_t bi_version;
+ grub_uint8_t *bi_kernelname;
+ struct nfs_diskless *bi_nfs_diskless;
+ grub_uint32_t bi_n_bios_used;
+ grub_uint32_t bi_bios_geom[FREEBSD_N_BIOS_GEOM];
+ grub_uint32_t bi_size;
+ grub_uint8_t bi_memsizes_valid;
+ grub_uint8_t bi_bios_dev;
+ grub_uint8_t bi_pad[2];
+ grub_uint32_t bi_basemem;
+ grub_uint32_t bi_extmem;
+ grub_uint32_t bi_symtab;
+ grub_uint32_t bi_esymtab;
+ grub_uint32_t bi_kernend;
+ grub_uint32_t bi_envp;
+ grub_uint32_t bi_modulep;
+} __attribute__ ((packed));
+
+#define OPENBSD_RB_ASKNAME (1 << 0) /* ask for file name to reboot from */
+#define OPENBSD_RB_SINGLE (1 << 1) /* reboot to single user only */
+#define OPENBSD_RB_NOSYNC (1 << 2) /* dont sync before reboot */
+#define OPENBSD_RB_HALT (1 << 3) /* don't reboot, just halt */
+#define OPENBSD_RB_INITNAME (1 << 4) /* name given for /etc/init (unused) */
+#define OPENBSD_RB_DFLTROOT (1 << 5) /* use compiled-in rootdev */
+#define OPENBSD_RB_KDB (1 << 6) /* give control to kernel debugger */
+#define OPENBSD_RB_RDONLY (1 << 7) /* mount root fs read-only */
+#define OPENBSD_RB_DUMP (1 << 8) /* dump kernel memory before reboot */
+#define OPENBSD_RB_MINIROOT (1 << 9) /* mini-root present in memory at boot time */
+#define OPENBSD_RB_CONFIG (1 << 10) /* change configured devices */
+#define OPENBSD_RB_TIMEBAD (1 << 11) /* don't call resettodr() in boot() */
+#define OPENBSD_RB_POWERDOWN (1 << 12) /* attempt to power down machine */
+#define OPENBSD_RB_SERCONS (1 << 13) /* use serial console if available */
+#define OPENBSD_RB_USERREQ (1 << 14) /* boot() called at user request (e.g. ddb) */
+
+#define OPENBSD_B_DEVMAGIC 0xa0000000
+#define OPENBSD_B_ADAPTORSHIFT 24
+#define OPENBSD_B_CTRLSHIFT 20
+#define OPENBSD_B_UNITSHIFT 16
+#define OPENBSD_B_PARTSHIFT 8
+#define OPENBSD_B_TYPESHIFT 0
+
+#define OPENBSD_BOOTARG_APIVER (OPENBSD_BAPIV_VECTOR | \
+ OPENBSD_BAPIV_ENV | \
+ OPENBSD_BAPIV_BMEMMAP)
+
+#define OPENBSD_BAPIV_ANCIENT 0x0 /* MD old i386 bootblocks */
+#define OPENBSD_BAPIV_VARS 0x1 /* MD structure w/ add info passed */
+#define OPENBSD_BAPIV_VECTOR 0x2 /* MI vector of MD structures passed */
+#define OPENBSD_BAPIV_ENV 0x4 /* MI environment vars vector */
+#define OPENBSD_BAPIV_BMEMMAP 0x8 /* MI memory map passed is in bytes */
+
+#define OPENBSD_BOOTARG_ENV 0x1000
+#define OPENBSD_BOOTARG_END -1
+
+#define OPENBSD_BOOTARG_MMAP 0
+
+struct grub_openbsd_bios_mmap
+{
+ grub_uint64_t addr;
+ grub_uint64_t len;
+ grub_uint32_t type;
+} bios_memmap_t;
+
+struct grub_openbsd_bootargs
+{
+ int ba_type;
+ int ba_size;
+ struct grub_openbsd_bootargs *ba_next;
+} __attribute__ ((packed));
+
+#define NETBSD_RB_AUTOBOOT 0 /* flags for system auto-booting itself */
+
+#define NETBSD_RB_ASKNAME (1 << 0) /* ask for file name to reboot from */
+#define NETBSD_RB_SINGLE (1 << 1) /* reboot to single user only */
+#define NETBSD_RB_NOSYNC (1 << 2) /* dont sync before reboot */
+#define NETBSD_RB_HALT (1 << 3) /* don't reboot, just halt */
+#define NETBSD_RB_INITNAME (1 << 4) /* name given for /etc/init (unused) */
+#define NETBSD_RB_UNUSED1 (1 << 5) /* was RB_DFLTROOT, obsolete */
+#define NETBSD_RB_KDB (1 << 6) /* give control to kernel debugger */
+#define NETBSD_RB_RDONLY (1 << 7) /* mount root fs read-only */
+#define NETBSD_RB_DUMP (1 << 8) /* dump kernel memory before reboot */
+#define NETBSD_RB_MINIROOT (1 << 9) /* mini-root present in memory at boot time */
+#define NETBSD_RB_STRING (1 << 10) /* use provided bootstr */
+#define NETBSD_RB_POWERDOWN ((1 << 11) | RB_HALT) /* turn power off (or at least halt) */
+#define NETBSD_RB_USERCONFIG (1 << 12) /* change configured devices */
+
+#define NETBSD_AB_NORMAL 0 /* boot normally (default) */
+
+#define NETBSD_AB_QUIET (1 << 16) /* boot quietly */
+#define NETBSD_AB_VERBOSE (1 << 17) /* boot verbosely */
+#define NETBSD_AB_SILENT (1 << 18) /* boot silently */
+#define NETBSD_AB_DEBUG (1 << 19) /* boot with debug messages */
+
+struct grub_netbsd_bootinfo
+{
+ grub_uint32_t bi_count;
+ void *bi_data[1];
+};
+
+#define NETBSD_BTINFO_BOOTPATH 0
+#define NETBSD_BTINFO_ROOTDEVICE 1
+#define NETBSD_BTINFO_BOOTDISK 3
+
+struct grub_netbsd_btinfo_common
+{
+ int len;
+ int type;
+};
+
+struct grub_netbsd_btinfo_bootpath
+{
+ struct grub_netbsd_btinfo_common common;
+ char bootpath[80];
+};
+
+struct grub_netbsd_btinfo_rootdevice
+{
+ struct grub_netbsd_btinfo_common common;
+ char devname[16];
+};
+
+struct grub_netbsd_btinfo_bootdisk
+{
+ struct grub_netbsd_btinfo_common common;
+ int labelsector; /* label valid if != -1 */
+ struct
+ {
+ grub_uint16_t type, checksum;
+ char packname[16];
+ } label;
+ int biosdev;
+ int partition;
+};
+
+void grub_rescue_cmd_freebsd (int argc, char *argv[]);
+void grub_rescue_cmd_openbsd (int argc, char *argv[]);
+void grub_rescue_cmd_netbsd (int argc, char *argv[]);
+
+void grub_rescue_cmd_freebsd_loadenv (int argc, char *argv[]);
+void grub_rescue_cmd_freebsd_module (int argc, char *argv[]);
+
+#endif /* ! GRUB_BSD_CPU_HEADER */
diff --git a/include/grub/i386/loader.h b/include/grub/i386/loader.h
index 45a1652..5f912cd 100644
--- a/include/grub/i386/loader.h
+++ b/include/grub/i386/loader.h
@@ -39,6 +39,9 @@ void EXPORT_FUNC(grub_multiboot_real_boot) (grub_addr_t entry,
void EXPORT_FUNC(grub_multiboot2_real_boot) (grub_addr_t entry,
struct grub_multiboot_info *mbi)
__attribute__ ((noreturn));
+void EXPORT_FUNC(grub_unix_real_boot) (grub_addr_t entry, ...)
+ __attribute__ ((cdecl,noreturn));
+
/* It is necessary to export these functions, because normal mode commands
reuse rescue mode commands. */
diff --git a/include/grub/i386/pc/init.h b/include/grub/i386/pc/init.h
index 115deb4..0c6a129 100644
--- a/include/grub/i386/pc/init.h
+++ b/include/grub/i386/pc/init.h
@@ -40,7 +40,7 @@ struct grub_machine_mmap_entry
/* 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 EXPORT_FUNC(grub_get_mmap_entry) (struct grub_machine_mmap_entry *entry,
grub_uint32_t cont);
/* Turn on/off Gate A20. */
diff --git a/kern/elf.c b/kern/elf.c
index ca10b5b..cb8a722 100644
--- a/kern/elf.c
+++ b/kern/elf.c
@@ -85,9 +85,8 @@ grub_elf_file (grub_file_t file)
return elf;
fail:
- grub_error_push ();
- grub_elf_close (elf);
- grub_error_pop ();
+ grub_free (elf->phdrs);
+ grub_free (elf);
return 0;
}
@@ -95,12 +94,17 @@ grub_elf_t
grub_elf_open (const char *name)
{
grub_file_t file;
+ grub_elf_t elf;
file = grub_gzfile_open (name, 1);
if (! file)
return 0;
- return grub_elf_file (file);
+ elf = grub_elf_file (file);
+ if (! elf)
+ grub_file_close (file);
+
+ return elf;
}
@@ -177,8 +181,8 @@ grub_elf32_size (grub_elf_t elf)
/* Run through the program headers to calculate the total memory size we
* should claim. */
- auto int calcsize (grub_elf_t _elf, Elf32_Phdr *phdr, void *_arg);
- int calcsize (grub_elf_t UNUSED _elf, Elf32_Phdr *phdr, void UNUSED *_arg)
+ auto int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf, Elf32_Phdr *phdr, void *_arg);
+ int NESTED_FUNC_ATTR calcsize (grub_elf_t UNUSED _elf, Elf32_Phdr *phdr, void UNUSED *_arg)
{
/* Only consider loadable segments. */
if (phdr->p_type != PT_LOAD)
@@ -228,9 +232,9 @@ grub_elf32_load (grub_elf_t _elf, grub_elf32_load_hook_t _load_hook,
if (phdr->p_type != PT_LOAD)
return 0;
- load_addr = phdr->p_paddr;
if (load_hook && load_hook (phdr, &load_addr))
return 1;
+ load_addr = phdr->p_paddr;
if (load_addr < load_base)
load_base = load_addr;
@@ -355,8 +359,8 @@ grub_elf64_size (grub_elf_t elf)
/* Run through the program headers to calculate the total memory size we
* should claim. */
- auto int calcsize (grub_elf_t _elf, Elf64_Phdr *phdr, void *_arg);
- int calcsize (grub_elf_t UNUSED _elf, Elf64_Phdr *phdr, void UNUSED *_arg)
+ auto int NESTED_FUNC_ATTR calcsize (grub_elf_t _elf, Elf64_Phdr *phdr, void *_arg);
+ int NESTED_FUNC_ATTR calcsize (grub_elf_t UNUSED _elf, Elf64_Phdr *phdr, void UNUSED *_arg)
{
/* Only consider loadable segments. */
if (phdr->p_type != PT_LOAD)
@@ -407,9 +411,9 @@ grub_elf64_load (grub_elf_t _elf, grub_elf64_load_hook_t _load_hook,
if (phdr->p_type != PT_LOAD)
return 0;
- load_addr = phdr->p_paddr;
if (load_hook && load_hook (phdr, &load_addr))
return 1;
+ load_addr = phdr->p_paddr;
if (load_addr < load_base)
load_base = load_addr;
diff --git a/kern/i386/loader.S b/kern/i386/loader.S
index 266f4ef..39cf6a0 100644
--- a/kern/i386/loader.S
+++ b/kern/i386/loader.S
@@ -162,3 +162,27 @@ FUNCTION(grub_multiboot2_real_boot)
movl $MULTIBOOT2_BOOTLOADER_MAGIC,%eax
popl %ecx
jmp *%ecx
+
+/*
+ * Use cdecl calling convention for *BSD kernels.
+ */
+
+FUNCTION(grub_unix_real_boot)
+
+ call EXT_C(grub_dl_unload_all)
+ call EXT_C(grub_stop_floppy)
+
+ /* Interrupts should be disabled. */
+ cli
+
+ /* Discard `grub_unix_real_boot' return address. */
+ popl %eax
+
+ /* Fetch `entry' address ... */
+ popl %eax
+
+ /*
+ * ... and put our return address in its place. The kernel will
+ * ignore it, but it expects %esp to point to it.
+ */
+ call *%eax
diff --git a/loader/aout.c b/loader/aout.c
new file mode 100755
index 0000000..2c82b60
--- /dev/null
+++ b/loader/aout.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008 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 3 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, see .
+ */
+
+#include
+#include
+#include
+#include
+
+int
+grub_aout_get_type (union grub_aout_header *header)
+{
+ int magic;
+
+ magic = AOUT_GETMAGIC (header->aout32);
+ if ((magic == AOUT32_OMAGIC) || (magic == AOUT32_NMAGIC) ||
+ (magic == AOUT32_ZMAGIC) || (magic == AOUT32_QMAGIC))
+ return AOUT_TYPE_AOUT32;
+ else if ((magic == AOUT64_OMAGIC) || (magic == AOUT64_NMAGIC) ||
+ (magic == AOUT64_ZMAGIC))
+ return AOUT_TYPE_AOUT64;
+ else
+ return AOUT_TYPE_NONE;
+}
+
+grub_err_t
+grub_aout_load (grub_file_t file, int offset,
+ grub_addr_t load_addr,
+ int load_size,
+ grub_addr_t bss_end_addr)
+{
+ if ((grub_file_seek (file, offset)) == (grub_off_t) - 1)
+ return grub_errno;
+
+ if (!load_size)
+ load_size = file->size - offset;
+
+ grub_file_read (file, (char *) load_addr, load_size);
+
+ if (grub_errno)
+ return grub_errno;
+
+ if (bss_end_addr)
+ grub_memset (load_addr + load_size, 0,
+ bss_end_addr - load_addr - load_size);
+
+ return GRUB_ERR_NONE;
+}
diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c
new file mode 100644
index 0000000..4966afa
--- /dev/null
+++ b/loader/i386/bsd.c
@@ -0,0 +1,771 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define ALIGN_DWORD(a) ALIGN_UP (a, 4)
+#define ALIGN_PAGE(a) ALIGN_UP (a, 4096)
+
+#define MOD_BUF_ALLOC_UNIT 4096
+
+static int kernel_type;
+static grub_dl_t my_mod;
+static grub_addr_t entry, kern_start, kern_end;
+static grub_uint32_t bootflags;
+static char *mod_buf;
+static grub_uint32_t mod_buf_len, mod_buf_max;
+static int is_elf_kernel;
+
+static const char freebsd_opts[] = "DhaCcdgmnpqrsv";
+static const grub_uint32_t freebsd_flags[] =
+{
+ FREEBSD_RB_DUAL, FREEBSD_RB_SERIAL, FREEBSD_RB_ASKNAME,
+ FREEBSD_RB_CDROM, FREEBSD_RB_CONFIG, FREEBSD_RB_KDB,
+ FREEBSD_RB_GDB, FREEBSD_RB_MUTE, FREEBSD_RB_NOINTR,
+ FREEBSD_RB_PAUSE, FREEBSD_RB_QUIET, FREEBSD_RB_DFLTROOT,
+ FREEBSD_RB_SINGLE, FREEBSD_RB_VERBOSE
+};
+
+static const char openbsd_opts[] = "abcsd";
+static const grub_uint32_t openbsd_flags[] =
+{
+ OPENBSD_RB_ASKNAME, OPENBSD_RB_HALT, OPENBSD_RB_CONFIG,
+ OPENBSD_RB_SINGLE, OPENBSD_RB_KDB
+};
+
+static const char netbsd_opts[] = "abcdmqsvxz";
+static const grub_uint32_t netbsd_flags[] =
+{
+ NETBSD_RB_ASKNAME, NETBSD_RB_HALT, NETBSD_RB_USERCONFIG,
+ NETBSD_RB_KDB, NETBSD_RB_MINIROOT, NETBSD_AB_QUIET,
+ NETBSD_RB_SINGLE, NETBSD_AB_VERBOSE, NETBSD_AB_DEBUG,
+ NETBSD_AB_SILENT
+};
+
+static void
+grub_bsd_get_device (grub_uint32_t * biosdev,
+ grub_uint32_t * unit,
+ grub_uint32_t * slice, grub_uint32_t * part)
+{
+ char *p;
+
+ *biosdev = *unit = *slice = *part = 0;
+ p = grub_env_get ("root");
+ if ((p) && ((p[0] == 'h') || (p[0] == 'f')) && (p[1] == 'd') &&
+ (p[2] >= '0') && (p[2] <= '9'))
+ {
+ if (p[0] == 'h')
+ *biosdev = 0x80;
+
+ *unit = grub_strtoul (p + 2, &p, 0);
+ *biosdev += *unit;
+
+ if ((p) && (p[0] == ','))
+ {
+ if ((p[1] >= '0') && (p[1] <= '9'))
+ {
+ *slice = grub_strtoul (p + 1, &p, 0);
+
+ if ((p) && (p[0] == ','))
+ p++;
+ }
+
+ if ((p[0] >= 'a') && (p[0] <= 'z'))
+ *part = p[0] - 'a';
+ }
+ }
+}
+
+static grub_err_t
+grub_freebsd_add_meta (grub_uint32_t type, void *data, grub_uint32_t len)
+{
+ if (mod_buf_max < mod_buf_len + len + 8)
+ {
+ char *new_buf;
+
+ do
+ {
+ mod_buf_max += MOD_BUF_ALLOC_UNIT;
+ }
+ while (mod_buf_max < mod_buf_len + len + 8);
+
+ new_buf = grub_malloc (mod_buf_max);
+ if (!new_buf)
+ return grub_errno;
+
+ grub_memcpy (new_buf, mod_buf, mod_buf_len);
+ grub_free (mod_buf);
+
+ mod_buf = new_buf;
+ }
+
+ *((grub_uint32_t *) (mod_buf + mod_buf_len)) = type;
+ *((grub_uint32_t *) (mod_buf + mod_buf_len + 4)) = len;
+ mod_buf_len += 8;
+
+ if (len)
+ grub_memcpy (mod_buf + mod_buf_len, data, len);
+
+ mod_buf_len = ALIGN_DWORD (mod_buf_len + len);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_freebsd_add_meta_module (int is_kern, int argc, char **argv,
+ grub_addr_t addr, grub_uint32_t size)
+{
+ char *name, *type;
+
+ name = grub_strrchr (argv[0], '/');
+ if (name)
+ name++;
+ else
+ name = argv[0];
+
+ if (grub_freebsd_add_meta (FREEBSD_MODINFO_NAME, name,
+ grub_strlen (name) + 1))
+ return grub_errno;
+
+ argc--;
+ argv++;
+
+ if ((argc) && (!grub_memcmp (argv[0], "type=", 5)))
+ {
+ type = &argv[0][5];
+ argc--;
+ argv++;
+ }
+ else
+ type = (is_kern) ? FREEBSD_MODTYPE_KERNEL : FREEBSD_MODTYPE_RAW;
+
+ if ((grub_freebsd_add_meta (FREEBSD_MODINFO_TYPE, type,
+ grub_strlen (type) + 1)) ||
+ (grub_freebsd_add_meta (FREEBSD_MODINFO_ADDR, &addr, sizeof (addr))) ||
+ (grub_freebsd_add_meta (FREEBSD_MODINFO_SIZE, &size, sizeof (size))))
+ return grub_errno;
+
+ if (argc)
+ {
+ int i, n;
+
+ n = 0;
+ for (i = 0; i < argc; i++)
+ {
+ n += grub_strlen (argv[i]) + 1;
+ }
+
+ if (n)
+ {
+ char cmdline[n], *p;
+
+ p = cmdline;
+ for (i = 0; i < argc; i++)
+ {
+ grub_strcpy (p, argv[i]);
+ p += grub_strlen (argv[i]);
+ *(p++) = ' ';
+ }
+ *p = 0;
+
+ if (grub_freebsd_add_meta (FREEBSD_MODINFO_ARGS, cmdline, n))
+ return grub_errno;
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static void
+grub_freebsd_list_modules (void)
+{
+ grub_uint32_t pos = 0;
+
+ grub_printf (" %-18s %-18s%14s%14s\n", "name", "type", "addr", "size");
+ while (pos < mod_buf_len)
+ {
+ grub_uint32_t type, size;
+
+ type = *((grub_uint32_t *) (mod_buf + pos));
+ size = *((grub_uint32_t *) (mod_buf + pos + 4));
+ pos += 8;
+ switch (type)
+ {
+ case FREEBSD_MODINFO_NAME:
+ case FREEBSD_MODINFO_TYPE:
+ grub_printf (" %-18s", mod_buf + pos);
+ break;
+ case FREEBSD_MODINFO_ADDR:
+ {
+ grub_addr_t addr;
+
+ addr = *((grub_addr_t *) (mod_buf + pos));
+ grub_printf (" 0x%08x", addr);
+ break;
+ }
+ case FREEBSD_MODINFO_SIZE:
+ {
+ grub_uint32_t len;
+
+ len = *((grub_uint32_t *) (mod_buf + pos));
+ grub_printf (" 0x%08x\n", len);
+ }
+ }
+
+ pos = ALIGN_DWORD (pos + size);
+ }
+}
+
+static grub_err_t
+grub_freebsd_boot (void)
+{
+ struct grub_freebsd_bootinfo bi;
+ char *p;
+ grub_uint32_t bootdev, biosdev, unit, slice, part;
+
+ auto int iterate_env (struct grub_env_var *var);
+ int iterate_env (struct grub_env_var *var)
+ {
+ if ((!grub_memcmp (var->name, "FreeBSD.", 8)) && (var->name[8]))
+ {
+ grub_strcpy (p, &var->name[8]);
+ p += grub_strlen (p);
+ *(p++) = '=';
+ grub_strcpy (p, var->value);
+ p += grub_strlen (p) + 1;
+ }
+
+ return 0;
+ }
+
+ grub_memset (&bi, 0, sizeof (bi));
+ bi.bi_version = FREEBSD_BOOTINFO_VERSION;
+ bi.bi_size = sizeof (bi);
+
+ grub_bsd_get_device (&biosdev, &unit, &slice, &part);
+ bootdev = (FREEBSD_B_DEVMAGIC + ((slice + 1) << FREEBSD_B_SLICESHIFT) +
+ (unit << FREEBSD_B_UNITSHIFT) + (part << FREEBSD_B_PARTSHIFT));
+
+ bi.bi_bios_dev = biosdev;
+
+ p = (char *) kern_end;
+
+ grub_env_iterate (iterate_env);
+
+ if (p != (char *) kern_end)
+ {
+ *(p++) = 0;
+
+ bi.bi_envp = kern_end;
+ kern_end = ALIGN_PAGE ((grub_uint32_t) p);
+ }
+
+ if (is_elf_kernel)
+ {
+ if (grub_freebsd_add_meta (FREEBSD_MODINFO_END, 0, 0))
+ return grub_errno;
+
+ grub_memcpy ((char *) kern_end, mod_buf, mod_buf_len);
+ bi.bi_modulep = kern_end;
+
+ kern_end = ALIGN_PAGE (kern_end + mod_buf_len);
+ }
+
+ bi.bi_kernend = kern_end;
+
+ grub_unix_real_boot (entry, bootflags | FREEBSD_RB_BOOTINFO, bootdev,
+ 0, 0, 0, &bi, bi.bi_modulep, kern_end);
+
+ /* Not reached. */
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_openbsd_boot (void)
+{
+ char *buf = (char *) GRUB_BSD_TEMP_BUFFER;
+ struct grub_machine_mmap_entry mmap;
+ struct grub_openbsd_bios_mmap *pm;
+ struct grub_openbsd_bootargs *pa;
+ grub_uint32_t bootdev, biosdev, unit, slice, part, cont;
+
+ pa = (struct grub_openbsd_bootargs *) buf;
+
+ pa->ba_type = OPENBSD_BOOTARG_MMAP;
+ pm = (struct grub_openbsd_bios_mmap *) (pa + 1);
+ cont = grub_get_mmap_entry (&mmap, 0);
+ if (mmap.size)
+ do
+ {
+ pm->addr = mmap.addr;
+ pm->len = mmap.len;
+ pm->type = mmap.type;
+ pm++;
+
+ if (!cont)
+ break;
+
+ cont = grub_get_mmap_entry (&mmap, cont);
+ }
+ while (mmap.size);
+
+ pa->ba_size = (char *) pm - (char *) pa;
+ pa->ba_next = (struct grub_openbsd_bootargs *) pm;
+ pa = pa->ba_next;
+ pa->ba_type = OPENBSD_BOOTARG_END;
+ pa++;
+
+ grub_bsd_get_device (&biosdev, &unit, &slice, &part);
+ bootdev = (OPENBSD_B_DEVMAGIC + (unit << OPENBSD_B_UNITSHIFT) +
+ (part << OPENBSD_B_PARTSHIFT));
+
+ grub_unix_real_boot (entry, bootflags, bootdev, OPENBSD_BOOTARG_APIVER,
+ 0, grub_upper_mem >> 10, grub_lower_mem >> 10,
+ (char *) pa - buf, buf);
+
+ /* Not reached. */
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_netbsd_boot (void)
+{
+ struct grub_netbsd_btinfo_rootdevice *rootdev;
+ struct grub_netbsd_bootinfo *bootinfo;
+ grub_uint32_t biosdev, unit, slice, part;
+
+ grub_bsd_get_device (&biosdev, &unit, &slice, &part);
+
+ rootdev = (struct grub_netbsd_btinfo_rootdevice *) GRUB_BSD_TEMP_BUFFER;
+
+ rootdev->common.len = sizeof (struct grub_netbsd_btinfo_rootdevice);
+ rootdev->common.type = NETBSD_BTINFO_ROOTDEVICE;
+ grub_sprintf (rootdev->devname, "%cd%d%c", (biosdev & 0x80) ? 'w' : 'f',
+ unit, 'a' + part);
+
+ bootinfo = (struct grub_netbsd_bootinfo *) (rootdev + 1);
+ bootinfo->bi_count = 1;
+ bootinfo->bi_data[0] = rootdev;
+
+ grub_unix_real_boot (entry, bootflags, 0, bootinfo,
+ 0, grub_upper_mem >> 10, grub_lower_mem >> 10);
+
+ /* Not reached. */
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_bsd_unload (void)
+{
+ if (mod_buf)
+ {
+ grub_free (mod_buf);
+ mod_buf = 0;
+ mod_buf_max = 0;
+ }
+
+ kernel_type = KERNEL_TYPE_NONE;
+ grub_dl_unref (my_mod);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_bsd_load_aout (grub_file_t file)
+{
+ grub_addr_t load_addr, bss_end_addr;
+ int ofs, align_page;
+ union grub_aout_header ah;
+
+ if ((grub_file_seek (file, 0)) == (grub_off_t) - 1)
+ return grub_errno;
+
+ if (grub_file_read (file, (char *) &ah, sizeof (ah)) != sizeof (ah))
+ return grub_error (GRUB_ERR_READ_ERROR, "cannot read the a.out header");
+
+ if (grub_aout_get_type (&ah) != AOUT_TYPE_AOUT32)
+ return grub_error (GRUB_ERR_BAD_OS, "invalid a.out header");
+
+ entry = ah.aout32.a_entry & 0xFFFFFF;
+
+ if (AOUT_GETMAGIC (ah.aout32) == AOUT32_ZMAGIC)
+ {
+ load_addr = entry;
+ ofs = 0x1000;
+ align_page = 0;
+ }
+ else
+ {
+ load_addr = entry & 0xF00000;
+ ofs = sizeof (struct grub_aout32_header);
+ align_page = 1;
+ }
+
+ if (load_addr < 0x100000)
+ return grub_error (GRUB_ERR_BAD_OS, "load address below 1M");
+
+ kern_start = load_addr;
+ kern_end = load_addr + ah.aout32.a_text + ah.aout32.a_data;
+ if (align_page)
+ kern_end = ALIGN_PAGE (kern_end);
+
+ if (ah.aout32.a_bss)
+ {
+ kern_end += ah.aout32.a_bss;
+ if (align_page)
+ kern_end = ALIGN_PAGE (kern_end);
+
+ bss_end_addr = kern_end;
+ }
+ else
+ bss_end_addr = 0;
+
+ return grub_aout_load (file, ofs, load_addr,
+ ah.aout32.a_text + ah.aout32.a_data, bss_end_addr);
+}
+
+static grub_err_t
+grub_bsd_elf32_hook (Elf32_Phdr * phdr, UNUSED grub_addr_t * addr)
+{
+ Elf32_Addr paddr;
+
+ phdr->p_paddr &= 0xFFFFFF;
+ paddr = phdr->p_paddr;
+
+ if ((paddr < grub_os_area_addr)
+ || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Address 0x%x is out of range",
+ paddr);
+
+ if ((!kern_start) || (paddr < kern_start))
+ kern_start = paddr;
+
+ if (paddr + phdr->p_memsz > kern_end)
+ kern_end = paddr + phdr->p_memsz;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_bsd_load_elf (grub_elf_t elf)
+{
+ kern_start = kern_end = 0;
+
+ if (grub_elf_is_elf32 (elf))
+ {
+ entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF;
+ return grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0);
+ }
+ else
+ return grub_error (GRUB_ERR_BAD_OS, "invalid elf");
+}
+
+static grub_err_t
+grub_bsd_load (int argc, char *argv[])
+{
+ grub_file_t file;
+ grub_elf_t elf;
+
+ grub_dl_ref (my_mod);
+
+ grub_loader_unset ();
+
+ if (argc == 0)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
+ goto fail;
+ }
+
+ file = grub_gzfile_open (argv[0], 1);
+ if (!file)
+ goto fail;
+
+ elf = grub_elf_file (file);
+ if (elf)
+ {
+ is_elf_kernel = 1;
+ grub_bsd_load_elf (elf);
+ grub_elf_close (elf);
+ }
+ else
+ {
+ is_elf_kernel = 0;
+ grub_errno = 0;
+ grub_bsd_load_aout (file);
+ grub_file_close (file);
+ }
+
+fail:
+
+ if (grub_errno != GRUB_ERR_NONE)
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+static grub_uint32_t
+grub_bsd_parse_flags (char *str, const char *opts,
+ const grub_uint32_t * flags)
+{
+ grub_uint32_t result = 0;
+
+ while (*str)
+ {
+ const char *po;
+ const grub_uint32_t *pf;
+
+ po = opts;
+ pf = flags;
+ while (*po)
+ {
+ if (*str == *po)
+ {
+ result |= *pf;
+ break;
+ }
+ po++;
+ pf++;
+ }
+ str++;
+ }
+
+ return result;
+}
+
+void
+grub_rescue_cmd_freebsd (int argc, char *argv[])
+{
+ kernel_type = KERNEL_TYPE_FREEBSD;
+ bootflags = ((argc <= 1) ? 0 :
+ grub_bsd_parse_flags (argv[1], freebsd_opts, freebsd_flags));
+
+ if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
+ {
+ kern_end = ALIGN_PAGE (kern_end);
+ if ((is_elf_kernel) &&
+ (grub_freebsd_add_meta_module (1, argc, argv, kern_start,
+ kern_end - kern_start)))
+ return;
+ grub_loader_set (grub_freebsd_boot, grub_bsd_unload, 1);
+ }
+}
+
+void
+grub_rescue_cmd_openbsd (int argc, char *argv[])
+{
+ kernel_type = KERNEL_TYPE_OPENBSD;
+ bootflags = ((argc <= 1) ? 0 :
+ grub_bsd_parse_flags (argv[1], openbsd_opts, openbsd_flags));
+
+ if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
+ grub_loader_set (grub_openbsd_boot, grub_bsd_unload, 1);
+}
+
+void
+grub_rescue_cmd_netbsd (int argc, char *argv[])
+{
+ kernel_type = KERNEL_TYPE_NETBSD;
+ bootflags = ((argc <= 1) ? 0 :
+ grub_bsd_parse_flags (argv[1], netbsd_opts, netbsd_flags));
+
+ if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
+ grub_loader_set (grub_netbsd_boot, grub_bsd_unload, 1);
+}
+
+void
+grub_rescue_cmd_freebsd_loadenv (int argc, char *argv[])
+{
+ grub_file_t file = 0;
+ char *buf = 0, *curr, *next;
+ int len;
+
+ if (kernel_type != KERNEL_TYPE_FREEBSD)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "only freebsd support environment");
+ return;
+ }
+
+ if (argc == 0)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "no filename");
+ goto fail;
+ }
+
+ file = grub_gzfile_open (argv[0], 1);
+ if ((!file) || (!file->size))
+ goto fail;
+
+ len = file->size;
+ buf = grub_malloc (len + 1);
+ if (!buf)
+ goto fail;
+
+ if (grub_file_read (file, buf, len) != len)
+ goto fail;
+
+ buf[len] = 0;
+
+ next = buf;
+ while (next)
+ {
+ char *p;
+
+ curr = next;
+ next = grub_strchr (curr, '\n');
+ if (next)
+ {
+
+ p = next - 1;
+ while (p > curr)
+ {
+ if ((*p != '\r') && (*p != ' ') && (*p != '\t'))
+ break;
+ p--;
+ }
+
+ if ((p > curr) && (*p == '"'))
+ p--;
+
+ *(p + 1) = 0;
+ next++;
+ }
+
+ if (*curr == '#')
+ continue;
+
+ p = grub_strchr (curr, '=');
+ if (!p)
+ continue;
+
+ *(p++) = 0;
+
+ if (*curr)
+ {
+ char name[grub_strlen (curr) + 8 + 1];
+
+ if (*p == '"')
+ p++;
+
+ grub_sprintf (name, "FreeBSD.%s", curr);
+ if (grub_env_set (name, p))
+ goto fail;
+ }
+ }
+
+fail:
+ grub_free (buf);
+
+ if (file)
+ grub_file_close (file);
+}
+
+void
+grub_rescue_cmd_freebsd_module (int argc, char *argv[])
+{
+ grub_file_t file = 0;
+
+ if (kernel_type != KERNEL_TYPE_FREEBSD)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "only freebsd support module");
+ return;
+ }
+
+ if (!is_elf_kernel)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "only elf kernel support module");
+ return;
+ }
+
+ /* List the current modules if no parameter. */
+ if (!argc)
+ {
+ grub_freebsd_list_modules ();
+ return;
+ }
+
+ file = grub_gzfile_open (argv[0], 1);
+ if ((!file) || (!file->size))
+ goto fail;
+
+ if (kern_end + file->size > grub_os_area_addr + grub_os_area_size)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "Not enough memory for the module");
+ goto fail;
+ }
+
+ grub_file_read (file, (char *) kern_end, file->size);
+ if ((!grub_errno) &&
+ (!grub_freebsd_add_meta_module (0, argc, argv, kern_end, file->size)))
+ kern_end = ALIGN_PAGE (kern_end + file->size);
+
+fail:
+ if (file)
+ grub_file_close (file);
+}
+
+GRUB_MOD_INIT (bsd)
+{
+ grub_rescue_register_command ("freebsd",
+ grub_rescue_cmd_freebsd,
+ "load freebsd kernel");
+ grub_rescue_register_command ("openbsd",
+ grub_rescue_cmd_openbsd,
+ "load openbsd kernel");
+ grub_rescue_register_command ("netbsd",
+ grub_rescue_cmd_netbsd, "load netbsd kernel");
+
+ grub_rescue_register_command ("freebsd_loadenv",
+ grub_rescue_cmd_freebsd_loadenv,
+ "load freebsd env");
+ grub_rescue_register_command ("freebsd_module",
+ grub_rescue_cmd_freebsd_module,
+ "load freebsd module");
+
+ my_mod = mod;
+}
+
+GRUB_MOD_FINI (bsd)
+{
+ grub_rescue_unregister_command ("freebsd");
+ grub_rescue_unregister_command ("openbsd");
+ grub_rescue_unregister_command ("netbsd");
+
+ grub_rescue_unregister_command ("freebsd_loadenv");
+ grub_rescue_unregister_command ("freebsd_module");
+
+ if (mod_buf)
+ {
+ grub_free (mod_buf);
+ mod_buf = 0;
+ mod_buf_max = 0;
+ }
+}
diff --git a/loader/i386/bsd_normal.c b/loader/i386/bsd_normal.c
new file mode 100644
index 0000000..f09cd57
--- /dev/null
+++ b/loader/i386/bsd_normal.c
@@ -0,0 +1,101 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+static grub_err_t
+grub_normal_freebsd_command (struct grub_arg_list *state
+ __attribute__ ((unused)), int argc, char **args)
+{
+ grub_rescue_cmd_freebsd (argc, args);
+ return grub_errno;
+}
+
+static grub_err_t
+grub_normal_openbsd_command (struct grub_arg_list *state
+ __attribute__ ((unused)), int argc, char **args)
+{
+ grub_rescue_cmd_openbsd (argc, args);
+ return grub_errno;
+}
+
+static grub_err_t
+grub_normal_netbsd_command (struct grub_arg_list *state
+ __attribute__ ((unused)), int argc, char **args)
+{
+ grub_rescue_cmd_netbsd (argc, args);
+ return grub_errno;
+}
+
+static grub_err_t
+grub_normal_freebsd_loadenv_command (struct grub_arg_list *state
+ __attribute__ ((unused)), int argc,
+ char **args)
+{
+ grub_rescue_cmd_freebsd_loadenv (argc, args);
+ return grub_errno;
+}
+
+static grub_err_t
+grub_normal_freebsd_module_command (struct grub_arg_list *state
+ __attribute__ ((unused)), int argc,
+ char **args)
+{
+ grub_rescue_cmd_freebsd_module (argc, args);
+ return grub_errno;
+}
+
+GRUB_MOD_INIT (bsd_normal)
+{
+ (void) mod; /* To stop warning. */
+ grub_register_command ("freebsd", grub_normal_freebsd_command,
+ GRUB_COMMAND_FLAG_BOTH,
+ "freebsd FILE [OPTS] [ARGS...]",
+ "Load freebsd kernel.", 0);
+ grub_register_command ("openbsd", grub_normal_openbsd_command,
+ GRUB_COMMAND_FLAG_BOTH,
+ "openbsd FILE [OPTS]", "Load openbsd kernel.", 0);
+ grub_register_command ("netbsd", grub_normal_netbsd_command,
+ GRUB_COMMAND_FLAG_BOTH,
+ "netbsd FILE [OPTS]", "Load netbsd kernel.", 0);
+
+ grub_register_command ("freebsd_loadenv",
+ grub_normal_freebsd_loadenv_command,
+ GRUB_COMMAND_FLAG_BOTH,
+ "freebsd_loadenv FILE", "Load freebsd env.", 0);
+ grub_register_command ("freebsd_module",
+ grub_normal_freebsd_module_command,
+ GRUB_COMMAND_FLAG_BOTH,
+ "freebsd_module [FILE [type=module_type] [ARGS...]]",
+ "Load freebsd module.", 0);
+}
+
+GRUB_MOD_FINI (bsd_normal)
+{
+ grub_unregister_command ("freebsd");
+ grub_unregister_command ("openbsd");
+ grub_unregister_command ("netbsd");
+
+ grub_unregister_command ("freebsd_loadenv");
+ grub_unregister_command ("freebsd_module");
+}
diff --git a/loader/i386/pc/multiboot.c b/loader/i386/pc/multiboot.c
index 893f11b..67959cf 100644
--- a/loader/i386/pc/multiboot.c
+++ b/loader/i386/pc/multiboot.c
@@ -36,6 +36,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -315,7 +316,22 @@ grub_multiboot (int argc, char *argv[])
goto fail;
}
- if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
+ if (header->flags & MULTIBOOT_AOUT_KLUDGE)
+ {
+ int ofs;
+
+ ofs = (char *) header - buffer -
+ (header->header_addr - header->load_addr);
+ if ((grub_aout_load (file, ofs, header->load_addr,
+ ((header->load_end_addr == 0) ? 0 :
+ header->load_end_addr - header->load_addr),
+ header->bss_end_addr))
+ !=GRUB_ERR_NONE)
+ goto fail;
+
+ entry = header->entry_addr;
+ }
+ else if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE)
goto fail;
mbi = grub_malloc (sizeof (struct grub_multiboot_info));
diff --git a/loader/multiboot2.c b/loader/multiboot2.c
index 65fdea1..42c6fad 100644
--- a/loader/multiboot2.c
+++ b/loader/multiboot2.c
@@ -371,6 +371,7 @@ grub_multiboot2 (int argc, char *argv[])
}
else
{
+ grub_errno = 0;
grub_dprintf ("loader", "Loading non-ELF multiboot 2 file.\n");
if (header)