[librm] Use libflat to enable A20 line on each real-to-protected transition
[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 FILE_LICENCE ( GPL2_OR_LATER );
20
21 #include <errno.h>
22 #include <gpxe/efi/efi.h>
23 #include <gpxe/image.h>
24 #include <gpxe/init.h>
25 #include <gpxe/features.h>
26
27 FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
28
29 struct image_type efi_image_type __image_type ( PROBE_NORMAL );
30
31 /** Event used to signal shutdown */
32 static EFI_EVENT efi_shutdown_event;
33
34 /**
35  * Shut down in preparation for booting an OS.
36  *
37  * This hook gets called at ExitBootServices time in order to make sure that
38  * the network cards are properly shut down before the OS takes over.
39  */
40 static EFIAPI void efi_shutdown_hook ( EFI_EVENT event __unused,
41                                        void *context __unused ) {
42         shutdown ( SHUTDOWN_BOOT );
43 }
44
45 /**
46  * Execute EFI image
47  *
48  * @v image             EFI image
49  * @ret rc              Return status code
50  */
51 static int efi_image_exec ( struct image *image ) {
52         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
53         EFI_HANDLE handle;
54         UINTN exit_data_size;
55         CHAR16 *exit_data;
56         EFI_STATUS efirc;
57         int rc;
58
59         /* Attempt loading image */
60         if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
61                                        user_to_virt ( image->data, 0 ),
62                                        image->len, &handle ) ) != 0 ) {
63                 /* Not an EFI image */
64                 DBGC ( image, "EFIIMAGE %p could not load: %s\n",
65                        image, efi_strerror ( efirc ) );
66                 return -ENOEXEC;
67         }
68
69         /* Be sure to shut down the NIC at ExitBootServices time, or else
70          * DMA from the card can corrupt the OS.
71          */
72         efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES,
73                                   TPL_CALLBACK, efi_shutdown_hook,
74                                   NULL, &efi_shutdown_event );
75         if ( efirc ) {
76                 rc = EFIRC_TO_RC ( efirc );
77                 goto done;
78         }
79
80         /* Start the image */
81         if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
82                                         &exit_data ) ) != 0 ) {
83                 DBGC ( image, "EFIIMAGE %p returned with status %s\n",
84                        image, efi_strerror ( efirc ) );
85         }
86
87         rc = EFIRC_TO_RC ( efirc );
88
89         /* Remove the shutdown hook */
90         bs->CloseEvent ( efi_shutdown_event );
91
92 done:
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 rc;
99 }
100
101 /**
102  * Load EFI image into memory
103  *
104  * @v image             EFI file
105  * @ret rc              Return status code
106  */
107 static int efi_image_load ( struct image *image ) {
108         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
109         EFI_HANDLE handle;
110         EFI_STATUS efirc;
111
112         /* Attempt loading image */
113         if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
114                                        user_to_virt ( image->data, 0 ),
115                                        image->len, &handle ) ) != 0 ) {
116                 /* Not an EFI image */
117                 DBGC ( image, "EFIIMAGE %p could not load: %s\n",
118                        image, efi_strerror ( efirc ) );
119                 return -ENOEXEC;
120         }
121
122         /* This is an EFI image */
123         if ( ! image->type )
124                 image->type = &efi_image_type;
125
126         /* Unload the image.  We can't leave it loaded, because we
127          * have no "unload" operation.
128          */
129         bs->UnloadImage ( handle );
130
131         return 0;
132 }
133
134 /** EFI image type */
135 struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
136         .name = "EFI",
137         .load = efi_image_load,
138         .exec = efi_image_exec,
139 };