pxe_loadfile.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,697 行 · 第 1/3 页
C
1,697 行
MenuLth = Ptr.MenuPtr->Header.Length;
Ptr.CurrentMenuItemPtr = Ptr.MenuPtr->MenuItem;
//
// build menu items array
//
for (Longest = NumMenuItems = Index = 0; Index < MenuLth && NumMenuItems <= MAX_MENULIST;) {
UINTN lth;
lth = Ptr.CurrentMenuItemPtr->DataLen + sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data);
MenuItemPtrs[NumMenuItems++] = Ptr.CurrentMenuItemPtr;
if (lth > Longest) {
//
// check if too long
//
if ((Longest = lth) > 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))) {
Longest = 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data));
}
}
Index += lth;
Ptr.BytePtr += lth;
}
if (Status != AUTO_SELECT) {
UINT8 BlankBuf[75];
EfiSetMem (BlankBuf, sizeof BlankBuf, ' ');
BlankBuf[Longest + 5 - (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))] = 0;
Aprint ("\n");
//
// now put up menu
//
for (Index = 0; Index < NumMenuItems; ++Index) {
PrintMenuItem (MenuItemPtrs[Index]);
}
TopRow = gST->ConOut->Mode->CursorRow - NumMenuItems;
//
// now wait for a selection
//
Done = FALSE;
do {
//
// highlight selection
//
EFI_INPUT_KEY Key;
UINTN NewSelected;
NewSelected = Selected;
//
// highlight selected row
//
gST->ConOut->SetAttribute (
gST->ConOut,
EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)
);
gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Selected);
Aprint (" --->%a\r", BlankBuf);
PrintMenuItem (MenuItemPtrs[Selected]);
gST->ConOut->SetAttribute (
gST->ConOut,
EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
);
gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + NumMenuItems);
//
// wait for a keystroke
//
while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {
UINT8 TmpBuf[512];
UINTN TmpBufLen;
TmpBufLen = sizeof TmpBuf;
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 */
&TmpBufLen,
TmpBuf
);
}
if (!Key.ScanCode) {
switch (Key.UnicodeChar) {
case Ctl ('c'):
Key.ScanCode = SCAN_ESC;
break;
case Ctl ('j'): /* linefeed */
case Ctl ('m'): /* return */
Done = TRUE;
break;
case Ctl ('i'): /* tab */
case ' ':
case 'd':
case 'D':
Key.ScanCode = SCAN_DOWN;
break;
case Ctl ('h'): /* backspace */
case 'u':
case 'U':
Key.ScanCode = SCAN_UP;
break;
default:
Key.ScanCode = 0;
}
}
switch (Key.ScanCode) {
case SCAN_LEFT:
case SCAN_UP:
if (NewSelected) {
--NewSelected;
}
break;
case SCAN_DOWN:
case SCAN_RIGHT:
if (++NewSelected == NumMenuItems) {
--NewSelected;
}
break;
case SCAN_PAGE_UP:
case SCAN_HOME:
NewSelected = 0;
break;
case SCAN_PAGE_DOWN:
case SCAN_END:
NewSelected = NumMenuItems - 1;
break;
case SCAN_ESC:
return LOCAL_BOOT;
}
/* unhighlight last selected row */
gST->ConOut->SetCursorPosition (gST->ConOut, 5, TopRow + Selected);
Aprint ("%a\r", BlankBuf);
PrintMenuItem (MenuItemPtrs[Selected]);
Selected = NewSelected;
} while (!Done);
}
SaveNumRte = Private->EfiBc.Mode->RouteTableEntries;
Type = NTOHS (MenuItemPtrs[Selected]->Type);
if (Type == 0) {
DEBUG ((EFI_D_WARN, "\nDoMenu() Local boot selected. "));
return LOCAL_BOOT;
}
Aprint ("Discover");
Status = Private->EfiBc.Discover (
&Private->EfiBc,
Type,
&Layer,
(BOOLEAN) (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected),
0
);
if (EFI_ERROR (Status)) {
Aprint ("\r \r");
DEBUG (
(EFI_D_WARN,
"\nDoMenu() Return w/ %xh (%r).",
Status,
Status)
);
return Status;
}
Aprint ("\rBOOT_SERVER_IP: ");
PrintIpv4 ((UINT8 *) &Private->ServerIp);
for (Index = SaveNumRte; Index < Private->EfiBc.Mode->RouteTableEntries; ++Index) {
if ((Index % 3) == 0) {
Aprint ("\r\nGATEWAY IP:");
}
Aprint (" ");
PrintIpv4 ((UINT8 *) &Private->EfiBc.Mode->RouteTable[Index].GwAddr);
Aprint (" ");
}
Aprint ("\n");
DEBUG ((EFI_D_WARN, "\nDoMenu() Return w/ EFI_SUCCESS. "));
return EFI_SUCCESS;
}
STATIC
UINT16
GetValue (
DHCPV4_OP_STRUCT *OpPtr
)
/*++
Routine Description:
Get value 8- or 16-bit value from DHCP option.
Arguments:
OpPtr - Pointer to DHCP option
Returns:
Value from DHCP option
--*/
{
if (OpPtr->Header.Length == 1) {
return OpPtr->Data[0];
} else {
return NTOHS (OpPtr->Data);
}
}
STATIC
UINT8 *
_PxeBcFindOpt (
UINT8 *BufferPtr,
UINTN BufferLen,
UINT8 OpCode
)
/*++
Routine Description:
Locate opcode in buffer.
Arguments:
BufferPtr - Pointer to buffer
BufferLen - Length of buffer
OpCode - Option number
Returns:
Pointer to opcode, may be NULL
--*/
{
if (BufferPtr == NULL) {
return NULL;
}
while (BufferLen != 0) {
if (*BufferPtr == OpCode) {
return BufferPtr;
}
switch (*BufferPtr) {
case OP_END:
return NULL;
case OP_PAD:
++BufferPtr;
--BufferLen;
continue;
}
if ((UINTN) BufferLen <= (UINTN) 2 + BufferPtr[1]) {
return NULL;
}
BufferLen -= 2 + BufferPtr[1];
BufferPtr += 2 + BufferPtr[1];
}
return NULL;
}
UINT8 *
PxeBcFindDhcpOpt (
EFI_PXE_BASE_CODE_PACKET *PacketPtr,
UINT8 OpCode
)
/*++
Routine Description:
Find option in packet
Arguments:
PacketPtr - Pointer to packet
OpCode - option number
Returns:
Pointer to option in packet
--*/
{
UINTN PacketLen;
UINT8 Overload;
UINT8 *OptionBufferPtr;
//
//
//
PacketLen = 380;
Overload = 0;
//
// Figure size of DHCP option space.
//
OptionBufferPtr = _PxeBcFindOpt (
PacketPtr->Dhcpv4.DhcpOptions,
380,
OP_DHCP_MAX_MESSAGE_SZ
);
if (OptionBufferPtr != NULL) {
if (OptionBufferPtr[1] == 2) {
UINT16 n;
EfiCopyMem (&n, &OptionBufferPtr[2], 2);
PacketLen = HTONS (n);
if (PacketLen < sizeof (EFI_PXE_BASE_CODE_DHCPV4_PACKET)) {
PacketLen = 380;
} else {
PacketLen -= (PacketPtr->Dhcpv4.DhcpOptions - &PacketPtr->Dhcpv4.BootpOpcode) + 28;
}
}
}
//
// Look for option overloading.
//
OptionBufferPtr = _PxeBcFindOpt (
PacketPtr->Dhcpv4.DhcpOptions,
PacketLen,
OP_DHCP_OPTION_OVERLOAD
);
if (OptionBufferPtr != NULL) {
if (OptionBufferPtr[1] == 1) {
Overload = OptionBufferPtr[2];
}
}
//
// Look for caller's option.
//
OptionBufferPtr = _PxeBcFindOpt (
PacketPtr->Dhcpv4.DhcpOptions,
PacketLen,
OpCode
);
if (OptionBufferPtr != NULL) {
return OptionBufferPtr;
}
if (Overload & OVLD_FILE) {
OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpBootFile, 128, OpCode);
if (OptionBufferPtr != NULL) {
return OptionBufferPtr;
}
}
if (Overload & OVLD_SRVR_NAME) {
OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpSrvName, 64, OpCode);
if (OptionBufferPtr != NULL) {
return OptionBufferPtr;
}
}
return NULL;
}
STATIC
EFI_STATUS
DownloadFile (
IN PXE_BASECODE_DEVICE *Private,
IN OUT UINT64 *BufferSize,
IN VOID *Buffer
)
/*++
Routine Description:
Download file into buffer
Arguments:
Private - Pointer to PxeBc interface
BufferSize - pointer to size of download buffer
Buffer - Pointer to buffer
Returns:
EFI_BUFFER_TOO_SMALL -
EFI_NOT_FOUND -
EFI_PROTOCOL_ERROR -
--*/
{
EFI_PXE_BASE_CODE_MTFTP_INFO MtftpInfo;
EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode;
DHCP_RECEIVE_BUFFER *RxBuf;
EFI_STATUS Status;
UINTN BlockSize;
RxBuf = (DHCP_RECEIVE_BUFFER *) Private->BootServerReceiveBuffer;
BlockSize = 0x8000;
DEBUG ((EFI_D_WARN, "\nDownloadFile() Enter."));
if (Buffer == NULL || *BufferSize == 0 || *BufferSize < Private->FileSize) {
if (Private->FileSize != 0) {
*BufferSize = Private->FileSize;
return EFI_BUFFER_TOO_SMALL;
}
Aprint ("\nTSize");
OpCode = EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE;
} else if (RxBuf->OpAdds.Status & WfM11a_TYPE) {
OpCode = EFI_PXE_BASE_CODE_MTFTP_READ_FILE;
EfiZeroMem (&MtftpInfo, sizeof MtftpInfo);
*(IPV4_ADDR *) &MtftpInfo.MCastIp = *(IPV4_ADDR *) RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_IP - 1]->Data;
EfiCopyMem (
&MtftpInfo.CPort,
RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_CPORT - 1]->Data,
sizeof MtftpInfo.CPort
);
EfiCopyMem (
&MtftpInfo.SPort,
RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_SPORT - 1]->Data,
sizeof MtftpInfo.SPort
);
MtftpInfo.ListenTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_TMOUT - 1]);
MtftpInfo.TransmitTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_DELAY - 1]);
Aprint ("\nMTFTP");
} else {
Aprint ("\nTFTP");
OpCode = EFI_PXE_BASE_CODE_TFTP_READ_FILE;
}
Private->FileSize = 0;
RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data[RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length] = 0;
Status = Private->EfiBc.Mtftp (
&Private->EfiBc,
OpCode,
Buffer,
FALSE,
BufferSize,
&BlockSize,
&Private->ServerIp,
(UINT8 *) RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data,
&MtftpInfo,
FALSE
);
if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) {
DEBUG ((EFI_D_WARN, "\nDownloadFile() Exit #1 %Xh", Status));
return Status;
}
if (sizeof (UINTN) < sizeof (UINT64) && *BufferSize > 0xFFFFFFFF) {
Private->FileSize = 0xFFFFFFFF;
} else {
Private->FileSize = (UINTN) *BufferSize;
}
if (OpCode == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {
DEBUG ((EFI_D_WARN, "\nDownloadFile() Exit #2"));
return EFI_BUFFER_TOO_SMALL;
}
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_WARN, "\nDownloadFile() Exit #3 %Xh", Status));
return Status;
}
if (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected && Private->EfiBc.Mode->PxeBisReplyReceived) {
UINT64 CredentialLen;
UINTN BlockSize;
UINT8 CredentialFilename[256];
UINT8 *op;
VOID *CredentialBuffer;
//
// Get name of credential file. It may be in the BOOTP
// bootfile field or a DHCP option.
//
EfiZeroMem (CredentialFilename, sizeof CredentialFilename);
op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_DHCP_BOOTFILE);
if (op != NULL) {
if (op[1] == 0) {
/* No credential filename */
return EFI_NOT_FOUND;
}
EfiCopyMem (CredentialFilename, &op[2], op[1]);
} else {
if (Private->EfiBc.Mode->PxeBisReply.Dhcpv4.BootpBootFile[0] == 0) {
/* No credential filename */
return EFI_NOT_FOUND;
}
EfiCopyMem (CredentialFilename, &op[2], 128);
}
//
// Get size of credential file. It may be available as a
// DHCP option. If not, use the TFTP get file size.
//
CredentialLen = 0;
op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_BOOT_FILE_SZ);
if (op != NULL) {
/*
* This is actually the size of the credential file
* buffer. The actual credential file size will be
* returned when we download the file.
*/
if (op[1] == 2) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?