Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / image / sdi.c
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 };