]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c
UefiCpuPkg/PiSmmCpuDxeSmm: patch "gSmiCr3" with PatchInstructionX86()
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcBoot.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Boot functions implementation for UefiPxeBc Driver.\r
3\r
b4815479 4 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
93aea44f 5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
a3bcde70
HT
6\r
7 This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php.\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "PxeBcImpl.h"\r
18\r
19\r
20/**\r
21 Display the string of the boot item.\r
22\r
23 If the length of the boot item string beyond 70 Char, just display 70 Char.\r
24\r
25 @param[in] Str The pointer to the string.\r
26 @param[in] Len The length of the string.\r
27\r
28**/\r
29VOID\r
30PxeBcDisplayBootItem (\r
31 IN UINT8 *Str,\r
32 IN UINT8 Len\r
33 )\r
34{\r
35 UINT8 Tmp;\r
36\r
37 //\r
38 // Cut off the chars behind 70th.\r
39 //\r
40 Len = (UINT8) MIN (PXEBC_DISPLAY_MAX_LINE, Len);\r
41 Tmp = Str[Len];\r
42 Str[Len] = 0;\r
43 AsciiPrint ("%a \n", Str);\r
44\r
45 //\r
46 // Restore the original 70th char.\r
47 //\r
48 Str[Len] = Tmp;\r
49}\r
50\r
51\r
52/**\r
53 Select and maintain the boot prompt if needed.\r
54\r
55 @param[in] Private Pointer to PxeBc private data.\r
56\r
57 @retval EFI_SUCCESS Selected boot prompt done.\r
58 @retval EFI_TIMEOUT Selected boot prompt timed out.\r
59 @retval EFI_NOT_FOUND The proxy offer is not Pxe10.\r
60 @retval EFI_ABORTED User cancelled the operation.\r
61 @retval EFI_NOT_READY Reading the input key from the keyboard has not finish.\r
62\r
63**/\r
64EFI_STATUS\r
65PxeBcSelectBootPrompt (\r
66 IN PXEBC_PRIVATE_DATA *Private\r
67 )\r
68{\r
69 PXEBC_DHCP_PACKET_CACHE *Cache;\r
70 PXEBC_VENDOR_OPTION *VendorOpt;\r
71 EFI_PXE_BASE_CODE_MODE *Mode;\r
72 EFI_EVENT TimeoutEvent;\r
73 EFI_EVENT DescendEvent;\r
74 EFI_INPUT_KEY InputKey;\r
75 EFI_STATUS Status;\r
76 UINT32 OfferType;\r
77 UINT8 Timeout;\r
78 UINT8 *Prompt;\r
79 UINT8 PromptLen;\r
80 INT32 SecCol;\r
81 INT32 SecRow;\r
82\r
83 TimeoutEvent = NULL;\r
84 DescendEvent = NULL;\r
85 Mode = Private->PxeBc.Mode;\r
86 Cache = Mode->ProxyOfferReceived ? &Private->ProxyOffer : &Private->DhcpAck;\r
87 OfferType = Mode->UsingIpv6 ? Cache->Dhcp6.OfferType : Cache->Dhcp4.OfferType;\r
88\r
89 //\r
9063c328 90 // Only DhcpPxe10 and ProxyPxe10 offer needs boot prompt.\r
a3bcde70 91 //\r
9063c328 92 if (OfferType != PxeOfferTypeProxyPxe10 && OfferType != PxeOfferTypeDhcpPxe10) {\r
a3bcde70
HT
93 return EFI_NOT_FOUND;\r
94 }\r
95\r
96 //\r
97 // There is no specified ProxyPxe10 for IPv6 in PXE and UEFI spec.\r
98 //\r
99 ASSERT (!Mode->UsingIpv6);\r
100\r
101 VendorOpt = &Cache->Dhcp4.VendorOpt;\r
30a95d4d 102 //\r
103 // According to the PXE specification 2.1, Table 2-1 PXE DHCP Options,\r
104 // we must not consider a boot prompt or boot menu if all of the following hold:\r
105 // - the PXE_DISCOVERY_CONTROL tag(6) is present inside the Vendor Options(43), and has bit 3 set \r
106 // - a boot file name has been presented in the initial DHCP or ProxyDHCP offer packet.\r
107 //\r
108 if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) &&\r
109 Cache->Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
110 return EFI_ABORTED;\r
111 }\r
112 \r
a3bcde70 113 if (!IS_VALID_BOOT_PROMPT (VendorOpt->BitMap)) {\r
9063c328 114 return EFI_TIMEOUT;\r
a3bcde70
HT
115 }\r
116\r
117 Timeout = VendorOpt->MenuPrompt->Timeout;\r
118 Prompt = VendorOpt->MenuPrompt->Prompt;\r
119 PromptLen = (UINT8) (VendorOpt->MenuPromptLen - 1);\r
120\r
121 //\r
122 // The valid scope of Timeout refers to PXE2.1 spec.\r
123 //\r
124 if (Timeout == 0) {\r
9063c328 125 return EFI_TIMEOUT;\r
a3bcde70
HT
126 }\r
127 if (Timeout == 255) {\r
9063c328 128 return EFI_SUCCESS;\r
a3bcde70
HT
129 }\r
130\r
131 //\r
132 // Create and start a timer as timeout event.\r
133 //\r
134 Status = gBS->CreateEvent (\r
135 EVT_TIMER,\r
136 TPL_CALLBACK,\r
137 NULL,\r
138 NULL,\r
139 &TimeoutEvent\r
140 );\r
141 if (EFI_ERROR (Status)) {\r
142 return Status;\r
143 }\r
144\r
145 Status = gBS->SetTimer (\r
146 TimeoutEvent,\r
147 TimerRelative,\r
b4815479 148 MultU64x32 (Timeout, TICKS_PER_SECOND)\r
a3bcde70
HT
149 );\r
150 if (EFI_ERROR (Status)) {\r
151 goto ON_EXIT;\r
152 }\r
153\r
154 //\r
155 // Create and start a periodic timer as descend event by second.\r
156 //\r
157 Status = gBS->CreateEvent (\r
158 EVT_TIMER,\r
159 TPL_CALLBACK,\r
160 NULL,\r
161 NULL,\r
162 &DescendEvent\r
163 );\r
164 if (EFI_ERROR (Status)) {\r
165 goto ON_EXIT;\r
166 }\r
167\r
168 Status = gBS->SetTimer (\r
169 DescendEvent,\r
170 TimerPeriodic,\r
171 TICKS_PER_SECOND\r
172 );\r
173 if (EFI_ERROR (Status)) {\r
174 goto ON_EXIT;\r
175 }\r
176\r
177 //\r
178 // Display the boot item and cursor on the screen.\r
179 //\r
180 SecCol = gST->ConOut->Mode->CursorColumn;\r
181 SecRow = gST->ConOut->Mode->CursorRow;\r
182\r
183 PxeBcDisplayBootItem (Prompt, PromptLen);\r
184\r
185 gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);\r
186 AsciiPrint ("(%d) ", Timeout--);\r
187\r
9063c328 188 Status = EFI_TIMEOUT;\r
a3bcde70
HT
189 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
190 if (!EFI_ERROR (gBS->CheckEvent (DescendEvent))) {\r
191 gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);\r
192 AsciiPrint ("(%d) ", Timeout--);\r
193 }\r
194 if (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {\r
195 gBS->Stall (10 * TICKS_PER_MS);\r
196 continue;\r
197 }\r
198 //\r
199 // Parse the input key by user.\r
9063c328 200 // If <F8> or <Ctrl> + <M> is pressed, return success to display the boot menu.\r
a3bcde70
HT
201 //\r
202 if (InputKey.ScanCode == 0) {\r
203\r
204 switch (InputKey.UnicodeChar) {\r
205\r
206 case CTRL ('c'):\r
207 Status = EFI_ABORTED;\r
208 break;\r
209\r
210 case CTRL ('m'):\r
211 case 'm':\r
212 case 'M':\r
9063c328 213 Status = EFI_SUCCESS;\r
a3bcde70
HT
214 break;\r
215\r
216 default:\r
217 continue;\r
218 }\r
219\r
220 } else {\r
221\r
222 switch (InputKey.ScanCode) {\r
223\r
224 case SCAN_F8:\r
9063c328 225 Status = EFI_SUCCESS;\r
a3bcde70
HT
226 break;\r
227\r
228 case SCAN_ESC:\r
229 Status = EFI_ABORTED;\r
230 break;\r
231\r
232 default:\r
233 continue;\r
234 }\r
235 }\r
236\r
237 break;\r
238 }\r
239\r
240 //\r
241 // Reset the cursor on the screen.\r
242 //\r
243 gST->ConOut->SetCursorPosition (gST->ConOut, 0 , SecRow + 1);\r
244\r
245ON_EXIT:\r
246 if (DescendEvent != NULL) {\r
247 gBS->CloseEvent (DescendEvent);\r
248 }\r
249 if (TimeoutEvent != NULL) {\r
250 gBS->CloseEvent (TimeoutEvent);\r
251 }\r
252\r
253 return Status;\r
254}\r
255\r
256\r
257/**\r
258 Select the boot menu by user's input.\r
259\r
260 @param[in] Private Pointer to PxeBc private data.\r
261 @param[out] Type The type of the menu.\r
262 @param[in] UseDefaultItem Use default item or not.\r
263\r
264 @retval EFI_ABORTED User cancel operation.\r
265 @retval EFI_SUCCESS Select the boot menu success.\r
266 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.\r
267\r
268**/\r
269EFI_STATUS\r
270PxeBcSelectBootMenu (\r
271 IN PXEBC_PRIVATE_DATA *Private,\r
272 OUT UINT16 *Type,\r
273 IN BOOLEAN UseDefaultItem\r
274 )\r
275{\r
276 EFI_PXE_BASE_CODE_MODE *Mode;\r
277 PXEBC_DHCP_PACKET_CACHE *Cache;\r
278 PXEBC_VENDOR_OPTION *VendorOpt;\r
279 EFI_INPUT_KEY InputKey;\r
280 UINT32 OfferType;\r
281 UINT8 MenuSize;\r
282 UINT8 MenuNum;\r
283 INT32 TopRow;\r
284 UINT16 Select;\r
285 UINT16 LastSelect;\r
286 UINT8 Index;\r
287 BOOLEAN Finish;\r
288 CHAR8 Blank[PXEBC_DISPLAY_MAX_LINE];\r
289 PXEBC_BOOT_MENU_ENTRY *MenuItem;\r
290 PXEBC_BOOT_MENU_ENTRY *MenuArray[PXEBC_MENU_MAX_NUM];\r
291\r
292 Finish = FALSE;\r
a1c0d0fb 293 Select = 0;\r
a3bcde70
HT
294 Index = 0;\r
295 *Type = 0;\r
296 Mode = Private->PxeBc.Mode;\r
297 Cache = Mode->ProxyOfferReceived ? &Private->ProxyOffer : &Private->DhcpAck;\r
298 OfferType = Mode->UsingIpv6 ? Cache->Dhcp6.OfferType : Cache->Dhcp4.OfferType;\r
299\r
300 //\r
9063c328 301 // There is no specified DhcpPxe10/ProxyPxe10 for IPv6 in PXE and UEFI spec.\r
a3bcde70
HT
302 //\r
303 ASSERT (!Mode->UsingIpv6);\r
9063c328 304 ASSERT (OfferType == PxeOfferTypeProxyPxe10 || OfferType == PxeOfferTypeDhcpPxe10);\r
a3bcde70
HT
305\r
306 VendorOpt = &Cache->Dhcp4.VendorOpt;\r
307 if (!IS_VALID_BOOT_MENU (VendorOpt->BitMap)) {\r
308 return EFI_SUCCESS;\r
309 }\r
310\r
311 //\r
312 // Display the boot menu on the screen.\r
313 //\r
314 SetMem (Blank, sizeof(Blank), ' ');\r
315\r
316 MenuSize = VendorOpt->BootMenuLen;\r
317 MenuItem = VendorOpt->BootMenu;\r
318\r
319 if (MenuSize == 0) {\r
320 return EFI_DEVICE_ERROR;\r
321 }\r
322\r
323 while (MenuSize > 0 && Index < PXEBC_MENU_MAX_NUM) {\r
324 ASSERT (MenuItem != NULL);\r
325 MenuArray[Index] = MenuItem;\r
326 MenuSize = (UINT8) (MenuSize - (MenuItem->DescLen + 3));\r
327 MenuItem = (PXEBC_BOOT_MENU_ENTRY *) ((UINT8 *) MenuItem + MenuItem->DescLen + 3);\r
328 Index++;\r
329 }\r
330\r
331 if (UseDefaultItem) {\r
332 ASSERT (MenuArray[0] != NULL);\r
333 CopyMem (Type, &MenuArray[0]->Type, sizeof (UINT16));\r
334 *Type = NTOHS (*Type);\r
335 return EFI_SUCCESS;\r
336 }\r
337\r
338 MenuNum = Index;\r
339\r
340 for (Index = 0; Index < MenuNum; Index++) {\r
341 ASSERT (MenuArray[Index] != NULL);\r
342 PxeBcDisplayBootItem (MenuArray[Index]->DescStr, MenuArray[Index]->DescLen);\r
343 }\r
344\r
345 TopRow = gST->ConOut->Mode->CursorRow - MenuNum;\r
346\r
347 //\r
348 // Select the boot item by user in the boot menu.\r
349 //\r
350 do {\r
351 //\r
352 // Highlight selected row.\r
353 //\r
354 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
355 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Select);\r
356 ASSERT (Select < PXEBC_MENU_MAX_NUM);\r
357 ASSERT (MenuArray[Select] != NULL);\r
358 Blank[MenuArray[Select]->DescLen] = 0;\r
359 AsciiPrint ("%a\r", Blank);\r
360 PxeBcDisplayBootItem (MenuArray[Select]->DescStr, MenuArray[Select]->DescLen);\r
361 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);\r
362 LastSelect = Select;\r
363\r
364 while (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {\r
365 gBS->Stall (10 * TICKS_PER_MS);\r
366 }\r
367\r
9063c328 368 if (InputKey.ScanCode == 0) {\r
a3bcde70
HT
369 switch (InputKey.UnicodeChar) {\r
370 case CTRL ('c'):\r
371 InputKey.ScanCode = SCAN_ESC;\r
372 break;\r
373\r
374 case CTRL ('j'): /* linefeed */\r
375 case CTRL ('m'): /* return */\r
376 Finish = TRUE;\r
377 break;\r
378\r
379 case CTRL ('i'): /* tab */\r
380 case ' ':\r
381 case 'd':\r
382 case 'D':\r
383 InputKey.ScanCode = SCAN_DOWN;\r
384 break;\r
385\r
386 case CTRL ('h'): /* backspace */\r
387 case 'u':\r
388 case 'U':\r
389 InputKey.ScanCode = SCAN_UP;\r
390 break;\r
391\r
392 default:\r
393 InputKey.ScanCode = 0;\r
394 }\r
395 }\r
396\r
397 switch (InputKey.ScanCode) {\r
398 case SCAN_LEFT:\r
399 case SCAN_UP:\r
400 if (Select != 0) {\r
401 Select--;\r
402 }\r
403 break;\r
404\r
405 case SCAN_DOWN:\r
406 case SCAN_RIGHT:\r
407 if (++Select == MenuNum) {\r
408 Select--;\r
409 }\r
410 break;\r
411\r
412 case SCAN_PAGE_UP:\r
413 case SCAN_HOME:\r
414 Select = 0;\r
415 break;\r
416\r
417 case SCAN_PAGE_DOWN:\r
418 case SCAN_END:\r
419 Select = (UINT16) (MenuNum - 1);\r
420 break;\r
421\r
422 case SCAN_ESC:\r
423 return EFI_ABORTED;\r
424 }\r
425\r
426 //\r
427 // Unhighlight the last selected row.\r
428 //\r
429 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
430 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + LastSelect);\r
431 ASSERT (LastSelect < PXEBC_MENU_MAX_NUM);\r
432 ASSERT (MenuArray[LastSelect] != NULL);\r
433 Blank[MenuArray[LastSelect]->DescLen] = 0;\r
434 AsciiPrint ("%a\r", Blank);\r
435 PxeBcDisplayBootItem (MenuArray[LastSelect]->DescStr, MenuArray[LastSelect]->DescLen);\r
436 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);\r
437 } while (!Finish);\r
438\r
439 //\r
440 // Swap the byte order.\r
441 //\r
442 ASSERT (Select < PXEBC_MENU_MAX_NUM);\r
443 ASSERT (MenuArray[Select] != NULL);\r
444 CopyMem (Type, &MenuArray[Select]->Type, sizeof (UINT16));\r
445 *Type = NTOHS (*Type);\r
446\r
447 return EFI_SUCCESS;\r
448}\r
449\r
450\r
451/**\r
452 Parse out the boot information from the last Dhcp4 reply packet.\r
453\r
454 @param[in, out] Private Pointer to PxeBc private data.\r
455 @param[out] BufferSize Size of the boot file to be downloaded.\r
456\r
457 @retval EFI_SUCCESS Successfully parsed out all the boot information.\r
458 @retval Others Failed to parse out the boot information.\r
459\r
460**/\r
461EFI_STATUS\r
462PxeBcDhcp4BootInfo (\r
463 IN OUT PXEBC_PRIVATE_DATA *Private,\r
464 OUT UINT64 *BufferSize\r
465 )\r
466{\r
467 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;\r
468 EFI_PXE_BASE_CODE_MODE *Mode;\r
469 EFI_STATUS Status;\r
470 PXEBC_DHCP4_PACKET_CACHE *Cache4;\r
471 UINT16 Value;\r
ecec4204
FS
472 PXEBC_VENDOR_OPTION *VendorOpt;\r
473 PXEBC_BOOT_SVR_ENTRY *Entry;\r
474 \r
a3bcde70
HT
475 PxeBc = &Private->PxeBc;\r
476 Mode = PxeBc->Mode;\r
477 Status = EFI_SUCCESS;\r
478 *BufferSize = 0;\r
479\r
480 //\r
481 // Get the last received Dhcp4 reply packet.\r
482 //\r
483 if (Mode->PxeReplyReceived) {\r
484 Cache4 = &Private->PxeReply.Dhcp4;\r
485 } else if (Mode->ProxyOfferReceived) {\r
486 Cache4 = &Private->ProxyOffer.Dhcp4;\r
487 } else {\r
488 Cache4 = &Private->DhcpAck.Dhcp4;\r
489 }\r
490\r
ecec4204 491 ASSERT (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);\r
a3bcde70 492\r
ecec4204
FS
493 //\r
494 // Parse the boot server address.\r
495 // If prompt/discover is disabled, get the first boot server from the boot servers list.\r
496 // Otherwise, parse the boot server Ipv4 address from next server address field in DHCP header.\r
497 // If all these fields are not available, use option 54 instead.\r
498 //\r
499 VendorOpt = &Cache4->VendorOpt;\r
500 if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) && IS_VALID_BOOT_SERVERS (VendorOpt->BitMap)) {\r
501 Entry = VendorOpt->BootSvr;\r
502 if (VendorOpt->BootSvrLen >= sizeof (PXEBC_BOOT_SVR_ENTRY) && Entry->IpCnt > 0) {\r
503 CopyMem (\r
504 &Private->ServerIp,\r
505 &Entry->IpAddr[0],\r
506 sizeof (EFI_IPv4_ADDRESS)\r
507 );\r
508 }\r
509 }\r
a3bcde70 510 if (Private->ServerIp.Addr[0] == 0) {\r
ecec4204
FS
511 //\r
512 // ServerIp.Addr[0] equals zero means we failed to get IP address from boot server list.\r
513 // Try to use next server address field.\r
514 //\r
515 CopyMem (\r
516 &Private->ServerIp,\r
517 &Cache4->Packet.Offer.Dhcp4.Header.ServerAddr,\r
518 sizeof (EFI_IPv4_ADDRESS)\r
519 );\r
520 }\r
521 if (Private->ServerIp.Addr[0] == 0) {\r
522 //\r
523 // Still failed , use the IP address from option 54.\r
524 //\r
a3bcde70
HT
525 CopyMem (\r
526 &Private->ServerIp,\r
527 Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,\r
528 sizeof (EFI_IPv4_ADDRESS)\r
529 );\r
530 }\r
531\r
532 //\r
533 // Parse the boot file name by option.\r
534 //\r
a3bcde70
HT
535 Private->BootFileName = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data;\r
536\r
537 if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) {\r
538 //\r
539 // Parse the boot file size by option.\r
540 //\r
541 CopyMem (&Value, Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->Data, sizeof (Value));\r
542 Value = NTOHS (Value);\r
543 //\r
544 // The field of boot file size is 512 bytes in unit.\r
545 //\r
546 *BufferSize = 512 * Value;\r
547 } else {\r
548 //\r
549 // Get the bootfile size by tftp command if no option available.\r
550 //\r
551 Status = PxeBc->Mtftp (\r
552 PxeBc,\r
553 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,\r
554 NULL,\r
555 FALSE,\r
556 BufferSize,\r
557 &Private->BlockSize,\r
558 &Private->ServerIp,\r
559 Private->BootFileName,\r
560 NULL,\r
561 FALSE\r
562 );\r
563 }\r
564\r
565 //\r
566 // Save the value of boot file size.\r
567 //\r
568 Private->BootFileSize = (UINTN) *BufferSize;\r
569\r
570 //\r
571 // Display all the information: boot server address, boot file name and boot file size.\r
572 //\r
573 AsciiPrint ("\n Server IP address is ");\r
574 PxeBcShowIp4Addr (&Private->ServerIp.v4);\r
575 AsciiPrint ("\n NBP filename is %a", Private->BootFileName);\r
576 AsciiPrint ("\n NBP filesize is %d Bytes", Private->BootFileSize);\r
577\r
578 return Status;\r
579}\r
580\r
581\r
582/**\r
583 Parse out the boot information from the last Dhcp6 reply packet.\r
584\r
585 @param[in, out] Private Pointer to PxeBc private data.\r
586 @param[out] BufferSize Size of the boot file to be downloaded.\r
587\r
588 @retval EFI_SUCCESS Successfully parsed out all the boot information.\r
589 @retval EFI_BUFFER_TOO_SMALL\r
590 @retval Others Failed to parse out the boot information.\r
591\r
592**/\r
593EFI_STATUS\r
594PxeBcDhcp6BootInfo (\r
595 IN OUT PXEBC_PRIVATE_DATA *Private,\r
596 OUT UINT64 *BufferSize\r
597 )\r
598{\r
599 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;\r
600 EFI_PXE_BASE_CODE_MODE *Mode;\r
601 EFI_STATUS Status;\r
602 PXEBC_DHCP6_PACKET_CACHE *Cache6;\r
603 UINT16 Value;\r
604\r
605 PxeBc = &Private->PxeBc;\r
606 Mode = PxeBc->Mode;\r
607 Status = EFI_SUCCESS;\r
608 *BufferSize = 0;\r
609\r
610 //\r
611 // Get the last received Dhcp6 reply packet.\r
612 //\r
613 if (Mode->PxeReplyReceived) {\r
614 Cache6 = &Private->PxeReply.Dhcp6;\r
615 } else if (Mode->ProxyOfferReceived) {\r
616 Cache6 = &Private->ProxyOffer.Dhcp6;\r
617 } else {\r
618 Cache6 = &Private->DhcpAck.Dhcp6;\r
619 }\r
620\r
621 ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);\r
622\r
6692d519
ZL
623 //\r
624 // Set the station address to IP layer.\r
625 //\r
626 Status = PxeBcSetIp6Address (Private);\r
627 if (EFI_ERROR (Status)) {\r
628 return Status;\r
629 }\r
630\r
631\r
a3bcde70
HT
632 //\r
633 // Parse (m)tftp server ip address and bootfile name.\r
634 //\r
635 Status = PxeBcExtractBootFileUrl (\r
6692d519 636 Private,\r
a3bcde70
HT
637 &Private->BootFileName,\r
638 &Private->ServerIp.v6,\r
639 (CHAR8 *) (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),\r
640 NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)\r
641 );\r
642 if (EFI_ERROR (Status)) {\r
643 return Status;\r
644 }\r
645\r
646 //\r
647 // Parse the value of boot file size.\r
648 //\r
649 if (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] != NULL) {\r
650 //\r
651 // Parse it out if have the boot file parameter option.\r
652 //\r
653 Status = PxeBcExtractBootFileParam ((CHAR8 *) Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM]->Data, &Value);\r
654 if (EFI_ERROR (Status)) {\r
655 return Status;\r
656 }\r
657 //\r
658 // The field of boot file size is 512 bytes in unit.\r
659 //\r
660 *BufferSize = 512 * Value;\r
661 } else {\r
662 //\r
663 // Send get file size command by tftp if option unavailable.\r
664 //\r
665 Status = PxeBc->Mtftp (\r
666 PxeBc,\r
667 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,\r
668 NULL,\r
669 FALSE,\r
670 BufferSize,\r
671 &Private->BlockSize,\r
672 &Private->ServerIp,\r
673 Private->BootFileName,\r
674 NULL,\r
675 FALSE\r
676 );\r
677 }\r
678\r
679 //\r
680 // Save the value of boot file size.\r
681 //\r
682 Private->BootFileSize = (UINTN) *BufferSize;\r
683\r
684 //\r
685 // Display all the information: boot server address, boot file name and boot file size.\r
686 //\r
687 AsciiPrint ("\n Server IP address is ");\r
688 PxeBcShowIp6Addr (&Private->ServerIp.v6);\r
689 AsciiPrint ("\n NBP filename is %a", Private->BootFileName);\r
690 AsciiPrint ("\n NBP filesize is %d Bytes", Private->BootFileSize);\r
691\r
692 return Status;\r
693}\r
694\r
695\r
696/**\r
697 Extract the discover information and boot server entry from the\r
698 cached packets if unspecified.\r
699\r
700 @param[in] Private Pointer to PxeBc private data.\r
701 @param[in] Type The type of bootstrap to perform.\r
9063c328 702 @param[in, out] DiscoverInfo Pointer to EFI_PXE_BASE_CODE_DISCOVER_INFO.\r
a3bcde70
HT
703 @param[out] BootEntry Pointer to PXEBC_BOOT_SVR_ENTRY.\r
704 @param[out] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.\r
705\r
706 @retval EFI_SUCCESS Successfully extracted the information.\r
707 @retval EFI_DEVICE_ERROR Failed to extract the information.\r
708\r
709**/\r
710EFI_STATUS\r
711PxeBcExtractDiscoverInfo (\r
712 IN PXEBC_PRIVATE_DATA *Private,\r
713 IN UINT16 Type,\r
9063c328 714 IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO **DiscoverInfo,\r
a3bcde70
HT
715 OUT PXEBC_BOOT_SVR_ENTRY **BootEntry,\r
716 OUT EFI_PXE_BASE_CODE_SRVLIST **SrvList\r
717 )\r
718{\r
719 EFI_PXE_BASE_CODE_MODE *Mode;\r
720 PXEBC_DHCP4_PACKET_CACHE *Cache4;\r
721 PXEBC_VENDOR_OPTION *VendorOpt;\r
722 PXEBC_BOOT_SVR_ENTRY *Entry;\r
723 BOOLEAN IsFound;\r
9063c328 724 EFI_PXE_BASE_CODE_DISCOVER_INFO *Info;\r
725 UINT16 Index;\r
a3bcde70
HT
726\r
727 Mode = Private->PxeBc.Mode;\r
9063c328 728 Info = *DiscoverInfo;\r
a3bcde70
HT
729\r
730 if (Mode->UsingIpv6) {\r
731 Info->IpCnt = 1;\r
732 Info->UseUCast = TRUE;\r
733\r
734 Info->SrvList[0].Type = Type;\r
735 Info->SrvList[0].AcceptAnyResponse = FALSE;\r
736\r
737 //\r
738 // There is no vendor options specified in DHCPv6, so take BootFileUrl in the last cached packet.\r
739 //\r
740 CopyMem (&Info->SrvList[0].IpAddr, &Private->ServerIp, sizeof (EFI_IP_ADDRESS));\r
741\r
742 *SrvList = Info->SrvList;\r
743 } else {\r
744 Entry = NULL;\r
745 IsFound = FALSE;\r
746 Cache4 = (Mode->ProxyOfferReceived) ? &Private->ProxyOffer.Dhcp4 : &Private->DhcpAck.Dhcp4;\r
747 VendorOpt = &Cache4->VendorOpt;\r
748\r
749 if (!Mode->DhcpAckReceived || !IS_VALID_DISCOVER_VENDOR_OPTION (VendorOpt->BitMap)) {\r
750 //\r
751 // Address is not acquired or no discovery options.\r
752 //\r
753 return EFI_INVALID_PARAMETER;\r
754 }\r
755\r
756 //\r
757 // Parse the boot server entry from the vendor option in the last cached packet.\r
758 //\r
759 Info->UseMCast = (BOOLEAN) !IS_DISABLE_MCAST_DISCOVER (VendorOpt->DiscoverCtrl);\r
760 Info->UseBCast = (BOOLEAN) !IS_DISABLE_BCAST_DISCOVER (VendorOpt->DiscoverCtrl);\r
761 Info->MustUseList = (BOOLEAN) IS_ENABLE_USE_SERVER_LIST (VendorOpt->DiscoverCtrl);\r
9063c328 762 Info->UseUCast = (BOOLEAN) IS_VALID_BOOT_SERVERS (VendorOpt->BitMap);\r
a3bcde70
HT
763\r
764 if (Info->UseMCast) {\r
765 //\r
766 // Get the multicast discover ip address from vendor option if has.\r
767 //\r
768 CopyMem (&Info->ServerMCastIp.v4, &VendorOpt->DiscoverMcastIp, sizeof (EFI_IPv4_ADDRESS));\r
769 }\r
770\r
771 Info->IpCnt = 0;\r
772\r
9063c328 773 if (Info->UseUCast) {\r
a3bcde70
HT
774 Entry = VendorOpt->BootSvr;\r
775\r
776 while (((UINT8) (Entry - VendorOpt->BootSvr)) < VendorOpt->BootSvrLen) {\r
777 if (Entry->Type == HTONS (Type)) {\r
778 IsFound = TRUE;\r
779 break;\r
780 }\r
781 Entry = GET_NEXT_BOOT_SVR_ENTRY (Entry);\r
782 }\r
783\r
784 if (!IsFound) {\r
785 return EFI_DEVICE_ERROR;\r
786 }\r
787\r
788 Info->IpCnt = Entry->IpCnt;\r
9063c328 789 if (Info->IpCnt >= 1) {\r
790 *DiscoverInfo = AllocatePool (sizeof (*Info) + (Info->IpCnt - 1) * sizeof (**SrvList));\r
791 if (*DiscoverInfo == NULL) {\r
792 return EFI_OUT_OF_RESOURCES; \r
793 } \r
794 CopyMem (*DiscoverInfo, Info, sizeof (*Info));\r
795 Info = *DiscoverInfo;\r
796 }\r
797\r
798 for (Index = 0; Index < Info->IpCnt; Index++) {\r
799 CopyMem (&Info->SrvList[Index].IpAddr, &Entry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));\r
800 Info->SrvList[Index].AcceptAnyResponse = !Info->MustUseList;\r
801 Info->SrvList[Index].Type = NTOHS (Entry->Type);\r
802 }\r
a3bcde70
HT
803 }\r
804\r
805 *BootEntry = Entry;\r
9063c328 806 *SrvList = Info->SrvList;\r
a3bcde70
HT
807 }\r
808\r
809 return EFI_SUCCESS;\r
810}\r
811\r
812\r
813/**\r
814 Build the discover packet and send out for boot server.\r
815\r
816 @param[in] Private Pointer to PxeBc private data.\r
817 @param[in] Type PxeBc option boot item type.\r
818 @param[in] Layer Pointer to option boot item layer.\r
819 @param[in] UseBis Use BIS or not.\r
820 @param[in] DestIp Pointer to the destination address.\r
821 @param[in] IpCount The count of the server address.\r
822 @param[in] SrvList Pointer to the server address list.\r
823\r
824 @retval EFI_SUCCESS Successfully discovered boot file.\r
825 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.\r
826 @retval EFI_NOT_FOUND Can't get the PXE reply packet.\r
827 @retval Others Failed to discover boot file.\r
828\r
829**/\r
830EFI_STATUS\r
831PxeBcDiscoverBootServer (\r
832 IN PXEBC_PRIVATE_DATA *Private,\r
833 IN UINT16 Type,\r
834 IN UINT16 *Layer,\r
835 IN BOOLEAN UseBis,\r
836 IN EFI_IP_ADDRESS *DestIp,\r
837 IN UINT16 IpCount,\r
838 IN EFI_PXE_BASE_CODE_SRVLIST *SrvList\r
839 )\r
840{\r
841 if (Private->PxeBc.Mode->UsingIpv6) {\r
842 return PxeBcDhcp6Discover (\r
843 Private,\r
844 Type,\r
845 Layer,\r
846 UseBis,\r
847 DestIp\r
848 );\r
849 } else {\r
850 return PxeBcDhcp4Discover (\r
851 Private,\r
852 Type,\r
853 Layer,\r
854 UseBis,\r
855 DestIp,\r
856 IpCount,\r
857 SrvList\r
858 );\r
859 }\r
860}\r
861\r
862\r
863/**\r
864 Discover all the boot information for boot file.\r
865\r
866 @param[in, out] Private Pointer to PxeBc private data.\r
867 @param[out] BufferSize Size of the boot file to be downloaded.\r
868\r
869 @retval EFI_SUCCESS Successfully obtained all the boot information .\r
870 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.\r
871 @retval EFI_ABORTED User cancel current operation.\r
872 @retval Others Failed to parse out the boot information.\r
873\r
874**/\r
875EFI_STATUS\r
876PxeBcDiscoverBootFile (\r
877 IN OUT PXEBC_PRIVATE_DATA *Private,\r
878 OUT UINT64 *BufferSize\r
879 )\r
880{\r
881 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;\r
882 EFI_PXE_BASE_CODE_MODE *Mode;\r
883 EFI_STATUS Status;\r
884 UINT16 Type;\r
885 UINT16 Layer;\r
886 BOOLEAN UseBis;\r
887\r
888 PxeBc = &Private->PxeBc;\r
889 Mode = PxeBc->Mode;\r
890 Type = EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP;\r
891 Layer = EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL;\r
892\r
893 //\r
894 // Start D.O.R.A/S.A.R.R exchange to acquire station ip address and\r
895 // other pxe boot information.\r
896 //\r
897 Status = PxeBc->Dhcp (PxeBc, TRUE);\r
898 if (EFI_ERROR (Status)) {\r
899 return Status;\r
900 }\r
901\r
902 //\r
903 // Select a boot server from boot server list.\r
904 //\r
905 Status = PxeBcSelectBootPrompt (Private);\r
906\r
907 if (Status == EFI_SUCCESS) {\r
908 //\r
909 // Choose by user's input.\r
910 //\r
9063c328 911 Status = PxeBcSelectBootMenu (Private, &Type, FALSE);\r
a3bcde70
HT
912 } else if (Status == EFI_TIMEOUT) {\r
913 //\r
914 // Choose by default item.\r
915 //\r
9063c328 916 Status = PxeBcSelectBootMenu (Private, &Type, TRUE);\r
a3bcde70
HT
917 }\r
918\r
919 if (!EFI_ERROR (Status)) {\r
920\r
921 if (Type == EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP) {\r
922 //\r
923 // Local boot(PXE bootstrap server) need abort\r
924 //\r
925 return EFI_ABORTED;\r
926 }\r
927\r
928 //\r
929 // Start to discover the boot server to get (m)tftp server ip address, bootfile\r
930 // name and bootfile size.\r
931 //\r
932 UseBis = (BOOLEAN) (Mode->BisSupported && Mode->BisDetected);\r
933 Status = PxeBc->Discover (PxeBc, Type, &Layer, UseBis, NULL);\r
934 if (EFI_ERROR (Status)) {\r
935 return Status;\r
936 }\r
9063c328 937\r
938 if (Mode->PxeReplyReceived && !Mode->ProxyOfferReceived) {\r
939 //\r
940 // Some network boot loader only search the packet in Mode.ProxyOffer to get its server\r
941 // IP address, so we need to store a copy of Mode.PxeReply packet into Mode.ProxyOffer.\r
942 //\r
943 if (Mode->UsingIpv6) {\r
944 CopyMem (\r
945 &Mode->ProxyOffer.Dhcpv6,\r
946 &Mode->PxeReply.Dhcpv6,\r
947 Private->PxeReply.Dhcp6.Packet.Ack.Length\r
948 );\r
949 } else {\r
950 CopyMem (\r
951 &Mode->ProxyOffer.Dhcpv4,\r
952 &Mode->PxeReply.Dhcpv4,\r
953 Private->PxeReply.Dhcp4.Packet.Ack.Length\r
954 ); \r
955 }\r
956 Mode->ProxyOfferReceived = TRUE;\r
957 }\r
a3bcde70
HT
958 }\r
959\r
960 //\r
961 // Parse the boot information.\r
962 //\r
963 if (Mode->UsingIpv6) {\r
964 Status = PxeBcDhcp6BootInfo (Private, BufferSize);\r
965 } else {\r
966 Status = PxeBcDhcp4BootInfo (Private, BufferSize);\r
967 }\r
968\r
969 return Status;\r
970}\r
971\r
972\r
973/**\r
974 Install PxeBaseCodeCallbackProtocol if not installed before.\r
975\r
976 @param[in, out] Private Pointer to PxeBc private data.\r
977 @param[out] NewMakeCallback If TRUE, it is a new callback.\r
978 Otherwise, it is not new callback.\r
979 @retval EFI_SUCCESS PxeBaseCodeCallbackProtocol installed succesfully.\r
980 @retval Others Failed to install PxeBaseCodeCallbackProtocol.\r
981\r
982**/\r
983EFI_STATUS\r
984PxeBcInstallCallback (\r
985 IN OUT PXEBC_PRIVATE_DATA *Private,\r
986 OUT BOOLEAN *NewMakeCallback\r
987 )\r
988{\r
989 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;\r
990 EFI_STATUS Status;\r
991\r
992 //\r
993 // Check whether PxeBaseCodeCallbackProtocol already installed.\r
994 //\r
995 PxeBc = &Private->PxeBc;\r
996 Status = gBS->HandleProtocol (\r
09cddd08 997 Private->Mode.UsingIpv6 ? Private->Ip6Nic->Controller : Private->Ip4Nic->Controller,\r
a3bcde70
HT
998 &gEfiPxeBaseCodeCallbackProtocolGuid,\r
999 (VOID **) &Private->PxeBcCallback\r
1000 );\r
1001 if (Status == EFI_UNSUPPORTED) {\r
1002\r
1003 CopyMem (\r
1004 &Private->LoadFileCallback,\r
1005 &gPxeBcCallBackTemplate,\r
1006 sizeof (EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL)\r
1007 );\r
1008\r
1009 //\r
1010 // Install a default callback if user didn't offer one.\r
1011 //\r
1012 Status = gBS->InstallProtocolInterface (\r
09cddd08 1013 Private->Mode.UsingIpv6 ? &Private->Ip6Nic->Controller : &Private->Ip4Nic->Controller,\r
a3bcde70
HT
1014 &gEfiPxeBaseCodeCallbackProtocolGuid,\r
1015 EFI_NATIVE_INTERFACE,\r
1016 &Private->LoadFileCallback\r
1017 );\r
1018\r
1019 (*NewMakeCallback) = (BOOLEAN) (Status == EFI_SUCCESS);\r
1020\r
1021 Status = PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, NewMakeCallback);\r
1022 if (EFI_ERROR (Status)) {\r
1023 PxeBc->Stop (PxeBc);\r
1024 return Status;\r
1025 }\r
1026 }\r
1027\r
1028 return EFI_SUCCESS;\r
1029}\r
1030\r
1031\r
1032/**\r
1033 Uninstall PxeBaseCodeCallbackProtocol.\r
1034\r
1035 @param[in] Private Pointer to PxeBc private data.\r
1036 @param[in] NewMakeCallback If TRUE, it is a new callback.\r
1037 Otherwise, it is not new callback.\r
1038\r
1039**/\r
1040VOID\r
1041PxeBcUninstallCallback (\r
1042 IN PXEBC_PRIVATE_DATA *Private,\r
1043 IN BOOLEAN NewMakeCallback\r
1044 )\r
1045{\r
1046 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;\r
1047\r
1048 PxeBc = &Private->PxeBc;\r
1049\r
1050 if (NewMakeCallback) {\r
1051\r
1052 NewMakeCallback = FALSE;\r
1053\r
1054 PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);\r
1055\r
1056 gBS->UninstallProtocolInterface (\r
09cddd08 1057 Private->Mode.UsingIpv6 ? Private->Ip6Nic->Controller : Private->Ip4Nic->Controller,\r
a3bcde70
HT
1058 &gEfiPxeBaseCodeCallbackProtocolGuid,\r
1059 &Private->LoadFileCallback\r
1060 );\r
1061 }\r
1062}\r
1063\r
1064\r
1065/**\r
1066 Download one of boot file in the list, and it's special for IPv6.\r
1067\r
1068 @param[in] Private Pointer to PxeBc private data.\r
1069 @param[in, out] BufferSize Size of user buffer for input;\r
1070 required buffer size for output.\r
1071 @param[in] Buffer Pointer to user buffer.\r
1072\r
1073 @retval EFI_SUCCESS Read one of boot file in the list successfully.\r
1074 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.\r
1075 @retval EFI_NOT_FOUND There is no proper boot file available.\r
1076 @retval Others Failed to download boot file in the list.\r
1077\r
1078**/\r
1079EFI_STATUS\r
1080PxeBcReadBootFileList (\r
1081 IN PXEBC_PRIVATE_DATA *Private,\r
1082 IN OUT UINT64 *BufferSize,\r
1083 IN VOID *Buffer OPTIONAL\r
1084 )\r
1085{\r
1086 EFI_STATUS Status;\r
1087 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;\r
1088\r
1089 PxeBc = &Private->PxeBc;\r
1090\r
1091 //\r
1092 // Try to download the boot file if everything is ready.\r
1093 //\r
1094 if (Buffer != NULL) {\r
1095 Status = PxeBc->Mtftp (\r
1096 PxeBc,\r
1097 EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
1098 Buffer,\r
1099 FALSE,\r
1100 BufferSize,\r
1101 &Private->BlockSize,\r
1102 &Private->ServerIp,\r
1103 Private->BootFileName,\r
1104 NULL,\r
1105 FALSE\r
1106 );\r
1107\r
1108\r
1109 } else {\r
1110 Status = EFI_BUFFER_TOO_SMALL;\r
1111 }\r
1112\r
1113 return Status;\r
1114}\r
1115\r
1116\r
1117/**\r
1118 Load boot file into user buffer.\r
1119\r
1120 @param[in] Private Pointer to PxeBc private data.\r
1121 @param[in, out] BufferSize Size of user buffer for input;\r
1122 required buffer size for output.\r
1123 @param[in] Buffer Pointer to user buffer.\r
1124\r
1125 @retval EFI_SUCCESS Get all the boot information successfully.\r
1126 @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.\r
1127 @retval EFI_ABORTED User cancelled the current operation.\r
1128 @retval Others Failed to parse out the boot information.\r
1129\r
1130**/\r
1131EFI_STATUS\r
1132PxeBcLoadBootFile (\r
1133 IN PXEBC_PRIVATE_DATA *Private,\r
1134 IN OUT UINTN *BufferSize,\r
1135 IN VOID *Buffer OPTIONAL\r
1136 )\r
1137{\r
1138 BOOLEAN NewMakeCallback;\r
1139 UINT64 RequiredSize;\r
1140 UINT64 CurrentSize;\r
1141 EFI_STATUS Status;\r
1142 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;\r
1143 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
1144\r
1145 NewMakeCallback = FALSE;\r
1146 PxeBc = &Private->PxeBc;\r
1147 PxeBcMode = &Private->Mode;\r
1148 CurrentSize = *BufferSize;\r
1149 RequiredSize = 0;\r
1150\r
1151 //\r
1152 // Install pxebc callback protocol if hasn't been installed yet.\r
1153 //\r
1154 Status = PxeBcInstallCallback (Private, &NewMakeCallback);\r
1155 if (EFI_ERROR(Status)) {\r
1156 return Status;\r
1157 }\r
1158\r
1159 if (Private->BootFileSize == 0) {\r
1160 //\r
1161 // Discover the boot information about the bootfile if hasn't.\r
1162 //\r
1163 Status = PxeBcDiscoverBootFile (Private, &RequiredSize);\r
278c6019 1164 if (EFI_ERROR (Status)) {\r
1165 goto ON_EXIT;\r
1166 }\r
a3bcde70
HT
1167\r
1168 if (PXEBC_IS_SIZE_OVERFLOWED (RequiredSize)) {\r
1169 //\r
1170 // It's error if the required buffer size is beyond the system scope.\r
1171 //\r
1172 Status = EFI_DEVICE_ERROR;\r
1173 goto ON_EXIT;\r
1174 } else if (RequiredSize > 0) {\r
1175 //\r
1176 // Get the right buffer size of the bootfile required.\r
1177 //\r
1178 if (CurrentSize < RequiredSize || Buffer == NULL) {\r
1179 //\r
1180 // It's buffer too small if the size of user buffer is smaller than the required.\r
1181 //\r
1182 CurrentSize = RequiredSize;\r
1183 Status = EFI_BUFFER_TOO_SMALL;\r
1184 goto ON_EXIT;\r
1185 }\r
1186 CurrentSize = RequiredSize;\r
1187 } else if (RequiredSize == 0 && PxeBcMode->UsingIpv6) {\r
1188 //\r
1189 // Try to download another bootfile in list if failed to get the filesize of the last one.\r
1190 // It's special for the case of IPv6.\r
1191 //\r
1192 Status = PxeBcReadBootFileList (Private, &CurrentSize, Buffer);\r
1193 goto ON_EXIT;\r
1194 }\r
1195 } else if (CurrentSize < Private->BootFileSize || Buffer == NULL ) {\r
1196 //\r
1197 // It's buffer too small if the size of user buffer is smaller than the required.\r
1198 //\r
1199 CurrentSize = Private->BootFileSize;\r
1200 Status = EFI_BUFFER_TOO_SMALL;\r
1201 goto ON_EXIT;\r
1202 }\r
1203\r
1204 //\r
1205 // Begin to download the bootfile if everything is ready.\r
1206 //\r
1207 AsciiPrint ("\n Downloading NBP file...\n");\r
1208 if (PxeBcMode->UsingIpv6) {\r
1209 Status = PxeBcReadBootFileList (\r
1210 Private,\r
1211 &CurrentSize,\r
1212 Buffer\r
1213 );\r
1214 } else {\r
1215 Status = PxeBc->Mtftp (\r
1216 PxeBc,\r
1217 EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
1218 Buffer,\r
1219 FALSE,\r
1220 &CurrentSize,\r
1221 &Private->BlockSize,\r
1222 &Private->ServerIp,\r
1223 Private->BootFileName,\r
1224 NULL,\r
1225 FALSE\r
1226 );\r
1227 }\r
1228\r
1229ON_EXIT:\r
1230 *BufferSize = (UINTN) CurrentSize;\r
1231 PxeBcUninstallCallback(Private, NewMakeCallback);\r
1232\r
1233 if (Status == EFI_SUCCESS) {\r
93aea44f 1234 AsciiPrint ("\n NBP file downloaded successfully.\n");\r
a3bcde70
HT
1235 return EFI_SUCCESS;\r
1236 } else if (Status == EFI_BUFFER_TOO_SMALL && Buffer != NULL) {\r
1237 AsciiPrint ("\n PXE-E05: Buffer size is smaller than the requested file.\n");\r
1238 } else if (Status == EFI_DEVICE_ERROR) {\r
1239 AsciiPrint ("\n PXE-E07: Network device error.\n");\r
1240 } else if (Status == EFI_OUT_OF_RESOURCES) {\r
1241 AsciiPrint ("\n PXE-E09: Could not allocate I/O buffers.\n");\r
1242 } else if (Status == EFI_NO_MEDIA) {\r
1243 AsciiPrint ("\n PXE-E12: Could not detect network connection.\n");\r
1244 } else if (Status == EFI_NO_RESPONSE) {\r
10e62442 1245 AsciiPrint ("\n PXE-E16: No valid offer received.\n");\r
a3bcde70
HT
1246 } else if (Status == EFI_TIMEOUT) {\r
1247 AsciiPrint ("\n PXE-E18: Server response timeout.\n");\r
1248 } else if (Status == EFI_ABORTED) {\r
1249 AsciiPrint ("\n PXE-E21: Remote boot cancelled.\n");\r
1250 } else if (Status == EFI_ICMP_ERROR) {\r
1251 AsciiPrint ("\n PXE-E22: Client received ICMP error from server.\n");\r
1252 } else if (Status == EFI_TFTP_ERROR) {\r
1253 AsciiPrint ("\n PXE-E23: Client received TFTP error from server.\n");\r
4496ff75 1254 } else if (Status == EFI_NOT_FOUND) {\r
1255 AsciiPrint ("\n PXE-E53: No boot filename received.\n");\r
a3bcde70
HT
1256 } else if (Status != EFI_BUFFER_TOO_SMALL) {\r
1257 AsciiPrint ("\n PXE-E99: Unexpected network error.\n");\r
1258 }\r
1259\r
1260 return Status;\r
1261}\r
1262\r