iPXE
pxe_image.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  * PXE image format
00030  *
00031  */
00032 
00033 #include <pxe.h>
00034 #include <pxe_call.h>
00035 #include <pic8259.h>
00036 #include <ipxe/uaccess.h>
00037 #include <ipxe/image.h>
00038 #include <ipxe/segment.h>
00039 #include <ipxe/netdevice.h>
00040 #include <ipxe/features.h>
00041 #include <ipxe/console.h>
00042 #include <ipxe/efi/efi.h>
00043 #include <ipxe/efi/IndustryStandard/PeImage.h>
00044 
00045 FEATURE ( FEATURE_IMAGE, "PXE", DHCP_EB_FEATURE_PXE, 1 );
00046 
00047 /** PXE command line */
00048 const char *pxe_cmdline;
00049 
00050 /**
00051  * Execute PXE image
00052  *
00053  * @v image             PXE image
00054  * @ret rc              Return status code
00055  */
00056 static int pxe_exec ( struct image *image ) {
00057         userptr_t buffer = real_to_user ( 0, 0x7c00 );
00058         struct net_device *netdev;
00059         int rc;
00060 
00061         /* Verify and prepare segment */
00062         if ( ( rc = prep_segment ( buffer, image->len, image->len ) ) != 0 ) {
00063                 DBGC ( image, "IMAGE %p could not prepare segment: %s\n",
00064                        image, strerror ( rc ) );
00065                 return rc;
00066         }
00067 
00068         /* Copy image to segment */
00069         memcpy_user ( buffer, 0, image->data, 0, image->len );
00070 
00071         /* Arbitrarily pick the most recently opened network device */
00072         if ( ( netdev = last_opened_netdev() ) == NULL ) {
00073                 DBGC ( image, "IMAGE %p could not locate PXE net device\n",
00074                        image );
00075                 return -ENODEV;
00076         }
00077         netdev_get ( netdev );
00078 
00079         /* Activate PXE */
00080         pxe_activate ( netdev );
00081 
00082         /* Construct fake DHCP packets */
00083         pxe_fake_cached_info();
00084 
00085         /* Set PXE command line */
00086         pxe_cmdline = image->cmdline;
00087 
00088         /* Reset console since PXE NBP will probably use it */
00089         console_reset();
00090 
00091         /* Disable IRQ, if applicable */
00092         if ( netdev_irq_supported ( netdev ) && netdev->dev->desc.irq )
00093                 disable_irq ( netdev->dev->desc.irq );
00094 
00095         /* Start PXE NBP */
00096         rc = pxe_start_nbp();
00097 
00098         /* Clear PXE command line */
00099         pxe_cmdline = NULL;
00100 
00101         /* Deactivate PXE */
00102         pxe_deactivate();
00103 
00104         /* Try to reopen network device.  Ignore errors, since the NBP
00105          * may have called PXENV_STOP_UNDI.
00106          */
00107         netdev_open ( netdev );
00108         netdev_put ( netdev );
00109 
00110         return rc;
00111 }
00112 
00113 /**
00114  * Probe PXE image
00115  *
00116  * @v image             PXE file
00117  * @ret rc              Return status code
00118  */
00119 int pxe_probe ( struct image *image ) {
00120 
00121         /* Images too large to fit in base memory cannot be PXE
00122          * images.  We include this check to help prevent unrecognised
00123          * images from being marked as PXE images, since PXE images
00124          * have no signature we can check against.
00125          */
00126         if ( image->len > ( 0xa0000 - 0x7c00 ) )
00127                 return -ENOEXEC;
00128 
00129         /* Rejecting zero-length images is also useful, since these
00130          * end up looking to the user like bugs in iPXE.
00131          */
00132         if ( ! image->len )
00133                 return -ENOEXEC;
00134 
00135         return 0;
00136 }
00137 
00138 /**
00139  * Probe PXE image (with rejection of potential EFI images)
00140  *
00141  * @v image             PXE file
00142  * @ret rc              Return status code
00143  */
00144 int pxe_probe_no_mz ( struct image *image ) {
00145         uint16_t magic;
00146         int rc;
00147 
00148         /* Probe PXE image */
00149         if ( ( rc = pxe_probe ( image ) ) != 0 )
00150                 return rc;
00151 
00152         /* Reject image with an "MZ" signature which may indicate an
00153          * EFI image incorrectly handed out to a BIOS system.
00154          */
00155         if ( image->len >= sizeof ( magic ) ) {
00156                 copy_from_user ( &magic, image->data, 0, sizeof ( magic ) );
00157                 if ( magic == cpu_to_le16 ( EFI_IMAGE_DOS_SIGNATURE ) ) {
00158                         DBGC ( image, "IMAGE %p may be an EFI image\n",
00159                                image );
00160                         return -ENOTTY;
00161                 }
00162         }
00163 
00164         return 0;
00165 }
00166 
00167 /** PXE image type */
00168 struct image_type pxe_image_type[] __image_type ( PROBE_PXE ) = {
00169         {
00170                 .name = "PXE-NBP",
00171                 .probe = pxe_probe_no_mz,
00172                 .exec = pxe_exec,
00173         },
00174         {
00175                 .name = "PXE-NBP (may be EFI?)",
00176                 .probe = pxe_probe,
00177                 .exec = pxe_exec,
00178         },
00179 };