]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootDxe.c
NetworkPkg: Update cache management in HTTP boot driver.
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootDxe.c
CommitLineData
d933e70a
JW
1/** @file\r
2 Driver Binding functions implementation for UEFI HTTP boot.\r
3\r
4Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials are licensed and made available under \r
6the terms and conditions of the BSD License that accompanies this distribution. \r
7The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php. \r
9 \r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
12\r
13**/\r
14\r
15#include "HttpBootDxe.h"\r
16\r
17///\r
18/// Driver Binding Protocol instance\r
19///\r
20EFI_DRIVER_BINDING_PROTOCOL gHttpBootIp4DxeDriverBinding = {\r
21 HttpBootIp4DxeDriverBindingSupported,\r
22 HttpBootIp4DxeDriverBindingStart,\r
23 HttpBootIp4DxeDriverBindingStop,\r
24 HTTP_BOOT_DXE_VERSION,\r
25 NULL,\r
26 NULL\r
27};\r
28\r
29/**\r
30 Destroy the HTTP child based on IPv4 stack.\r
31\r
32 @param[in] This Pointer to the EFI_DRIVER_BINDING_PROTOCOL.\r
33 @param[in] Private Pointer to HTTP_BOOT_PRIVATE_DATA.\r
34\r
35**/\r
36VOID\r
37HttpBootDestroyIp4Children (\r
38 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
39 IN HTTP_BOOT_PRIVATE_DATA *Private\r
40 )\r
41{\r
42 ASSERT (This != NULL);\r
43 ASSERT (Private != NULL);\r
44 ASSERT (Private->UsingIpv6 == FALSE);\r
45\r
46 if (Private->Dhcp4Child != NULL) {\r
47 gBS->CloseProtocol (\r
48 Private->Dhcp4Child,\r
49 &gEfiDhcp4ProtocolGuid,\r
50 This->DriverBindingHandle,\r
51 Private->Controller\r
52 );\r
53\r
54 NetLibDestroyServiceChild (\r
55 Private->Controller,\r
56 This->DriverBindingHandle,\r
57 &gEfiDhcp4ServiceBindingProtocolGuid,\r
58 Private->Dhcp4Child\r
59 );\r
60 }\r
61\r
62 if (Private->HttpCreated) {\r
63 HttpIoDestroyIo (&Private->HttpIo);\r
64 Private->HttpCreated = FALSE;\r
65 }\r
66\r
67 gBS->CloseProtocol (\r
68 Private->Controller,\r
69 &gEfiCallerIdGuid,\r
70 This->DriverBindingHandle,\r
71 Private->ChildHandle\r
72 );\r
73\r
74 gBS->UninstallMultipleProtocolInterfaces (\r
75 Private->ChildHandle,\r
76 &gEfiLoadFileProtocolGuid,\r
77 &Private->LoadFile,\r
78 &gEfiDevicePathProtocolGuid,\r
79 Private->DevicePath,\r
80 NULL\r
81 );\r
82\r
83 if (Private->DevicePath != NULL) {\r
84 FreePool (Private->DevicePath);\r
85 Private->DevicePath = NULL;\r
86 }\r
87}\r
88\r
89/**\r
90 Tests to see if this driver supports a given controller. If a child device is provided, \r
91 it further tests to see if this driver supports creating a handle for the specified child device.\r
92\r
93 This function checks to see if the driver specified by This supports the device specified by \r
94 ControllerHandle. Drivers will typically use the device path attached to \r
95 ControllerHandle and/or the services from the bus I/O abstraction attached to \r
96 ControllerHandle to determine if the driver supports ControllerHandle. This function \r
97 may be called many times during platform initialization. In order to reduce boot times, the tests \r
98 performed by this function must be very small, and take as little time as possible to execute. This \r
99 function must not change the state of any hardware devices, and this function must be aware that the \r
100 device specified by ControllerHandle may already be managed by the same driver or a \r
101 different driver. This function must match its calls to AllocatePages() with FreePages(), \r
102 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). \r
103 Because ControllerHandle may have been previously started by the same driver, if a protocol is \r
104 already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
105 to guarantee the state of ControllerHandle is not modified by this function.\r
106\r
107 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
108 @param[in] ControllerHandle The handle of the controller to test. This handle \r
109 must support a protocol interface that supplies \r
110 an I/O abstraction to the driver.\r
111 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
112 parameter is ignored by device drivers, and is optional for bus \r
113 drivers. For bus drivers, if this parameter is not NULL, then \r
114 the bus driver must determine if the bus controller specified \r
115 by ControllerHandle and the child controller specified \r
116 by RemainingDevicePath are both supported by this \r
117 bus driver.\r
118\r
119 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
120 RemainingDevicePath is supported by the driver specified by This.\r
121 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
122 RemainingDevicePath is already being managed by the driver\r
123 specified by This.\r
124 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
125 RemainingDevicePath is already being managed by a different\r
126 driver or an application that requires exclusive access.\r
127 Currently not implemented.\r
128 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
129 RemainingDevicePath is not supported by the driver specified by This.\r
130**/\r
131EFI_STATUS\r
132EFIAPI\r
133HttpBootIp4DxeDriverBindingSupported (\r
134 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
135 IN EFI_HANDLE ControllerHandle,\r
136 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
137 )\r
138{\r
139 EFI_STATUS Status;\r
140 \r
141 //\r
142 // Try to open the DHCP4, HTTP4 and Device Path protocol.\r
143 //\r
144 Status = gBS->OpenProtocol (\r
145 ControllerHandle,\r
146 &gEfiDhcp4ServiceBindingProtocolGuid,\r
147 NULL,\r
148 This->DriverBindingHandle,\r
149 ControllerHandle,\r
150 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
151 );\r
152 if (EFI_ERROR (Status)) {\r
153 return Status;\r
154 }\r
155\r
156 Status = gBS->OpenProtocol (\r
157 ControllerHandle,\r
158 &gEfiHttpServiceBindingProtocolGuid,\r
159 NULL,\r
160 This->DriverBindingHandle,\r
161 ControllerHandle,\r
162 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
163 );\r
164 if (EFI_ERROR (Status)) {\r
165 return Status;\r
166 }\r
167\r
168 Status = gBS->OpenProtocol (\r
169 ControllerHandle,\r
170 &gEfiDevicePathProtocolGuid,\r
171 NULL,\r
172 This->DriverBindingHandle,\r
173 ControllerHandle,\r
174 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
175 );\r
176\r
177 return Status;\r
178}\r
179\r
180\r
181/**\r
182 Starts a device controller or a bus controller.\r
183\r
184 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
185 As a result, much of the error checking on the parameters to Start() has been moved into this \r
186 common boot service. It is legal to call Start() from other locations, \r
187 but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
188 1. ControllerHandle must be a valid EFI_HANDLE.\r
189 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
190 EFI_DEVICE_PATH_PROTOCOL.\r
191 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
192 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. \r
193\r
194 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
195 @param[in] ControllerHandle The handle of the controller to start. This handle \r
196 must support a protocol interface that supplies \r
197 an I/O abstraction to the driver.\r
198 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This \r
199 parameter is ignored by device drivers, and is optional for bus \r
200 drivers. For a bus driver, if this parameter is NULL, then handles \r
201 for all the children of Controller are created by this driver. \r
202 If this parameter is not NULL and the first Device Path Node is \r
203 not the End of Device Path Node, then only the handle for the \r
204 child device specified by the first Device Path Node of \r
205 RemainingDevicePath is created by this driver.\r
206 If the first Device Path Node of RemainingDevicePath is \r
207 the End of Device Path Node, no child handle is created by this\r
208 driver.\r
209\r
210 @retval EFI_SUCCESS The device was started.\r
211 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
212 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
213 @retval Others The driver failded to start the device.\r
214\r
215**/\r
216EFI_STATUS\r
217EFIAPI\r
218HttpBootIp4DxeDriverBindingStart (\r
219 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
220 IN EFI_HANDLE ControllerHandle,\r
221 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
222 )\r
223{\r
224 EFI_STATUS Status;\r
225 HTTP_BOOT_PRIVATE_DATA *Private;\r
226 EFI_DEV_PATH *Node;\r
227 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
228 UINT32 *Id;\r
229\r
230 Status = gBS->OpenProtocol (\r
231 ControllerHandle,\r
232 &gEfiCallerIdGuid,\r
233 (VOID **) &Id,\r
234 This->DriverBindingHandle,\r
235 ControllerHandle,\r
236 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
237 );\r
238 if (!EFI_ERROR (Status)) {\r
239 return EFI_ALREADY_STARTED;\r
240 }\r
241\r
242 //\r
243 // Initialize the private data structure.\r
244 //\r
245 Private = AllocateZeroPool (sizeof (HTTP_BOOT_PRIVATE_DATA));\r
246 if (Private == NULL) {\r
247 return EFI_OUT_OF_RESOURCES;\r
248 }\r
249 Private->Signature = HTTP_BOOT_PRIVATE_DATA_SIGNATURE;\r
250 Private->Controller = ControllerHandle;\r
251 Private->Image = This->ImageHandle;\r
252 Private->UsingIpv6 = FALSE;\r
253 InitializeListHead (&Private->CacheList);\r
254\r
255 //\r
256 // Create DHCP child instance.\r
257 //\r
258 Status = NetLibCreateServiceChild (\r
259 ControllerHandle,\r
260 This->DriverBindingHandle,\r
261 &gEfiDhcp4ServiceBindingProtocolGuid,\r
262 &Private->Dhcp4Child\r
263 );\r
264 if (EFI_ERROR (Status)) {\r
265 goto ON_ERROR;\r
266 }\r
267\r
268 Status = gBS->OpenProtocol (\r
269 Private->Dhcp4Child,\r
270 &gEfiDhcp4ProtocolGuid,\r
271 (VOID **) &Private->Dhcp4,\r
272 This->DriverBindingHandle,\r
273 ControllerHandle,\r
274 EFI_OPEN_PROTOCOL_BY_DRIVER\r
275 );\r
276 if (EFI_ERROR (Status)) {\r
277 goto ON_ERROR;\r
278 }\r
279\r
280 //\r
281 // Get the Ip4Config2 protocol, it's required to configure the default gateway address.\r
282 //\r
283 Status = gBS->OpenProtocol (\r
284 ControllerHandle,\r
285 &gEfiIp4Config2ProtocolGuid,\r
286 (VOID **) &Private->Ip4Config2,\r
287 This->DriverBindingHandle,\r
288 ControllerHandle,\r
289 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
290 );\r
291 if (EFI_ERROR (Status)) {\r
292 goto ON_ERROR;\r
293 }\r
294\r
295 //\r
296 // Get the NII interface if it exists, it's not required.\r
297 //\r
298 Status = gBS->OpenProtocol (\r
299 ControllerHandle,\r
300 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
301 (VOID **) &Private->Nii,\r
302 This->DriverBindingHandle,\r
303 ControllerHandle,\r
304 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
305 );\r
306 if (EFI_ERROR (Status)) {\r
307 Private->Nii = NULL;\r
308 }\r
309\r
310 //\r
311 // Open Device Path Protocol to prepare for appending IP and URI node.\r
312 //\r
313 Status = gBS->OpenProtocol (\r
314 ControllerHandle,\r
315 &gEfiDevicePathProtocolGuid,\r
316 (VOID **) &Private->ParentDevicePath,\r
317 This->DriverBindingHandle,\r
318 ControllerHandle,\r
319 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
320 );\r
321 if (EFI_ERROR (Status)) {\r
322 goto ON_ERROR;\r
323 }\r
324\r
325 //\r
326 // Append IPv4 device path node.\r
327 //\r
328 Node = AllocateZeroPool (sizeof (IPv4_DEVICE_PATH));\r
329 if (Node == NULL) {\r
330 Status = EFI_OUT_OF_RESOURCES;\r
331 goto ON_ERROR;\r
332 }\r
333 Node->Ipv4.Header.Type = MESSAGING_DEVICE_PATH;\r
334 Node->Ipv4.Header.SubType = MSG_IPv4_DP;\r
335 SetDevicePathNodeLength (Node, sizeof (IPv4_DEVICE_PATH));\r
336 Node->Ipv4.StaticIpAddress = FALSE;\r
337 DevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);\r
338 FreePool (Node);\r
339 if (DevicePath == NULL) {\r
340 Status = EFI_OUT_OF_RESOURCES;\r
341 goto ON_ERROR;\r
342 }\r
343\r
344 //\r
345 // Append URI device path node.\r
346 //\r
347 Node = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
348 if (Node == NULL) {\r
349 Status = EFI_OUT_OF_RESOURCES;\r
350 goto ON_ERROR;\r
351 }\r
352 Node->DevPath.Type = MESSAGING_DEVICE_PATH;\r
353 Node->DevPath.SubType = MSG_URI_DP;\r
354 SetDevicePathNodeLength (Node, sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
355 Private->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node);\r
356 FreePool (Node);\r
357 FreePool (DevicePath);\r
358 if (Private->DevicePath == NULL) {\r
359 Status = EFI_OUT_OF_RESOURCES;\r
360 goto ON_ERROR;\r
361 }\r
362\r
363 //\r
364 // Create a child handle for the HTTP boot and install DevPath and Load file protocol on it.\r
365 //\r
366 CopyMem (&Private->LoadFile, &gHttpBootDxeLoadFile, sizeof (Private->LoadFile));\r
367 Status = gBS->InstallMultipleProtocolInterfaces (\r
368 &Private->ChildHandle,\r
369 &gEfiLoadFileProtocolGuid,\r
370 &Private->LoadFile,\r
371 &gEfiDevicePathProtocolGuid,\r
372 Private->DevicePath,\r
373 NULL\r
374 );\r
375 if (EFI_ERROR (Status)) {\r
376 goto ON_ERROR;\r
377 }\r
378\r
379 //\r
380 // Install a protocol with Caller Id Guid to the NIC, this is just to build the relationship between\r
381 // NIC handle and the private data.\r
382 //\r
383 Status = gBS->InstallProtocolInterface (\r
384 &ControllerHandle,\r
385 &gEfiCallerIdGuid,\r
386 EFI_NATIVE_INTERFACE,\r
387 &Private->Id\r
388 );\r
389 if (EFI_ERROR (Status)) {\r
390 goto ON_ERROR;\r
391 }\r
392\r
393 //\r
394 // Open the Caller Id child to setup a parent-child relationship between\r
395 // real NIC handle and the HTTP boot child handle.\r
396 //\r
397 Status = gBS->OpenProtocol (\r
398 ControllerHandle,\r
399 &gEfiCallerIdGuid,\r
400 (VOID **) &Id,\r
401 This->DriverBindingHandle,\r
402 Private->ChildHandle,\r
403 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
404 );\r
405 if (EFI_ERROR (Status)) {\r
406 goto ON_ERROR;\r
407 }\r
408\r
409 return EFI_SUCCESS;\r
410\r
411ON_ERROR:\r
412 \r
413 HttpBootDestroyIp4Children (This, Private);\r
414 FreePool (Private);\r
415\r
416 return Status;\r
417}\r
418\r
419/**\r
420 Stops a device controller or a bus controller.\r
421 \r
422 The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
423 As a result, much of the error checking on the parameters to Stop() has been moved \r
424 into this common boot service. It is legal to call Stop() from other locations, \r
425 but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
426 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
427 same driver's Start() function.\r
428 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
429 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
430 Start() function, and the Start() function must have called OpenProtocol() on\r
431 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
432 \r
433 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
434 @param[in] ControllerHandle A handle to the device being stopped. The handle must \r
435 support a bus specific I/O protocol for the driver \r
436 to use to stop the device.\r
437 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
438 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL \r
439 if NumberOfChildren is 0.\r
440\r
441 @retval EFI_SUCCESS The device was stopped.\r
442 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
443\r
444**/\r
445EFI_STATUS\r
446EFIAPI\r
447HttpBootIp4DxeDriverBindingStop (\r
448 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
449 IN EFI_HANDLE ControllerHandle,\r
450 IN UINTN NumberOfChildren,\r
451 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
452 )\r
453{\r
454 EFI_STATUS Status;\r
455 EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
456 HTTP_BOOT_PRIVATE_DATA *Private;\r
457 EFI_HANDLE NicHandle;\r
458 UINT32 *Id;\r
459\r
460 //\r
461 // Try to get the Load File Protocol from the controller handle.\r
462 //\r
463 Status = gBS->OpenProtocol (\r
464 ControllerHandle,\r
465 &gEfiLoadFileProtocolGuid,\r
466 (VOID **) &LoadFile,\r
467 This->DriverBindingHandle,\r
468 ControllerHandle,\r
469 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
470 );\r
471 if (EFI_ERROR (Status)) {\r
472 //\r
473 // If failed, try to find the NIC handle for this controller.\r
474 //\r
475 NicHandle = HttpBootGetNicByIp4Children (ControllerHandle);\r
476 if (NicHandle == NULL) {\r
477 return EFI_SUCCESS;\r
478 }\r
479\r
480 //\r
481 // Try to retrieve the private data by the Caller Id Guid.\r
482 //\r
483 Status = gBS->OpenProtocol (\r
484 NicHandle,\r
485 &gEfiCallerIdGuid,\r
486 (VOID **) &Id,\r
487 This->DriverBindingHandle,\r
488 ControllerHandle,\r
489 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
490 );\r
491 if (EFI_ERROR (Status)) {\r
492 return Status;\r
493 }\r
494 Private = HTTP_BOOT_PRIVATE_DATA_FROM_ID (Id);\r
495 } else {\r
496 Private = HTTP_BOOT_PRIVATE_DATA_FROM_LOADFILE (LoadFile);\r
497 NicHandle = Private->Controller;\r
498 }\r
499\r
500 //\r
501 // Disable the HTTP boot function.\r
502 //\r
503 Status = HttpBootStop (Private);\r
504 if (Status != EFI_SUCCESS && Status != EFI_NOT_STARTED) {\r
505 return Status;\r
506 }\r
507\r
508 //\r
509 // Destory all child instance and uninstall protocol interface.\r
510 //\r
511 HttpBootDestroyIp4Children (This, Private);\r
512\r
513 //\r
514 // Release the cached data.\r
515 //\r
516 HttpBootFreeCacheList (Private);\r
517\r
518 gBS->UninstallProtocolInterface (\r
519 NicHandle,\r
520 &gEfiCallerIdGuid,\r
521 &Private->Id\r
522 );\r
523 FreePool (Private);\r
524\r
525 return EFI_SUCCESS;\r
526}\r
527\r
528/**\r
529 This is the declaration of an EFI image entry point. This entry point is\r
530 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
531 both device drivers and bus drivers.\r
532\r
533 @param[in] ImageHandle The firmware allocated handle for the UEFI image.\r
534 @param[in] SystemTable A pointer to the EFI System Table.\r
535\r
536 @retval EFI_SUCCESS The operation completed successfully.\r
537 @retval Others An unexpected error occurred.\r
538\r
539**/\r
540EFI_STATUS\r
541EFIAPI\r
542HttpBootDxeDriverEntryPoint (\r
543 IN EFI_HANDLE ImageHandle,\r
544 IN EFI_SYSTEM_TABLE *SystemTable\r
545 )\r
546{\r
547 //\r
548 // Install UEFI Driver Model protocol(s).\r
549 //\r
550 return EfiLibInstallDriverBindingComponentName2 (\r
551 ImageHandle,\r
552 SystemTable,\r
553 &gHttpBootIp4DxeDriverBinding,\r
554 ImageHandle,\r
555 &gHttpBootDxeComponentName,\r
556 &gHttpBootDxeComponentName2\r
557 );\r
558}\r
559\r