1032 lines
26 KiB
C
1032 lines
26 KiB
C
/*++
|
||
|
||
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;
|
||
EFI_HANDLE PXEHandle;
|
||
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
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
GetParametersFromRom (
|
||
VOID
|
||
)
|
||
{
|
||
UINTN BufferSize = sizeof(EFI_HANDLE);
|
||
INTN Count = 0;
|
||
EFI_GUID PXEGuid = EFI_PXE_BASE_CODE_PROTOCOL;
|
||
UINT16 layer = 0;
|
||
EFI_STATUS Status = EFI_UNSUPPORTED;
|
||
PUCHAR p;
|
||
|
||
//
|
||
// Get a pointer to all the PXE APIs.
|
||
//
|
||
FlipToPhysical();
|
||
Status = EfiST->BootServices->LocateHandle( ByProtocol,
|
||
&PXEGuid,
|
||
NULL,
|
||
&BufferSize,
|
||
&PXEHandle );
|
||
FlipToVirtual();
|
||
if( Status != EFI_SUCCESS ) {
|
||
|
||
if( BdDebuggerEnabled ) {
|
||
DbgPrint( "GetParametersFromRom: LocateHandle failed (%d)\n", Status);
|
||
}
|
||
return (ARC_STATUS)Status;
|
||
}
|
||
|
||
|
||
FlipToPhysical();
|
||
Status = EfiST->BootServices->HandleProtocol( PXEHandle,
|
||
&PXEGuid,
|
||
&PXEClient );
|
||
FlipToVirtual();
|
||
|
||
if( Status != EFI_SUCCESS ) {
|
||
|
||
if( BdDebuggerEnabled ) {
|
||
DbgPrint( "GetParametersFromRom: HandleProtocol failed (%d)\n", Status);
|
||
}
|
||
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
|
||
//
|
||
NetServerIpAddress = 0;
|
||
NetLocalIpAddress = 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];
|
||
}
|
||
|
||
|
||
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
|
||
// '\'.
|
||
//
|
||
strcpy( NetBootPath, PXEClient->Mode->ProxyOffer.Dhcpv4.BootpBootFile );
|
||
p = strrchr( NetBootPath, '\\' );
|
||
if( p ) {
|
||
p++;
|
||
*p = '\0';
|
||
}
|
||
|
||
return ESUCCESS;
|
||
|
||
}
|
||
|
||
VOID
|
||
EfiNetTerminate(
|
||
VOID
|
||
)
|
||
{
|
||
FlipToPhysical();
|
||
|
||
PXEClient->Stop( PXEClient );
|
||
|
||
FlipToVirtual();
|
||
}
|
||
|
||
|
||
VOID
|
||
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:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSMBIOS_SYSTEM_INFORMATION_STRUCT SystemInfoHeader = NULL;
|
||
|
||
*Guid = NULL;
|
||
*GuidLength = 0;
|
||
|
||
SystemInfoHeader = (PSMBIOS_SYSTEM_INFORMATION_STRUCT)FindSMBIOSTable( SMBIOS_SYSTEM_INFORMATION );
|
||
|
||
if( SystemInfoHeader ) {
|
||
|
||
if(BdDebuggerEnabled) { DbgPrint( "GetGuid: Failed Alloc.\r\n" ); }
|
||
*Guid = (PUCHAR)BlAllocateHeap( SYSID_UUID_DATA_SIZE );
|
||
if( *Guid ) {
|
||
*GuidLength = SYSID_UUID_DATA_SIZE;
|
||
|
||
RtlCopyMemory( *Guid,
|
||
SystemInfoHeader->Uuid,
|
||
SYSID_UUID_DATA_SIZE );
|
||
|
||
} else {
|
||
if(BdDebuggerEnabled) { DbgPrint( "GetGuid: Failed Alloc.\r\n" ); }
|
||
*GuidLength = 0;
|
||
}
|
||
|
||
} else {
|
||
|
||
if(BdDebuggerEnabled) { DbgPrint( "GetGuid: Failed to find a SMBIOS_SYSTEM_INFORMATION table.\n" ); }
|
||
}
|
||
}
|
||
|
||
|
||
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;
|
||
|
||
EfiST->BootServices->AllocatePool( EfiLoaderData,
|
||
Size,
|
||
(VOID **) &Dst );
|
||
|
||
if (Dst) {
|
||
DstPos = (UINT8 *) Dst;
|
||
|
||
/*
|
||
* Copy all device path instances
|
||
*/
|
||
|
||
while (Inst = DevicePathInstance (&Src1, &Size)) {
|
||
|
||
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_GUID EfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL;
|
||
EFI_GUID EfiDevicePathProtocol = DEVICE_PATH_PROTOCOL;
|
||
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,
|
||
NextBootFile,
|
||
ArcOpenReadOnly,
|
||
&BootFileId );
|
||
if (Status != ESUCCESS) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// What memory address did he get loaded into?
|
||
//
|
||
LoadedImageAddress = BlFileTable[BootFileId].u.NetFileContext.InMemoryCopy;
|
||
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, NextBootFile );
|
||
uString.MaximumLength = MAX_PATH;
|
||
uString.Buffer = WideNextBootFile;
|
||
RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
|
||
|
||
i = wcslen(uString.Buffer);
|
||
FlipToPhysical();
|
||
EfiStatus = EfiST->BootServices->AllocatePool( EfiLoaderData,
|
||
i + sizeof(FILEPATH_DEVICE_PATH) + sizeof(EFI_DEVICE_PATH),
|
||
(VOID **) &FilePath );
|
||
FlipToVirtual();
|
||
|
||
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.
|
||
//
|
||
FlipToPhysical();
|
||
EfiStatus = EfiST->BootServices->AllocatePool( EfiLoaderData,
|
||
sizeof(TFTP_RESTART_BLOCK),
|
||
(VOID **) &restartBlock );
|
||
FlipToVirtual();
|
||
|
||
restartBlockV1 = (PTFTP_RESTART_BLOCK_V1)(&restartBlock->RestartBlockV1);
|
||
|
||
BlSetHeadlessRestartBlock(restartBlock);
|
||
|
||
if (AdministratorPassword) {
|
||
RtlMoveMemory(restartBlock->AdministratorPassword,AdministratorPassword, OSC_ADMIN_PASSWORD_LEN);
|
||
}
|
||
|
||
restartBlockV1->RebootParameter = Param;
|
||
|
||
if (RebootFile != NULL) {
|
||
strcpy(restartBlockV1->RebootFile, RebootFile);
|
||
}
|
||
|
||
if (SifFile != NULL) {
|
||
strcpy(restartBlockV1->SifFile, SifFile);
|
||
}
|
||
|
||
if (User != NULL) {
|
||
strcpy(restartBlockV1->User, User);
|
||
}
|
||
if (Domain != NULL) {
|
||
strcpy(restartBlockV1->Domain, Domain);
|
||
}
|
||
if (Password != NULL) {
|
||
strcpy(restartBlockV1->Password, Password);
|
||
}
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
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) {
|
||
strcpy(User, gTFTPRestartBlock.RestartBlockV1.User);
|
||
}
|
||
if (Domain != NULL) {
|
||
strcpy(Domain, gTFTPRestartBlock.RestartBlockV1.Domain);
|
||
}
|
||
if (Password != NULL) {
|
||
strcpy(Password, gTFTPRestartBlock.RestartBlockV1.Password);
|
||
}
|
||
|
||
//
|
||
// 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) {
|
||
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
|
||
)
|
||
{
|
||
SHORT status;
|
||
t_PXENV_GET_BINL_INFO gbi;
|
||
BOOTPLAYER packet;
|
||
|
||
|
||
//
|
||
// Get client IP address, server IP address, default gateway IP address,
|
||
// and subnet mask from the DHCP ACK packet.
|
||
//
|
||
|
||
gbi.packet_type = PXENV_PACKET_TYPE_DHCP_ACK;
|
||
gbi.buffer_size = sizeof(packet);
|
||
gbi.buffer_offset = (USHORT)((ULONG_PTR)&packet & 0x0f);
|
||
gbi.buffer_segment = (USHORT)(((ULONG_PTR)&packet >> 4) & 0xffff);
|
||
|
||
status = NETPC_ROM_SERVICES( PXENV_GET_BINL_INFO, &gbi );
|
||
if ( status != PXENV_EXIT_SUCCESS ) {
|
||
DbgPrint("PXENV_GET_BINL_INFO(DHCPACK) failed with %x\n", status);
|
||
return ENODEV;
|
||
}
|
||
|
||
NetworkLoaderBlock->DHCPServerACK = BlAllocateHeap(gbi.buffer_size);
|
||
if (NetworkLoaderBlock->DHCPServerACK == NULL) {
|
||
return ENOMEM;
|
||
}
|
||
|
||
memcpy( NetworkLoaderBlock->DHCPServerACK, &packet, gbi.buffer_size );
|
||
NetworkLoaderBlock->DHCPServerACKLength = gbi.buffer_size;
|
||
|
||
gbi.packet_type = PXENV_PACKET_TYPE_BINL_REPLY;
|
||
gbi.buffer_size = sizeof(packet);
|
||
gbi.buffer_offset = (USHORT)((ULONG_PTR)&packet & 0x0f);
|
||
gbi.buffer_segment = (USHORT)(((ULONG_PTR)&packet >> 4) & 0xffff);
|
||
|
||
status = NETPC_ROM_SERVICES( PXENV_GET_BINL_INFO, &gbi );
|
||
if ( status != PXENV_EXIT_SUCCESS ) {
|
||
DbgPrint("PXENV_GET_BINL_INFO(BINLREPLY) failed with %x\n", status);
|
||
} else {
|
||
|
||
NetworkLoaderBlock->BootServerReplyPacket = BlAllocateHeap(gbi.buffer_size);
|
||
if (NetworkLoaderBlock->BootServerReplyPacket == NULL) {
|
||
return ENOMEM;
|
||
}
|
||
|
||
memcpy( NetworkLoaderBlock->BootServerReplyPacket, &packet, gbi.buffer_size );
|
||
NetworkLoaderBlock->BootServerReplyPacketLength = gbi.buffer_size;
|
||
}
|
||
|
||
return ESUCCESS;
|
||
}
|
||
|