iPXE
sdi.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2012 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 (at your option) 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 #include <stdint.h>
00027 #include <string.h>
00028 #include <errno.h>
00029 #include <realmode.h>
00030 #include <sdi.h>
00031 #include <ipxe/image.h>
00032 #include <ipxe/features.h>
00033 
00034 /** @file
00035  *
00036  * System Deployment Image (SDI)
00037  *
00038  * Based on the MSDN article "RAM boot using SDI in Windows XP
00039  * Embedded with Service Pack 1", available at the time of writing
00040  * from:
00041  *
00042  *   http://msdn.microsoft.com/en-us/library/ms838543.aspx
00043  */
00044 
00045 FEATURE ( FEATURE_IMAGE, "SDI", DHCP_EB_FEATURE_SDI, 1 );
00046 
00047 /**
00048  * Parse SDI image header
00049  *
00050  * @v image             SDI file
00051  * @v sdi               SDI header to fill in
00052  * @ret rc              Return status code
00053  */
00054 static int sdi_parse_header ( struct image *image, struct sdi_header *sdi ) {
00055 
00056         /* Sanity check */
00057         if ( image->len < sizeof ( *sdi ) ) {
00058                 DBGC ( image, "SDI %p too short for SDI header\n", image );
00059                 return -ENOEXEC;
00060         }
00061 
00062         /* Read in header */
00063         copy_from_user ( sdi, image->data, 0, sizeof ( *sdi ) );
00064 
00065         /* Check signature */
00066         if ( sdi->magic != SDI_MAGIC ) {
00067                 DBGC ( image, "SDI %p is not an SDI image\n", image );
00068                 return -ENOEXEC;
00069         }
00070 
00071         return 0;
00072 }
00073 
00074 /**
00075  * Execute SDI image
00076  *
00077  * @v image             SDI file
00078  * @ret rc              Return status code
00079  */
00080 static int sdi_exec ( struct image *image ) {
00081         struct sdi_header sdi;
00082         uint32_t sdiptr;
00083         int rc;
00084 
00085         /* Parse image header */
00086         if ( ( rc = sdi_parse_header ( image, &sdi ) ) != 0 )
00087                 return rc;
00088 
00089         /* Check that image is bootable */
00090         if ( sdi.boot_size == 0 ) {
00091                 DBGC ( image, "SDI %p is not bootable\n", image );
00092                 return -ENOTTY;
00093         }
00094         DBGC ( image, "SDI %p image at %08lx+%08zx\n",
00095                image, user_to_phys ( image->data, 0 ), image->len );
00096         DBGC ( image, "SDI %p boot code at %08lx+%llx\n", image,
00097                user_to_phys ( image->data, sdi.boot_offset ), sdi.boot_size );
00098 
00099         /* Copy boot code */
00100         memcpy_user ( real_to_user ( SDI_BOOT_SEG, SDI_BOOT_OFF ), 0,
00101                       image->data, sdi.boot_offset, sdi.boot_size );
00102 
00103         /* Jump to boot code */
00104         sdiptr = ( user_to_phys ( image->data, 0 ) | SDI_WTF );
00105         __asm__ __volatile__ ( REAL_CODE ( "ljmp %0, %1\n\t" )
00106                                : : "i" ( SDI_BOOT_SEG ),
00107                                    "i" ( SDI_BOOT_OFF ),
00108                                    "d" ( sdiptr ) );
00109 
00110         /* There is no way for the image to return, since we provide
00111          * no return address.
00112          */
00113         assert ( 0 );
00114 
00115         return -ECANCELED; /* -EIMPOSSIBLE */
00116 }
00117 
00118 /**
00119  * Probe SDI image
00120  *
00121  * @v image             SDI file
00122  * @ret rc              Return status code
00123  */
00124 static int sdi_probe ( struct image *image ) {
00125         struct sdi_header sdi;
00126         int rc;
00127 
00128         /* Parse image */
00129         if ( ( rc = sdi_parse_header ( image, &sdi ) ) != 0 )
00130                 return rc;
00131 
00132         return 0;
00133 }
00134 
00135 /** SDI image type */
00136 struct image_type sdi_image_type __image_type ( PROBE_NORMAL ) = {
00137         .name = "SDI",
00138         .probe = sdi_probe,
00139         .exec = sdi_exec,
00140 };