From e6427b7ee117ea4af0812bb13b57999bccd8e058 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 4 Sep 2012 01:26:48 +0100 Subject: [PATCH] [sdi] Add support for SDI images Add support (disabled by default) for booting .sdi images as used by Windows XP Embedded. Signed-off-by: Michael Brown --- src/arch/i386/image/sdi.c | 136 ++++++++++++++++++++++++++++ src/arch/i386/include/sdi.h | 39 ++++++++ src/arch/x86/include/bits/errfile.h | 1 + src/config/config.c | 3 + src/config/general.h | 1 + src/include/ipxe/features.h | 1 + 6 files changed, 181 insertions(+) create mode 100644 src/arch/i386/image/sdi.c create mode 100644 src/arch/i386/include/sdi.h diff --git a/src/arch/i386/image/sdi.c b/src/arch/i386/image/sdi.c new file mode 100644 index 00000000..df1c3a86 --- /dev/null +++ b/src/arch/i386/image/sdi.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * System Deployment Image (SDI) + * + * Based on the MSDN article "RAM boot using SDI in Windows XP + * Embedded with Service Pack 1", available at the time of writing + * from: + * + * http://msdn.microsoft.com/en-us/library/ms838543.aspx + */ + +FEATURE ( FEATURE_IMAGE, "SDI", DHCP_EB_FEATURE_SDI, 1 ); + +/** + * Parse SDI image header + * + * @v image SDI file + * @v sdi SDI header to fill in + * @ret rc Return status code + */ +static int sdi_parse_header ( struct image *image, struct sdi_header *sdi ) { + + /* Sanity check */ + if ( image->len < sizeof ( *sdi ) ) { + DBGC ( image, "SDI %p too short for SDI header\n", image ); + return -ENOEXEC; + } + + /* Read in header */ + copy_from_user ( sdi, image->data, 0, sizeof ( *sdi ) ); + + /* Check signature */ + if ( sdi->magic != SDI_MAGIC ) { + DBGC ( image, "SDI %p is not an SDI image\n", image ); + return -ENOEXEC; + } + + return 0; +} + +/** + * Execute SDI image + * + * @v image SDI file + * @ret rc Return status code + */ +static int sdi_exec ( struct image *image ) { + struct sdi_header sdi; + uint32_t sdiptr; + int rc; + + /* Parse image header */ + if ( ( rc = sdi_parse_header ( image, &sdi ) ) != 0 ) + return rc; + + /* Check that image is bootable */ + if ( sdi.boot_size == 0 ) { + DBGC ( image, "SDI %p is not bootable\n", image ); + return -ENOTTY; + } + DBGC ( image, "SDI %p image at %08lx+%08zx\n", + image, user_to_phys ( image->data, 0 ), image->len ); + DBGC ( image, "SDI %p boot code at %08lx+%llx\n", image, + user_to_phys ( image->data, sdi.boot_offset ), sdi.boot_size ); + + /* Copy boot code */ + memcpy_user ( real_to_user ( SDI_BOOT_SEG, SDI_BOOT_OFF ), 0, + image->data, sdi.boot_offset, sdi.boot_size ); + + /* Jump to boot code */ + sdiptr = ( user_to_phys ( image->data, 0 ) | SDI_WTF ); + __asm__ __volatile__ ( REAL_CODE ( "ljmp %0, %1\n\t" ) + : : "i" ( SDI_BOOT_SEG ), + "i" ( SDI_BOOT_OFF ), + "d" ( sdiptr ) ); + + /* There is no way for the image to return, since we provide + * no return address. + */ + assert ( 0 ); + + return -ECANCELED; /* -EIMPOSSIBLE */ +} + +/** + * Probe SDI image + * + * @v image SDI file + * @ret rc Return status code + */ +static int sdi_probe ( struct image *image ) { + struct sdi_header sdi; + int rc; + + /* Parse image */ + if ( ( rc = sdi_parse_header ( image, &sdi ) ) != 0 ) + return rc; + + return 0; +} + +/** SDI image type */ +struct image_type sdi_image_type __image_type ( PROBE_NORMAL ) = { + .name = "SDI", + .probe = sdi_probe, + .exec = sdi_exec, +}; diff --git a/src/arch/i386/include/sdi.h b/src/arch/i386/include/sdi.h new file mode 100644 index 00000000..fc486402 --- /dev/null +++ b/src/arch/i386/include/sdi.h @@ -0,0 +1,39 @@ +#ifndef _SDI_H +#define _SDI_H + +/** @file + * + * System Deployment Image (SDI) + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** SDI image header */ +struct sdi_header { + /** Signature */ + uint32_t magic; + /** Version (as an ASCII string) */ + uint32_t version; + /** Reserved */ + uint8_t reserved[8]; + /** Boot code offset */ + uint64_t boot_offset; + /** Boot code size */ + uint64_t boot_size; +} __attribute__ (( packed )); + +/** SDI image signature */ +#define SDI_MAGIC \ + ( ( '$' << 0 ) | ( 'S' << 8 ) | ( 'D' << 16 ) | ( 'I' << 24 ) ) + +/** SDI boot segment */ +#define SDI_BOOT_SEG 0x0000 + +/** SDI boot offset */ +#define SDI_BOOT_OFF 0x7c00 + +/** Constant to binary-OR with physical address of SDI image */ +#define SDI_WTF 0x41 + +#endif /* _SDI_H */ diff --git a/src/arch/x86/include/bits/errfile.h b/src/arch/x86/include/bits/errfile.h index f66cbaa1..25e070e8 100644 --- a/src/arch/x86/include/bits/errfile.h +++ b/src/arch/x86/include/bits/errfile.h @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_com32 ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00080000 ) #define ERRFILE_comboot_resolv ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00090000 ) #define ERRFILE_comboot_call ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000a0000 ) +#define ERRFILE_sdi ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000b0000 ) #define ERRFILE_undi ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 ) #define ERRFILE_undiload ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 ) diff --git a/src/config/config.c b/src/config/config.c index 202da726..78ae93c4 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -181,6 +181,9 @@ REQUIRE_OBJECT ( comboot_resolv ); #ifdef IMAGE_EFI REQUIRE_OBJECT ( efi_image ); #endif +#ifdef IMAGE_SDI +REQUIRE_OBJECT ( sdi ); +#endif /* * Drag in all requested commands diff --git a/src/config/general.h b/src/config/general.h index 6fc39831..638320a4 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -100,6 +100,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define IMAGE_BZIMAGE /* Linux bzImage image support */ //#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */ //#define IMAGE_EFI /* EFI image support */ +//#define IMAGE_SDI /* SDI image support */ /* * Command-line commands to include diff --git a/src/include/ipxe/features.h b/src/include/ipxe/features.h index 498ec944..0c92f5be 100644 --- a/src/include/ipxe/features.h +++ b/src/include/ipxe/features.h @@ -53,6 +53,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define DHCP_EB_FEATURE_FCOE 0x25 /**< FCoE protocol */ #define DHCP_EB_FEATURE_VLAN 0x26 /**< VLAN support */ #define DHCP_EB_FEATURE_MENU 0x27 /**< Menu support */ +#define DHCP_EB_FEATURE_SDI 0x28 /**< SDI image support */ /** @} */