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)