1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <efi_driver.h>
21
22
23
24
25
26
27
28static efi_status_t check_node_type(efi_handle_t handle)
29{
30 efi_status_t r, ret = EFI_SUCCESS;
31 const struct efi_device_path *dp;
32
33
34 r = EFI_CALL(systab.boottime->open_protocol(
35 handle, &efi_guid_device_path, (void **)&dp,
36 NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL));
37 if (r == EFI_SUCCESS && dp) {
38
39 const struct efi_device_path *node = efi_dp_last_node(dp);
40
41 if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE)
42 ret = EFI_UNSUPPORTED;
43 }
44 return ret;
45}
46
47
48
49
50
51
52
53
54
55static efi_status_t EFIAPI efi_uc_supported(
56 struct efi_driver_binding_protocol *this,
57 efi_handle_t controller_handle,
58 struct efi_device_path *remaining_device_path)
59{
60 efi_status_t r, ret;
61 void *interface;
62 struct efi_driver_binding_extended_protocol *bp =
63 (struct efi_driver_binding_extended_protocol *)this;
64
65 EFI_ENTRY("%p, %p, %ls", this, controller_handle,
66 efi_dp_str(remaining_device_path));
67
68 ret = EFI_CALL(systab.boottime->open_protocol(
69 controller_handle, bp->ops->protocol,
70 &interface, this->driver_binding_handle,
71 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
72 switch (ret) {
73 case EFI_ACCESS_DENIED:
74 case EFI_ALREADY_STARTED:
75 goto out;
76 case EFI_SUCCESS:
77 break;
78 default:
79 ret = EFI_UNSUPPORTED;
80 goto out;
81 }
82
83 ret = check_node_type(controller_handle);
84
85 r = EFI_CALL(systab.boottime->close_protocol(
86 controller_handle, bp->ops->protocol,
87 this->driver_binding_handle,
88 controller_handle));
89 if (r != EFI_SUCCESS)
90 ret = EFI_UNSUPPORTED;
91out:
92 return EFI_EXIT(ret);
93}
94
95
96
97
98
99
100
101
102
103static efi_status_t EFIAPI efi_uc_start(
104 struct efi_driver_binding_protocol *this,
105 efi_handle_t controller_handle,
106 struct efi_device_path *remaining_device_path)
107{
108 efi_status_t r, ret;
109 void *interface = NULL;
110 struct efi_driver_binding_extended_protocol *bp =
111 (struct efi_driver_binding_extended_protocol *)this;
112
113 EFI_ENTRY("%p, %pUl, %ls", this, controller_handle,
114 efi_dp_str(remaining_device_path));
115
116
117 ret = EFI_CALL(systab.boottime->open_protocol(
118 controller_handle, bp->ops->protocol,
119 &interface, this->driver_binding_handle,
120 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
121 switch (ret) {
122 case EFI_ACCESS_DENIED:
123 case EFI_ALREADY_STARTED:
124 goto out;
125 case EFI_SUCCESS:
126 break;
127 default:
128 ret = EFI_UNSUPPORTED;
129 goto out;
130 }
131 ret = check_node_type(controller_handle);
132 if (ret != EFI_SUCCESS) {
133 r = EFI_CALL(systab.boottime->close_protocol(
134 controller_handle, bp->ops->protocol,
135 this->driver_binding_handle,
136 controller_handle));
137 if (r != EFI_SUCCESS)
138 EFI_PRINT("Failure to close handle\n");
139 goto out;
140 }
141
142
143 bp->ops->bind(controller_handle, interface);
144
145out:
146 return EFI_EXIT(ret);
147}
148
149
150
151
152
153
154
155
156static efi_status_t disconnect_child(efi_handle_t controller_handle,
157 efi_handle_t child_handle)
158{
159 efi_status_t ret;
160 efi_guid_t *guid_controller = NULL;
161 efi_guid_t *guid_child_controller = NULL;
162
163 ret = EFI_CALL(systab.boottime->close_protocol(
164 controller_handle, guid_controller,
165 child_handle, child_handle));
166 if (ret != EFI_SUCCESS) {
167 EFI_PRINT("Cannot close protocol\n");
168 return ret;
169 }
170 ret = EFI_CALL(systab.boottime->uninstall_protocol_interface(
171 child_handle, guid_child_controller, NULL));
172 if (ret != EFI_SUCCESS) {
173 EFI_PRINT("Cannot uninstall protocol interface\n");
174 return ret;
175 }
176 return ret;
177}
178
179
180
181
182
183
184
185
186
187
188static efi_status_t EFIAPI efi_uc_stop(
189 struct efi_driver_binding_protocol *this,
190 efi_handle_t controller_handle,
191 size_t number_of_children,
192 efi_handle_t *child_handle_buffer)
193{
194 efi_status_t ret;
195 efi_uintn_t count;
196 struct efi_open_protocol_info_entry *entry_buffer;
197 efi_guid_t *guid_controller = NULL;
198
199 EFI_ENTRY("%p, %pUl, %zu, %p", this, controller_handle,
200 number_of_children, child_handle_buffer);
201
202
203 if (number_of_children) {
204 efi_uintn_t i;
205
206 for (i = 0; i < number_of_children; ++i) {
207 ret = disconnect_child(controller_handle,
208 child_handle_buffer[i]);
209 if (ret != EFI_SUCCESS)
210 return ret;
211 }
212 return EFI_SUCCESS;
213 }
214
215
216 ret = EFI_CALL(systab.boottime->open_protocol_information(
217 controller_handle, guid_controller,
218 &entry_buffer, &count));
219 if (ret != EFI_SUCCESS)
220 goto out;
221 while (count) {
222 if (entry_buffer[--count].attributes &
223 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
224 ret = disconnect_child(
225 controller_handle,
226 entry_buffer[count].agent_handle);
227 if (ret != EFI_SUCCESS)
228 goto out;
229 }
230 }
231 ret = EFI_CALL(systab.boottime->free_pool(entry_buffer));
232 if (ret != EFI_SUCCESS)
233 printf("%s(%u) %s: ERROR: Cannot free pool\n",
234 __FILE__, __LINE__, __func__);
235
236
237 ret = EFI_CALL(systab.boottime->close_protocol(
238 controller_handle, guid_controller,
239 this->driver_binding_handle, controller_handle));
240out:
241 return EFI_EXIT(ret);
242}
243
244static efi_status_t efi_add_driver(struct driver *drv)
245{
246 efi_status_t ret;
247 const struct efi_driver_ops *ops = drv->ops;
248 struct efi_driver_binding_extended_protocol *bp;
249
250 debug("EFI: Adding driver '%s'\n", drv->name);
251 if (!ops->protocol) {
252 printf("EFI: ERROR: protocol GUID missing for driver '%s'\n",
253 drv->name);
254 return EFI_INVALID_PARAMETER;
255 }
256 bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
257 if (!bp)
258 return EFI_OUT_OF_RESOURCES;
259
260 bp->bp.supported = efi_uc_supported;
261 bp->bp.start = efi_uc_start;
262 bp->bp.stop = efi_uc_stop;
263 bp->bp.version = 0xffffffff;
264 bp->ops = drv->ops;
265
266 ret = efi_create_handle(&bp->bp.driver_binding_handle);
267 if (ret != EFI_SUCCESS) {
268 free(bp);
269 goto out;
270 }
271 bp->bp.image_handle = bp->bp.driver_binding_handle;
272 ret = efi_add_protocol(bp->bp.driver_binding_handle,
273 &efi_guid_driver_binding_protocol, bp);
274 if (ret != EFI_SUCCESS) {
275 efi_delete_handle(bp->bp.driver_binding_handle);
276 free(bp);
277 goto out;
278 }
279out:
280 return ret;
281}
282
283
284
285
286
287
288
289efi_status_t efi_driver_init(void)
290{
291 struct driver *drv;
292 efi_status_t ret = EFI_SUCCESS;
293
294
295 efi_save_gd();
296
297 debug("EFI: Initializing EFI driver framework\n");
298 for (drv = ll_entry_start(struct driver, driver);
299 drv < ll_entry_end(struct driver, driver); ++drv) {
300 if (drv->id == UCLASS_EFI) {
301 ret = efi_add_driver(drv);
302 if (ret != EFI_SUCCESS) {
303 printf("EFI: ERROR: failed to add driver %s\n",
304 drv->name);
305 break;
306 }
307 }
308 }
309 return ret;
310}
311
312static int efi_uc_init(struct uclass *class)
313{
314 printf("EFI: Initializing UCLASS_EFI\n");
315 return 0;
316}
317
318static int efi_uc_destroy(struct uclass *class)
319{
320 printf("Destroying UCLASS_EFI\n");
321 return 0;
322}
323
324UCLASS_DRIVER(efi) = {
325 .name = "efi",
326 .id = UCLASS_EFI,
327 .init = efi_uc_init,
328 .destroy = efi_uc_destroy,
329};
330