iPXE
bootsector.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 /**
00027  * @file
00028  *
00029  * x86 bootsector image format
00030  *
00031  */
00032 
00033 #include <errno.h>
00034 #include <realmode.h>
00035 #include <biosint.h>
00036 #include <bootsector.h>
00037 #include <ipxe/console.h>
00038 
00039 /** Vector for storing original INT 18 handler
00040  *
00041  * We do not chain to this vector, so there is no need to place it in
00042  * .text16.
00043  */
00044 static struct segoff int18_vector;
00045 
00046 /** Vector for storing original INT 19 handler
00047  *
00048  * We do not chain to this vector, so there is no need to place it in
00049  * .text16.
00050  */
00051 static struct segoff int19_vector;
00052 
00053 /** Restart point for INT 18 or 19 */
00054 extern void bootsector_exec_fail ( void );
00055 
00056 /**
00057  * Jump to preloaded bootsector
00058  *
00059  * @v segment           Real-mode segment
00060  * @v offset            Real-mode offset
00061  * @v drive             Drive number to pass to boot sector
00062  * @ret rc              Return status code
00063  */
00064 int call_bootsector ( unsigned int segment, unsigned int offset,
00065                       unsigned int drive ) {
00066         int discard_b, discard_D, discard_d;
00067 
00068         /* Reset console, since boot sector will probably use it */
00069         console_reset();
00070 
00071         DBG ( "Booting from boot sector at %04x:%04x\n", segment, offset );
00072 
00073         /* Hook INTs 18 and 19 to capture failure paths */
00074         hook_bios_interrupt ( 0x18, ( intptr_t ) bootsector_exec_fail,
00075                               &int18_vector );
00076         hook_bios_interrupt ( 0x19, ( intptr_t ) bootsector_exec_fail,
00077                               &int19_vector );
00078 
00079         /* Boot the loaded sector
00080          *
00081          * We assume that the boot sector may completely destroy our
00082          * real-mode stack, so we preserve everything we need in
00083          * static storage.
00084          */
00085         __asm__ __volatile__ ( REAL_CODE ( /* Save return address off-stack */
00086                                            "popw %%cs:saved_retaddr\n\t"
00087                                            /* Save stack pointer */
00088                                            "movw %%ss, %%ax\n\t"
00089                                            "movw %%ax, %%cs:saved_ss\n\t"
00090                                            "movw %%sp, %%cs:saved_sp\n\t"
00091                                            /* Save frame pointer (gcc bug) */
00092                                            "movl %%ebp, %%cs:saved_ebp\n\t"
00093                                            /* Prepare jump to boot sector */
00094                                            "pushw %%bx\n\t"
00095                                            "pushw %%di\n\t"
00096                                            /* Clear all registers */
00097                                            "xorl %%eax, %%eax\n\t"
00098                                            "xorl %%ebx, %%ebx\n\t"
00099                                            "xorl %%ecx, %%ecx\n\t"
00100                                            /* %edx contains drive number */
00101                                            "xorl %%esi, %%esi\n\t"
00102                                            "xorl %%edi, %%edi\n\t"
00103                                            "xorl %%ebp, %%ebp\n\t"
00104                                            "movw %%ax, %%ds\n\t"
00105                                            "movw %%ax, %%es\n\t"
00106                                            "movw %%ax, %%fs\n\t"
00107                                            "movw %%ax, %%gs\n\t"
00108                                            /* Jump to boot sector */
00109                                            "sti\n\t"
00110                                            "lret\n\t"
00111                                            /* Preserved variables */
00112                                            "\nsaved_ebp: .long 0\n\t"
00113                                            "\nsaved_ss: .word 0\n\t"
00114                                            "\nsaved_sp: .word 0\n\t"
00115                                            "\nsaved_retaddr: .word 0\n\t"
00116                                            /* Boot failure return point */
00117                                            "\nbootsector_exec_fail:\n\t"
00118                                            /* Restore frame pointer (gcc bug) */
00119                                            "movl %%cs:saved_ebp, %%ebp\n\t"
00120                                            /* Restore stack pointer */
00121                                            "movw %%cs:saved_ss, %%ax\n\t"
00122                                            "movw %%ax, %%ss\n\t"
00123                                            "movw %%cs:saved_sp, %%sp\n\t"
00124                                            /* Return via saved address */
00125                                            "jmp *%%cs:saved_retaddr\n\t" )
00126                                : "=b" ( discard_b ), "=D" ( discard_D ),
00127                                  "=d" ( discard_d )
00128                                : "b" ( segment ), "D" ( offset ),
00129                                  "d" ( drive )
00130                                : "eax", "ecx", "esi" );
00131 
00132         DBG ( "Booted disk returned via INT 18 or 19\n" );
00133 
00134         /* Unhook INTs 18 and 19 */
00135         unhook_bios_interrupt ( 0x18, ( intptr_t ) bootsector_exec_fail,
00136                                 &int18_vector );
00137         unhook_bios_interrupt ( 0x19, ( intptr_t ) bootsector_exec_fail,
00138                                 &int19_vector );
00139         
00140         return -ECANCELED;
00141 }