/*
* 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
#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 %sp, %bp
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 $GRUB_DRIVEMAP_INT13H_OFFSET(grub_drivemap_int13_mapstart), %bx
xor %si, %si
1:movw %cs:(%bx,%si), %ax
cmp %ah, %al
jz 3f /* DRV=DST => map end - drive not remapped, leave DL as-is. */
cmp %dl, %al
jz 2f /* Found - drive remapped, modify DL. */
add $2, %si
jmp 1b /* Not found, but more remaining, loop. */
2:mov %ah, %dl
3:pop %si
pop %bx
xchgw %ax, -4(%bp) /* 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 6(%bp)
movw (%bp), %bp /* Restore the caller BP (is this needed and/or sensible?). */
lcall *%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
movw %ax, 6(%bp)
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. */
# cmpb $0x08, -1(%bp) /* Caller's AH. */
# jne 4f
# xchgw %ax, -4(%bp) /* Map entry used. */
# cmp %ah, %al /* DRV=DST => drive not remapped. */
# je 4f
# mov %ah, %dl /* Undo remap. */
4:mov %bp, %sp
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)