summaryrefslogtreecommitdiffstats
path: root/grub-core/commands/i386/pc/drivemap_int13h.S
diff options
context:
space:
mode:
Diffstat (limited to 'grub-core/commands/i386/pc/drivemap_int13h.S')
-rw-r--r--grub-core/commands/i386/pc/drivemap_int13h.S124
1 files changed, 124 insertions, 0 deletions
diff --git a/grub-core/commands/i386/pc/drivemap_int13h.S b/grub-core/commands/i386/pc/drivemap_int13h.S
new file mode 100644
index 0000000..3c87521
--- /dev/null
+++ b/grub-core/commands/i386/pc/drivemap_int13h.S
@@ -0,0 +1,124 @@
+/* drivemap_int13h.S - interrupt handler for the BIOS drive remapper */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008, 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+#define INT13H_OFFSET(x) ((x) - LOCAL (base))
+
+.code16
+
+/* Copy starts here. When deployed, this code must be segment-aligned. */
+
+/* The replacement int13 handler. Preserve all registers. */
+FUNCTION(grub_drivemap_handler)
+LOCAL (base):
+ /* 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
+#ifdef __APPLE__
+ LOCAL(mapstart_offset) = INT13H_OFFSET(LOCAL (mapstart))
+ movw $LOCAL(mapstart_offset), %bx
+#else
+ movw $INT13H_OFFSET(LOCAL (mapstart)), %bx
+#endif
+
+more_remaining:
+ movw %cs:(%bx), %ax
+ cmpb %ah, %al
+ jz not_found /* DRV=DST => map end - drive not remapped, keep DL. */
+ inc %bx
+ inc %bx
+ cmpb %dl, %al
+ jnz more_remaining /* Not found, but more remaining, loop. */
+ movb %ah, %dl /* Found - drive remapped, modify DL. */
+
+not_found:
+ pop %bx
+ pop %ax
+
+ /* If the call isn't ah=0x8 or ah=0x15 we must restore %dx. */
+ cmpb $0x8, %ah
+ jz norestore
+ cmpb $0x15, %ah
+ jz norestore
+
+ /* Restore flags. */
+ popf
+ pushf
+
+#ifdef __APPLE__
+ LOCAL(oldhandler_offset) = INT13H_OFFSET (LOCAL (oldhandler))
+ lcall *%cs:LOCAL(oldhandler_offset)
+#else
+ lcall *%cs:INT13H_OFFSET (LOCAL (oldhandler))
+#endif
+
+ push %bp
+ mov %sp, %bp
+
+tail:
+ /* Save new flags below %esp so the caller will recieve new flags. */
+ pushf
+ pop %dx
+ mov %dx, 8(%bp)
+
+ pop %bp
+
+ /* Restore %dx. */
+ pop %dx
+ iret
+
+norestore:
+
+ /* Restore flags. */
+ popf
+ pushf
+
+#ifdef __APPLE__
+ lcall *%cs:LOCAL(oldhandler_offset)
+#else
+ lcall *%cs:INT13H_OFFSET (LOCAL (oldhandler))
+#endif
+
+ push %bp
+ mov %sp, %bp
+
+ /* Save %dx. So it won't be restored to original value. */
+ mov %dx, 2(%bp)
+
+ jmp tail
+
+/* 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)
+LOCAL (oldhandler):
+ .word 0x0, 0x0
+
+/* This label MUST be at the end of the copied block, since the installer code
+ reserves additional space for mappings at runtime and copies them over it. */
+ .align 2
+
+VARIABLE(grub_drivemap_mapstart)
+LOCAL (mapstart):
+ .byte 0