On Feb 11, 2008 10:11 PM, walt <[EMAIL PROTECTED]> 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
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));
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel