From 4435667a0081e8dbd6c1c3be9a22e8ec201401d1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 14 May 2006 13:44:47 +0000 Subject: [PATCH] Add int13_boot(), to allow booting from INT 13 emulated drives. --- src/arch/i386/include/int13.h | 1 + src/arch/i386/interface/pcbios/int13.c | 88 ++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/src/arch/i386/include/int13.h b/src/arch/i386/include/int13.h index 0d93880c..8f3062be 100644 --- a/src/arch/i386/include/int13.h +++ b/src/arch/i386/include/int13.h @@ -153,5 +153,6 @@ struct int13_disk_parameters { extern void register_int13_drive ( struct int13_drive *drive ); extern void unregister_int13_drive ( struct int13_drive *drive ); +extern int int13_boot ( unsigned int drive ); #endif /* INT13_H */ diff --git a/src/arch/i386/interface/pcbios/int13.c b/src/arch/i386/interface/pcbios/int13.c index edf62f4d..229bb3ba 100644 --- a/src/arch/i386/interface/pcbios/int13.c +++ b/src/arch/i386/interface/pcbios/int13.c @@ -16,7 +16,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include +#include +#include #include #include #include @@ -41,6 +44,16 @@ static struct segoff __text16 ( int13_vector ); /** Assembly wrapper */ extern void int13_wrapper ( void ); +/** Vector for storing original INT 18 handler + * + * We do not chain to this vector, so there is no need to place it in + * .text16. + */ +static struct segoff int18_vector; + +/** Restart point for INT 18 */ +extern void int13_exec_fail ( void ); + /** List of registered emulated drives */ static LIST_HEAD ( drives ); @@ -473,3 +486,78 @@ void unregister_int13_drive ( struct int13_drive *drive ) { if ( list_empty ( &drives ) ) unhook_int13(); } + +/** + * Attempt to boot from an INT 13 drive + * + * @v drive Drive number + * @ret rc Return status code + * + * This boots from the specified INT 13 drive by loading the Master + * Boot Record to 0000:7c00 and jumping to it. INT 18 is hooked to + * capture an attempt by the MBR to boot the next device. (This is + * the closest thing to a return path from an MBR). + * + * Note that this function can never return success, by definition. + */ +int int13_boot ( unsigned int drive ) { + int status, signature; + int d0, d1; + + DBG ( "Booting from INT 13 drive %02x\n", drive ); + + /* Use INT 13 to read the boot sector */ + REAL_EXEC ( rm_int13_boot, + "pushw $0\n\t" + "popw %%es\n\t" + "int $0x13\n\t" + "jc 1f\n\t" + "xorl %%eax, %%eax\n\t" + "\n1:\n\t" + "movzwl %%es:0x7dfe, %%ebx\n\t", + 4, + OUT_CONSTRAINTS ( "=a" ( status ), "=b" ( signature ), + "=c" ( d0 ), "=d" ( drive ) ), + IN_CONSTRAINTS ( "0" ( 0x0201 ), "1" ( 0x7c00 ), + "2" ( 0x0001 ), "3" ( drive ) ), + CLOBBER ( "ebp" ) ); + if ( status ) + return -EIO; + + /* Check signature is correct */ + if ( signature != be16_to_cpu ( 0x55aa ) ) { + DBG ( "Invalid disk signature %#04x (should be 0x55aa)\n", + cpu_to_be16 ( signature ) ); + return -ENOEXEC; + } + + /* Hook INT 18 to capture failure path */ + hook_bios_interrupt ( 0x18, ( unsigned int ) int13_exec_fail, + &int18_vector ); + + /* Boot the loaded sector */ + REAL_EXEC ( rm_int13_exec, + "movw %%ss, %%ax\n\t" /* Preserve stack pointer */ + "movw %%ax, %%cs:int13_exec_saved_ss\n\t" + "movw %%sp, %%cs:int13_exec_saved_sp\n\t" + "ljmp $0, $0x7c00\n\t" + "\nint13_exec_saved_ss: .word 0\n\t" + "\nint13_exec_saved_sp: .word 0\n\t" + "\nint13_exec_fail:\n\t" + "movw %%cs:int13_exec_saved_ss, %%ax\n\t" + "movw %%ax, %%ss\n\t" + "movw %%cs:int13_exec_saved_sp, %%sp\n\t" + "\n99:\n\t", + 1, + OUT_CONSTRAINTS ( "=d" ( d1 ) ), + IN_CONSTRAINTS ( "d" ( drive ) ), + CLOBBER ( "eax", "ebx", "ecx", "esi", "edi", "ebp" ) ); + + DBG ( "Booted disk returned via INT 18\n" ); + + /* Unhook INT 18 */ + unhook_bios_interrupt ( 0x18, ( unsigned int ) int13_exec_fail, + &int18_vector ); + + return -ECANCELED; +}