pxe_loadfile.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,697 行 · 第 1/3 页
C
1,697 行
/*++
Copyright (c) 2004 - 2005, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
pxe_loadfile.c
Abstract:
An implementation of the load file protocol for network devices.
--*/
#include "bc.h"
#define DO_MENU (EFI_SUCCESS)
#define NO_MENU (DO_MENU + 1)
#define LOCAL_BOOT (EFI_ABORTED)
#define AUTO_SELECT (NO_MENU)
#define NUMBER_ROWS 25 // we set to mode 0
#define MAX_MENULIST 23
#define Ctl(x) (0x1F & (x))
typedef union {
DHCPV4_OP_STRUCT *OpPtr;
PXE_BOOT_MENU_ENTRY *CurrentMenuItemPtr;
PXE_OP_DISCOVERY_CONTROL *DiscCtlOpStr;
PXE_OP_BOOT_MENU *MenuPtr;
UINT8 *BytePtr;
} UNION_PTR;
STATIC
EFI_PXE_BASE_CODE_CALLBACK_STATUS
EFIAPI
bc_callback (
IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL * This,
IN EFI_PXE_BASE_CODE_FUNCTION Function,
IN BOOLEAN Received,
IN UINT32 PacketLength,
IN EFI_PXE_BASE_CODE_PACKET * PacketPtr OPTIONAL
)
/*++
Routine Description:
PxeBc callback routine for status updates and aborts.
Arguments:
This - Pointer to PxeBcCallback interface
Function - PxeBc function ID#
Received - Receive/transmit flag
PacketLength - Length of received packet (0 == idle callback)
PacketPtr - Pointer to received packet (NULL == idle callback)
Returns:
EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE -
EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT -
--*/
{
STATIC UINTN Propeller;
EFI_INPUT_KEY Key;
UINTN Row;
UINTN Col;
Propeller = 0;
//
// Resolve Warning 4 unreferenced parameter problem
//
This = This;
//
// Check for user abort.
//
if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_SUCCESS) {
if (!Key.ScanCode) {
if (Key.UnicodeChar == Ctl ('c')) {
return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
}
} else if (Key.ScanCode == SCAN_ESC) {
return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
}
}
//
// Do nothing if this is a receive.
//
if (Received) {
return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
}
//
// The display code is only for these functions.
//
switch (Function) {
case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:
//
// If this is a transmit and not a M/TFTP open request,
// return now. Do not print a dot for each M/TFTP packet
// that is sent, only for the open packets.
//
if (PacketLength != 0 && PacketPtr != NULL) {
if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {
return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
}
}
break;
case EFI_PXE_BASE_CODE_FUNCTION_DHCP:
case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:
break;
default:
return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
}
//
// Display routines
//
if (PacketLength != 0 && PacketPtr != NULL) {
//
// Display a '.' when a packet is transmitted.
//
Aprint (".");
} else if (PacketLength == 0 && PacketPtr == NULL) {
//
// Display a propeller when waiting for packets if at
// least 200 ms have passed.
//
Row = gST->ConOut->Mode->CursorRow;
Col = gST->ConOut->Mode->CursorColumn;
Aprint ("%c", "/-\\|"[Propeller]);
gST->ConOut->SetCursorPosition (gST->ConOut, Col, Row);
Propeller = (Propeller + 1) & 3;
}
return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
}
STATIC EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL _bc_callback = {
EFI_PXE_BASE_CODE_CALLBACK_INTERFACE_REVISION,
&bc_callback
};
STATIC
VOID
PrintIpv4 (
UINT8 *Ptr
)
/*++
Routine Description:
Display an IPv4 address in dot notation.
Arguments:
Ptr - Pointer to IPv4 address.
Returns:
None
--*/
{
if (Ptr != NULL) {
Aprint ("%d.%d.%d.%d", Ptr[0], Ptr[1], Ptr[2], Ptr[3]);
}
}
STATIC
VOID
ShowMyInfo (
IN PXE_BASECODE_DEVICE *Private
)
/*++
Routine Description:
Display client and server IP information.
Arguments:
Private - Pointer to PxeBc interface
Returns:
None
--*/
{
EFI_PXE_BASE_CODE_MODE *PxeBcMode;
UINTN Index;
//
// Do nothing if a NULL pointer is passed in.
//
if (Private == NULL) {
return ;
}
//
// Get pointer to PXE BaseCode mode structure
//
PxeBcMode = Private->EfiBc.Mode;
//
// Display client IP address
//
Aprint ("\rCLIENT IP: ");
PrintIpv4 (PxeBcMode->StationIp.v4.Addr);
//
// Display subnet mask
//
Aprint (" MASK: ");
PrintIpv4 (PxeBcMode->SubnetMask.v4.Addr);
//
// Display DHCP and proxyDHCP IP addresses
//
if (PxeBcMode->ProxyOfferReceived) {
Aprint ("\nDHCP IP: ");
PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);
Aprint (" PROXY IP: ");
PrintIpv4 (((DHCPV4_OP_SERVER_IP *) PXE_OFFER_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);
} else {
Aprint (" DHCP IP: ");
PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);
}
//
// Display gateway IP addresses
//
for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {
if ((Index % 3) == 0) {
Aprint ("\r\nGATEWAY IP:");
}
Aprint (" ");
PrintIpv4 (PxeBcMode->RouteTable[Index].GwAddr.v4.Addr);
Aprint (" ");
}
Aprint ("\n");
}
STATIC
EFI_STATUS
DoPrompt (
PXE_BASECODE_DEVICE *Private,
PXE_OP_BOOT_PROMPT *BootPromptPtr
)
/*++
Routine Description:
Display prompt and wait for input.
Arguments:
Private - Pointer to PxeBc interface
BootPromptPtr - Pointer to PXE boot prompt option
Returns:
AUTO_SELECT -
DO_MENU -
NO_MENU -
LOCAL_BOOT -
--*/
{
EFI_STATUS Status;
EFI_EVENT TimeoutEvent;
EFI_EVENT SecondsEvent;
INT32 SecColumn;
INT32 SecRow;
UINT8 SaveChar;
UINT8 SecsLeft;
//
// if auto select, just get right to it
//
if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_AUTO_SELECT) {
return AUTO_SELECT;
}
//
// if no timeout, go directly to display of menu
//
if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_NO_TIMEOUT) {
return DO_MENU;
}
//
//
//
Status = gBS->CreateEvent (
EFI_EVENT_TIMER,
EFI_TPL_CALLBACK,
NULL,
NULL,
&TimeoutEvent
);
if (EFI_ERROR (Status)) {
return DO_MENU;
}
Status = gBS->SetTimer (
TimeoutEvent,
TimerRelative,
BootPromptPtr->Timeout * 10000000 + 100000
);
if (EFI_ERROR (Status)) {
gBS->CloseEvent (TimeoutEvent);
return DO_MENU;
}
//
//
//
Status = gBS->CreateEvent (
EFI_EVENT_TIMER,
EFI_TPL_CALLBACK,
NULL,
NULL,
&SecondsEvent
);
if (EFI_ERROR (Status)) {
gBS->CloseEvent (TimeoutEvent);
return DO_MENU;
}
Status = gBS->SetTimer (
SecondsEvent,
TimerPeriodic,
10000000
); /* 1 second */
if (EFI_ERROR (Status)) {
gBS->CloseEvent (SecondsEvent);
gBS->CloseEvent (TimeoutEvent);
return DO_MENU;
}
//
// display the prompt
// IMPORTANT! This prompt is an ASCII character string that may
// not be terminated with a NULL byte.
//
SaveChar = BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1];
BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = 0;
Aprint ("%a ", BootPromptPtr->Prompt);
BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = SaveChar;
//
// wait until time expires or selection made - menu or local
//
SecColumn = gST->ConOut->Mode->CursorColumn;
SecRow = gST->ConOut->Mode->CursorRow;
SecsLeft = BootPromptPtr->Timeout;
gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
Aprint ("(%d) ", SecsLeft);
//
// set the default action to be AUTO_SELECT
//
Status = AUTO_SELECT;
while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
EFI_INPUT_KEY Key;
if (!EFI_ERROR (gBS->CheckEvent (SecondsEvent))) {
--SecsLeft;
gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
Aprint ("(%d) ", SecsLeft);
}
if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {
UINT8 Buffer[512];
UINTN BufferSize;
EFI_STATUS Status;
BufferSize = sizeof Buffer;
Status = Private->EfiBc.UdpRead (
&Private->EfiBc,
EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |
EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,
NULL, /* dest ip */
NULL, /* dest port */
NULL, /* src ip */
NULL, /* src port */
NULL, /* hdr size */
NULL, /* hdr ptr */
&BufferSize,
Buffer
);
continue;
}
if (Key.ScanCode == 0) {
switch (Key.UnicodeChar) {
case Ctl ('c'):
Status = LOCAL_BOOT;
break;
case Ctl ('m'):
case 'm':
case 'M':
Status = DO_MENU;
break;
default:
continue;
}
} else {
switch (Key.ScanCode) {
case SCAN_F8:
Status = DO_MENU;
break;
case SCAN_ESC:
Status = LOCAL_BOOT;
break;
default:
continue;
}
}
break;
}
gBS->CloseEvent (SecondsEvent);
gBS->CloseEvent (TimeoutEvent);
gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
Aprint (" ");
return Status;
}
STATIC
VOID
PrintMenuItem (
PXE_BOOT_MENU_ENTRY *MenuItemPtr
)
/*++
Routine Description:
Display one menu item.
Arguments:
MenuItemPtr - Pointer to PXE menu item option.
Returns:
None
--*/
{
UINT8 Length;
UINT8 SaveChar;
Length = (UINT8) EFI_MIN (70, MenuItemPtr->DataLen);
SaveChar = MenuItemPtr->Data[Length];
MenuItemPtr->Data[Length] = 0;
Aprint (" %a\n", MenuItemPtr->Data);
MenuItemPtr->Data[Length] = SaveChar;
}
STATIC
EFI_STATUS
DoMenu (
PXE_BASECODE_DEVICE *Private,
DHCP_RECEIVE_BUFFER *RxBufferPtr
)
/*++
Routine Description:
Display and process menu.
Arguments:
Private - Pointer to PxeBc interface
RxBufferPtr - Pointer to receive buffer
Returns:
NO_MENU -
LOCAL_BOOT -
--*/
{
PXE_OP_DISCOVERY_CONTROL *DiscoveryControlPtr;
PXE_BOOT_MENU_ENTRY *MenuItemPtrs[MAX_MENULIST];
EFI_STATUS Status;
UNION_PTR Ptr;
UINTN SaveNumRte;
UINTN TopRow;
UINTN MenuLth;
UINTN NumMenuItems;
UINTN Index;
UINTN Longest;
UINTN Selected;
UINT16 Type;
UINT16 Layer;
BOOLEAN Done;
Selected = 0;
Layer = 0;
DEBUG ((EFI_D_WARN, "\nDoMenu() Enter."));
/* see if we have a menu/prompt */
if (!(RxBufferPtr->OpAdds.Status & DISCOVER_TYPE)) {
DEBUG (
(EFI_D_WARN,
"\nDoMenu() No menu/prompt info. OpAdds.Status == %xh ",
RxBufferPtr->OpAdds.Status)
);
return NO_MENU;
}
DiscoveryControlPtr = (PXE_OP_DISCOVERY_CONTROL *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
//
// if not USE_BOOTFILE or no bootfile given, must have menu stuff
//
if ((DiscoveryControlPtr->ControlBits & USE_BOOTFILE) && RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
DEBUG ((EFI_D_WARN, "\nDoMenu() DHCP w/ bootfile. "));
return NO_MENU;
}
//
// do prompt & menu if necessary
//
Status = DoPrompt (Private, (PXE_OP_BOOT_PROMPT *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]);
if (Status == LOCAL_BOOT) {
DEBUG ((EFI_D_WARN, "\nDoMenu() DoPrompt() returned LOCAL_BOOT. "));
return Status;
}
Ptr.BytePtr = (UINT8 *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?