]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_loadfile.c
remove clean console control protocol.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / PxeBcDxe / Pxe_loadfile.c
CommitLineData
772db4bb 1/** @file\r
2\r
19b15d63 3Copyright (c) 2004 - 2008, Intel Corporation\r
772db4bb 4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13 pxe_loadfile.c\r
14\r
15Abstract:\r
16 An implementation of the load file protocol for network devices.\r
17\r
18\r
19**/\r
20\r
21\r
22#include "Bc.h"\r
23\r
24#define DO_MENU (EFI_SUCCESS)\r
25#define NO_MENU (DO_MENU + 1)\r
26#define LOCAL_BOOT (EFI_ABORTED)\r
27#define AUTO_SELECT (NO_MENU)\r
28\r
29#define NUMBER_ROWS 25 // we set to mode 0\r
30#define MAX_MENULIST 23\r
31\r
32#define Ctl(x) (0x1F & (x))\r
33\r
34typedef union {\r
35 DHCPV4_OP_STRUCT *OpPtr;\r
36 PXE_BOOT_MENU_ENTRY *CurrentMenuItemPtr;\r
37 PXE_OP_DISCOVERY_CONTROL *DiscCtlOpStr;\r
38 PXE_OP_BOOT_MENU *MenuPtr;\r
39 UINT8 *BytePtr;\r
40} UNION_PTR;\r
41\r
19b15d63 42UINTN mPropeller;\r
772db4bb 43\r
44/**\r
45 PxeBc callback routine for status updates and aborts.\r
46\r
47 @param This Pointer to PxeBcCallback\r
48 interface\r
49 @param Function PxeBc function ID#\r
50 @param Received Receive/transmit flag\r
51 @param PacketLength Length of received packet (0\r
52 == idle callback)\r
53 @param PacketPtr Pointer to received packet\r
54 (NULL == idle callback)\r
55\r
56 @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE\r
57 EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT\r
58 -\r
59\r
60**/\r
772db4bb 61EFI_PXE_BASE_CODE_CALLBACK_STATUS\r
62EFIAPI\r
63bc_callback (\r
64 IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL * This,\r
65 IN EFI_PXE_BASE_CODE_FUNCTION Function,\r
66 IN BOOLEAN Received,\r
67 IN UINT32 PacketLength,\r
68 IN EFI_PXE_BASE_CODE_PACKET * PacketPtr OPTIONAL\r
69 )\r
70{\r
772db4bb 71 EFI_INPUT_KEY Key;\r
72 UINTN Row;\r
73 UINTN Col;\r
74\r
19b15d63 75 mPropeller = 0;\r
772db4bb 76 //\r
77 // Resolve Warning 4 unreferenced parameter problem\r
78 //\r
79 This = This;\r
80\r
81 //\r
82 // Check for user abort.\r
83 //\r
84 if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_SUCCESS) {\r
85 if (!Key.ScanCode) {\r
86 if (Key.UnicodeChar == Ctl ('c')) {\r
87 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;\r
88 }\r
89 } else if (Key.ScanCode == SCAN_ESC) {\r
90 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;\r
91 }\r
92 }\r
93 //\r
94 // Do nothing if this is a receive.\r
95 //\r
96 if (Received) {\r
97 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
98 }\r
99 //\r
100 // The display code is only for these functions.\r
101 //\r
102 switch (Function) {\r
103 case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:\r
104 //\r
105 // If this is a transmit and not a M/TFTP open request,\r
106 // return now. Do not print a dot for each M/TFTP packet\r
107 // that is sent, only for the open packets.\r
108 //\r
109 if (PacketLength != 0 && PacketPtr != NULL) {\r
110 if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {\r
111 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
112 }\r
113 }\r
114\r
115 break;\r
116\r
117 case EFI_PXE_BASE_CODE_FUNCTION_DHCP:\r
118 case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:\r
119 break;\r
120\r
121 default:\r
122 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
123 }\r
124 //\r
125 // Display routines\r
126 //\r
127 if (PacketLength != 0 && PacketPtr != NULL) {\r
128 //\r
129 // Display a '.' when a packet is transmitted.\r
130 //\r
131 AsciiPrint (".");\r
132 } else if (PacketLength == 0 && PacketPtr == NULL) {\r
133 //\r
134 // Display a propeller when waiting for packets if at\r
135 // least 200 ms have passed.\r
136 //\r
137 Row = gST->ConOut->Mode->CursorRow;\r
138 Col = gST->ConOut->Mode->CursorColumn;\r
139\r
19b15d63 140 AsciiPrint ("%c", "/-\\|"[mPropeller]);\r
772db4bb 141 gST->ConOut->SetCursorPosition (gST->ConOut, Col, Row);\r
142\r
19b15d63 143 mPropeller = (mPropeller + 1) & 3;\r
772db4bb 144 }\r
145\r
146 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
147}\r
148\r
fe1e36e5 149EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL _bc_callback = {\r
772db4bb 150 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_REVISION,\r
151 &bc_callback\r
152};\r
153\r
154\r
155/**\r
156 Display an IPv4 address in dot notation.\r
157\r
158 @param Ptr Pointer to IPv4 address.\r
159\r
160 @return None\r
161\r
162**/\r
772db4bb 163VOID\r
164PrintIpv4 (\r
165 UINT8 *Ptr\r
166 )\r
167{\r
168 if (Ptr != NULL) {\r
169 AsciiPrint ("%d.%d.%d.%d", Ptr[0], Ptr[1], Ptr[2], Ptr[3]);\r
170 }\r
171}\r
172\r
173\r
174/**\r
175 Display client and server IP information.\r
176\r
177 @param Private Pointer to PxeBc interface\r
178\r
179 @return None\r
180\r
181**/\r
772db4bb 182VOID\r
183ShowMyInfo (\r
184 IN PXE_BASECODE_DEVICE *Private\r
185 )\r
186{\r
187 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
188 UINTN Index;\r
189\r
190 //\r
191 // Do nothing if a NULL pointer is passed in.\r
192 //\r
193 if (Private == NULL) {\r
194 return ;\r
195 }\r
196 //\r
197 // Get pointer to PXE BaseCode mode structure\r
198 //\r
199 PxeBcMode = Private->EfiBc.Mode;\r
200\r
201 //\r
202 // Display client IP address\r
203 //\r
204 AsciiPrint ("\rCLIENT IP: ");\r
205 PrintIpv4 (PxeBcMode->StationIp.v4.Addr);\r
206\r
207 //\r
208 // Display subnet mask\r
209 //\r
210 AsciiPrint (" MASK: ");\r
211 PrintIpv4 (PxeBcMode->SubnetMask.v4.Addr);\r
212\r
213 //\r
214 // Display DHCP and proxyDHCP IP addresses\r
215 //\r
216 if (PxeBcMode->ProxyOfferReceived) {\r
217 AsciiPrint ("\nDHCP IP: ");\r
218 PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);\r
219\r
220 AsciiPrint (" PROXY IP: ");\r
221 PrintIpv4 (((DHCPV4_OP_SERVER_IP *) PXE_OFFER_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);\r
222 } else {\r
223 AsciiPrint (" DHCP IP: ");\r
224 PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);\r
225 }\r
226 //\r
227 // Display gateway IP addresses\r
228 //\r
229 for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {\r
230 if ((Index % 3) == 0) {\r
231 AsciiPrint ("\r\nGATEWAY IP:");\r
232 }\r
233\r
234 AsciiPrint (" ");\r
235 PrintIpv4 (PxeBcMode->RouteTable[Index].GwAddr.v4.Addr);\r
236 AsciiPrint (" ");\r
237 }\r
238\r
239 AsciiPrint ("\n");\r
240}\r
241\r
242\r
243/**\r
244 Display prompt and wait for input.\r
245\r
246 @param Private Pointer to PxeBc interface\r
247 @param BootPromptPtr Pointer to PXE boot prompt\r
248 option\r
249\r
250 @retval AUTO_SELECT DO_MENU -\r
251 @retval NO_MENU\r
252 @retval LOCAL_BOOT\r
253\r
254**/\r
772db4bb 255EFI_STATUS\r
256DoPrompt (\r
257 PXE_BASECODE_DEVICE *Private,\r
258 PXE_OP_BOOT_PROMPT *BootPromptPtr\r
259 )\r
260{\r
261 EFI_STATUS Status;\r
262 EFI_EVENT TimeoutEvent;\r
263 EFI_EVENT SecondsEvent;\r
264 INT32 SecColumn;\r
265 INT32 SecRow;\r
266 UINT8 SaveChar;\r
267 UINT8 SecsLeft;\r
268\r
269 //\r
270 // if auto select, just get right to it\r
271 //\r
272 if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_AUTO_SELECT) {\r
273 return AUTO_SELECT;\r
274 }\r
275 //\r
276 // if no timeout, go directly to display of menu\r
277 //\r
278 if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_NO_TIMEOUT) {\r
279 return DO_MENU;\r
280 }\r
281 //\r
282 //\r
283 //\r
284 Status = gBS->CreateEvent (\r
285 EVT_TIMER,\r
286 TPL_CALLBACK,\r
287 NULL,\r
288 NULL,\r
289 &TimeoutEvent\r
290 );\r
291\r
292 if (EFI_ERROR (Status)) {\r
293 return DO_MENU;\r
294 }\r
295\r
296 Status = gBS->SetTimer (\r
297 TimeoutEvent,\r
298 TimerRelative,\r
299 BootPromptPtr->Timeout * 10000000 + 100000\r
300 );\r
301\r
302 if (EFI_ERROR (Status)) {\r
303 gBS->CloseEvent (TimeoutEvent);\r
304 return DO_MENU;\r
305 }\r
306 //\r
307 //\r
308 //\r
309 Status = gBS->CreateEvent (\r
310 EVT_TIMER,\r
311 TPL_CALLBACK,\r
312 NULL,\r
313 NULL,\r
314 &SecondsEvent\r
315 );\r
316\r
317 if (EFI_ERROR (Status)) {\r
318 gBS->CloseEvent (TimeoutEvent);\r
319 return DO_MENU;\r
320 }\r
321\r
322 Status = gBS->SetTimer (\r
323 SecondsEvent,\r
324 TimerPeriodic,\r
325 10000000\r
326 ); /* 1 second */\r
327\r
328 if (EFI_ERROR (Status)) {\r
329 gBS->CloseEvent (SecondsEvent);\r
330 gBS->CloseEvent (TimeoutEvent);\r
331 return DO_MENU;\r
332 }\r
333 //\r
334 // display the prompt\r
335 // IMPORTANT! This prompt is an ASCII character string that may\r
336 // not be terminated with a NULL byte.\r
337 //\r
338 SaveChar = BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1];\r
339 BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = 0;\r
340\r
341 AsciiPrint ("%a ", BootPromptPtr->Prompt);\r
342 BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = SaveChar;\r
343\r
344 //\r
345 // wait until time expires or selection made - menu or local\r
346 //\r
347 SecColumn = gST->ConOut->Mode->CursorColumn;\r
348 SecRow = gST->ConOut->Mode->CursorRow;\r
349 SecsLeft = BootPromptPtr->Timeout;\r
350\r
351 gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);\r
352 AsciiPrint ("(%d) ", SecsLeft);\r
353\r
354 //\r
355 // set the default action to be AUTO_SELECT\r
356 //\r
357 Status = AUTO_SELECT;\r
358\r
359 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
360 EFI_INPUT_KEY Key;\r
361\r
362 if (!EFI_ERROR (gBS->CheckEvent (SecondsEvent))) {\r
363 --SecsLeft;\r
364 gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);\r
365 AsciiPrint ("(%d) ", SecsLeft);\r
366 }\r
367\r
368 if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {\r
369 UINT8 Buffer[512];\r
370 UINTN BufferSize;\r
772db4bb 371\r
372 BufferSize = sizeof Buffer;\r
373\r
374 Status = Private->EfiBc.UdpRead (\r
375 &Private->EfiBc,\r
376 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |\r
377 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |\r
378 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,\r
379 NULL, /* dest ip */\r
380 NULL, /* dest port */\r
381 NULL, /* src ip */\r
382 NULL, /* src port */\r
383 NULL, /* hdr size */\r
384 NULL, /* hdr ptr */\r
385 &BufferSize,\r
386 Buffer\r
387 );\r
388\r
389 continue;\r
390 }\r
391\r
392 if (Key.ScanCode == 0) {\r
393 switch (Key.UnicodeChar) {\r
394 case Ctl ('c'):\r
395 Status = LOCAL_BOOT;\r
396 break;\r
397\r
398 case Ctl ('m'):\r
399 case 'm':\r
400 case 'M':\r
401 Status = DO_MENU;\r
402 break;\r
403\r
404 default:\r
405 continue;\r
406 }\r
407 } else {\r
408 switch (Key.ScanCode) {\r
409 case SCAN_F8:\r
410 Status = DO_MENU;\r
411 break;\r
412\r
413 case SCAN_ESC:\r
414 Status = LOCAL_BOOT;\r
415 break;\r
416\r
417 default:\r
418 continue;\r
419 }\r
420 }\r
421\r
422 break;\r
423 }\r
424\r
425 gBS->CloseEvent (SecondsEvent);\r
426 gBS->CloseEvent (TimeoutEvent);\r
427\r
428 gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);\r
429 AsciiPrint (" ");\r
430\r
431 return Status;\r
432}\r
433\r
434\r
435/**\r
436 Display one menu item.\r
437\r
438 @param MenuItemPtr Pointer to PXE menu item\r
439 option.\r
440\r
441 @return None\r
442\r
443**/\r
772db4bb 444VOID\r
445PrintMenuItem (\r
446 PXE_BOOT_MENU_ENTRY *MenuItemPtr\r
447 )\r
448{\r
449 UINT8 Length;\r
450 UINT8 SaveChar;\r
451\r
452 Length = (UINT8) MIN (70, MenuItemPtr->DataLen);\r
453 SaveChar = MenuItemPtr->Data[Length];\r
454\r
455 MenuItemPtr->Data[Length] = 0;\r
456 AsciiPrint (" %a\n", MenuItemPtr->Data);\r
457 MenuItemPtr->Data[Length] = SaveChar;\r
458}\r
459\r
460\r
461/**\r
462 Display and process menu.\r
463\r
464 @param Private Pointer to PxeBc interface\r
465 @param RxBufferPtr Pointer to receive buffer\r
466\r
467 @retval NO_MENU\r
468 @retval LOCAL_BOOT\r
469\r
470**/\r
772db4bb 471EFI_STATUS\r
472DoMenu (\r
473 PXE_BASECODE_DEVICE *Private,\r
474 DHCP_RECEIVE_BUFFER *RxBufferPtr\r
475 )\r
476{\r
477 PXE_OP_DISCOVERY_CONTROL *DiscoveryControlPtr;\r
478 PXE_BOOT_MENU_ENTRY *MenuItemPtrs[MAX_MENULIST];\r
479 EFI_STATUS Status;\r
480 UNION_PTR Ptr;\r
481 UINTN SaveNumRte;\r
482 UINTN TopRow;\r
483 UINTN MenuLth;\r
484 UINTN NumMenuItems;\r
485 UINTN Index;\r
486 UINTN Longest;\r
487 UINTN Selected;\r
488 UINT16 Type;\r
489 UINT16 Layer;\r
490 BOOLEAN Done;\r
491\r
492 Selected = 0;\r
493 Layer = 0;\r
494\r
495 DEBUG ((DEBUG_WARN, "\nDoMenu() Enter."));\r
496\r
497 /* see if we have a menu/prompt */\r
498 if (!(RxBufferPtr->OpAdds.Status & DISCOVER_TYPE)) {\r
499 DEBUG (\r
500 (DEBUG_WARN,\r
501 "\nDoMenu() No menu/prompt info. OpAdds.Status == %xh ",\r
502 RxBufferPtr->OpAdds.Status)\r
503 );\r
504\r
505 return NO_MENU;\r
506 }\r
507\r
508 DiscoveryControlPtr = (PXE_OP_DISCOVERY_CONTROL *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];\r
509\r
510 //\r
511 // if not USE_BOOTFILE or no bootfile given, must have menu stuff\r
512 //\r
513 if ((DiscoveryControlPtr->ControlBits & USE_BOOTFILE) && RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {\r
514 DEBUG ((DEBUG_WARN, "\nDoMenu() DHCP w/ bootfile. "));\r
515 return NO_MENU;\r
516 }\r
517 //\r
518 // do prompt & menu if necessary\r
519 //\r
520 Status = DoPrompt (Private, (PXE_OP_BOOT_PROMPT *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]);\r
521\r
522 if (Status == LOCAL_BOOT) {\r
523 DEBUG ((DEBUG_WARN, "\nDoMenu() DoPrompt() returned LOCAL_BOOT. "));\r
524\r
525 return Status;\r
526 }\r
527\r
528 Ptr.BytePtr = (UINT8 *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];\r
529\r
530 MenuLth = Ptr.MenuPtr->Header.Length;\r
531 Ptr.CurrentMenuItemPtr = Ptr.MenuPtr->MenuItem;\r
532\r
533 //\r
534 // build menu items array\r
535 //\r
536 for (Longest = NumMenuItems = Index = 0; Index < MenuLth && NumMenuItems < MAX_MENULIST;) {\r
537 UINTN lth;\r
538\r
539 lth = Ptr.CurrentMenuItemPtr->DataLen + sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data);\r
540\r
541 MenuItemPtrs[NumMenuItems++] = Ptr.CurrentMenuItemPtr;\r
542\r
543 if (lth > Longest) {\r
544 //\r
545 // check if too long\r
546 //\r
547 if ((Longest = lth) > 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))) {\r
548 Longest = 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data));\r
549 }\r
550 }\r
551\r
552 Index += lth;\r
553 Ptr.BytePtr += lth;\r
554 }\r
555\r
556 if (Status != AUTO_SELECT) {\r
557 UINT8 BlankBuf[75];\r
558\r
559 SetMem (BlankBuf, sizeof BlankBuf, ' ');\r
560 BlankBuf[Longest + 5 - (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))] = 0;\r
561 AsciiPrint ("\n");\r
562\r
563 //\r
564 // now put up menu\r
565 //\r
566 for (Index = 0; Index < NumMenuItems; ++Index) {\r
567 PrintMenuItem (MenuItemPtrs[Index]);\r
568 }\r
569\r
570 TopRow = gST->ConOut->Mode->CursorRow - NumMenuItems;\r
571\r
572 //\r
573 // now wait for a selection\r
574 //\r
575 Done = FALSE;\r
576 do {\r
577 //\r
578 // highlight selection\r
579 //\r
580 EFI_INPUT_KEY Key;\r
581 UINTN NewSelected;\r
582\r
583 NewSelected = Selected;\r
584\r
585 //\r
586 // highlight selected row\r
587 //\r
588 gST->ConOut->SetAttribute (\r
589 gST->ConOut,\r
590 EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)\r
591 );\r
592 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Selected);\r
593\r
594 AsciiPrint (" --->%a\r", BlankBuf);\r
595\r
596 PrintMenuItem (MenuItemPtrs[Selected]);\r
597 gST->ConOut->SetAttribute (\r
598 gST->ConOut,\r
599 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)\r
600 );\r
601 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + NumMenuItems);\r
602\r
603 //\r
604 // wait for a keystroke\r
605 //\r
606 while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {\r
607 UINT8 TmpBuf[512];\r
608 UINTN TmpBufLen;\r
609\r
610 TmpBufLen = sizeof TmpBuf;\r
611\r
612 Private->EfiBc.UdpRead (\r
613 &Private->EfiBc,\r
614 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |\r
615 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |\r
616 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,\r
617 NULL, /* dest ip */\r
618 NULL, /* dest port */\r
619 NULL, /* src ip */\r
620 NULL, /* src port */\r
621 NULL, /* hdr size */\r
622 NULL, /* hdr ptr */\r
623 &TmpBufLen,\r
624 TmpBuf\r
625 );\r
626 }\r
627\r
628 if (!Key.ScanCode) {\r
629 switch (Key.UnicodeChar) {\r
630 case Ctl ('c'):\r
631 Key.ScanCode = SCAN_ESC;\r
632 break;\r
633\r
634 case Ctl ('j'): /* linefeed */\r
635 case Ctl ('m'): /* return */\r
636 Done = TRUE;\r
637 break;\r
638\r
639 case Ctl ('i'): /* tab */\r
640 case ' ':\r
641 case 'd':\r
642 case 'D':\r
643 Key.ScanCode = SCAN_DOWN;\r
644 break;\r
645\r
646 case Ctl ('h'): /* backspace */\r
647 case 'u':\r
648 case 'U':\r
649 Key.ScanCode = SCAN_UP;\r
650 break;\r
651\r
652 default:\r
653 Key.ScanCode = 0;\r
654 }\r
655 }\r
656\r
657 switch (Key.ScanCode) {\r
658 case SCAN_LEFT:\r
659 case SCAN_UP:\r
660 if (NewSelected) {\r
661 --NewSelected;\r
662 }\r
663\r
664 break;\r
665\r
666 case SCAN_DOWN:\r
667 case SCAN_RIGHT:\r
668 if (++NewSelected == NumMenuItems) {\r
669 --NewSelected;\r
670 }\r
671\r
672 break;\r
673\r
674 case SCAN_PAGE_UP:\r
675 case SCAN_HOME:\r
676 NewSelected = 0;\r
677 break;\r
678\r
679 case SCAN_PAGE_DOWN:\r
680 case SCAN_END:\r
681 NewSelected = NumMenuItems - 1;\r
682 break;\r
683\r
684 case SCAN_ESC:\r
685 return LOCAL_BOOT;\r
686 }\r
687\r
688 /* unhighlight last selected row */\r
689 gST->ConOut->SetCursorPosition (gST->ConOut, 5, TopRow + Selected);\r
690\r
691 AsciiPrint ("%a\r", BlankBuf);\r
692\r
693 PrintMenuItem (MenuItemPtrs[Selected]);\r
694\r
695 Selected = NewSelected;\r
696 } while (!Done);\r
697 }\r
698\r
699 SaveNumRte = Private->EfiBc.Mode->RouteTableEntries;\r
700\r
701 Type = NTOHS (MenuItemPtrs[Selected]->Type);\r
702\r
703 if (Type == 0) {\r
704 DEBUG ((DEBUG_WARN, "\nDoMenu() Local boot selected. "));\r
705 return LOCAL_BOOT;\r
706 }\r
707\r
708 AsciiPrint ("Discover");\r
709\r
710 Status = Private->EfiBc.Discover (\r
711 &Private->EfiBc,\r
712 Type,\r
713 &Layer,\r
714 (BOOLEAN) (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected),\r
715 0\r
716 );\r
717\r
718 if (EFI_ERROR (Status)) {\r
719 AsciiPrint ("\r \r");\r
720\r
721 DEBUG (\r
722 (DEBUG_WARN,\r
723 "\nDoMenu() Return w/ %xh (%r).",\r
724 Status,\r
725 Status)\r
726 );\r
727\r
728 return Status;\r
729 }\r
730\r
731 AsciiPrint ("\rBOOT_SERVER_IP: ");\r
732 PrintIpv4 ((UINT8 *) &Private->ServerIp);\r
733\r
734 for (Index = SaveNumRte; Index < Private->EfiBc.Mode->RouteTableEntries; ++Index) {\r
735 if ((Index % 3) == 0) {\r
736 AsciiPrint ("\r\nGATEWAY IP:");\r
737 }\r
738\r
739 AsciiPrint (" ");\r
740 PrintIpv4 ((UINT8 *) &Private->EfiBc.Mode->RouteTable[Index].GwAddr);\r
741 AsciiPrint (" ");\r
742 }\r
743\r
744 AsciiPrint ("\n");\r
745\r
746 DEBUG ((DEBUG_WARN, "\nDoMenu() Return w/ EFI_SUCCESS. "));\r
747\r
748 return EFI_SUCCESS;\r
749}\r
750\r
751\r
752/**\r
753 Get value 8- or 16-bit value from DHCP option.\r
754\r
755 @param OpPtr Pointer to DHCP option\r
756\r
757 @return Value from DHCP option\r
758\r
759**/\r
772db4bb 760UINT16\r
761GetValue (\r
762 DHCPV4_OP_STRUCT *OpPtr\r
763 )\r
764{\r
765 if (OpPtr->Header.Length == 1) {\r
766 return OpPtr->Data[0];\r
767 } else {\r
768 return NTOHS (OpPtr->Data);\r
769 }\r
770}\r
771\r
772\r
773/**\r
774 Locate opcode in buffer.\r
775\r
776 @param BufferPtr Pointer to buffer\r
777 @param BufferLen Length of buffer\r
778 @param OpCode Option number\r
779\r
780 @return Pointer to opcode, may be NULL\r
781\r
782**/\r
772db4bb 783UINT8 *\r
784_PxeBcFindOpt (\r
785 UINT8 *BufferPtr,\r
786 UINTN BufferLen,\r
787 UINT8 OpCode\r
788 )\r
789{\r
790 if (BufferPtr == NULL) {\r
791 return NULL;\r
792 }\r
793\r
794 while (BufferLen != 0) {\r
795 if (*BufferPtr == OpCode) {\r
796 return BufferPtr;\r
797 }\r
798\r
799 switch (*BufferPtr) {\r
800 case OP_END:\r
801 return NULL;\r
802\r
803 case OP_PAD:\r
804 ++BufferPtr;\r
805 --BufferLen;\r
806 continue;\r
807 }\r
808\r
809 if ((UINTN) BufferLen <= (UINTN) 2 + BufferPtr[1]) {\r
810 return NULL;\r
811 }\r
812\r
813 BufferLen -= 2 + BufferPtr[1];\r
814 BufferPtr += 2 + BufferPtr[1];\r
815 }\r
816\r
817 return NULL;\r
818}\r
819\r
820\r
821/**\r
822 Find option in packet\r
823\r
824 @param PacketPtr Pointer to packet\r
825 @param OpCode option number\r
826\r
827 @return Pointer to option in packet\r
828\r
829**/\r
772db4bb 830UINT8 *\r
831PxeBcFindDhcpOpt (\r
832 EFI_PXE_BASE_CODE_PACKET *PacketPtr,\r
833 UINT8 OpCode\r
834 )\r
835{\r
836 UINTN PacketLen;\r
837 UINT8 Overload;\r
838 UINT8 *OptionBufferPtr;\r
839\r
840 //\r
841 //\r
842 //\r
843 PacketLen = 380;\r
844 Overload = 0;\r
845\r
846 //\r
847 // Figure size of DHCP option space.\r
848 //\r
849 OptionBufferPtr = _PxeBcFindOpt (\r
850 PacketPtr->Dhcpv4.DhcpOptions,\r
851 380,\r
852 OP_DHCP_MAX_MESSAGE_SZ\r
853 );\r
854\r
855 if (OptionBufferPtr != NULL) {\r
856 if (OptionBufferPtr[1] == 2) {\r
857 UINT16 n;\r
858\r
859 CopyMem (&n, &OptionBufferPtr[2], 2);\r
860 PacketLen = HTONS (n);\r
861\r
862 if (PacketLen < sizeof (EFI_PXE_BASE_CODE_DHCPV4_PACKET)) {\r
863 PacketLen = 380;\r
864 } else {\r
865 PacketLen -= (PacketPtr->Dhcpv4.DhcpOptions - &PacketPtr->Dhcpv4.BootpOpcode) + 28;\r
866 }\r
867 }\r
868 }\r
869 //\r
870 // Look for option overloading.\r
871 //\r
872 OptionBufferPtr = _PxeBcFindOpt (\r
873 PacketPtr->Dhcpv4.DhcpOptions,\r
874 PacketLen,\r
875 OP_DHCP_OPTION_OVERLOAD\r
876 );\r
877\r
878 if (OptionBufferPtr != NULL) {\r
879 if (OptionBufferPtr[1] == 1) {\r
880 Overload = OptionBufferPtr[2];\r
881 }\r
882 }\r
883 //\r
884 // Look for caller's option.\r
885 //\r
886 OptionBufferPtr = _PxeBcFindOpt (\r
887 PacketPtr->Dhcpv4.DhcpOptions,\r
888 PacketLen,\r
889 OpCode\r
890 );\r
891\r
892 if (OptionBufferPtr != NULL) {\r
893 return OptionBufferPtr;\r
894 }\r
895\r
896 if (Overload & OVLD_FILE) {\r
897 OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpBootFile, 128, OpCode);\r
898\r
899 if (OptionBufferPtr != NULL) {\r
900 return OptionBufferPtr;\r
901 }\r
902 }\r
903\r
904 if (Overload & OVLD_SRVR_NAME) {\r
905 OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpSrvName, 64, OpCode);\r
906\r
907 if (OptionBufferPtr != NULL) {\r
908 return OptionBufferPtr;\r
909 }\r
910 }\r
911\r
912 return NULL;\r
913}\r
914\r
915\r
916/**\r
917 Download file into buffer\r
918\r
919 @param Private Pointer to PxeBc interface\r
920 @param BufferSize pointer to size of download\r
921 buffer\r
922 @param Buffer Pointer to buffer\r
923\r
924 @return EFI_BUFFER_TOO_SMALL -\r
925 @return EFI_NOT_FOUND -\r
926 @return EFI_PROTOCOL_ERROR -\r
927\r
928**/\r
772db4bb 929EFI_STATUS\r
930DownloadFile (\r
931 IN PXE_BASECODE_DEVICE *Private,\r
932 IN OUT UINT64 *BufferSize,\r
933 IN VOID *Buffer\r
934 )\r
935{\r
936 EFI_PXE_BASE_CODE_MTFTP_INFO MtftpInfo;\r
937 EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode;\r
938 DHCP_RECEIVE_BUFFER *RxBuf;\r
939 EFI_STATUS Status;\r
940 UINTN BlockSize;\r
941\r
942 RxBuf = (DHCP_RECEIVE_BUFFER *) Private->BootServerReceiveBuffer;\r
943 BlockSize = 0x8000;\r
944\r
945 DEBUG ((EFI_D_WARN, "\nDownloadFile() Enter."));\r
946\r
947 if (Buffer == NULL || *BufferSize == 0 || *BufferSize < Private->FileSize) {\r
948 if (Private->FileSize != 0) {\r
949 *BufferSize = Private->FileSize;\r
950 return EFI_BUFFER_TOO_SMALL;\r
951 }\r
952\r
953 AsciiPrint ("\nTSize");\r
954\r
955 OpCode = EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE;\r
956 } else if (RxBuf->OpAdds.Status & WfM11a_TYPE) {\r
957 OpCode = EFI_PXE_BASE_CODE_MTFTP_READ_FILE;\r
958\r
959 ZeroMem (&MtftpInfo, sizeof MtftpInfo);\r
960\r
961 *(IPV4_ADDR *) &MtftpInfo.MCastIp = *(IPV4_ADDR *) RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_IP - 1]->Data;\r
962\r
963 CopyMem (\r
964 &MtftpInfo.CPort,\r
965 RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_CPORT - 1]->Data,\r
966 sizeof MtftpInfo.CPort\r
967 );\r
968\r
969 CopyMem (\r
970 &MtftpInfo.SPort,\r
971 RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_SPORT - 1]->Data,\r
972 sizeof MtftpInfo.SPort\r
973 );\r
974\r
975 MtftpInfo.ListenTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_TMOUT - 1]);\r
976\r
977 MtftpInfo.TransmitTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_DELAY - 1]);\r
978\r
979 AsciiPrint ("\nMTFTP");\r
980 } else {\r
981 AsciiPrint ("\nTFTP");\r
982\r
983 OpCode = EFI_PXE_BASE_CODE_TFTP_READ_FILE;\r
984 }\r
985\r
986 Private->FileSize = 0;\r
987\r
988 RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data[RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length] = 0;\r
989\r
990 Status = Private->EfiBc.Mtftp (\r
991 &Private->EfiBc,\r
992 OpCode,\r
993 Buffer,\r
994 FALSE,\r
995 BufferSize,\r
996 &BlockSize,\r
997 &Private->ServerIp,\r
998 (UINT8 *) RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data,\r
999 &MtftpInfo,\r
1000 FALSE\r
1001 );\r
1002\r
1003 if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) {\r
1004 DEBUG ((DEBUG_WARN, "\nDownloadFile() Exit #1 %Xh", Status));\r
1005 return Status;\r
1006 }\r
1007\r
1008 if (sizeof (UINTN) < sizeof (UINT64) && *BufferSize > 0xFFFFFFFF) {\r
1009 Private->FileSize = 0xFFFFFFFF;\r
1010 } else {\r
1011 Private->FileSize = (UINTN) *BufferSize;\r
1012 }\r
1013\r
1014 if (OpCode == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {\r
1015 DEBUG ((DEBUG_WARN, "\nDownloadFile() Exit #2"));\r
1016 return EFI_BUFFER_TOO_SMALL;\r
1017 }\r
1018\r
1019 if (EFI_ERROR (Status)) {\r
1020 DEBUG ((DEBUG_WARN, "\nDownloadFile() Exit #3 %Xh", Status));\r
1021 return Status;\r
1022 }\r
1023\r
1024 if (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected && Private->EfiBc.Mode->PxeBisReplyReceived) {\r
1025 UINT64 CredentialLen;\r
772db4bb 1026 UINT8 CredentialFilename[256];\r
1027 UINT8 *op;\r
1028 VOID *CredentialBuffer;\r
1029\r
1030 //\r
1031 // Get name of credential file. It may be in the BOOTP\r
1032 // bootfile field or a DHCP option.\r
1033 //\r
1034 ZeroMem (CredentialFilename, sizeof CredentialFilename);\r
1035\r
1036 op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_DHCP_BOOTFILE);\r
1037\r
1038 if (op != NULL) {\r
1039 if (op[1] == 0) {\r
1040 /* No credential filename */\r
1041 return EFI_NOT_FOUND;\r
1042 }\r
1043\r
1044 CopyMem (CredentialFilename, &op[2], op[1]);\r
1045 } else {\r
1046 if (Private->EfiBc.Mode->PxeBisReply.Dhcpv4.BootpBootFile[0] == 0) {\r
1047 /* No credential filename */\r
1048 return EFI_NOT_FOUND;\r
1049 }\r
1050\r
1051 CopyMem (CredentialFilename, &op[2], 128);\r
1052 }\r
1053 //\r
1054 // Get size of credential file. It may be available as a\r
1055 // DHCP option. If not, use the TFTP get file size.\r
1056 //\r
1057 CredentialLen = 0;\r
1058\r
1059 op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_BOOT_FILE_SZ);\r
1060\r
1061 if (op != NULL) {\r
1062 /*\r
1063 * This is actually the size of the credential file\r
1064 * buffer. The actual credential file size will be\r
1065 * returned when we download the file.\r
1066 */\r
1067 if (op[1] == 2) {\r
1068 UINT16 n;\r
1069\r
1070 CopyMem (&n, &op[2], 2);\r
1071 CredentialLen = HTONS (n) * 512;\r
1072 }\r
1073 }\r
1074\r
1075 if (CredentialLen == 0) {\r
1076 BlockSize = 8192;\r
1077\r
1078 Status = Private->EfiBc.Mtftp (\r
1079 &Private->EfiBc,\r
1080 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,\r
1081 NULL,\r
1082 FALSE,\r
1083 &CredentialLen,\r
1084 &BlockSize,\r
1085 &Private->ServerIp,\r
1086 CredentialFilename,\r
1087 NULL,\r
1088 FALSE\r
1089 );\r
1090\r
1091 if (EFI_ERROR (Status)) {\r
1092 return Status;\r
1093 }\r
1094\r
1095 if (CredentialLen == 0) {\r
1096 //\r
1097 // %%TBD -- EFI error for invalid credential\r
1098 // file.\r
1099 //\r
1100 return EFI_PROTOCOL_ERROR;\r
1101 }\r
1102 }\r
1103 //\r
1104 // Allocate credential file buffer.\r
1105 //\r
1106 Status = gBS->AllocatePool (\r
1107 EfiBootServicesData,\r
1108 (UINTN) CredentialLen,\r
1109 &CredentialBuffer\r
1110 );\r
1111\r
1112 if (EFI_ERROR (Status)) {\r
1113 return Status;\r
1114 }\r
1115 //\r
1116 // Download credential file.\r
1117 //\r
1118 BlockSize = 8192;\r
1119\r
1120 Status = Private->EfiBc.Mtftp (\r
1121 &Private->EfiBc,\r
1122 EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
1123 CredentialBuffer,\r
1124 FALSE,\r
1125 &CredentialLen,\r
1126 &BlockSize,\r
1127 &Private->ServerIp,\r
1128 CredentialFilename,\r
1129 NULL,\r
1130 FALSE\r
1131 );\r
1132\r
1133 if (EFI_ERROR (Status)) {\r
1134 gBS->FreePool (CredentialBuffer);\r
1135 return Status;\r
1136 }\r
1137 //\r
1138 // Verify credentials.\r
1139 //\r
1140 if (PxebcBisVerify (Private, Buffer, Private->FileSize, CredentialBuffer, (UINTN) CredentialLen)) {\r
1141 Status = EFI_SUCCESS;\r
1142 } else {\r
1143 //\r
1144 // %%TBD -- An EFI error code for failing credential verification.\r
1145 //\r
1146 Status = EFI_PROTOCOL_ERROR;\r
1147 }\r
1148\r
1149 gBS->FreePool (CredentialBuffer);\r
1150 }\r
1151\r
1152 return Status;\r
1153}\r
1154\r
1155\r
1156/**\r
1157 Start PXE DHCP. Get DHCP and proxyDHCP information.\r
1158 Display remote boot menu and prompt. Select item from menu.\r
1159\r
1160 @param Private Pointer to PxeBc interface\r
1161 @param BufferSize Pointer to download buffer\r
1162 size\r
1163 @param Buffer Pointer to download buffer\r
1164\r
1165 @retval EFI_SUCCESS\r
1166 @retval EFI_NOT_READY\r
1167\r
1168**/\r
772db4bb 1169EFI_STATUS\r
1170LoadfileStart (\r
1171 IN PXE_BASECODE_DEVICE *Private,\r
1172 IN OUT UINT64 *BufferSize,\r
1173 IN VOID *Buffer\r
1174 )\r
1175{\r
1176 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
1177 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
1178 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
1179 EFI_STATUS Status;\r
1180 VOID *RxBuf;\r
1181\r
1182 DEBUG ((DEBUG_WARN, "\nLoadfileStart() Enter."));\r
1183\r
1184 //\r
1185 // Try to start BaseCode, for now only IPv4 is supported\r
1186 // so don't try to start using IPv6.\r
1187 //\r
1188 Status = Private->EfiBc.Start (&Private->EfiBc, FALSE);\r
1189\r
1190 if (EFI_ERROR (Status)) {\r
1191 if (Status != EFI_ALREADY_STARTED) {\r
1192 DEBUG ((DEBUG_NET, "\nLoadfileStart() Exit BC.Start() == %xh", Status));\r
1193 return Status;\r
1194 }\r
1195 }\r
1196 //\r
1197 // Get pointers to PXE mode structure, SNP protocol structure\r
1198 // and SNP mode structure.\r
1199 //\r
1200 PxeBcMode = Private->EfiBc.Mode;\r
1201 Snp = Private->SimpleNetwork;\r
1202 SnpMode = Snp->Mode;\r
1203\r
1204 //\r
1205 // Display client MAC address, like 16-bit PXE ROMs\r
1206 //\r
1207 AsciiPrint ("\nCLIENT MAC ADDR: ");\r
1208\r
1209 {\r
1210 UINTN Index;\r
1211 UINTN hlen;\r
1212\r
1213 hlen = SnpMode->HwAddressSize;\r
1214\r
1215 for (Index = 0; Index < hlen; ++Index) {\r
1216 AsciiPrint ("%02x ", SnpMode->CurrentAddress.Addr[Index]);\r
1217 }\r
1218 }\r
1219\r
1220 AsciiPrint ("\nDHCP");\r
1221\r
1222 Status = Private->EfiBc.Dhcp (&Private->EfiBc, TRUE);\r
1223\r
1224 if (EFI_ERROR (Status)) {\r
1225 DEBUG ((DEBUG_WARN, "\nLoadfileStart() Exit BC.Dhcp() == %Xh", Status));\r
1226 AsciiPrint ("\r \r");\r
1227 return Status;\r
1228 }\r
1229\r
1230 ShowMyInfo (Private);\r
1231\r
1232 RxBuf = PxeBcMode->ProxyOfferReceived ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;\r
1233#define RxBufferPtr ((DHCP_RECEIVE_BUFFER *) RxBuf)\r
1234\r
1235 Status = DoMenu (Private, RxBufferPtr);\r
1236\r
1237 if (Status == EFI_SUCCESS) {\r
1238 //\r
1239 // did a discovery - take info from discovery packet\r
1240 //\r
1241 RxBuf = &PXE_ACK_BUFFER;\r
1242 } else if (Status == NO_MENU) {\r
1243 //\r
1244 // did not do a discovery - take info from rxbuf\r
1245 //\r
1246 Private->ServerIp.Addr[0] = RxBufferPtr->u.Dhcpv4.siaddr;\r
1247\r
1248 if (!(Private->ServerIp.Addr[0])) {\r
1249 *(IPV4_ADDR *) &Private->ServerIp = *(IPV4_ADDR *) RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]->Data;\r
1250 }\r
1251 } else {\r
1252 DEBUG ((DEBUG_WARN, "\nLoadfileStart() Exit DoMenu() == %Xh", Status));\r
1253 return Status;\r
1254 }\r
1255\r
1256 if (!RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {\r
1257 DEBUG ((DEBUG_WARN, "\nLoadfileStart() Exit Not ready?"));\r
1258 return EFI_NOT_READY;\r
1259 }\r
1260 //\r
1261 // check for file size option sent\r
1262 //\r
1263 if (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]) {\r
1264 Private->FileSize = 512 * NTOHS (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]->Data);\r
1265 }\r
1266\r
1267 Private->BootServerReceiveBuffer = RxBufferPtr;\r
1268\r
1269 Status = DownloadFile (Private, BufferSize, Buffer);\r
1270\r
1271 DEBUG (\r
1272 (DEBUG_WARN,\r
1273 "\nLoadfileStart() Exit. DownloadFile() = %Xh",\r
1274 Status)\r
1275 );\r
1276\r
1277 return Status;\r
1278}\r
1279\r
1280\r
1281/**\r
1282 Loadfile interface for PxeBc interface\r
1283\r
1284 @param This Pointer to Loadfile interface\r
1285 @param FilePath Not used and not checked\r
1286 @param BootPolicy Must be TRUE\r
1287 @param BufferSize Pointer to buffer size\r
1288 @param Buffer Pointer to download buffer or\r
1289 NULL\r
1290\r
1291 @return EFI_INVALID_PARAMETER -\r
1292 @return EFI_UNSUPPORTED -\r
1293 @return EFI_SUCCESS -\r
1294 @return EFI_BUFFER_TOO_SMALL -\r
1295\r
1296**/\r
1297EFI_STATUS\r
1298EFIAPI\r
1299LoadFile (\r
1300 IN EFI_LOAD_FILE_PROTOCOL *This,\r
1301 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1302 IN BOOLEAN BootPolicy,\r
1303 IN OUT UINTN *BufferSize,\r
1304 IN OUT VOID *Buffer\r
1305 )\r
1306{\r
1307 LOADFILE_DEVICE *LoadfilePtr;\r
1308 UINT64 TmpBufSz;\r
1309 INT32 OrigMode;\r
1310 INT32 OrigAttribute;\r
1311 BOOLEAN RemoveCallback;\r
1312 BOOLEAN NewMakeCallback;\r
1313 EFI_STATUS Status;\r
1314 EFI_STATUS TempStatus;\r
687a2e5f 1315\r
1316 //\r
1317 // The following line is only used for passing ICC build.\r
1318 //\r
0e549d5b 1319 DEBUG ((EFI_D_INFO, "FilePath = %p\n", FilePath));\r
687a2e5f 1320\r
772db4bb 1321 //\r
1322 //\r
1323 //\r
1324 OrigMode = gST->ConOut->Mode->Mode;\r
1325 OrigAttribute = gST->ConOut->Mode->Attribute;\r
1326 RemoveCallback = FALSE;\r
1327\r
1328 AsciiPrint ("Running LoadFile()\n");\r
1329\r
1330 //\r
1331 // Resolve Warning 4 unreferenced parameter problem\r
1332 //\r
1333 FilePath = NULL;\r
1334\r
1335 //\r
1336 // If either if these parameters are NULL, we cannot continue.\r
1337 //\r
1338 if (This == NULL || BufferSize == NULL) {\r
1339 DEBUG ((DEBUG_WARN, "\nLoadFile() This or BufferSize == NULL"));\r
1340 return EFI_INVALID_PARAMETER;\r
1341 }\r
1342 //\r
1343 // We only support BootPolicy == TRUE\r
1344 //\r
1345 if (!BootPolicy) {\r
1346 DEBUG ((DEBUG_WARN, "\nLoadFile() BootPolicy == FALSE"));\r
1347 return EFI_UNSUPPORTED;\r
1348 }\r
1349 //\r
1350 // Get pointer to LoadFile protocol structure.\r
1351 //\r
1352 LoadfilePtr = CR (This, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE);\r
1353\r
1354 if (LoadfilePtr == NULL) {\r
1355 DEBUG (\r
1356 (DEBUG_NET,\r
1357 "\nLoadFile() Could not get pointer to LoadFile structure")\r
1358 );\r
1359 return EFI_INVALID_PARAMETER;\r
1360 }\r
1361 //\r
1362 // Lock interface\r
1363 //\r
1364 EfiAcquireLock (&LoadfilePtr->Lock);\r
1365\r
1366 //\r
1367 // Set console output mode and display attribute\r
1368 //\r
1369 if (OrigMode != 0) {\r
1370 gST->ConOut->SetMode (gST->ConOut, 0);\r
1371 }\r
1372\r
1373 gST->ConOut->SetAttribute (\r
1374 gST->ConOut,\r
1375 EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK)\r
1376 );\r
1377\r
1378 //\r
1379 // See if BaseCode already has a Callback protocol attached.\r
1380 // If there is none, attach our own Callback protocol.\r
1381 //\r
1382 Status = gBS->HandleProtocol (\r
1383 LoadfilePtr->Private->Handle,\r
1384 &gEfiPxeBaseCodeCallbackProtocolGuid,\r
1385 (VOID *) &LoadfilePtr->Private->CallbackProtocolPtr\r
1386 );\r
1387\r
1388 if (Status == EFI_SUCCESS) {\r
1389 //\r
1390 // There is already a callback routine. Do nothing.\r
1391 //\r
1392 DEBUG ((DEBUG_WARN, "\nLoadFile() BC callback exists."));\r
1393\r
1394 } else if (Status == EFI_UNSUPPORTED) {\r
1395 //\r
1396 // No BaseCode Callback protocol found. Add our own.\r
1397 //\r
1398 Status = gBS->InstallProtocolInterface (\r
1399 &LoadfilePtr->Private->Handle,\r
1400 &gEfiPxeBaseCodeCallbackProtocolGuid,\r
1401 EFI_NATIVE_INTERFACE,\r
1402 &_bc_callback\r
1403 );\r
1404\r
1405 DEBUG ((DEBUG_WARN, "\nLoadFile() Callback install status == %xh", Status));\r
1406\r
1407 RemoveCallback = (BOOLEAN) (Status == EFI_SUCCESS);\r
1408\r
1409 if (LoadfilePtr->Private->EfiBc.Mode != NULL && LoadfilePtr->Private->EfiBc.Mode->Started) {\r
1410 NewMakeCallback = TRUE;\r
1411 LoadfilePtr->Private->EfiBc.SetParameters (\r
1412 &LoadfilePtr->Private->EfiBc,\r
1413 NULL,\r
1414 NULL,\r
1415 NULL,\r
1416 NULL,\r
1417 &NewMakeCallback\r
1418 );\r
1419 }\r
1420\r
1421 } else {\r
1422 DEBUG ((DEBUG_WARN, "\nLoadFile() Callback check status == %xh", Status));\r
1423 }\r
1424 //\r
1425 // Check for starting or for continuing after already getting\r
1426 // the file size.\r
1427 //\r
1428 if (LoadfilePtr->Private->FileSize == 0) {\r
1429 TmpBufSz = 0;\r
1430 Status = LoadfileStart (LoadfilePtr->Private, &TmpBufSz, Buffer);\r
1431\r
1432 if (sizeof (UINTN) < sizeof (UINT64) && TmpBufSz > 0xFFFFFFFF) {\r
1433 *BufferSize = 0xFFFFFFFF;\r
1434 } else {\r
1435 *BufferSize = (UINTN) TmpBufSz;\r
1436 }\r
1437\r
1438 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1439 //\r
1440 // This is done so loadfile will work even if the boot manager\r
1441 // did not make the first call with Buffer == NULL.\r
1442 //\r
1443 Buffer = NULL;\r
1444 }\r
1445 } else if (Buffer == NULL) {\r
1446 DEBUG ((DEBUG_WARN, "\nLoadfile() Get buffer size"));\r
1447\r
1448 //\r
1449 // Continuing from previous LoadFile request. Make sure there\r
1450 // is a buffer and that it is big enough.\r
1451 //\r
1452 *BufferSize = LoadfilePtr->Private->FileSize;\r
1453 Status = EFI_BUFFER_TOO_SMALL;\r
1454 } else {\r
1455 DEBUG ((DEBUG_WARN, "\nLoadFile() Download file"));\r
1456\r
1457 //\r
1458 // Everything looks good, try to download the file.\r
1459 //\r
1460 TmpBufSz = *BufferSize;\r
1461 Status = DownloadFile (LoadfilePtr->Private, &TmpBufSz, Buffer);\r
1462\r
1463 //\r
1464 // Next call to loadfile will start DHCP process again.\r
1465 //\r
1466 LoadfilePtr->Private->FileSize = 0;\r
1467 }\r
1468 //\r
1469 // If we added a callback protocol, now is the time to remove it.\r
1470 //\r
1471 if (RemoveCallback) {\r
1472 NewMakeCallback = FALSE;\r
1473 TempStatus = LoadfilePtr->Private->EfiBc.SetParameters (\r
1474 &LoadfilePtr->Private->EfiBc,\r
1475 NULL,\r
1476 NULL,\r
1477 NULL,\r
1478 NULL,\r
1479 &NewMakeCallback\r
1480 );\r
1481\r
1482 if (TempStatus == EFI_SUCCESS) {\r
1483 gBS->UninstallProtocolInterface (\r
1484 LoadfilePtr->Private->Handle,\r
1485 &gEfiPxeBaseCodeCallbackProtocolGuid,\r
1486 &_bc_callback\r
1487 );\r
1488 }\r
1489 }\r
1490 //\r
1491 // Restore display mode and attribute\r
1492 //\r
1493 if (OrigMode != 0) {\r
1494 gST->ConOut->SetMode (gST->ConOut, OrigMode);\r
1495 }\r
1496\r
1497 gST->ConOut->SetAttribute (gST->ConOut, OrigAttribute);\r
1498\r
1499 //\r
1500 // Unlock interface\r
1501 //\r
1502 EfiReleaseLock (&LoadfilePtr->Lock);\r
1503\r
1504 DEBUG ((DEBUG_WARN, "\nBC.Loadfile() Status == %xh\n", Status));\r
1505\r
1506 if (Status == EFI_SUCCESS) {\r
1507 return EFI_SUCCESS;\r
1508\r
1509 } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
1510 //\r
1511 // Error is only displayed when we are actually trying to\r
1512 // download the boot image.\r
1513 //\r
1514 if (Buffer == NULL) {\r
1515 return EFI_BUFFER_TOO_SMALL;\r
1516 }\r
1517\r
1518 AsciiPrint ("\nPXE-E05: Download buffer is smaller than requested file.\n");\r
1519\r
1520 } else if (Status == EFI_DEVICE_ERROR) {\r
1521 AsciiPrint ("\nPXE-E07: Network device error. Check network connection.\n");\r
1522\r
1523 } else if (Status == EFI_OUT_OF_RESOURCES) {\r
1524 AsciiPrint ("\nPXE-E09: Could not allocate I/O buffers.\n");\r
1525\r
1526 } else if (Status == EFI_NO_MEDIA) {\r
1527 AsciiPrint ("\nPXE-E12: Could not detect network connection. Check cable.\n");\r
1528\r
1529 } else if (Status == EFI_NO_RESPONSE) {\r
1530 AsciiPrint ("\nPXE-E16: Valid PXE offer not received.\n");\r
1531\r
1532 } else if (Status == EFI_TIMEOUT) {\r
1533 AsciiPrint ("\nPXE-E18: Timeout. Server did not respond.\n");\r
1534\r
1535 } else if (Status == EFI_ABORTED) {\r
1536 AsciiPrint ("\nPXE-E21: Remote boot cancelled.\n");\r
1537\r
1538 } else if (Status == EFI_ICMP_ERROR) {\r
1539 AsciiPrint ("\nPXE-E22: Client received ICMP error from server.\n");\r
1540\r
1541 if (LoadfilePtr->Private->EfiBc.Mode != NULL) {\r
1542 if (LoadfilePtr->Private->EfiBc.Mode->IcmpErrorReceived) {\r
1543\r
1544 AsciiPrint (\r
1545 "PXE-E98: Type: %xh Code: %xh ",\r
1546 LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type,\r
1547 LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code\r
1548 );\r
1549\r
1550 switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type) {\r
1551 case 0x03:\r
1552 switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code) {\r
1553 case 0x00: /* net unreachable */\r
1554 AsciiPrint ("Net unreachable");\r
1555 break;\r
1556\r
1557 case 0x01: /* host unreachable */\r
1558 AsciiPrint ("Host unreachable");\r
1559 break;\r
1560\r
1561 case 0x02: /* protocol unreachable */\r
1562 AsciiPrint ("Protocol unreachable");\r
1563 break;\r
1564\r
1565 case 0x03: /* port unreachable */\r
1566 AsciiPrint ("Port unreachable");\r
1567 break;\r
1568\r
1569 case 0x04: /* Fragmentation needed */\r
1570 AsciiPrint ("Fragmentation needed");\r
1571 break;\r
1572\r
1573 case 0x05: /* Source route failed */\r
1574 AsciiPrint ("Source route failed");\r
1575 break;\r
1576 }\r
1577\r
1578 break;\r
1579 }\r
1580\r
1581 AsciiPrint ("\n");\r
1582 }\r
1583 }\r
1584\r
1585 } else if (Status == EFI_TFTP_ERROR) {\r
1586 AsciiPrint ("\nPXE-E23: Client received TFTP error from server.\n");\r
1587\r
1588 if (LoadfilePtr->Private->EfiBc.Mode != NULL) {\r
1589 if (LoadfilePtr->Private->EfiBc.Mode->TftpErrorReceived) {\r
1590 AsciiPrint (\r
1591 "PXE-E98: Code: %xh %a\n",\r
1592 LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorCode,\r
1593 LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorString\r
1594 );\r
1595 }\r
1596 }\r
1597\r
1598 } else {\r
1599 AsciiPrint ("\nPXE-E99: Unexpected network error: %xh\n", Status);\r
1600 }\r
1601\r
1602 LoadfilePtr->Private->EfiBc.Stop (&LoadfilePtr->Private->EfiBc);\r
1603\r
1604 return Status;\r
1605}\r