]> code.delx.au - refind/blob - net/discovery/efi_discovery_prefix.c
Worked around bug/quirk in some EFIs that prevented filesystem drivers
[refind] / net / discovery / efi_discovery_prefix.c
1 /*
2 * Copyright (C) 2009 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 <stdlib.h>
23 #include <ipxe/efi/efi_driver.h>
24 #include <ipxe/efi/efi_snp.h>
25 #include <ipxe/efi/efi_strings.h>
26 #include <ipxe/umalloc.h>
27 #include <ipxe/uri.h>
28 #include <ipxe/init.h>
29 #include <usr/ifmgmt.h>
30 #include <usr/route.h>
31 #include <usr/autoboot.h>
32
33 #define MAX_EXIT_BUFFER_SIZE 256
34
35 /**
36 * Close all open net devices
37 *
38 * Called before a fresh boot attempt in order to free up memory. We
39 * don't just close the device immediately after the boot fails,
40 * because there may still be TCP connections in the process of
41 * closing.
42 */
43 static void close_all_netdevs ( void ) {
44 struct net_device *netdev;
45
46 for_each_netdev ( netdev ) {
47 ifclose ( netdev );
48 }
49 }
50
51 static struct uri* try_getting_next_server ( struct net_device *netdev ) {
52 struct uri *filename;
53
54 /* Close all other network devices */
55 close_all_netdevs();
56
57 /* Open device and display device status */
58 if ( ifopen ( netdev ) != 0 )
59 goto err_ifopen;
60 ifstat ( netdev );
61
62 /* Configure device */
63 if (ifconf ( netdev, NULL )!= 0 )
64 goto err_dhcp;
65 route();
66
67 /* Fetch next server and filename */
68 filename = fetch_next_server_and_filename ( NULL );
69 if ( ! filename )
70 goto err_filename;
71 if ( ! uri_has_path ( filename ) ) {
72 /* Ignore empty filename */
73 uri_put ( filename );
74 filename = NULL;
75 }
76
77 return filename;
78 err_filename:
79 err_dhcp:
80 err_ifopen:
81 return NULL;
82 }
83
84
85 static struct uri* efi_discover ( void ) {
86 struct net_device *netdev;
87
88 struct uri* filename = NULL;
89
90 for_each_netdev ( netdev ) {
91 filename = try_getting_next_server ( netdev );
92 }
93
94 return filename;
95 }
96
97 /**
98 * EFI entry point
99 *
100 * @v image_handle Image handle
101 * @v systab System table
102 * @ret efirc EFI return status code
103 */
104 EFI_STATUS EFIAPI _efi_discovery_start ( EFI_HANDLE image_handle,
105 EFI_SYSTEM_TABLE *systab ) {
106 EFI_STATUS efirc;
107 struct uri* filename;
108 userptr_t user_buf;
109 wchar_t* exit_buf;
110
111 /* Initialise EFI environment */
112 if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 )
113 goto err_init;
114
115 if ( ( user_buf = umalloc(MAX_EXIT_BUFFER_SIZE*2) ) == 0)
116 {
117 efirc = EFI_OUT_OF_RESOURCES;
118 goto err_init;
119 }
120
121 exit_buf = (wchar_t *)user_to_phys(user_buf,0);
122
123 initialise();
124 startup();
125
126 if ( ( filename = efi_discover() ) == NULL)
127 {
128 efirc = EFI_NOT_FOUND;
129 goto err_filename;
130 }
131
132 efi_snp_release();
133 efi_loaded_image->Unload ( image_handle );
134 efi_driver_reconnect_all();
135
136 efi_snprintf(exit_buf,MAX_EXIT_BUFFER_SIZE,"%s - %s", filename->host, filename->path);
137 uri_put(filename);
138
139 systab->BootServices->Exit(image_handle, efirc, MAX_EXIT_BUFFER_SIZE, (CHAR16 *) exit_buf);
140
141 err_filename:
142 err_init:
143 systab->BootServices->Exit(image_handle, efirc, 0, NULL);
144 return efirc;
145 }
146
147 /**
148 * Probe EFI root bus
149 *
150 * @v rootdev EFI root device
151 */
152 static int efi_probe ( struct root_device *rootdev __unused ) {
153
154 return efi_driver_connect_all();
155 }
156
157 /**
158 * Remove EFI root bus
159 *
160 * @v rootdev EFI root device
161 */
162 static void efi_remove ( struct root_device *rootdev __unused ) {
163
164 efi_driver_disconnect_all();
165 }
166
167 /** EFI root device driver */
168 static struct root_driver efi_root_driver = {
169 .probe = efi_probe,
170 .remove = efi_remove,
171 };
172
173 /** EFI root device */
174 struct root_device efi_root_device __root_device = {
175 .dev = { .name = "EFI" },
176 .driver = &efi_root_driver,
177 };