Message-Id: <email address hidden>
Date: Tue, 16 Aug 2005 14:20:14 +0100
From: Matthew Garrett <email address hidden>
To: Debian Bug Tracking System <email address hidden>
Subject: grub: Does not fall back to source drive if BIOS fails to pass boot drive
Package: grub
Version: 0.95+cvs20040624-12
Severity: normal
Tags: patch
On boot, the BIOS is supposed to pass the boot drive to the bootloader
in register dx. Not all BIOSes do this. The included patch causes grub
to attempt to boot off the boot drive passed by the BIOS. If this fails,
it then reverts to the drive that grub was originally installed to. It
should only trigger in cases that currently fail.
+/* The offset of STAGE1_SOURCE_DRIVE. */
+#define STAGE1_SOURCE_DRIVE 0x4e
+
/* The offset of a magic number used by Windows NT. */
#define STAGE1_WINDOWS_NT_MAGIC 0x1b8
+
+source_drive:
+ .byte GRUB_INVALID_DRIVE
+
/*
* ljmp to the next instruction because some bogus BIOSes
* jump to 07C0:0000 instead of 0000:7C00.
*/
ljmp $0, $ABS(real_start)
-
+
real_start:
/* set up %ds and %ss as offset from 0 */
@@ -236,7 +240,18 @@
testb $STAGE1_BIOS_HD_FLAG, %dl
jz floppy_probe
- /* Nope, we definitely have a hard disk, and we're screwed. */
+ /* Nope, we definitely have a hard disk, and we're screwed.
+ Try as hard as we can to recover. */
+
+ MOV_MEM_TO_AL(ABS(source_drive)) /* movb ABS(source_drive), %al */
+ cmpb $GRUB_INVALID_DRIVE, %al
+ je 1f
+ cmpb %al, %dl /* We've been here before */
+ je 1f
+ movb %al, %dl
+ jmp 1b
+
+1:
jmp hd_probe_error
- if (! new_drive)
+ if (! new_drive) {
new_drive = src_drive;
- else if (src_drive != dest_drive)
- grub_printf ("Warning: the option `d' was not used, but the Stage 1 will"
- " be installed on a\ndifferent drive than the drive where"
- " the Stage 2 resides.\n");
+ *((unsigned char *) (stage1_buffer + STAGE1_SOURCE_DRIVE)) =
+ GRUB_INVALID_DRIVE;
+ } else {
+ if (src_drive != dest_drive)
+ grub_printf ("Warning: the option `d' was not used, but the"
+ " Stage 1 will be installed on a\ndifferent"
+ " drive than the drive where the Stage 2"
+ " resides.\n");
+ *((unsigned char *) (stage1_buffer + STAGE1_SOURCE_DRIVE)) =
+ src_drive;
+ }
/* Set the boot drive. */
*((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE)) = new_drive;
-- System Information:
Debian Release: 3.1
Architecture: i386 (i586)
Kernel: Linux 2.6.8-2-386
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Versions of packages grub depends on:
ii libc6 2.3.2.ds1-20 GNU C Library: Shared libraries an
ii libncurses5 5.4-4 Shared libraries for terminal hand
Message-Id: <email address hidden>
Date: Tue, 16 Aug 2005 14:20:14 +0100
From: Matthew Garrett <email address hidden>
To: Debian Bug Tracking System <email address hidden>
Subject: grub: Does not fall back to source drive if BIOS fails to pass boot drive
Package: grub
Version: 0.95+cvs20040624-12
Severity: normal
Tags: patch
On boot, the BIOS is supposed to pass the boot drive to the bootloader
in register dx. Not all BIOSes do this. The included patch causes grub
to attempt to boot off the boot drive passed by the BIOS. If this fails,
it then reverts to the drive that grub was originally installed to. It
should only trigger in cases that currently fail.
diff -ur -x 'Makefile*' -x 'config.*' grub-0. 95+cvs20040624/ stage1/ stage1. h grubme/ stage1/ stage1. h 95+cvs20040624/ stage1/ stage1. h 2004-03-27 17:02:53 +0000 stage1/ stage1. h 2005-08-16 13:54:01 +0100 BOOT_DRIVE_ MASK 0x4d
--- grub-0.
+++ grubme/
@@ -54,6 +54,9 @@
/* The offset of BOOT_DRIVE_MASK. */
#define STAGE1_
+/* The offset of STAGE1_ SOURCE_ DRIVE. */ WINDOWS_ NT_MAGIC 0x1b8
+#define STAGE1_SOURCE_DRIVE 0x4e
+
/* The offset of a magic number used by Windows NT. */
#define STAGE1_
diff -ur -x 'Makefile*' -x 'config.*' grub-0. 95+cvs20040624/ stage1/ stage1. S grubme/ stage1/ stage1. S 95+cvs20040624/ stage1/ stage1. S 2004-03-27 17:02:53 +0000 stage1/ stage1. S 2005-08-16 13:55:34 +0100
--- grub-0.
+++ grubme/
@@ -115,12 +115,16 @@
boot_drive_mask:
.byte 0x00
+
+source_drive:
+ .byte GRUB_INVALID_DRIVE
+
/*
* ljmp to the next instruction because some bogus BIOSes
* jump to 07C0:0000 instead of 0000:7C00.
*/
ljmp $0, $ABS(real_start)
-
+
real_start:
/* set up %ds and %ss as offset from 0 */ BIOS_HD_ FLAG, %dl
@@ -236,7 +240,18 @@
testb $STAGE1_
jz floppy_probe
- /* Nope, we definitely have a hard disk, and we're screwed. */ TO_AL(ABS( source_ drive)) /* movb ABS(source_drive), %al */ DRIVE, %al
+ /* Nope, we definitely have a hard disk, and we're screwed.
+ Try as hard as we can to recover. */
+
+ MOV_MEM_
+ cmpb $GRUB_INVALID_
+ je 1f
+ cmpb %al, %dl /* We've been here before */
+ je 1f
+ movb %al, %dl
+ jmp 1b
+
+1:
jmp hd_probe_error
final_init: 95+cvs20040624/ stage2/ builtins. c grubme/ stage2/ builtins. c 95+cvs20040624/ stage2/ builtins. c 2005-08-16 13:34:13 +0100 stage2/ builtins. c 2005-08-16 13:57:44 +0100
diff -ur -x 'Makefile*' -x 'config.*' grub-0.
--- grub-0.
+++ grubme/
@@ -2063,12 +2063,19 @@
src_part_start = part_start;
src_geom = buf_geom;
- if (! new_drive) SOURCE_ DRIVE)) = SOURCE_ DRIVE)) =
+ if (! new_drive) {
new_drive = src_drive;
- else if (src_drive != dest_drive)
- grub_printf ("Warning: the option `d' was not used, but the Stage 1 will"
- " be installed on a\ndifferent drive than the drive where"
- " the Stage 2 resides.\n");
+ *((unsigned char *) (stage1_buffer + STAGE1_
+ GRUB_INVALID_DRIVE;
+ } else {
+ if (src_drive != dest_drive)
+ grub_printf ("Warning: the option `d' was not used, but the"
+ " Stage 1 will be installed on a\ndifferent"
+ " drive than the drive where the Stage 2"
+ " resides.\n");
+ *((unsigned char *) (stage1_buffer + STAGE1_
+ src_drive;
+ }
/* Set the boot drive. */
*((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE)) = new_drive;
-- System Information: en_GB.UTF- 8 (charmap=UTF-8)
Debian Release: 3.1
Architecture: i386 (i586)
Kernel: Linux 2.6.8-2-386
Locale: LANG=en_GB.UTF-8, LC_CTYPE=
Versions of packages grub depends on:
ii libc6 2.3.2.ds1-20 GNU C Library: Shared libraries an
ii libncurses5 5.4-4 Shared libraries for terminal hand
-- debconf information: boot_loader: true replace_ other_boot_ loader: false
* grub/install_
grub/