Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1305 lines
35 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
net.c
Abstract:
This module implements the net boot file system used by the operating
system loader.
It only contains those functions which are firmware/BIOS dependent.
Author:
Revision History:
--*/
#include "..\bootlib.h"
#include "stdio.h"
#ifdef UINT16
#undef UINT16
#endif
#ifdef INT16
#undef INT16
#endif
#include <dhcp.h>
#include <netfs.h>
#include <pxe_cmn.h>
#include <pxe_api.h>
#include <udp_api.h>
#include <tftp_api.h>
#include "bldr.h"
#include "bootia64.h"
#include "efi.h"
#include "efip.h"
#include "bldria64.h"
#include "extern.h"
#include "smbios.h"
#ifndef BOOL
typedef int BOOL;
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef BYTE
typedef unsigned char BYTE;
#endif
#ifndef LPBYTE
typedef BYTE *LPBYTE;
#endif
#define MAX_PATH 260
//
// Define global data.
//
CHAR NetBootPath[129];
EFI_PXE_BASE_CODE *PXEClient;
ULONG NetLocalIpAddress;
ULONG NetLocalSubnetMask;
ULONG NetServerIpAddress;
ULONG NetGatewayIpAddress;
UCHAR NetLocalHardwareAddress[16];
UCHAR MyGuid[16];
ULONG MyGuidLength = sizeof(MyGuid);
BOOLEAN MyGuidValid = FALSE;
TFTP_RESTART_BLOCK gTFTPRestartBlock;
VOID
EfiDumpBuffer(
PVOID Buffer,
ULONG BufferSize
)
/*++
Routine Description:
Dumps the buffer content on to the debugger output.
Arguments:
Buffer: buffer pointer.
BufferSize: size of the buffer.
Return Value:
none
--*/
{
#define NUM_CHARS 16
ULONG i, limit;
CHAR TextBuffer[NUM_CHARS + 1];
PUCHAR BufferPtr = Buffer;
BlPrint(TEXT("------------------------------------\r\n"));
//
// Hex dump of the bytes
//
limit = ((BufferSize - 1) / NUM_CHARS + 1) * NUM_CHARS;
for (i = 0; i < limit; i++) {
if (i < BufferSize) {
BlPrint(TEXT("%x "), (UCHAR)BufferPtr[i]);
if (BufferPtr[i] < 31 ) {
TextBuffer[i % NUM_CHARS] = '.';
} else if (BufferPtr[i] == '\0') {
TextBuffer[i % NUM_CHARS] = ' ';
} else {
TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i];
}
} else {
BlPrint(TEXT(" "));
TextBuffer[i % NUM_CHARS] = ' ';
}
if ((i + 1) % NUM_CHARS == 0) {
TextBuffer[NUM_CHARS] = 0;
BlPrint(TEXT(" %s\r\n"), TextBuffer);
}
}
BlPrint(TEXT("------------------------------------\r\n"));
#if 0
//
// enable this to make it pause after dumping the buffer.
//
DBG_EFI_PAUSE();
#endif
}
EFI_STATUS
EfiGetPxeClient(
VOID
)
/*++
Routine Description:
Obtains the global pointer to the PXE device
booted from in a RIS scenario.
Arguments:
none
Return Value:
ESUCCESS when successful, otherwise failure
--*/
{
EFI_STATUS Status = EFI_UNSUPPORTED;
EFI_GUID PXEGuid = EFI_PXE_BASE_CODE_PROTOCOL;
EFI_LOADED_IMAGE *EfiImageInfo;
EFI_DEVICE_PATH *PXEDevicePath;
EFI_HANDLE PXEHandle;
if (PXEClient) {
//
// already have a pointer to the device
// no more work needed
//
return ESUCCESS;
}
//
// get the correct PXE Handle by looking at the loaded
// image for oschooser
//
//
// get the image info for oschooser
//
FlipToPhysical();
Status = EfiST->BootServices->HandleProtocol (EfiImageHandle,
&EfiLoadedImageProtocol,
&EfiImageInfo);
FlipToVirtual();
if (Status != EFI_SUCCESS) {
if( BdDebuggerEnabled ) {
DbgPrint( "EfiGetPxeClient: HandleProtocol failed -LoadedImageProtocol (%d)\n", Status);
}
return Status;
}
//
// get the device path to the image
//
FlipToPhysical();
Status = EfiST->BootServices->HandleProtocol (EfiImageInfo->DeviceHandle,
&EfiDevicePathProtocol,
&PXEDevicePath);
FlipToVirtual();
if (Status != EFI_SUCCESS) {
if( BdDebuggerEnabled ) {
DbgPrint( "EfiGetPxeClient: HandleProtocol failed -DevicePathProtocol (%d)\n", Status);
}
return Status;
}
//
// get the PXE_BASE_CODE_PROTOCOL interface from returned handle
//
FlipToPhysical();
Status = EfiST->BootServices->LocateDevicePath(&PXEGuid,
&PXEDevicePath,
&PXEHandle);
FlipToVirtual();
if (Status != EFI_SUCCESS)
{
if( BdDebuggerEnabled ) {
DbgPrint( "EfiGetPxeClient: LocateDevicePath failed (%d)\n", Status);
}
return Status;
}
// get the pxebc interface from PXEHandle
FlipToPhysical();
Status = EfiST->BootServices->HandleProtocol(PXEHandle,
&PXEGuid,
&PXEClient);
FlipToVirtual();
if (Status != EFI_SUCCESS)
{
if( BdDebuggerEnabled ) {
DbgPrint( "EfiGetPxeClient: HandleProtocol failed -PXEBCP interface (%d)\n", Status);
}
return Status;
}
return EFI_SUCCESS;
}
ARC_STATUS
FindDhcpOption(
IN EFI_PXE_BASE_CODE_PACKET Packet,
IN UCHAR Option,
IN ULONG MaximumLength,
OUT PUCHAR OptionData,
OUT PULONG Length OPTIONAL,
IN ULONG Instance OPTIONAL
)
/*++
Routine Description:
Searches a dhcp packet for a given option.
Arguments:
Packet - pointer to the dhcp packet. Caller is responsible for assuring
that the packet is a valid dhcp packet.
Option - the dhcp option we're searching for.
MaximumLength - size in bytes of OptionData buffer.
OptionData - buffer to receive the option.
Length - if specified, receives the actual length of option copied.
Instance - specifies which instance of the option you are searching for.
If not specified (zero), then we just grab the first instance of the tag.
Return Value:
ARC_STATUS indicating outcome.
--*/
{
PUCHAR curOption;
ULONG copyLength;
ULONG i = 0;
if (MaximumLength == 0) {
return EINVAL;
}
RtlZeroMemory(OptionData, MaximumLength);
//
// Parse the DHCP options looking for a specific one.
//
curOption = (PUCHAR)&Packet.Dhcpv4.DhcpOptions;
while ((curOption - (PUCHAR)&Packet.Dhcpv4) < sizeof(EFI_PXE_BASE_CODE_DHCPV4_PACKET) &&
*curOption != 0xff) {
if (*curOption == DHCP_PAD) {
//
// just walk past any pad options
// these will not have any length
//
curOption++;
}
else {
if (*curOption == Option) {
//
// Found it, copy and leave.
//
if ( i == Instance ) {
if (sizeof(EFI_PXE_BASE_CODE_DHCPV4_PACKET) <= curOption + 2 - (PUCHAR)&Packet.Dhcpv4 ||
sizeof(EFI_PXE_BASE_CODE_DHCPV4_PACKET) <= curOption + 2 + curOption[1] - (PUCHAR)&Packet.Dhcpv4 ) {
//
// invalid option. it walked past the end of the packet
//
break;
}
if (curOption[1] > MaximumLength) {
copyLength = MaximumLength;
} else {
copyLength = curOption[1];
}
RtlCopyMemory(OptionData,
curOption+2,
copyLength);
if (ARGUMENT_PRESENT(Length)) {
*Length = copyLength;
}
return ESUCCESS;
}
i++;
}
curOption = curOption + 2 + curOption[1];
}
}
return EINVAL;
}
BOOLEAN
IsIpv4AddressNonZero(
EFI_IPv4_ADDRESS *pAddress
)
{
if (pAddress->Addr[0] != 0 ||
pAddress->Addr[1] != 0 ||
pAddress->Addr[2] != 0 ||
pAddress->Addr[3] != 0) {
return(TRUE);
}
return(FALSE);
}
ARC_STATUS
GetParametersFromRom (
VOID
)
{
UINTN Count = 0;
EFI_STATUS Status = EFI_UNSUPPORTED;
PUCHAR p;
UCHAR temp[4];
//
// obtain a pointer to the PXE device we booted from
//
Status = EfiGetPxeClient();
if (Status != EFI_SUCCESS) {
return (ARC_STATUS) Status;
}
//
// Our IP address is down in:
// PXEClient->Mode->StationIp.v4
//
// The server's IP address is down in:
// PXEClient->Mode->ProxyOffer.Dhcpv4.BootpSiAddr
//
// Our NIC's GUID should be down in:
// PXEClient->Mode->ProxyOffer.Dhcpv4.BootpHwAddr
//
// Our Subnetmask is down in:
// PXEClient->Mode->SubnetMask.v4
//
NetServerIpAddress = 0;
NetLocalIpAddress = 0;
NetLocalSubnetMask = 0;
NetGatewayIpAddress = 0;
for( Count = 0; Count < 4; Count++ ) {
NetServerIpAddress = (NetServerIpAddress << 8) + PXEClient->Mode->ProxyOffer.Dhcpv4.BootpSiAddr[Count];
NetLocalIpAddress = (NetLocalIpAddress << 8) + PXEClient->Mode->StationIp.v4.Addr[Count];
NetLocalSubnetMask = (NetLocalSubnetMask << 8) + PXEClient->Mode->SubnetMask.v4.Addr[Count];
}
//
// Our gateway address is either in the dhcp ack or the proxy offer packet.
// proxy offer overrides the dhcp ack.
// first look for the dhcp router option, then look in the packet itself.
//
//
if (FindDhcpOption(PXEClient->Mode->DhcpAck, DHCP_ROUTER, sizeof(temp), (PUCHAR)temp, NULL, 0) == ESUCCESS) {
NetGatewayIpAddress = (temp[0] << 24) +
(temp[1] << 16) +
(temp[2] << 8) +
temp[3];
} else if (IsIpv4AddressNonZero((EFI_IPv4_ADDRESS *)&PXEClient->Mode->DhcpAck.Dhcpv4.BootpGiAddr[0])) {
NetGatewayIpAddress = (PXEClient->Mode->DhcpAck.Dhcpv4.BootpGiAddr[0] << 24) +
(PXEClient->Mode->DhcpAck.Dhcpv4.BootpGiAddr[1] << 16) +
(PXEClient->Mode->DhcpAck.Dhcpv4.BootpGiAddr[2] << 8) +
PXEClient->Mode->DhcpAck.Dhcpv4.BootpGiAddr[3];
}
if (FindDhcpOption(PXEClient->Mode->ProxyOffer, DHCP_ROUTER, sizeof(temp), (PUCHAR)temp, NULL, 0) == ESUCCESS) {
NetGatewayIpAddress = (temp[0] << 24) +
(temp[1] << 16) +
(temp[2] << 8) +
temp[3];
} else if (IsIpv4AddressNonZero((EFI_IPv4_ADDRESS *)&PXEClient->Mode->ProxyOffer.Dhcpv4.BootpGiAddr[0])) {
NetGatewayIpAddress = (PXEClient->Mode->ProxyOffer.Dhcpv4.BootpGiAddr[0] << 24) +
(PXEClient->Mode->ProxyOffer.Dhcpv4.BootpGiAddr[1] << 16) +
(PXEClient->Mode->ProxyOffer.Dhcpv4.BootpGiAddr[2] << 8) +
PXEClient->Mode->ProxyOffer.Dhcpv4.BootpGiAddr[3];
}
memcpy( NetLocalHardwareAddress, PXEClient->Mode->ProxyOffer.Dhcpv4.BootpHwAddr, sizeof(NetLocalHardwareAddress) );
//
// Get the path where we were launched from. We what to remove the
// actual file name (oschoice.efi in this case), but leave that trailing
// '\'.
//
strncpy( NetBootPath, (PCHAR)PXEClient->Mode->ProxyOffer.Dhcpv4.BootpBootFile, sizeof(NetBootPath) );
NetBootPath[sizeof(NetBootPath)-1] = '\0';
p = (PUCHAR)strrchr( NetBootPath, '\\' );
if( p ) {
p++;
*p = '\0';
} else {
NetBootPath[0] = '\0'; // no path
}
return ESUCCESS;
}
VOID
EfiNetTerminate(
VOID
)
{
FlipToPhysical();
PXEClient->Stop( PXEClient );
FlipToVirtual();
}
ARC_STATUS
GetGuid(
OUT PUCHAR *Guid,
OUT PULONG GuidLength
)
/*++
Routine Description:
This routine returns the Guid of this machine.
Arguments:
Guid - Place to store pointer to the guid.
GuidLength - Place to store the length in bytes of the guid.
Return Value:
ARC code indicating outcome.
--*/
{
PSMBIOS_SYSTEM_INFORMATION_STRUCT SystemInfoHeader = NULL;
*Guid = NULL;
*GuidLength = 0;
SystemInfoHeader = (PSMBIOS_SYSTEM_INFORMATION_STRUCT)FindSMBIOSTable( SMBIOS_SYSTEM_INFORMATION );
if( SystemInfoHeader ) {
*Guid = (PUCHAR)BlAllocateHeap( SYSID_UUID_DATA_SIZE );
if( *Guid ) {
*GuidLength = SYSID_UUID_DATA_SIZE;
RtlCopyMemory( *Guid,
SystemInfoHeader->Uuid,
SYSID_UUID_DATA_SIZE );
return ESUCCESS;
} else {
if(BdDebuggerEnabled) { DbgPrint( "GetGuid: Failed Alloc.\r\n" ); }
*GuidLength = 0;
return ENOMEM;
}
} else {
if(BdDebuggerEnabled) { DbgPrint( "GetGuid: Failed to find a SMBIOS_SYSTEM_INFORMATION table.\n" ); }
}
return ENODEV;
}
ULONG
CalculateChecksum(
IN PLONG Block,
IN ULONG Length
)
/*++
Routine Description:
This routine calculates a simple two's-complement checksum of a block of
memory. If the returned value is stored in the block (in a word that was
zero during the calculation), then new checksum of the block will be zero.
Arguments:
Block - Address of a block of data. Must be 4-byte aligned.
Length - Length of the block. Must be a multiple of 4.
Return Value:
ULONG - Two's complement additive checksum of the input block.
--*/
{
LONG checksum = 0;
ASSERT( ((ULONG_PTR)Block & 3) == 0 );
ASSERT( (Length & 3) == 0 );
for ( ; Length != 0; Length -= 4 ) {
checksum += *Block;
Block++;
}
return -checksum;
}
UINTN
DevicePathSize (
IN EFI_DEVICE_PATH *DevPath
)
{
EFI_DEVICE_PATH *Start;
/*
* Search for the end of the device path structure
* */
Start = DevPath;
while (!IsDevicePathEnd(DevPath)) {
DevPath = NextDevicePathNode(DevPath);
}
/*
* Compute the size
*/
return ((UINTN) DevPath - (UINTN) Start) + sizeof(EFI_DEVICE_PATH);
}
EFI_DEVICE_PATH *
DevicePathInstance (
IN OUT EFI_DEVICE_PATH **DevicePath,
OUT UINTN *Size
)
{
EFI_DEVICE_PATH *Start, *Next, *DevPath;
UINTN Count;
DevPath = *DevicePath;
Start = DevPath;
if (!DevPath) {
return NULL;
}
/*
* Check for end of device path type
* */
for (Count = 0; ; Count++) {
Next = NextDevicePathNode(DevPath);
if (IsDevicePathEndType(DevPath)) {
break;
}
if (Count > 01000) {
break;
}
DevPath = Next;
}
ASSERT (DevicePathSubType(DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE ||
DevicePathSubType(DevPath) == END_INSTANCE_DEVICE_PATH_SUBTYPE);
/*
* Set next position
*/
if (DevicePathSubType(DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
Next = NULL;
}
*DevicePath = Next;
/*
* Return size and start of device path instance
*/
*Size = ((UINT8 *) DevPath) - ((UINT8 *) Start);
return Start;
}
UINTN
DevicePathInstanceCount (
IN EFI_DEVICE_PATH *DevicePath
)
{
UINTN Count, Size;
Count = 0;
while (DevicePathInstance(&DevicePath, &Size)) {
Count += 1;
}
return Count;
}
EFI_DEVICE_PATH *
AppendDevicePath (
IN EFI_DEVICE_PATH *Src1,
IN EFI_DEVICE_PATH *Src2
)
/* Src1 may have multiple "instances" and each instance is appended
* Src2 is appended to each instance is Src1. (E.g., it's possible
* to append a new instance to the complete device path by passing
* it in Src2) */
{
UINTN Src1Size, Src1Inst, Src2Size, Size;
EFI_DEVICE_PATH *Dst, *Inst;
UINT8 *DstPos;
EFI_DEVICE_PATH EndInstanceDevicePath[] = { END_DEVICE_PATH_TYPE,
END_INSTANCE_DEVICE_PATH_SUBTYPE,
END_DEVICE_PATH_LENGTH,
0 };
EFI_DEVICE_PATH EndDevicePath[] = { END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
END_DEVICE_PATH_LENGTH,
0 };
Src1Size = DevicePathSize(Src1);
Src1Inst = DevicePathInstanceCount(Src1);
Src2Size = DevicePathSize(Src2);
Size = Src1Size * Src1Inst + Src2Size;
EfiAllocateAndZeroMemory( EfiLoaderData,
Size,
(VOID **) &Dst );
if (Dst) {
DstPos = (UINT8 *) Dst;
/*
* Copy all device path instances
*/
while ((Inst = DevicePathInstance (&Src1, &Size)) != 0) {
RtlCopyMemory(DstPos, Inst, Size);
DstPos += Size;
RtlCopyMemory(DstPos, Src2, Src2Size);
DstPos += Src2Size;
RtlCopyMemory(DstPos, EndInstanceDevicePath, sizeof(EFI_DEVICE_PATH));
DstPos += sizeof(EFI_DEVICE_PATH);
}
/* Change last end marker */
DstPos -= sizeof(EFI_DEVICE_PATH);
RtlCopyMemory(DstPos, EndDevicePath, sizeof(EFI_DEVICE_PATH));
}
return Dst;
}
NTSTATUS
NetSoftReboot(
IN PUCHAR NextBootFile,
IN ULONGLONG Param,
IN PUCHAR RebootFile OPTIONAL,
IN PUCHAR SifFile OPTIONAL,
IN PUCHAR User OPTIONAL,
IN PUCHAR Domain OPTIONAL,
IN PUCHAR Password OPTIONAL,
IN PUCHAR AdministratorPassword OPTIONAL
)
/*++
Routine Description:
This routine will load the specified file, build a parameter
list and transfer control to the loaded file.
Arguments:
NextBootFile - Fully qualified path name of the file to download.
Param - Reboot parameter to set.
RebootFile - String identifying the file to reboot to when after the current reboot is done.
SifFile - Optional SIF file to pass to the next loader.
User/Domain/Password/AdministratorPassword - Optional credentials to pass to the next loader.
Return Value:
Should not return if successful.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
EFI_DEVICE_PATH *ldrDevicePath = NULL, *Eop = NULL;
EFI_HANDLE ImageHandle = NULL;
UINTN i = 0;
EFI_STATUS EfiStatus = EFI_SUCCESS;
WCHAR WideNextBootFile[MAX_PATH];
FILEPATH_DEVICE_PATH *FilePath = NULL;
UNICODE_STRING uString;
ANSI_STRING aString;
EFI_LOADED_IMAGE *OriginalEfiImageInfo = NULL;
EFI_LOADED_IMAGE *LoadedEfiImageInfo = NULL;
EFI_DEVICE_PATH *OriginalEfiDevicePath = NULL;
PTFTP_RESTART_BLOCK restartBlock = NULL;
PTFTP_RESTART_BLOCK_V1 restartBlockV1 = NULL;
ULONG BootFileId = 0;
PUCHAR LoadedImageAddress = NULL;
ULONG LoadedImageSize = 0;
//
// Load the file we want to boot into memory.
//
Status = BlOpen( NET_DEVICE_ID,
(PCHAR)NextBootFile,
ArcOpenReadOnly,
&BootFileId );
if (Status != ESUCCESS) {
return Status;
}
//
// What memory address did he get loaded into?
//
// make sure we have the physical address
//
LoadedImageAddress = (PUCHAR)((ULONGLONG)(BlFileTable[BootFileId].u.NetFileContext.InMemoryCopy) & ~KSEG0_BASE);
LoadedImageSize = BlFileTable[BootFileId].u.NetFileContext.FileSize;
//
// BUild a device path to the target file. We'll do this by gathering
// some information about ourselves, knowing that we're about to load/launch
// an image from the server, just like where we came from.
//
//
// Get image information on ourselves.
//
FlipToPhysical();
EfiStatus = EfiST->BootServices->HandleProtocol( EfiImageHandle,
&EfiLoadedImageProtocol,
&OriginalEfiImageInfo );
FlipToVirtual();
if( EFI_ERROR(EfiStatus) ) {
if( BdDebuggerEnabled ) {
DbgPrint( "NetSoftReboot: HandleProtocol_1 failed (%d)\n", EfiStatus );
}
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Get our DevicePath too.
//
FlipToPhysical();
EfiStatus = EfiST->BootServices->HandleProtocol( OriginalEfiImageInfo->DeviceHandle,
&EfiDevicePathProtocol,
&OriginalEfiDevicePath );
FlipToVirtual();
if( EFI_ERROR(EfiStatus) ) {
if( BdDebuggerEnabled ) {
DbgPrint( "NetSoftReboot: HandleProtocol_2 failed (%d)\n", EfiStatus );
}
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Now build a device path based on the DeviceHandle of ourselves, along
// with the path to the image we want to load.
//
RtlInitString( &aString, (PCHAR)NextBootFile );
uString.MaximumLength = MAX_PATH;
uString.Buffer = WideNextBootFile;
RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
i = wcslen(uString.Buffer);
EfiStatus = EfiAllocateAndZeroMemory( EfiLoaderData,
i + sizeof(FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH),
(VOID **) &FilePath );
if( EFI_ERROR(EfiStatus) ) {
if( BdDebuggerEnabled ) {
DbgPrint( "NetSoftReboot: AllocatePool_1 failed (%d)\n", EfiStatus );
}
return STATUS_NO_MEMORY;
}
FilePath->Header.Type = MEDIA_DEVICE_PATH;
FilePath->Header.SubType = MEDIA_FILEPATH_DP;
SetDevicePathNodeLength (&FilePath->Header, i + sizeof(FILEPATH_DEVICE_PATH));
RtlCopyMemory (FilePath->PathName, uString.Buffer, i);
FlipToPhysical();
Eop = NextDevicePathNode(&FilePath->Header);
SetDevicePathEndNode(Eop);
//
// Append file path to device's device path
//
ldrDevicePath = (EFI_DEVICE_PATH *)FilePath;
ldrDevicePath = AppendDevicePath ( OriginalEfiDevicePath,
ldrDevicePath );
FlipToVirtual();
//
// Load the image, then set its loadoptions in preparation
// for launching it.
//
if( BdDebuggerEnabled ) {
DbgPrint( "NetSoftReboot: About to LoadImage.\n" );
}
FlipToPhysical();
EfiStatus = EfiST->BootServices->LoadImage( FALSE,
EfiImageHandle,
ldrDevicePath,
LoadedImageAddress,
LoadedImageSize,
&ImageHandle );
FlipToVirtual();
if( EFI_ERROR(EfiStatus) ) {
if( BdDebuggerEnabled ) {
DbgPrint( "NetSoftReboot: LoadImage failed (%d)\n", EfiStatus );
}
return STATUS_NO_MEMORY;
} else {
if( BdDebuggerEnabled ) {
DbgPrint( "NetSoftReboot: LoadImage worked (%d)\n", EfiStatus );
}
}
//
// allocate a chunk of memory, then load it up w/ all the boot options.
//
EfiStatus = EfiAllocateAndZeroMemory( EfiLoaderData,
sizeof(TFTP_RESTART_BLOCK),
(VOID **) &restartBlock );
if( EFI_ERROR(EfiStatus) ) {
if( BdDebuggerEnabled ) {
DbgPrint( "NetSoftReboot: Failed to allocate memory for restartBlock (%d)\n", EfiStatus );
}
return STATUS_NO_MEMORY;
}
restartBlockV1 = (PTFTP_RESTART_BLOCK_V1)(&restartBlock->RestartBlockV1);
//
// There's no need to pass the headless settings through the restart block.
// The only way to get headless settings on EFI is to get them from firmware
// and we'll be checking for formware settings when we reboot back into
// setupldr anyway. -matth (2/2002)
//
// BlSetHeadlessRestartBlock(restartBlock);
if (AdministratorPassword) {
RtlMoveMemory(restartBlock->AdministratorPassword,AdministratorPassword, OSC_ADMIN_PASSWORD_LEN);
}
restartBlockV1->RebootParameter = Param;
if (RebootFile != NULL) {
strncpy(restartBlockV1->RebootFile, (PCHAR)RebootFile, sizeof(restartBlockV1->RebootFile));
restartBlockV1->RebootFile[sizeof(restartBlockV1->RebootFile)-1] = '\0';
}
if (SifFile != NULL) {
strncpy(restartBlockV1->SifFile, (PCHAR)SifFile, sizeof(restartBlockV1->SifFile));
restartBlockV1->SifFile[sizeof(restartBlockV1->SifFile)-1] = '\0';
}
if (User != NULL) {
strncpy(restartBlockV1->User, (PCHAR)User, sizeof(restartBlockV1->User));
restartBlockV1->User[sizeof(restartBlockV1->User)-1] = '\0';
}
if (Domain != NULL) {
strncpy(restartBlockV1->Domain, (PCHAR)Domain, sizeof(restartBlockV1->Domain));
restartBlockV1->Domain[sizeof(restartBlockV1->Domain)-1] = '\0';
}
if (Password != NULL) {
strncpy(restartBlockV1->Password, (PCHAR)Password, sizeof(restartBlockV1->Password));
restartBlockV1->Password[sizeof(restartBlockV1->Password)-1] = '\0';
}
//
// Set the tag in the restart block and calculate and store the checksum.
//
restartBlockV1->Tag = 'rtsR';
restartBlockV1->Checksum = CalculateChecksum((PLONG)(restartBlockV1), 128);
//
// For all versions of RIS after NT5.0 we have a new datastructure which is
// more adaptable for the future. For this section we have a different checksum,
// do that now.
//
restartBlock->TftpRestartBlockVersion = TFTP_RESTART_BLOCK_VERSION;
restartBlock->NewCheckSumLength = sizeof(TFTP_RESTART_BLOCK);
restartBlock->NewCheckSum = CalculateChecksum((PLONG)restartBlock,
restartBlock->NewCheckSumLength);
//
// We've got the command-line options all setup. Now we need to
// actually put them into ImageInfo->LoadOptions so they get
// passed to the loaded image.
//
if( BdDebuggerEnabled ) {
DbgPrint( "NetSoftReboot: About to EfiLoadedImageProtocol on the loadedImage.\n" );
}
FlipToPhysical();
EfiStatus = EfiST->BootServices->HandleProtocol( ImageHandle,
&EfiLoadedImageProtocol,
&LoadedEfiImageInfo );
FlipToVirtual();
if( EFI_ERROR(EfiStatus) ) {
if( BdDebuggerEnabled ) {
DbgPrint( "NetSoftReboot: HandleProtocol_3 failed (%d)\n", EfiStatus );
}
return STATUS_INSUFFICIENT_RESOURCES;
}
LoadedEfiImageInfo->LoadOptions = (PVOID)restartBlock;
LoadedEfiImageInfo->LoadOptionsSize = sizeof(TFTP_RESTART_BLOCK);
#if DBG
EfiDumpBuffer(LoadedEfiImageInfo->LoadOptions, sizeof(TFTP_RESTART_BLOCK));
#endif
//
// Since we loaded the image from a memory buffer, he's not
// going to have a DeviceHandle set. We'll fail quickly when
// setupldr.efi starts. We can just set it right here, and
// we know exactly what it is because it's the same as the
// network device handle for Oschoice.efi, wich we have
// readily available.
//
LoadedEfiImageInfo->DeviceHandle = OriginalEfiImageInfo->DeviceHandle;
LoadedEfiImageInfo->FilePath = ldrDevicePath;
if( BdDebuggerEnabled ) {
DbgPrint( "NetSoftReboot: LoadedEfiImageInfo->DeviceHandle: 0x%08lx\n", PtrToUlong(LoadedEfiImageInfo->DeviceHandle) );
DbgPrint( "NetSoftReboot: LoadedEfiImageInfo->FilePath: 0x%08lx\n", PtrToUlong(LoadedEfiImageInfo->FilePath) );
}
//
// We shouldn't return from this call!
//
if( BdDebuggerEnabled ) {
DbgPrint( "NetSoftReboot: StartImage.\n" );
}
FlipToPhysical();
EfiStatus = EfiST->BootServices->StartImage( ImageHandle,
0,
NULL );
FlipToVirtual();
if( EFI_ERROR(EfiStatus) ) {
if( BdDebuggerEnabled ) {
DbgPrint( "NetSoftReboot: StartImage failed (%d)\n", EfiStatus );
}
return STATUS_INSUFFICIENT_RESOURCES;
}
return Status;
}
VOID
NetGetRebootParameters(
OUT PULONGLONG Param OPTIONAL,
OUT PUCHAR RebootFile OPTIONAL,
OUT PUCHAR SifFile OPTIONAL,
OUT PUCHAR User OPTIONAL,
OUT PUCHAR Domain OPTIONAL,
OUT PUCHAR Password OPTIONAL,
OUT PUCHAR AdministratorPassword OPTIONAL,
BOOLEAN ClearRestartBlock
)
/*++
Routine Description:
This routine reads the reboot parameters from the global TFTP_RESTART_BLOCK
and returns them.
Arguments:
Param - Space for returning the value.
RebootFile - Optional space for storing the file to reboot to when done here. (size >= char[128])
SifFile - Optional space for storing a SIF file passed from whoever
initiated the soft reboot.
User/Domain/Password/AdministratorPassword - Optional space to store credentials passed across
the soft reboot.
ClearRestartBlock - If set to TRUE, it wipes out the memory here - should be done exactly once, at the
last call to this function.
Return Value:
None.
--*/
{
BOOLEAN restartBlockValid = FALSE;
#if DBG
EfiDumpBuffer(&gTFTPRestartBlock, sizeof(TFTP_RESTART_BLOCK));
#endif
//
// See if the block is valid. If it's not, we create a temporary empty
// one so the copy logic below doesn't have to keep checking.
//
if ((gTFTPRestartBlock.RestartBlockV1.Tag == 'rtsR') &&
(CalculateChecksum((PLONG)(&gTFTPRestartBlock.RestartBlockV1), 128) == 0)) {
restartBlockValid = TRUE;
}
//
// Copy out the parameters that were in the original TFTP_RESTART_BLOCK structure.
// These shipped in Win2K.
//
//
// Unfortunetly we do not know the size of the parameters passed to us.
// Assume they are no smaller than the fields in the restart block
//
if (Param != NULL) {
*Param = gTFTPRestartBlock.RestartBlockV1.RebootParameter;
}
if (RebootFile != NULL) {
memcpy(RebootFile, gTFTPRestartBlock.RestartBlockV1.RebootFile, sizeof(gTFTPRestartBlock.RestartBlockV1.RebootFile));
}
if (SifFile != NULL) {
memcpy(SifFile, gTFTPRestartBlock.RestartBlockV1.SifFile, sizeof(gTFTPRestartBlock.RestartBlockV1.SifFile));
}
if (User != NULL) {
strncpy((PCHAR)User, gTFTPRestartBlock.RestartBlockV1.User, sizeof(gTFTPRestartBlock.RestartBlockV1.User));
User[sizeof(gTFTPRestartBlock.RestartBlockV1.User)-1] = '\0';
}
if (Domain != NULL) {
strncpy((PCHAR)Domain, gTFTPRestartBlock.RestartBlockV1.Domain,sizeof(gTFTPRestartBlock.RestartBlockV1.Domain));
Domain[sizeof(gTFTPRestartBlock.RestartBlockV1.Domain)-1] = '\0';
}
if (Password != NULL) {
strncpy((PCHAR)Password, gTFTPRestartBlock.RestartBlockV1.Password, sizeof(gTFTPRestartBlock.RestartBlockV1.Password));
Password[sizeof(gTFTPRestartBlock.RestartBlockV1.Password)-1] = '\0';
}
//
// Now do a new check for all versions past Win2K
//
if (restartBlockValid) {
if ((gTFTPRestartBlock.NewCheckSumLength == 0) ||
(CalculateChecksum((PLONG)(&gTFTPRestartBlock), gTFTPRestartBlock.NewCheckSumLength) != 0)) {
//
// A pre-Win2K OsChooser has given us this block. Clear out all fields
// that are post-Win2K and continue.
//
RtlZeroMemory( &gTFTPRestartBlock, sizeof(TFTP_RESTART_BLOCK) );
}
}
//
// Now extract the parameters from the block.
//
if (gTFTPRestartBlock.TftpRestartBlockVersion == TFTP_RESTART_BLOCK_VERSION) {
//
// Don't load these here. Rather get the headless settings from firmware.
// -matth (2/2002)
//
// BlGetHeadlessRestartBlock(&gTFTPRestartBlock, restartBlockValid);
if (AdministratorPassword) {
RtlMoveMemory(AdministratorPassword,gTFTPRestartBlock.AdministratorPassword, OSC_ADMIN_PASSWORD_LEN);
}
}
if (restartBlockValid && ClearRestartBlock) {
RtlZeroMemory(&gTFTPRestartBlock, sizeof(TFTP_RESTART_BLOCK));
}
#if DBG
BlPrint(TEXT("Done getting TFTP_RESTART_BLOCK.\r\n"));
#endif
return;
}
ARC_STATUS
NetFillNetworkLoaderBlock (
PNETWORK_LOADER_BLOCK NetworkLoaderBlock
)
{
EFI_STATUS Status;
ARC_STATUS ArcStatus;
//
// get a pointer to the PXE client code.
//
Status = EfiGetPxeClient();
if (Status != EFI_SUCCESS) {
ArcStatus = EIO;
goto cleanup;
}
//
// save off the DHCPServerACK packet
//
NetworkLoaderBlock->DHCPServerACK = BlAllocateHeap(sizeof(EFI_PXE_BASE_CODE_PACKET));
if (NetworkLoaderBlock->DHCPServerACK == NULL) {
ArcStatus = ENOMEM;
goto cleanup;
}
memcpy(
NetworkLoaderBlock->DHCPServerACK,
&PXEClient->Mode->DhcpAck,
sizeof(EFI_PXE_BASE_CODE_PACKET) );
NetworkLoaderBlock->DHCPServerACKLength = sizeof(EFI_PXE_BASE_CODE_PACKET);
//
// save off the BINL reply packet
//
NetworkLoaderBlock->BootServerReplyPacket = BlAllocateHeap(sizeof(EFI_PXE_BASE_CODE_PACKET));
if (NetworkLoaderBlock->BootServerReplyPacket == NULL) {
ArcStatus = ENOMEM;
goto cleanup;
}
memcpy(
NetworkLoaderBlock->BootServerReplyPacket,
&PXEClient->Mode->ProxyOffer,
sizeof(EFI_PXE_BASE_CODE_PACKET) );
NetworkLoaderBlock->BootServerReplyPacketLength = sizeof(EFI_PXE_BASE_CODE_PACKET);
//
// we succeeded, mark success
//
ArcStatus = ESUCCESS;
cleanup:
return(ArcStatus);
}