iPXE
com32.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
00022  *
00023  * SYSLINUX COM32 image format
00024  *
00025  */
00026 
00027 FILE_LICENCE ( GPL2_OR_LATER );
00028 
00029 #include <stdint.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <strings.h>
00033 #include <errno.h>
00034 #include <assert.h>
00035 #include <realmode.h>
00036 #include <basemem.h>
00037 #include <comboot.h>
00038 #include <ipxe/uaccess.h>
00039 #include <ipxe/image.h>
00040 #include <ipxe/segment.h>
00041 #include <ipxe/init.h>
00042 #include <ipxe/io.h>
00043 #include <ipxe/console.h>
00044 
00045 /**
00046  * Execute COMBOOT image
00047  *
00048  * @v image             COM32 image
00049  * @ret rc              Return status code
00050  */
00051 static int com32_exec_loop ( struct image *image ) {
00052         struct memory_map memmap;
00053         unsigned int i;
00054         int state;
00055         uint32_t avail_mem_top;
00056 
00057         state = rmsetjmp ( comboot_return );
00058 
00059         switch ( state ) {
00060         case 0: /* First time through; invoke COM32 program */
00061 
00062                 /* Get memory map */
00063                 get_memmap ( &memmap );
00064 
00065                 /* Find end of block covering COM32 image loading area */
00066                 for ( i = 0, avail_mem_top = 0 ; i < memmap.count ; i++ ) {
00067                         if ( (memmap.regions[i].start <= COM32_START_PHYS) &&
00068                              (memmap.regions[i].end > COM32_START_PHYS + image->len) ) {
00069                                 avail_mem_top = memmap.regions[i].end;
00070                                 break;
00071                         }
00072                 }
00073 
00074                 DBGC ( image, "COM32 %p: available memory top = 0x%x\n",
00075                        image, avail_mem_top );
00076 
00077                 assert ( avail_mem_top != 0 );
00078 
00079                 /* Hook COMBOOT API interrupts */
00080                 hook_comboot_interrupts();
00081 
00082                 /* Unregister image, so that a "boot" command doesn't
00083                  * throw us into an execution loop.  We never
00084                  * reregister ourselves; COMBOOT images expect to be
00085                  * removed on exit.
00086                  */
00087                 unregister_image ( image );
00088 
00089                 __asm__ __volatile__ ( PHYS_CODE (
00090                         /* Preserve registers */
00091                         "pushal\n\t"
00092                         /* Preserve stack pointer */
00093                         "subl $4, %k0\n\t"
00094                         "movl %%esp, (%k0)\n\t"
00095                         /* Switch to COM32 stack */
00096                         "movl %k0, %%esp\n\t"
00097                         /* Enable interrupts */
00098                         "sti\n\t"
00099                         /* Construct stack frame */
00100                         "pushl %k1\n\t"
00101                         "pushl %k2\n\t"
00102                         "pushl %k3\n\t"
00103                         "pushl %k4\n\t"
00104                         "pushl %k5\n\t"
00105                         "pushl %k6\n\t"
00106                         "pushl $6\n\t"
00107                         /* Call COM32 entry point */
00108                         "movl %k7, %k0\n\t"
00109                         "call *%k0\n\t"
00110                         /* Disable interrupts */
00111                         "cli\n\t"
00112                         /* Restore stack pointer */
00113                         "movl 24(%%esp), %%esp\n\t"
00114                         /* Restore registers */
00115                         "popal\n\t" )
00116                         :
00117                         : "r" ( avail_mem_top ),
00118                           "r" ( virt_to_phys ( com32_cfarcall_wrapper ) ),
00119                           "r" ( virt_to_phys ( com32_farcall_wrapper ) ),
00120                           "r" ( get_fbms() * 1024 - ( COM32_BOUNCE_SEG << 4 ) ),
00121                           "i" ( COM32_BOUNCE_SEG << 4 ),
00122                           "r" ( virt_to_phys ( com32_intcall_wrapper ) ),
00123                           "r" ( virt_to_phys ( image->cmdline ?
00124                                                image->cmdline : "" ) ),
00125                           "i" ( COM32_START_PHYS )
00126                         : "memory" );
00127                 DBGC ( image, "COM32 %p: returned\n", image );
00128                 break;
00129 
00130         case COMBOOT_EXIT:
00131                 DBGC ( image, "COM32 %p: exited\n", image );
00132                 break;
00133 
00134         case COMBOOT_EXIT_RUN_KERNEL:
00135                 assert ( image->replacement );
00136                 DBGC ( image, "COM32 %p: exited to run kernel %s\n",
00137                        image, image->replacement->name );
00138                 break;
00139 
00140         case COMBOOT_EXIT_COMMAND:
00141                 DBGC ( image, "COM32 %p: exited after executing command\n",
00142                        image );
00143                 break;
00144 
00145         default:
00146                 assert ( 0 );
00147                 break;
00148         }
00149 
00150         unhook_comboot_interrupts();
00151         comboot_force_text_mode();
00152 
00153         return 0;
00154 }
00155 
00156 /**
00157  * Check image name extension
00158  *
00159  * @v image             COM32 image
00160  * @ret rc              Return status code
00161  */
00162 static int com32_identify ( struct image *image ) {
00163         const char *ext;
00164         static const uint8_t magic[] = { 0xB8, 0xFF, 0x4C, 0xCD, 0x21 };
00165         uint8_t buf[5];
00166 
00167         if ( image->len >= 5 ) {
00168                 /* Check for magic number
00169                  * mov eax,21cd4cffh
00170                  * B8 FF 4C CD 21
00171                  */
00172                 copy_from_user ( buf, image->data, 0, sizeof(buf) );
00173                 if ( ! memcmp ( buf, magic, sizeof(buf) ) ) {
00174                         DBGC ( image, "COM32 %p: found magic number\n",
00175                                image );
00176                         return 0;
00177                 }
00178         }
00179 
00180         /* Magic number not found; check filename extension */
00181 
00182         ext = strrchr( image->name, '.' );
00183 
00184         if ( ! ext ) {
00185                 DBGC ( image, "COM32 %p: no extension\n",
00186                        image );
00187                 return -ENOEXEC;
00188         }
00189 
00190         ++ext;
00191 
00192         if ( strcasecmp( ext, "c32" ) ) {
00193                 DBGC ( image, "COM32 %p: unrecognized extension %s\n",
00194                        image, ext );
00195                 return -ENOEXEC;
00196         }
00197 
00198         return 0;
00199 }
00200 
00201 
00202 /**
00203  * Load COM32 image into memory
00204  * @v image             COM32 image
00205  * @ret rc              Return status code
00206  */
00207 static int com32_load_image ( struct image *image ) {
00208         size_t filesz, memsz;
00209         userptr_t buffer;
00210         int rc;
00211 
00212         filesz = image->len;
00213         memsz = filesz;
00214         buffer = phys_to_user ( COM32_START_PHYS );
00215         if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
00216                 DBGC ( image, "COM32 %p: could not prepare segment: %s\n",
00217                        image, strerror ( rc ) );
00218                 return rc;
00219         }
00220 
00221         /* Copy image to segment */
00222         memcpy_user ( buffer, 0, image->data, 0, filesz );
00223 
00224         return 0;
00225 }
00226 
00227 /**
00228  * Prepare COM32 low memory bounce buffer
00229  * @v image             COM32 image
00230  * @ret rc              Return status code
00231  */
00232 static int com32_prepare_bounce_buffer ( struct image * image ) {
00233         unsigned int seg;
00234         userptr_t seg_userptr;
00235         size_t filesz, memsz;
00236         int rc;
00237 
00238         seg = COM32_BOUNCE_SEG;
00239         seg_userptr = real_to_user ( seg, 0 );
00240 
00241         /* Ensure the entire 64k segment is free */
00242         memsz = 0xFFFF;
00243         filesz = 0;
00244 
00245         /* Prepare, verify, and load the real-mode segment */
00246         if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) {
00247                 DBGC ( image, "COM32 %p: could not prepare bounce buffer segment: %s\n",
00248                        image, strerror ( rc ) );
00249                 return rc;
00250         }
00251 
00252         return 0;
00253 }
00254 
00255 /**
00256  * Probe COM32 image
00257  *
00258  * @v image             COM32 image
00259  * @ret rc              Return status code
00260  */
00261 static int com32_probe ( struct image *image ) {
00262         int rc;
00263 
00264         DBGC ( image, "COM32 %p: name '%s'\n", image, image->name );
00265 
00266         /* Check if this is a COMBOOT image */
00267         if ( ( rc = com32_identify ( image ) ) != 0 ) {
00268                 return rc;
00269         }
00270 
00271         return 0;
00272 }
00273 
00274 /**
00275  * Execute COMBOOT image
00276  *
00277  * @v image             COM32 image
00278  * @ret rc              Return status code
00279  */
00280 static int com32_exec ( struct image *image ) {
00281         int rc;
00282 
00283         /* Load image */
00284         if ( ( rc = com32_load_image ( image ) ) != 0 ) {
00285                 return rc;
00286         }
00287 
00288         /* Prepare bounce buffer segment */
00289         if ( ( rc = com32_prepare_bounce_buffer ( image ) ) != 0 ) {
00290                 return rc;
00291         }
00292 
00293         /* Reset console */
00294         console_reset();
00295 
00296         return com32_exec_loop ( image );
00297 }
00298 
00299 /** SYSLINUX COM32 image type */
00300 struct image_type com32_image_type __image_type ( PROBE_NORMAL ) = {
00301         .name = "COM32",
00302         .probe = com32_probe,
00303         .exec = com32_exec,
00304 };