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