1145 lines
30 KiB
C
1145 lines
30 KiB
C
|
||
/*++
|
||
|
||
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 (arad@fc.hp.com) 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 HalpPalProcPointer=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_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;
|
||
|
||
// Zero out the return buffer
|
||
|
||
RtlZeroMemory(ReturnValues,sizeof(SAL_PAL_RETURN_VALUES));
|
||
|
||
if (!NT_SUCCESS(HalpSalPalData.Status)) {
|
||
ReturnValues->ReturnValues[0] = SAL_STATUS_NOT_IMPLEMENTED;
|
||
return (ReturnValues->ReturnValues[0]);
|
||
}
|
||
fixLogId = HalpSalPalData.Flags & HALP_SALPAL_FIX_MCE_LOG_ID;
|
||
|
||
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 = HalpSalProc(FunctionId,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7);
|
||
KiReleaseSpinLock(&HalpSalSpinLock);
|
||
break;
|
||
|
||
case SAL_GET_STATE_INFO:
|
||
KiAcquireSpinLock(&HalpSalStateInfoSpinLock);
|
||
*ReturnValues = HalpSalProc(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 = HalpSalProc(FunctionId,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7);
|
||
KiReleaseSpinLock(&HalpSalStateInfoSpinLock);
|
||
break;
|
||
|
||
case SAL_PCI_CONFIG_READ:
|
||
case SAL_PCI_CONFIG_WRITE:
|
||
|
||
KiAcquireSpinLock(&HalpSalSpinLock);
|
||
*ReturnValues = HalpSalProc(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 = HalpSalProc(FunctionId,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7);
|
||
KiReleaseSpinLock(&HalpSalSpinLock);
|
||
}
|
||
else
|
||
*ReturnValues = HalpSalProc(FunctionId,Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7);
|
||
break;
|
||
|
||
//
|
||
// These SAL calls are MP-safe, but not re-entrant
|
||
//
|
||
|
||
case SAL_MC_RENDEZ:
|
||
*ReturnValues = HalpSalProc(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
|
||
|
||
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] ));
|
||
|
||
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)
|
||
|
||
--*/
|
||
{
|
||
KIRQL OldIrql;
|
||
|
||
|
||
// Zero out the return buffer
|
||
|
||
RtlZeroMemory(ReturnValues,sizeof(SAL_PAL_RETURN_VALUES));
|
||
|
||
if (!NT_SUCCESS(HalpSalPalData.Status)) {
|
||
ReturnValues->ReturnValues[0] = PAL_STATUS_NOT_IMPLEMENTED;
|
||
return (ReturnValues->ReturnValues[0]);
|
||
}
|
||
|
||
// Only allow PAL calls that are supported
|
||
|
||
switch (FunctionId) {
|
||
|
||
// Virtual mode PAL calls
|
||
|
||
case PAL_CACHE_FLUSH:
|
||
case PAL_CACHE_INFO:
|
||
case PAL_CACHE_INIT:
|
||
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:
|
||
case PAL_HALT_INFO:
|
||
case PAL_HALT_LIGHT:
|
||
case PAL_PREFETCH_VISIBILITY:
|
||
case PAL_SHUTDOWN:
|
||
case PAL_FREQ_RATIOS:
|
||
case PAL_VERSION:
|
||
|
||
// PAL is MP-safe, but not re-entrant, so just raise IRQL
|
||
|
||
KeRaiseIrql(SYNCH_LEVEL, &OldIrql);
|
||
*ReturnValues = HalpPalProc(FunctionId,Arg1,Arg2,Arg3);
|
||
KeLowerIrql(OldIrql);
|
||
break;
|
||
|
||
// Physical mode, static PAL calls
|
||
|
||
case PAL_MEM_ATTRIB:
|
||
case PAL_BUS_GET_FEATURES:
|
||
case PAL_BUS_SET_FEATURES:
|
||
case PAL_DEBUG_INFO:
|
||
case PAL_FIXED_ADDR:
|
||
case PAL_FREQ_BASE:
|
||
case PAL_PLATFORM_ADDR:
|
||
case PAL_PROC_GET_FEATURES:
|
||
case PAL_PROC_SET_FEATURES:
|
||
case PAL_REGISTER_INFO:
|
||
case PAL_RSE_INFO:
|
||
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, so just raise IRQL
|
||
|
||
KeRaiseIrql(SYNCH_LEVEL, &OldIrql);
|
||
*ReturnValues = HalpPalProcPhysicalStatic(FunctionId,Arg1,Arg2,Arg3);
|
||
KeLowerIrql(OldIrql);
|
||
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:
|
||
|
||
// PAL is MP-safe, but not re-entrant, so just raise IRQL
|
||
|
||
KeRaiseIrql(SYNCH_LEVEL, &OldIrql);
|
||
*ReturnValues = HalpPalProcPhysicalStacked(FunctionId,Arg1,Arg2,Arg3);
|
||
KeLowerIrql(OldIrql);
|
||
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
|
||
|
||
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] ));
|
||
|
||
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;
|
||
}
|
||
}
|
||
|