|  | @@ -0,0 +1,136 @@
 | 
		
	
		
			
			|  | 1 | +/*
 | 
		
	
		
			
			|  | 2 | + * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
 | 
		
	
		
			
			|  | 3 | + *
 | 
		
	
		
			
			|  | 4 | + * This program is free software; you can redistribute it and/or
 | 
		
	
		
			
			|  | 5 | + * modify it under the terms of the GNU General Public License as
 | 
		
	
		
			
			|  | 6 | + * published by the Free Software Foundation; either version 2 of the
 | 
		
	
		
			
			|  | 7 | + * License, or (at your option) any later version.
 | 
		
	
		
			
			|  | 8 | + *
 | 
		
	
		
			
			|  | 9 | + * This program is distributed in the hope that it will be useful, but
 | 
		
	
		
			
			|  | 10 | + * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
		
	
		
			
			|  | 11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
		
	
		
			
			|  | 12 | + * General Public License for more details.
 | 
		
	
		
			
			|  | 13 | + *
 | 
		
	
		
			
			|  | 14 | + * You should have received a copy of the GNU General Public License
 | 
		
	
		
			
			|  | 15 | + * along with this program; if not, write to the Free Software
 | 
		
	
		
			
			|  | 16 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
		
	
		
			
			|  | 17 | + * 02110-1301, USA.
 | 
		
	
		
			
			|  | 18 | + */
 | 
		
	
		
			
			|  | 19 | +
 | 
		
	
		
			
			|  | 20 | +FILE_LICENCE ( GPL2_OR_LATER );
 | 
		
	
		
			
			|  | 21 | +
 | 
		
	
		
			
			|  | 22 | +#include <stdint.h>
 | 
		
	
		
			
			|  | 23 | +#include <string.h>
 | 
		
	
		
			
			|  | 24 | +#include <errno.h>
 | 
		
	
		
			
			|  | 25 | +#include <realmode.h>
 | 
		
	
		
			
			|  | 26 | +#include <sdi.h>
 | 
		
	
		
			
			|  | 27 | +#include <ipxe/image.h>
 | 
		
	
		
			
			|  | 28 | +#include <ipxe/features.h>
 | 
		
	
		
			
			|  | 29 | +
 | 
		
	
		
			
			|  | 30 | +/** @file
 | 
		
	
		
			
			|  | 31 | + *
 | 
		
	
		
			
			|  | 32 | + * System Deployment Image (SDI)
 | 
		
	
		
			
			|  | 33 | + *
 | 
		
	
		
			
			|  | 34 | + * Based on the MSDN article "RAM boot using SDI in Windows XP
 | 
		
	
		
			
			|  | 35 | + * Embedded with Service Pack 1", available at the time of writing
 | 
		
	
		
			
			|  | 36 | + * from:
 | 
		
	
		
			
			|  | 37 | + *
 | 
		
	
		
			
			|  | 38 | + *   http://msdn.microsoft.com/en-us/library/ms838543.aspx
 | 
		
	
		
			
			|  | 39 | + */
 | 
		
	
		
			
			|  | 40 | +
 | 
		
	
		
			
			|  | 41 | +FEATURE ( FEATURE_IMAGE, "SDI", DHCP_EB_FEATURE_SDI, 1 );
 | 
		
	
		
			
			|  | 42 | +
 | 
		
	
		
			
			|  | 43 | +/**
 | 
		
	
		
			
			|  | 44 | + * Parse SDI image header
 | 
		
	
		
			
			|  | 45 | + *
 | 
		
	
		
			
			|  | 46 | + * @v image		SDI file
 | 
		
	
		
			
			|  | 47 | + * @v sdi		SDI header to fill in
 | 
		
	
		
			
			|  | 48 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 49 | + */
 | 
		
	
		
			
			|  | 50 | +static int sdi_parse_header ( struct image *image, struct sdi_header *sdi ) {
 | 
		
	
		
			
			|  | 51 | +
 | 
		
	
		
			
			|  | 52 | +	/* Sanity check */
 | 
		
	
		
			
			|  | 53 | +	if ( image->len < sizeof ( *sdi ) ) {
 | 
		
	
		
			
			|  | 54 | +		DBGC ( image, "SDI %p too short for SDI header\n", image );
 | 
		
	
		
			
			|  | 55 | +		return -ENOEXEC;
 | 
		
	
		
			
			|  | 56 | +	}
 | 
		
	
		
			
			|  | 57 | +
 | 
		
	
		
			
			|  | 58 | +	/* Read in header */
 | 
		
	
		
			
			|  | 59 | +	copy_from_user ( sdi, image->data, 0, sizeof ( *sdi ) );
 | 
		
	
		
			
			|  | 60 | +
 | 
		
	
		
			
			|  | 61 | +	/* Check signature */
 | 
		
	
		
			
			|  | 62 | +	if ( sdi->magic != SDI_MAGIC ) {
 | 
		
	
		
			
			|  | 63 | +		DBGC ( image, "SDI %p is not an SDI image\n", image );
 | 
		
	
		
			
			|  | 64 | +		return -ENOEXEC;
 | 
		
	
		
			
			|  | 65 | +	}
 | 
		
	
		
			
			|  | 66 | +
 | 
		
	
		
			
			|  | 67 | +	return 0;
 | 
		
	
		
			
			|  | 68 | +}
 | 
		
	
		
			
			|  | 69 | +
 | 
		
	
		
			
			|  | 70 | +/**
 | 
		
	
		
			
			|  | 71 | + * Execute SDI image
 | 
		
	
		
			
			|  | 72 | + *
 | 
		
	
		
			
			|  | 73 | + * @v image		SDI file
 | 
		
	
		
			
			|  | 74 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 75 | + */
 | 
		
	
		
			
			|  | 76 | +static int sdi_exec ( struct image *image ) {
 | 
		
	
		
			
			|  | 77 | +	struct sdi_header sdi;
 | 
		
	
		
			
			|  | 78 | +	uint32_t sdiptr;
 | 
		
	
		
			
			|  | 79 | +	int rc;
 | 
		
	
		
			
			|  | 80 | +
 | 
		
	
		
			
			|  | 81 | +	/* Parse image header */
 | 
		
	
		
			
			|  | 82 | +	if ( ( rc = sdi_parse_header ( image, &sdi ) ) != 0 )
 | 
		
	
		
			
			|  | 83 | +		return rc;
 | 
		
	
		
			
			|  | 84 | +
 | 
		
	
		
			
			|  | 85 | +	/* Check that image is bootable */
 | 
		
	
		
			
			|  | 86 | +	if ( sdi.boot_size == 0 ) {
 | 
		
	
		
			
			|  | 87 | +		DBGC ( image, "SDI %p is not bootable\n", image );
 | 
		
	
		
			
			|  | 88 | +		return -ENOTTY;
 | 
		
	
		
			
			|  | 89 | +	}
 | 
		
	
		
			
			|  | 90 | +	DBGC ( image, "SDI %p image at %08lx+%08zx\n",
 | 
		
	
		
			
			|  | 91 | +	       image, user_to_phys ( image->data, 0 ), image->len );
 | 
		
	
		
			
			|  | 92 | +	DBGC ( image, "SDI %p boot code at %08lx+%llx\n", image,
 | 
		
	
		
			
			|  | 93 | +	       user_to_phys ( image->data, sdi.boot_offset ), sdi.boot_size );
 | 
		
	
		
			
			|  | 94 | +
 | 
		
	
		
			
			|  | 95 | +	/* Copy boot code */
 | 
		
	
		
			
			|  | 96 | +	memcpy_user ( real_to_user ( SDI_BOOT_SEG, SDI_BOOT_OFF ), 0,
 | 
		
	
		
			
			|  | 97 | +		      image->data, sdi.boot_offset, sdi.boot_size );
 | 
		
	
		
			
			|  | 98 | +
 | 
		
	
		
			
			|  | 99 | +	/* Jump to boot code */
 | 
		
	
		
			
			|  | 100 | +	sdiptr = ( user_to_phys ( image->data, 0 ) | SDI_WTF );
 | 
		
	
		
			
			|  | 101 | +	__asm__ __volatile__ ( REAL_CODE ( "ljmp %0, %1\n\t" )
 | 
		
	
		
			
			|  | 102 | +			       : : "i" ( SDI_BOOT_SEG ),
 | 
		
	
		
			
			|  | 103 | +				   "i" ( SDI_BOOT_OFF ),
 | 
		
	
		
			
			|  | 104 | +				   "d" ( sdiptr ) );
 | 
		
	
		
			
			|  | 105 | +
 | 
		
	
		
			
			|  | 106 | +	/* There is no way for the image to return, since we provide
 | 
		
	
		
			
			|  | 107 | +	 * no return address.
 | 
		
	
		
			
			|  | 108 | +	 */
 | 
		
	
		
			
			|  | 109 | +	assert ( 0 );
 | 
		
	
		
			
			|  | 110 | +
 | 
		
	
		
			
			|  | 111 | +	return -ECANCELED; /* -EIMPOSSIBLE */
 | 
		
	
		
			
			|  | 112 | +}
 | 
		
	
		
			
			|  | 113 | +
 | 
		
	
		
			
			|  | 114 | +/**
 | 
		
	
		
			
			|  | 115 | + * Probe SDI image
 | 
		
	
		
			
			|  | 116 | + *
 | 
		
	
		
			
			|  | 117 | + * @v image		SDI file
 | 
		
	
		
			
			|  | 118 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 119 | + */
 | 
		
	
		
			
			|  | 120 | +static int sdi_probe ( struct image *image ) {
 | 
		
	
		
			
			|  | 121 | +	struct sdi_header sdi;
 | 
		
	
		
			
			|  | 122 | +	int rc;
 | 
		
	
		
			
			|  | 123 | +
 | 
		
	
		
			
			|  | 124 | +	/* Parse image */
 | 
		
	
		
			
			|  | 125 | +	if ( ( rc = sdi_parse_header ( image, &sdi ) ) != 0 )
 | 
		
	
		
			
			|  | 126 | +		return rc;
 | 
		
	
		
			
			|  | 127 | +
 | 
		
	
		
			
			|  | 128 | +	return 0;
 | 
		
	
		
			
			|  | 129 | +}
 | 
		
	
		
			
			|  | 130 | +
 | 
		
	
		
			
			|  | 131 | +/** SDI image type */
 | 
		
	
		
			
			|  | 132 | +struct image_type sdi_image_type __image_type ( PROBE_NORMAL ) = {
 | 
		
	
		
			
			|  | 133 | +	.name = "SDI",
 | 
		
	
		
			
			|  | 134 | +	.probe = sdi_probe,
 | 
		
	
		
			
			|  | 135 | +	.exec = sdi_exec,
 | 
		
	
		
			
			|  | 136 | +};
 |