+++ /dev/null
-/*++\r
-\r
-Copyright (c) 2006 - 2007, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-Module Name:\r
- pxe_loadfile.c\r
-\r
-Abstract:\r
- An implementation of the load file protocol for network devices.\r
-\r
---*/\r
-\r
-\r
-#include "Bc.h"\r
-\r
-#define DO_MENU (EFI_SUCCESS)\r
-#define NO_MENU (DO_MENU + 1)\r
-#define LOCAL_BOOT (EFI_ABORTED)\r
-#define AUTO_SELECT (NO_MENU)\r
-\r
-#define NUMBER_ROWS 25 // we set to mode 0\r
-#define MAX_MENULIST 23\r
-\r
-#define Ctl(x) (0x1F & (x))\r
-\r
-typedef union {\r
- DHCPV4_OP_STRUCT *OpPtr;\r
- PXE_BOOT_MENU_ENTRY *CurrentMenuItemPtr;\r
- PXE_OP_DISCOVERY_CONTROL *DiscCtlOpStr;\r
- PXE_OP_BOOT_MENU *MenuPtr;\r
- UINT8 *BytePtr;\r
-} UNION_PTR;\r
-\r
-\r
-STATIC\r
-EFI_PXE_BASE_CODE_CALLBACK_STATUS\r
-EFIAPI\r
-bc_callback (\r
- IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL * This,\r
- IN EFI_PXE_BASE_CODE_FUNCTION Function,\r
- IN BOOLEAN Received,\r
- IN UINT32 PacketLength,\r
- IN EFI_PXE_BASE_CODE_PACKET * PacketPtr OPTIONAL\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- PxeBc callback routine for status updates and aborts.\r
-\r
-Arguments:\r
-\r
- This - Pointer to PxeBcCallback interface\r
- Function - PxeBc function ID#\r
- Received - Receive/transmit flag\r
- PacketLength - Length of received packet (0 == idle callback)\r
- PacketPtr - Pointer to received packet (NULL == idle callback)\r
-\r
-Returns:\r
-\r
- EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE -\r
- EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT -\r
-\r
---*/\r
-{\r
- STATIC UINTN Propeller;\r
-\r
- EFI_INPUT_KEY Key;\r
- UINTN Row;\r
- UINTN Col;\r
-\r
- Propeller = 0;\r
- //\r
- // Resolve Warning 4 unreferenced parameter problem\r
- //\r
- This = This;\r
-\r
- //\r
- // Check for user abort.\r
- //\r
- if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_SUCCESS) {\r
- if (!Key.ScanCode) {\r
- if (Key.UnicodeChar == Ctl ('c')) {\r
- return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;\r
- }\r
- } else if (Key.ScanCode == SCAN_ESC) {\r
- return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;\r
- }\r
- }\r
- //\r
- // Do nothing if this is a receive.\r
- //\r
- if (Received) {\r
- return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
- }\r
- //\r
- // The display code is only for these functions.\r
- //\r
- switch (Function) {\r
- case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:\r
- //\r
- // If this is a transmit and not a M/TFTP open request,\r
- // return now. Do not print a dot for each M/TFTP packet\r
- // that is sent, only for the open packets.\r
- //\r
- if (PacketLength != 0 && PacketPtr != NULL) {\r
- if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {\r
- return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
- }\r
- }\r
-\r
- break;\r
-\r
- case EFI_PXE_BASE_CODE_FUNCTION_DHCP:\r
- case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:\r
- break;\r
-\r
- default:\r
- return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
- }\r
- //\r
- // Display routines\r
- //\r
- if (PacketLength != 0 && PacketPtr != NULL) {\r
- //\r
- // Display a '.' when a packet is transmitted.\r
- //\r
- AsciiPrint (".");\r
- } else if (PacketLength == 0 && PacketPtr == NULL) {\r
- //\r
- // Display a propeller when waiting for packets if at\r
- // least 200 ms have passed.\r
- //\r
- Row = gST->ConOut->Mode->CursorRow;\r
- Col = gST->ConOut->Mode->CursorColumn;\r
-\r
- AsciiPrint ("%c", "/-\\|"[Propeller]);\r
- gST->ConOut->SetCursorPosition (gST->ConOut, Col, Row);\r
-\r
- Propeller = (Propeller + 1) & 3;\r
- }\r
-\r
- return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;\r
-}\r
-\r
-STATIC EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL _bc_callback = {\r
- EFI_PXE_BASE_CODE_CALLBACK_INTERFACE_REVISION,\r
- &bc_callback\r
-};\r
-\r
-STATIC\r
-VOID\r
-PrintIpv4 (\r
- UINT8 *Ptr\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Display an IPv4 address in dot notation.\r
-\r
-Arguments:\r
-\r
- Ptr - Pointer to IPv4 address.\r
-\r
-Returns:\r
-\r
- None\r
-\r
---*/\r
-{\r
- if (Ptr != NULL) {\r
- AsciiPrint ("%d.%d.%d.%d", Ptr[0], Ptr[1], Ptr[2], Ptr[3]);\r
- }\r
-}\r
-\r
-STATIC\r
-VOID\r
-ShowMyInfo (\r
- IN PXE_BASECODE_DEVICE *Private\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Display client and server IP information.\r
-\r
-Arguments:\r
-\r
- Private - Pointer to PxeBc interface\r
-\r
-Returns:\r
-\r
- None\r
-\r
---*/\r
-{\r
- EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
- UINTN Index;\r
-\r
- //\r
- // Do nothing if a NULL pointer is passed in.\r
- //\r
- if (Private == NULL) {\r
- return ;\r
- }\r
- //\r
- // Get pointer to PXE BaseCode mode structure\r
- //\r
- PxeBcMode = Private->EfiBc.Mode;\r
-\r
- //\r
- // Display client IP address\r
- //\r
- AsciiPrint ("\rCLIENT IP: ");\r
- PrintIpv4 (PxeBcMode->StationIp.v4.Addr);\r
-\r
- //\r
- // Display subnet mask\r
- //\r
- AsciiPrint (" MASK: ");\r
- PrintIpv4 (PxeBcMode->SubnetMask.v4.Addr);\r
-\r
- //\r
- // Display DHCP and proxyDHCP IP addresses\r
- //\r
- if (PxeBcMode->ProxyOfferReceived) {\r
- AsciiPrint ("\nDHCP IP: ");\r
- PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);\r
-\r
- AsciiPrint (" PROXY IP: ");\r
- PrintIpv4 (((DHCPV4_OP_SERVER_IP *) PXE_OFFER_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);\r
- } else {\r
- AsciiPrint (" DHCP IP: ");\r
- PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);\r
- }\r
- //\r
- // Display gateway IP addresses\r
- //\r
- for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {\r
- if ((Index % 3) == 0) {\r
- AsciiPrint ("\r\nGATEWAY IP:");\r
- }\r
-\r
- AsciiPrint (" ");\r
- PrintIpv4 (PxeBcMode->RouteTable[Index].GwAddr.v4.Addr);\r
- AsciiPrint (" ");\r
- }\r
-\r
- AsciiPrint ("\n");\r
-}\r
-\r
-STATIC\r
-EFI_STATUS\r
-DoPrompt (\r
- PXE_BASECODE_DEVICE *Private,\r
- PXE_OP_BOOT_PROMPT *BootPromptPtr\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Display prompt and wait for input.\r
-\r
-Arguments:\r
-\r
- Private - Pointer to PxeBc interface\r
- BootPromptPtr - Pointer to PXE boot prompt option\r
-\r
-Returns:\r
-\r
- AUTO_SELECT -\r
- DO_MENU -\r
- NO_MENU -\r
- LOCAL_BOOT -\r
-\r
---*/\r
-{\r
- EFI_STATUS Status;\r
- EFI_EVENT TimeoutEvent;\r
- EFI_EVENT SecondsEvent;\r
- INT32 SecColumn;\r
- INT32 SecRow;\r
- UINT8 SaveChar;\r
- UINT8 SecsLeft;\r
-\r
- //\r
- // if auto select, just get right to it\r
- //\r
- if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_AUTO_SELECT) {\r
- return AUTO_SELECT;\r
- }\r
- //\r
- // if no timeout, go directly to display of menu\r
- //\r
- if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_NO_TIMEOUT) {\r
- return DO_MENU;\r
- }\r
- //\r
- //\r
- //\r
- Status = gBS->CreateEvent (\r
- EVT_TIMER,\r
- TPL_CALLBACK,\r
- NULL,\r
- NULL,\r
- &TimeoutEvent\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return DO_MENU;\r
- }\r
-\r
- Status = gBS->SetTimer (\r
- TimeoutEvent,\r
- TimerRelative,\r
- BootPromptPtr->Timeout * 10000000 + 100000\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- gBS->CloseEvent (TimeoutEvent);\r
- return DO_MENU;\r
- }\r
- //\r
- //\r
- //\r
- Status = gBS->CreateEvent (\r
- EVT_TIMER,\r
- TPL_CALLBACK,\r
- NULL,\r
- NULL,\r
- &SecondsEvent\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- gBS->CloseEvent (TimeoutEvent);\r
- return DO_MENU;\r
- }\r
-\r
- Status = gBS->SetTimer (\r
- SecondsEvent,\r
- TimerPeriodic,\r
- 10000000\r
- ); /* 1 second */\r
-\r
- if (EFI_ERROR (Status)) {\r
- gBS->CloseEvent (SecondsEvent);\r
- gBS->CloseEvent (TimeoutEvent);\r
- return DO_MENU;\r
- }\r
- //\r
- // display the prompt\r
- // IMPORTANT! This prompt is an ASCII character string that may\r
- // not be terminated with a NULL byte.\r
- //\r
- SaveChar = BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1];\r
- BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = 0;\r
-\r
- AsciiPrint ("%a ", BootPromptPtr->Prompt);\r
- BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = SaveChar;\r
-\r
- //\r
- // wait until time expires or selection made - menu or local\r
- //\r
- SecColumn = gST->ConOut->Mode->CursorColumn;\r
- SecRow = gST->ConOut->Mode->CursorRow;\r
- SecsLeft = BootPromptPtr->Timeout;\r
-\r
- gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);\r
- AsciiPrint ("(%d) ", SecsLeft);\r
-\r
- //\r
- // set the default action to be AUTO_SELECT\r
- //\r
- Status = AUTO_SELECT;\r
-\r
- while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
- EFI_INPUT_KEY Key;\r
-\r
- if (!EFI_ERROR (gBS->CheckEvent (SecondsEvent))) {\r
- --SecsLeft;\r
- gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);\r
- AsciiPrint ("(%d) ", SecsLeft);\r
- }\r
-\r
- if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {\r
- UINT8 Buffer[512];\r
- UINTN BufferSize;\r
-\r
- BufferSize = sizeof Buffer;\r
-\r
- Private->EfiBc.UdpRead (\r
- &Private->EfiBc,\r
- EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |\r
- EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |\r
- EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,\r
- NULL, /* dest ip */\r
- NULL, /* dest port */\r
- NULL, /* src ip */\r
- NULL, /* src port */\r
- NULL, /* hdr size */\r
- NULL, /* hdr ptr */\r
- &BufferSize,\r
- Buffer\r
- );\r
-\r
- continue;\r
- }\r
-\r
- if (Key.ScanCode == 0) {\r
- switch (Key.UnicodeChar) {\r
- case Ctl ('c'):\r
- Status = LOCAL_BOOT;\r
- break;\r
-\r
- case Ctl ('m'):\r
- case 'm':\r
- case 'M':\r
- Status = DO_MENU;\r
- break;\r
-\r
- default:\r
- continue;\r
- }\r
- } else {\r
- switch (Key.ScanCode) {\r
- case SCAN_F8:\r
- Status = DO_MENU;\r
- break;\r
-\r
- case SCAN_ESC:\r
- Status = LOCAL_BOOT;\r
- break;\r
-\r
- default:\r
- continue;\r
- }\r
- }\r
-\r
- break;\r
- }\r
-\r
- gBS->CloseEvent (SecondsEvent);\r
- gBS->CloseEvent (TimeoutEvent);\r
-\r
- gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);\r
- AsciiPrint (" ");\r
-\r
- return Status;\r
-}\r
-\r
-STATIC\r
-VOID\r
-PrintMenuItem (\r
- PXE_BOOT_MENU_ENTRY *MenuItemPtr\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Display one menu item.\r
-\r
-Arguments:\r
-\r
- MenuItemPtr - Pointer to PXE menu item option.\r
-\r
-Returns:\r
-\r
- None\r
-\r
---*/\r
-{\r
- UINT8 Length;\r
- UINT8 SaveChar;\r
-\r
- Length = (UINT8) EFI_MIN (70, MenuItemPtr->DataLen);\r
- SaveChar = MenuItemPtr->Data[Length];\r
-\r
- MenuItemPtr->Data[Length] = 0;\r
- AsciiPrint (" %a\n", MenuItemPtr->Data);\r
- MenuItemPtr->Data[Length] = SaveChar;\r
-}\r
-\r
-STATIC\r
-EFI_STATUS\r
-DoMenu (\r
- PXE_BASECODE_DEVICE *Private,\r
- DHCP_RECEIVE_BUFFER *RxBufferPtr\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Display and process menu.\r
-\r
-Arguments:\r
-\r
- Private - Pointer to PxeBc interface\r
- RxBufferPtr - Pointer to receive buffer\r
-\r
-Returns:\r
-\r
- NO_MENU -\r
- LOCAL_BOOT -\r
-\r
---*/\r
-{\r
- PXE_OP_DISCOVERY_CONTROL *DiscoveryControlPtr;\r
- PXE_BOOT_MENU_ENTRY *MenuItemPtrs[MAX_MENULIST];\r
- EFI_STATUS Status;\r
- UNION_PTR Ptr;\r
- UINTN SaveNumRte;\r
- UINTN TopRow;\r
- UINTN MenuLth;\r
- UINTN NumMenuItems;\r
- UINTN Index;\r
- UINTN Longest;\r
- UINTN Selected;\r
- UINT16 Type;\r
- UINT16 Layer;\r
- BOOLEAN Done;\r
-\r
- Selected = 0;\r
- Layer = 0;\r
-\r
- DEBUG ((EFI_D_WARN, "\nDoMenu() Enter."));\r
-\r
- /* see if we have a menu/prompt */\r
- if (!(RxBufferPtr->OpAdds.Status & DISCOVER_TYPE)) {\r
- DEBUG (\r
- (EFI_D_WARN,\r
- "\nDoMenu() No menu/prompt info. OpAdds.Status == %xh ",\r
- RxBufferPtr->OpAdds.Status)\r
- );\r
-\r
- return NO_MENU;\r
- }\r
-\r
- DiscoveryControlPtr = (PXE_OP_DISCOVERY_CONTROL *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];\r
-\r
- //\r
- // if not USE_BOOTFILE or no bootfile given, must have menu stuff\r
- //\r
- if ((DiscoveryControlPtr->ControlBits & USE_BOOTFILE) && RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {\r
- DEBUG ((EFI_D_WARN, "\nDoMenu() DHCP w/ bootfile. "));\r
- return NO_MENU;\r
- }\r
- //\r
- // do prompt & menu if necessary\r
- //\r
- Status = DoPrompt (Private, (PXE_OP_BOOT_PROMPT *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]);\r
-\r
- if (Status == LOCAL_BOOT) {\r
- DEBUG ((EFI_D_WARN, "\nDoMenu() DoPrompt() returned LOCAL_BOOT. "));\r
-\r
- return Status;\r
- }\r
-\r
- Ptr.BytePtr = (UINT8 *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];\r
-\r
- MenuLth = Ptr.MenuPtr->Header.Length;\r
- Ptr.CurrentMenuItemPtr = Ptr.MenuPtr->MenuItem;\r
-\r
- //\r
- // build menu items array\r
- //\r
- for (Longest = NumMenuItems = Index = 0; Index < MenuLth && NumMenuItems < MAX_MENULIST;) {\r
- UINTN lth;\r
-\r
- lth = Ptr.CurrentMenuItemPtr->DataLen + sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data);\r
-\r
- MenuItemPtrs[NumMenuItems++] = Ptr.CurrentMenuItemPtr;\r
-\r
- if (lth > Longest) {\r
- //\r
- // check if too long\r
- //\r
- if ((Longest = lth) > 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))) {\r
- Longest = 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data));\r
- }\r
- }\r
-\r
- Index += lth;\r
- Ptr.BytePtr += lth;\r
- }\r
-\r
- if (Status != AUTO_SELECT) {\r
- UINT8 BlankBuf[75];\r
-\r
- SetMem (BlankBuf, sizeof BlankBuf, ' ');\r
- BlankBuf[Longest + 5 - (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))] = 0;\r
- AsciiPrint ("\n");\r
-\r
- //\r
- // now put up menu\r
- //\r
- for (Index = 0; Index < NumMenuItems; ++Index) {\r
- PrintMenuItem (MenuItemPtrs[Index]);\r
- }\r
-\r
- TopRow = gST->ConOut->Mode->CursorRow - NumMenuItems;\r
-\r
- //\r
- // now wait for a selection\r
- //\r
- Done = FALSE;\r
- do {\r
- //\r
- // highlight selection\r
- //\r
- EFI_INPUT_KEY Key;\r
- UINTN NewSelected;\r
-\r
- NewSelected = Selected;\r
-\r
- //\r
- // highlight selected row\r
- //\r
- gST->ConOut->SetAttribute (\r
- gST->ConOut,\r
- EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)\r
- );\r
- gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Selected);\r
-\r
- AsciiPrint (" --->%a\r", BlankBuf);\r
-\r
- PrintMenuItem (MenuItemPtrs[Selected]);\r
- gST->ConOut->SetAttribute (\r
- gST->ConOut,\r
- EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)\r
- );\r
- gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + NumMenuItems);\r
-\r
- //\r
- // wait for a keystroke\r
- //\r
- while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {\r
- UINT8 TmpBuf[512];\r
- UINTN TmpBufLen;\r
-\r
- TmpBufLen = sizeof TmpBuf;\r
-\r
- Private->EfiBc.UdpRead (\r
- &Private->EfiBc,\r
- EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |\r
- EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |\r
- EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,\r
- NULL, /* dest ip */\r
- NULL, /* dest port */\r
- NULL, /* src ip */\r
- NULL, /* src port */\r
- NULL, /* hdr size */\r
- NULL, /* hdr ptr */\r
- &TmpBufLen,\r
- TmpBuf\r
- );\r
- }\r
-\r
- if (!Key.ScanCode) {\r
- switch (Key.UnicodeChar) {\r
- case Ctl ('c'):\r
- Key.ScanCode = SCAN_ESC;\r
- break;\r
-\r
- case Ctl ('j'): /* linefeed */\r
- case Ctl ('m'): /* return */\r
- Done = TRUE;\r
- break;\r
-\r
- case Ctl ('i'): /* tab */\r
- case ' ':\r
- case 'd':\r
- case 'D':\r
- Key.ScanCode = SCAN_DOWN;\r
- break;\r
-\r
- case Ctl ('h'): /* backspace */\r
- case 'u':\r
- case 'U':\r
- Key.ScanCode = SCAN_UP;\r
- break;\r
-\r
- default:\r
- Key.ScanCode = 0;\r
- }\r
- }\r
-\r
- switch (Key.ScanCode) {\r
- case SCAN_LEFT:\r
- case SCAN_UP:\r
- if (NewSelected) {\r
- --NewSelected;\r
- }\r
-\r
- break;\r
-\r
- case SCAN_DOWN:\r
- case SCAN_RIGHT:\r
- if (++NewSelected == NumMenuItems) {\r
- --NewSelected;\r
- }\r
-\r
- break;\r
-\r
- case SCAN_PAGE_UP:\r
- case SCAN_HOME:\r
- NewSelected = 0;\r
- break;\r
-\r
- case SCAN_PAGE_DOWN:\r
- case SCAN_END:\r
- NewSelected = NumMenuItems - 1;\r
- break;\r
-\r
- case SCAN_ESC:\r
- return LOCAL_BOOT;\r
- }\r
-\r
- /* unhighlight last selected row */\r
- gST->ConOut->SetCursorPosition (gST->ConOut, 5, TopRow + Selected);\r
-\r
- AsciiPrint ("%a\r", BlankBuf);\r
-\r
- PrintMenuItem (MenuItemPtrs[Selected]);\r
-\r
- Selected = NewSelected;\r
- } while (!Done);\r
- }\r
-\r
- SaveNumRte = Private->EfiBc.Mode->RouteTableEntries;\r
-\r
- Type = NTOHS (MenuItemPtrs[Selected]->Type);\r
-\r
- if (Type == 0) {\r
- DEBUG ((EFI_D_WARN, "\nDoMenu() Local boot selected. "));\r
- return LOCAL_BOOT;\r
- }\r
-\r
- AsciiPrint ("Discover");\r
-\r
- Status = Private->EfiBc.Discover (\r
- &Private->EfiBc,\r
- Type,\r
- &Layer,\r
- (BOOLEAN) (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected),\r
- 0\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- AsciiPrint ("\r \r");\r
-\r
- DEBUG (\r
- (EFI_D_WARN,\r
- "\nDoMenu() Return w/ %xh (%r).",\r
- Status,\r
- Status)\r
- );\r
-\r
- return Status;\r
- }\r
-\r
- AsciiPrint ("\rBOOT_SERVER_IP: ");\r
- PrintIpv4 ((UINT8 *) &Private->ServerIp);\r
-\r
- for (Index = SaveNumRte; Index < Private->EfiBc.Mode->RouteTableEntries; ++Index) {\r
- if ((Index % 3) == 0) {\r
- AsciiPrint ("\r\nGATEWAY IP:");\r
- }\r
-\r
- AsciiPrint (" ");\r
- PrintIpv4 ((UINT8 *) &Private->EfiBc.Mode->RouteTable[Index].GwAddr);\r
- AsciiPrint (" ");\r
- }\r
-\r
- AsciiPrint ("\n");\r
-\r
- DEBUG ((EFI_D_WARN, "\nDoMenu() Return w/ EFI_SUCCESS. "));\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-STATIC\r
-UINT16\r
-GetValue (\r
- DHCPV4_OP_STRUCT *OpPtr\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Get value 8- or 16-bit value from DHCP option.\r
-\r
-Arguments:\r
-\r
- OpPtr - Pointer to DHCP option\r
-\r
-Returns:\r
-\r
- Value from DHCP option\r
-\r
---*/\r
-{\r
- if (OpPtr->Header.Length == 1) {\r
- return OpPtr->Data[0];\r
- } else {\r
- return NTOHS (OpPtr->Data);\r
- }\r
-}\r
-\r
-STATIC\r
-UINT8 *\r
-_PxeBcFindOpt (\r
- UINT8 *BufferPtr,\r
- UINTN BufferLen,\r
- UINT8 OpCode\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Locate opcode in buffer.\r
-\r
-Arguments:\r
-\r
- BufferPtr - Pointer to buffer\r
- BufferLen - Length of buffer\r
- OpCode - Option number\r
-\r
-Returns:\r
-\r
- Pointer to opcode, may be NULL\r
-\r
---*/\r
-{\r
- if (BufferPtr == NULL) {\r
- return NULL;\r
- }\r
-\r
- while (BufferLen != 0) {\r
- if (*BufferPtr == OpCode) {\r
- return BufferPtr;\r
- }\r
-\r
- switch (*BufferPtr) {\r
- case OP_END:\r
- return NULL;\r
-\r
- case OP_PAD:\r
- ++BufferPtr;\r
- --BufferLen;\r
- continue;\r
- }\r
-\r
- if ((UINTN) BufferLen <= (UINTN) 2 + BufferPtr[1]) {\r
- return NULL;\r
- }\r
-\r
- BufferLen -= 2 + BufferPtr[1];\r
- BufferPtr += 2 + BufferPtr[1];\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-STATIC\r
-UINT8 *\r
-PxeBcFindDhcpOpt (\r
- EFI_PXE_BASE_CODE_PACKET *PacketPtr,\r
- UINT8 OpCode\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Find option in packet\r
-\r
-Arguments:\r
-\r
- PacketPtr - Pointer to packet\r
- OpCode - option number\r
-\r
-Returns:\r
-\r
- Pointer to option in packet\r
-\r
---*/\r
-{\r
- UINTN PacketLen;\r
- UINT8 Overload;\r
- UINT8 *OptionBufferPtr;\r
-\r
- //\r
- //\r
- //\r
- PacketLen = 380;\r
- Overload = 0;\r
-\r
- //\r
- // Figure size of DHCP option space.\r
- //\r
- OptionBufferPtr = _PxeBcFindOpt (\r
- PacketPtr->Dhcpv4.DhcpOptions,\r
- 380,\r
- OP_DHCP_MAX_MESSAGE_SZ\r
- );\r
-\r
- if (OptionBufferPtr != NULL) {\r
- if (OptionBufferPtr[1] == 2) {\r
- UINT16 n;\r
-\r
- CopyMem (&n, &OptionBufferPtr[2], 2);\r
- PacketLen = HTONS (n);\r
-\r
- if (PacketLen < sizeof (EFI_PXE_BASE_CODE_DHCPV4_PACKET)) {\r
- PacketLen = 380;\r
- } else {\r
- PacketLen -= (PacketPtr->Dhcpv4.DhcpOptions - &PacketPtr->Dhcpv4.BootpOpcode) + 28;\r
- }\r
- }\r
- }\r
- //\r
- // Look for option overloading.\r
- //\r
- OptionBufferPtr = _PxeBcFindOpt (\r
- PacketPtr->Dhcpv4.DhcpOptions,\r
- PacketLen,\r
- OP_DHCP_OPTION_OVERLOAD\r
- );\r
-\r
- if (OptionBufferPtr != NULL) {\r
- if (OptionBufferPtr[1] == 1) {\r
- Overload = OptionBufferPtr[2];\r
- }\r
- }\r
- //\r
- // Look for caller's option.\r
- //\r
- OptionBufferPtr = _PxeBcFindOpt (\r
- PacketPtr->Dhcpv4.DhcpOptions,\r
- PacketLen,\r
- OpCode\r
- );\r
-\r
- if (OptionBufferPtr != NULL) {\r
- return OptionBufferPtr;\r
- }\r
-\r
- if (Overload & OVLD_FILE) {\r
- OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpBootFile, 128, OpCode);\r
-\r
- if (OptionBufferPtr != NULL) {\r
- return OptionBufferPtr;\r
- }\r
- }\r
-\r
- if (Overload & OVLD_SRVR_NAME) {\r
- OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpSrvName, 64, OpCode);\r
-\r
- if (OptionBufferPtr != NULL) {\r
- return OptionBufferPtr;\r
- }\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-STATIC\r
-EFI_STATUS\r
-DownloadFile (\r
- IN PXE_BASECODE_DEVICE *Private,\r
- IN OUT UINT64 *BufferSize,\r
- IN VOID *Buffer\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Download file into buffer\r
-\r
-Arguments:\r
-\r
- Private - Pointer to PxeBc interface\r
- BufferSize - pointer to size of download buffer\r
- Buffer - Pointer to buffer\r
-\r
-Returns:\r
-\r
- EFI_BUFFER_TOO_SMALL -\r
- EFI_NOT_FOUND -\r
- EFI_PROTOCOL_ERROR -\r
-\r
---*/\r
-{\r
- EFI_PXE_BASE_CODE_MTFTP_INFO MtftpInfo;\r
- EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode;\r
- DHCP_RECEIVE_BUFFER *RxBuf;\r
- EFI_STATUS Status;\r
- UINTN BlockSize;\r
-\r
- RxBuf = (DHCP_RECEIVE_BUFFER *) Private->BootServerReceiveBuffer;\r
- BlockSize = 0x8000;\r
-\r
- DEBUG ((EFI_D_WARN, "\nDownloadFile() Enter."));\r
-\r
- if (Buffer == NULL || *BufferSize == 0 || *BufferSize < Private->FileSize) {\r
- if (Private->FileSize != 0) {\r
- *BufferSize = Private->FileSize;\r
- return EFI_BUFFER_TOO_SMALL;\r
- }\r
-\r
- AsciiPrint ("\nTSize");\r
-\r
- OpCode = EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE;\r
- } else if (RxBuf->OpAdds.Status & WfM11a_TYPE) {\r
- OpCode = EFI_PXE_BASE_CODE_MTFTP_READ_FILE;\r
-\r
- ZeroMem (&MtftpInfo, sizeof MtftpInfo);\r
-\r
- *(IPV4_ADDR *) &MtftpInfo.MCastIp = *(IPV4_ADDR *) RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_IP - 1]->Data;\r
-\r
- CopyMem (\r
- &MtftpInfo.CPort,\r
- RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_CPORT - 1]->Data,\r
- sizeof MtftpInfo.CPort\r
- );\r
-\r
- CopyMem (\r
- &MtftpInfo.SPort,\r
- RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_SPORT - 1]->Data,\r
- sizeof MtftpInfo.SPort\r
- );\r
-\r
- MtftpInfo.ListenTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_TMOUT - 1]);\r
-\r
- MtftpInfo.TransmitTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_DELAY - 1]);\r
-\r
- AsciiPrint ("\nMTFTP");\r
- } else {\r
- AsciiPrint ("\nTFTP");\r
-\r
- OpCode = EFI_PXE_BASE_CODE_TFTP_READ_FILE;\r
- }\r
-\r
- Private->FileSize = 0;\r
-\r
- RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data[RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length] = 0;\r
-\r
- Status = Private->EfiBc.Mtftp (\r
- &Private->EfiBc,\r
- OpCode,\r
- Buffer,\r
- FALSE,\r
- BufferSize,\r
- &BlockSize,\r
- &Private->ServerIp,\r
- (UINT8 *) RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data,\r
- &MtftpInfo,\r
- FALSE\r
- );\r
-\r
- if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) {\r
- DEBUG ((EFI_D_WARN, "\nDownloadFile() Exit #1 %Xh", Status));\r
- return Status;\r
- }\r
-\r
- if (sizeof (UINTN) < sizeof (UINT64) && *BufferSize > 0xFFFFFFFF) {\r
- Private->FileSize = 0xFFFFFFFF;\r
- } else {\r
- Private->FileSize = (UINTN) *BufferSize;\r
- }\r
-\r
- if (OpCode == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {\r
- DEBUG ((EFI_D_WARN, "\nDownloadFile() Exit #2"));\r
- return EFI_BUFFER_TOO_SMALL;\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_WARN, "\nDownloadFile() Exit #3 %Xh", Status));\r
- return Status;\r
- }\r
-\r
- if (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected && Private->EfiBc.Mode->PxeBisReplyReceived) {\r
- UINT64 CredentialLen;\r
- UINT8 CredentialFilename[256];\r
- UINT8 *op;\r
- VOID *CredentialBuffer;\r
-\r
- //\r
- // Get name of credential file. It may be in the BOOTP\r
- // bootfile field or a DHCP option.\r
- //\r
- ZeroMem (CredentialFilename, sizeof CredentialFilename);\r
-\r
- op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_DHCP_BOOTFILE);\r
-\r
- if (op != NULL) {\r
- if (op[1] == 0) {\r
- /* No credential filename */\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- CopyMem (CredentialFilename, &op[2], op[1]);\r
- } else {\r
- if (Private->EfiBc.Mode->PxeBisReply.Dhcpv4.BootpBootFile[0] == 0) {\r
- /* No credential filename */\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- CopyMem (CredentialFilename, &op[2], 128);\r
- }\r
- //\r
- // Get size of credential file. It may be available as a\r
- // DHCP option. If not, use the TFTP get file size.\r
- //\r
- CredentialLen = 0;\r
-\r
- op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_BOOT_FILE_SZ);\r
-\r
- if (op != NULL) {\r
- /*\r
- * This is actually the size of the credential file\r
- * buffer. The actual credential file size will be\r
- * returned when we download the file.\r
- */\r
- if (op[1] == 2) {\r
- UINT16 n;\r
-\r
- CopyMem (&n, &op[2], 2);\r
- CredentialLen = HTONS (n) * 512;\r
- }\r
- }\r
-\r
- if (CredentialLen == 0) {\r
- BlockSize = 8192;\r
-\r
- Status = Private->EfiBc.Mtftp (\r
- &Private->EfiBc,\r
- EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,\r
- NULL,\r
- FALSE,\r
- &CredentialLen,\r
- &BlockSize,\r
- &Private->ServerIp,\r
- CredentialFilename,\r
- NULL,\r
- FALSE\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- if (CredentialLen == 0) {\r
- //\r
- // %%TBD -- EFI error for invalid credential\r
- // file.\r
- //\r
- return EFI_PROTOCOL_ERROR;\r
- }\r
- }\r
- //\r
- // Allocate credential file buffer.\r
- //\r
- CredentialBuffer = AllocatePool ((UINTN) CredentialLen);\r
- if (CredentialBuffer == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- //\r
- // Download credential file.\r
- //\r
- BlockSize = 8192;\r
-\r
- Status = Private->EfiBc.Mtftp (\r
- &Private->EfiBc,\r
- EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
- CredentialBuffer,\r
- FALSE,\r
- &CredentialLen,\r
- &BlockSize,\r
- &Private->ServerIp,\r
- CredentialFilename,\r
- NULL,\r
- FALSE\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- FreePool (CredentialBuffer);\r
- return Status;\r
- }\r
- //\r
- // Verify credentials.\r
- //\r
- if (PxebcBisVerify (Private, Buffer, Private->FileSize, CredentialBuffer, (UINTN) CredentialLen)) {\r
- Status = EFI_SUCCESS;\r
- } else {\r
- //\r
- // %%TBD -- An EFI error code for failing credential verification.\r
- //\r
- Status = EFI_PROTOCOL_ERROR;\r
- }\r
-\r
- FreePool (CredentialBuffer);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-STATIC\r
-EFI_STATUS\r
-LoadfileStart (\r
- IN PXE_BASECODE_DEVICE *Private,\r
- IN OUT UINT64 *BufferSize,\r
- IN VOID *Buffer\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Start PXE DHCP. Get DHCP and proxyDHCP information.\r
- Display remote boot menu and prompt. Select item from menu.\r
-\r
-Arguments:\r
-\r
- Private - Pointer to PxeBc interface\r
- BufferSize - Pointer to download buffer size\r
- Buffer - Pointer to download buffer\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS -\r
- EFI_NOT_READY -\r
-\r
---*/\r
-{\r
- EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
- EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
- EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
- EFI_STATUS Status;\r
- VOID *RxBuf;\r
-\r
- DEBUG ((EFI_D_WARN, "\nLoadfileStart() Enter."));\r
-\r
- //\r
- // Try to start BaseCode, for now only IPv4 is supported\r
- // so don't try to start using IPv6.\r
- //\r
- Status = Private->EfiBc.Start (&Private->EfiBc, FALSE);\r
-\r
- if (EFI_ERROR (Status)) {\r
- if (Status != EFI_ALREADY_STARTED) {\r
- DEBUG ((EFI_D_NET, "\nLoadfileStart() Exit BC.Start() == %xh", Status));\r
- return Status;\r
- }\r
- }\r
- //\r
- // Get pointers to PXE mode structure, SNP protocol structure\r
- // and SNP mode structure.\r
- //\r
- PxeBcMode = Private->EfiBc.Mode;\r
- Snp = Private->SimpleNetwork;\r
- SnpMode = Snp->Mode;\r
-\r
- //\r
- // Display client MAC address, like 16-bit PXE ROMs\r
- //\r
- AsciiPrint ("\nCLIENT MAC ADDR: ");\r
-\r
- {\r
- UINTN Index;\r
- UINTN hlen;\r
-\r
- hlen = SnpMode->HwAddressSize;\r
-\r
- for (Index = 0; Index < hlen; ++Index) {\r
- AsciiPrint ("%02x ", SnpMode->CurrentAddress.Addr[Index]);\r
- }\r
- }\r
-\r
- AsciiPrint ("\nDHCP");\r
-\r
- Status = Private->EfiBc.Dhcp (&Private->EfiBc, TRUE);\r
-\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit BC.Dhcp() == %Xh", Status));\r
- AsciiPrint ("\r \r");\r
- return Status;\r
- }\r
-\r
- ShowMyInfo (Private);\r
-\r
- RxBuf = PxeBcMode->ProxyOfferReceived ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;\r
-#define RxBufferPtr ((DHCP_RECEIVE_BUFFER *) RxBuf)\r
-\r
- Status = DoMenu (Private, RxBufferPtr);\r
-\r
- if (Status == EFI_SUCCESS) {\r
- //\r
- // did a discovery - take info from discovery packet\r
- //\r
- RxBuf = &PXE_ACK_BUFFER;\r
- } else if (Status == NO_MENU) {\r
- //\r
- // did not do a discovery - take info from rxbuf\r
- //\r
- Private->ServerIp.Addr[0] = RxBufferPtr->u.Dhcpv4.siaddr;\r
-\r
- if (!(Private->ServerIp.Addr[0])) {\r
- *(IPV4_ADDR *) &Private->ServerIp = *(IPV4_ADDR *) RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]->Data;\r
- }\r
- } else {\r
- DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit DoMenu() == %Xh", Status));\r
- return Status;\r
- }\r
-\r
- if (!RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {\r
- DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit Not ready?"));\r
- return EFI_NOT_READY;\r
- }\r
- //\r
- // check for file size option sent\r
- //\r
- if (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]) {\r
- Private->FileSize = 512 * NTOHS (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]->Data);\r
- }\r
-\r
- Private->BootServerReceiveBuffer = RxBufferPtr;\r
-\r
- Status = DownloadFile (Private, BufferSize, Buffer);\r
-\r
- DEBUG (\r
- (EFI_D_WARN,\r
- "\nLoadfileStart() Exit. DownloadFile() = %Xh",\r
- Status)\r
- );\r
-\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-LoadFile (\r
- IN EFI_LOAD_FILE_PROTOCOL *This,\r
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
- IN BOOLEAN BootPolicy,\r
- IN OUT UINTN *BufferSize,\r
- IN OUT VOID *Buffer\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Loadfile interface for PxeBc interface\r
-\r
-Arguments:\r
-\r
- This - Pointer to Loadfile interface\r
- FilePath - Not used and not checked\r
- BootPolicy - Must be TRUE\r
- BufferSize - Pointer to buffer size\r
- Buffer - Pointer to download buffer or NULL\r
-\r
-Returns:\r
-\r
- EFI_INVALID_PARAMETER -\r
- EFI_UNSUPPORTED -\r
- EFI_SUCCESS -\r
- EFI_BUFFER_TOO_SMALL -\r
-\r
---*/\r
-{\r
- LOADFILE_DEVICE *LoadfilePtr;\r
- UINT64 TmpBufSz;\r
- INT32 OrigMode;\r
- INT32 OrigAttribute;\r
- BOOLEAN RemoveCallback;\r
- BOOLEAN NewMakeCallback;\r
- EFI_STATUS Status;\r
- EFI_STATUS TempStatus;\r
- //\r
- //\r
- //\r
- OrigMode = gST->ConOut->Mode->Mode;\r
- OrigAttribute = gST->ConOut->Mode->Attribute;\r
- RemoveCallback = FALSE;\r
-\r
- AsciiPrint ("Running LoadFile()\n");\r
-\r
- //\r
- // If either if these parameters are NULL, we cannot continue.\r
- //\r
- if (This == NULL || BufferSize == NULL) {\r
- DEBUG ((EFI_D_WARN, "\nLoadFile() This or BufferSize == NULL"));\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- //\r
- // We only support BootPolicy == TRUE\r
- //\r
- if (!BootPolicy) {\r
- DEBUG ((EFI_D_WARN, "\nLoadFile() BootPolicy == FALSE"));\r
- return EFI_UNSUPPORTED;\r
- }\r
- //\r
- // Get pointer to LoadFile protocol structure.\r
- //\r
- LoadfilePtr = CR (This, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE);\r
-\r
- if (LoadfilePtr == NULL) {\r
- DEBUG (\r
- (EFI_D_NET,\r
- "\nLoadFile() Could not get pointer to LoadFile structure")\r
- );\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- //\r
- // Lock interface\r
- //\r
- EfiAcquireLock (&LoadfilePtr->Lock);\r
-\r
- //\r
- // Set console output mode and display attribute\r
- //\r
- if (OrigMode != 0) {\r
- gST->ConOut->SetMode (gST->ConOut, 0);\r
- }\r
-\r
- gST->ConOut->SetAttribute (\r
- gST->ConOut,\r
- EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK)\r
- );\r
-\r
- //\r
- // See if BaseCode already has a Callback protocol attached.\r
- // If there is none, attach our own Callback protocol.\r
- //\r
- Status = gBS->HandleProtocol (\r
- LoadfilePtr->Private->Handle,\r
- &gEfiPxeBaseCodeCallbackProtocolGuid,\r
- (VOID *) &LoadfilePtr->Private->CallbackProtocolPtr\r
- );\r
-\r
- if (Status == EFI_SUCCESS) {\r
- //\r
- // There is already a callback routine. Do nothing.\r
- //\r
- DEBUG ((EFI_D_WARN, "\nLoadFile() BC callback exists."));\r
- } else if (Status == EFI_UNSUPPORTED) {\r
- //\r
- // No BaseCode Callback protocol found. Add our own.\r
- //\r
- Status = gBS->InstallProtocolInterface (\r
- &LoadfilePtr->Private->Handle,\r
- &gEfiPxeBaseCodeCallbackProtocolGuid,\r
- EFI_NATIVE_INTERFACE,\r
- &_bc_callback\r
- );\r
-\r
- DEBUG ((EFI_D_WARN, "\nLoadFile() Callback install status == %xh", Status));\r
-\r
- RemoveCallback = (BOOLEAN) (Status == EFI_SUCCESS);\r
-\r
- if (LoadfilePtr->Private->EfiBc.Mode != NULL && LoadfilePtr->Private->EfiBc.Mode->Started) {\r
- NewMakeCallback = TRUE;\r
- LoadfilePtr->Private->EfiBc.SetParameters (\r
- &LoadfilePtr->Private->EfiBc,\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL,\r
- &NewMakeCallback\r
- );\r
- }\r
- } else {\r
- DEBUG ((EFI_D_WARN, "\nLoadFile() Callback check status == %xh", Status));\r
- }\r
- //\r
- // Check for starting or for continuing after already getting\r
- // the file size.\r
- //\r
- if (LoadfilePtr->Private->FileSize == 0) {\r
- TmpBufSz = 0;\r
- Status = LoadfileStart (LoadfilePtr->Private, &TmpBufSz, Buffer);\r
-\r
- if (sizeof (UINTN) < sizeof (UINT64) && TmpBufSz > 0xFFFFFFFF) {\r
- *BufferSize = 0xFFFFFFFF;\r
- } else {\r
- *BufferSize = (UINTN) TmpBufSz;\r
- }\r
-\r
- if (Status == EFI_BUFFER_TOO_SMALL) {\r
- //\r
- // This is done so loadfile will work even if the boot manager\r
- // did not make the first call with Buffer == NULL.\r
- //\r
- Buffer = NULL;\r
- }\r
- } else if (Buffer == NULL) {\r
- DEBUG ((EFI_D_WARN, "\nLoadfile() Get buffer size"));\r
-\r
- //\r
- // Continuing from previous LoadFile request. Make sure there\r
- // is a buffer and that it is big enough.\r
- //\r
- *BufferSize = LoadfilePtr->Private->FileSize;\r
- Status = EFI_BUFFER_TOO_SMALL;\r
- } else {\r
- DEBUG ((EFI_D_WARN, "\nLoadFile() Download file"));\r
-\r
- //\r
- // Everything looks good, try to download the file.\r
- //\r
- TmpBufSz = *BufferSize;\r
- Status = DownloadFile (LoadfilePtr->Private, &TmpBufSz, Buffer);\r
-\r
- //\r
- // Next call to loadfile will start DHCP process again.\r
- //\r
- LoadfilePtr->Private->FileSize = 0;\r
- }\r
- //\r
- // If we added a callback protocol, now is the time to remove it.\r
- //\r
- if (RemoveCallback) {\r
- NewMakeCallback = FALSE;\r
- TempStatus = LoadfilePtr->Private->EfiBc.SetParameters (\r
- &LoadfilePtr->Private->EfiBc,\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL,\r
- &NewMakeCallback\r
- );\r
-\r
- if (TempStatus == EFI_SUCCESS) {\r
- gBS->UninstallProtocolInterface (\r
- LoadfilePtr->Private->Handle,\r
- &gEfiPxeBaseCodeCallbackProtocolGuid,\r
- &_bc_callback\r
- );\r
- }\r
- }\r
- //\r
- // Restore display mode and attribute\r
- //\r
- if (OrigMode != 0) {\r
- gST->ConOut->SetMode (gST->ConOut, OrigMode);\r
- }\r
-\r
- gST->ConOut->SetAttribute (gST->ConOut, OrigAttribute);\r
-\r
- //\r
- // Unlock interface\r
- //\r
- EfiReleaseLock (&LoadfilePtr->Lock);\r
-\r
- DEBUG ((EFI_D_WARN, "\nBC.Loadfile() Status == %xh\n", Status));\r
-\r
- if (Status == EFI_SUCCESS) {\r
- /* 0 */\r
- return EFI_SUCCESS;\r
- } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
- /* 5 */\r
- //\r
- // Error is only displayed when we are actually trying to\r
- // download the boot image.\r
- //\r
- if (Buffer == NULL) {\r
- return EFI_BUFFER_TOO_SMALL;\r
- }\r
- AsciiPrint ("\nPXE-E05: Download buffer is smaller than requested file.\n");\r
- } else if (Status == EFI_DEVICE_ERROR) {\r
- /* 7 */\r
- AsciiPrint ("\nPXE-E07: Network device error. Check network connection.\n");\r
- } else if (Status == EFI_OUT_OF_RESOURCES) {\r
- /* 9 */\r
- AsciiPrint ("\nPXE-E09: Could not allocate I/O buffers.\n");\r
- } else if (Status == EFI_NO_MEDIA) {\r
- /* 12 */\r
- AsciiPrint ("\nPXE-E12: Could not detect network connection. Check cable.\n");\r
- } else if (Status == EFI_NO_RESPONSE) {\r
- /* 16 */\r
- AsciiPrint ("\nPXE-E16: Valid PXE offer not received.\n");\r
- } else if (Status == EFI_TIMEOUT) {\r
- /* 18 */\r
- AsciiPrint ("\nPXE-E18: Timeout. Server did not respond.\n");\r
- } else if (Status == EFI_ABORTED) {\r
- /* 21 */\r
- AsciiPrint ("\nPXE-E21: Remote boot cancelled.\n");\r
- } else if (Status == EFI_ICMP_ERROR) {\r
- /* 22 */\r
- AsciiPrint ("\nPXE-E22: Client received ICMP error from server.\n");\r
-\r
- if ((LoadfilePtr->Private->EfiBc.Mode != NULL) && LoadfilePtr->Private->EfiBc.Mode->IcmpErrorReceived) {\r
- AsciiPrint (\r
- "PXE-E98: Type: %xh Code: %xh ",\r
- LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type,\r
- LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code\r
- );\r
-\r
- switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type) {\r
- case 0x03:\r
- switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code) {\r
- case 0x00: /* net unreachable */\r
- AsciiPrint ("Net unreachable");\r
- break;\r
-\r
- case 0x01: /* host unreachable */\r
- AsciiPrint ("Host unreachable");\r
- break;\r
-\r
- case 0x02: /* protocol unreachable */\r
- AsciiPrint ("Protocol unreachable");\r
- break;\r
-\r
- case 0x03: /* port unreachable */\r
- AsciiPrint ("Port unreachable");\r
- break;\r
-\r
- case 0x04: /* Fragmentation needed */\r
- AsciiPrint ("Fragmentation needed");\r
- break;\r
-\r
- case 0x05: /* Source route failed */\r
- AsciiPrint ("Source route failed");\r
- break;\r
- }\r
-\r
- break;\r
- }\r
-\r
- AsciiPrint ("\n");\r
- }\r
- } else if (Status == EFI_TFTP_ERROR) {\r
- /* 23 */\r
- AsciiPrint ("\nPXE-E23: Client received TFTP error from server.\n");\r
-\r
- if ((LoadfilePtr->Private->EfiBc.Mode != NULL) && (LoadfilePtr->Private->EfiBc.Mode->TftpErrorReceived)) {\r
- AsciiPrint (\r
- "PXE-E98: Code: %xh %a\n",\r
- LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorCode,\r
- LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorString\r
- );\r
- }\r
- } else {\r
- AsciiPrint ("\nPXE-E99: Unexpected network error: %xh\n", Status);\r
- }\r
-\r
- LoadfilePtr->Private->EfiBc.Stop (&LoadfilePtr->Private->EfiBc);\r
-\r
- return Status;\r
-}\r