* [PATCH] a.out support for multiboot and freebsd @ 2008-02-09 18:41 Bean 2008-02-09 21:57 ` walt 0 siblings, 1 reply; 37+ messages in thread From: Bean @ 2008-02-09 18:41 UTC (permalink / raw) To: The development of GRUB 2 Hi, This patch add a.out support for multiboot. It also support the boot2 loader (a.out format) of freebsd: set root=(hd0,0,a) aout_freebsd /boot/loader boot 2008-02-10 Bean <bean123ch@gmail.com> * conf/i386-pc.rmk (pkglib_MODULES): Add aout.mod _aout_freebsd.mod and aout_freebsd.mod. (aout_mod_SOURCES): New variable. (aout_mod_CFLAGS): Likewise. (aout_mod_LDFLAGS): Likewise. (_aout_freebsd_mod_SOURCES): New variable. (_aout_freebsd_mod_CFLAGS): Likewise. (_aout_freebsd_mod_LDFLAGS): Likewise. (aout_freebsd_mod_SOURCES): New variable. (aout_freebsd_mod_CFLAGS): Likewise. (aout_freebsd_mod_LDFLAGS): Likewise. * include/grub/aout.h: New file. * include/grub/i386/loader.h (grub_freebsd_real_boot): New function. (grub_rescue_cmd_aout_freebsd): Likewise. * kern/i386/loader.S (grub_freebsd_real_boot): New function. * loader/aout.c: New file. * loader/i386/pc/aout_freebsd.c: New file. * loader/i386/pc/aout_freebsd_normal.c: New file. * loader/i386/pc/multiboot.c (grub_multiboot): Handle a.out format. diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 78e4f00..6a9c167 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -146,7 +146,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 _aout_freebsd.mod aout_freebsd.mod # For biosdisk.mod. biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c @@ -298,4 +299,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 _aout_freebsd.mod +_aout_freebsd_mod_SOURCES = loader/i386/pc/aout_freebsd.c +_aout_freebsd_mod_CFLAGS = $(COMMON_CFLAGS) +_aout_freebsd_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For aout_freebsd.mod +aout_freebsd_mod_SOURCES = loader/i386/pc/aout_freebsd_normal.c +aout_freebsd_mod_CFLAGS = $(COMMON_CFLAGS) +aout_freebsd_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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_AOUT_HEADER +#define GRUB_AOUT_HEADER 1 + +#include <grub/types.h> + +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/loader.h b/include/grub/i386/loader.h index 45a1652..a7d5124 100644 --- a/include/grub/i386/loader.h +++ b/include/grub/i386/loader.h @@ -39,10 +39,16 @@ 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_freebsd_real_boot) (grub_addr_t entry, + grub_uint32_t bootdrv, + void *bootinfo) + __attribute__ ((noreturn)); + /* It is necessary to export these functions, because normal mode commands reuse rescue mode commands. */ void grub_rescue_cmd_linux (int argc, char *argv[]); void grub_rescue_cmd_initrd (int argc, char *argv[]); +void grub_rescue_cmd_aout_freebsd (int argc, char *argv[]); #endif /* ! GRUB_LOADER_CPU_HEADER */ diff --git a/kern/i386/loader.S b/kern/i386/loader.S index 266f4ef..6c5a5c1 100644 --- a/kern/i386/loader.S +++ b/kern/i386/loader.S @@ -162,3 +162,24 @@ FUNCTION(grub_multiboot2_real_boot) movl $MULTIBOOT2_BOOTLOADER_MAGIC,%eax popl %ecx jmp *%ecx + + +#define FREEBSD_RB_BOOTINFO 0x80000000 + +FUNCTION(grub_freebsd_real_boot) + pushl %ecx + xorl %ecx, %ecx + pushl %ecx + pushl %ecx + pushl %ecx + pushl %edx + pushl $FREEBSD_RB_BOOTINFO + pushl %eax + + call EXT_C(grub_dl_unload_all) + call EXT_C(grub_stop_floppy) + + cli + + popl %ecx + call *%ecx 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/file.h> +#include <grub/err.h> +#include <grub/dl.h> +#include <grub/aout.h> + +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/pc/aout_freebsd.c b/loader/i386/pc/aout_freebsd.c new file mode 100755 index 0000000..b757862 --- /dev/null +++ b/loader/i386/pc/aout_freebsd.c @@ -0,0 +1,195 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/file.h> +#include <grub/err.h> +#include <grub/rescue.h> +#include <grub/dl.h> +#include <grub/env.h> +#include <grub/misc.h> +#include <grub/gzio.h> +#include <grub/aout.h> + +#define BOOTINFO_VERSION 1 +#define N_BIOS_GEOM 8 +#define B_DEVMAGIC 0xa0000000 + +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[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; +} __attribute__ ((packed)); + +static grub_dl_t my_mod; + +static grub_addr_t entry; + +static grub_err_t +grub_aout_freebsd_boot (void) +{ + struct grub_freebsd_bootinfo bi; + char *p; + grub_uint32_t bootdev; + + grub_memset (&bi, 0, sizeof (bi)); + bi.bi_version = BOOTINFO_VERSION; + bi.bi_size = sizeof (bi); + + /* Slice 2 (whole disk). */ + bootdev = B_DEVMAGIC + (2 << 20); + + 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') + bi.bi_bios_dev = 0x80; + + bi.bi_bios_dev += grub_strtoul (p + 2, &p, 0); + + if ((p) && (p[0] == ',') && (p[1] >= '0') && (p[1] <= '9')) + { + /* Partition number. */ + bootdev |= (grub_strtoul (p + 1, &p, 0)) << 8; + + if ((p) && (p[0] == ',') && (p[1] >= 'a') && (p[1] <= 'z')) + { + /* Unit number. */ + bootdev |= (p[1] - 'a') << 8; + } + } + } + + grub_freebsd_real_boot (entry, bootdev, &bi); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_aout_freebsd_unload (void) +{ + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +} + +void +grub_rescue_cmd_aout_freebsd (int argc, char *argv[]) +{ + grub_file_t file = 0; + union grub_aout_header ah; + grub_addr_t load_addr, bss_end_addr; + int ofs, align_4k; + + grub_dl_ref (my_mod); + + 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; + + if (grub_file_read (file, (char *) &ah, sizeof (ah)) != sizeof (ah)) + { + grub_error (GRUB_ERR_READ_ERROR, "cannot read the a.out header"); + goto fail; + } + + if (grub_aout_get_type (&ah) != AOUT_TYPE_AOUT32) + { + grub_error (GRUB_ERR_READ_ERROR, "invalid a.out header"); + goto fail; + } + + entry = ah.aout32.a_entry & 0xFFFFFF; + + if (AOUT_GETMAGIC (ah.aout32) == AOUT32_ZMAGIC) + { + load_addr = entry; + ofs = 0x1000; + align_4k = 0; + } + else + { + load_addr = entry & 0xF00000; + ofs = sizeof (struct grub_aout32_header); + align_4k = 1; + } + + if (load_addr < 0x100000) + { + grub_error (GRUB_ERR_BAD_OS, "load address below 1M"); + goto fail; + } + + if (ah.aout32.a_bss) + { + bss_end_addr = load_addr + ah.aout32.a_text + ah.aout32.a_data; + if (align_4k) + bss_end_addr = (bss_end_addr + 0xFFF) & 0xFFFFF000; + + bss_end_addr += ah.aout32.a_bss; + if (align_4k) + bss_end_addr = (bss_end_addr + 0xFFF) & 0xFFFFF000; + } + else + bss_end_addr = 0; + + if (grub_aout_load (file, ofs, load_addr, + ah.aout32.a_text + ah.aout32.a_data, bss_end_addr)) + goto fail; + + grub_loader_set (grub_aout_freebsd_boot, grub_aout_freebsd_unload, 1); + +fail: + + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + grub_dl_unref (my_mod); +} + +GRUB_MOD_INIT (aout_freebsd) +{ + grub_rescue_register_command ("aout_freebsd", grub_rescue_cmd_aout_freebsd, + "load freebsd loader"); + my_mod = mod; +} + +GRUB_MOD_FINI (aout_freebsd) +{ + grub_rescue_unregister_command ("aout_freebsd"); +} diff --git a/loader/i386/pc/aout_freebsd_normal.c b/loader/i386/pc/aout_freebsd_normal.c new file mode 100755 index 0000000..d9e2b81 --- /dev/null +++ b/loader/i386/pc/aout_freebsd_normal.c @@ -0,0 +1,47 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/err.h> +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/aout.h> + +static grub_err_t +grub_normal_aout_freebsd_command (struct grub_arg_list *state + __attribute__ ((unused)), int argc, + char **args) +{ + grub_rescue_cmd_aout_freebsd (argc, args); + return grub_errno; +} + +GRUB_MOD_INIT (aout_freebsd_normal) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("aout_freebsd", grub_normal_aout_freebsd_command, + GRUB_COMMAND_FLAG_BOTH, + "aout_freebsd FILE [ARGS...]", + "Load freebsd loader.", 0); +} + +GRUB_MOD_FINI (aout_freebsd_normal) +{ + grub_unregister_command ("aout_freebsd"); +} diff --git a/loader/i386/pc/multiboot.c b/loader/i386/pc/multiboot.c index 011cc9a..d39f66e 100644 --- a/loader/i386/pc/multiboot.c +++ b/loader/i386/pc/multiboot.c @@ -36,6 +36,7 @@ #include <grub/machine/init.h> #include <grub/machine/memory.h> #include <grub/elf.h> +#include <grub/aout.h> #include <grub/file.h> #include <grub/err.h> #include <grub/rescue.h> @@ -315,7 +316,18 @@ grub_multiboot (int argc, char *argv[]) goto fail; } - if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) + if (header->flags & MULTIBOOT_AOUT_KLUDGE) + { + if ((grub_aout_load (file, (char *) header - buffer, 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)); -- Bean ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-09 18:41 [PATCH] a.out support for multiboot and freebsd Bean @ 2008-02-09 21:57 ` walt 2008-02-10 5:33 ` Bean 0 siblings, 1 reply; 37+ messages in thread From: walt @ 2008-02-09 21:57 UTC (permalink / raw) To: grub-devel Bean wrote: > Hi, > > This patch add a.out support for multiboot. It also support the boot2 > loader (a.out format) of freebsd: > > set root=(hd0,0,a) > aout_freebsd /boot/loader > boot > > 2008-02-10 Bean<bean123ch@gmail.com> ... Hi Bean, and thanks for the patch. Unfortunately, the patch is malformed in at least two places and also has whitespace corruption. I did my best to edit the patch by hand until it seemed to apply okay, but I don't trust my results. I have this same patch corruption problem with many of your posts. Can you change the way you attach patches somehow? Maybe change email client? Anyone else have a suggestion? Bean, can you download your own patch from the mailing list and see if it will apply to your own code? Thanks! ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-09 21:57 ` walt @ 2008-02-10 5:33 ` Bean 2008-02-10 9:22 ` Vesa Jääskeläinen 2008-02-10 18:27 ` walt 0 siblings, 2 replies; 37+ messages in thread From: Bean @ 2008-02-10 5:33 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 983 bytes --] On Feb 10, 2008 5:57 AM, walt <wa1ter@myrealbox.com> wrote: > Bean wrote: > > Hi, > > > > This patch add a.out support for multiboot. It also support the boot2 > > loader (a.out format) of freebsd: > > > > set root=(hd0,0,a) > > aout_freebsd /boot/loader > > boot > > > > 2008-02-10 Bean<bean123ch@gmail.com> ... > > Hi Bean, and thanks for the patch. Unfortunately, the patch is malformed > in at least two places and also has whitespace corruption. I did my best > to edit the patch by hand until it seemed to apply okay, but I don't trust > my results. > > I have this same patch corruption problem with many of your posts. Can > you change the way you attach patches somehow? Maybe change email client? > Anyone else have a suggestion? > > Bean, can you download your own patch from the mailing list and see if it > will apply to your own code? i'm using the web interface to send patch, maybe it cause some problem. here is the raw diff file, it should be fine. -- Bean [-- Attachment #2: a3.diff --] [-- Type: application/octet-stream, Size: 16371 bytes --] diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 78e4f00..6a9c167 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -146,7 +146,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 _aout_freebsd.mod aout_freebsd.mod # For biosdisk.mod. biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c @@ -298,4 +299,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 _aout_freebsd.mod +_aout_freebsd_mod_SOURCES = loader/i386/pc/aout_freebsd.c +_aout_freebsd_mod_CFLAGS = $(COMMON_CFLAGS) +_aout_freebsd_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For aout_freebsd.mod +aout_freebsd_mod_SOURCES = loader/i386/pc/aout_freebsd_normal.c +aout_freebsd_mod_CFLAGS = $(COMMON_CFLAGS) +aout_freebsd_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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_AOUT_HEADER +#define GRUB_AOUT_HEADER 1 + +#include <grub/types.h> + +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/loader.h b/include/grub/i386/loader.h index 45a1652..a7d5124 100644 --- a/include/grub/i386/loader.h +++ b/include/grub/i386/loader.h @@ -39,10 +39,16 @@ 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_freebsd_real_boot) (grub_addr_t entry, + grub_uint32_t bootdrv, + void *bootinfo) + __attribute__ ((noreturn)); + /* It is necessary to export these functions, because normal mode commands reuse rescue mode commands. */ void grub_rescue_cmd_linux (int argc, char *argv[]); void grub_rescue_cmd_initrd (int argc, char *argv[]); +void grub_rescue_cmd_aout_freebsd (int argc, char *argv[]); #endif /* ! GRUB_LOADER_CPU_HEADER */ diff --git a/kern/i386/loader.S b/kern/i386/loader.S index 266f4ef..6c5a5c1 100644 --- a/kern/i386/loader.S +++ b/kern/i386/loader.S @@ -162,3 +162,24 @@ FUNCTION(grub_multiboot2_real_boot) movl $MULTIBOOT2_BOOTLOADER_MAGIC,%eax popl %ecx jmp *%ecx + + +#define FREEBSD_RB_BOOTINFO 0x80000000 + +FUNCTION(grub_freebsd_real_boot) + pushl %ecx + xorl %ecx, %ecx + pushl %ecx + pushl %ecx + pushl %ecx + pushl %edx + pushl $FREEBSD_RB_BOOTINFO + pushl %eax + + call EXT_C(grub_dl_unload_all) + call EXT_C(grub_stop_floppy) + + cli + + popl %ecx + call *%ecx 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/file.h> +#include <grub/err.h> +#include <grub/dl.h> +#include <grub/aout.h> + +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/pc/aout_freebsd.c b/loader/i386/pc/aout_freebsd.c new file mode 100755 index 0000000..b757862 --- /dev/null +++ b/loader/i386/pc/aout_freebsd.c @@ -0,0 +1,195 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/file.h> +#include <grub/err.h> +#include <grub/rescue.h> +#include <grub/dl.h> +#include <grub/env.h> +#include <grub/misc.h> +#include <grub/gzio.h> +#include <grub/aout.h> + +#define BOOTINFO_VERSION 1 +#define N_BIOS_GEOM 8 +#define B_DEVMAGIC 0xa0000000 + +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[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; +} __attribute__ ((packed)); + +static grub_dl_t my_mod; + +static grub_addr_t entry; + +static grub_err_t +grub_aout_freebsd_boot (void) +{ + struct grub_freebsd_bootinfo bi; + char *p; + grub_uint32_t bootdev; + + grub_memset (&bi, 0, sizeof (bi)); + bi.bi_version = BOOTINFO_VERSION; + bi.bi_size = sizeof (bi); + + /* Slice 2 (whole disk). */ + bootdev = B_DEVMAGIC + (2 << 20); + + 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') + bi.bi_bios_dev = 0x80; + + bi.bi_bios_dev += grub_strtoul (p + 2, &p, 0); + + if ((p) && (p[0] == ',') && (p[1] >= '0') && (p[1] <= '9')) + { + /* Partition number. */ + bootdev |= (grub_strtoul (p + 1, &p, 0)) << 8; + + if ((p) && (p[0] == ',') && (p[1] >= 'a') && (p[1] <= 'z')) + { + /* Unit number. */ + bootdev |= (p[1] - 'a') << 8; + } + } + } + + grub_freebsd_real_boot (entry, bootdev, &bi); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_aout_freebsd_unload (void) +{ + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +} + +void +grub_rescue_cmd_aout_freebsd (int argc, char *argv[]) +{ + grub_file_t file = 0; + union grub_aout_header ah; + grub_addr_t load_addr, bss_end_addr; + int ofs, align_4k; + + grub_dl_ref (my_mod); + + 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; + + if (grub_file_read (file, (char *) &ah, sizeof (ah)) != sizeof (ah)) + { + grub_error (GRUB_ERR_READ_ERROR, "cannot read the a.out header"); + goto fail; + } + + if (grub_aout_get_type (&ah) != AOUT_TYPE_AOUT32) + { + grub_error (GRUB_ERR_READ_ERROR, "invalid a.out header"); + goto fail; + } + + entry = ah.aout32.a_entry & 0xFFFFFF; + + if (AOUT_GETMAGIC (ah.aout32) == AOUT32_ZMAGIC) + { + load_addr = entry; + ofs = 0x1000; + align_4k = 0; + } + else + { + load_addr = entry & 0xF00000; + ofs = sizeof (struct grub_aout32_header); + align_4k = 1; + } + + if (load_addr < 0x100000) + { + grub_error (GRUB_ERR_BAD_OS, "load address below 1M"); + goto fail; + } + + if (ah.aout32.a_bss) + { + bss_end_addr = load_addr + ah.aout32.a_text + ah.aout32.a_data; + if (align_4k) + bss_end_addr = (bss_end_addr + 0xFFF) & 0xFFFFF000; + + bss_end_addr += ah.aout32.a_bss; + if (align_4k) + bss_end_addr = (bss_end_addr + 0xFFF) & 0xFFFFF000; + } + else + bss_end_addr = 0; + + if (grub_aout_load (file, ofs, load_addr, + ah.aout32.a_text + ah.aout32.a_data, bss_end_addr)) + goto fail; + + grub_loader_set (grub_aout_freebsd_boot, grub_aout_freebsd_unload, 1); + +fail: + + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + grub_dl_unref (my_mod); +} + +GRUB_MOD_INIT (aout_freebsd) +{ + grub_rescue_register_command ("aout_freebsd", grub_rescue_cmd_aout_freebsd, + "load freebsd loader"); + my_mod = mod; +} + +GRUB_MOD_FINI (aout_freebsd) +{ + grub_rescue_unregister_command ("aout_freebsd"); +} diff --git a/loader/i386/pc/aout_freebsd_normal.c b/loader/i386/pc/aout_freebsd_normal.c new file mode 100755 index 0000000..d9e2b81 --- /dev/null +++ b/loader/i386/pc/aout_freebsd_normal.c @@ -0,0 +1,47 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/err.h> +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/aout.h> + +static grub_err_t +grub_normal_aout_freebsd_command (struct grub_arg_list *state + __attribute__ ((unused)), int argc, + char **args) +{ + grub_rescue_cmd_aout_freebsd (argc, args); + return grub_errno; +} + +GRUB_MOD_INIT (aout_freebsd_normal) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("aout_freebsd", grub_normal_aout_freebsd_command, + GRUB_COMMAND_FLAG_BOTH, + "aout_freebsd FILE [ARGS...]", + "Load freebsd loader.", 0); +} + +GRUB_MOD_FINI (aout_freebsd_normal) +{ + grub_unregister_command ("aout_freebsd"); +} diff --git a/loader/i386/pc/multiboot.c b/loader/i386/pc/multiboot.c index 011cc9a..d39f66e 100644 --- a/loader/i386/pc/multiboot.c +++ b/loader/i386/pc/multiboot.c @@ -36,6 +36,7 @@ #include <grub/machine/init.h> #include <grub/machine/memory.h> #include <grub/elf.h> +#include <grub/aout.h> #include <grub/file.h> #include <grub/err.h> #include <grub/rescue.h> @@ -315,7 +316,18 @@ grub_multiboot (int argc, char *argv[]) goto fail; } - if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) + if (header->flags & MULTIBOOT_AOUT_KLUDGE) + { + if ((grub_aout_load (file, (char *) header - buffer, 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)); ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-10 5:33 ` Bean @ 2008-02-10 9:22 ` Vesa Jääskeläinen 2008-02-10 9:47 ` Bean 2008-02-10 18:27 ` walt 1 sibling, 1 reply; 37+ messages in thread From: Vesa Jääskeläinen @ 2008-02-10 9:22 UTC (permalink / raw) To: The development of GRUB 2 Bean wrote: > On Feb 10, 2008 5:57 AM, walt <wa1ter@myrealbox.com> wrote: >> Bean wrote: >>> Hi, >>> >>> This patch add a.out support for multiboot. It also support the boot2 >>> loader (a.out format) of freebsd: >>> >>> set root=(hd0,0,a) >>> aout_freebsd /boot/loader >>> boot >>> >>> 2008-02-10 Bean<bean123ch@gmail.com> ... >> Hi Bean, and thanks for the patch. Unfortunately, the patch is malformed >> in at least two places and also has whitespace corruption. I did my best >> to edit the patch by hand until it seemed to apply okay, but I don't trust >> my results. >> >> I have this same patch corruption problem with many of your posts. Can >> you change the way you attach patches somehow? Maybe change email client? >> Anyone else have a suggestion? >> >> Bean, can you download your own patch from the mailing list and see if it >> will apply to your own code? > > i'm using the web interface to send patch, maybe it cause some > problem. here is the > raw diff file, it should be fine. Hi, I looked differences of your patch attachments as compared with others that seems to be working nicely. When you copy'n'paste they will get broken. Here is example from my message (mail client was Thunderbird): Content-Type: text/plain; name="unknown_glyph.diff" Content-Disposition: inline; filename="unknown_glyph.diff" Content-Transfer-Encoding: Base64 And here is example from your email: Content-Type: application/octet-stream; name=a3.diff Content-Transfer-Encoding: base64 X-Attachment-Id: f_fch5ujm00 Content-Disposition: attachment; filename=a3.diff With a quick check, gmail indeed does send them as binary as default when using Opera. Then I configured Opera to understand diff files (eg. that they are "text/plain"), after that gmail sent patches nicely. Perhaps you could add new MIME type to your web browser to handle "diff" file extesions as "text/plain"? Thanks, Vesa Jääskeläinen ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-10 9:22 ` Vesa Jääskeläinen @ 2008-02-10 9:47 ` Bean 0 siblings, 0 replies; 37+ messages in thread From: Bean @ 2008-02-10 9:47 UTC (permalink / raw) To: The development of GRUB 2 On Feb 10, 2008 5:22 PM, Vesa Jääskeläinen <chaac@nic.fi> wrote: > > Bean wrote: > > On Feb 10, 2008 5:57 AM, walt <wa1ter@myrealbox.com> wrote: > >> Bean wrote: > >>> Hi, > >>> > >>> This patch add a.out support for multiboot. It also support the boot2 > >>> loader (a.out format) of freebsd: > >>> > >>> set root=(hd0,0,a) > >>> aout_freebsd /boot/loader > >>> boot > >>> > >>> 2008-02-10 Bean<bean123ch@gmail.com> ... > >> Hi Bean, and thanks for the patch. Unfortunately, the patch is malformed > >> in at least two places and also has whitespace corruption. I did my best > >> to edit the patch by hand until it seemed to apply okay, but I don't trust > >> my results. > >> > >> I have this same patch corruption problem with many of your posts. Can > >> you change the way you attach patches somehow? Maybe change email client? > >> Anyone else have a suggestion? > >> > >> Bean, can you download your own patch from the mailing list and see if it > >> will apply to your own code? > > > > i'm using the web interface to send patch, maybe it cause some > > problem. here is the > > raw diff file, it should be fine. > > Hi, > > I looked differences of your patch attachments as compared with others > that seems to be working nicely. When you copy'n'paste they will get > broken. > > Here is example from my message (mail client was Thunderbird): > > Content-Type: text/plain; > name="unknown_glyph.diff" > Content-Disposition: inline; > filename="unknown_glyph.diff" > Content-Transfer-Encoding: Base64 > > And here is example from your email: > > Content-Type: application/octet-stream; name=a3.diff > Content-Transfer-Encoding: base64 > X-Attachment-Id: f_fch5ujm00 > Content-Disposition: attachment; filename=a3.diff > > With a quick check, gmail indeed does send them as binary as default > when using Opera. Then I configured Opera to understand diff files (eg. > that they are "text/plain"), after that gmail sent patches nicely. > Perhaps you could add new MIME type to your web browser to handle "diff" > file extesions as "text/plain"? I'm using firefox, is there a way to add MIME types ? or maybe i can rename the patch files as *.txt. -- Bean ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-10 5:33 ` Bean 2008-02-10 9:22 ` Vesa Jääskeläinen @ 2008-02-10 18:27 ` walt 2008-02-10 22:28 ` Bean 1 sibling, 1 reply; 37+ messages in thread From: walt @ 2008-02-10 18:27 UTC (permalink / raw) To: grub-devel Bean wrote: > On Feb 10, 2008 5:57 AM, walt<wa1ter@myrealbox.com> wrote: >> Bean wrote: >>> Hi, >>> >>> This patch add a.out support for multiboot. It also support the boot2 >>> loader (a.out format) of freebsd: >>> >>> set root=(hd0,0,a) >>> aout_freebsd /boot/loader >>> boot >>> > ... > i'm using the web interface to send patch, maybe it cause some > problem. here is the raw diff file, it should be fine. Yes, the patch is perfect this time, thanks. I'm still seeing two (small?) problems with aout /boot/loader. The FreeBSD loader has a variable 'currdev' that is not being set correctly. 'currdev' must point to the partition containing /boot/kernel, otherwise loader will say "can't load 'kernel'". If I use the loader interactive shell to set currdev to the correct partition then it will boot the kernel correctly. Well, almost correctly :o) The second problem is that once the kernel starts running, the console never shows the normal dmesg messages. I thought the kernel had died or rebooted until I saw the normal login prompt finally appear. Is this maybe some setting for the console that I can change in grub2 before starting loader? Thanks for all your time and help with this! ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-10 18:27 ` walt @ 2008-02-10 22:28 ` Bean 2008-02-11 14:11 ` walt 0 siblings, 1 reply; 37+ messages in thread From: Bean @ 2008-02-10 22:28 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 580 bytes --] Hi, The following patch support freebsd a.out and elf, now you can load the kernel directly. 1. Boot through loader: set root=(hd0,0,a) freebsd /boot/loader It should be able to deduce the root device from the root variable. 2. Booting directly: freebsd (hd0,0,a)/boot/kernel/kernel freebsd_loadenv (hd0,0,a)/boot/devices.hints set FreeBSD.vfs.root.mountfrom=ufs:ad0s1a environment variable for FreeBSD has the FreeBSD. prefix, the prefix is removed before jumping to kernel code. Please note that you need to set root device explicitly using vfs.root.mountfrom. -- Bean [-- Attachment #2: a4.diff --] [-- Type: text/plain, Size: 20773 bytes --] diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 78e4f00..430055b 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -146,7 +146,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 _freebsd.mod freebsd.mod # For biosdisk.mod. biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c @@ -298,4 +299,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 _freebsd.mod +_freebsd_mod_SOURCES = loader/i386/pc/freebsd.c +_freebsd_mod_CFLAGS = $(COMMON_CFLAGS) +_freebsd_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For freebsd.mod +freebsd_mod_SOURCES = loader/i386/pc/freebsd_normal.c +freebsd_mod_CFLAGS = $(COMMON_CFLAGS) +freebsd_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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_AOUT_HEADER +#define GRUB_AOUT_HEADER 1 + +#include <grub/types.h> + +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/loader.h b/include/grub/i386/loader.h index 45a1652..c0b10e5 100644 --- a/include/grub/i386/loader.h +++ b/include/grub/i386/loader.h @@ -39,10 +39,17 @@ 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_freebsd_real_boot) (grub_addr_t entry, + grub_uint32_t bootdrv, + void *bootinfo) + __attribute__ ((noreturn)); + /* It is necessary to export these functions, because normal mode commands reuse rescue mode commands. */ void grub_rescue_cmd_linux (int argc, char *argv[]); void grub_rescue_cmd_initrd (int argc, char *argv[]); +void grub_rescue_cmd_freebsd (int argc, char *argv[]); +void grub_rescue_cmd_freebsd_loadenv (int argc, char *argv[]); #endif /* ! GRUB_LOADER_CPU_HEADER */ diff --git a/kern/elf.c b/kern/elf.c index ca10b5b..3e90ea0 100644 --- a/kern/elf.c +++ b/kern/elf.c @@ -228,9 +228,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; @@ -407,9 +407,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..6c5a5c1 100644 --- a/kern/i386/loader.S +++ b/kern/i386/loader.S @@ -162,3 +162,24 @@ FUNCTION(grub_multiboot2_real_boot) movl $MULTIBOOT2_BOOTLOADER_MAGIC,%eax popl %ecx jmp *%ecx + + +#define FREEBSD_RB_BOOTINFO 0x80000000 + +FUNCTION(grub_freebsd_real_boot) + pushl %ecx + xorl %ecx, %ecx + pushl %ecx + pushl %ecx + pushl %ecx + pushl %edx + pushl $FREEBSD_RB_BOOTINFO + pushl %eax + + call EXT_C(grub_dl_unload_all) + call EXT_C(grub_stop_floppy) + + cli + + popl %ecx + call *%ecx 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/file.h> +#include <grub/err.h> +#include <grub/dl.h> +#include <grub/aout.h> + +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/pc/freebsd.c b/loader/i386/pc/freebsd.c new file mode 100755 index 0000000..3c744aa --- /dev/null +++ b/loader/i386/pc/freebsd.c @@ -0,0 +1,361 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/file.h> +#include <grub/err.h> +#include <grub/rescue.h> +#include <grub/dl.h> +#include <grub/mm.h> +#include <grub/elfload.h> +#include <grub/env.h> +#include <grub/misc.h> +#include <grub/gzio.h> +#include <grub/aout.h> + +#define BOOTINFO_VERSION 1 +#define N_BIOS_GEOM 8 +#define B_DEVMAGIC 0xa0000000 +#define BASE_SLICE 2 + +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[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)); + +static grub_dl_t my_mod; + +static grub_addr_t entry, kernend; + +static grub_err_t +grub_freebsd_boot (void) +{ + struct grub_freebsd_bootinfo bi; + char *p; + grub_uint32_t bootdev; + + 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 = BOOTINFO_VERSION; + bi.bi_size = sizeof (bi); + + bootdev = B_DEVMAGIC + (BASE_SLICE << 20); + + 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') + bi.bi_bios_dev = 0x80; + + bi.bi_bios_dev += grub_strtoul (p + 2, &p, 0); + + if ((p) && (p[0] == ',') && (p[1] >= '0') && (p[1] <= '9')) + { + /* Partition number. */ + bootdev |= (grub_strtoul (p + 1, &p, 0)) << 8; + + /* Unit number. */ + bootdev |= (bi.bi_bios_dev & 0x7F) << 16; + } + } + + kernend = (kernend + 3) & (~3); + p = (char *) kernend; + + grub_env_iterate (iterate_env); + + if (p != (char *) kernend) + { + *(p++) = 0; + + bi.bi_envp = kernend; + bi.bi_kernend = ((grub_uint32_t) p + 3) & (~3); + } + else + bi.bi_kernend = kernend; + + grub_freebsd_real_boot (entry, bootdev, &bi); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_freebsd_unload (void) +{ + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_bsd_load_aout (grub_file_t file, union grub_aout_header *ah) +{ + grub_addr_t load_addr, bss_end_addr; + int ofs, align_4k; + + 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_4k = 0; + } + else + { + load_addr = entry & 0xF00000; + ofs = sizeof (struct grub_aout32_header); + align_4k = 1; + } + + if (load_addr < 0x100000) + return grub_error (GRUB_ERR_BAD_OS, "load address below 1M"); + + kernend = load_addr + ah->aout32.a_text + ah->aout32.a_data; + if (align_4k) + kernend = (kernend + 0xFFF) & 0xFFFFF000; + + if (ah->aout32.a_bss) + { + kernend += ah->aout32.a_bss; + if (align_4k) + kernend = (kernend + 0xFFF) & 0xFFFFF000; + + bss_end_addr = kernend; + } + 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 (paddr + phdr->p_memsz > kernend) + kernend = paddr + phdr->p_memsz; + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_bsd_load_elf (grub_file_t file) +{ + grub_elf_t elf = 0; + grub_err_t err; + + kernend = 0; + elf = grub_elf_file (file); + if (!elf) + return grub_errno; + + if (grub_elf_is_elf32 (elf)) + { + entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF; + err = grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0); + } + else + err = grub_error (GRUB_ERR_BAD_OS, "invalid elf"); + + return err; +} + +void +grub_rescue_cmd_freebsd_loadenv (int argc, char *argv[]) +{ + grub_file_t file = 0; + char *buf = 0, *curr, *next; + int len; + + 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 (int argc, char *argv[]) +{ + grub_file_t file = 0; + union grub_aout_header ah; + + grub_dl_ref (my_mod); + + 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; + + if (grub_file_read (file, (char *) &ah, sizeof (ah)) != sizeof (ah)) + { + grub_error (GRUB_ERR_READ_ERROR, "cannot read the a.out header"); + goto fail; + } + + if (grub_aout_get_type (&ah) == AOUT_TYPE_NONE) + grub_bsd_load_elf (file); + else + grub_bsd_load_aout (file, &ah); + + if (grub_errno == GRUB_ERR_NONE) + grub_loader_set (grub_freebsd_boot, grub_freebsd_unload, 1); + +fail: + + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + grub_dl_unref (my_mod); +} + +GRUB_MOD_INIT (aout_freebsd) +{ + grub_rescue_register_command ("freebsd", + grub_rescue_cmd_freebsd, + "load freebsd loader"); + grub_rescue_register_command ("freebsd_loadenv", + grub_rescue_cmd_freebsd_loadenv, + "load freebsd env"); + + my_mod = mod; +} + +GRUB_MOD_FINI (aout_freebsd) +{ + grub_rescue_unregister_command ("freebsd"); + grub_rescue_unregister_command ("freebsd_loadenv"); +} diff --git a/loader/i386/pc/freebsd_normal.c b/loader/i386/pc/freebsd_normal.c new file mode 100755 index 0000000..f9f7d47 --- /dev/null +++ b/loader/i386/pc/freebsd_normal.c @@ -0,0 +1,60 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/err.h> +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/aout.h> + +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_freebsd_loadenv_command (struct grub_arg_list *state + __attribute__ ((unused)), int argc, + char **args) +{ + grub_rescue_cmd_freebsd_loadenv (argc, args); + return grub_errno; +} + +GRUB_MOD_INIT (aout_freebsd_normal) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("freebsd", grub_normal_freebsd_command, + GRUB_COMMAND_FLAG_BOTH, + "aout_freebsd FILE [ARGS...]", + "Load freebsd loader.", 0); + grub_register_command ("freebsd_loadenv", + grub_normal_freebsd_loadenv_command, + GRUB_COMMAND_FLAG_BOTH, + "freebsd_loadenv FILE", "Load freebsd env.", 0); +} + +GRUB_MOD_FINI (aout_freebsd_normal) +{ + grub_unregister_command ("freebsd"); + grub_unregister_command ("freebsd_loadenv"); +} diff --git a/loader/i386/pc/multiboot.c b/loader/i386/pc/multiboot.c index 893f11b..e9fcc4a 100644 --- a/loader/i386/pc/multiboot.c +++ b/loader/i386/pc/multiboot.c @@ -36,6 +36,7 @@ #include <grub/machine/init.h> #include <grub/machine/memory.h> #include <grub/elf.h> +#include <grub/aout.h> #include <grub/file.h> #include <grub/err.h> #include <grub/rescue.h> @@ -315,7 +316,18 @@ grub_multiboot (int argc, char *argv[]) goto fail; } - if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) + if (header->flags & MULTIBOOT_AOUT_KLUDGE) + { + if ((grub_aout_load (file, (char *) header - buffer, 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)); ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-10 22:28 ` Bean @ 2008-02-11 14:11 ` walt 2008-02-11 14:28 ` Bean 0 siblings, 1 reply; 37+ messages in thread From: walt @ 2008-02-11 14:11 UTC (permalink / raw) To: grub-devel Bean wrote: > Hi, > > The following patch support freebsd a.out and elf, now you can load > the kernel directly. > > 1. Boot through loader: > > set root=(hd0,0,a) > freebsd /boot/loader > > It should be able to deduce the root device from the root variable. I still see currdev=disk0s1c but that should be s1a, not s1c. > > 2. Booting directly: > freebsd (hd0,0,a)/boot/kernel/kernel At this point I see 'broken magic at 0x6b30'. I'm running FreeBSD CURRENT, not stable. Could that be the problem? ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-11 14:11 ` walt @ 2008-02-11 14:28 ` Bean 2008-02-11 20:45 ` Bean 0 siblings, 1 reply; 37+ messages in thread From: Bean @ 2008-02-11 14:28 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 938 bytes --] On Feb 11, 2008 10:11 PM, walt <wa1ter@myrealbox.com> wrote: > Bean wrote: > > Hi, > > > > The following patch support freebsd a.out and elf, now you can load > > the kernel directly. > > > > 1. Boot through loader: > > > > set root=(hd0,0,a) > > freebsd /boot/loader > > > > It should be able to deduce the root device from the root variable. > > I still see currdev=disk0s1c but that should be s1a, not s1c. i found a small bug in the root device calculation, the new patch below should be ok. > > > > 2. Booting directly: > > freebsd (hd0,0,a)/boot/kernel/kernel > > At this point I see 'broken magic at 0x6b30'. I'm running FreeBSD > CURRENT, not stable. Could that be the problem? I'm testing FreeBSD 6.3, the 7 series haven't been tried yet. Perhaps you can upload the kernel file somewhere for me to check. The patch also contain incomplete support for openbsd kernel, it's not working yet, you can just ignore it. -- Bean [-- Attachment #2: a5.diff --] [-- Type: text/plain, Size: 28748 bytes --] diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 78e4f00..430055b 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -146,7 +146,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 _freebsd.mod freebsd.mod # For biosdisk.mod. biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c @@ -298,4 +299,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 _freebsd.mod +_freebsd_mod_SOURCES = loader/i386/pc/freebsd.c +_freebsd_mod_CFLAGS = $(COMMON_CFLAGS) +_freebsd_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For freebsd.mod +freebsd_mod_SOURCES = loader/i386/pc/freebsd_normal.c +freebsd_mod_CFLAGS = $(COMMON_CFLAGS) +freebsd_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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_AOUT_HEADER +#define GRUB_AOUT_HEADER 1 + +#include <grub/types.h> + +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..079a8f8 --- /dev/null +++ b/include/grub/i386/bsd.h @@ -0,0 +1,131 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_BSD_CPU_HEADER +#define GRUB_BSD_CPU_HEADER 1 + +#include <grub/types.h> + +#define KERNEL_TYPE_FREEBSD 0 +#define KERNEL_TYPE_OPENBSD 1 +#define KERNEL_TYPE_NETBSD 2 + +#define FREEBSD_RB_ASKNAME 0x01 /* ask for file name to reboot from */ +#define FREEBSD_RB_SINGLE 0x02 /* reboot to single user only */ +#define FREEBSD_RB_NOSYNC 0x04 /* dont sync before reboot */ +#define FREEBSD_RB_HALT 0x08 /* don't reboot, just halt */ +#define FREEBSD_RB_INITNAME 0x10 /* name given for /etc/init (unused) */ +#define FREEBSD_RB_DFLTROOT 0x20 /* use compiled-in rootdev */ +#define FREEBSD_RB_KDB 0x40 /* give control to kernel debugger */ +#define FREEBSD_RB_RDONLY 0x80 /* mount root fs read-only */ +#define FREEBSD_RB_DUMP 0x100 /* dump kernel memory before reboot */ +#define FREEBSD_RB_MINIROOT 0x200 /* mini-root present in memory at boot time */ +#define FREEBSD_RB_CONFIG 0x400 /* invoke user configuration routing */ +#define FREEBSD_RB_VERBOSE 0x800 /* print all potentially useful info */ +#define FREEBSD_RB_SERIAL 0x1000 /* user serial port as console */ +#define FREEBSD_RB_CDROM 0x2000 /* use cdrom as root */ +#define FREEBSD_RB_GDB 0x8000 /* use GDB remote debugger instead of DDB */ +#define FREEBSD_RB_MUTE 0x10000 /* Come up with the console muted */ +#define FREENSD_RB_MULTIPLE 0x20000000 /* Use multiple consoles */ +#define FREEBSD_RB_BOOTINFO 0x80000000 /* 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 + +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 0x0001 /* ask for file name to reboot from */ +#define OPENBSD_RB_SINGLE 0x0002 /* reboot to single user only */ +#define OPENBSD_RB_NOSYNC 0x0004 /* dont sync before reboot */ +#define OPENBSD_RB_HALT 0x0008 /* don't reboot, just halt */ +#define OPENBSD_RB_INITNAME 0x0010 /* name given for /etc/init (unused) */ +#define OPENBSD_RB_DFLTROOT 0x0020 /* use compiled-in rootdev */ +#define OPENBSD_RB_KDB 0x0040 /* give control to kernel debugger */ +#define OPENBSD_RB_RDONLY 0x0080 /* mount root fs read-only */ +#define OPENBSD_RB_DUMP 0x0100 /* dump kernel memory before reboot */ +#define OPENBSD_RB_MINIROOT 0x0200 /* mini-root present in memory at boot time */ +#define OPENBSD_RB_CONFIG 0x0400 /* change configured devices */ +#define OPENBSD_RB_TIMEBAD 0x0800 /* don't call resettodr() in boot() */ +#define OPENBSD_RB_POWERDOWN 0x1000 /* attempt to power down machine */ +#define OPENBSD_RB_SERCONS 0x2000 /* use serial console if available */ +#define OPENBSD_RB_USERREQ 0x4000 /* 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_CONSDEV 5 + +#define OPENBSD_MAKEDEV(x,y) ((((x) & 0xff) << 8) | \ + ((y) & 0xff) | \ + (((y) & 0xffff00) << 8)) + +struct grub_openbsd_consdev +{ + grub_uint32_t consdev; + grub_uint32_t conspeed; +} __attribute__ ((packed)); + +struct grub_openbsd_bootargs +{ + grub_uint32_t ba_type; + grub_uint32_t ba_size; + struct grub_openbsd_bootargs *ba_next; +} __attribute__ ((packed)); + +#endif /* ! GRUB_BSD_CPU_HEADER */ diff --git a/include/grub/i386/loader.h b/include/grub/i386/loader.h index 45a1652..262fd9f 100644 --- a/include/grub/i386/loader.h +++ b/include/grub/i386/loader.h @@ -39,10 +39,16 @@ 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. */ void grub_rescue_cmd_linux (int argc, char *argv[]); void grub_rescue_cmd_initrd (int argc, char *argv[]); +void grub_rescue_cmd_freebsd (int argc, char *argv[]); +void grub_rescue_cmd_freebsd_loadenv (int argc, char *argv[]); +void grub_rescue_cmd_openbsd (int argc, char *argv[]); #endif /* ! GRUB_LOADER_CPU_HEADER */ diff --git a/kern/elf.c b/kern/elf.c index ca10b5b..3e90ea0 100644 --- a/kern/elf.c +++ b/kern/elf.c @@ -228,9 +228,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; @@ -407,9 +407,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..c8dd30a 100644 --- a/kern/i386/loader.S +++ b/kern/i386/loader.S @@ -162,3 +162,14 @@ FUNCTION(grub_multiboot2_real_boot) movl $MULTIBOOT2_BOOTLOADER_MAGIC,%eax popl %ecx jmp *%ecx + + +FUNCTION(grub_unix_real_boot) + call EXT_C(grub_dl_unload_all) + call EXT_C(grub_stop_floppy) + + cli + + popl %eax + popl %eax + 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/file.h> +#include <grub/err.h> +#include <grub/dl.h> +#include <grub/aout.h> + +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/pc/freebsd.c b/loader/i386/pc/freebsd.c new file mode 100755 index 0000000..40b88f1 --- /dev/null +++ b/loader/i386/pc/freebsd.c @@ -0,0 +1,430 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/machine/memory.h> +#include <grub/cpu/bsd.h> +#include <grub/file.h> +#include <grub/err.h> +#include <grub/rescue.h> +#include <grub/dl.h> +#include <grub/mm.h> +#include <grub/elfload.h> +#include <grub/env.h> +#include <grub/misc.h> +#include <grub/gzio.h> +#include <grub/aout.h> + +#define ALIGN_DWORD(a) ((a + 3) & (~3)) +#define ALIGN_PAGE(a) ((a + 4095) & (~4095)) + +static int kernel_type; +static grub_dl_t my_mod; +static grub_addr_t entry, kernend; +static grub_uint32_t bootflags; + +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; + + *biosdev += grub_strtoul (p + 2, &p, 0); + *unit = (*biosdev & 0x7f); + + 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_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; + + kernend = ALIGN_DWORD(kernend); + p = (char *) kernend; + + grub_env_iterate (iterate_env); + + if (p != (char *) kernend) + { + *(p++) = 0; + + bi.bi_envp = kernend; + bi.bi_kernend = ALIGN_DWORD((grub_uint32_t) p); + } + else + bi.bi_kernend = kernend; + + grub_unix_real_boot (entry, bootflags | FREEBSD_RB_BOOTINFO, bootdev, + 0, 0, 0, &bi, 0, 0); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_openbsd_boot (void) +{ + struct grub_openbsd_bootargs *p; + grub_uint32_t bootdev, biosdev, unit, slice, part; + struct grub_openbsd_consdev cd; + + auto void NESTED_FUNC_ATTR add_bootarg (int type, int size, void *ptr); + void NESTED_FUNC_ATTR add_bootarg (int type, int size, void *ptr) + { + p->ba_type = type; + p->ba_size = sizeof (struct grub_openbsd_bootargs) + size; + p->ba_next = (struct grub_openbsd_bootargs *) ((char *) p + p->ba_size); + grub_memcpy ((char *) (p + 1), ptr, size); + p = p->ba_next; + } + + kernend = ALIGN_DWORD(kernend); + p = (struct grub_openbsd_bootargs *) kernend; + + grub_bsd_get_device (&biosdev, &unit, &slice, &part); + bootdev = (OPENBSD_B_DEVMAGIC + (unit << OPENBSD_B_UNITSHIFT) + + (part << OPENBSD_B_PARTSHIFT)); + + cd.consdev = OPENBSD_MAKEDEV(12, 0); + cd.conspeed = 9600; + add_bootarg (OPENBSD_BOOTARG_CONSDEV, sizeof(cd), &cd); + + p->ba_type = OPENBSD_BOOTARG_END; + p->ba_next = 0; + p++; + + bootflags; + + //grub_unix_real_boot (entry, bootflags, bootdev, + // OPENBSD_BOOTARG_APIVER, + // 0, 0, 0, (grub_uint32_t) p - kernend , kernend); + + grub_unix_real_boot (entry, bootflags, bootdev, 0, + 0, grub_upper_mem, grub_lower_mem, 0, 0); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_bsd_unload (void) +{ + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_bsd_load_aout (grub_file_t file, union grub_aout_header *ah) +{ + grub_addr_t load_addr, bss_end_addr; + int ofs, align_page; + + 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"); + + kernend = load_addr + ah->aout32.a_text + ah->aout32.a_data; + if (align_page) + kernend = ALIGN_PAGE(kernend); + + if (ah->aout32.a_bss) + { + kernend += ah->aout32.a_bss; + if (align_page) + kernend = ALIGN_PAGE(kernend); + + bss_end_addr = kernend; + } + 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 (paddr + phdr->p_memsz > kernend) + kernend = paddr + phdr->p_memsz; + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_bsd_load_elf (grub_file_t file) +{ + grub_elf_t elf = 0; + grub_err_t err; + + kernend = 0; + elf = grub_elf_file (file); + if (!elf) + return grub_errno; + + if (grub_elf_is_elf32 (elf)) + { + entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF; + err = grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0); + } + else + err = grub_error (GRUB_ERR_BAD_OS, "invalid elf"); + + return err; +} + +static grub_err_t +grub_bsd_load (int argc, char *argv[]) +{ + grub_file_t file = 0; + union grub_aout_header ah; + + grub_dl_ref (my_mod); + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); + goto fail; + } + + bootflags = 0; + file = grub_gzfile_open (argv[0], 1); + if (!file) + goto fail; + + if (grub_file_read (file, (char *) &ah, sizeof (ah)) != sizeof (ah)) + { + grub_error (GRUB_ERR_READ_ERROR, "cannot read the a.out header"); + goto fail; + } + + if (grub_aout_get_type (&ah) == AOUT_TYPE_NONE) + grub_bsd_load_elf (file); + else + grub_bsd_load_aout (file, &ah); + +fail: + + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + grub_dl_unref (my_mod); + + return grub_errno; +} + +void +grub_rescue_cmd_freebsd (int argc, char *argv[]) +{ + kernel_type = KERNEL_TYPE_FREEBSD; + + if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE) + grub_loader_set (grub_freebsd_boot, grub_bsd_unload, 1); +} + +void +grub_rescue_cmd_openbsd (int argc, char *argv[]) +{ + kernel_type = KERNEL_TYPE_OPENBSD; + + if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE) + grub_loader_set (grub_openbsd_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 (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); +} + +GRUB_MOD_INIT (freebsd) +{ + grub_rescue_register_command ("freebsd", + grub_rescue_cmd_freebsd, + "load freebsd kernel"); + grub_rescue_register_command ("freebsd_loadenv", + grub_rescue_cmd_freebsd_loadenv, + "load freebsd env"); + grub_rescue_register_command ("openbsd", + grub_rescue_cmd_openbsd, + "load openbsd kernel"); + + my_mod = mod; +} + +GRUB_MOD_FINI (freebsd) +{ + grub_rescue_unregister_command ("freebsd"); + grub_rescue_unregister_command ("freebsd_loadenv"); + grub_rescue_unregister_command ("openbsd"); +} diff --git a/loader/i386/pc/freebsd_normal.c b/loader/i386/pc/freebsd_normal.c new file mode 100755 index 0000000..afb6490 --- /dev/null +++ b/loader/i386/pc/freebsd_normal.c @@ -0,0 +1,74 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/err.h> +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/aout.h> + +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_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_openbsd_command (struct grub_arg_list *state + __attribute__ ((unused)), int argc, char **args) +{ + grub_rescue_cmd_openbsd (argc, args); + return grub_errno; +} + +GRUB_MOD_INIT (freebsd_normal) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("freebsd", grub_normal_freebsd_command, + GRUB_COMMAND_FLAG_BOTH, + "freebsd FILE [ARGS...]", + "Load freebsd 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 ("openbsd", grub_normal_openbsd_command, + GRUB_COMMAND_FLAG_BOTH, + "openbsd FILE [ARGS...]", + "Load openbsd kernel.", 0); +} + +GRUB_MOD_FINI (freebsd_normal) +{ + grub_unregister_command ("freebsd"); + grub_unregister_command ("freebsd_loadenv"); + grub_unregister_command ("openbsd"); +} 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 <grub/machine/init.h> #include <grub/machine/memory.h> #include <grub/elf.h> +#include <grub/aout.h> #include <grub/file.h> #include <grub/err.h> #include <grub/rescue.h> @@ -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)); ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-11 14:28 ` Bean @ 2008-02-11 20:45 ` Bean 2008-02-11 20:46 ` Bean 0 siblings, 1 reply; 37+ messages in thread From: Bean @ 2008-02-11 20:45 UTC (permalink / raw) To: The development of GRUB 2 Hi, Change in this patch: 1. support OpenBSD kernel: set root=(hd0,3,a) openbsd /bsd The modules name is changed to bsd.mod. 2. Support setting kernel flags one character represent one flag, for FreeBSD, it's "DhaCcdgmnpqrsv", for OpenBSD, it's "abcsd". for example, to enable ask for root device name, single user mode and verbose output in FreeBSD: set root=(hd0,2,a) freebsd /boot/loader asv -- Bean ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-11 20:45 ` Bean @ 2008-02-11 20:46 ` Bean 2008-02-11 21:28 ` Robert Millan 2008-02-11 21:51 ` walt 0 siblings, 2 replies; 37+ messages in thread From: Bean @ 2008-02-11 20:46 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 532 bytes --] On Feb 12, 2008 4:45 AM, Bean <bean123ch@gmail.com> wrote: > Hi, > > Change in this patch: > > 1. support OpenBSD kernel: > > set root=(hd0,3,a) > openbsd /bsd > > The modules name is changed to bsd.mod. > > 2. Support setting kernel flags > > one character represent one flag, for FreeBSD, it's "DhaCcdgmnpqrsv", > for OpenBSD, it's "abcsd". > > for example, to enable ask for root device name, single user mode and > verbose output in FreeBSD: > > set root=(hd0,2,a) > freebsd /boot/loader asv sorry, forget the patch. -- Bean [-- Attachment #2: a6.diff --] [-- Type: text/plain, Size: 29983 bytes --] diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 78e4f00..82ef90b 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -146,7 +146,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 @@ -298,4 +299,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 _freebsd.mod +_bsd_mod_SOURCES = loader/i386/pc/bsd.c +_bsd_mod_CFLAGS = $(COMMON_CFLAGS) +_bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For freebsd.mod +bsd_mod_SOURCES = loader/i386/pc/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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_AOUT_HEADER +#define GRUB_AOUT_HEADER 1 + +#include <grub/types.h> + +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..5d8d05d --- /dev/null +++ b/include/grub/i386/bsd.h @@ -0,0 +1,137 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_BSD_CPU_HEADER +#define GRUB_BSD_CPU_HEADER 1 + +#include <grub/types.h> + +#define KERNEL_TYPE_FREEBSD 0 +#define KERNEL_TYPE_OPENBSD 1 +#define KERNEL_TYPE_NETBSD 2 + +#define FREEBSD_RB_ASKNAME 0x1 /* ask for file name to reboot from */ +#define FREEBSD_RB_SINGLE 0x2 /* reboot to single user only */ +#define FREEBSD_RB_NOSYNC 0x4 /* dont sync before reboot */ +#define FREEBSD_RB_HALT 0x8 /* don't reboot, just halt */ +#define FREEBSD_RB_INITNAME 0x10 /* name given for /etc/init (unused) */ +#define FREEBSD_RB_DFLTROOT 0x20 /* use compiled-in rootdev */ +#define FREEBSD_RB_KDB 0x40 /* give control to kernel debugger */ +#define FREEBSD_RB_RDONLY 0x80 /* mount root fs read-only */ +#define FREEBSD_RB_DUMP 0x100 /* dump kernel memory before reboot */ +#define FREEBSD_RB_MINIROOT 0x200 /* mini-root present in memory at boot time */ +#define FREEBSD_RB_CONFIG 0x400 /* invoke user configuration routing */ +#define FREEBSD_RB_VERBOSE 0x800 /* print all potentially useful info */ +#define FREEBSD_RB_SERIAL 0x1000 /* user serial port as console */ +#define FREEBSD_RB_CDROM 0x2000 /* use cdrom as root */ +#define FREEBSD_RB_GDB 0x8000 /* use GDB remote debugger instead of DDB */ +#define FREEBSD_RB_MUTE 0x10000 /* Come up with the console muted */ +#define FREEBSD_RB_PAUSE 0x100000 +#define FREEBSD_RB_QUIET 0x200000 +#define FREEBSD_RB_NOINTR 0x10000000 +#define FREENSD_RB_MULTIPLE 0x20000000 /* Use multiple consoles */ +#define FREEBSD_RB_DUAL FREENSD_RB_MULTIPLE +#define FREEBSD_RB_BOOTINFO 0x80000000 /* 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 + +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 0x0001 /* ask for file name to reboot from */ +#define OPENBSD_RB_SINGLE 0x0002 /* reboot to single user only */ +#define OPENBSD_RB_NOSYNC 0x0004 /* dont sync before reboot */ +#define OPENBSD_RB_HALT 0x0008 /* don't reboot, just halt */ +#define OPENBSD_RB_INITNAME 0x0010 /* name given for /etc/init (unused) */ +#define OPENBSD_RB_DFLTROOT 0x0020 /* use compiled-in rootdev */ +#define OPENBSD_RB_KDB 0x0040 /* give control to kernel debugger */ +#define OPENBSD_RB_RDONLY 0x0080 /* mount root fs read-only */ +#define OPENBSD_RB_DUMP 0x0100 /* dump kernel memory before reboot */ +#define OPENBSD_RB_MINIROOT 0x0200 /* mini-root present in memory at boot time */ +#define OPENBSD_RB_CONFIG 0x0400 /* change configured devices */ +#define OPENBSD_RB_TIMEBAD 0x0800 /* don't call resettodr() in boot() */ +#define OPENBSD_RB_POWERDOWN 0x1000 /* attempt to power down machine */ +#define OPENBSD_RB_SERCONS 0x2000 /* use serial console if available */ +#define OPENBSD_RB_USERREQ 0x4000 /* 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 +{ + grub_uint32_t ba_type; + grub_uint32_t ba_size; + struct grub_openbsd_bootargs *ba_next; +} __attribute__ ((packed)); + +void grub_rescue_cmd_freebsd (int argc, char *argv[]); +void grub_rescue_cmd_openbsd (int argc, char *argv[]); + +void grub_rescue_cmd_freebsd_loadenv (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..3e90ea0 100644 --- a/kern/elf.c +++ b/kern/elf.c @@ -228,9 +228,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; @@ -407,9 +407,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..c8dd30a 100644 --- a/kern/i386/loader.S +++ b/kern/i386/loader.S @@ -162,3 +162,14 @@ FUNCTION(grub_multiboot2_real_boot) movl $MULTIBOOT2_BOOTLOADER_MAGIC,%eax popl %ecx jmp *%ecx + + +FUNCTION(grub_unix_real_boot) + call EXT_C(grub_dl_unload_all) + call EXT_C(grub_stop_floppy) + + cli + + popl %eax + popl %eax + 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/file.h> +#include <grub/err.h> +#include <grub/dl.h> +#include <grub/aout.h> + +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/pc/bsd.c b/loader/i386/pc/bsd.c new file mode 100644 index 0000000..f4bddb0 --- /dev/null +++ b/loader/i386/pc/bsd.c @@ -0,0 +1,481 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/machine/memory.h> +#include <grub/machine/init.h> +#include <grub/cpu/bsd.h> +#include <grub/file.h> +#include <grub/err.h> +#include <grub/rescue.h> +#include <grub/dl.h> +#include <grub/mm.h> +#include <grub/elfload.h> +#include <grub/env.h> +#include <grub/misc.h> +#include <grub/gzio.h> +#include <grub/aout.h> + +#define ALIGN_DWORD(a) ((a + 3) & (~3)) +#define ALIGN_PAGE(a) ((a + 4095) & (~4095)) + +static int kernel_type; +static grub_dl_t my_mod; +static grub_addr_t entry, kernend; +static grub_uint32_t bootflags; + +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 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; + + *biosdev += grub_strtoul (p + 2, &p, 0); + *unit = (*biosdev & 0x7f); + + 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_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; + + kernend = ALIGN_DWORD (kernend); + p = (char *) kernend; + + grub_env_iterate (iterate_env); + + if (p != (char *) kernend) + { + *(p++) = 0; + + bi.bi_envp = kernend; + bi.bi_kernend = ALIGN_DWORD ((grub_uint32_t) p); + } + else + bi.bi_kernend = kernend; + + grub_unix_real_boot (entry, bootflags | FREEBSD_RB_BOOTINFO, bootdev, + 0, 0, 0, &bi, 0, 0); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_openbsd_boot (void) +{ + char *buf = (char *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + 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_bsd_unload (void) +{ + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_bsd_load_aout (grub_file_t file, union grub_aout_header *ah) +{ + grub_addr_t load_addr, bss_end_addr; + int ofs, align_page; + + 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"); + + kernend = load_addr + ah->aout32.a_text + ah->aout32.a_data; + if (align_page) + kernend = ALIGN_PAGE (kernend); + + if (ah->aout32.a_bss) + { + kernend += ah->aout32.a_bss; + if (align_page) + kernend = ALIGN_PAGE (kernend); + + bss_end_addr = kernend; + } + 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 (paddr + phdr->p_memsz > kernend) + kernend = paddr + phdr->p_memsz; + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_bsd_load_elf (grub_file_t file) +{ + grub_elf_t elf = 0; + grub_err_t err; + + kernend = 0; + elf = grub_elf_file (file); + if (!elf) + return grub_errno; + + if (grub_elf_is_elf32 (elf)) + { + entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF; + err = grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0); + } + else + err = grub_error (GRUB_ERR_BAD_OS, "invalid elf"); + + return err; +} + +static grub_err_t +grub_bsd_load (int argc, char *argv[]) +{ + grub_file_t file = 0; + union grub_aout_header ah; + + 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; + + if (grub_file_read (file, (char *) &ah, sizeof (ah)) != sizeof (ah)) + { + grub_error (GRUB_ERR_READ_ERROR, "cannot read the a.out header"); + goto fail; + } + + if (grub_aout_get_type (&ah) == AOUT_TYPE_NONE) + grub_bsd_load_elf (file); + else + grub_bsd_load_aout (file, &ah); + +fail: + + if (file) + grub_file_close (file); + + 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) + 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_freebsd_loadenv (int argc, char *argv[]) +{ + grub_file_t file = 0; + char *buf = 0, *curr, *next; + int len; + + 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); +} + +GRUB_MOD_INIT (bsd) +{ + grub_rescue_register_command ("freebsd", + grub_rescue_cmd_freebsd, + "load freebsd kernel"); + grub_rescue_register_command ("freebsd_loadenv", + grub_rescue_cmd_freebsd_loadenv, + "load freebsd env"); + grub_rescue_register_command ("openbsd", + grub_rescue_cmd_openbsd, + "load openbsd kernel"); + + my_mod = mod; +} + +GRUB_MOD_FINI (bsd) +{ + grub_rescue_unregister_command ("freebsd"); + grub_rescue_unregister_command ("freebsd_loadenv"); + grub_rescue_unregister_command ("openbsd"); +} diff --git a/loader/i386/pc/bsd_normal.c b/loader/i386/pc/bsd_normal.c new file mode 100644 index 0000000..8273f2d --- /dev/null +++ b/loader/i386/pc/bsd_normal.c @@ -0,0 +1,71 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/err.h> +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/aout.h> + +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_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_openbsd_command (struct grub_arg_list *state + __attribute__ ((unused)), int argc, char **args) +{ + grub_rescue_cmd_openbsd (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 [ARGS...]", "Load freebsd 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 ("openbsd", grub_normal_openbsd_command, + GRUB_COMMAND_FLAG_BOTH, + "openbsd FILE [ARGS...]", "Load openbsd kernel.", 0); +} + +GRUB_MOD_FINI (bsd_normal) +{ + grub_unregister_command ("freebsd"); + grub_unregister_command ("freebsd_loadenv"); + grub_unregister_command ("openbsd"); +} 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 <grub/machine/init.h> #include <grub/machine/memory.h> #include <grub/elf.h> +#include <grub/aout.h> #include <grub/file.h> #include <grub/err.h> #include <grub/rescue.h> @@ -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)); ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-11 20:46 ` Bean @ 2008-02-11 21:28 ` Robert Millan 2008-02-11 21:46 ` Bean 2008-02-11 21:51 ` walt 1 sibling, 1 reply; 37+ messages in thread From: Robert Millan @ 2008-02-11 21:28 UTC (permalink / raw) To: The development of GRUB 2 On Tue, Feb 12, 2008 at 04:46:31AM +0800, Bean wrote: > +# For _freebsd.mod > +_bsd_mod_SOURCES = loader/i386/pc/bsd.c You forgot to rename the commend ;-) > +_bsd_mod_CFLAGS = $(COMMON_CFLAGS) > +_bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) > + > +# For freebsd.mod > +bsd_mod_SOURCES = loader/i386/pc/bsd_normal.c > +bsd_mod_CFLAGS = $(COMMON_CFLAGS) > +bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) How much pc-dependant are those? Can we hope they will work in e.g. i386-coreboot in the future, when *BSD kernels remove their BIOS dependency? > +#define FREEBSD_RB_ASKNAME 0x1 /* ask for file name to reboot from */ > +#define FREEBSD_RB_SINGLE 0x2 /* reboot to single user only */ > +#define FREEBSD_RB_NOSYNC 0x4 /* dont sync before reboot */ > +#define FREEBSD_RB_HALT 0x8 /* don't reboot, just halt */ > +#define FREEBSD_RB_INITNAME 0x10 /* name given for /etc/init (unused) */ > +#define FREEBSD_RB_DFLTROOT 0x20 /* use compiled-in rootdev */ > +#define FREEBSD_RB_KDB 0x40 /* give control to kernel debugger */ > +#define FREEBSD_RB_RDONLY 0x80 /* mount root fs read-only */ > +#define FREEBSD_RB_DUMP 0x100 /* dump kernel memory before reboot */ > +#define FREEBSD_RB_MINIROOT 0x200 /* mini-root present in memory at boot time */ > +#define FREEBSD_RB_CONFIG 0x400 /* invoke user configuration routing */ > +#define FREEBSD_RB_VERBOSE 0x800 /* print all potentially useful info */ > +#define FREEBSD_RB_SERIAL 0x1000 /* user serial port as console */ > +#define FREEBSD_RB_CDROM 0x2000 /* use cdrom as root */ > +#define FREEBSD_RB_GDB 0x8000 /* use GDB remote debugger instead of DDB */ > +#define FREEBSD_RB_MUTE 0x10000 /* Come up with the console muted */ > +#define FREEBSD_RB_PAUSE 0x100000 > +#define FREEBSD_RB_QUIET 0x200000 > +#define FREEBSD_RB_NOINTR 0x10000000 > +#define FREENSD_RB_MULTIPLE 0x20000000 /* Use multiple consoles */ > +#define FREEBSD_RB_DUAL FREENSD_RB_MULTIPLE > +#define FREEBSD_RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */ Usually we have "(1 << 0)", "(1 << 1)", etc for bitmask lists. > +FUNCTION(grub_unix_real_boot) > + call EXT_C(grub_dl_unload_all) > + call EXT_C(grub_stop_floppy) > + > + cli > + > + popl %eax > + popl %eax > + call *%eax Why a call? Do we need the return address in the stack here? A comment would be nice in that case. > +#define ALIGN_DWORD(a) ((a + 3) & (~3)) > +#define ALIGN_PAGE(a) ((a + 4095) & (~4095)) We already have ALIGN_UP: ./include/grub/misc.h:#define ALIGN_UP(addr, align) ((long)((char *)addr + align - 1) & ~(align - 1)) it'd be better to reuse that, I think. > +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 > +}; We usually put a newline after the '='. -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-11 21:28 ` Robert Millan @ 2008-02-11 21:46 ` Bean 2008-02-12 11:16 ` Robert Millan 0 siblings, 1 reply; 37+ messages in thread From: Bean @ 2008-02-11 21:46 UTC (permalink / raw) To: The development of GRUB 2 On Feb 12, 2008 5:28 AM, Robert Millan <rmh@aybabtu.com> wrote: > On Tue, Feb 12, 2008 at 04:46:31AM +0800, Bean wrote: > > +# For _freebsd.mod > > +_bsd_mod_SOURCES = loader/i386/pc/bsd.c > > You forgot to rename the commend ;-) oh, yes. > > > +_bsd_mod_CFLAGS = $(COMMON_CFLAGS) > > +_bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) > > + > > +# For freebsd.mod > > +bsd_mod_SOURCES = loader/i386/pc/bsd_normal.c > > +bsd_mod_CFLAGS = $(COMMON_CFLAGS) > > +bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) > > How much pc-dependant are those? Can we hope they will work in e.g. > i386-coreboot in the future, when *BSD kernels remove their BIOS > dependency? freebsd doesn't need bios at all, openbsd need the memory map, but i guess it's easy to construct one without using int 15. > > > +#define FREEBSD_RB_ASKNAME 0x1 /* ask for file name to reboot from */ > > +#define FREEBSD_RB_SINGLE 0x2 /* reboot to single user only */ > > +#define FREEBSD_RB_NOSYNC 0x4 /* dont sync before reboot */ > > +#define FREEBSD_RB_HALT 0x8 /* don't reboot, just halt */ > > +#define FREEBSD_RB_INITNAME 0x10 /* name given for /etc/init (unused) */ > > +#define FREEBSD_RB_DFLTROOT 0x20 /* use compiled-in rootdev */ > > +#define FREEBSD_RB_KDB 0x40 /* give control to kernel debugger */ > > +#define FREEBSD_RB_RDONLY 0x80 /* mount root fs read-only */ > > +#define FREEBSD_RB_DUMP 0x100 /* dump kernel memory before reboot */ > > +#define FREEBSD_RB_MINIROOT 0x200 /* mini-root present in memory at boot time */ > > +#define FREEBSD_RB_CONFIG 0x400 /* invoke user configuration routing */ > > +#define FREEBSD_RB_VERBOSE 0x800 /* print all potentially useful info */ > > +#define FREEBSD_RB_SERIAL 0x1000 /* user serial port as console */ > > +#define FREEBSD_RB_CDROM 0x2000 /* use cdrom as root */ > > +#define FREEBSD_RB_GDB 0x8000 /* use GDB remote debugger instead of DDB */ > > +#define FREEBSD_RB_MUTE 0x10000 /* Come up with the console muted */ > > +#define FREEBSD_RB_PAUSE 0x100000 > > +#define FREEBSD_RB_QUIET 0x200000 > > +#define FREEBSD_RB_NOINTR 0x10000000 > > +#define FREENSD_RB_MULTIPLE 0x20000000 /* Use multiple consoles */ > > +#define FREEBSD_RB_DUAL FREENSD_RB_MULTIPLE > > +#define FREEBSD_RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */ > > Usually we have "(1 << 0)", "(1 << 1)", etc for bitmask lists. ok. > > > +FUNCTION(grub_unix_real_boot) > > + call EXT_C(grub_dl_unload_all) > > + call EXT_C(grub_stop_floppy) > > + > > + cli > > + > > + popl %eax > > + popl %eax > > + call *%eax > > Why a call? Do we need the return address in the stack here? A comment would > be nice in that case. bsds using stack to pass parameter, it's like this: void __cdecl (*func)(parm1, parm2,...); the first pop remove the return address, the second gets the address of func, and then call it. the function never returns, using call just make sure the first parameter is at esp + 4. > > > +#define ALIGN_DWORD(a) ((a + 3) & (~3)) > > +#define ALIGN_PAGE(a) ((a + 4095) & (~4095)) > > We already have ALIGN_UP: > > ./include/grub/misc.h:#define ALIGN_UP(addr, align) ((long)((char *)addr + align - 1) & ~(align - 1)) > > it'd be better to reuse that, I think. > > > +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 > > +}; > > We usually put a newline after the '='. ok. -- Bean ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-11 21:46 ` Bean @ 2008-02-12 11:16 ` Robert Millan 0 siblings, 0 replies; 37+ messages in thread From: Robert Millan @ 2008-02-12 11:16 UTC (permalink / raw) To: The development of GRUB 2 On Tue, Feb 12, 2008 at 05:46:49AM +0800, Bean wrote: > > > +_bsd_mod_CFLAGS = $(COMMON_CFLAGS) > > > +_bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) > > > + > > > +# For freebsd.mod > > > +bsd_mod_SOURCES = loader/i386/pc/bsd_normal.c > > > +bsd_mod_CFLAGS = $(COMMON_CFLAGS) > > > +bsd_mod_LDFLAGS = $(COMMON_LDFLAGS) > > > > How much pc-dependant are those? Can we hope they will work in e.g. > > i386-coreboot in the future, when *BSD kernels remove their BIOS > > dependency? > > freebsd doesn't need bios at all, openbsd need the memory map, but i > guess it's easy to construct one without using int 15. In that case, loader/i386/ would be better than loader/i386/pc. Moving files in CVS is painful ;-) > > > +FUNCTION(grub_unix_real_boot) > > > + call EXT_C(grub_dl_unload_all) > > > + call EXT_C(grub_stop_floppy) > > > + > > > + cli > > > + > > > + popl %eax > > > + popl %eax > > > + call *%eax > > > > Why a call? Do we need the return address in the stack here? A comment would > > be nice in that case. > > bsds using stack to pass parameter, it's like this: > > void __cdecl (*func)(parm1, parm2,...); > > the first pop remove the return address, the second gets the address > of func, and then call it. the function never returns, using call just > make sure the first parameter is at esp + 4. Ok. How about adding a comment to make this clear? Maybe something like: /* Use cdecl calling convention for *BSD kernels. */ FUNCTION(grub_unix_real_boot) .... /* 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 does this look good? -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-11 20:46 ` Bean 2008-02-11 21:28 ` Robert Millan @ 2008-02-11 21:51 ` walt 2008-02-12 4:03 ` Bean 2008-02-12 11:19 ` Robert Millan 1 sibling, 2 replies; 37+ messages in thread From: walt @ 2008-02-11 21:51 UTC (permalink / raw) To: grub-devel On Tue, 2008-02-12 at 04:46 +0800, Bean wrote: > On Feb 12, 2008 4:45 AM, Bean <bean123ch@gmail.com> wrote: > > Hi, > > > > Change in this patch: > > > > 1. support OpenBSD kernel: > > > > set root=(hd0,3,a) > > openbsd /bsd > > > > The modules name is changed to bsd.mod. > > > > 2. Support setting kernel flags > > > > one character represent one flag, for FreeBSD, it's "DhaCcdgmnpqrsv", > > for OpenBSD, it's "abcsd". > > > > for example, to enable ask for root device name, single user mode and > > verbose output in FreeBSD: > > > > set root=(hd0,2,a) > > freebsd /boot/loader asv Any BSD kernel I try to load, including /boot/loader, gives me a 'free magic broken' error. Same with 'multiboot netbsd'. A separate problem is that 'ls' will list the root directory of my OpenBSD partition, but not any of the subdirectories like usr, etc, home.... It just says 'out of disk' when I try. ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-11 21:51 ` walt @ 2008-02-12 4:03 ` Bean 2008-02-12 11:19 ` Robert Millan 1 sibling, 0 replies; 37+ messages in thread From: Bean @ 2008-02-12 4:03 UTC (permalink / raw) To: The development of GRUB 2 On Feb 12, 2008 5:51 AM, walt <wa1ter@myrealbox.com> wrote: > > Any BSD kernel I try to load, including /boot/loader, gives me a 'free > magic broken' error. Same with 'multiboot netbsd'. > > A separate problem is that 'ls' will list the root directory of my > OpenBSD partition, but not any of the subdirectories like usr, etc, > home.... It just says 'out of disk' when I try. This seems like a fs problem, are you using the same system as before ? perhaps you can copy the kernel to a fat partition and see if it can be loaded. -- Bean ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-11 21:51 ` walt 2008-02-12 4:03 ` Bean @ 2008-02-12 11:19 ` Robert Millan 2008-02-12 18:47 ` Bean 1 sibling, 1 reply; 37+ messages in thread From: Robert Millan @ 2008-02-12 11:19 UTC (permalink / raw) To: The development of GRUB 2 On Mon, Feb 11, 2008 at 01:51:49PM -0800, walt wrote: > > Any BSD kernel I try to load, including /boot/loader, gives me a 'free > magic broken' error. Same with 'multiboot netbsd'. Sounds like an error I've seen before. What is the exact error you see, and when? -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-12 11:19 ` Robert Millan @ 2008-02-12 18:47 ` Bean 2008-02-12 19:36 ` Robert Millan 0 siblings, 1 reply; 37+ messages in thread From: Bean @ 2008-02-12 18:47 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 1800 bytes --] Hi, The new version adds NetBSD support and data file loading in FreeBSD. You can't load kernel modules, because they have relocation and symbol issue which is too much to handle, however, you can load data files like splashimage or memdisk. Examples: 1. Load freebsd loader set root=(hd0,1,a) freebsd /boot/loader boot 2. Load freebsd kernel directly set root=(hd0,1,a) freebsd /boot/kernel/kernel freebsd_loadenv /boot/device.hints freebsd_module /boot/splash.bmp type=splash_image_data set FreeBSD.vfs.root.mountfrom=ufs:ad0s1a boot Note that in order to show the splashimage, you need to add splash_bmp module to the kernel. 3. Load OpenBSD kernel set root=(hd0,2,a) openbsd /bsd 4. Load NetBSD kernel set root=(hd0,3,a) netbsd /netbsd 2008-02-12 Bean <bean123ch@gmail.com> * conf/i386-pc.rmk (pkglib_MODULES): Add aout.mod _bsd.mod and bsd.mod. (aout_mod_SOURCES): New variable. (aout_mod_CFLAGS): Likewise. (aout_mod_LDFLAGS): Likewise. (_bsd_mod_SOURCES): New variable. (_bsd_mod_CFLAGS): Likewise. (_bsd_mod_LDFLAGS): Likewise. (bsd_mod_SOURCES): New variable. (bsd_mod_CFLAGS): Likewise. (bsd_mod_LDFLAGS): Likewise. * include/grub/aout.h: New file. * include/grub/i386/loader.h (grub_unix_real_boot): New function. * include/grub/i386/bsd.h: New file. * include/grub/i386/pc/init.h (grub_get_mmap_entry): Use EXPORT_FUNC to make it public. * kern/elf.c (grub_elf32_load): Get the physical address after the hook function is called, so that it's possible to change it inside the hook. (grub_elf64_load): Likewise. * kern/i386/loader.S (grub_unix_real_boot): New function. * loader/aout.c: New file. * loader/i386/bsd.c: New file. * loader/i386/bsd_normal.c: New file. * loader/i386/pc/multiboot.c (grub_multiboot): Handle a.out format. -- Bean [-- Attachment #2: bsd.diff --] [-- Type: text/plain, Size: 41814 bytes --] diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 78e4f00..1a7ee66 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -146,7 +146,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 @@ -298,4 +299,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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_AOUT_HEADER +#define GRUB_AOUT_HEADER 1 + +#include <grub/types.h> + +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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_BSD_CPU_HEADER +#define GRUB_BSD_CPU_HEADER 1 + +#include <grub/types.h> + +#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..3e90ea0 100644 --- a/kern/elf.c +++ b/kern/elf.c @@ -228,9 +228,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; @@ -407,9 +407,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..baf1255 100644 --- a/kern/i386/loader.S +++ b/kern/i386/loader.S @@ -162,3 +162,25 @@ 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/file.h> +#include <grub/err.h> +#include <grub/dl.h> +#include <grub/aout.h> + +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..2bc737e --- /dev/null +++ b/loader/i386/bsd.c @@ -0,0 +1,772 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/cpu/loader.h> +#include <grub/cpu/bsd.h> +#include <grub/machine/init.h> +#include <grub/machine/memory.h> +#include <grub/file.h> +#include <grub/err.h> +#include <grub/rescue.h> +#include <grub/dl.h> +#include <grub/mm.h> +#include <grub/elfload.h> +#include <grub/env.h> +#include <grub/misc.h> +#include <grub/gzio.h> +#include <grub/aout.h> + +#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, union grub_aout_header *ah) +{ + grub_addr_t load_addr, bss_end_addr; + int ofs, align_page; + + 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_file_t file) +{ + grub_elf_t elf = 0; + grub_err_t err; + + kern_start = kern_end = 0; + elf = grub_elf_file (file); + if (!elf) + return grub_errno; + + if (grub_elf_is_elf32 (elf)) + { + entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF; + err = grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0); + } + else + err = grub_error (GRUB_ERR_BAD_OS, "invalid elf"); + + return err; +} + +static grub_err_t +grub_bsd_load (int argc, char *argv[]) +{ + grub_file_t file = 0; + union grub_aout_header ah; + + 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; + + if (grub_file_read (file, (char *) &ah, sizeof (ah)) != sizeof (ah)) + { + grub_error (GRUB_ERR_READ_ERROR, "cannot read the a.out header"); + goto fail; + } + + is_elf_kernel = (grub_aout_get_type (&ah) == AOUT_TYPE_NONE); + if (is_elf_kernel) + grub_bsd_load_elf (file); + else + grub_bsd_load_aout (file, &ah); + +fail: + + if (file) + grub_file_close (file); + + 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/err.h> +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/aout.h> + +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 <grub/machine/init.h> #include <grub/machine/memory.h> #include <grub/elf.h> +#include <grub/aout.h> #include <grub/file.h> #include <grub/err.h> #include <grub/rescue.h> @@ -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)); ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-12 18:47 ` Bean @ 2008-02-12 19:36 ` Robert Millan 2008-02-13 10:40 ` Bean 0 siblings, 1 reply; 37+ messages in thread From: Robert Millan @ 2008-02-12 19:36 UTC (permalink / raw) To: The development of GRUB 2 On Wed, Feb 13, 2008 at 02:47:30AM +0800, Bean wrote: > + /* ... and put our return address in its place (the kernel will ignore > + it, but it expects %esp to point to it. */ > + call *%eax Unmatched parenthesis here (sorry I guess that's my fault ;-)). -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-12 19:36 ` Robert Millan @ 2008-02-13 10:40 ` Bean 2008-02-13 15:40 ` Robert Millan 2008-02-13 17:25 ` walt 0 siblings, 2 replies; 37+ messages in thread From: Bean @ 2008-02-13 10:40 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 637 bytes --] On Feb 13, 2008 3:36 AM, Robert Millan <rmh@aybabtu.com> wrote: > On Wed, Feb 13, 2008 at 02:47:30AM +0800, Bean wrote: > > + /* ... and put our return address in its place (the kernel will ignore > > + it, but it expects %esp to point to it. */ > > + call *%eax > > Unmatched parenthesis here (sorry I guess that's my fault ;-)). Ok. I also fix the alloc magic broken problem, it's caused by grub_elf_file, which will close the file when the elf magic is not found. However, the upper level still use that file, that cause the memory problem. The patch should be applied after the previous bsd.diff. -- Bean [-- Attachment #2: bsd_2.diff --] [-- Type: text/plain, Size: 5969 bytes --] diff --git a/kern/elf.c b/kern/elf.c index 3e90ea0..f4a71c1 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; } @@ -177,8 +176,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) @@ -355,8 +354,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) diff --git a/kern/i386/loader.S b/kern/i386/loader.S index baf1255..39cf6a0 100644 --- a/kern/i386/loader.S +++ b/kern/i386/loader.S @@ -181,6 +181,8 @@ FUNCTION(grub_unix_real_boot) /* 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. */ + /* + * ... 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/i386/bsd.c b/loader/i386/bsd.c index 2bc737e..4966afa 100644 --- a/loader/i386/bsd.c +++ b/loader/i386/bsd.c @@ -400,17 +400,24 @@ grub_bsd_unload (void) } static grub_err_t -grub_bsd_load_aout (grub_file_t file, union grub_aout_header *ah) +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_aout_get_type (ah) != AOUT_TYPE_AOUT32) + 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; + entry = ah.aout32.a_entry & 0xFFFFFF; - if (AOUT_GETMAGIC (ah->aout32) == AOUT32_ZMAGIC) + if (AOUT_GETMAGIC (ah.aout32) == AOUT32_ZMAGIC) { load_addr = entry; ofs = 0x1000; @@ -427,13 +434,13 @@ grub_bsd_load_aout (grub_file_t file, union grub_aout_header *ah) 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; + 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) + if (ah.aout32.a_bss) { - kern_end += ah->aout32.a_bss; + kern_end += ah.aout32.a_bss; if (align_page) kern_end = ALIGN_PAGE (kern_end); @@ -443,7 +450,7 @@ grub_bsd_load_aout (grub_file_t file, union grub_aout_header *ah) bss_end_addr = 0; return grub_aout_load (file, ofs, load_addr, - ah->aout32.a_text + ah->aout32.a_data, bss_end_addr); + ah.aout32.a_text + ah.aout32.a_data, bss_end_addr); } static grub_err_t @@ -469,32 +476,24 @@ grub_bsd_elf32_hook (Elf32_Phdr * phdr, UNUSED grub_addr_t * addr) } static grub_err_t -grub_bsd_load_elf (grub_file_t file) +grub_bsd_load_elf (grub_elf_t elf) { - grub_elf_t elf = 0; - grub_err_t err; - kern_start = kern_end = 0; - elf = grub_elf_file (file); - if (!elf) - return grub_errno; if (grub_elf_is_elf32 (elf)) { entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF; - err = grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0); + return grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0); } else - err = grub_error (GRUB_ERR_BAD_OS, "invalid elf"); - - return err; + return grub_error (GRUB_ERR_BAD_OS, "invalid elf"); } static grub_err_t grub_bsd_load (int argc, char *argv[]) { - grub_file_t file = 0; - union grub_aout_header ah; + grub_file_t file; + grub_elf_t elf; grub_dl_ref (my_mod); @@ -510,23 +509,23 @@ grub_bsd_load (int argc, char *argv[]) if (!file) goto fail; - if (grub_file_read (file, (char *) &ah, sizeof (ah)) != sizeof (ah)) + elf = grub_elf_file (file); + if (elf) { - grub_error (GRUB_ERR_READ_ERROR, "cannot read the a.out header"); - goto fail; + is_elf_kernel = 1; + grub_bsd_load_elf (elf); + grub_elf_close (elf); } - - is_elf_kernel = (grub_aout_get_type (&ah) == AOUT_TYPE_NONE); - if (is_elf_kernel) - grub_bsd_load_elf (file); else - grub_bsd_load_aout (file, &ah); + { + is_elf_kernel = 0; + grub_errno = 0; + grub_bsd_load_aout (file); + grub_file_close (file); + } fail: - if (file) - grub_file_close (file); - if (grub_errno != GRUB_ERR_NONE) grub_dl_unref (my_mod); 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) ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-13 10:40 ` Bean @ 2008-02-13 15:40 ` Robert Millan 2008-02-13 16:51 ` Bean 2008-02-13 17:25 ` walt 1 sibling, 1 reply; 37+ messages in thread From: Robert Millan @ 2008-02-13 15:40 UTC (permalink / raw) To: The development of GRUB 2 On Wed, Feb 13, 2008 at 06:40:14PM +0800, Bean wrote: > On Feb 13, 2008 3:36 AM, Robert Millan <rmh@aybabtu.com> wrote: > > On Wed, Feb 13, 2008 at 02:47:30AM +0800, Bean wrote: > > > + /* ... and put our return address in its place (the kernel will ignore > > > + it, but it expects %esp to point to it. */ > > > + call *%eax > > > > Unmatched parenthesis here (sorry I guess that's my fault ;-)). > > Ok. I also fix the alloc magic broken problem, it's caused by > grub_elf_file, which will close the file when the elf magic is not > found. However, the upper level still use that file, that cause the > memory problem. > > The patch should be applied after the previous bsd.diff. You forgot the ChangeLog entry.. > --- 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) Why this? -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-13 15:40 ` Robert Millan @ 2008-02-13 16:51 ` Bean 0 siblings, 0 replies; 37+ messages in thread From: Bean @ 2008-02-13 16:51 UTC (permalink / raw) To: The development of GRUB 2 On Feb 13, 2008 11:40 PM, Robert Millan <rmh@aybabtu.com> wrote: > > On Wed, Feb 13, 2008 at 06:40:14PM +0800, Bean wrote: > > On Feb 13, 2008 3:36 AM, Robert Millan <rmh@aybabtu.com> wrote: > > > On Wed, Feb 13, 2008 at 02:47:30AM +0800, Bean wrote: > > > > + /* ... and put our return address in its place (the kernel will ignore > > > > + it, but it expects %esp to point to it. */ > > > > + call *%eax > > > > > > Unmatched parenthesis here (sorry I guess that's my fault ;-)). > > > > Ok. I also fix the alloc magic broken problem, it's caused by > > grub_elf_file, which will close the file when the elf magic is not > > found. However, the upper level still use that file, that cause the > > memory problem. > > > > The patch should be applied after the previous bsd.diff. > > You forgot the ChangeLog entry.. > > > --- 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) > > Why this? After grub_elf_file have failed, the grub_errno would be set, we need to reset it in order to test for another case. -- Bean ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-13 10:40 ` Bean 2008-02-13 15:40 ` Robert Millan @ 2008-02-13 17:25 ` walt 2008-02-13 17:37 ` Bean 1 sibling, 1 reply; 37+ messages in thread From: walt @ 2008-02-13 17:25 UTC (permalink / raw) To: grub-devel Bean wrote: > Ok. I also fix the alloc magic broken problem, it's caused by > grub_elf_file, which will close the file when the elf magic is not > found. However, the upper level still use that file, that cause the > memory problem. > > The patch should be applied after the previous bsd.diff... I'm very confused by the results :o/ I'm now running today's cvs plus bsd.diff plus bsd_2.diff. Some things work and some don't. I can boot openbsd perfectly -- but only if I load the 'bsd' kernel from a different filesystem e.g. FAT32. I can't read any files from the FFS/UFS on my openbsd partition -- I get 'outside of partition'. I can multiboot netbsd perfectly -- but not from the netbsd partition. If I 'multiboot /netbsd' from the netbsd partition I get 'broken magic'. However, I can 'netbsd /netbsd' perfectly from the netbsd partition. (See why I'm confused?) When I 'freebsd /boot/loader' or 'freebsd /boot/kernel/kernel' from the FreeBSD partition I get 'broken magic'. If I 'freebsd /kernel' from a FAT32 partition the kernel seems to load okay but then when I 'boot' nothing prints to the console and the OS never starts. If I 'freebsd /loader' from a FAT fs then the loader runs correctly but of course I need to set 'currdev' by hand. I'm wondering if you have commited all of your UFS/FFS patches to cvs. Seems like I'm seeing some old UFS problems that you fixed once already(?). ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-13 17:25 ` walt @ 2008-02-13 17:37 ` Bean 2008-02-13 20:31 ` walt 0 siblings, 1 reply; 37+ messages in thread From: Bean @ 2008-02-13 17:37 UTC (permalink / raw) To: The development of GRUB 2 On Feb 14, 2008 1:25 AM, walt <wa1ter@myrealbox.com> wrote: > Bean wrote: > > > Ok. I also fix the alloc magic broken problem, it's caused by > > grub_elf_file, which will close the file when the elf magic is not > > found. However, the upper level still use that file, that cause the > > memory problem. > > > > The patch should be applied after the previous bsd.diff... > > I'm very confused by the results :o/ I'm now running today's cvs > plus bsd.diff plus bsd_2.diff. Some things work and some don't. > > I can boot openbsd perfectly -- but only if I load the 'bsd' kernel > from a different filesystem e.g. FAT32. I can't read any files from > the FFS/UFS on my openbsd partition -- I get 'outside of partition'. > > I can multiboot netbsd perfectly -- but not from the netbsd partition. > If I 'multiboot /netbsd' from the netbsd partition I get 'broken magic'. > However, I can 'netbsd /netbsd' perfectly from the netbsd partition. > (See why I'm confused?) > > When I 'freebsd /boot/loader' or 'freebsd /boot/kernel/kernel' from > the FreeBSD partition I get 'broken magic'. If I 'freebsd /kernel' > from a FAT32 partition the kernel seems to load okay but then when > I 'boot' nothing prints to the console and the OS never starts. > If I 'freebsd /loader' from a FAT fs then the loader runs correctly > but of course I need to set 'currdev' by hand. > > I'm wondering if you have commited all of your UFS/FFS patches to > cvs. Seems like I'm seeing some old UFS problems that you fixed > once already(?). Is it possible that your build is not clean ? you can try to run make distclean and then configure and make, see if there is any difference. i'm also putting my compiled version at: http://grub4dos.sourceforge.net/grub2/g2ldr you can load it as linux kernel, please see if it helps. -- Bean ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-13 17:37 ` Bean @ 2008-02-13 20:31 ` walt 2008-02-14 2:43 ` Bean 0 siblings, 1 reply; 37+ messages in thread From: walt @ 2008-02-13 20:31 UTC (permalink / raw) To: grub-devel Bean wrote: > On Feb 14, 2008 1:25 AM, walt<wa1ter@myrealbox.com> wrote: >> ... >> I'm wondering if you have commited all of your UFS/FFS patches to >> cvs. Seems like I'm seeing some old UFS problems that you fixed >> once already(?). > Is it possible that your build is not clean ? you can try to run make > distclean and then configure and make, see if there is any difference. Yes, I do that every time. I'm betting that your source tree is not the same as mine -- i.e. you have some patches I don't have. Could you perhaps put up a tarball of your working source tree so I can compare it to mine? > i'm also putting my compiled version at: > > http://grub4dos.sourceforge.net/grub2/g2ldr Yes, this works perfectly except that I still can't read my openbsd filesystem correctly. I can list / but none of the subdirectories, and I can't even read a small text file from /. (I guess that also means I can't properly read the directories in /). Everything I try gives me 'out of partition' or similar. Progress! :o) ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-13 20:31 ` walt @ 2008-02-14 2:43 ` Bean 2008-02-15 13:29 ` walt 0 siblings, 1 reply; 37+ messages in thread From: Bean @ 2008-02-14 2:43 UTC (permalink / raw) To: The development of GRUB 2 On Feb 14, 2008 4:31 AM, walt <wa1ter@myrealbox.com> wrote: > Yes, this works perfectly except that I still can't read my openbsd > filesystem correctly. I can list / but none of the subdirectories, > and I can't even read a small text file from /. (I guess that also > means I can't properly read the directories in /). Everything I try > gives me 'out of partition' or similar. > > Progress! :o) In that case, it should be a fs problem, what's the disk layout, how big is your ufs partition ? It could be handy if you can make a small image that produce similar results. -- Bean ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-14 2:43 ` Bean @ 2008-02-15 13:29 ` walt 2008-02-15 14:03 ` Bean 2008-02-15 14:14 ` Bean 0 siblings, 2 replies; 37+ messages in thread From: walt @ 2008-02-15 13:29 UTC (permalink / raw) To: grub-devel Bean wrote: > On Feb 14, 2008 4:31 AM, walt<wa1ter@myrealbox.com> wrote: >> Yes, this works perfectly except that I still can't read my openbsd >> filesystem correctly. I can list / but none of the subdirectories, >> and I can't even read a small text file from /. (I guess that also >> means I can't properly read the directories in /). Everything I try >> gives me 'out of partition' or similar. >> >> Progress! :o) > > In that case, it should be a fs problem, what's the disk layout, how > big is your ufs partition ? It could be handy if you can make a small > image that produce similar results. I made a small openbsd image to send you, but it works perfectly with your g2ldr so there's no point in sending it :o) I think that problem is not worth your time or mine. I still have the bigger problem that my grub2 doesn't work like your g2ldr. My version still halts with 'broken magic' or reboots instantly when I type 'boot'. These are bugs that I was seeing several weeks ago and you already fixed them once, but now they are back again. I still think that a patch or two never got committed to cvs, but I don't know which one(s). Could you try applying your bsd.diff and bsd_2.diff to current cvs sources and see if it works for you? Here is what I do: Apply the two patches to a clean cvs tree. ./autogen.sh [because you patched an rmk file] mkdir build cd build ../configure && make rm ata.mod ./grub-mkimage -d . -o grub2 *.mod Then I use grub legacy to boot grub2 as the 'kernel'. Do you see any problems with the above? Does it work properly for you? Thanks, Bean! ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-15 13:29 ` walt @ 2008-02-15 14:03 ` Bean 2008-02-15 14:14 ` Bean 1 sibling, 0 replies; 37+ messages in thread From: Bean @ 2008-02-15 14:03 UTC (permalink / raw) To: The development of GRUB 2 On Fri, Feb 15, 2008 at 9:29 PM, walt <wa1ter@myrealbox.com> wrote: > > Bean wrote: > > On Feb 14, 2008 4:31 AM, walt<wa1ter@myrealbox.com> wrote: > >> Yes, this works perfectly except that I still can't read my openbsd > >> filesystem correctly. I can list / but none of the subdirectories, > >> and I can't even read a small text file from /. (I guess that also > >> means I can't properly read the directories in /). Everything I try > >> gives me 'out of partition' or similar. > >> > >> Progress! :o) > > > > In that case, it should be a fs problem, what's the disk layout, how > > big is your ufs partition ? It could be handy if you can make a small > > image that produce similar results. > > I made a small openbsd image to send you, but it works perfectly with > your g2ldr so there's no point in sending it :o) I think that problem > is not worth your time or mine. > > I still have the bigger problem that my grub2 doesn't work like your > g2ldr. My version still halts with 'broken magic' or reboots instantly > when I type 'boot'. These are bugs that I was seeing several weeks > ago and you already fixed them once, but now they are back again. > > I still think that a patch or two never got committed to cvs, but I > don't know which one(s). Could you try applying your bsd.diff and > bsd_2.diff to current cvs sources and see if it works for you? > > Here is what I do: > > Apply the two patches to a clean cvs tree. > ./autogen.sh [because you patched an rmk file] > mkdir build > cd build > ../configure && make > rm ata.mod > ./grub-mkimage -d . -o grub2 *.mod Don't include all the modules in the kernel, you only need those necessary to access the boot partition, for example, i use the following command to create core.img: ./grub-mkimage -d . -o core.img biosdisk iso9660 pc fat ntfs ext2 ufs bsd boot ls multiboot To create g2ldr, add the lnxboot.img header: cat lnxboot.img core.img > g2ldr This contain enough modules to do the test, no need to load extra module from disk. Also, please use linux to build grub2, *bsd may compile ok, but don't know if the result is correct. -- Bean ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-15 13:29 ` walt 2008-02-15 14:03 ` Bean @ 2008-02-15 14:14 ` Bean 2008-02-15 18:43 ` walt 2008-02-15 22:43 ` walt 1 sibling, 2 replies; 37+ messages in thread From: Bean @ 2008-02-15 14:14 UTC (permalink / raw) To: The development of GRUB 2 On Fri, Feb 15, 2008 at 9:29 PM, walt <wa1ter@myrealbox.com> wrote: > I made a small openbsd image to send you, but it works perfectly with > your g2ldr so there's no point in sending it :o) I think that problem > is not worth your time or mine. BTW, how big is your ufs partition ? I have tested FreeBSD 6.3, NetBSD 4.0 and OpenBSD 4.2 in a 1G virtual disk, they all seems ok, perhaps if the disk is larger, the problem would occur. -- Bean ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-15 14:14 ` Bean @ 2008-02-15 18:43 ` walt 2008-02-15 18:58 ` Bean 2008-02-16 16:43 ` Bean 2008-02-15 22:43 ` walt 1 sibling, 2 replies; 37+ messages in thread From: walt @ 2008-02-15 18:43 UTC (permalink / raw) To: grub-devel Bean wrote: > On Fri, Feb 15, 2008 at 9:29 PM, walt<wa1ter@myrealbox.com> wrote: >> I made a small openbsd image to send you, but it works perfectly with >> your g2ldr so there's no point in sending it :o) I think that problem >> is not worth your time or mine. > > BTW, how big is your ufs partition ? I have tested FreeBSD 6.3, NetBSD > 4.0 and OpenBSD 4.2 in a 1G virtual disk, they all seems ok, perhaps > if the disk is larger, the problem would occur. Your instructions to load only the needed modules works great, thanks. My openbsd partition is 7GB, but some other ufs partitions are bigger than that. I suspect that I have some disklabel conflict on that disk. I have netbsd, openbsd, freebsd all installed on the same disk, each with its own disklabel. I don't know why it would cause that problem in particular, though. I'd like to know exactly how you create your virtual disks for testing. I've been creating appropriate-size partitions on a USB stick and then copying whatever files I need onto it. Then I use dd to make an img file to run in qemu. It's a very slow process and I'd like to do it better. Any hints? Thanks. ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-15 18:43 ` walt @ 2008-02-15 18:58 ` Bean 2008-02-16 16:43 ` Bean 1 sibling, 0 replies; 37+ messages in thread From: Bean @ 2008-02-15 18:58 UTC (permalink / raw) To: The development of GRUB 2 On Sat, Feb 16, 2008 at 2:43 AM, walt <wa1ter@myrealbox.com> wrote: > > Bean wrote: > > On Fri, Feb 15, 2008 at 9:29 PM, walt<wa1ter@myrealbox.com> wrote: > >> I made a small openbsd image to send you, but it works perfectly with > >> your g2ldr so there's no point in sending it :o) I think that problem > >> is not worth your time or mine. > > > > BTW, how big is your ufs partition ? I have tested FreeBSD 6.3, NetBSD > > 4.0 and OpenBSD 4.2 in a 1G virtual disk, they all seems ok, perhaps > > if the disk is larger, the problem would occur. > > Your instructions to load only the needed modules works great, thanks. > > My openbsd partition is 7GB, but some other ufs partitions are bigger > than that. I suspect that I have some disklabel conflict on that disk. > I have netbsd, openbsd, freebsd all installed on the same disk, each > with its own disklabel. I don't know why it would cause that problem > in particular, though. > > I'd like to know exactly how you create your virtual disks for testing. > I've been creating appropriate-size partitions on a USB stick and then > copying whatever files I need onto it. Then I use dd to make an img > file to run in qemu. It's a very slow process and I'd like to do it > better. Any hints? I'm creating a blank disk using qemu-img, then install using the iso file. -- Bean ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-15 18:43 ` walt 2008-02-15 18:58 ` Bean @ 2008-02-16 16:43 ` Bean 2008-02-16 18:12 ` walt 1 sibling, 1 reply; 37+ messages in thread From: Bean @ 2008-02-16 16:43 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 2232 bytes --] On Feb 16, 2008 2:43 AM, walt <wa1ter@myrealbox.com> wrote: > I'd like to know exactly how you create your virtual disks for testing. > I've been creating appropriate-size partitions on a USB stick and then > copying whatever files I need onto it. Then I use dd to make an img > file to run in qemu. It's a very slow process and I'd like to do it > better. Any hints? i think the problem may be caused by dd. bsd disk label record the start sector on disk, if you just copy the partition, the disk label would be wrong, therefore cause the 'out of partition' problem, which generally means reading beyond the end of disk. I recommend install inside qemu to create consistent disk structure. Anyway, i think the bsd module should be fine, here is the whole patch, if nobody objects, i would like to commit it soon. 2008-02-16 Bean <bean123ch@gmail.com> * conf/i386-pc.rmk (pkglib_MODULES): Add aout.mod _bsd.mod and bsd.mod. (aout_mod_SOURCES): New variable. (aout_mod_CFLAGS): Likewise. (aout_mod_LDFLAGS): Likewise. (_bsd_mod_SOURCES): New variable. (_bsd_mod_CFLAGS): Likewise. (_bsd_mod_LDFLAGS): Likewise. (bsd_mod_SOURCES): New variable. (bsd_mod_CFLAGS): Likewise. (bsd_mod_LDFLAGS): Likewise. * include/grub/aout.h: New file. * include/grub/i386/loader.h (grub_unix_real_boot): New function. * include/grub/i386/bsd.h: New file. * include/grub/i386/pc/init.h (grub_get_mmap_entry): Use EXPORT_FUNC to make it public. * kern/elf.c (grub_elf32_load): Get the physical address after the hook function is called, so that it's possible to change it inside the hook. (grub_elf64_load): Likewise. (grub_elf_file): Don't close the file if elf header is not found. (grub_elf_close): Close the file if grub_elf_file fails (The new grub_elf_file won't close it). (grub_elf32_size): Use NESTED_FUNC_ATTR for nested function calcsize. (grub_elf64_size): Likewise. * kern/i386/loader.S (grub_unix_real_boot): New function. * loader/aout.c: New file. * loader/i386/bsd.c: New file. * loader/i386/bsd_normal.c: New file. * loader/i386/pc/multiboot.c (grub_multiboot): Handle a.out format. * loader/multiboot2.c (grub_multiboot2): Reset grub_errno so that it can test othe formats. -- Bean [-- Attachment #2: bsd3.diff --] [-- Type: text/plain, Size: 43820 bytes --] 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_AOUT_HEADER +#define GRUB_AOUT_HEADER 1 + +#include <grub/types.h> + +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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_BSD_CPU_HEADER +#define GRUB_BSD_CPU_HEADER 1 + +#include <grub/types.h> + +#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; } \f @@ -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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/file.h> +#include <grub/err.h> +#include <grub/dl.h> +#include <grub/aout.h> + +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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/cpu/loader.h> +#include <grub/cpu/bsd.h> +#include <grub/machine/init.h> +#include <grub/machine/memory.h> +#include <grub/file.h> +#include <grub/err.h> +#include <grub/rescue.h> +#include <grub/dl.h> +#include <grub/mm.h> +#include <grub/elfload.h> +#include <grub/env.h> +#include <grub/misc.h> +#include <grub/gzio.h> +#include <grub/aout.h> + +#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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/err.h> +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/aout.h> + +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 <grub/machine/init.h> #include <grub/machine/memory.h> #include <grub/elf.h> +#include <grub/aout.h> #include <grub/file.h> #include <grub/err.h> #include <grub/rescue.h> @@ -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) ^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-16 16:43 ` Bean @ 2008-02-16 18:12 ` walt 2008-02-16 18:29 ` Bean 0 siblings, 1 reply; 37+ messages in thread From: walt @ 2008-02-16 18:12 UTC (permalink / raw) To: grub-devel On Sun, 2008-02-17 at 00:43 +0800, Bean wrote: > ... > Anyway, i think the bsd module should be fine, here is the whole > patch, if nobody objects, i would like to commit it soon... I vote yes, thanks. I can boot freebsd directly, openbsd directly, netbsd directly or using multiboot. The only problem is that 'aout' doesn't appear as one of the commands I can choose, so I couldn't try it. When I used grub-mkimage I included aout.mod -- should that be needed in addition to bsd.mod? Great work, Bean, thanks. ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-16 18:12 ` walt @ 2008-02-16 18:29 ` Bean 2008-02-19 16:41 ` Bean 0 siblings, 1 reply; 37+ messages in thread From: Bean @ 2008-02-16 18:29 UTC (permalink / raw) To: The development of GRUB 2 On Feb 17, 2008 2:12 AM, walt <wa1ter@myrealbox.com> wrote: > > On Sun, 2008-02-17 at 00:43 +0800, Bean wrote: > > ... > > Anyway, i think the bsd module should be fine, here is the whole > > patch, if nobody objects, i would like to commit it soon... > > I vote yes, thanks. I can boot freebsd directly, openbsd directly, > netbsd directly or using multiboot. The only problem is that 'aout' > doesn't appear as one of the commands I can choose, so I couldn't > try it. When I used grub-mkimage I included aout.mod -- should that > be needed in addition to bsd.mod? > > Great work, Bean, thanks. aout is shared code for a.out support, bsd module use it to load the a.out format kernel (/boot/loader in freebsd). you don't need to specify it directly, grub-mkimage can figure out bsd depend on aout and load it automatically. -- Bean ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-16 18:29 ` Bean @ 2008-02-19 16:41 ` Bean 0 siblings, 0 replies; 37+ messages in thread From: Bean @ 2008-02-19 16:41 UTC (permalink / raw) To: The development of GRUB 2 On Feb 17, 2008 2:29 AM, Bean <bean123ch@gmail.com> wrote: > On Feb 17, 2008 2:12 AM, walt <wa1ter@myrealbox.com> wrote: > > > > On Sun, 2008-02-17 at 00:43 +0800, Bean wrote: > > > ... > > > Anyway, i think the bsd module should be fine, here is the whole > > > patch, if nobody objects, i would like to commit it soon... > > > > I vote yes, thanks. I can boot freebsd directly, openbsd directly, > > netbsd directly or using multiboot. The only problem is that 'aout' > > doesn't appear as one of the commands I can choose, so I couldn't > > try it. When I used grub-mkimage I included aout.mod -- should that > > be needed in addition to bsd.mod? > > > > Great work, Bean, thanks. > > aout is shared code for a.out support, bsd module use it to load the > a.out format kernel (/boot/loader in freebsd). you don't need to > specify it directly, grub-mkimage can figure out bsd depend on aout > and load it automatically. Committed. -- Bean ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-15 14:14 ` Bean 2008-02-15 18:43 ` walt @ 2008-02-15 22:43 ` walt 2008-02-16 1:00 ` walt 1 sibling, 1 reply; 37+ messages in thread From: walt @ 2008-02-15 22:43 UTC (permalink / raw) To: grub-devel On Fri, 2008-02-15 at 22:14 +0800, Bean wrote: > On Fri, Feb 15, 2008 at 9:29 PM, walt <wa1ter@myrealbox.com> wrote: > > I made a small openbsd image to send you, but it works perfectly with > > your g2ldr so there's no point in sending it :o) I think that problem > > is not worth your time or mine. > > BTW, how big is your ufs partition ? I have tested FreeBSD 6.3, NetBSD > 4.0 and OpenBSD 4.2 in a 1G virtual disk, they all seems ok, perhaps > if the disk is larger, the problem would occur. Hah! I think I found the problem. I just noticed that gparted calls my openbsd/ufs partition an *ext2* filesystem! I seem to recall similar messages from other fs utility programs about the magic number being for ext2 even though it's really ufs. This is probably a leftover magic number from an earlier linux or such. I haven't found any way to change just the magic number instead of deleting the partition and starting over. Do you know of an easy way to do it? I could use a hex disc editor but I don't know where the magic number is, exactly. Thanks! ^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH] a.out support for multiboot and freebsd 2008-02-15 22:43 ` walt @ 2008-02-16 1:00 ` walt 0 siblings, 0 replies; 37+ messages in thread From: walt @ 2008-02-16 1:00 UTC (permalink / raw) To: grub-devel walt wrote: > On Fri, 2008-02-15 at 22:14 +0800, Bean wrote: >> On Fri, Feb 15, 2008 at 9:29 PM, walt<wa1ter@myrealbox.com> wrote: >>> I made a small openbsd image to send you, but it works perfectly with >>> your g2ldr so there's no point in sending it :o) I think that problem >>> is not worth your time or mine. >> BTW, how big is your ufs partition ? I have tested FreeBSD 6.3, NetBSD >> 4.0 and OpenBSD 4.2 in a 1G virtual disk, they all seems ok, perhaps >> if the disk is larger, the problem would occur. > > Hah! I think I found the problem. I just noticed that gparted calls my > openbsd/ufs partition an *ext2* filesystem! I seem to recall similar > messages from other fs utility programs about the magic number being > for ext2 even though it's really ufs. This is probably a leftover > magic number from an earlier linux or such. > > I haven't found any way to change just the magic number instead of > deleting the partition and starting over. Do you know of an easy > way to do it? I could use a hex disc editor but I don't know where > the magic number is, exactly. Never mind, I found the magic number and changed it. Now I don't see any complaints about ext2 or a bad magic number, but grub2 still can't read any directory but / on my openbsd partition. I'll go back to saying that this particular problem isn't worth more of your time or mine. (But I do learn a lot by chasing these bugs even if I can't fix them :o) ^ permalink raw reply [flat|nested] 37+ messages in thread
end of thread, other threads:[~2008-02-19 16:41 UTC | newest] Thread overview: 37+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-02-09 18:41 [PATCH] a.out support for multiboot and freebsd Bean 2008-02-09 21:57 ` walt 2008-02-10 5:33 ` Bean 2008-02-10 9:22 ` Vesa Jääskeläinen 2008-02-10 9:47 ` Bean 2008-02-10 18:27 ` walt 2008-02-10 22:28 ` Bean 2008-02-11 14:11 ` walt 2008-02-11 14:28 ` Bean 2008-02-11 20:45 ` Bean 2008-02-11 20:46 ` Bean 2008-02-11 21:28 ` Robert Millan 2008-02-11 21:46 ` Bean 2008-02-12 11:16 ` Robert Millan 2008-02-11 21:51 ` walt 2008-02-12 4:03 ` Bean 2008-02-12 11:19 ` Robert Millan 2008-02-12 18:47 ` Bean 2008-02-12 19:36 ` Robert Millan 2008-02-13 10:40 ` Bean 2008-02-13 15:40 ` Robert Millan 2008-02-13 16:51 ` Bean 2008-02-13 17:25 ` walt 2008-02-13 17:37 ` Bean 2008-02-13 20:31 ` walt 2008-02-14 2:43 ` Bean 2008-02-15 13:29 ` walt 2008-02-15 14:03 ` Bean 2008-02-15 14:14 ` Bean 2008-02-15 18:43 ` walt 2008-02-15 18:58 ` Bean 2008-02-16 16:43 ` Bean 2008-02-16 18:12 ` walt 2008-02-16 18:29 ` Bean 2008-02-19 16:41 ` Bean 2008-02-15 22:43 ` walt 2008-02-16 1:00 ` walt
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.