~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/ipxe/src/image/efi_image.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2008 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 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 <errno.h>
 
23
#include <stdlib.h>
 
24
#include <wchar.h>
 
25
#include <ipxe/efi/efi.h>
 
26
#include <ipxe/efi/efi_snp.h>
 
27
#include <ipxe/efi/efi_download.h>
 
28
#include <ipxe/efi/efi_file.h>
 
29
#include <ipxe/efi/efi_utils.h>
 
30
#include <ipxe/efi/efi_strings.h>
 
31
#include <ipxe/efi/efi_wrap.h>
 
32
#include <ipxe/efi/efi_pxe.h>
 
33
#include <ipxe/image.h>
 
34
#include <ipxe/init.h>
 
35
#include <ipxe/features.h>
 
36
#include <ipxe/uri.h>
 
37
#include <ipxe/console.h>
 
38
 
 
39
FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
 
40
 
 
41
/* Disambiguate the various error causes */
 
42
#define EINFO_EEFI_LOAD                                                 \
 
43
        __einfo_uniqify ( EINFO_EPLATFORM, 0x01,                        \
 
44
                          "Could not load image" )
 
45
#define EINFO_EEFI_LOAD_PROHIBITED                                      \
 
46
        __einfo_platformify ( EINFO_EEFI_LOAD, EFI_SECURITY_VIOLATION,  \
 
47
                              "Image prohibited by security policy" )
 
48
#define EEFI_LOAD_PROHIBITED                                            \
 
49
        __einfo_error ( EINFO_EEFI_LOAD_PROHIBITED )
 
50
#define EEFI_LOAD( efirc ) EPLATFORM ( EINFO_EEFI_LOAD, efirc,          \
 
51
                                       EEFI_LOAD_PROHIBITED )
 
52
#define EINFO_EEFI_START                                                \
 
53
        __einfo_uniqify ( EINFO_EPLATFORM, 0x02,                        \
 
54
                          "Could not start image" )
 
55
#define EEFI_START( efirc ) EPLATFORM ( EINFO_EEFI_START, efirc )
 
56
 
 
57
/**
 
58
 * Create device path for image
 
59
 *
 
60
 * @v image             EFI image
 
61
 * @v parent            Parent device path
 
62
 * @ret path            Device path, or NULL on failure
 
63
 *
 
64
 * The caller must eventually free() the device path.
 
65
 */
 
66
static EFI_DEVICE_PATH_PROTOCOL *
 
67
efi_image_path ( struct image *image, EFI_DEVICE_PATH_PROTOCOL *parent ) {
 
68
        EFI_DEVICE_PATH_PROTOCOL *path;
 
69
        FILEPATH_DEVICE_PATH *filepath;
 
70
        EFI_DEVICE_PATH_PROTOCOL *end;
 
71
        size_t name_len;
 
72
        size_t prefix_len;
 
73
        size_t filepath_len;
 
74
        size_t len;
 
75
 
 
76
        /* Calculate device path lengths */
 
77
        prefix_len = efi_devpath_len ( parent );
 
78
        name_len = strlen ( image->name );
 
79
        filepath_len = ( SIZE_OF_FILEPATH_DEVICE_PATH +
 
80
                         ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
 
81
        len = ( prefix_len + filepath_len + sizeof ( *end ) );
 
82
 
 
83
        /* Allocate device path */
 
84
        path = zalloc ( len );
 
85
        if ( ! path )
 
86
                return NULL;
 
87
 
 
88
        /* Construct device path */
 
89
        memcpy ( path, parent, prefix_len );
 
90
        filepath = ( ( ( void * ) path ) + prefix_len );
 
91
        filepath->Header.Type = MEDIA_DEVICE_PATH;
 
92
        filepath->Header.SubType = MEDIA_FILEPATH_DP;
 
93
        filepath->Header.Length[0] = ( filepath_len & 0xff );
 
94
        filepath->Header.Length[1] = ( filepath_len >> 8 );
 
95
        efi_snprintf ( filepath->PathName, ( name_len + 1 /* NUL */ ),
 
96
                       "%s", image->name );
 
97
        end = ( ( ( void * ) filepath ) + filepath_len );
 
98
        end->Type = END_DEVICE_PATH_TYPE;
 
99
        end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
 
100
        end->Length[0] = sizeof ( *end );
 
101
 
 
102
        return path;
 
103
}
 
104
 
 
105
/**
 
106
 * Create command line for image
 
107
 *
 
108
 * @v image             EFI image
 
109
 * @ret cmdline         Command line, or NULL on failure
 
110
 */
 
111
static wchar_t * efi_image_cmdline ( struct image *image ) {
 
112
        wchar_t *cmdline;
 
113
        size_t len;
 
114
 
 
115
        len = ( strlen ( image->name ) +
 
116
                ( image->cmdline ?
 
117
                  ( 1 /* " " */ + strlen ( image->cmdline ) ) : 0 ) );
 
118
        cmdline = zalloc ( ( len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
 
119
        if ( ! cmdline )
 
120
                return NULL;
 
121
        efi_snprintf ( cmdline, ( len + 1 /* NUL */ ), "%s%s%s",
 
122
                       image->name,
 
123
                       ( image->cmdline ? " " : "" ),
 
124
                       ( image->cmdline ? image->cmdline : "" ) );
 
125
        return cmdline;
 
126
}
 
127
 
 
128
/**
 
129
 * Execute EFI image
 
130
 *
 
131
 * @v image             EFI image
 
132
 * @ret rc              Return status code
 
133
 */
 
134
static int efi_image_exec ( struct image *image ) {
 
135
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 
136
        struct efi_snp_device *snpdev;
 
137
        EFI_DEVICE_PATH_PROTOCOL *path;
 
138
        union {
 
139
                EFI_LOADED_IMAGE_PROTOCOL *image;
 
140
                void *interface;
 
141
        } loaded;
 
142
        EFI_HANDLE handle;
 
143
        wchar_t *cmdline;
 
144
        EFI_STATUS efirc;
 
145
        int rc;
 
146
 
 
147
        /* Find an appropriate device handle to use */
 
148
        snpdev = last_opened_snpdev();
 
149
        if ( ! snpdev ) {
 
150
                DBGC ( image, "EFIIMAGE %p could not identify SNP device\n",
 
151
                       image );
 
152
                rc = -ENODEV;
 
153
                goto err_no_snpdev;
 
154
        }
 
155
 
 
156
        /* Install file I/O protocols */
 
157
        if ( ( rc = efi_file_install ( snpdev->handle ) ) != 0 ) {
 
158
                DBGC ( image, "EFIIMAGE %p could not install file protocol: "
 
159
                       "%s\n", image, strerror ( rc ) );
 
160
                goto err_file_install;
 
161
        }
 
162
 
 
163
        /* Install PXE base code protocol */
 
164
        if ( ( rc = efi_pxe_install ( snpdev->handle, snpdev->netdev ) ) != 0 ){
 
165
                DBGC ( image, "EFIIMAGE %p could not install PXE protocol: "
 
166
                       "%s\n", image, strerror ( rc ) );
 
167
                goto err_pxe_install;
 
168
        }
 
169
 
 
170
        /* Install iPXE download protocol */
 
171
        if ( ( rc = efi_download_install ( snpdev->handle ) ) != 0 ) {
 
172
                DBGC ( image, "EFIIMAGE %p could not install iPXE download "
 
173
                       "protocol: %s\n", image, strerror ( rc ) );
 
174
                goto err_download_install;
 
175
        }
 
176
 
 
177
        /* Create device path for image */
 
178
        path = efi_image_path ( image, snpdev->path );
 
179
        if ( ! path ) {
 
180
                DBGC ( image, "EFIIMAGE %p could not create device path\n",
 
181
                       image );
 
182
                rc = -ENOMEM;
 
183
                goto err_image_path;
 
184
        }
 
185
 
 
186
        /* Create command line for image */
 
187
        cmdline = efi_image_cmdline ( image );
 
188
        if ( ! cmdline ) {
 
189
                DBGC ( image, "EFIIMAGE %p could not create command line\n",
 
190
                       image );
 
191
                rc = -ENOMEM;
 
192
                goto err_cmdline;
 
193
        }
 
194
 
 
195
        /* Attempt loading image */
 
196
        if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path,
 
197
                                       user_to_virt ( image->data, 0 ),
 
198
                                       image->len, &handle ) ) != 0 ) {
 
199
                /* Not an EFI image */
 
200
                rc = -EEFI_LOAD ( efirc );
 
201
                DBGC ( image, "EFIIMAGE %p could not load: %s\n",
 
202
                       image, strerror ( rc ) );
 
203
                goto err_load_image;
 
204
        }
 
205
 
 
206
        /* Get the loaded image protocol for the newly loaded image */
 
207
        efirc = bs->OpenProtocol ( handle, &efi_loaded_image_protocol_guid,
 
208
                                   &loaded.interface, efi_image_handle,
 
209
                                   NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL );
 
210
        if ( efirc ) {
 
211
                /* Should never happen */
 
212
                rc = -EEFI ( efirc );
 
213
                goto err_open_protocol;
 
214
        }
 
215
 
 
216
        /* Some EFI 1.10 implementations seem not to fill in DeviceHandle */
 
217
        if ( loaded.image->DeviceHandle == NULL ) {
 
218
                DBGC ( image, "EFIIMAGE %p filling in missing DeviceHandle\n",
 
219
                       image );
 
220
                loaded.image->DeviceHandle = snpdev->handle;
 
221
        }
 
222
 
 
223
        /* Sanity checks */
 
224
        assert ( loaded.image->ParentHandle == efi_image_handle );
 
225
        assert ( loaded.image->DeviceHandle == snpdev->handle );
 
226
        assert ( loaded.image->LoadOptionsSize == 0 );
 
227
        assert ( loaded.image->LoadOptions == NULL );
 
228
 
 
229
        /* Set command line */
 
230
        loaded.image->LoadOptions = cmdline;
 
231
        loaded.image->LoadOptionsSize =
 
232
                ( ( wcslen ( cmdline ) + 1 /* NUL */ ) * sizeof ( wchar_t ) );
 
233
 
 
234
        /* Release network devices for use via SNP */
 
235
        efi_snp_release();
 
236
 
 
237
        /* Wrap calls made by the loaded image (for debugging) */
 
238
        efi_wrap ( handle );
 
239
 
 
240
        /* Reset console since image will probably use it */
 
241
        console_reset();
 
242
 
 
243
        /* Start the image */
 
244
        if ( ( efirc = bs->StartImage ( handle, NULL, NULL ) ) != 0 ) {
 
245
                rc = -EEFI_START ( efirc );
 
246
                DBGC ( image, "EFIIMAGE %p could not start (or returned with "
 
247
                       "error): %s\n", image, strerror ( rc ) );
 
248
                goto err_start_image;
 
249
        }
 
250
 
 
251
        /* Success */
 
252
        rc = 0;
 
253
 
 
254
 err_start_image:
 
255
        efi_snp_claim();
 
256
 err_open_protocol:
 
257
        /* If there was no error, then the image must have been
 
258
         * started and returned successfully.  It either unloaded
 
259
         * itself, or it intended to remain loaded (e.g. it was a
 
260
         * driver).  We therefore do not unload successful images.
 
261
         *
 
262
         * If there was an error, attempt to unload the image.  This
 
263
         * may not work.  In particular, there is no way to tell
 
264
         * whether an error returned from StartImage() was due to
 
265
         * being unable to start the image (in which case we probably
 
266
         * should call UnloadImage()), or due to the image itself
 
267
         * returning an error (in which case we probably should not
 
268
         * call UnloadImage()).  We therefore ignore any failures from
 
269
         * the UnloadImage() call itself.
 
270
         */
 
271
        if ( rc != 0 )
 
272
                bs->UnloadImage ( handle );
 
273
 err_load_image:
 
274
        free ( cmdline );
 
275
 err_cmdline:
 
276
        free ( path );
 
277
 err_image_path:
 
278
        efi_download_uninstall ( snpdev->handle );
 
279
 err_download_install:
 
280
        efi_pxe_uninstall ( snpdev->handle );
 
281
 err_pxe_install:
 
282
        efi_file_uninstall ( snpdev->handle );
 
283
 err_file_install:
 
284
 err_no_snpdev:
 
285
        return rc;
 
286
}
 
287
 
 
288
/**
 
289
 * Probe EFI image
 
290
 *
 
291
 * @v image             EFI file
 
292
 * @ret rc              Return status code
 
293
 */
 
294
static int efi_image_probe ( struct image *image ) {
 
295
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 
296
        static EFI_DEVICE_PATH_PROTOCOL empty_path = {
 
297
                .Type = END_DEVICE_PATH_TYPE,
 
298
                .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE,
 
299
                .Length[0] = sizeof ( empty_path ),
 
300
        };
 
301
        EFI_HANDLE handle;
 
302
        EFI_STATUS efirc;
 
303
        int rc;
 
304
 
 
305
        /* Attempt loading image */
 
306
        if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, &empty_path,
 
307
                                       user_to_virt ( image->data, 0 ),
 
308
                                       image->len, &handle ) ) != 0 ) {
 
309
                /* Not an EFI image */
 
310
                rc = -EEFI_LOAD ( efirc );
 
311
                DBGC ( image, "EFIIMAGE %p could not load: %s\n",
 
312
                       image, strerror ( rc ) );
 
313
                return rc;
 
314
        }
 
315
 
 
316
        /* Unload the image.  We can't leave it loaded, because we
 
317
         * have no "unload" operation.
 
318
         */
 
319
        bs->UnloadImage ( handle );
 
320
 
 
321
        return 0;
 
322
}
 
323
 
 
324
/** EFI image type */
 
325
struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
 
326
        .name = "EFI",
 
327
        .probe = efi_image_probe,
 
328
        .exec = efi_image_exec,
 
329
};