[efi] Add EFI image format and basic runtime environment
[people/sha0/gpxe.git] / src / image / efi_image.c
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <errno.h>
20 #include <gpxe/efi/efi.h>
21 #include <gpxe/image.h>
22 #include <gpxe/features.h>
23
24 FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
25
26 struct image_type efi_image_type __image_type ( PROBE_NORMAL );
27
28 /**
29  * Execute EFI image
30  *
31  * @v image             EFI image
32  * @ret rc              Return status code
33  */
34 static int efi_image_exec ( struct image *image ) {
35         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
36         EFI_HANDLE handle;
37         UINTN exit_data_size;
38         CHAR16 *exit_data;
39         EFI_STATUS efirc;
40
41         /* Attempt loading image */
42         if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
43                                        user_to_virt ( image->data, 0 ),
44                                        image->len, &handle ) ) != 0 ) {
45                 /* Not an EFI image */
46                 DBGC ( image, "EFIIMAGE %p could not load: %lx\n",
47                        image, efirc );
48                 return -ENOEXEC;
49         }
50
51         /* Start the image */
52         if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
53                                         &exit_data ) ) != 0 ) {
54                 DBGC ( image, "EFIIMAGE %p returned with status %lx\n",
55                        image, efirc );
56                 goto done;
57         }
58
59  done:
60         /* Unload the image.  We can't leave it loaded, because we
61          * have no "unload" operation.
62          */
63         bs->UnloadImage ( handle );
64
65         return EFIRC_TO_RC ( efirc );
66 }
67
68 /**
69  * Load EFI image into memory
70  *
71  * @v image             EFI file
72  * @ret rc              Return status code
73  */
74 static int efi_image_load ( struct image *image ) {
75         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
76         EFI_HANDLE handle;
77         EFI_STATUS efirc;
78
79         /* Attempt loading image */
80         if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
81                                        user_to_virt ( image->data, 0 ),
82                                        image->len, &handle ) ) != 0 ) {
83                 /* Not an EFI image */
84                 DBGC ( image, "EFIIMAGE %p could not load: %lx\n",
85                        image, efirc );
86                 return -ENOEXEC;
87         }
88
89         /* This is an EFI image */
90         if ( ! image->type )
91                 image->type = &efi_image_type;
92
93         /* Unload the image.  We can't leave it loaded, because we
94          * have no "unload" operation.
95          */
96         bs->UnloadImage ( handle );
97
98         return 0;
99 }
100
101 /** EFI image type */
102 struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
103         .name = "EFI",
104         .load = efi_image_load,
105         .exec = efi_image_exec,
106 };