]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/HttpBootDxe/HttpBootImpl.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / HttpBootDxe / HttpBootImpl.c
CommitLineData
d933e70a
JW
1/** @file\r
2 The implementation of EFI_LOAD_FILE_PROTOCOL for UEFI HTTP boot.\r
3\r
f33d3994 4Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
44a7d08b 5(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
ecf98fbc 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
d933e70a
JW
7\r
8**/\r
9\r
10#include "HttpBootDxe.h"\r
11\r
95b5c32f
FS
12/**\r
13 Install HTTP Boot Callback Protocol if not installed before.\r
14\r
15 @param[in] Private Pointer to HTTP Boot private data.\r
16\r
c36b7b51 17 @retval EFI_SUCCESS HTTP Boot Callback Protocol installed successfully.\r
95b5c32f
FS
18 @retval Others Failed to install HTTP Boot Callback Protocol.\r
19\r
20**/\r
21EFI_STATUS\r
22HttpBootInstallCallback (\r
d1050b9d 23 IN HTTP_BOOT_PRIVATE_DATA *Private\r
95b5c32f
FS
24 )\r
25{\r
d1050b9d
MK
26 EFI_STATUS Status;\r
27 EFI_HANDLE ControllerHandle;\r
95b5c32f
FS
28\r
29 if (!Private->UsingIpv6) {\r
30 ControllerHandle = Private->Ip4Nic->Controller;\r
31 } else {\r
32 ControllerHandle = Private->Ip6Nic->Controller;\r
33 }\r
34\r
35 //\r
36 // Check whether gEfiHttpBootCallbackProtocolGuid already installed.\r
37 //\r
38 Status = gBS->HandleProtocol (\r
39 ControllerHandle,\r
40 &gEfiHttpBootCallbackProtocolGuid,\r
d1050b9d 41 (VOID **)&Private->HttpBootCallback\r
95b5c32f
FS
42 );\r
43 if (Status == EFI_UNSUPPORTED) {\r
95b5c32f
FS
44 CopyMem (\r
45 &Private->LoadFileCallback,\r
46 &gHttpBootDxeHttpBootCallback,\r
47 sizeof (EFI_HTTP_BOOT_CALLBACK_PROTOCOL)\r
48 );\r
49\r
50 //\r
51 // Install a default callback if user didn't offer one.\r
52 //\r
53 Status = gBS->InstallProtocolInterface (\r
54 &ControllerHandle,\r
55 &gEfiHttpBootCallbackProtocolGuid,\r
56 EFI_NATIVE_INTERFACE,\r
57 &Private->LoadFileCallback\r
58 );\r
59 if (EFI_ERROR (Status)) {\r
60 return Status;\r
61 }\r
d1050b9d 62\r
95b5c32f
FS
63 Private->HttpBootCallback = &Private->LoadFileCallback;\r
64 }\r
65\r
66 return EFI_SUCCESS;\r
67}\r
68\r
69/**\r
70 Uninstall HTTP Boot Callback Protocol if it's installed by this driver.\r
71\r
72 @param[in] Private Pointer to HTTP Boot private data.\r
73\r
74**/\r
75VOID\r
76HttpBootUninstallCallback (\r
d1050b9d 77 IN HTTP_BOOT_PRIVATE_DATA *Private\r
95b5c32f
FS
78 )\r
79{\r
80 if (Private->HttpBootCallback == &Private->LoadFileCallback) {\r
81 gBS->UninstallProtocolInterface (\r
d1050b9d
MK
82 Private->Controller,\r
83 &gEfiHttpBootCallbackProtocolGuid,\r
84 &Private->HttpBootCallback\r
85 );\r
95b5c32f
FS
86 Private->HttpBootCallback = NULL;\r
87 }\r
88}\r
89\r
d933e70a
JW
90/**\r
91 Enable the use of UEFI HTTP boot function.\r
92\r
f75a7f56 93 If the driver has already been started but not satisfy the requirement (IP stack and\r
587d204c
FS
94 specified boot file path), this function will stop the driver and start it again.\r
95\r
d933e70a 96 @param[in] Private The pointer to the driver's private data.\r
b659408b
ZL
97 @param[in] UsingIpv6 Specifies the type of IP addresses that are to be\r
98 used during the session that is being started.\r
99 Set to TRUE for IPv6, and FALSE for IPv4.\r
fa848a40 100 @param[in] FilePath The device specific path of the file to load.\r
d933e70a
JW
101\r
102 @retval EFI_SUCCESS HTTP boot was successfully enabled.\r
587d204c
FS
103 @retval EFI_INVALID_PARAMETER Private is NULL or FilePath is NULL.\r
104 @retval EFI_INVALID_PARAMETER The FilePath doesn't contain a valid URI device path node.\r
d933e70a 105 @retval EFI_ALREADY_STARTED The driver is already in started state.\r
fa848a40 106 @retval EFI_OUT_OF_RESOURCES There are not enough resources.\r
f75a7f56 107\r
d933e70a
JW
108**/\r
109EFI_STATUS\r
110HttpBootStart (\r
d1050b9d
MK
111 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
112 IN BOOLEAN UsingIpv6,\r
113 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
d933e70a
JW
114 )\r
115{\r
d1050b9d
MK
116 UINTN Index;\r
117 EFI_STATUS Status;\r
118 CHAR8 *Uri;\r
d933e70a 119\r
0dc59296 120 Uri = NULL;\r
f75a7f56 121\r
d1050b9d 122 if ((Private == NULL) || (FilePath == NULL)) {\r
d933e70a
JW
123 return EFI_INVALID_PARAMETER;\r
124 }\r
f75a7f56 125\r
587d204c
FS
126 //\r
127 // Check the URI in the input FilePath, in order to see whether it is\r
f75a7f56 128 // required to boot from a new specified boot file.\r
587d204c
FS
129 //\r
130 Status = HttpBootParseFilePath (FilePath, &Uri);\r
131 if (EFI_ERROR (Status)) {\r
132 return EFI_INVALID_PARAMETER;\r
133 }\r
f75a7f56 134\r
587d204c
FS
135 //\r
136 // Check whether we need to stop and restart the HTTP boot driver.\r
137 //\r
d933e70a 138 if (Private->Started) {\r
587d204c
FS
139 //\r
140 // Restart is needed in 2 cases:\r
141 // 1. Http boot driver has already been started but not on the required IP stack.\r
142 // 2. The specified boot file URI in FilePath is different with the one we have\r
143 // recorded before.\r
144 //\r
f75a7f56 145 if ((UsingIpv6 != Private->UsingIpv6) ||\r
d1050b9d
MK
146 ((Uri != NULL) && (AsciiStrCmp (Private->BootFileUri, Uri) != 0)))\r
147 {\r
587d204c
FS
148 //\r
149 // Restart is required, first stop then continue this start function.\r
150 //\r
151 Status = HttpBootStop (Private);\r
152 if (EFI_ERROR (Status)) {\r
0dc59296
JW
153 if (Uri != NULL) {\r
154 FreePool (Uri);\r
155 }\r
d1050b9d 156\r
587d204c
FS
157 return Status;\r
158 }\r
159 } else {\r
160 //\r
161 // Restart is not required.\r
162 //\r
163 if (Uri != NULL) {\r
164 FreePool (Uri);\r
165 }\r
d1050b9d 166\r
587d204c
FS
167 return EFI_ALREADY_STARTED;\r
168 }\r
d933e70a
JW
169 }\r
170\r
b659408b
ZL
171 //\r
172 // Detect whether using ipv6 or not, and set it to the private data.\r
173 //\r
d1050b9d 174 if (UsingIpv6 && (Private->Ip6Nic != NULL)) {\r
b659408b 175 Private->UsingIpv6 = TRUE;\r
d1050b9d 176 } else if (!UsingIpv6 && (Private->Ip4Nic != NULL)) {\r
b659408b
ZL
177 Private->UsingIpv6 = FALSE;\r
178 } else {\r
587d204c
FS
179 if (Uri != NULL) {\r
180 FreePool (Uri);\r
181 }\r
d1050b9d 182\r
b659408b
ZL
183 return EFI_UNSUPPORTED;\r
184 }\r
fa848a40
FS
185\r
186 //\r
587d204c 187 // Record the specified URI and prepare the URI parser if needed.\r
fa848a40 188 //\r
587d204c 189 Private->FilePathUri = Uri;\r
fa848a40
FS
190 if (Private->FilePathUri != NULL) {\r
191 Status = HttpParseUrl (\r
192 Private->FilePathUri,\r
d1050b9d 193 (UINT32)AsciiStrLen (Private->FilePathUri),\r
fa848a40
FS
194 FALSE,\r
195 &Private->FilePathUriParser\r
196 );\r
197 if (EFI_ERROR (Status)) {\r
587d204c 198 FreePool (Private->FilePathUri);\r
fa848a40
FS
199 return Status;\r
200 }\r
201 }\r
f75a7f56 202\r
b659408b
ZL
203 //\r
204 // Init the content of cached DHCP offer list.\r
205 //\r
206 ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer));\r
d933e70a 207 if (!Private->UsingIpv6) {\r
d933e70a 208 for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
632dcfd6 209 Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = HTTP_CACHED_DHCP4_PACKET_MAX_SIZE;\r
d933e70a
JW
210 }\r
211 } else {\r
b659408b 212 for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
632dcfd6 213 Private->OfferBuffer[Index].Dhcp6.Packet.Offer.Size = HTTP_CACHED_DHCP6_PACKET_MAX_SIZE;\r
b659408b 214 }\r
d933e70a
JW
215 }\r
216\r
b659408b
ZL
217 if (Private->UsingIpv6) {\r
218 //\r
219 // Set Ip6 policy to Automatic to start the Ip6 router discovery.\r
220 //\r
221 Status = HttpBootSetIp6Policy (Private);\r
222 if (EFI_ERROR (Status)) {\r
223 return Status;\r
224 }\r
225 }\r
d1050b9d
MK
226\r
227 Private->Started = TRUE;\r
95b5c32f 228 Print (L"\n>>Start HTTP Boot over IPv%d", Private->UsingIpv6 ? 6 : 4);\r
d933e70a
JW
229\r
230 return EFI_SUCCESS;\r
231}\r
232\r
233/**\r
b659408b 234 Attempt to complete a DHCPv4 D.O.R.A or DHCPv6 S.R.A.A sequence to retrieve the boot resource information.\r
d933e70a
JW
235\r
236 @param[in] Private The pointer to the driver's private data.\r
237\r
238 @retval EFI_SUCCESS Boot info was successfully retrieved.\r
239 @retval EFI_INVALID_PARAMETER Private is NULL.\r
240 @retval EFI_NOT_STARTED The driver is in stopped state.\r
241 @retval EFI_DEVICE_ERROR An unexpected network error occurred.\r
242 @retval Others Other errors as indicated.\r
f75a7f56 243\r
d933e70a
JW
244**/\r
245EFI_STATUS\r
246HttpBootDhcp (\r
d1050b9d 247 IN HTTP_BOOT_PRIVATE_DATA *Private\r
d933e70a
JW
248 )\r
249{\r
d1050b9d 250 EFI_STATUS Status;\r
d933e70a
JW
251\r
252 if (Private == NULL) {\r
253 return EFI_INVALID_PARAMETER;\r
254 }\r
f75a7f56 255\r
d933e70a
JW
256 if (!Private->Started) {\r
257 return EFI_NOT_STARTED;\r
258 }\r
259\r
260 Status = EFI_DEVICE_ERROR;\r
261\r
262 if (!Private->UsingIpv6) {\r
b659408b
ZL
263 //\r
264 // Start D.O.R.A process to get a IPv4 address and other boot information.\r
265 //\r
d933e70a
JW
266 Status = HttpBootDhcp4Dora (Private);\r
267 } else {\r
d1050b9d 268 //\r
b659408b
ZL
269 // Start S.A.R.R process to get a IPv6 address and other boot information.\r
270 //\r
271 Status = HttpBootDhcp6Sarr (Private);\r
d933e70a
JW
272 }\r
273\r
274 return Status;\r
275}\r
276\r
277/**\r
278 Attempt to download the boot file through HTTP message exchange.\r
279\r
280 @param[in] Private The pointer to the driver's private data.\r
281 @param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return\r
282 code of EFI_SUCCESS, the amount of data transferred to\r
283 Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,\r
284 the size of Buffer required to retrieve the requested file.\r
285 @param[in] Buffer The memory buffer to transfer the file to. If Buffer is NULL,\r
286 then the size of the requested file is returned in\r
287 BufferSize.\r
587d204c 288 @param[out] ImageType The image type of the downloaded file.\r
d933e70a
JW
289\r
290 @retval EFI_SUCCESS Boot file was loaded successfully.\r
587d204c
FS
291 @retval EFI_INVALID_PARAMETER Private is NULL, or ImageType is NULL, or BufferSize is NULL.\r
292 @retval EFI_INVALID_PARAMETER *BufferSize is not zero, and Buffer is NULL.\r
d933e70a 293 @retval EFI_NOT_STARTED The driver is in stopped state.\r
f75a7f56 294 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the boot file. BufferSize has\r
d933e70a
JW
295 been updated with the size needed to complete the request.\r
296 @retval EFI_DEVICE_ERROR An unexpected network error occurred.\r
297 @retval Others Other errors as indicated.\r
f75a7f56 298\r
d933e70a
JW
299**/\r
300EFI_STATUS\r
301HttpBootLoadFile (\r
d1050b9d
MK
302 IN HTTP_BOOT_PRIVATE_DATA *Private,\r
303 IN OUT UINTN *BufferSize,\r
304 IN VOID *Buffer OPTIONAL,\r
305 OUT HTTP_BOOT_IMAGE_TYPE *ImageType\r
d933e70a
JW
306 )\r
307{\r
d1050b9d 308 EFI_STATUS Status;\r
d933e70a 309\r
d1050b9d 310 if ((Private == NULL) || (ImageType == NULL) || (BufferSize == NULL)) {\r
587d204c
FS
311 return EFI_INVALID_PARAMETER;\r
312 }\r
313\r
d1050b9d 314 if ((*BufferSize != 0) && (Buffer == NULL)) {\r
d933e70a
JW
315 return EFI_INVALID_PARAMETER;\r
316 }\r
f75a7f56 317\r
d933e70a
JW
318 if (!Private->Started) {\r
319 return EFI_NOT_STARTED;\r
320 }\r
321\r
95b5c32f 322 Status = HttpBootInstallCallback (Private);\r
d1050b9d 323 if (EFI_ERROR (Status)) {\r
95b5c32f
FS
324 goto ON_EXIT;\r
325 }\r
d933e70a
JW
326\r
327 if (Private->BootFileUri == NULL) {\r
328 //\r
329 // Parse the cached offer to get the boot file URL first.\r
330 //\r
331 Status = HttpBootDiscoverBootInfo (Private);\r
332 if (EFI_ERROR (Status)) {\r
f33d3994 333 AsciiPrint ("\n Error: Could not retrieve NBP file size from HTTP server.\n");\r
95b5c32f 334 goto ON_EXIT;\r
d933e70a
JW
335 }\r
336 }\r
337\r
338 if (!Private->HttpCreated) {\r
339 //\r
340 // Create HTTP child.\r
341 //\r
342 Status = HttpBootCreateHttpIo (Private);\r
343 if (EFI_ERROR (Status)) {\r
95b5c32f 344 goto ON_EXIT;\r
d933e70a
JW
345 }\r
346 }\r
347\r
348 if (Private->BootFileSize == 0) {\r
349 //\r
350 // Discover the information about the bootfile if we haven't.\r
351 //\r
352\r
353 //\r
354 // Try to use HTTP HEAD method.\r
355 //\r
356 Status = HttpBootGetBootFile (\r
357 Private,\r
358 TRUE,\r
359 &Private->BootFileSize,\r
587d204c 360 NULL,\r
44a7d08b 361 &Private->ImageType\r
d933e70a 362 );\r
671b0cea
SK
363 if ((Private->AuthData != NULL) && (Status == EFI_ACCESS_DENIED)) {\r
364 //\r
365 // Try to use HTTP HEAD method again since the Authentication information is provided.\r
366 //\r
367 Status = HttpBootGetBootFile (\r
368 Private,\r
369 TRUE,\r
370 &Private->BootFileSize,\r
371 NULL,\r
372 &Private->ImageType\r
373 );\r
374 } else if ((EFI_ERROR (Status)) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
d933e70a
JW
375 //\r
376 // Failed to get file size by HEAD method, may be trunked encoding, try HTTP GET method.\r
377 //\r
378 ASSERT (Private->BootFileSize == 0);\r
379 Status = HttpBootGetBootFile (\r
380 Private,\r
381 FALSE,\r
382 &Private->BootFileSize,\r
587d204c 383 NULL,\r
44a7d08b 384 &Private->ImageType\r
d933e70a 385 );\r
d1050b9d 386 if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
fca04738 387 AsciiPrint ("\n Error: Could not retrieve NBP file size from HTTP server.\n");\r
95b5c32f 388 goto ON_EXIT;\r
d933e70a
JW
389 }\r
390 }\r
391 }\r
392\r
393 if (*BufferSize < Private->BootFileSize) {\r
394 *BufferSize = Private->BootFileSize;\r
d1050b9d
MK
395 *ImageType = Private->ImageType;\r
396 Status = EFI_BUFFER_TOO_SMALL;\r
95b5c32f 397 goto ON_EXIT;\r
d933e70a
JW
398 }\r
399\r
400 //\r
401 // Load the boot file into Buffer\r
402 //\r
95b5c32f
FS
403 Status = HttpBootGetBootFile (\r
404 Private,\r
405 FALSE,\r
406 BufferSize,\r
407 Buffer,\r
408 ImageType\r
409 );\r
f75a7f56 410\r
95b5c32f
FS
411ON_EXIT:\r
412 HttpBootUninstallCallback (Private);\r
f75a7f56 413\r
f33d3994
JW
414 if (EFI_ERROR (Status)) {\r
415 if (Status == EFI_ACCESS_DENIED) {\r
416 AsciiPrint ("\n Error: Could not establish connection with HTTP server.\n");\r
d1050b9d 417 } else if ((Status == EFI_BUFFER_TOO_SMALL) && (Buffer != NULL)) {\r
f33d3994
JW
418 AsciiPrint ("\n Error: Buffer size is smaller than the requested file.\n");\r
419 } else if (Status == EFI_OUT_OF_RESOURCES) {\r
420 AsciiPrint ("\n Error: Could not allocate I/O buffers.\n");\r
421 } else if (Status == EFI_DEVICE_ERROR) {\r
422 AsciiPrint ("\n Error: Network device error.\n");\r
423 } else if (Status == EFI_TIMEOUT) {\r
424 AsciiPrint ("\n Error: Server response timeout.\n");\r
425 } else if (Status == EFI_ABORTED) {\r
426 AsciiPrint ("\n Error: Remote boot cancelled.\n");\r
427 } else if (Status != EFI_BUFFER_TOO_SMALL) {\r
428 AsciiPrint ("\n Error: Unexpected network error.\n");\r
429 }\r
fca04738 430 }\r
f75a7f56 431\r
95b5c32f 432 return Status;\r
d933e70a
JW
433}\r
434\r
435/**\r
436 Disable the use of UEFI HTTP boot function.\r
437\r
438 @param[in] Private The pointer to the driver's private data.\r
439\r
440 @retval EFI_SUCCESS HTTP boot was successfully disabled.\r
441 @retval EFI_NOT_STARTED The driver is already in stopped state.\r
442 @retval EFI_INVALID_PARAMETER Private is NULL.\r
443 @retval Others Unexpected error when stop the function.\r
f75a7f56 444\r
d933e70a
JW
445**/\r
446EFI_STATUS\r
447HttpBootStop (\r
d1050b9d 448 IN HTTP_BOOT_PRIVATE_DATA *Private\r
d933e70a
JW
449 )\r
450{\r
d1050b9d 451 UINTN Index;\r
d933e70a
JW
452\r
453 if (Private == NULL) {\r
454 return EFI_INVALID_PARAMETER;\r
455 }\r
f75a7f56 456\r
d933e70a
JW
457 if (!Private->Started) {\r
458 return EFI_NOT_STARTED;\r
459 }\r
f75a7f56 460\r
d933e70a
JW
461 if (Private->HttpCreated) {\r
462 HttpIoDestroyIo (&Private->HttpIo);\r
463 Private->HttpCreated = FALSE;\r
464 }\r
f75a7f56 465\r
d933e70a
JW
466 Private->Started = FALSE;\r
467 ZeroMem (&Private->StationIp, sizeof (EFI_IP_ADDRESS));\r
468 ZeroMem (&Private->SubnetMask, sizeof (EFI_IP_ADDRESS));\r
469 ZeroMem (&Private->GatewayIp, sizeof (EFI_IP_ADDRESS));\r
d1050b9d
MK
470 Private->Port = 0;\r
471 Private->BootFileUri = NULL;\r
d933e70a 472 Private->BootFileUriParser = NULL;\r
d1050b9d
MK
473 Private->BootFileSize = 0;\r
474 Private->SelectIndex = 0;\r
475 Private->SelectProxyType = HttpOfferTypeMax;\r
d933e70a
JW
476\r
477 if (!Private->UsingIpv6) {\r
478 //\r
479 // Stop and release the DHCP4 child.\r
480 //\r
481 Private->Dhcp4->Stop (Private->Dhcp4);\r
482 Private->Dhcp4->Configure (Private->Dhcp4, NULL);\r
483\r
484 for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
485 if (Private->OfferBuffer[Index].Dhcp4.UriParser) {\r
486 HttpUrlFreeParser (Private->OfferBuffer[Index].Dhcp4.UriParser);\r
487 }\r
488 }\r
489 } else {\r
b659408b
ZL
490 //\r
491 // Stop and release the DHCP6 child.\r
492 //\r
493 Private->Dhcp6->Stop (Private->Dhcp6);\r
494 Private->Dhcp6->Configure (Private->Dhcp6, NULL);\r
f75a7f56 495\r
b659408b
ZL
496 for (Index = 0; Index < HTTP_BOOT_OFFER_MAX_NUM; Index++) {\r
497 if (Private->OfferBuffer[Index].Dhcp6.UriParser) {\r
498 HttpUrlFreeParser (Private->OfferBuffer[Index].Dhcp6.UriParser);\r
499 }\r
500 }\r
d933e70a 501 }\r
fa848a40 502\r
671b0cea
SK
503 if (Private->AuthData != NULL) {\r
504 FreePool (Private->AuthData);\r
505 Private->AuthData = NULL;\r
506 }\r
507\r
508 if (Private->AuthScheme != NULL) {\r
509 FreePool (Private->AuthScheme);\r
510 Private->AuthScheme = NULL;\r
511 }\r
512\r
7b1dbd15
JW
513 if (Private->DnsServerIp != NULL) {\r
514 FreePool (Private->DnsServerIp);\r
515 Private->DnsServerIp = NULL;\r
516 }\r
517\r
d1050b9d 518 if (Private->FilePathUri != NULL) {\r
fa848a40
FS
519 FreePool (Private->FilePathUri);\r
520 HttpUrlFreeParser (Private->FilePathUriParser);\r
d1050b9d 521 Private->FilePathUri = NULL;\r
fa848a40
FS
522 Private->FilePathUriParser = NULL;\r
523 }\r
f75a7f56 524\r
d933e70a
JW
525 ZeroMem (Private->OfferBuffer, sizeof (Private->OfferBuffer));\r
526 Private->OfferNum = 0;\r
527 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));\r
528 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));\r
f75a7f56 529\r
fa848a40 530 HttpBootFreeCacheList (Private);\r
f75a7f56 531\r
d933e70a
JW
532 return EFI_SUCCESS;\r
533}\r
534\r
535/**\r
536 Causes the driver to load a specified file.\r
537\r
538 @param This Protocol instance pointer.\r
539 @param FilePath The device specific path of the file to load.\r
540 @param BootPolicy If TRUE, indicates that the request originates from the\r
541 boot manager is attempting to load FilePath as a boot\r
542 selection. If FALSE, then FilePath must match as exact file\r
543 to be loaded.\r
544 @param BufferSize On input the size of Buffer in bytes. On output with a return\r
545 code of EFI_SUCCESS, the amount of data transferred to\r
546 Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,\r
547 the size of Buffer required to retrieve the requested file.\r
548 @param Buffer The memory buffer to transfer the file to. IF Buffer is NULL,\r
549 then the size of the requested file is returned in\r
550 BufferSize.\r
551\r
552 @retval EFI_SUCCESS The file was loaded.\r
553 @retval EFI_UNSUPPORTED The device does not support the provided BootPolicy\r
554 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or\r
555 BufferSize is NULL.\r
556 @retval EFI_NO_MEDIA No medium was present to load the file.\r
557 @retval EFI_DEVICE_ERROR The file was not loaded due to a device error.\r
558 @retval EFI_NO_RESPONSE The remote system did not respond.\r
559 @retval EFI_NOT_FOUND The file was not found.\r
560 @retval EFI_ABORTED The file load process was manually cancelled.\r
561 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.\r
562 BufferSize has been updated with the size needed to complete\r
563 the request.\r
564\r
565**/\r
566EFI_STATUS\r
567EFIAPI\r
568HttpBootDxeLoadFile (\r
d1050b9d
MK
569 IN EFI_LOAD_FILE_PROTOCOL *This,\r
570 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
571 IN BOOLEAN BootPolicy,\r
572 IN OUT UINTN *BufferSize,\r
573 IN VOID *Buffer OPTIONAL\r
d933e70a
JW
574 )\r
575{\r
d1050b9d
MK
576 HTTP_BOOT_PRIVATE_DATA *Private;\r
577 HTTP_BOOT_VIRTUAL_NIC *VirtualNic;\r
578 EFI_STATUS MediaStatus;\r
579 BOOLEAN UsingIpv6;\r
580 EFI_STATUS Status;\r
581 HTTP_BOOT_IMAGE_TYPE ImageType;\r
582\r
583 if ((This == NULL) || (BufferSize == NULL) || (FilePath == NULL)) {\r
d933e70a
JW
584 return EFI_INVALID_PARAMETER;\r
585 }\r
586\r
587 //\r
588 // Only support BootPolicy\r
589 //\r
590 if (!BootPolicy) {\r
591 return EFI_UNSUPPORTED;\r
592 }\r
593\r
b659408b 594 VirtualNic = HTTP_BOOT_VIRTUAL_NIC_FROM_LOADFILE (This);\r
d1050b9d 595 Private = VirtualNic->Private;\r
f75a7f56 596\r
d933e70a
JW
597 //\r
598 // Check media status before HTTP boot start\r
599 //\r
152f2d5e 600 MediaStatus = EFI_SUCCESS;\r
601 NetLibDetectMediaWaitTimeout (Private->Controller, HTTP_BOOT_CHECK_MEDIA_WAITING_TIME, &MediaStatus);\r
602 if (MediaStatus != EFI_SUCCESS) {\r
fca04738 603 AsciiPrint ("\n Error: Could not detect network connection.\n");\r
d933e70a
JW
604 return EFI_NO_MEDIA;\r
605 }\r
f75a7f56 606\r
b659408b
ZL
607 //\r
608 // Check whether the virtual nic is using IPv6 or not.\r
609 //\r
fa848a40 610 UsingIpv6 = FALSE;\r
b659408b
ZL
611 if (VirtualNic == Private->Ip6Nic) {\r
612 UsingIpv6 = TRUE;\r
613 }\r
fa848a40 614\r
d933e70a 615 //\r
fa848a40 616 // Initialize HTTP boot.\r
d933e70a 617 //\r
fa848a40 618 Status = HttpBootStart (Private, UsingIpv6, FilePath);\r
d1050b9d 619 if ((Status != EFI_SUCCESS) && (Status != EFI_ALREADY_STARTED)) {\r
587d204c 620 return Status;\r
b659408b 621 }\r
f75a7f56 622\r
fa848a40
FS
623 //\r
624 // Load the boot file.\r
625 //\r
587d204c 626 ImageType = ImageTypeMax;\r
d1050b9d 627 Status = HttpBootLoadFile (Private, BufferSize, Buffer, &ImageType);\r
587d204c 628 if (EFI_ERROR (Status)) {\r
d1050b9d 629 if ((Status == EFI_BUFFER_TOO_SMALL) && ((ImageType == ImageTypeVirtualCd) || (ImageType == ImageTypeVirtualDisk))) {\r
587d204c
FS
630 Status = EFI_WARN_FILE_SYSTEM;\r
631 } else if (Status != EFI_BUFFER_TOO_SMALL) {\r
632 HttpBootStop (Private);\r
633 }\r
d1050b9d 634\r
587d204c 635 return Status;\r
d933e70a
JW
636 }\r
637\r
587d204c
FS
638 //\r
639 // Register the RAM Disk to the system if needed.\r
640 //\r
d1050b9d 641 if ((ImageType == ImageTypeVirtualCd) || (ImageType == ImageTypeVirtualDisk)) {\r
587d204c
FS
642 Status = HttpBootRegisterRamDisk (Private, *BufferSize, Buffer, ImageType);\r
643 if (!EFI_ERROR (Status)) {\r
644 Status = EFI_WARN_FILE_SYSTEM;\r
fca04738
FS
645 } else {\r
646 AsciiPrint ("\n Error: Could not register RAM disk to the system.\n");\r
b659408b 647 }\r
d933e70a 648 }\r
287f05cd
FS
649\r
650 //\r
651 // Stop the HTTP Boot service after the boot image is downloaded.\r
652 //\r
653 HttpBootStop (Private);\r
d933e70a
JW
654 return Status;\r
655}\r
656\r
657///\r
658/// Load File Protocol instance\r
659///\r
f75a7f56 660GLOBAL_REMOVE_IF_UNREFERENCED\r
d933e70a
JW
661EFI_LOAD_FILE_PROTOCOL gHttpBootDxeLoadFile = {\r
662 HttpBootDxeLoadFile\r
663};\r
95b5c32f
FS
664\r
665/**\r
666 Callback function that is invoked when the HTTP Boot driver is about to transmit or has received a\r
667 packet.\r
668\r
669 This function is invoked when the HTTP Boot driver is about to transmit or has received packet.\r
670 Parameters DataType and Received specify the type of event and the format of the buffer pointed\r
671 to by Data. Due to the polling nature of UEFI device drivers, this callback function should not\r
672 execute for more than 5 ms.\r
673 The returned status code determines the behavior of the HTTP Boot driver.\r
674\r
675 @param[in] This Pointer to the EFI_HTTP_BOOT_CALLBACK_PROTOCOL instance.\r
676 @param[in] DataType The event that occurs in the current state.\r
677 @param[in] Received TRUE if the callback is being invoked due to a receive event.\r
678 FALSE if the callback is being invoked due to a transmit event.\r
679 @param[in] DataLength The length in bytes of the buffer pointed to by Data.\r
680 @param[in] Data A pointer to the buffer of data, the data type is specified by\r
681 DataType.\r
f75a7f56 682\r
95b5c32f
FS
683 @retval EFI_SUCCESS Tells the HTTP Boot driver to continue the HTTP Boot process.\r
684 @retval EFI_ABORTED Tells the HTTP Boot driver to abort the current HTTP Boot process.\r
685**/\r
686EFI_STATUS\r
3858c58a 687EFIAPI\r
95b5c32f 688HttpBootCallback (\r
d1050b9d
MK
689 IN EFI_HTTP_BOOT_CALLBACK_PROTOCOL *This,\r
690 IN EFI_HTTP_BOOT_CALLBACK_DATA_TYPE DataType,\r
691 IN BOOLEAN Received,\r
692 IN UINT32 DataLength,\r
693 IN VOID *Data OPTIONAL\r
95b5c32f
FS
694 )\r
695{\r
696 EFI_HTTP_MESSAGE *HttpMessage;\r
697 EFI_HTTP_HEADER *HttpHeader;\r
698 HTTP_BOOT_PRIVATE_DATA *Private;\r
699 UINT32 Percentage;\r
700\r
d1050b9d 701 Private = HTTP_BOOT_PRIVATE_DATA_FROM_CALLBACK_PROTOCOL (This);\r
95b5c32f
FS
702\r
703 switch (DataType) {\r
d1050b9d
MK
704 case HttpBootDhcp4:\r
705 case HttpBootDhcp6:\r
706 Print (L".");\r
707 break;\r
708\r
709 case HttpBootHttpRequest:\r
710 if (Data != NULL) {\r
711 HttpMessage = (EFI_HTTP_MESSAGE *)Data;\r
712 if ((HttpMessage->Data.Request->Method == HttpMethodGet) &&\r
713 (HttpMessage->Data.Request->Url != NULL))\r
714 {\r
715 Print (L"\n URI: %s\n", HttpMessage->Data.Request->Url);\r
716 }\r
717 }\r
718\r
719 break;\r
720\r
721 case HttpBootHttpResponse:\r
722 if (Data != NULL) {\r
723 HttpMessage = (EFI_HTTP_MESSAGE *)Data;\r
724\r
725 if (HttpMessage->Data.Response != NULL) {\r
726 if (HttpBootIsHttpRedirectStatusCode (HttpMessage->Data.Response->StatusCode)) {\r
727 //\r
728 // Server indicates the resource has been redirected to a different URL\r
729 // according to the section 6.4 of RFC7231 and the RFC 7538.\r
730 // Display the redirect information on the screen.\r
731 //\r
732 HttpHeader = HttpFindHeader (\r
733 HttpMessage->HeaderCount,\r
734 HttpMessage->Headers,\r
735 HTTP_HEADER_LOCATION\r
736 );\r
737 if (HttpHeader != NULL) {\r
738 Print (L"\n HTTP ERROR: Resource Redirected.\n New Location: %a\n", HttpHeader->FieldValue);\r
739 }\r
740\r
741 break;\r
742 }\r
743 }\r
744\r
745 HttpHeader = HttpFindHeader (\r
746 HttpMessage->HeaderCount,\r
747 HttpMessage->Headers,\r
748 HTTP_HEADER_CONTENT_LENGTH\r
749 );\r
750 if (HttpHeader != NULL) {\r
751 Private->FileSize = AsciiStrDecimalToUintn (HttpHeader->FieldValue);\r
752 Private->ReceivedSize = 0;\r
753 Private->Percentage = 0;\r
754 }\r
95b5c32f 755 }\r
95b5c32f 756\r
d1050b9d 757 break;\r
f75a7f56 758\r
d1050b9d
MK
759 case HttpBootHttpEntityBody:\r
760 if (DataLength != 0) {\r
761 if (Private->FileSize != 0) {\r
bb4831c0 762 //\r
d1050b9d 763 // We already know the file size, print in percentage format.\r
bb4831c0 764 //\r
d1050b9d
MK
765 if (Private->ReceivedSize == 0) {\r
766 Print (L" File Size: %lu Bytes\n", Private->FileSize);\r
bb4831c0 767 }\r
f75a7f56 768\r
d1050b9d
MK
769 Private->ReceivedSize += DataLength;\r
770 Percentage = (UINT32)DivU64x64Remainder (MultU64x32 (Private->ReceivedSize, 100), Private->FileSize, NULL);\r
771 if (Private->Percentage != Percentage) {\r
772 Private->Percentage = Percentage;\r
773 Print (L"\r Downloading...%d%%", Percentage);\r
774 }\r
775 } else {\r
776 //\r
777 // In some case we couldn't get the file size from the HTTP header, so we\r
778 // just print the downloaded file size.\r
779 //\r
780 Private->ReceivedSize += DataLength;\r
781 Print (L"\r Downloading...%lu Bytes", Private->ReceivedSize);\r
95b5c32f 782 }\r
95b5c32f 783 }\r
95b5c32f 784\r
d1050b9d
MK
785 break;\r
786\r
787 default:\r
788 break;\r
789 }\r
95b5c32f
FS
790\r
791 return EFI_SUCCESS;\r
792}\r
793\r
794///\r
795/// HTTP Boot Callback Protocol instance\r
796///\r
f75a7f56 797GLOBAL_REMOVE_IF_UNREFERENCED\r
95b5c32f
FS
798EFI_HTTP_BOOT_CALLBACK_PROTOCOL gHttpBootDxeHttpBootCallback = {\r
799 HttpBootCallback\r
800};\r