1 /* 2 * Copyright (C) 2007 Michael Brown <mbrown (at) fensystems.co.uk>. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19 FILE_LICENCE ( GPL2_OR_LATER ); 20 21 /** 22 * @file 23 * 24 * x86 bootsector image format 25 * 26 */ 27 28 #include <errno.h> 29 #include <realmode.h> 30 #include <biosint.h> 31 #include <bootsector.h> 32 33 /** Vector for storing original INT 18 handler 34 * 35 * We do not chain to this vector, so there is no need to place it in 36 * .text16. 37 */ 38 static struct segoff int18_vector; 39 40 /** Vector for storing original INT 19 handler 41 * 42 * We do not chain to this vector, so there is no need to place it in 43 * .text16. 44 */ 45 static struct segoff int19_vector; 46 47 /** Restart point for INT 18 or 19 */ 48 extern void bootsector_exec_fail ( void ); 49 50 /** 51 * Jump to preloaded bootsector 52 * 53 * @v segment Real-mode segment 54 * @v offset Real-mode offset 55 * @v drive Drive number to pass to boot sector 56 * @ret rc Return status code 57 */ 58 int call_bootsector ( unsigned int segment, unsigned int offset, 59 unsigned int drive ) { 60 int discard_b, discard_D, discard_d; 61 62 DBG ( "Booting from boot sector at %04x:%04x\n", segment, offset ); 63 64 /* Hook INTs 18 and 19 to capture failure paths */ 65 hook_bios_interrupt ( 0x18, ( unsigned int ) bootsector_exec_fail, 66 &int18_vector ); 67 hook_bios_interrupt ( 0x19, ( unsigned int ) bootsector_exec_fail, 68 &int19_vector ); 69 70 /* Boot the loaded sector 71 * 72 * We assume that the boot sector may completely destroy our 73 * real-mode stack, so we preserve everything we need in 74 * static storage. 75 */ 76 __asm__ __volatile__ ( REAL_CODE ( /* Save return address off-stack */ 77 "popw %%cs:saved_retaddr\n\t" 78 /* Save stack pointer */ 79 "movw %%ss, %%ax\n\t" 80 "movw %%ax, %%cs:saved_ss\n\t" 81 "movw %%sp, %%cs:saved_sp\n\t" 82 /* Jump to boot sector */ 83 "pushw %%bx\n\t" 84 "pushw %%di\n\t" 85 "sti\n\t" 86 "lret\n\t" 87 /* Preserved variables */ 88 "\nsaved_ss: .word 0\n\t" 89 "\nsaved_sp: .word 0\n\t" 90 "\nsaved_retaddr: .word 0\n\t" 91 /* Boot failure return point */ 92 "\nbootsector_exec_fail:\n\t" 93 /* Restore stack pointer */ 94 "movw %%cs:saved_ss, %%ax\n\t" 95 "movw %%ax, %%ss\n\t" 96 "movw %%cs:saved_sp, %%sp\n\t" 97 /* Return via saved address */ 98 "jmp *%%cs:saved_retaddr\n\t" ) 99 : "=b" ( discard_b ), "=D" ( discard_D ), 100 "=d" ( discard_d ) 101 : "b" ( segment ), "D" ( offset ), 102 "d" ( drive ) 103 : "eax", "ecx", "esi", "ebp" ); 104 105 DBG ( "Booted disk returned via INT 18 or 19\n" ); 106 107 /* Unhook INTs 18 and 19 */ 108 unhook_bios_interrupt ( 0x18, ( unsigned int ) bootsector_exec_fail, 109 &int18_vector ); 110 unhook_bios_interrupt ( 0x19, ( unsigned int ) bootsector_exec_fail, 111 &int19_vector ); 112 113 return -ECANCELED; 114 } 115