1 /** @file
2 Driver Binding functions implementation for UEFI HTTP boot.
3
4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available under
6 the terms and conditions of the BSD License that accompanies this distribution.
7 The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "HttpBootDxe.h"
16
17 ///
18 /// Driver Binding Protocol instance
19 ///
20 EFI_DRIVER_BINDING_PROTOCOL gHttpBootIp4DxeDriverBinding = {
21 HttpBootIp4DxeDriverBindingSupported,
22 HttpBootIp4DxeDriverBindingStart,
23 HttpBootIp4DxeDriverBindingStop,
24 HTTP_BOOT_DXE_VERSION,
25 NULL,
26 NULL
27 };
28
29 EFI_DRIVER_BINDING_PROTOCOL gHttpBootIp6DxeDriverBinding = {
30 HttpBootIp6DxeDriverBindingSupported,
31 HttpBootIp6DxeDriverBindingStart,
32 HttpBootIp6DxeDriverBindingStop,
33 HTTP_BOOT_DXE_VERSION,
34 NULL,
35 NULL
36 };
37
38 /**
39 Destroy the HTTP child based on IPv4 stack.
40
41 @param[in] This Pointer to the EFI_DRIVER_BINDING_PROTOCOL.
42 @param[in] Private Pointer to HTTP_BOOT_PRIVATE_DATA.
43
44 **/
45 VOID
HttpBootDestroyIp4Children(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN HTTP_BOOT_PRIVATE_DATA * Private)46 HttpBootDestroyIp4Children (
47 IN EFI_DRIVER_BINDING_PROTOCOL *This,
48 IN HTTP_BOOT_PRIVATE_DATA *Private
49 )
50 {
51 ASSERT (This != NULL);
52 ASSERT (Private != NULL);
53
54 if (Private->Dhcp4Child != NULL) {
55 gBS->CloseProtocol (
56 Private->Dhcp4Child,
57 &gEfiDhcp4ProtocolGuid,
58 This->DriverBindingHandle,
59 Private->Controller
60 );
61
62 NetLibDestroyServiceChild (
63 Private->Controller,
64 This->DriverBindingHandle,
65 &gEfiDhcp4ServiceBindingProtocolGuid,
66 Private->Dhcp4Child
67 );
68 }
69
70 if (Private->HttpCreated) {
71 HttpIoDestroyIo (&Private->HttpIo);
72 Private->HttpCreated = FALSE;
73 }
74
75 if (Private->Ip4Nic != NULL) {
76
77 gBS->CloseProtocol (
78 Private->Controller,
79 &gEfiCallerIdGuid,
80 This->DriverBindingHandle,
81 Private->Ip4Nic->Controller
82 );
83
84 gBS->UninstallMultipleProtocolInterfaces (
85 Private->Ip4Nic->Controller,
86 &gEfiLoadFileProtocolGuid,
87 &Private->Ip4Nic->LoadFile,
88 &gEfiDevicePathProtocolGuid,
89 Private->Ip4Nic->DevicePath,
90 NULL
91 );
92 FreePool (Private->Ip4Nic);
93 Private->Ip4Nic = NULL;
94 }
95
96 }
97
98 /**
99 Destroy the HTTP child based on IPv6 stack.
100
101 @param[in] This Pointer to the EFI_DRIVER_BINDING_PROTOCOL.
102 @param[in] Private Pointer to HTTP_BOOT_PRIVATE_DATA.
103
104 **/
105 VOID
HttpBootDestroyIp6Children(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN HTTP_BOOT_PRIVATE_DATA * Private)106 HttpBootDestroyIp6Children (
107 IN EFI_DRIVER_BINDING_PROTOCOL *This,
108 IN HTTP_BOOT_PRIVATE_DATA *Private
109 )
110 {
111 ASSERT (This != NULL);
112 ASSERT (Private != NULL);
113
114 if (Private->Ip6Child != NULL) {
115 gBS->CloseProtocol (
116 Private->Ip6Child,
117 &gEfiIp6ProtocolGuid,
118 This->DriverBindingHandle,
119 Private->Controller
120 );
121
122 NetLibDestroyServiceChild (
123 Private->Controller,
124 This->DriverBindingHandle,
125 &gEfiIp6ServiceBindingProtocolGuid,
126 Private->Ip6Child
127 );
128 }
129
130 if (Private->Dhcp6Child != NULL) {
131 gBS->CloseProtocol (
132 Private->Dhcp6Child,
133 &gEfiDhcp6ProtocolGuid,
134 This->DriverBindingHandle,
135 Private->Controller
136 );
137
138 NetLibDestroyServiceChild (
139 Private->Controller,
140 This->DriverBindingHandle,
141 &gEfiDhcp6ServiceBindingProtocolGuid,
142 Private->Dhcp6Child
143 );
144 }
145
146 if (Private->HttpCreated) {
147 HttpIoDestroyIo(&Private->HttpIo);
148 Private->HttpCreated = FALSE;
149 }
150
151 if (Private->Ip6Nic != NULL) {
152
153 gBS->CloseProtocol (
154 Private->Controller,
155 &gEfiCallerIdGuid,
156 This->DriverBindingHandle,
157 Private->Ip6Nic->Controller
158 );
159
160 gBS->UninstallMultipleProtocolInterfaces (
161 Private->Ip6Nic->Controller,
162 &gEfiLoadFileProtocolGuid,
163 &Private->Ip6Nic->LoadFile,
164 &gEfiDevicePathProtocolGuid,
165 Private->Ip6Nic->DevicePath,
166 NULL
167 );
168 FreePool (Private->Ip6Nic);
169 Private->Ip6Nic = NULL;
170 }
171 }
172
173 /**
174 Tests to see if this driver supports a given controller. If a child device is provided,
175 it further tests to see if this driver supports creating a handle for the specified child device.
176
177 This function checks to see if the driver specified by This supports the device specified by
178 ControllerHandle. Drivers will typically use the device path attached to
179 ControllerHandle and/or the services from the bus I/O abstraction attached to
180 ControllerHandle to determine if the driver supports ControllerHandle. This function
181 may be called many times during platform initialization. In order to reduce boot times, the tests
182 performed by this function must be very small, and take as little time as possible to execute. This
183 function must not change the state of any hardware devices, and this function must be aware that the
184 device specified by ControllerHandle may already be managed by the same driver or a
185 different driver. This function must match its calls to AllocatePages() with FreePages(),
186 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
187 Because ControllerHandle may have been previously started by the same driver, if a protocol is
188 already in the opened state, then it must not be closed with CloseProtocol(). This is required
189 to guarantee the state of ControllerHandle is not modified by this function.
190
191 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
192 @param[in] ControllerHandle The handle of the controller to test. This handle
193 must support a protocol interface that supplies
194 an I/O abstraction to the driver.
195 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
196 parameter is ignored by device drivers, and is optional for bus
197 drivers. For bus drivers, if this parameter is not NULL, then
198 the bus driver must determine if the bus controller specified
199 by ControllerHandle and the child controller specified
200 by RemainingDevicePath are both supported by this
201 bus driver.
202
203 @retval EFI_SUCCESS The device specified by ControllerHandle and
204 RemainingDevicePath is supported by the driver specified by This.
205 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
206 RemainingDevicePath is already being managed by the driver
207 specified by This.
208 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
209 RemainingDevicePath is already being managed by a different
210 driver or an application that requires exclusive access.
211 Currently not implemented.
212 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
213 RemainingDevicePath is not supported by the driver specified by This.
214 **/
215 EFI_STATUS
216 EFIAPI
HttpBootIp4DxeDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)217 HttpBootIp4DxeDriverBindingSupported (
218 IN EFI_DRIVER_BINDING_PROTOCOL *This,
219 IN EFI_HANDLE ControllerHandle,
220 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
221 )
222 {
223 EFI_STATUS Status;
224
225 //
226 // Try to open the DHCP4, HTTP4 and Device Path protocol.
227 //
228 Status = gBS->OpenProtocol (
229 ControllerHandle,
230 &gEfiDhcp4ServiceBindingProtocolGuid,
231 NULL,
232 This->DriverBindingHandle,
233 ControllerHandle,
234 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
235 );
236 if (EFI_ERROR (Status)) {
237 return Status;
238 }
239
240 Status = gBS->OpenProtocol (
241 ControllerHandle,
242 &gEfiHttpServiceBindingProtocolGuid,
243 NULL,
244 This->DriverBindingHandle,
245 ControllerHandle,
246 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
247 );
248 if (EFI_ERROR (Status)) {
249 return Status;
250 }
251
252 Status = gBS->OpenProtocol (
253 ControllerHandle,
254 &gEfiDevicePathProtocolGuid,
255 NULL,
256 This->DriverBindingHandle,
257 ControllerHandle,
258 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
259 );
260
261 return Status;
262 }
263
264
265 /**
266 Starts a device controller or a bus controller.
267
268 The Start() function is designed to be invoked from the EFI boot service ConnectController().
269 As a result, much of the error checking on the parameters to Start() has been moved into this
270 common boot service. It is legal to call Start() from other locations,
271 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
272 1. ControllerHandle must be a valid EFI_HANDLE.
273 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
274 EFI_DEVICE_PATH_PROTOCOL.
275 3. Prior to calling Start(), the Supported() function for the driver specified by This must
276 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
277
278 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
279 @param[in] ControllerHandle The handle of the controller to start. This handle
280 must support a protocol interface that supplies
281 an I/O abstraction to the driver.
282 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
283 parameter is ignored by device drivers, and is optional for bus
284 drivers. For a bus driver, if this parameter is NULL, then handles
285 for all the children of Controller are created by this driver.
286 If this parameter is not NULL and the first Device Path Node is
287 not the End of Device Path Node, then only the handle for the
288 child device specified by the first Device Path Node of
289 RemainingDevicePath is created by this driver.
290 If the first Device Path Node of RemainingDevicePath is
291 the End of Device Path Node, no child handle is created by this
292 driver.
293
294 @retval EFI_SUCCESS The device was started.
295 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
296 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
297 @retval Others The driver failded to start the device.
298
299 **/
300 EFI_STATUS
301 EFIAPI
HttpBootIp4DxeDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)302 HttpBootIp4DxeDriverBindingStart (
303 IN EFI_DRIVER_BINDING_PROTOCOL *This,
304 IN EFI_HANDLE ControllerHandle,
305 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
306 )
307 {
308 EFI_STATUS Status;
309 HTTP_BOOT_PRIVATE_DATA *Private;
310 EFI_DEV_PATH *Node;
311 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
312 UINT32 *Id;
313
314 Status = gBS->OpenProtocol (
315 ControllerHandle,
316 &gEfiCallerIdGuid,
317 (VOID **) &Id,
318 This->DriverBindingHandle,
319 ControllerHandle,
320 EFI_OPEN_PROTOCOL_GET_PROTOCOL
321 );
322
323 if (!EFI_ERROR (Status)) {
324 Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id);
325 } else {
326 //
327 // Initialize the private data structure.
328 //
329 Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA));
330 if (Private == NULL) {
331 return EFI_OUT_OF_RESOURCES;
332 }
333 Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE;
334 Private->Controller = ControllerHandle;
335 InitializeListHead (&Private->CacheList);
336 //
337 // Get the NII interface if it exists, it's not required.
338 //
339 Status = gBS->OpenProtocol (
340 ControllerHandle,
341 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
342 (VOID **) &Private->Nii,
343 This->DriverBindingHandle,
344 ControllerHandle,
345 EFI_OPEN_PROTOCOL_GET_PROTOCOL
346 );
347 if (EFI_ERROR (Status)) {
348 Private->Nii = NULL;
349 }
350
351 //
352 // Open Device Path Protocol to prepare for appending IP and URI node.
353 //
354 Status = gBS->OpenProtocol (
355 ControllerHandle,
356 &gEfiDevicePathProtocolGuid,
357 (VOID **) &Private->ParentDevicePath,
358 This->DriverBindingHandle,
359 ControllerHandle,
360 EFI_OPEN_PROTOCOL_GET_PROTOCOL
361 );
362 if (EFI_ERROR (Status)) {
363 goto ON_ERROR;
364 }
365
366 //
367 // Initialize the HII configuration form.
368 //
369 Status = HttpBootConfigFormInit (Private);
370 if (EFI_ERROR (Status)) {
371 goto ON_ERROR;
372 }
373
374 //
375 // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between
376 // NIC handle and the private data.
377 //
378 Status = gBS->InstallProtocolInterface (
379 &ControllerHandle,
380 &gEfiCallerIdGuid,
381 EFI_NATIVE_INTERFACE,
382 &Private->Id
383 );
384 if (EFI_ERROR (Status)) {
385 goto ON_ERROR;
386 }
387
388 }
389
390 if (Private->Ip4Nic != NULL) {
391 //
392 // Already created before
393 //
394 return EFI_SUCCESS;
395 }
396
397 Private->Ip4Nic = AllocateZeroPool (sizeof (HTTP_BOOT_VIRTUAL_NIC));
398 if (Private->Ip4Nic == NULL) {
399 return EFI_OUT_OF_RESOURCES;
400 }
401 Private->Ip4Nic->Private = Private;
402 Private->Ip4Nic->ImageHandle = This->DriverBindingHandle;
403 Private->Ip4Nic->Signature = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE;
404
405 //
406 // Create DHCP4 child instance.
407 //
408 Status = NetLibCreateServiceChild (
409 ControllerHandle,
410 This->DriverBindingHandle,
411 &gEfiDhcp4ServiceBindingProtocolGuid,
412 &Private->Dhcp4Child
413 );
414 if (EFI_ERROR (Status)) {
415 goto ON_ERROR;
416 }
417
418 Status = gBS->OpenProtocol (
419 Private->Dhcp4Child,
420 &gEfiDhcp4ProtocolGuid,
421 (VOID **) &Private->Dhcp4,
422 This->DriverBindingHandle,
423 ControllerHandle,
424 EFI_OPEN_PROTOCOL_BY_DRIVER
425 );
426 if (EFI_ERROR (Status)) {
427 goto ON_ERROR;
428 }
429
430 //
431 // Get the Ip4Config2 protocol, it's required to configure the default gateway address.
432 //
433 Status = gBS->OpenProtocol (
434 ControllerHandle,
435 &gEfiIp4Config2ProtocolGuid,
436 (VOID **) &Private->Ip4Config2,
437 This->DriverBindingHandle,
438 ControllerHandle,
439 EFI_OPEN_PROTOCOL_GET_PROTOCOL
440 );
441 if (EFI_ERROR (Status)) {
442 goto ON_ERROR;
443 }
444
445 //
446 // Append IPv4 device path node.
447 //
448 Node = AllocateZeroPool (sizeof (IPv4_DEVICE_PATH));
449 if (Node == NULL) {
450 Status = EFI_OUT_OF_RESOURCES;
451 goto ON_ERROR;
452 }
453 Node->Ipv4.Header.Type = MESSAGING_DEVICE_PATH;
454 Node->Ipv4.Header.SubType = MSG_IPv4_DP;
455 SetDevicePathNodeLength (Node, sizeof (IPv4_DEVICE_PATH));
456 Node->Ipv4.StaticIpAddress = FALSE;
457 DevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
458 FreePool (Node);
459 if (DevicePath == NULL) {
460 Status = EFI_OUT_OF_RESOURCES;
461 goto ON_ERROR;
462 }
463
464 //
465 // Append URI device path node.
466 //
467 Node = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL));
468 if (Node == NULL) {
469 Status = EFI_OUT_OF_RESOURCES;
470 goto ON_ERROR;
471 }
472 Node->DevPath.Type = MESSAGING_DEVICE_PATH;
473 Node->DevPath.SubType = MSG_URI_DP;
474 SetDevicePathNodeLength (Node, sizeof (EFI_DEVICE_PATH_PROTOCOL));
475 Private->Ip4Nic->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
476 FreePool (Node);
477 FreePool (DevicePath);
478 if (Private->Ip4Nic->DevicePath == NULL) {
479 Status = EFI_OUT_OF_RESOURCES;
480 goto ON_ERROR;
481 }
482
483 //
484 // Create a child handle for the HTTP boot and install DevPath and Load file protocol on it.
485 //
486 CopyMem (&Private->Ip4Nic->LoadFile, &gHttpBootDxeLoadFile, sizeof (EFI_LOAD_FILE_PROTOCOL));
487 Status = gBS->InstallMultipleProtocolInterfaces (
488 &Private->Ip4Nic->Controller,
489 &gEfiLoadFileProtocolGuid,
490 &Private->Ip4Nic->LoadFile,
491 &gEfiDevicePathProtocolGuid,
492 Private->Ip4Nic->DevicePath,
493 NULL
494 );
495 if (EFI_ERROR (Status)) {
496 goto ON_ERROR;
497 }
498
499 //
500 // Open the Caller Id child to setup a parent-child relationship between
501 // real NIC handle and the HTTP boot Ipv4 NIC handle.
502 //
503 Status = gBS->OpenProtocol (
504 ControllerHandle,
505 &gEfiCallerIdGuid,
506 (VOID **) &Id,
507 This->DriverBindingHandle,
508 Private->Ip4Nic->Controller,
509 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
510 );
511 if (EFI_ERROR (Status)) {
512 goto ON_ERROR;
513 }
514
515 return EFI_SUCCESS;
516
517
518 ON_ERROR:
519
520 HttpBootDestroyIp4Children (This, Private);
521 HttpBootConfigFormUnload (Private);
522 FreePool (Private);
523
524 return Status;
525 }
526
527
528 /**
529 Stops a device controller or a bus controller.
530
531 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
532 As a result, much of the error checking on the parameters to Stop() has been moved
533 into this common boot service. It is legal to call Stop() from other locations,
534 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
535 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
536 same driver's Start() function.
537 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
538 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
539 Start() function, and the Start() function must have called OpenProtocol() on
540 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
541
542 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
543 @param[in] ControllerHandle A handle to the device being stopped. The handle must
544 support a bus specific I/O protocol for the driver
545 to use to stop the device.
546 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
547 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
548 if NumberOfChildren is 0.
549
550 @retval EFI_SUCCESS The device was stopped.
551 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
552
553 **/
554 EFI_STATUS
555 EFIAPI
HttpBootIp4DxeDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)556 HttpBootIp4DxeDriverBindingStop (
557 IN EFI_DRIVER_BINDING_PROTOCOL *This,
558 IN EFI_HANDLE ControllerHandle,
559 IN UINTN NumberOfChildren,
560 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
561 )
562 {
563 EFI_STATUS Status;
564 EFI_LOAD_FILE_PROTOCOL *LoadFile;
565 HTTP_BOOT_PRIVATE_DATA *Private;
566 EFI_HANDLE NicHandle;
567 UINT32 *Id;
568
569 //
570 // Try to get the Load File Protocol from the controller handle.
571 //
572 Status = gBS->OpenProtocol (
573 ControllerHandle,
574 &gEfiLoadFileProtocolGuid,
575 (VOID **) &LoadFile,
576 This->DriverBindingHandle,
577 ControllerHandle,
578 EFI_OPEN_PROTOCOL_GET_PROTOCOL
579 );
580 if (EFI_ERROR (Status)) {
581 //
582 // If failed, try to find the NIC handle for this controller.
583 //
584 NicHandle = HttpBootGetNicByIp4Children (ControllerHandle);
585 if (NicHandle == NULL) {
586 return EFI_SUCCESS;
587 }
588
589 //
590 // Try to retrieve the private data by the Caller Id Guid.
591 //
592 Status = gBS->OpenProtocol (
593 NicHandle,
594 &gEfiCallerIdGuid,
595 (VOID **) &Id,
596 This->DriverBindingHandle,
597 ControllerHandle,
598 EFI_OPEN_PROTOCOL_GET_PROTOCOL
599 );
600 if (EFI_ERROR (Status)) {
601 return Status;
602 }
603 Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID (Id);
604 } else {
605 Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (LoadFile);
606 NicHandle = Private->Controller;
607 }
608
609 //
610 // Disable the HTTP boot function.
611 //
612 Status = HttpBootStop (Private);
613 if (Status != EFI_SUCCESS && Status != EFI_NOT_STARTED) {
614 return Status;
615 }
616
617 //
618 // Destory all child instance and uninstall protocol interface.
619 //
620 HttpBootDestroyIp4Children (This, Private);
621
622 if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) {
623 //
624 // Release the cached data.
625 //
626 HttpBootFreeCacheList (Private);
627
628 //
629 // Unload the config form.
630 //
631 HttpBootConfigFormUnload (Private);
632
633 gBS->UninstallProtocolInterface (
634 NicHandle,
635 &gEfiCallerIdGuid,
636 &Private->Id
637 );
638 FreePool (Private);
639
640 }
641
642 return EFI_SUCCESS;
643 }
644
645 /**
646 Tests to see if this driver supports a given controller. If a child device is provided,
647 it further tests to see if this driver supports creating a handle for the specified child device.
648
649 This function checks to see if the driver specified by This supports the device specified by
650 ControllerHandle. Drivers will typically use the device path attached to
651 ControllerHandle and/or the services from the bus I/O abstraction attached to
652 ControllerHandle to determine if the driver supports ControllerHandle. This function
653 may be called many times during platform initialization. In order to reduce boot times, the tests
654 performed by this function must be very small, and take as little time as possible to execute. This
655 function must not change the state of any hardware devices, and this function must be aware that the
656 device specified by ControllerHandle may already be managed by the same driver or a
657 different driver. This function must match its calls to AllocatePages() with FreePages(),
658 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
659 Because ControllerHandle may have been previously started by the same driver, if a protocol is
660 already in the opened state, then it must not be closed with CloseProtocol(). This is required
661 to guarantee the state of ControllerHandle is not modified by this function.
662
663 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
664 @param[in] ControllerHandle The handle of the controller to test. This handle
665 must support a protocol interface that supplies
666 an I/O abstraction to the driver.
667 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
668 parameter is ignored by device drivers, and is optional for bus
669 drivers. For bus drivers, if this parameter is not NULL, then
670 the bus driver must determine if the bus controller specified
671 by ControllerHandle and the child controller specified
672 by RemainingDevicePath are both supported by this
673 bus driver.
674
675 @retval EFI_SUCCESS The device specified by ControllerHandle and
676 RemainingDevicePath is supported by the driver specified by This.
677 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
678 RemainingDevicePath is already being managed by the driver
679 specified by This.
680 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
681 RemainingDevicePath is already being managed by a different
682 driver or an application that requires exclusive access.
683 Currently not implemented.
684 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
685 RemainingDevicePath is not supported by the driver specified by This.
686 **/
687 EFI_STATUS
688 EFIAPI
HttpBootIp6DxeDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)689 HttpBootIp6DxeDriverBindingSupported (
690 IN EFI_DRIVER_BINDING_PROTOCOL *This,
691 IN EFI_HANDLE ControllerHandle,
692 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
693 )
694 {
695 EFI_STATUS Status;
696
697 //
698 // Try to open the DHCP6, HTTP and Device Path protocol.
699 //
700 Status = gBS->OpenProtocol (
701 ControllerHandle,
702 &gEfiDhcp6ServiceBindingProtocolGuid,
703 NULL,
704 This->DriverBindingHandle,
705 ControllerHandle,
706 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
707 );
708 if (EFI_ERROR (Status)) {
709 return Status;
710 }
711
712 Status = gBS->OpenProtocol (
713 ControllerHandle,
714 &gEfiHttpServiceBindingProtocolGuid,
715 NULL,
716 This->DriverBindingHandle,
717 ControllerHandle,
718 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
719 );
720 if (EFI_ERROR (Status)) {
721 return Status;
722 }
723
724 Status = gBS->OpenProtocol (
725 ControllerHandle,
726 &gEfiDevicePathProtocolGuid,
727 NULL,
728 This->DriverBindingHandle,
729 ControllerHandle,
730 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
731 );
732
733 return Status;
734
735 }
736
737 /**
738 Starts a device controller or a bus controller.
739
740 The Start() function is designed to be invoked from the EFI boot service ConnectController().
741 As a result, much of the error checking on the parameters to Start() has been moved into this
742 common boot service. It is legal to call Start() from other locations,
743 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
744 1. ControllerHandle must be a valid EFI_HANDLE.
745 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
746 EFI_DEVICE_PATH_PROTOCOL.
747 3. Prior to calling Start(), the Supported() function for the driver specified by This must
748 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
749
750 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
751 @param[in] ControllerHandle The handle of the controller to start. This handle
752 must support a protocol interface that supplies
753 an I/O abstraction to the driver.
754 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
755 parameter is ignored by device drivers, and is optional for bus
756 drivers. For a bus driver, if this parameter is NULL, then handles
757 for all the children of Controller are created by this driver.
758 If this parameter is not NULL and the first Device Path Node is
759 not the End of Device Path Node, then only the handle for the
760 child device specified by the first Device Path Node of
761 RemainingDevicePath is created by this driver.
762 If the first Device Path Node of RemainingDevicePath is
763 the End of Device Path Node, no child handle is created by this
764 driver.
765
766 @retval EFI_SUCCESS The device was started.
767 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
768 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
769 @retval Others The driver failded to start the device.
770
771 **/
772 EFI_STATUS
773 EFIAPI
HttpBootIp6DxeDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)774 HttpBootIp6DxeDriverBindingStart (
775 IN EFI_DRIVER_BINDING_PROTOCOL *This,
776 IN EFI_HANDLE ControllerHandle,
777 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
778 )
779 {
780 EFI_STATUS Status;
781 HTTP_BOOT_PRIVATE_DATA *Private;
782 EFI_DEV_PATH *Node;
783 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
784 UINT32 *Id;
785
786 Status = gBS->OpenProtocol (
787 ControllerHandle,
788 &gEfiCallerIdGuid,
789 (VOID **) &Id,
790 This->DriverBindingHandle,
791 ControllerHandle,
792 EFI_OPEN_PROTOCOL_GET_PROTOCOL
793 );
794
795 if (!EFI_ERROR (Status)) {
796 Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID(Id);
797 } else {
798 //
799 // Initialize the private data structure.
800 //
801 Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA));
802 if (Private == NULL) {
803 return EFI_OUT_OF_RESOURCES;
804 }
805 Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE;
806 Private->Controller = ControllerHandle;
807 InitializeListHead (&Private->CacheList);
808 //
809 // Get the NII interface if it exists, it's not required.
810 //
811 Status = gBS->OpenProtocol (
812 ControllerHandle,
813 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
814 (VOID **) &Private->Nii,
815 This->DriverBindingHandle,
816 ControllerHandle,
817 EFI_OPEN_PROTOCOL_GET_PROTOCOL
818 );
819 if (EFI_ERROR (Status)) {
820 Private->Nii = NULL;
821 }
822
823 //
824 // Open Device Path Protocol to prepare for appending IP and URI node.
825 //
826 Status = gBS->OpenProtocol (
827 ControllerHandle,
828 &gEfiDevicePathProtocolGuid,
829 (VOID **) &Private->ParentDevicePath,
830 This->DriverBindingHandle,
831 ControllerHandle,
832 EFI_OPEN_PROTOCOL_GET_PROTOCOL
833 );
834 if (EFI_ERROR (Status)) {
835 goto ON_ERROR;
836 }
837
838 //
839 // Initialize the HII configuration form.
840 //
841 Status = HttpBootConfigFormInit (Private);
842 if (EFI_ERROR (Status)) {
843 goto ON_ERROR;
844 }
845
846 //
847 // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between
848 // NIC handle and the private data.
849 //
850 Status = gBS->InstallProtocolInterface (
851 &ControllerHandle,
852 &gEfiCallerIdGuid,
853 EFI_NATIVE_INTERFACE,
854 &Private->Id
855 );
856 if (EFI_ERROR (Status)) {
857 goto ON_ERROR;
858 }
859
860 }
861
862 if (Private->Ip6Nic != NULL) {
863 //
864 // Already created before
865 //
866 return EFI_SUCCESS;
867 }
868
869 Private->Ip6Nic = AllocateZeroPool (sizeof (HTTP_BOOT_VIRTUAL_NIC));
870 if (Private->Ip6Nic == NULL) {
871 return EFI_OUT_OF_RESOURCES;
872 }
873 Private->Ip6Nic->Private = Private;
874 Private->Ip6Nic->ImageHandle = This->DriverBindingHandle;
875 Private->Ip6Nic->Signature = HTTP_BOOT_VIRTUAL_NIC_SIGNATURE;
876
877 //
878 // Create Dhcp6 child and open Dhcp6 protocol
879 Status = NetLibCreateServiceChild (
880 ControllerHandle,
881 This->DriverBindingHandle,
882 &gEfiDhcp6ServiceBindingProtocolGuid,
883 &Private->Dhcp6Child
884 );
885 if (EFI_ERROR (Status)) {
886 goto ON_ERROR;
887 }
888
889 Status = gBS->OpenProtocol (
890 Private->Dhcp6Child,
891 &gEfiDhcp6ProtocolGuid,
892 (VOID **) &Private->Dhcp6,
893 This->DriverBindingHandle,
894 ControllerHandle,
895 EFI_OPEN_PROTOCOL_BY_DRIVER
896 );
897 if (EFI_ERROR (Status)) {
898 goto ON_ERROR;
899 }
900
901 //
902 // Create Ip6 child and open Ip6 protocol for background ICMP packets.
903 //
904 Status = NetLibCreateServiceChild (
905 ControllerHandle,
906 This->DriverBindingHandle,
907 &gEfiIp6ServiceBindingProtocolGuid,
908 &Private->Ip6Child
909 );
910 if (EFI_ERROR (Status)) {
911 goto ON_ERROR;
912 }
913
914 Status = gBS->OpenProtocol (
915 Private->Ip6Child,
916 &gEfiIp6ProtocolGuid,
917 (VOID **) &Private->Ip6,
918 This->DriverBindingHandle,
919 ControllerHandle,
920 EFI_OPEN_PROTOCOL_BY_DRIVER
921 );
922 if (EFI_ERROR (Status)) {
923 goto ON_ERROR;
924 }
925
926 //
927 // Locate Ip6Config protocol, it's required to configure the default gateway address.
928 //
929 Status = gBS->OpenProtocol (
930 ControllerHandle,
931 &gEfiIp6ConfigProtocolGuid,
932 (VOID **) &Private->Ip6Config,
933 This->DriverBindingHandle,
934 ControllerHandle,
935 EFI_OPEN_PROTOCOL_GET_PROTOCOL
936 );
937 if (EFI_ERROR (Status)) {
938 goto ON_ERROR;
939 }
940
941 //
942 // Append IPv6 device path node.
943 //
944 Node = AllocateZeroPool (sizeof (IPv6_DEVICE_PATH));
945 if (Node == NULL) {
946 Status = EFI_OUT_OF_RESOURCES;
947 goto ON_ERROR;
948 }
949 Node->Ipv6.Header.Type = MESSAGING_DEVICE_PATH;
950 Node->Ipv6.Header.SubType = MSG_IPv6_DP;
951 Node->Ipv6.PrefixLength = IP6_PREFIX_LENGTH;
952 SetDevicePathNodeLength (Node, sizeof (IPv6_DEVICE_PATH));
953 DevicePath = AppendDevicePathNode(Private->ParentDevicePath, (EFI_DEVICE_PATH*) Node);
954 FreePool(Node);
955 if (DevicePath == NULL) {
956 Status = EFI_OUT_OF_RESOURCES;
957 goto ON_ERROR;
958 }
959
960 //
961 // Append URI device path node.
962 //
963 Node = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL));
964 if (Node == NULL) {
965 Status = EFI_OUT_OF_RESOURCES;
966 goto ON_ERROR;
967 }
968 Node->DevPath.Type = MESSAGING_DEVICE_PATH;
969 Node->DevPath.SubType = MSG_URI_DP;
970 SetDevicePathNodeLength (Node, sizeof (EFI_DEVICE_PATH_PROTOCOL));
971 Private->Ip6Nic->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);
972 FreePool (Node);
973 FreePool (DevicePath);
974 if (Private->Ip6Nic->DevicePath == NULL) {
975 Status = EFI_OUT_OF_RESOURCES;
976 goto ON_ERROR;
977 }
978
979 //
980 // Create a child handle for the HTTP boot and install DevPath and Load file protocol on it.
981 //
982 CopyMem (&Private->Ip6Nic->LoadFile, &gHttpBootDxeLoadFile, sizeof (Private->LoadFile));
983 Status = gBS->InstallMultipleProtocolInterfaces (
984 &Private->Ip6Nic->Controller,
985 &gEfiLoadFileProtocolGuid,
986 &Private->Ip6Nic->LoadFile,
987 &gEfiDevicePathProtocolGuid,
988 Private->Ip6Nic->DevicePath,
989 NULL
990 );
991 if (EFI_ERROR (Status)) {
992 goto ON_ERROR;
993 }
994
995 //
996 // Open the Caller Id child to setup a parent-child relationship between
997 // real NIC handle and the HTTP boot child handle.
998 //
999 Status = gBS->OpenProtocol (
1000 ControllerHandle,
1001 &gEfiCallerIdGuid,
1002 (VOID **) &Id,
1003 This->DriverBindingHandle,
1004 Private->Ip6Nic->Controller,
1005 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1006 );
1007 if (EFI_ERROR (Status)) {
1008 goto ON_ERROR;
1009 }
1010
1011 return EFI_SUCCESS;
1012
1013 ON_ERROR:
1014
1015 HttpBootDestroyIp6Children(This, Private);
1016 HttpBootConfigFormUnload (Private);
1017 FreePool (Private);
1018
1019 return Status;
1020 }
1021
1022 /**
1023 Stops a device controller or a bus controller.
1024
1025 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
1026 As a result, much of the error checking on the parameters to Stop() has been moved
1027 into this common boot service. It is legal to call Stop() from other locations,
1028 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
1029 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
1030 same driver's Start() function.
1031 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
1032 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
1033 Start() function, and the Start() function must have called OpenProtocol() on
1034 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
1035
1036 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1037 @param[in] ControllerHandle A handle to the device being stopped. The handle must
1038 support a bus specific I/O protocol for the driver
1039 to use to stop the device.
1040 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
1041 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1042 if NumberOfChildren is 0.
1043
1044 @retval EFI_SUCCESS The device was stopped.
1045 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
1046
1047 **/
1048 EFI_STATUS
1049 EFIAPI
HttpBootIp6DxeDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)1050 HttpBootIp6DxeDriverBindingStop (
1051 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1052 IN EFI_HANDLE ControllerHandle,
1053 IN UINTN NumberOfChildren,
1054 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
1055 )
1056 {
1057 EFI_STATUS Status;
1058 EFI_LOAD_FILE_PROTOCOL *LoadFile;
1059 HTTP_BOOT_PRIVATE_DATA *Private;
1060 EFI_HANDLE NicHandle;
1061 UINT32 *Id;
1062
1063 //
1064 // Try to get the Load File Protocol from the controller handle.
1065 //
1066 Status = gBS->OpenProtocol (
1067 ControllerHandle,
1068 &gEfiLoadFileProtocolGuid,
1069 (VOID **) &LoadFile,
1070 This->DriverBindingHandle,
1071 ControllerHandle,
1072 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1073 );
1074 if (EFI_ERROR (Status)) {
1075 //
1076 // If failed, try to find the NIC handle for this controller.
1077 //
1078 NicHandle = HttpBootGetNicByIp6Children (ControllerHandle);
1079 if (NicHandle == NULL) {
1080 return EFI_SUCCESS;
1081 }
1082
1083 //
1084 // Try to retrieve the private data by the Caller Id Guid.
1085 //
1086 Status = gBS->OpenProtocol (
1087 NicHandle,
1088 &gEfiCallerIdGuid,
1089 (VOID **) &Id,
1090 This->DriverBindingHandle,
1091 ControllerHandle,
1092 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1093 );
1094 if (EFI_ERROR (Status)) {
1095 return Status;
1096 }
1097 Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID (Id);
1098 } else {
1099 Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (LoadFile);
1100 NicHandle = Private->Controller;
1101 }
1102
1103 //
1104 // Disable the HTTP boot function.
1105 //
1106 Status = HttpBootStop (Private);
1107 if (Status != EFI_SUCCESS && Status != EFI_NOT_STARTED) {
1108 return Status;
1109 }
1110
1111 //
1112 // Destory all child instance and uninstall protocol interface.
1113 //
1114 HttpBootDestroyIp6Children (This, Private);
1115
1116 if (Private->Ip4Nic == NULL && Private->Ip6Nic == NULL) {
1117 //
1118 // Release the cached data.
1119 //
1120 HttpBootFreeCacheList (Private);
1121
1122 //
1123 // Unload the config form.
1124 //
1125 HttpBootConfigFormUnload (Private);
1126
1127 gBS->UninstallProtocolInterface (
1128 NicHandle,
1129 &gEfiCallerIdGuid,
1130 &Private->Id
1131 );
1132 FreePool (Private);
1133
1134 }
1135
1136 return EFI_SUCCESS;
1137 }
1138 /**
1139 This is the declaration of an EFI image entry point. This entry point is
1140 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
1141 both device drivers and bus drivers.
1142
1143 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
1144 @param[in] SystemTable A pointer to the EFI System Table.
1145
1146 @retval EFI_SUCCESS The operation completed successfully.
1147 @retval Others An unexpected error occurred.
1148
1149 **/
1150 EFI_STATUS
1151 EFIAPI
HttpBootDxeDriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1152 HttpBootDxeDriverEntryPoint (
1153 IN EFI_HANDLE ImageHandle,
1154 IN EFI_SYSTEM_TABLE *SystemTable
1155 )
1156 {
1157 EFI_STATUS Status;
1158
1159 //
1160 // Install UEFI Driver Model protocol(s).
1161 //
1162 Status = EfiLibInstallDriverBindingComponentName2 (
1163 ImageHandle,
1164 SystemTable,
1165 &gHttpBootIp4DxeDriverBinding,
1166 ImageHandle,
1167 &gHttpBootDxeComponentName,
1168 &gHttpBootDxeComponentName2
1169 );
1170 if (EFI_ERROR (Status)) {
1171 return Status;
1172 }
1173
1174 Status = EfiLibInstallDriverBindingComponentName2 (
1175 ImageHandle,
1176 SystemTable,
1177 &gHttpBootIp6DxeDriverBinding,
1178 NULL,
1179 &gHttpBootDxeComponentName,
1180 &gHttpBootDxeComponentName2
1181 );
1182 if (EFI_ERROR (Status)) {
1183 gBS->UninstallMultipleProtocolInterfaces(
1184 ImageHandle,
1185 &gEfiDriverBindingProtocolGuid,
1186 &gHttpBootIp4DxeDriverBinding,
1187 &gEfiComponentName2ProtocolGuid,
1188 &gHttpBootDxeComponentName2,
1189 &gEfiComponentNameProtocolGuid,
1190 &gHttpBootDxeComponentName,
1191 NULL
1192 );
1193 }
1194 return Status;
1195 }
1196
1197