diff --git a/commands/i386/pc/drivemap.c b/commands/i386/pc/drivemap.c index 898fb51..97a1936 100644 --- a/commands/i386/pc/drivemap.c +++ b/commands/i386/pc/drivemap.c @@ -23,8 +23,9 @@ #include #include #include +#include #include - +#include /* Real mode IVT slot (seg:off far pointer) for interrupt 0x13. */ @@ -356,10 +357,49 @@ uninstall_int13_handler (void) return GRUB_ERR_NONE; } +static int +grub_get_root_biosnumber_drivemap (void) +{ + char *biosnum; + int ret = -1; + grub_device_t dev; + + biosnum = grub_env_get ("biosnum"); + + if (biosnum) + return grub_strtoul (biosnum, 0, 0); + + dev = grub_device_open (0); + if (dev && dev->disk && dev->disk->dev + && grub_strcmp (dev->disk->dev->name, "biosdisk") == 0) + { + drivemap_node_t *curnode = map_head; + ret = (int) dev->disk->id; + while (curnode) + { + if (curnode->redirto == ret) + { + ret = curnode->newdrive; + break; + } + curnode = curnode->next; + } + + } + + if (dev) + grub_device_close (dev); + + return ret; +} + static grub_extcmd_t cmd; +static int (*grub_get_root_biosnumber_saved) (void); GRUB_MOD_INIT (drivemap) { + grub_get_root_biosnumber_saved = grub_get_root_biosnumber; + grub_get_root_biosnumber = grub_get_root_biosnumber_drivemap; cmd = grub_register_extcmd ("drivemap", grub_cmd_drivemap, GRUB_COMMAND_FLAG_BOTH, "drivemap" @@ -374,6 +414,7 @@ GRUB_MOD_INIT (drivemap) GRUB_MOD_FINI (drivemap) { + grub_get_root_biosnumber = grub_get_root_biosnumber_saved; grub_loader_unregister_preboot_hook (drivemap_hook); drivemap_hook = 0; grub_unregister_extcmd (cmd); diff --git a/commands/i386/pc/drivemap_int13h.S b/commands/i386/pc/drivemap_int13h.S index 7a3e8e7..ba31a9c 100644 --- a/commands/i386/pc/drivemap_int13h.S +++ b/commands/i386/pc/drivemap_int13h.S @@ -27,6 +27,11 @@ /* The replacement int13 handler. Preserve all registers. */ FUNCTION(grub_drivemap_handler) + /* Save %dx for future restore. */ + push %dx + /* Push flags. Used to simulate interrupt with original flags. */ + pushf + /* Map the drive number (always in DL). */ push %ax push %bx @@ -51,11 +56,48 @@ not_found: pop %bx pop %ax - /* Upon arrival to this point the stack must be exactly like at entry. - This long jump will transfer the caller's stack to the old INT13 - handler, thus making it return directly to the original caller. */ - .byte 0xea + cmpb $0x8, %ah + jz norestore + cmpb $0x15, %ah + jz norestore + + /* Restore flags. */ + popf + pushf + + lcall *%cs:INT13H_OFFSET (EXT_C (grub_drivemap_oldhandler)) + + push %bp + mov %sp, %bp + +postamble: + + pushf + pop %dx + mov %dx, 8(%bp) + + pop %bp + + /* Restore %dx. */ + pop %dx + iret + +norestore: + + /* Restore flags. */ + popf + pushf + + lcall *%cs:INT13H_OFFSET (EXT_C (grub_drivemap_oldhandler)) + + push %bp + mov %sp, %bp + + /* Save %dx. */ + mov %dx, 2(%bp) + jmp postamble + /* Far pointer to the old handler. Stored as a CS:IP in the style of real-mode IVT entries (thus PI:SC in mem). */ VARIABLE(grub_drivemap_oldhandler) diff --git a/conf/common.rmk b/conf/common.rmk index 3e59c3a..b328bc4 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -353,19 +353,13 @@ pkglib_MODULES += minicmd.mod extcmd.mod hello.mod handler.mod \ loopback.mod fs_uuid.mod configfile.mod echo.mod \ terminfo.mod test.mod blocklist.mod hexdump.mod \ read.mod sleep.mod loadenv.mod crc.mod parttool.mod \ - pcpart.mod memrw.mod boot.mod normal.mod sh.mod lua.mod \ - gptsync.mod + pcpart.mod memrw.mod normal.mod sh.mod lua.mod gptsync.mod # For gptsync.mod. gptsync_mod_SOURCES = commands/gptsync.c gptsync_mod_CFLAGS = $(COMMON_CFLAGS) gptsync_mod_LDFLAGS = $(COMMON_LDFLAGS) -# For boot.mod. -boot_mod_SOURCES = commands/boot.c -boot_mod_CFLAGS = $(COMMON_CFLAGS) -boot_mod_LDFLAGS = $(COMMON_LDFLAGS) - # For minicmd.mod. minicmd_mod_SOURCES = commands/minicmd.c minicmd_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index 2f768c0..483f279 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -109,6 +109,12 @@ pkglib_MODULES = linux.mod multiboot.mod \ halt.mod datetime.mod date.mod datehook.mod \ lsmmap.mod mmap.mod +# For boot.mod. +pkglib_MODULES += boot.mod +boot_mod_SOURCES = commands/boot.c +boot_mod_CFLAGS = $(COMMON_CFLAGS) +boot_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For mmap.mod. mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c mmap_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index 91e271d..d146733 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -117,6 +117,12 @@ symlist.c: $(addprefix include/grub/,$(kernel_mod_HEADERS)) config.h gensymlist. kernel_syms.lst: $(addprefix include/grub/,$(kernel_mod_HEADERS)) config.h genkernsyms.sh /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) +# For boot.mod. +pkglib_MODULES += boot.mod +boot_mod_SOURCES = commands/boot.c +boot_mod_CFLAGS = $(COMMON_CFLAGS) +boot_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For acpi.mod. acpi_mod_SOURCES = commands/acpi.c commands/efi/acpi.c acpi_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 961e616..6e91b42 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -108,6 +108,12 @@ pkglib_MODULES = halt.mod reboot.mod suspend.mod \ nand.mod memdisk.mod pci.mod lspci.mod datetime.mod \ date.mod datehook.mod lsmmap.mod mmap.mod +# For boot.mod. +pkglib_MODULES += boot.mod +boot_mod_SOURCES = commands/boot.c +boot_mod_CFLAGS = $(COMMON_CFLAGS) +boot_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For mmap.mod. mmap_mod_SOURCES = mmap/mmap.c mmap/i386/uppermem.c mmap/i386/mmap.c mmap_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index fe67a8f..bebb571 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -189,6 +189,12 @@ pkglib_MODULES = biosdisk.mod chain.mod \ usb.mod uhci.mod ohci.mod usbtest.mod usbms.mod usb_keyboard.mod \ efiemu.mod mmap.mod acpi.mod drivemap.mod +# For boot.mod. +pkglib_MODULES += boot.mod +boot_mod_SOURCES = commands/boot.c lib/i386/pc/biosnum.c +boot_mod_CFLAGS = $(COMMON_CFLAGS) +boot_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For drivemap.mod. drivemap_mod_SOURCES = commands/i386/pc/drivemap.c \ commands/i386/pc/drivemap_int13h.S @@ -445,3 +451,7 @@ endif include $(srcdir)/conf/i386.mk include $(srcdir)/conf/common.mk + +ifeq (0,1) +pkglib_MODULES += boot.mod +endif diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index 8b5be2b..a15f5b2 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -119,6 +119,12 @@ pkglib_MODULES = halt.mod \ memdisk.mod \ lsmmap.mod +# For boot.mod. +pkglib_MODULES += boot.mod +boot_mod_SOURCES = commands/boot.c lib/i386/pc/biosnum.c +boot_mod_CFLAGS = $(COMMON_CFLAGS) +boot_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For linux.mod. linux_mod_SOURCES = loader/powerpc/ieee1275/linux.c linux_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk index d16501b..f84b281 100644 --- a/conf/sparc64-ieee1275.rmk +++ b/conf/sparc64-ieee1275.rmk @@ -149,6 +149,12 @@ pkglib_MODULES = halt.mod \ memdisk.mod \ lsmmap.mod +# For boot.mod. +pkglib_MODULES += boot.mod +boot_mod_SOURCES = commands/boot.c lib/i386/pc/biosnum.c +boot_mod_CFLAGS = $(COMMON_CFLAGS) +boot_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For linux.mod. linux_mod_SOURCES = loader/sparc64/ieee1275/linux.c linux_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index 175f8cc..82d0005 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -115,6 +115,12 @@ symlist.c: $(addprefix include/grub/,$(kernel_mod_HEADERS)) config.h gensymlist. kernel_syms.lst: $(addprefix include/grub/,$(kernel_mod_HEADERS)) config.h genkernsyms.sh /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) +# For boot.mod. +pkglib_MODULES += boot.mod +boot_mod_SOURCES = commands/boot.c lib/i386/pc/biosnum.c +boot_mod_CFLAGS = $(COMMON_CFLAGS) +boot_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For acpi.mod. acpi_mod_SOURCES = commands/acpi.c commands/efi/acpi.c acpi_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/include/grub/i386/pc/biosnum.h b/include/grub/i386/pc/biosnum.h new file mode 100644 index 0000000..29c8ecc --- /dev/null +++ b/include/grub/i386/pc/biosnum.h @@ -0,0 +1,6 @@ +#ifndef GRUB_BIOSNUM_MACHINE_HEADER +#define GRUB_BIOSNUM_MACHINE_HEADER 1 + +extern int (*grub_get_root_biosnumber) (void); + +#endif diff --git a/lib/i386/pc/biosnum.c b/lib/i386/pc/biosnum.c new file mode 100644 index 0000000..15274e6 --- /dev/null +++ b/lib/i386/pc/biosnum.c @@ -0,0 +1,46 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include + +static int +grub_get_root_biosnumber_default (void) +{ + char *biosnum; + int ret = -1; + grub_device_t dev; + + biosnum = grub_env_get ("biosnum"); + + if (biosnum) + return grub_strtoul (biosnum, 0, 0); + + dev = grub_device_open (0); + if (dev && dev->disk && dev->disk->dev + && grub_strcmp (dev->disk->dev->name, "biosdisk") == 0) + ret = (int) dev->disk->id; + + if (dev) + grub_device_close (dev); + + return ret; +} + +int (*grub_get_root_biosnumber) (void) = grub_get_root_biosnumber_default; diff --git a/loader/i386/bsd.c b/loader/i386/bsd.c index ab3a635..45f6571 100644 --- a/loader/i386/bsd.c +++ b/loader/i386/bsd.c @@ -33,6 +33,12 @@ #include #include #include +#ifdef GRUB_MACHINE_PCBIOS +#include +#include +#include +#include +#endif #define ALIGN_DWORD(a) ALIGN_UP (a, 4) #define ALIGN_QWORD(a) ALIGN_UP (a, 8) @@ -81,23 +87,22 @@ grub_bsd_get_device (grub_uint32_t * biosdev, 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')) + grub_device_t dev; + + *biosdev = grub_get_root_biosnumber () & 0xff; + *unit = (*biosdev & 0x7f); + *slice = 0xff; + *part = 0xff; + dev = grub_device_open (0); + if (dev && dev->disk && dev->disk->partition) { - if (p[0] == 'h') - *biosdev = 0x80; - - *unit = grub_strtoul (p + 2, &p, 0); - *biosdev += *unit; - if ((p) && (p[0] == ',')) + p = dev->disk->partition->partmap->get_name (dev->disk->partition); + if (p) { - if ((p[1] >= '0') && (p[1] <= '9')) + if ((p[0] >= '0') && (p[0] <= '9')) { - *slice = grub_strtoul (p + 1, &p, 0); + *slice = grub_strtoul (p, &p, 0); if ((p) && (p[0] == ',')) p++; @@ -107,6 +112,8 @@ grub_bsd_get_device (grub_uint32_t * biosdev, *part = p[0] - 'a'; } } + if (dev) + grub_device_close (dev); } static grub_err_t diff --git a/loader/i386/multiboot.c b/loader/i386/multiboot.c index a59085c..06128d7 100644 --- a/loader/i386/multiboot.c +++ b/loader/i386/multiboot.c @@ -42,6 +42,12 @@ #include #include #include +#ifdef GRUB_MACHINE_PCBIOS +#include +#include +#include +#include +#endif extern grub_dl_t my_mod; static struct grub_multiboot_info *mbi, *mbi_dest; @@ -148,46 +154,42 @@ grub_multiboot_load_elf (grub_file_t file, void *buffer) static int grub_multiboot_get_bootdev (grub_uint32_t *bootdev) { +#ifdef GRUB_MACHINE_PCBIOS char *p; + grub_uint32_t biosdev, slice = ~0, part = ~0; + grub_device_t dev; - p = grub_env_get ("root"); - if ((p) && ((p[0] == 'h') || (p[0] == 'f')) && (p[1] == 'd') && - (p[2] >= '0') && (p[2] <= '9')) - { - grub_uint32_t bd; + biosdev = grub_get_root_biosnumber (); - bd = (p[0] == 'h') ? 0x80 : 0; - bd += grub_strtoul (p + 2, &p, 0); - bd <<= 24; + dev = grub_device_open (0); + if (dev && dev->disk && dev->disk->partition) + { - if ((p) && (p[0] == ',')) + p = dev->disk->partition->partmap->get_name (dev->disk->partition); + if (p) { - if ((p[1] >= '0') && (p[1] <= '9')) + if ((p[0] >= '0') && (p[0] <= '9')) { - - bd += ((grub_strtoul (p + 1, &p, 0) - 1) & 0xFF) << 16; + slice = grub_strtoul (p, &p, 0); if ((p) && (p[0] == ',')) p++; } - else - bd += 0xFF0000; if ((p[0] >= 'a') && (p[0] <= 'z')) - bd += (p[0] - 'a') << 8; - else - bd += 0xFF00; + part = p[0] - 'a'; } - else - bd += 0xFFFF00; - - bd += 0xFF; - - *bootdev = bd; - return 1; } - + if (dev) + grub_device_close (dev); + + *bootdev = ((biosdev & 0xff) << 24) | ((slice & 0xff) << 16) + | ((part & 0xff) << 16) | 0xff; + return (biosdev != ~0UL); +#else + *bootdev = 0xffffffff; return 0; +#endif } void diff --git a/loader/i386/pc/chainloader.c b/loader/i386/pc/chainloader.c index 304886b..fe7e89a 100644 --- a/loader/i386/pc/chainloader.c +++ b/loader/i386/pc/chainloader.c @@ -31,6 +31,7 @@ #include #include #include +#include static grub_dl_t my_mod; static int boot_drive; @@ -89,29 +90,18 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) grub_file_close (file); /* Obtain the partition table from the root device. */ + drive = grub_get_root_biosnumber (); dev = grub_device_open (0); - if (dev) + if (dev && dev->disk && dev->disk->partition) { - grub_disk_t disk = dev->disk; - - if (disk) - { - grub_partition_t p = disk->partition; - - /* In i386-pc, the id is equal to the BIOS drive number. */ - drive = (int) disk->id; - - if (p) - { - grub_disk_read (disk, p->offset, 446, 64, - (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR); - part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR - + (p->index << 4)); - } - } - - grub_device_close (dev); + grub_disk_read (dev->disk, dev->disk->partition->offset, 446, 64, + (void *) GRUB_MEMORY_MACHINE_PART_TABLE_ADDR); + part_addr = (void *) (GRUB_MEMORY_MACHINE_PART_TABLE_ADDR + + (dev->disk->partition->index << 4)); } + + if (dev) + grub_device_close (dev); /* Ignore errors. Perhaps it's not fatal. */ grub_errno = GRUB_ERR_NONE;