iPXE
com32_call.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Daniel Verkamp <daniel@drv.nu>.
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 
00020 /**
00021  * @file SYSLINUX COM32 helpers
00022  *
00023  */
00024 
00025 FILE_LICENCE ( GPL2_OR_LATER );
00026 
00027 #include <stdint.h>
00028 #include <realmode.h>
00029 #include <comboot.h>
00030 #include <assert.h>
00031 #include <ipxe/uaccess.h>
00032 
00033 static com32sys_t __bss16 ( com32_regs );
00034 #define com32_regs __use_data16 ( com32_regs )
00035 
00036 static uint8_t __bss16 ( com32_int_vector );
00037 #define com32_int_vector __use_data16 ( com32_int_vector )
00038 
00039 static uint32_t __bss16 ( com32_farcall_proc );
00040 #define com32_farcall_proc __use_data16 ( com32_farcall_proc )
00041 
00042 uint16_t __bss16 ( com32_saved_sp );
00043 
00044 /**
00045  * Interrupt call helper
00046  */
00047 void __asmcall com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
00048 
00049         DBGC ( &com32_regs, "COM32 INT%x in %#08lx out %#08lx\n",
00050                interrupt, inregs_phys, outregs_phys );
00051 
00052         memcpy_user ( virt_to_user( &com32_regs ), 0,
00053                       phys_to_user ( inregs_phys ), 0,
00054                       sizeof(com32sys_t) );
00055 
00056         com32_int_vector = interrupt;
00057 
00058         __asm__ __volatile__ (
00059                 REAL_CODE ( /* Save all registers */
00060                             "pushal\n\t"
00061                             "pushw %%ds\n\t"
00062                             "pushw %%es\n\t"
00063                             "pushw %%fs\n\t"
00064                             "pushw %%gs\n\t"
00065                             /* Mask off unsafe flags */
00066                             "movl (com32_regs + 40), %%eax\n\t"
00067                             "andl $0x200cd7, %%eax\n\t"
00068                             "movl %%eax, (com32_regs + 40)\n\t"
00069                             /* Load com32_regs into the actual registers */
00070                             "movw %%sp, %%ss:(com32_saved_sp)\n\t"
00071                             "movw $com32_regs, %%sp\n\t"
00072                             "popw %%gs\n\t"
00073                             "popw %%fs\n\t"
00074                             "popw %%es\n\t"
00075                             "popw %%ds\n\t"
00076                             "popal\n\t"
00077                             "popfl\n\t"
00078                             "movw %%ss:(com32_saved_sp), %%sp\n\t"
00079                             /* patch INT instruction */
00080                             "pushw %%ax\n\t"
00081                             "movb %%ss:(com32_int_vector), %%al\n\t"
00082                             "movb %%al, %%cs:(com32_intcall_instr + 1)\n\t"
00083                             /* perform a jump to avoid problems with cache
00084                              * consistency in self-modifying code on some CPUs (486)
00085                              */
00086                             "jmp 1f\n"
00087                             "1:\n\t"
00088                             "popw %%ax\n\t"
00089                             "com32_intcall_instr:\n\t"
00090                             /* INT instruction to be patched */
00091                             "int $0xFF\n\t"
00092                             /* Copy regs back to com32_regs */
00093                             "movw %%sp, %%ss:(com32_saved_sp)\n\t"
00094                             "movw $(com32_regs + 44), %%sp\n\t"
00095                             "pushfl\n\t"
00096                             "pushal\n\t"
00097                             "pushw %%ds\n\t"
00098                             "pushw %%es\n\t"
00099                             "pushw %%fs\n\t"
00100                             "pushw %%gs\n\t"
00101                             "movw %%ss:(com32_saved_sp), %%sp\n\t"
00102                             /* Restore registers */
00103                             "popw %%gs\n\t"
00104                             "popw %%fs\n\t"
00105                             "popw %%es\n\t"
00106                             "popw %%ds\n\t"
00107                             "popal\n\t")
00108                             : : );
00109 
00110         if ( outregs_phys ) {
00111                 memcpy_user ( phys_to_user ( outregs_phys ), 0,
00112                               virt_to_user( &com32_regs ), 0,
00113                               sizeof(com32sys_t) );
00114         }
00115 }
00116 
00117 /**
00118  * Farcall helper
00119  */
00120 void __asmcall com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t outregs_phys ) {
00121 
00122         DBGC ( &com32_regs, "COM32 farcall %04x:%04x in %#08lx out %#08lx\n",
00123                ( proc >> 16 ), ( proc & 0xffff ), inregs_phys, outregs_phys );
00124 
00125         memcpy_user ( virt_to_user( &com32_regs ), 0,
00126                       phys_to_user ( inregs_phys ), 0,
00127                       sizeof(com32sys_t) );
00128 
00129         com32_farcall_proc = proc;
00130 
00131         __asm__ __volatile__ (
00132                 REAL_CODE ( /* Save all registers */
00133                             "pushal\n\t"
00134                             "pushw %%ds\n\t"
00135                             "pushw %%es\n\t"
00136                             "pushw %%fs\n\t"
00137                             "pushw %%gs\n\t"
00138                             /* Mask off unsafe flags */
00139                             "movl (com32_regs + 40), %%eax\n\t"
00140                             "andl $0x200cd7, %%eax\n\t"
00141                             "movl %%eax, (com32_regs + 40)\n\t"
00142                             /* Load com32_regs into the actual registers */
00143                             "movw %%sp, %%ss:(com32_saved_sp)\n\t"
00144                             "movw $com32_regs, %%sp\n\t"
00145                             "popw %%gs\n\t"
00146                             "popw %%fs\n\t"
00147                             "popw %%es\n\t"
00148                             "popw %%ds\n\t"
00149                             "popal\n\t"
00150                             "popfl\n\t"
00151                             "movw %%ss:(com32_saved_sp), %%sp\n\t"
00152                             /* Call procedure */
00153                             "lcall *%%ss:(com32_farcall_proc)\n\t"
00154                             /* Copy regs back to com32_regs */
00155                             "movw %%sp, %%ss:(com32_saved_sp)\n\t"
00156                             "movw $(com32_regs + 44), %%sp\n\t"
00157                             "pushfl\n\t"
00158                             "pushal\n\t"
00159                             "pushw %%ds\n\t"
00160                             "pushw %%es\n\t"
00161                             "pushw %%fs\n\t"
00162                             "pushw %%gs\n\t"
00163                             "movw %%ss:(com32_saved_sp), %%sp\n\t"
00164                             /* Restore registers */
00165                             "popw %%gs\n\t"
00166                             "popw %%fs\n\t"
00167                             "popw %%es\n\t"
00168                             "popw %%ds\n\t"
00169                             "popal\n\t")
00170                             : : );
00171 
00172         if ( outregs_phys ) {
00173                 memcpy_user ( phys_to_user ( outregs_phys ), 0,
00174                               virt_to_user( &com32_regs ), 0,
00175                               sizeof(com32sys_t) );
00176         }
00177 }
00178 
00179 /**
00180  * CDECL farcall helper
00181  */
00182 int __asmcall com32_cfarcall ( uint32_t proc, physaddr_t stack, size_t stacksz ) {
00183         int32_t eax;
00184 
00185         DBGC ( &com32_regs, "COM32 cfarcall %04x:%04x params %#08lx+%#zx\n",
00186                ( proc >> 16 ), ( proc & 0xffff ), stack, stacksz );
00187 
00188         copy_user_to_rm_stack ( phys_to_user ( stack ), stacksz );
00189         com32_farcall_proc = proc;
00190 
00191         __asm__ __volatile__ (
00192                 REAL_CODE ( "lcall *%%ss:(com32_farcall_proc)\n\t" )
00193                 : "=a" (eax)
00194                 :
00195                 : "ecx", "edx" );
00196 
00197         remove_user_from_rm_stack ( 0, stacksz );
00198 
00199         return eax;
00200 }