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.
1396 lines
39 KiB
1396 lines
39 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
pbiosc.c
|
|
|
|
Abstract:
|
|
|
|
This module contains Pnp BIOS dependent routines. It includes code to initialize
|
|
16 bit GDT selectors and to call pnp bios api.
|
|
|
|
Author:
|
|
|
|
Shie-Lin Tzong (shielint) 15-Jan-1998
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "pnpmgrp.h"
|
|
#include "pnpcvrt.h"
|
|
#include "pbios.h"
|
|
#include "..\..\ke\i386\abios.h"
|
|
|
|
//
|
|
// Functions for PNP_BIOS_ENUMERATION_CONTEXT
|
|
//
|
|
|
|
#define PI_SHUTDOWN_EXAMINE_BIOS_DEVICE 1
|
|
#define PI_SHUTDOWN_LEGACY_RESOURCES 2
|
|
|
|
typedef struct _PNP_BIOS_DEVICE_NODE_LIST {
|
|
struct _PNP_BIOS_DEVICE_NODE_LIST *Next;
|
|
PNP_BIOS_DEVICE_NODE DeviceNode;
|
|
} PNP_BIOS_DEVICE_NODE_LIST, *PPNP_BIOS_DEVICE_NODE_LIST;
|
|
|
|
typedef struct _PNP_BIOS_ENUMERATION_CONTEXT {
|
|
PUNICODE_STRING KeyName;
|
|
ULONG Function;
|
|
union {
|
|
struct {
|
|
PVOID BiosInfo;
|
|
ULONG BiosInfoLength;
|
|
PPNP_BIOS_DEVICE_NODE_LIST *DeviceList;
|
|
} ExamineBiosDevice;
|
|
struct {
|
|
PCM_RESOURCE_LIST LegacyResources;
|
|
} LegacyResources;
|
|
} u;
|
|
} PNP_BIOS_ENUMERATION_CONTEXT, *PPNP_BIOS_ENUMERATION_CONTEXT;
|
|
|
|
typedef struct _PNP_BIOS_SHUT_DOWN_CONTEXT {
|
|
PPNP_BIOS_DEVICE_NODE_LIST DeviceList;
|
|
PVOID Resources;
|
|
} PNP_BIOS_SHUT_DOWN_CONTEXT, *PPNP_BIOS_SHUT_DOWN_CONTEXT;
|
|
|
|
//
|
|
// A big structure for calling Pnp BIOS functions
|
|
//
|
|
|
|
#define PNP_BIOS_GET_NUMBER_DEVICE_NODES 0
|
|
#define PNP_BIOS_GET_DEVICE_NODE 1
|
|
#define PNP_BIOS_SET_DEVICE_NODE 2
|
|
#define PNP_BIOS_GET_EVENT 3
|
|
#define PNP_BIOS_SEND_MESSAGE 4
|
|
#define PNP_BIOS_GET_DOCK_INFORMATION 5
|
|
// Function 6 is reserved
|
|
#define PNP_BIOS_SELECT_BOOT_DEVICE 7
|
|
#define PNP_BIOS_GET_BOOT_DEVICE 8
|
|
#define PNP_BIOS_SET_OLD_ISA_RESOURCES 9
|
|
#define PNP_BIOS_GET_OLD_ISA_RESOURCES 0xA
|
|
#define PNP_BIOS_GET_ISA_CONFIGURATION 0x40
|
|
|
|
//
|
|
// Control Flags for Set_Device_node
|
|
//
|
|
|
|
#define SET_CONFIGURATION_NOW 1
|
|
#define SET_CONFIGURATION_FOR_NEXT_BOOT 2
|
|
|
|
typedef struct _PB_PARAMETERS {
|
|
USHORT Function;
|
|
union {
|
|
struct {
|
|
USHORT *NumberNodes;
|
|
USHORT *NodeSize;
|
|
} GetNumberDeviceNodes;
|
|
|
|
struct {
|
|
USHORT *Node;
|
|
PPNP_BIOS_DEVICE_NODE NodeBuffer;
|
|
USHORT Control;
|
|
} GetDeviceNode;
|
|
|
|
struct {
|
|
USHORT Node;
|
|
PPNP_BIOS_DEVICE_NODE NodeBuffer;
|
|
USHORT Control;
|
|
} SetDeviceNode;
|
|
|
|
struct {
|
|
USHORT *Message;
|
|
} GetEvent;
|
|
|
|
struct {
|
|
USHORT Message;
|
|
} SendMessage;
|
|
|
|
struct {
|
|
PVOID Resources;
|
|
} SetAllocatedResources;
|
|
} u;
|
|
} PB_PARAMETERS, *PPB_PARAMETERS;
|
|
|
|
#define PB_MAXIMUM_STACK_SIZE (sizeof(PB_PARAMETERS) + sizeof(USHORT) * 2)
|
|
|
|
//
|
|
// Status should be checked before calling PnP BIOS.
|
|
// = STATUS_SUCCESS, can call PnP BIOS
|
|
// = STATUS_NOT_SUPPORTED, dont call PnP BIOS
|
|
// = STATUS_UNSUCCESSFUL, failed initialization, dont call PnP BIOS
|
|
// = STATUS_REINITIALIZATION_NEEDED, try to initialize, call PnP BIOS only if successful.
|
|
//
|
|
|
|
NTSTATUS PbBiosInitialized = STATUS_REINITIALIZATION_NEEDED;
|
|
|
|
//
|
|
// PbBiosCodeSelector contains the selector of the PNP
|
|
// BIOS code.
|
|
//
|
|
|
|
USHORT PbBiosCodeSelector;
|
|
|
|
//
|
|
// PbBiosDataSelector contains the selector of the PNP
|
|
// BIOS data area (F0000-FFFFF)
|
|
//
|
|
|
|
USHORT PbBiosDataSelector;
|
|
|
|
//
|
|
// PbSelectors[] contains general purpose preallocated selectors
|
|
//
|
|
|
|
USHORT PbSelectors[2];
|
|
|
|
//
|
|
// PbBiosEntryPoint contains the Pnp Bios entry offset
|
|
//
|
|
|
|
ULONG PbBiosEntryPoint;
|
|
|
|
//
|
|
// SpinLock to serialize Pnp Bios call
|
|
//
|
|
|
|
KSPIN_LOCK PbBiosSpinlock;
|
|
|
|
//
|
|
// PiShutdownContext
|
|
//
|
|
|
|
PNP_BIOS_SHUT_DOWN_CONTEXT PiShutdownContext;
|
|
|
|
//
|
|
// External References
|
|
//
|
|
|
|
extern
|
|
USHORT
|
|
PbCallPnpBiosWorker (
|
|
IN ULONG EntryOffset,
|
|
IN ULONG EntrySelector,
|
|
IN PUSHORT Parameters,
|
|
IN USHORT Size
|
|
);
|
|
|
|
//
|
|
// Internal prototypes
|
|
//
|
|
|
|
VOID
|
|
PnPBiosCollectLegacyDeviceResources (
|
|
IN PCM_RESOURCE_LIST *ReturnedResources
|
|
);
|
|
|
|
VOID
|
|
PnPBiosReserveLegacyDeviceResources (
|
|
IN PUCHAR BiosResources
|
|
);
|
|
|
|
NTSTATUS
|
|
PnPBiosExamineDeviceKeys (
|
|
IN PVOID BiosInfo,
|
|
IN ULONG BiosInfoLength,
|
|
IN OUT PPNP_BIOS_DEVICE_NODE_LIST *DeviceList
|
|
);
|
|
|
|
BOOLEAN
|
|
PnPBiosExamineBiosDeviceKey(
|
|
IN HANDLE KeyHandle,
|
|
IN PUNICODE_STRING KeyName,
|
|
IN OUT PPNP_BIOS_ENUMERATION_CONTEXT Context
|
|
);
|
|
|
|
BOOLEAN
|
|
PnPBiosExamineBiosDeviceInstanceKey(
|
|
IN HANDLE KeyHandle,
|
|
IN PUNICODE_STRING KeyName,
|
|
IN OUT PPNP_BIOS_ENUMERATION_CONTEXT Context
|
|
);
|
|
|
|
NTSTATUS
|
|
PnPBiosExtractInfo(
|
|
IN ULONG BiosHandle,
|
|
IN PVOID BiosInfo,
|
|
IN ULONG BiosInfoLength,
|
|
OUT PVOID *Header,
|
|
OUT ULONG *HeaderLength,
|
|
OUT PVOID *Tail,
|
|
OUT ULONG *TailLength
|
|
);
|
|
|
|
VOID
|
|
PnPBiosSetDeviceNodes (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
PbHardwareService (
|
|
IN PPB_PARAMETERS Parameters
|
|
);
|
|
|
|
VOID
|
|
PbAddress32ToAddress16 (
|
|
IN PVOID Address32,
|
|
IN PUSHORT Address16,
|
|
IN USHORT Selector
|
|
);
|
|
|
|
BOOLEAN
|
|
PnPBiosGetBiosHandleFromDeviceKey(
|
|
IN HANDLE KeyHandle,
|
|
OUT PULONG BiosDeviceId
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, PnPBiosGetBiosHandleFromDeviceKey)
|
|
#pragma alloc_text(PAGE, PnPBiosCollectLegacyDeviceResources)
|
|
#pragma alloc_text(PAGE, PnPBiosExamineDeviceKeys)
|
|
#pragma alloc_text(PAGE, PnPBiosExamineBiosDeviceKey)
|
|
#pragma alloc_text(PAGE, PnPBiosExamineBiosDeviceInstanceKey)
|
|
#pragma alloc_text(PAGE, PnPBiosExtractInfo)
|
|
#pragma alloc_text(PAGE, PnPBiosInitializePnPBios)
|
|
#pragma alloc_text(PAGELK, PbAddress32ToAddress16)
|
|
#pragma alloc_text(PAGELK, PnPBiosSetDeviceNodes)
|
|
#pragma alloc_text(PAGELK, PnPBiosReserveLegacyDeviceResources)
|
|
#pragma alloc_text(PAGELK, PbHardwareService)
|
|
#pragma alloc_text(PAGELK, PnPBiosShutdownSystem)
|
|
#endif
|
|
|
|
VOID
|
|
PnPBiosShutdownSystem (
|
|
IN ULONG Phase,
|
|
IN OUT PVOID *Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the Pnp shutdowm preparation.
|
|
At phase 0, it prepares the data for the Pnp bios devices whose states needed to be
|
|
updated to pnp bios.
|
|
At phase 1, we write the data to pnp bios.
|
|
|
|
Arguments:
|
|
|
|
Phase - specifies the shutdown phase.
|
|
|
|
Context - at phase 0, it supplies a variable to receive the returned context info.
|
|
at phase 1, it supplies a variable to specify the context info.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PVOID biosInfo;
|
|
ULONG length, codeBase;
|
|
NTSTATUS status;
|
|
PPNP_BIOS_DEVICE_NODE_LIST pnpBiosDeviceNode;
|
|
PCM_RESOURCE_LIST legacyResources;
|
|
PUCHAR biosResources;
|
|
PHYSICAL_ADDRESS physicalAddr;
|
|
PVOID virtualAddr;
|
|
KGDTENTRY gdtEntry;
|
|
|
|
ASSERT(!PpDisableFirmwareMapper);
|
|
if (PpDisableFirmwareMapper) {
|
|
|
|
return;
|
|
}
|
|
if (Phase == 0) {
|
|
|
|
*Context = NULL;
|
|
|
|
status = PnPBiosGetBiosInfo(&biosInfo, &length);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
if (PbBiosInitialized == STATUS_REINITIALIZATION_NEEDED) {
|
|
|
|
PbBiosInitialized = STATUS_UNSUCCESSFUL;
|
|
PbBiosEntryPoint = (ULONG)
|
|
((PPNP_BIOS_INSTALLATION_CHECK)biosInfo)->ProtectedModeEntryOffset;
|
|
//
|
|
// Initialize selectors to use PNP bios code
|
|
//
|
|
gdtEntry.LimitLow = 0xFFFF;
|
|
gdtEntry.HighWord.Bytes.Flags1 = 0;
|
|
gdtEntry.HighWord.Bytes.Flags2 = 0;
|
|
gdtEntry.HighWord.Bits.Pres = 1;
|
|
gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM;
|
|
gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE;
|
|
gdtEntry.HighWord.Bits.Type = 31;
|
|
gdtEntry.HighWord.Bits.Default_Big = 0;
|
|
|
|
physicalAddr.HighPart = 0;
|
|
physicalAddr.LowPart =
|
|
((PPNP_BIOS_INSTALLATION_CHECK)biosInfo)->ProtectedModeCodeBaseAddress;
|
|
virtualAddr = MmMapIoSpace (physicalAddr, 0x10000, TRUE);
|
|
if (virtualAddr) {
|
|
|
|
codeBase = (ULONG)virtualAddr;
|
|
|
|
gdtEntry.BaseLow = (USHORT) (codeBase & 0xffff);
|
|
gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (codeBase >> 16) & 0xff;
|
|
gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (codeBase >> 24) & 0xff;
|
|
|
|
KeI386SetGdtSelector (PbBiosCodeSelector, &gdtEntry);
|
|
//
|
|
// initialize 16 bit data selector for Pnp BIOS
|
|
//
|
|
gdtEntry.LimitLow = 0xFFFF;
|
|
gdtEntry.HighWord.Bytes.Flags1 = 0;
|
|
gdtEntry.HighWord.Bytes.Flags2 = 0;
|
|
gdtEntry.HighWord.Bits.Pres = 1;
|
|
gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM;
|
|
gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE;
|
|
gdtEntry.HighWord.Bits.Type = 19;
|
|
gdtEntry.HighWord.Bits.Default_Big = 1;
|
|
|
|
physicalAddr.LowPart =
|
|
((PPNP_BIOS_INSTALLATION_CHECK)biosInfo)->ProtectedModeDataBaseAddress;
|
|
virtualAddr = MmMapIoSpace (physicalAddr, 0x10000, TRUE);
|
|
if (virtualAddr) {
|
|
|
|
codeBase = (ULONG)virtualAddr;
|
|
|
|
gdtEntry.BaseLow = (USHORT)(codeBase & 0xffff);
|
|
gdtEntry.HighWord.Bits.BaseMid = (UCHAR)(codeBase >> 16) & 0xff;
|
|
gdtEntry.HighWord.Bits.BaseHi = (UCHAR)(codeBase >> 24) & 0xff;
|
|
|
|
KeI386SetGdtSelector (PbBiosDataSelector, &gdtEntry);
|
|
//
|
|
// Initialize the other two general purpose data selector such that
|
|
// on subsequent init we only need to init the base addr.
|
|
//
|
|
KeI386SetGdtSelector (PbSelectors[0], &gdtEntry);
|
|
KeI386SetGdtSelector (PbSelectors[1], &gdtEntry);
|
|
|
|
PbBiosInitialized = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
PnPBiosExamineDeviceKeys(
|
|
biosInfo,
|
|
length,
|
|
(PPNP_BIOS_DEVICE_NODE_LIST *) &PiShutdownContext.DeviceList
|
|
);
|
|
PnPBiosCollectLegacyDeviceResources (&legacyResources);
|
|
if (legacyResources) {
|
|
status = PpCmResourcesToBiosResources (legacyResources, NULL, &biosResources, &length);
|
|
if (NT_SUCCESS(status) && biosResources) {
|
|
PiShutdownContext.Resources = (PCM_RESOURCE_LIST)ExAllocatePool(NonPagedPool, length);
|
|
if (PiShutdownContext.Resources) {
|
|
RtlMoveMemory(PiShutdownContext.Resources, biosResources, length);
|
|
}
|
|
ExFreePool(biosResources);
|
|
}
|
|
ExFreePool(legacyResources);
|
|
}
|
|
if (PiShutdownContext.DeviceList || PiShutdownContext.Resources) {
|
|
*Context = &PiShutdownContext;
|
|
}
|
|
ExFreePool(biosInfo);
|
|
}
|
|
|
|
return;
|
|
|
|
} else if (*Context) {
|
|
//
|
|
// Phase 1: Everything below should be PAGELK or NonPaged
|
|
//
|
|
ASSERT(*Context == &PiShutdownContext);
|
|
pnpBiosDeviceNode = PiShutdownContext.DeviceList;
|
|
biosResources = PiShutdownContext.Resources;
|
|
if (pnpBiosDeviceNode || biosResources) {
|
|
|
|
//
|
|
// Call pnp bios from boot processor
|
|
//
|
|
|
|
KeSetSystemAffinityThread(1);
|
|
|
|
if (pnpBiosDeviceNode) {
|
|
PnPBiosSetDeviceNodes(pnpBiosDeviceNode);
|
|
}
|
|
if (biosResources) {
|
|
PnPBiosReserveLegacyDeviceResources(biosResources);
|
|
}
|
|
|
|
//
|
|
// Restore old affinity for current thread.
|
|
//
|
|
|
|
KeRevertToUserAffinityThread();
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
PnPBiosGetBiosHandleFromDeviceKey(
|
|
IN HANDLE KeyHandle,
|
|
OUT PULONG BiosDeviceId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes a handle to System\Enum\Root\<Device Instance> and sets
|
|
BiosDeviceId to the PNPBIOS ID of the device.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - handle to System\Enum\Root\<Device Instance>
|
|
|
|
BiosDeviceId - After this function is ran, this value will be filled with
|
|
the ID assigned to the device by PNPBIOS.
|
|
|
|
Return Value:
|
|
|
|
FALSE if the handle does not refer to a PNPBIOS device.
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING unicodeName;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|
NTSTATUS status;
|
|
HANDLE handle;
|
|
ULONG biosDeviceHandle = ~0ul;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Make sure this is a pnp bios device by checking its pnp bios device
|
|
// handle.
|
|
//
|
|
PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_CONTROL);
|
|
status = IopOpenRegistryKeyEx( &handle,
|
|
KeyHandle,
|
|
&unicodeName,
|
|
KEY_READ
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return FALSE ;
|
|
}
|
|
|
|
status = IopGetRegistryValue (handle,
|
|
L"PnpBiosDeviceHandle",
|
|
&keyValueInformation);
|
|
ZwClose(handle);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
if ((keyValueInformation->Type == REG_DWORD) &&
|
|
(keyValueInformation->DataLength == sizeof(ULONG))) {
|
|
|
|
biosDeviceHandle = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
}
|
|
if (biosDeviceHandle > 0xffff) {
|
|
return FALSE;
|
|
}
|
|
*BiosDeviceId = biosDeviceHandle ;
|
|
return TRUE ;
|
|
}
|
|
|
|
VOID
|
|
PnPBiosCollectLegacyDeviceResources (
|
|
IN PCM_RESOURCE_LIST *ReturnedResources
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
ReturnedResources - supplies a pointer to a variable to receive legacy resources.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE baseHandle;
|
|
PNP_BIOS_ENUMERATION_CONTEXT context;
|
|
PVOID buffer;
|
|
UNICODE_STRING workName, tmpName;
|
|
|
|
PAGED_CODE();
|
|
|
|
*ReturnedResources = NULL;
|
|
|
|
buffer = ExAllocatePool(PagedPool, PNP_LARGE_SCRATCH_BUFFER_SIZE);
|
|
if (!buffer) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Open System\CurrentControlSet\Enum\Root key and call worker routine to recursively
|
|
// scan through the subkeys.
|
|
//
|
|
|
|
status = IopCreateRegistryKeyEx( &baseHandle,
|
|
NULL,
|
|
&CmRegistryMachineSystemCurrentControlSetEnumRootName,
|
|
KEY_READ,
|
|
REG_OPTION_NON_VOLATILE,
|
|
NULL
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
workName.Buffer = (PWSTR)buffer;
|
|
RtlFillMemory(buffer, PNP_LARGE_SCRATCH_BUFFER_SIZE, 0);
|
|
workName.MaximumLength = PNP_LARGE_SCRATCH_BUFFER_SIZE;
|
|
workName.Length = 0;
|
|
PiWstrToUnicodeString(&tmpName, REGSTR_KEY_ROOTENUM);
|
|
RtlAppendStringToString((PSTRING)&workName, (PSTRING)&tmpName);
|
|
|
|
//
|
|
// Enumerate all subkeys under the System\CCS\Enum\Root.
|
|
//
|
|
|
|
context.KeyName = &workName;
|
|
context.Function = PI_SHUTDOWN_LEGACY_RESOURCES;
|
|
context.u.LegacyResources.LegacyResources = NULL;
|
|
status = PipApplyFunctionToSubKeys(baseHandle,
|
|
NULL,
|
|
KEY_READ,
|
|
FUNCTIONSUBKEY_FLAG_IGNORE_NON_CRITICAL_ERRORS,
|
|
PnPBiosExamineBiosDeviceKey,
|
|
&context
|
|
);
|
|
ZwClose(baseHandle);
|
|
*ReturnedResources = context.u.LegacyResources.LegacyResources;
|
|
}
|
|
ExFreePool(buffer);
|
|
}
|
|
|
|
NTSTATUS
|
|
PnPBiosExamineDeviceKeys (
|
|
IN PVOID BiosInfo,
|
|
IN ULONG BiosInfoLength,
|
|
IN OUT PPNP_BIOS_DEVICE_NODE_LIST *DeviceList
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine scans through System\Enum\Root subtree to build a device node for
|
|
each root device.
|
|
|
|
Arguments:
|
|
|
|
DeviceRelations - supplies a variable to receive the returned DEVICE_RELATIONS structure.
|
|
|
|
Return Value:
|
|
|
|
A NTSTATUS code.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE baseHandle;
|
|
PNP_BIOS_ENUMERATION_CONTEXT context;
|
|
PVOID buffer;
|
|
UNICODE_STRING workName, tmpName;
|
|
|
|
PAGED_CODE();
|
|
|
|
buffer = ExAllocatePool(PagedPool, PNP_LARGE_SCRATCH_BUFFER_SIZE);
|
|
if (!buffer) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
//
|
|
// Open System\CurrentControlSet\Enum\Root key and call worker routine to recursively
|
|
// scan through the subkeys.
|
|
//
|
|
|
|
status = IopCreateRegistryKeyEx( &baseHandle,
|
|
NULL,
|
|
&CmRegistryMachineSystemCurrentControlSetEnumRootName,
|
|
KEY_READ,
|
|
REG_OPTION_NON_VOLATILE,
|
|
NULL
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
workName.Buffer = (PWSTR)buffer;
|
|
RtlFillMemory(buffer, PNP_LARGE_SCRATCH_BUFFER_SIZE, 0);
|
|
workName.MaximumLength = PNP_LARGE_SCRATCH_BUFFER_SIZE;
|
|
workName.Length = 0;
|
|
PiWstrToUnicodeString(&tmpName, REGSTR_KEY_ROOTENUM);
|
|
RtlAppendStringToString((PSTRING)&workName, (PSTRING)&tmpName);
|
|
|
|
//
|
|
// Enumerate all subkeys under the System\CCS\Enum\Root.
|
|
//
|
|
|
|
context.KeyName = &workName;
|
|
context.Function = PI_SHUTDOWN_EXAMINE_BIOS_DEVICE;
|
|
context.u.ExamineBiosDevice.BiosInfo = BiosInfo;
|
|
context.u.ExamineBiosDevice.BiosInfoLength = BiosInfoLength;
|
|
context.u.ExamineBiosDevice.DeviceList = DeviceList;
|
|
|
|
status = PipApplyFunctionToSubKeys(baseHandle,
|
|
NULL,
|
|
KEY_READ,
|
|
FUNCTIONSUBKEY_FLAG_IGNORE_NON_CRITICAL_ERRORS,
|
|
PnPBiosExamineBiosDeviceKey,
|
|
&context
|
|
);
|
|
ZwClose(baseHandle);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
BOOLEAN
|
|
PnPBiosExamineBiosDeviceKey(
|
|
IN HANDLE KeyHandle,
|
|
IN PUNICODE_STRING KeyName,
|
|
IN OUT PPNP_BIOS_ENUMERATION_CONTEXT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a callback function for PipApplyFunctionToSubKeys.
|
|
It is called for each subkey under HKLM\System\CCS\Enum\BusKey.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Supplies a handle to this key.
|
|
|
|
KeyName - Supplies the name of this key.
|
|
|
|
Context - points to the ROOT_ENUMERATOR_CONTEXT structure.
|
|
|
|
Returns:
|
|
|
|
TRUE to continue the enumeration.
|
|
FALSE to abort it.
|
|
|
|
--*/
|
|
{
|
|
USHORT length;
|
|
PWSTR p;
|
|
PUNICODE_STRING unicodeName;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Context->Function != PI_SHUTDOWN_EXAMINE_BIOS_DEVICE ||
|
|
KeyName->Buffer[0] == L'*') {
|
|
|
|
unicodeName = ((PPNP_BIOS_ENUMERATION_CONTEXT)Context)->KeyName;
|
|
length = unicodeName->Length;
|
|
|
|
p = unicodeName->Buffer;
|
|
if ( unicodeName->Length / sizeof(WCHAR) != 0) {
|
|
p += unicodeName->Length / sizeof(WCHAR);
|
|
*p = OBJ_NAME_PATH_SEPARATOR;
|
|
unicodeName->Length += sizeof (WCHAR);
|
|
}
|
|
|
|
RtlAppendStringToString((PSTRING)unicodeName, (PSTRING)KeyName);
|
|
|
|
//
|
|
// Enumerate all subkeys under the current device key.
|
|
//
|
|
|
|
PipApplyFunctionToSubKeys(KeyHandle,
|
|
NULL,
|
|
KEY_ALL_ACCESS,
|
|
FUNCTIONSUBKEY_FLAG_IGNORE_NON_CRITICAL_ERRORS,
|
|
PnPBiosExamineBiosDeviceInstanceKey,
|
|
Context
|
|
);
|
|
unicodeName->Length = length;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
PnPBiosExamineBiosDeviceInstanceKey(
|
|
IN HANDLE KeyHandle,
|
|
IN PUNICODE_STRING KeyName,
|
|
IN OUT PPNP_BIOS_ENUMERATION_CONTEXT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a callback function for PipApplyFunctionToSubKeys.
|
|
It is called for each subkey under HKLM\System\Enum\Root\DeviceKey.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Supplies a handle to this key.
|
|
|
|
KeyName - Supplies the name of this key.
|
|
|
|
Context - points to the ROOT_ENUMERATOR_CONTEXT structure.
|
|
|
|
Returns:
|
|
|
|
TRUE to continue the enumeration.
|
|
FALSE to abort it.
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING unicodeName;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|
NTSTATUS status;
|
|
HANDLE handle;
|
|
ULONG biosDeviceHandle = ~0ul;
|
|
PCM_RESOURCE_LIST config = NULL;
|
|
ULONG length, totalLength;
|
|
PPNP_BIOS_DEVICE_NODE_LIST deviceNode;
|
|
PUCHAR p;
|
|
PVOID header, tail;
|
|
ULONG headerLength, tailLength ;
|
|
PUCHAR biosResources;
|
|
BOOLEAN isEnabled ;
|
|
|
|
UNREFERENCED_PARAMETER( KeyName );
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Context->Function == PI_SHUTDOWN_LEGACY_RESOURCES) {
|
|
ULONG tmp = 0;
|
|
|
|
//
|
|
// Skip any firmware identified device.
|
|
//
|
|
|
|
status = IopGetRegistryValue (KeyHandle,
|
|
L"FirmwareIdentified",
|
|
&keyValueInformation);
|
|
if (NT_SUCCESS(status)) {
|
|
if ((keyValueInformation->Type == REG_DWORD) &&
|
|
(keyValueInformation->DataLength == sizeof(ULONG))) {
|
|
|
|
tmp = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|
}
|
|
ExFreePool(keyValueInformation);
|
|
}
|
|
if (tmp != 0) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Skip any IoReportDetectedDevice and virtual/madeup device.
|
|
//
|
|
|
|
status = IopGetRegistryValue (KeyHandle,
|
|
L"Legacy",
|
|
&keyValueInformation);
|
|
if (NT_SUCCESS(status)) {
|
|
ExFreePool(keyValueInformation);
|
|
}
|
|
if (status != STATUS_OBJECT_NAME_NOT_FOUND) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Process it.
|
|
// Check if the device has BOOT config
|
|
//
|
|
|
|
PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
|
|
status = IopOpenRegistryKeyEx( &handle,
|
|
KeyHandle,
|
|
&unicodeName,
|
|
KEY_READ
|
|
);
|
|
if (NT_SUCCESS(status)) {
|
|
status = PipReadDeviceConfiguration (
|
|
handle,
|
|
REGISTRY_BOOT_CONFIG,
|
|
&config,
|
|
&length);
|
|
ZwClose(handle);
|
|
if (NT_SUCCESS(status) && config && length != 0) {
|
|
PCM_RESOURCE_LIST list;
|
|
|
|
list = Context->u.LegacyResources.LegacyResources;
|
|
status = IopMergeCmResourceLists(list, config, &Context->u.LegacyResources.LegacyResources);
|
|
if (NT_SUCCESS(status) && list) {
|
|
ExFreePool(list);
|
|
}
|
|
ExFreePool(config);
|
|
}
|
|
}
|
|
} else if (Context->Function == PI_SHUTDOWN_EXAMINE_BIOS_DEVICE) {
|
|
//
|
|
// First check if this key was created by firmware mapper. If yes, make sure
|
|
// the device is still present.
|
|
//
|
|
|
|
if (PipIsFirmwareMapperDevicePresent(KeyHandle) == FALSE) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Make sure this is a pnp bios device by checking its pnp bios
|
|
// device handle.
|
|
//
|
|
if (!PnPBiosGetBiosHandleFromDeviceKey(KeyHandle, &biosDeviceHandle)) {
|
|
return TRUE ;
|
|
}
|
|
|
|
//
|
|
// Get pointers to the header and tail.
|
|
//
|
|
// Gross hack warning -
|
|
// In the disable case, we need a bios resource template to whack
|
|
// to "off". We will index into header to do this, as header and tail
|
|
// point directly into the BIOS resource list!
|
|
//
|
|
status = PnPBiosExtractInfo (
|
|
biosDeviceHandle,
|
|
Context->u.ExamineBiosDevice.BiosInfo,
|
|
Context->u.ExamineBiosDevice.BiosInfoLength,
|
|
&header,
|
|
&headerLength,
|
|
&tail,
|
|
&tailLength
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Has this PnPBIOS device been disabled?
|
|
//
|
|
// N.B. This check examines flags for the current profile. We actually
|
|
// have no clue what profile we will next be booting into, so the UI
|
|
// should not show disable in current profile for PnPBIOS devices. A
|
|
// work item yet to be done...
|
|
//
|
|
isEnabled = IopIsDeviceInstanceEnabled(KeyHandle, Context->KeyName, FALSE) ;
|
|
|
|
if (!isEnabled) {
|
|
|
|
//
|
|
// This device is being disabled. Set up and attain a pointer to
|
|
// the appropriately built BIOS resource list.
|
|
//
|
|
biosResources = ((PUCHAR)header) + sizeof(PNP_BIOS_DEVICE_NODE) ;
|
|
PpBiosResourcesSetToDisabled (biosResources, &length);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Check if the pnp bios device has any assigned ForcedConfig
|
|
//
|
|
PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
|
|
status = IopOpenRegistryKeyEx( &handle,
|
|
KeyHandle,
|
|
&unicodeName,
|
|
KEY_READ
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
return TRUE ;
|
|
}
|
|
|
|
status = PipReadDeviceConfiguration (
|
|
handle,
|
|
REGISTRY_FORCED_CONFIG,
|
|
&config,
|
|
&length
|
|
);
|
|
|
|
ZwClose(handle);
|
|
if ((!NT_SUCCESS(status)) || (!config) || (length == 0)) {
|
|
return TRUE ;
|
|
}
|
|
|
|
status = PpCmResourcesToBiosResources (
|
|
config,
|
|
tail,
|
|
&biosResources,
|
|
&length
|
|
);
|
|
ExFreePool(config);
|
|
if (!NT_SUCCESS(status) || !biosResources) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate PNP_BIOS_DEVICE_NODE_LIST structure
|
|
//
|
|
|
|
totalLength = headerLength + length + tailLength;
|
|
deviceNode = ExAllocatePool(NonPagedPool, totalLength + sizeof(PVOID));
|
|
if (deviceNode) {
|
|
deviceNode->Next = *(Context->u.ExamineBiosDevice.DeviceList);
|
|
*(Context->u.ExamineBiosDevice.DeviceList) = deviceNode;
|
|
p = (PUCHAR)&deviceNode->DeviceNode;
|
|
RtlCopyMemory(p, header, headerLength);
|
|
p += headerLength;
|
|
RtlCopyMemory(p, biosResources, length);
|
|
p += length;
|
|
RtlCopyMemory(p, tail, tailLength);
|
|
deviceNode->DeviceNode.Size = (USHORT)totalLength;
|
|
}
|
|
|
|
if (isEnabled) {
|
|
ExFreePool(biosResources);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
NTSTATUS
|
|
PnPBiosExtractInfo(
|
|
IN ULONG BiosHandle,
|
|
IN PVOID BiosInfo,
|
|
IN ULONG BiosInfoLength,
|
|
OUT PVOID *Header,
|
|
OUT ULONG *HeaderLength,
|
|
OUT PVOID *Tail,
|
|
OUT ULONG *TailLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine extracts desired information for the specified bios device.
|
|
|
|
Arguments:
|
|
|
|
BiosHandle - specifies the bios device.
|
|
|
|
BiosInfo - The PnP BIOS Installation Check Structure followed by the
|
|
DevNode Structures reported by the BIOS. The detailed format is
|
|
documented in the PnP BIOS spec.
|
|
|
|
BiosInfoLength - Length in bytes of the block whose address is stored in
|
|
BiosInfo.
|
|
|
|
Header - specifies a variable to receive the beginning address of the bios
|
|
device node structure.
|
|
|
|
HeaderLength - specifies a variable to receive the length of the bios device
|
|
node header.
|
|
|
|
Tail - specifies a variable to receive the address of the bios device node's
|
|
PossibleResourceBlock.
|
|
|
|
TailLength - specifies a variable to receive the size of the tail.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if no errors, otherwise the appropriate error.
|
|
|
|
--*/
|
|
{
|
|
PCM_PNP_BIOS_INSTALLATION_CHECK biosInstallCheck;
|
|
PCM_PNP_BIOS_DEVICE_NODE devNodeHeader;
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
PUCHAR currentPtr;
|
|
int lengthRemaining;
|
|
int remainingNodeLength;
|
|
int numNodes;
|
|
PUCHAR configPtr;
|
|
|
|
PAGED_CODE();
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// Make sure the data is at least large enough to hold the BIOS Installation
|
|
// Check structure and check that the PnP signature is correct.
|
|
//
|
|
|
|
if (BiosInfoLength < sizeof(CM_PNP_BIOS_INSTALLATION_CHECK)) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
#endif
|
|
|
|
biosInstallCheck = (PCM_PNP_BIOS_INSTALLATION_CHECK)BiosInfo;
|
|
|
|
#if DBG
|
|
|
|
if (biosInstallCheck->Signature[0] != '$' ||
|
|
biosInstallCheck->Signature[1] != 'P' ||
|
|
biosInstallCheck->Signature[2] != 'n' ||
|
|
biosInstallCheck->Signature[3] != 'P') {
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
#endif
|
|
|
|
currentPtr = (PUCHAR)BiosInfo + biosInstallCheck->Length;
|
|
lengthRemaining = BiosInfoLength - biosInstallCheck->Length;
|
|
|
|
for (numNodes = 0; lengthRemaining > sizeof(CM_PNP_BIOS_DEVICE_NODE); numNodes++) {
|
|
|
|
devNodeHeader = (PCM_PNP_BIOS_DEVICE_NODE)currentPtr;
|
|
|
|
if (devNodeHeader->Size > lengthRemaining) {
|
|
IopDbgPrint((IOP_PNPBIOS_WARNING_LEVEL,
|
|
"Node # %d, invalid size (%d), length remaining (%d)\n",
|
|
devNodeHeader->Node,
|
|
devNodeHeader->Size,
|
|
lengthRemaining));
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (devNodeHeader->Node == BiosHandle) {
|
|
*Header = devNodeHeader;
|
|
*HeaderLength = sizeof(CM_PNP_BIOS_DEVICE_NODE);
|
|
|
|
configPtr = currentPtr + sizeof(*devNodeHeader);
|
|
remainingNodeLength = devNodeHeader->Size - sizeof(*devNodeHeader) - 1;
|
|
while (*configPtr != TAG_COMPLETE_END && remainingNodeLength) {
|
|
configPtr++;
|
|
remainingNodeLength--;
|
|
}
|
|
if (*configPtr == TAG_COMPLETE_END && remainingNodeLength) {
|
|
configPtr += 2;
|
|
remainingNodeLength--;
|
|
}
|
|
*Tail = configPtr;
|
|
*TailLength = remainingNodeLength;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
currentPtr += devNodeHeader->Size;
|
|
lengthRemaining -= devNodeHeader->Size;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PnPBiosInitializePnPBios (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine setup selectors to invoke Pnp BIOS.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
A NTSTATUS code to indicate the result of the initialization.
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
NTSTATUS status;
|
|
USHORT selectors[4];
|
|
|
|
PAGED_CODE();
|
|
//
|
|
// Check if we even need to initialize support for PnP BIOS.
|
|
//
|
|
ASSERT(!PpDisableFirmwareMapper);
|
|
if (PpDisableFirmwareMapper) {
|
|
|
|
PbBiosInitialized = STATUS_NOT_SUPPORTED;
|
|
return PbBiosInitialized;
|
|
}
|
|
//
|
|
// Initialize BIOS call spinlock
|
|
//
|
|
KeInitializeSpinLock (&PbBiosSpinlock);
|
|
|
|
//
|
|
// Call pnp bios from boot processor
|
|
//
|
|
KeSetSystemAffinityThread(1);
|
|
|
|
//
|
|
// Initialize stack segment
|
|
//
|
|
KiStack16GdtEntry = KiAbiosGetGdt() + KGDT_STACK16;
|
|
|
|
KiInitializeAbiosGdtEntry(
|
|
(PKGDTENTRY)KiStack16GdtEntry,
|
|
0L,
|
|
0xffff,
|
|
TYPE_DATA
|
|
);
|
|
|
|
//
|
|
// Allocate 4 selectors for calling PnP Bios APIs.
|
|
//
|
|
|
|
i = 4;
|
|
status = KeI386AllocateGdtSelectors (selectors, (USHORT) i);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
PbBiosCodeSelector = selectors[0];
|
|
PbBiosDataSelector = selectors[1];
|
|
PbSelectors[0] = selectors[2];
|
|
PbSelectors[1] = selectors[3];
|
|
|
|
PbBiosInitialized = STATUS_REINITIALIZATION_NEEDED;
|
|
} else {
|
|
|
|
PbBiosInitialized = STATUS_UNSUCCESSFUL;
|
|
IopDbgPrint((IOP_PNPBIOS_WARNING_LEVEL,
|
|
"PnpBios: Failed to allocate selectors to call PnP BIOS at shutdown.\n"));
|
|
}
|
|
|
|
KeRevertToUserAffinityThread();
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
PnPBiosSetDeviceNodes (
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the caller specified resource to pnp bios slot/device
|
|
data.
|
|
|
|
Arguments:
|
|
|
|
Context - specifies a list of Pnp bios device to be set.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code
|
|
|
|
--*/
|
|
{
|
|
PB_PARAMETERS biosParameters;
|
|
PPNP_BIOS_DEVICE_NODE_LIST deviceList = (PPNP_BIOS_DEVICE_NODE_LIST)Context;
|
|
PPNP_BIOS_DEVICE_NODE deviceNode;
|
|
|
|
while (deviceList) {
|
|
deviceNode = &deviceList->DeviceNode;
|
|
|
|
//
|
|
// call Pnp Bios to set the resources
|
|
//
|
|
|
|
biosParameters.Function = PNP_BIOS_SET_DEVICE_NODE;
|
|
biosParameters.u.SetDeviceNode.Node = deviceNode->Node;
|
|
biosParameters.u.SetDeviceNode.NodeBuffer = deviceNode;
|
|
biosParameters.u.SetDeviceNode.Control = SET_CONFIGURATION_FOR_NEXT_BOOT;
|
|
PbHardwareService (&biosParameters); // Ignore the return status
|
|
deviceList = deviceList->Next;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
PnPBiosReserveLegacyDeviceResources (
|
|
IN PUCHAR biosResources
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
ReturnedResources - supplies a pointer to a variable to receive legacy resources.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PB_PARAMETERS biosParameters;
|
|
|
|
//
|
|
// call Pnp Bios to reserve the resources
|
|
//
|
|
|
|
biosParameters.Function = PNP_BIOS_SET_OLD_ISA_RESOURCES;
|
|
biosParameters.u.SetAllocatedResources.Resources = biosResources;
|
|
PbHardwareService (&biosParameters); // Ignore the return status
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
PbHardwareService (
|
|
IN PPB_PARAMETERS Parameters
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets up stack parameters and calls an
|
|
assembly worker routine to actually invoke the PNP BIOS code.
|
|
|
|
Arguments:
|
|
|
|
Parameters - supplies a pointer to the parameter block.
|
|
|
|
Return Value:
|
|
|
|
An NTSTATUS code to indicate the result of the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status ;
|
|
USHORT stackParameters[PB_MAXIMUM_STACK_SIZE / 2];
|
|
ULONG i = 0;
|
|
USHORT retCode;
|
|
KIRQL oldIrql;
|
|
|
|
//
|
|
// Did we initialize correctly?
|
|
//
|
|
status = PbBiosInitialized;
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
return status ;
|
|
}
|
|
|
|
//
|
|
// Convert and copy the caller's parameters to the format that
|
|
// will be used to invoked pnp bios.
|
|
//
|
|
|
|
stackParameters[i] = Parameters->Function;
|
|
i++;
|
|
|
|
switch (Parameters->Function) {
|
|
case PNP_BIOS_SET_DEVICE_NODE:
|
|
stackParameters[i++] = Parameters->u.SetDeviceNode.Node;
|
|
PbAddress32ToAddress16(Parameters->u.SetDeviceNode.NodeBuffer,
|
|
&stackParameters[i],
|
|
PbSelectors[0]);
|
|
i += 2;
|
|
stackParameters[i++] = Parameters->u.SetDeviceNode.Control;
|
|
stackParameters[i++] = PbBiosDataSelector;
|
|
break;
|
|
|
|
case PNP_BIOS_SET_OLD_ISA_RESOURCES:
|
|
PbAddress32ToAddress16(Parameters->u.SetAllocatedResources.Resources,
|
|
&stackParameters[i],
|
|
PbSelectors[0]);
|
|
i += 2;
|
|
stackParameters[i++] = PbBiosDataSelector;
|
|
break;
|
|
default:
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
MmLockPagableSectionByHandle(ExPageLockHandle);
|
|
//
|
|
// Copy the parameters to stack and invoke Pnp Bios.
|
|
//
|
|
|
|
ExAcquireSpinLock (&PbBiosSpinlock, &oldIrql);
|
|
|
|
retCode = PbCallPnpBiosWorker (
|
|
PbBiosEntryPoint,
|
|
PbBiosCodeSelector,
|
|
stackParameters,
|
|
(USHORT)(i * sizeof(USHORT)));
|
|
|
|
ExReleaseSpinLock (&PbBiosSpinlock, oldIrql);
|
|
|
|
MmUnlockPagableImageSection(ExPageLockHandle);
|
|
|
|
//
|
|
// Map Bios returned code to nt status code.
|
|
//
|
|
|
|
if (retCode == 0) {
|
|
return STATUS_SUCCESS;
|
|
} else {
|
|
IopDbgPrint((IOP_PNPBIOS_WARNING_LEVEL,
|
|
"PnpBios: Bios API call failed. Returned Code = %x\n", retCode));
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
PbAddress32ToAddress16 (
|
|
IN PVOID Address32,
|
|
IN PUSHORT Address16,
|
|
IN USHORT Selector
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts the 32 bit address to 16 bit selector:offset address
|
|
and stored in user specified location.
|
|
|
|
Arguments:
|
|
|
|
Address32 - the 32 bit address to be converted.
|
|
|
|
Address16 - supplies the location to receive the 16 bit sel:offset address
|
|
|
|
Selector - the 16 bit selector for seg:offset address
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KGDTENTRY gdtEntry;
|
|
ULONG baseAddr;
|
|
|
|
//
|
|
// Map virtual address to selector:0 address
|
|
//
|
|
|
|
gdtEntry.LimitLow = 0xFFFF;
|
|
gdtEntry.HighWord.Bytes.Flags1 = 0;
|
|
gdtEntry.HighWord.Bytes.Flags2 = 0;
|
|
gdtEntry.HighWord.Bits.Pres = 1;
|
|
gdtEntry.HighWord.Bits.Dpl = DPL_SYSTEM;
|
|
gdtEntry.HighWord.Bits.Granularity = GRAN_BYTE;
|
|
gdtEntry.HighWord.Bits.Type = 19;
|
|
gdtEntry.HighWord.Bits.Default_Big = 1;
|
|
baseAddr = (ULONG)Address32;
|
|
gdtEntry.BaseLow = (USHORT) (baseAddr & 0xffff);
|
|
gdtEntry.HighWord.Bits.BaseMid = (UCHAR) (baseAddr >> 16) & 0xff;
|
|
gdtEntry.HighWord.Bits.BaseHi = (UCHAR) (baseAddr >> 24) & 0xff;
|
|
KeI386SetGdtSelector (Selector, &gdtEntry);
|
|
*Address16 = 0;
|
|
*(Address16 + 1) = Selector;
|
|
}
|