2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
23 * EFI boot manager invocation
34 #include "efi/Protocol/GraphicsOutput.h"
38 /** Original OpenProtocol() method */
39 static EFI_OPEN_PROTOCOL orig_open_protocol
;
42 * Intercept OpenProtocol()
44 * @v handle EFI handle
45 * @v protocol Protocol GUID
46 * @v interface Opened interface
47 * @v agent_handle Agent handle
48 * @v controller_handle Controller handle
49 * @v attributes Attributes
50 * @ret efirc EFI status code
52 static EFI_STATUS EFIAPI
53 efi_open_protocol_wrapper ( EFI_HANDLE handle
, EFI_GUID
*protocol
,
54 VOID
**interface
, EFI_HANDLE agent_handle
,
55 EFI_HANDLE controller_handle
, UINT32 attributes
) {
56 static unsigned int count
;
59 /* Open the protocol */
60 if ( ( efirc
= orig_open_protocol ( handle
, protocol
, interface
,
61 agent_handle
, controller_handle
,
62 attributes
) ) != 0 ) {
66 /* Block first attempt by bootmgfw.efi to open
67 * EFI_GRAPHICS_OUTPUT_PROTOCOL. This forces error messages
68 * to be displayed in text mode (thereby avoiding the totally
69 * blank error screen if the fonts are missing). We must
70 * allow subsequent attempts to succeed, otherwise the OS will
73 if ( ( memcmp ( protocol
, &efi_graphics_output_protocol_guid
,
74 sizeof ( *protocol
) ) == 0 ) &&
75 ( count
++ == 0 ) && ( ! cmdline_gui
) ) {
76 DBG ( "Forcing text mode output\n" );
77 return EFI_INVALID_PARAMETER
;
84 * Boot from EFI device
86 * @v file Virtual file
88 * @v device Device handle
90 void efi_boot ( struct vdisk_file
*file
, EFI_DEVICE_PATH_PROTOCOL
*path
,
92 EFI_BOOT_SERVICES
*bs
= efi_systab
->BootServices
;
94 EFI_LOADED_IMAGE_PROTOCOL
*image
;
97 EFI_PHYSICAL_ADDRESS phys
;
103 /* Allocate memory */
104 pages
= ( ( file
->len
+ PAGE_SIZE
- 1 ) / PAGE_SIZE
);
105 if ( ( efirc
= bs
->AllocatePages ( AllocateAnyPages
,
106 EfiBootServicesData
, pages
,
108 die ( "Could not allocate %d pages: %#lx\n",
109 pages
, ( ( unsigned long ) efirc
) );
111 data
= ( ( void * ) ( intptr_t ) phys
);
115 file
->read ( file
, data
, 0, file
->len
);
116 DBG ( "Read %s\n", file
->name
);
119 if ( ( efirc
= bs
->LoadImage ( FALSE
, efi_image_handle
, path
, data
,
120 file
->len
, &handle
) ) != 0 ) {
121 die ( "Could not load %s: %#lx\n",
122 file
->name
, ( ( unsigned long ) efirc
) );
124 DBG ( "Loaded %s\n", file
->name
);
126 /* Get loaded image protocol */
127 if ( ( efirc
= bs
->OpenProtocol ( handle
,
128 &efi_loaded_image_protocol_guid
,
129 &loaded
.intf
, efi_image_handle
, NULL
,
130 EFI_OPEN_PROTOCOL_GET_PROTOCOL
))!=0){
131 die ( "Could not get loaded image protocol for %s: %#lx\n",
132 file
->name
, ( ( unsigned long ) efirc
) );
135 /* Force correct device handle */
136 if ( loaded
.image
->DeviceHandle
!= device
) {
137 DBG ( "Forcing correct DeviceHandle (%p->%p)\n",
138 loaded
.image
->DeviceHandle
, device
);
139 loaded
.image
->DeviceHandle
= device
;
142 /* Intercept calls to OpenProtocol() */
144 loaded
.image
->SystemTable
->BootServices
->OpenProtocol
;
145 loaded
.image
->SystemTable
->BootServices
->OpenProtocol
=
146 efi_open_protocol_wrapper
;
151 if ( ( efirc
= bs
->StartImage ( handle
, NULL
, NULL
) ) != 0 ) {
152 die ( "Could not start %s: %#lx\n",
153 file
->name
, ( ( unsigned long ) efirc
) );
156 die ( "%s returned\n", file
->name
);