/* * GRUB -- GRand Unified Bootloader * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,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 . */ /* * Note: These functions defined in this file may be called from C. * Be careful of that you must not modify some registers. Quote * from gcc-2.95.2/gcc/config/i386/i386.h: 1 for registers not available across function calls. These must include the FIXED_REGISTERS and also any registers that can be used without being saved. The latter must include the registers where values are returned and the register where structure-value addresses are passed. Aside from that, you can include as many other registers as you like. ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg { 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } */ /* * Note: GRUB is compiled with the options -mrtd and -mregparm=3. * So the first three arguments are passed in %eax, %edx, and %ecx, * respectively, and if a function has a fixed number of arguments * and the number if greater than three, the function must return * with "ret $N" where N is ((the number of arguments) - 3) * 4. */ #include .intel_syntax noprefix #define GRUB_DRIVEMAP_INT13H_OFFSET(x) ((x) - grub_drivemap_int13_handler_base) /* Copy starts here. When deployed, this label must be segment-aligned. */ VARIABLE(grub_drivemap_int13_handler_base) /* 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_int13_oldhandler) .long 0 /* Drivemap module bundle - INT 13h handler - BIOS HD map */ /* We need to use relative addressing, and with CS to top it all, since we must make as few changes to the registers as possible. IP-relative addressing like on amd64 would make life way easier here. */ .code16 FUNCTION(grub_drivemap_int13_handler) push bp mov bp, sp push ax /* We'll need it later to determine the used BIOS function. */ /* Map the drive number (always in DL?). */ push ax push bx push si mov bx, offset GRUB_DRIVEMAP_INT13H_OFFSET(grub_drivemap_int13_mapstart) xor si, si 1:mov ax, word ptr cs:[bx + si] cmp al, ah jz 3f /* DRV=DST => map end - drive not remapped, leave DL as-is. */ cmp al, dl jz 2f /* Found - drive remapped, modify DL. */ add si, 2 jmp 1b /* Not found, but more remaining, loop. */ 2:mov dl, ah 3:pop si pop bx xchg ax, [bp - 4] /* Recover the old AX and save the map entry for later. */ push bp /* Simulate interrupt call: push flags and do a far call in order to set the stack the way the old handler expects it so that its iret works. */ push [bp + 6] mov bp, word ptr [bp] /* Restore the caller BP (is this needed and/or sensible?). */ call dword ptr cs:[GRUB_DRIVEMAP_INT13H_OFFSET(grub_drivemap_int13_oldhandler)] pop bp /* The pushed flags were removed by iret. */ /* Set the saved flags to what the int13h handler returned. */ push ax pushf pop ax mov word ptr [bp + 6], ax pop ax /* Reverse map any returned drive number if the data returned includes it. The only func that does this seems to be origAH = 0x08, but many BIOS refs say retDL = # of drives connected. However, the GRUB Legacy code treats this as the _drive number_ and "undoes" the remapping. Thus, this section has been disabled for testing if it's required. */ # cmp byte ptr [bp - 1], 0x08 /* Caller's AH. */ # jne 4f # xchg ax, [bp - 4] /* Map entry used. */ # cmp al, ah /* DRV=DST => drive not remapped. */ # je 4f # mov dl, ah /* Undo remap. */ 4:mov sp, bp pop bp iret /* 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_int13_mapstart) /* Copy stops here. */ .code32 VARIABLE(grub_drivemap_int13_size) .word GRUB_DRIVEMAP_INT13H_OFFSET(grub_drivemap_int13_size)