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.
1297 lines
35 KiB
1297 lines
35 KiB
|
|
/*++
|
|
|
|
Copyright (c) 1995 Intel Corporation
|
|
|
|
Module Name:
|
|
|
|
i64fw.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the routines that transfer control
|
|
from the kernel to the PAL and SAL code.
|
|
|
|
Author:
|
|
|
|
Arad Rostampour ([email protected]) Mar-21-99
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
#include "arc.h"
|
|
#include "arccodes.h"
|
|
#include "i64fw.h"
|
|
|
|
#include <efi.h>
|
|
|
|
|
|
extern KSPIN_LOCK HalpSalSpinLock;
|
|
extern KSPIN_LOCK HalpSalStateInfoSpinLock;
|
|
|
|
BOOLEAN
|
|
MmSetPageProtection(
|
|
IN PVOID VirtualAddress,
|
|
IN SIZE_T NumberOfBytes,
|
|
IN ULONG NewProtect
|
|
);
|
|
|
|
VOID
|
|
HalpReboot (
|
|
VOID
|
|
);
|
|
|
|
|
|
HALP_SAL_PAL_DATA HalpSalPalData;
|
|
ULONGLONG HalpSalProcPointer=0;
|
|
ULONGLONG HalpSalProcGlobalPointer=0;
|
|
ULONGLONG HalpPhysSalProcPointer=0;
|
|
ULONGLONG HalpPhysSalProcGlobalPointer=0;
|
|
ULONGLONG HalpPhysPalProcPointer=0;
|
|
ULONGLONG HalpVirtPalProcPointer=0;
|
|
|
|
// Testing #defines
|
|
//
|
|
//#define SAL_TEST
|
|
//#define PAL_TEST
|
|
|
|
#if DBG
|
|
ULONG HalpDebugTestSalPalCall=0;
|
|
#endif
|
|
|
|
|
|
LONGLONG
|
|
HalCallPal(
|
|
IN ULONGLONG FunctionIndex,
|
|
IN ULONGLONG Arguement1,
|
|
IN ULONGLONG Arguement2,
|
|
IN ULONGLONG Arguement3,
|
|
OUT PULONGLONG ReturnValue0,
|
|
OUT PULONGLONG ReturnValue1,
|
|
OUT PULONGLONG ReturnValue2,
|
|
OUT PULONGLONG ReturnValue3
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Will interface to PAL Calls.
|
|
//
|
|
LONGLONG Status;
|
|
|
|
SAL_PAL_RETURN_VALUES rv = {0};
|
|
PSAL_PAL_RETURN_VALUES p = &rv;
|
|
|
|
Status = (LONGLONG) HalpPalCall(FunctionIndex,Arguement1,Arguement2,Arguement3,p);
|
|
|
|
if (ReturnValue0 != 0) // Check the pointer is not NULL
|
|
|
|
*ReturnValue0 = (ULONGLONG)(p -> ReturnValues[0]);
|
|
|
|
if (ReturnValue1 != 0) // check the pointer is not NULL
|
|
|
|
*ReturnValue1 = (ULONGLONG)(p -> ReturnValues[1]);
|
|
|
|
if (ReturnValue2 != 0) // check the pointer is not NULL
|
|
|
|
*ReturnValue2 = (ULONGLONG)(p -> ReturnValues[2]);
|
|
|
|
if (ReturnValue3 != 0) // check the pointer is not NULL
|
|
|
|
*ReturnValue3 = (ULONGLONG)(p -> ReturnValues[3]);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
SAL_PAL_RETURN_VALUES
|
|
HalpSalProcPhysical(
|
|
IN LONGLONG FunctionId,
|
|
IN LONGLONG Arg1,
|
|
IN LONGLONG Arg2,
|
|
IN LONGLONG Arg3,
|
|
IN LONGLONG Arg4,
|
|
IN LONGLONG Arg5,
|
|
IN LONGLONG Arg6,
|
|
IN LONGLONG Arg7
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is a wrapper for making a physical mode SAL call. This
|
|
function's only job is to provide the stack and backing store pointers
|
|
needed by HalpSalProcPhysicalEx.
|
|
|
|
Arguments:
|
|
|
|
FunctionId - The SAL function ID.
|
|
|
|
Arg1 through Arg7 - The values to be passed to SAL_PROC.
|
|
|
|
Return Value:
|
|
|
|
A SAL_PAL_RETURN_VALUES structure filled in with the data returned by
|
|
HalpSalProcPhysicalEx.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONGLONG StackPointer;
|
|
ULONGLONG BackingStorePointer;
|
|
ULONGLONG StackBase;
|
|
|
|
//
|
|
// Load the addresses of the stack and backing store reserved for
|
|
// physical mode SAL calls on this processor.
|
|
//
|
|
|
|
StackBase = PCR->HalReserved[PROCESSOR_PHYSICAL_FW_STACK_INDEX];
|
|
|
|
StackPointer = GET_FW_STACK_POINTER(StackBase);
|
|
BackingStorePointer = GET_FW_BACKING_STORE_POINTER(StackBase);
|
|
|
|
//
|
|
// Branch to the assembly routine that makes the actual SAL call.
|
|
//
|
|
|
|
return HalpSalProcPhysicalEx(
|
|
FunctionId,
|
|
Arg1,
|
|
Arg2,
|
|
Arg3,
|
|
Arg4,
|
|
Arg5,
|
|
Arg6,
|
|
Arg7,
|
|
(LONGLONG) StackPointer,
|
|
(LONGLONG) BackingStorePointer
|
|
);
|
|
}
|
|
|
|
SAL_STATUS
|
|
HalpSalCall(
|
|
IN LONGLONG FunctionId,
|
|
IN LONGLONG Arg1,
|
|
IN LONGLONG Arg2,
|
|
IN LONGLONG Arg3,
|
|
IN LONGLONG Arg4,
|
|
IN LONGLONG Arg5,
|
|
IN LONGLONG Arg6,
|
|
IN LONGLONG Arg7,
|
|
OUT PSAL_PAL_RETURN_VALUES ReturnValues
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is a wrapper function for making a SAL call. Callers within the
|
|
HAL must use this function to call the SAL.
|
|
|
|
Arguments:
|
|
|
|
FunctionId - The SAL function ID
|
|
Arg1-Arg7 - SAL defined arguments for each call
|
|
ReturnValues - A pointer to an array of 4 64-bit return values
|
|
|
|
Return Value:
|
|
|
|
SAL's return status, return value 0, is returned in addition to the ReturnValues structure
|
|
being filled
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL OldIrql;
|
|
KIRQL TempIrql;
|
|
BOOLEAN fixLogId;
|
|
HALP_SAL_PROC SalProc;
|
|
|
|
//
|
|
// Zero out the return buffer.
|
|
//
|
|
|
|
RtlZeroMemory(ReturnValues,sizeof(SAL_PAL_RETURN_VALUES));
|
|
|
|
//
|
|
// Choose a SAL call dispatcher depending upon whether a virtual mapping
|
|
// for the SAL exists. If a virtual mapping isn't in place we'll try
|
|
// to make the call in physical mode. Return SAL_STATUS_NOT_IMPLEMENTED
|
|
// if we aren't configured to make calls in either mode.
|
|
//
|
|
|
|
if (!NT_SUCCESS(HalpSalPalData.Status) || HalpSalProcPointer == 0) {
|
|
|
|
//
|
|
// We've already ruled out a virtual mode call. If possible
|
|
// we'll try to make an equivalent physical mode call in this
|
|
// case.
|
|
//
|
|
|
|
if (HalpPhysSalProcPointer != 0) {
|
|
SalProc = HalpSalProcPhysical;
|
|
|
|
} else {
|
|
return SAL_STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
} else {
|
|
SalProc = HalpSalProc;
|
|
}
|
|
|
|
|
|
fixLogId = (HalpSalPalData.Flags & HALP_SALPAL_FIX_MCE_LOG_ID) != 0;
|
|
|
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|
|
|
switch (FunctionId) {
|
|
|
|
// These calls are neither re-entrant, nor MP-safe as defined by the SAL spec
|
|
|
|
case SAL_SET_VECTORS:
|
|
case SAL_MC_SET_PARAMS:
|
|
case SAL_FREQ_BASE:
|
|
|
|
KiAcquireSpinLock(&HalpSalSpinLock);
|
|
*ReturnValues = SalProc(FunctionId,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7);
|
|
KiReleaseSpinLock(&HalpSalSpinLock);
|
|
break;
|
|
|
|
case SAL_GET_STATE_INFO:
|
|
KiAcquireSpinLock(&HalpSalStateInfoSpinLock);
|
|
*ReturnValues = SalProc(FunctionId,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7);
|
|
if ( fixLogId && (ReturnValues->ReturnValues[0] >= (LONGLONG)0) ) {
|
|
// ERROR_RECORD_HEADER.Id++
|
|
*(PULONGLONG)((ULONGLONG)Arg3) = ++HalpSalPalData.Reserved[0];
|
|
}
|
|
KiReleaseSpinLock(&HalpSalStateInfoSpinLock);
|
|
break;
|
|
|
|
case SAL_GET_STATE_INFO_SIZE:
|
|
case SAL_CLEAR_STATE_INFO:
|
|
|
|
KiAcquireSpinLock(&HalpSalStateInfoSpinLock);
|
|
*ReturnValues = SalProc(FunctionId,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7);
|
|
KiReleaseSpinLock(&HalpSalStateInfoSpinLock);
|
|
break;
|
|
|
|
case SAL_PCI_CONFIG_READ:
|
|
case SAL_PCI_CONFIG_WRITE:
|
|
|
|
KiAcquireSpinLock(&HalpSalSpinLock);
|
|
*ReturnValues = SalProc(FunctionId,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7);
|
|
KiReleaseSpinLock(&HalpSalSpinLock);
|
|
break;
|
|
|
|
//
|
|
// Move these to MP safe after SAL is fixed
|
|
// Kernel ensures only one CACHE_FLUSH at a time
|
|
//
|
|
|
|
case SAL_CACHE_INIT:
|
|
case SAL_CACHE_FLUSH:
|
|
if ( HalpSalPalData.Flags & HALP_SALPAL_FIX_MP_SAFE ) {
|
|
KiAcquireSpinLock(&HalpSalSpinLock);
|
|
*ReturnValues = SalProc(FunctionId,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7);
|
|
KiReleaseSpinLock(&HalpSalSpinLock);
|
|
}
|
|
else
|
|
*ReturnValues = SalProc(FunctionId,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7);
|
|
break;
|
|
|
|
//
|
|
// These SAL calls are MP-safe, but not re-entrant
|
|
//
|
|
|
|
case SAL_MC_RENDEZ:
|
|
*ReturnValues = SalProc(FunctionId,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7);
|
|
break;
|
|
|
|
//
|
|
// These calls are not supported at this time
|
|
//
|
|
|
|
case SAL_UPDATE_PAL: // needs end of firmware space to be mapped, and possible authentication code to execute
|
|
|
|
default:
|
|
ReturnValues->ReturnValues[0] = SAL_STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
KeLowerIrql(OldIrql);
|
|
|
|
#ifdef SAL_TEST
|
|
if (ReturnValues->ReturnValues[0] == SAL_STATUS_NOT_IMPLEMENTED) {
|
|
InternalTestSal(FunctionId,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7,ReturnValues);
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
// To avoid Kd hangs while flushing and then MP synchronization issues..
|
|
HalDebugPrint(( HAL_INFO,
|
|
"HAL: Got out of SAL call #0x%I64x with status 0x%I64x and RetVals 0x%I64x, 0x%I64x, 0x%I64x\n",
|
|
FunctionId,
|
|
ReturnValues->ReturnValues[0],
|
|
ReturnValues->ReturnValues[1],
|
|
ReturnValues->ReturnValues[2],
|
|
ReturnValues->ReturnValues[3] ));
|
|
#endif
|
|
|
|
return (ReturnValues->ReturnValues[0]);
|
|
|
|
}
|
|
|
|
PAL_STATUS
|
|
HalpPalCall(
|
|
IN LONGLONG FunctionId,
|
|
IN LONGLONG Arg1,
|
|
IN LONGLONG Arg2,
|
|
IN LONGLONG Arg3,
|
|
OUT PSAL_PAL_RETURN_VALUES ReturnValues
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is a wrapper function for making a PAL call. Callers within the
|
|
HAL must use this function to call the PAL.
|
|
|
|
Arguments:
|
|
|
|
FunctionId - The PAL function ID
|
|
Arg1-Arg3 - PAL defined arguments for each call
|
|
ReturnValues - A pointer to an array of 4 64-bit return values
|
|
|
|
Return Value:
|
|
|
|
PAL's return status, return value 0, is returned in addition to the ReturnValues structure
|
|
being filled
|
|
|
|
Assumptions:
|
|
|
|
PAL is being called with psr.bn = 1 in all cases (not from an interrupted state)
|
|
|
|
--*/
|
|
{
|
|
// Zero out the return buffer
|
|
|
|
RtlZeroMemory(ReturnValues,sizeof(SAL_PAL_RETURN_VALUES));
|
|
|
|
// Only allow PAL calls that are supported
|
|
|
|
switch (FunctionId) {
|
|
|
|
// Virtual mode PAL calls
|
|
|
|
case PAL_CACHE_FLUSH:
|
|
case PAL_CACHE_INFO:
|
|
case PAL_CACHE_PROT_INFO:
|
|
case PAL_CACHE_SUMMARY:
|
|
case PAL_PTCE_INFO:
|
|
case PAL_VM_INFO:
|
|
case PAL_VM_PAGE_SIZE:
|
|
case PAL_VM_SUMMARY:
|
|
case PAL_PERF_MON_INFO:
|
|
case PAL_MC_CLEAR_LOG:
|
|
case PAL_MC_DRAIN:
|
|
case PAL_MC_ERROR_INFO:
|
|
case PAL_HALT_LIGHT:
|
|
case PAL_PREFETCH_VISIBILITY:
|
|
case PAL_SHUTDOWN:
|
|
case PAL_FREQ_RATIOS:
|
|
case PAL_VERSION:
|
|
case PAL_MEM_ATTRIB:
|
|
case PAL_DEBUG_INFO:
|
|
case PAL_FIXED_ADDR:
|
|
case PAL_FREQ_BASE:
|
|
case PAL_PLATFORM_ADDR:
|
|
case PAL_REGISTER_INFO:
|
|
case PAL_RSE_INFO:
|
|
|
|
// PAL is MP-safe, but not re-entrant, HalpPalProc/HalpPalProcPhysicalStatic disables interrupts.
|
|
|
|
//
|
|
// FIXFIX: Temporary solution to make sure we have a valid Pal TR per processor
|
|
// to make virtual PAL calls.
|
|
// PCR->HalReserved[ PROCESSOR_PHYSICAL_FW_STACK_INDEX] gets set for every processor
|
|
// by call to HalpAllocateProcessorPhysicalCallStacks during SalPal init
|
|
//
|
|
if (HalpVirtPalProcPointer && PCR->HalReserved[PROCESSOR_PHYSICAL_FW_STACK_INDEX]) {
|
|
|
|
*ReturnValues = HalpPalProc(FunctionId,Arg1,Arg2,Arg3);
|
|
|
|
} else if (HalpPhysPalProcPointer) {
|
|
|
|
// call in physical mode
|
|
*ReturnValues = HalpPalProcPhysicalStatic(FunctionId, Arg1, Arg2, Arg3);
|
|
|
|
} else {
|
|
|
|
// Hal PalProc pointers are not setup yet
|
|
|
|
ReturnValues->ReturnValues[0] = PAL_STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
break;
|
|
|
|
// Physical mode, static PAL calls
|
|
|
|
case PAL_HALT:
|
|
case PAL_CACHE_INIT:
|
|
case PAL_BUS_GET_FEATURES:
|
|
case PAL_BUS_SET_FEATURES:
|
|
case PAL_PROC_GET_FEATURES:
|
|
case PAL_PROC_SET_FEATURES:
|
|
case PAL_MC_DYNAMIC_STATE:
|
|
case PAL_MC_EXPECTED:
|
|
case PAL_MC_REGISTER_MEM:
|
|
case PAL_MC_RESUME:
|
|
case PAL_CACHE_LINE_INIT:
|
|
case PAL_MEM_FOR_TEST:
|
|
case PAL_COPY_INFO:
|
|
case PAL_ENTER_IA_32_ENV:
|
|
case PAL_PMI_ENTRYPOINT:
|
|
|
|
//
|
|
// PAL is MP-safe, but not re-entrant, HalpPalProcPhysicalStatic
|
|
// disables interrupts.
|
|
//
|
|
|
|
if (HalpPhysPalProcPointer) {
|
|
|
|
*ReturnValues = HalpPalProcPhysicalStatic(FunctionId, Arg1, Arg2, Arg3);
|
|
|
|
} else {
|
|
|
|
// Hal PalProc pointers are not setup yet
|
|
|
|
ReturnValues->ReturnValues[0] = PAL_STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
break;
|
|
|
|
// Physical mode, stacked PAL calls
|
|
|
|
case PAL_VM_TR_READ:
|
|
case PAL_CACHE_READ:
|
|
case PAL_CACHE_WRITE:
|
|
case PAL_TEST_PROC:
|
|
case PAL_COPY_PAL:
|
|
case PAL_HALT_INFO:
|
|
{
|
|
ULONGLONG StackBase;
|
|
ULONGLONG BackingStorePointer;
|
|
ULONGLONG StackPointer;
|
|
|
|
//
|
|
// Load the addresses of the stack and backing store reserved for
|
|
// physical mode PAL calls on this processor.
|
|
//
|
|
|
|
StackBase = PCR->HalReserved[PROCESSOR_PHYSICAL_FW_STACK_INDEX];
|
|
|
|
StackPointer = GET_FW_STACK_POINTER(StackBase);
|
|
BackingStorePointer = GET_FW_BACKING_STORE_POINTER(StackBase);
|
|
|
|
//
|
|
// PAL is MP-safe, but not re-entrant, HalpPalProcPhysicalStacked
|
|
// disables interrupts.
|
|
//
|
|
|
|
if (HalpPhysPalProcPointer) {
|
|
|
|
*ReturnValues = HalpPalProcPhysicalStacked(
|
|
FunctionId,
|
|
Arg1,
|
|
Arg2,
|
|
Arg3,
|
|
(LONGLONG) StackPointer,
|
|
(LONGLONG) BackingStorePointer
|
|
);
|
|
|
|
} else {
|
|
|
|
// Hal PalProc pointers are not setup yet
|
|
ReturnValues->ReturnValues[0] = PAL_STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
HalDebugPrint(( HAL_ERROR, "HAL: Unknown PAL Call ProcId #0x%I64x\n", FunctionId ));
|
|
ReturnValues->ReturnValues[0] = PAL_STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
#ifdef PAL_TEST
|
|
if (ReturnValues->ReturnValues[0] == PAL_STATUS_NOT_IMPLEMENTED) {
|
|
InternalTestPal(FunctionId,Arg1,Arg2,Arg3,ReturnValues);
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
// To avoid Kd hangs while flushing...
|
|
HalDebugPrint(( HAL_INFO,
|
|
"HAL: Got out of PAL call #0x%I64x with status 0x%I64x and RetVals 0x%I64x, 0x%I64x, 0x%I64x\n",
|
|
FunctionId,
|
|
ReturnValues->ReturnValues[0],
|
|
ReturnValues->ReturnValues[1],
|
|
ReturnValues->ReturnValues[2],
|
|
ReturnValues->ReturnValues[3] ));
|
|
#endif
|
|
|
|
return (ReturnValues->ReturnValues[0]);
|
|
}
|
|
|
|
|
|
VOID
|
|
HalReturnToFirmware(
|
|
IN FIRMWARE_ENTRY Routine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns control to the firmware routine specified. Since the simulation
|
|
does not provide PAL and SAL support, it just stops the system.
|
|
|
|
System reboot can be done here.
|
|
|
|
Arguments:
|
|
|
|
Routine - Supplies a value indicating which firmware routine to invoke.
|
|
|
|
Return Value:
|
|
|
|
Does not return.
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (Routine) {
|
|
case HalHaltRoutine:
|
|
case HalPowerDownRoutine:
|
|
case HalRestartRoutine:
|
|
case HalRebootRoutine:
|
|
HalpReboot();
|
|
break;
|
|
|
|
default:
|
|
HalDebugPrint(( HAL_INFO, "HAL: HalReturnToFirmware called\n" ));
|
|
DbgBreakPoint();
|
|
break;
|
|
}
|
|
}
|
|
|
|
ARC_STATUS
|
|
HalGetEnvironmentVariable (
|
|
IN PCHAR Variable,
|
|
IN USHORT Length,
|
|
OUT PCHAR Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function locates an environment variable and returns its value.
|
|
|
|
The following system environment variables are supported:
|
|
|
|
variable value
|
|
|
|
LastKnownGood FALSE
|
|
SYSTEMPARTITION multi(0)disk(0)rdisk(0)partition(1)
|
|
OSLOADER multi(0)disk(0)rdisk(0)partition(1)\osloader.exe
|
|
OSLOADPARTITION multi(0)disk(0)rdisk(0)partition(1)
|
|
OSLOADFILENAME \WINNT
|
|
LOADIDENTIFIER Windows NT
|
|
COUNTDOWN 10
|
|
AUTOLOAD YES
|
|
|
|
|
|
The only environment variable this implementation supports is
|
|
"LastKnownGood". The returned value is always "FALSE".
|
|
|
|
Arguments:
|
|
|
|
Variable - Supplies a pointer to a zero terminated environment variable
|
|
name.
|
|
|
|
Length - Supplies the length of the value buffer in bytes.
|
|
|
|
Buffer - Supplies a pointer to a buffer that receives the variable value.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS is returned if the enviroment variable is located. Otherwise,
|
|
ENOENT is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
return ENOENT;
|
|
}
|
|
|
|
|
|
ARC_STATUS
|
|
HalSetEnvironmentVariable (
|
|
IN PCHAR Variable,
|
|
IN PCHAR Value
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates an environment variable with the specified value.
|
|
|
|
The environment variable this implementation supports is
|
|
|
|
LastKnownGood
|
|
SYSTEMPARTITION
|
|
OSLOADER
|
|
OSLOADPARTITION
|
|
OSLOADFILENAME
|
|
OSLOADOPTIONS
|
|
LOADIDENTIFIER
|
|
COUNTDOWN
|
|
AUTOLOAD
|
|
|
|
For all bug LastKnowGood we return ESUCCESS, but don't actually do
|
|
anything.
|
|
|
|
Arguments:
|
|
|
|
Variable - Supplies a pointer to an environment variable name.
|
|
|
|
Value - Supplies a pointer to the environment variable value.
|
|
|
|
Return Value:
|
|
|
|
ESUCCESS is returned if the environment variable is created. Otherwise,
|
|
ENOMEM is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
return ENOENT;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
HalGetEnvironmentVariableEx (
|
|
IN PWSTR VariableName,
|
|
IN LPGUID VendorGuid,
|
|
OUT PVOID Value,
|
|
IN OUT PULONG ValueLength,
|
|
OUT PULONG Attributes OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function locates an environment variable and returns its value.
|
|
|
|
Arguments:
|
|
|
|
VariableName - The name of the variable to query. This is a null-terminated
|
|
Unicode string.
|
|
|
|
VendorGuid - The GUID for the vendor associated with the variable.
|
|
|
|
Value - The address of the buffer into which the variable value is to be copied.
|
|
|
|
ValueLength - On input, the length in bytes of the Value buffer. On output,
|
|
the length in bytes of the variable value. If the input buffer is large
|
|
enough, then ValueLength indicates the amount of data copied into Value.
|
|
If the input buffer is too small, then nothing is copied into the buffer,
|
|
and ValueLength indicates the required buffer length.
|
|
|
|
Attributes - Returns the attributes of the variable.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS The function succeeded.
|
|
STATUS_BUFFER_TOO_SMALL The input buffer was too small.
|
|
STATUS_VARIABLE_NOT_FOUND The requested variable does not exist.
|
|
STATUS_INVALID_PARAMETER One of the parameters is invalid.
|
|
STATUS_UNSUPPORTED The HAL does not support this function.
|
|
STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS ntStatus;
|
|
EFI_STATUS efiStatus;
|
|
ULONGLONG wideValueLength = *ValueLength;
|
|
ULONGLONG wideAttributes;
|
|
|
|
efiStatus = HalpCallEfi (
|
|
EFI_GET_VARIABLE_INDEX,
|
|
(ULONGLONG)VariableName,
|
|
(ULONGLONG)VendorGuid,
|
|
(ULONGLONG)&wideAttributes,
|
|
(ULONGLONG)&wideValueLength,
|
|
(ULONGLONG)Value,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
|
|
*ValueLength = (ULONG)wideValueLength;
|
|
if ( ARGUMENT_PRESENT(Attributes) ) {
|
|
*Attributes = (ULONG)wideAttributes;
|
|
}
|
|
switch (efiStatus) {
|
|
case EFI_SUCCESS:
|
|
ntStatus = STATUS_SUCCESS;
|
|
break;
|
|
case EFI_NOT_FOUND:
|
|
ntStatus = STATUS_VARIABLE_NOT_FOUND;
|
|
break;
|
|
case EFI_BUFFER_TOO_SMALL:
|
|
ntStatus = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
case EFI_INVALID_PARAMETER:
|
|
ntStatus = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
default:
|
|
ntStatus = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
HalSetEnvironmentVariableEx (
|
|
IN PWSTR VariableName,
|
|
IN LPGUID VendorGuid,
|
|
IN PVOID Value,
|
|
IN ULONG ValueLength,
|
|
IN ULONG Attributes
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates an environment variable with the specified value.
|
|
|
|
Arguments:
|
|
|
|
VariableName - The name of the variable to set. This is a null-terminated
|
|
Unicode string.
|
|
|
|
VendorGuid - The GUID for the vendor associated with the variable.
|
|
|
|
Value - The address of the buffer containing the new variable value.
|
|
|
|
ValueLength - The length in bytes of the Value buffer.
|
|
|
|
Attributes - The attributes of the variable. The attribute bit
|
|
VARIABLE_ATTRIBUTE_NON_VOLATILE MUST be set.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS The function succeeded.
|
|
STATUS_INSUFFICIENT_RESOURCES Not enough storage is available.
|
|
STATUS_INVALID_PARAMETER One of the parameters is invalid.
|
|
STATUS_UNSUPPORTED The HAL does not support this function.
|
|
STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS ntStatus;
|
|
EFI_STATUS efiStatus;
|
|
|
|
if ( (Attributes & VARIABLE_ATTRIBUTE_NON_VOLATILE) == 0 ) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// First, delete the old value, if it exists. This is necessary to ensure that
|
|
// the attributes specified to this routine are correctly applied.
|
|
//
|
|
|
|
efiStatus = HalpCallEfi (
|
|
EFI_SET_VARIABLE_INDEX,
|
|
(ULONGLONG)VariableName,
|
|
(ULONGLONG)VendorGuid,
|
|
(ULONGLONG)0, // Attributes
|
|
(ULONGLONG)0, // ValueLength
|
|
(ULONGLONG)NULL, // Value
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Now create the new variable, unless the ValueLength is zero. In that
|
|
// case, the caller actually wanted the variable deleted, which we just did.
|
|
//
|
|
|
|
if (ValueLength != 0) {
|
|
efiStatus = HalpCallEfi (
|
|
EFI_SET_VARIABLE_INDEX,
|
|
(ULONGLONG)VariableName,
|
|
(ULONGLONG)VendorGuid,
|
|
(ULONGLONG)EFI_VARIABLE_ATTRIBUTE,
|
|
(ULONGLONG)ValueLength,
|
|
(ULONGLONG)Value,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
}
|
|
|
|
switch (efiStatus) {
|
|
case EFI_SUCCESS:
|
|
ntStatus = STATUS_SUCCESS;
|
|
break;
|
|
case EFI_NOT_FOUND:
|
|
ntStatus = STATUS_VARIABLE_NOT_FOUND;
|
|
break;
|
|
case EFI_OUT_OF_RESOURCES:
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
case EFI_INVALID_PARAMETER:
|
|
ntStatus = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
default:
|
|
ntStatus = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
HalEnumerateEnvironmentVariablesEx (
|
|
IN ULONG InformationClass,
|
|
OUT PVOID Buffer,
|
|
IN OUT PULONG BufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns information about system environment variables.
|
|
|
|
Arguments:
|
|
|
|
InformationClass - Specifies the type of information to return.
|
|
|
|
Buffer - The address of the buffer that is to receive the returned data.
|
|
The format of the returned data depends on InformationClass.
|
|
|
|
BufferLength - On input, the length in bytes of the buffer. On output,
|
|
the length in bytes of the returned data. If the input buffer is
|
|
large enough, then BufferLength indicates the amount of data copied
|
|
into Buffer. If the input buffer is too small, then BufferLength
|
|
indicates the required buffer length.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS The function succeeded.
|
|
STATUS_BUFFER_TOO_SMALL The input buffer was too small.
|
|
STATUS_INVALID_PARAMETER One of the parameters is invalid.
|
|
STATUS_UNSUPPORTED The HAL does not support this function.
|
|
STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
EFI_STATUS efiStatus;
|
|
PUCHAR currentPtr;
|
|
PVARIABLE_NAME name;
|
|
PVARIABLE_NAME_AND_VALUE nameAndValue;
|
|
PVARIABLE_NAME previousEntry;
|
|
PWCHAR previousName;
|
|
ULONG variableNameLength;
|
|
GUID guid;
|
|
ULONG baseLength;
|
|
ULONG remainingLength;
|
|
PUCHAR valuePtr;
|
|
ULONG valueLength;
|
|
PULONG attrPtr;
|
|
LOGICAL filling;
|
|
ULONG requiredLength;
|
|
|
|
#define MAX_VARIABLE_NAME 255
|
|
|
|
WCHAR variableName[MAX_VARIABLE_NAME + 1];
|
|
|
|
if ( (InformationClass != VARIABLE_INFORMATION_NAMES) &&
|
|
(InformationClass != VARIABLE_INFORMATION_VALUES) ) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( ALIGN_DOWN_POINTER(Buffer, ULONG) != Buffer ) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ( InformationClass == VARIABLE_INFORMATION_NAMES ) {
|
|
baseLength = FIELD_OFFSET( VARIABLE_NAME, Name );
|
|
} else {
|
|
baseLength = FIELD_OFFSET( VARIABLE_NAME_AND_VALUE, Name );
|
|
}
|
|
|
|
currentPtr = Buffer;
|
|
remainingLength = *BufferLength;
|
|
|
|
filling = (LOGICAL)(remainingLength != 0);
|
|
if ( !filling ) {
|
|
ntStatus = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
previousEntry = NULL;
|
|
|
|
variableName[0] = 0;
|
|
|
|
while ( TRUE ) {
|
|
|
|
variableNameLength = (MAX_VARIABLE_NAME + 1) * sizeof(WCHAR);
|
|
|
|
{
|
|
ULONGLONG wideLength = variableNameLength;
|
|
|
|
efiStatus = HalpCallEfi (
|
|
EFI_GET_NEXT_VARIABLE_NAME_INDEX,
|
|
(ULONGLONG)&wideLength,
|
|
(ULONGLONG)variableName,
|
|
(ULONGLONG)&guid,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
|
|
variableNameLength = (ULONG)wideLength;
|
|
}
|
|
|
|
switch (efiStatus) {
|
|
case EFI_SUCCESS:
|
|
break;
|
|
case EFI_NOT_FOUND:
|
|
break;
|
|
default:
|
|
ntStatus = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
if ( efiStatus != EFI_SUCCESS ) {
|
|
break;
|
|
}
|
|
|
|
if ( ALIGN_UP_POINTER(currentPtr, ULONG) != currentPtr ) {
|
|
PUCHAR alignedPtr = ALIGN_UP_POINTER( currentPtr, ULONG );
|
|
ULONG fill = (ULONG)(alignedPtr - currentPtr);
|
|
currentPtr = alignedPtr;
|
|
if ( remainingLength < fill ) {
|
|
filling = FALSE;
|
|
remainingLength = 0;
|
|
ntStatus = STATUS_BUFFER_TOO_SMALL;
|
|
} else {
|
|
remainingLength -= fill;
|
|
}
|
|
}
|
|
|
|
requiredLength = baseLength + variableNameLength;
|
|
if ( InformationClass != VARIABLE_INFORMATION_NAMES ) {
|
|
requiredLength = ALIGN_UP( requiredLength, ULONG );
|
|
}
|
|
|
|
if ( remainingLength < requiredLength ) {
|
|
|
|
remainingLength = 0;
|
|
filling = FALSE;
|
|
ntStatus = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
} else {
|
|
|
|
remainingLength -= requiredLength;
|
|
}
|
|
|
|
name = (PVARIABLE_NAME)currentPtr;
|
|
nameAndValue = (PVARIABLE_NAME_AND_VALUE)currentPtr;
|
|
|
|
if ( InformationClass == VARIABLE_INFORMATION_NAMES ) {
|
|
|
|
if ( filling ) {
|
|
|
|
RtlCopyMemory( &name->VendorGuid, &guid, sizeof(GUID) );
|
|
wcscpy( name->Name, variableName );
|
|
|
|
if ( previousEntry != NULL ) {
|
|
previousEntry->NextEntryOffset = (ULONG)(currentPtr - (PUCHAR)previousEntry);
|
|
}
|
|
previousEntry = (PVARIABLE_NAME)currentPtr;
|
|
}
|
|
|
|
currentPtr += requiredLength;
|
|
|
|
} else {
|
|
|
|
ULONGLONG wideLength;
|
|
ULONGLONG wideAttr;
|
|
|
|
if ( filling ) {
|
|
|
|
RtlCopyMemory( &nameAndValue->VendorGuid, &guid, sizeof(GUID) );
|
|
wcscpy( nameAndValue->Name, variableName );
|
|
|
|
valuePtr = (PUCHAR)nameAndValue->Name + variableNameLength;
|
|
valuePtr = ALIGN_UP_POINTER( valuePtr, ULONG );
|
|
valueLength = remainingLength;
|
|
attrPtr = &nameAndValue->Attributes;
|
|
|
|
nameAndValue->ValueOffset = (ULONG)(valuePtr - (PUCHAR)nameAndValue);
|
|
|
|
} else {
|
|
|
|
valuePtr = NULL;
|
|
valueLength = 0;
|
|
attrPtr = NULL;
|
|
}
|
|
|
|
wideLength = valueLength;
|
|
|
|
efiStatus = HalpCallEfi (
|
|
EFI_GET_VARIABLE_INDEX,
|
|
(ULONGLONG)variableName,
|
|
(ULONGLONG)&guid,
|
|
(ULONGLONG)&wideAttr,
|
|
(ULONGLONG)&wideLength,
|
|
(ULONGLONG)valuePtr,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
|
|
valueLength = (ULONG)wideLength;
|
|
if ( attrPtr != NULL ) {
|
|
*attrPtr = (ULONG)wideAttr;
|
|
}
|
|
|
|
switch (efiStatus) {
|
|
case EFI_SUCCESS:
|
|
if ( filling ) {
|
|
nameAndValue->ValueLength = valueLength;
|
|
remainingLength -= valueLength;
|
|
if ( previousEntry != NULL ) {
|
|
previousEntry->NextEntryOffset = (ULONG)(currentPtr - (PUCHAR)previousEntry);
|
|
}
|
|
previousEntry = (PVARIABLE_NAME)currentPtr;
|
|
}
|
|
break;
|
|
case EFI_BUFFER_TOO_SMALL:
|
|
efiStatus = EFI_SUCCESS;
|
|
remainingLength = 0;
|
|
filling = FALSE;
|
|
ntStatus = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
default:
|
|
ntStatus = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
if ( efiStatus != EFI_SUCCESS ) {
|
|
break;
|
|
}
|
|
|
|
currentPtr += requiredLength + valueLength;
|
|
}
|
|
}
|
|
|
|
if ( previousEntry != NULL ) {
|
|
previousEntry->NextEntryOffset = 0;
|
|
}
|
|
|
|
*BufferLength = (ULONG)(currentPtr - (PUCHAR)Buffer);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
HalpGetPlatformId(
|
|
OUT PHAL_PLATFORM_ID PlatformId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function fills in the ANSI_STRING structures for the Vendor and Device IDs out
|
|
of the SalSystemTable.
|
|
|
|
Arguments:
|
|
|
|
PlatformId - Pointer to a structure with two ANSI_STRING structures for Vendor/DeviceIds
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if SalSystemTable available, otherwise STATUS_UNSUCCESSFUL
|
|
|
|
Assumptions:
|
|
|
|
The two strings in PlatformId will not be freed or modified, and are therefore pointing
|
|
directly to the SalSystemTable.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR i;
|
|
|
|
// Initialize the VendorId ANSI_STRING structure to point to SalSystemTable entry
|
|
// Note, both strings are either NULL terminated OR exactly 32-bytes in length and
|
|
// not NULL terminated.
|
|
|
|
if (!NT_SUCCESS(HalpSalPalData.Status)) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
i=0;;
|
|
while (HalpSalPalData.SalSystemTable->OemId[i] && i < OEM_ID_LENGTH) {
|
|
i++;
|
|
}
|
|
PlatformId->VendorId.Buffer = HalpSalPalData.SalSystemTable->OemId;
|
|
PlatformId->VendorId.Length = i;
|
|
PlatformId->VendorId.MaximumLength = i;
|
|
|
|
// Initialize the DeviceId ANSI_STRING structure to point to SalSystemTable entry
|
|
|
|
i=0;
|
|
while (HalpSalPalData.SalSystemTable->ProductId[i] && i < OEM_PRODUCT_ID_LENGTH) {
|
|
i++;
|
|
}
|
|
PlatformId->DeviceId.Buffer = HalpSalPalData.SalSystemTable->ProductId;
|
|
PlatformId->DeviceId.Length = i;
|
|
PlatformId->DeviceId.MaximumLength = i;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*****************************************************************
|
|
TEST CODE FOR THE SAL AND PAL:
|
|
|
|
These routines provide an infrastructure for supporting SAL and
|
|
PAL calls not supported by firmware, overriding there meaning
|
|
if SAL or PAL returns STATUS_NOT_IMPLEMENTED. The #define for
|
|
SAL_TEST and/or PAL_TEST must be defined for this behavior.
|
|
|
|
*****************************************************************/
|
|
ULONG
|
|
NoSalPCIRead(
|
|
IN ULONG Tok,
|
|
IN ULONG Size
|
|
)
|
|
{
|
|
ULONG Data;
|
|
ULONG i = Tok % sizeof(ULONG);
|
|
|
|
WRITE_PORT_ULONG((PULONG)0xcf8, 0x80000000 | Tok);
|
|
switch (Size) {
|
|
case 1: Data = READ_PORT_UCHAR((PUCHAR)(ULongToPtr(0xcfc + i) )); break;
|
|
case 2: Data = READ_PORT_USHORT((PUSHORT)(ULongToPtr(0xcfc + i) )); break;
|
|
case 4: Data = READ_PORT_ULONG((PULONG)(0xcfc)); break;
|
|
}
|
|
return(Data);
|
|
}
|
|
|
|
VOID
|
|
NoSalPCIWrite(
|
|
IN ULONG Tok,
|
|
IN ULONG Size,
|
|
IN ULONG Data
|
|
)
|
|
{
|
|
ULONG i = Tok % sizeof(ULONG);
|
|
|
|
WRITE_PORT_ULONG((PULONG)0xcf8, 0x80000000 | Tok);
|
|
switch (Size) {
|
|
case 1: WRITE_PORT_UCHAR((PUCHAR)(ULongToPtr(0xcfc + i) ), (UCHAR)Data); break;
|
|
case 2: WRITE_PORT_USHORT((PUSHORT)(ULongToPtr(0xcfc + i) ), (USHORT)Data); break;
|
|
case 4: WRITE_PORT_ULONG((PULONG)(0xcfc), Data); break;
|
|
}
|
|
}
|
|
|
|
|
|
#define PCIBUS(Tok) (((ULONG)(Tok) >> 16) & 0xff)
|
|
#define PCIDEV(Tok) (((ULONG)(Tok) >> 11) & 0x1f)
|
|
#define PCIFUNC(Tok) (((ULONG)(Tok) >> 8) & 0x7)
|
|
#define PCIOFF(Tok) (((ULONG)(Tok) >> 2) & 0x3f)
|
|
|
|
VOID
|
|
InternalTestSal(
|
|
IN LONGLONG FunctionId,
|
|
IN LONGLONG Arg1,
|
|
IN LONGLONG Arg2,
|
|
IN LONGLONG Arg3,
|
|
IN LONGLONG Arg4,
|
|
IN LONGLONG Arg5,
|
|
IN LONGLONG Arg6,
|
|
IN LONGLONG Arg7,
|
|
OUT PSAL_PAL_RETURN_VALUES ReturnValues
|
|
)
|
|
{
|
|
switch (FunctionId) {
|
|
|
|
case SAL_PCI_CONFIG_READ: {
|
|
ULONG Data;
|
|
HalDebugPrint(( HAL_INFO, "HAL: << SAL_PCI_CONFIG_READ - Bus: %d Dev: %2d Func: %d Off: %2d Size = %d ",
|
|
PCIBUS(Arg1), PCIDEV(Arg1), PCIFUNC(Arg1), PCIOFF(Arg1), Arg2 ));
|
|
ReturnValues->ReturnValues[0] = SAL_STATUS_SUCCESS;
|
|
ReturnValues->ReturnValues[1] = Data = NoSalPCIRead((ULONG)Arg1, (ULONG)Arg2);
|
|
HalDebugPrint(( HAL_INFO, " Data = 0x%08x\n", Data ));
|
|
break;
|
|
}
|
|
|
|
case SAL_PCI_CONFIG_WRITE:
|
|
HalDebugPrint(( HAL_INFO, "HAL: >> SAL_PCI_CONFIG_WRITE: Bus: %d Dev: %2d Func: %d Off: %2d Size = %d Val = 0x%08x\n",
|
|
PCIBUS(Arg1), PCIDEV(Arg1), PCIFUNC(Arg1), PCIOFF(Arg1), Arg2, Arg3 ));
|
|
NoSalPCIWrite((ULONG)Arg1, (ULONG)Arg2, (ULONG)Arg3);
|
|
ReturnValues->ReturnValues[0] = SAL_STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
ReturnValues->ReturnValues[0] = SAL_STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
InternalTestPal(
|
|
IN LONGLONG FunctionId,
|
|
IN LONGLONG Arg1,
|
|
IN LONGLONG Arg2,
|
|
IN LONGLONG Arg3,
|
|
OUT PSAL_PAL_RETURN_VALUES ReturnValues
|
|
)
|
|
{
|
|
|
|
switch (FunctionId) {
|
|
|
|
default:
|
|
ReturnValues->ReturnValues[0] = SAL_STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
}
|
|
|