465 lines
11 KiB
C++
465 lines
11 KiB
C++
|
//++
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation
|
||
|
//
|
||
|
// Module Name:
|
||
|
//
|
||
|
// blpnp.cpp
|
||
|
//
|
||
|
// Abstract:
|
||
|
//
|
||
|
// This module implements PNP BIOS support for the boot loader environment.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
|
||
|
#include "bl.h"
|
||
|
|
||
|
//
|
||
|
// PNP status codes.
|
||
|
//
|
||
|
|
||
|
#define PNP_STATUS_SUCCESS 0x0000
|
||
|
|
||
|
typedef UINT16 PNP_STATUS;
|
||
|
|
||
|
//
|
||
|
// PNP enumeration terminator value.
|
||
|
//
|
||
|
|
||
|
#define PNP_NO_MORE_NODES 0xFF
|
||
|
|
||
|
//
|
||
|
// PNP BIOS state.
|
||
|
//
|
||
|
|
||
|
PPNP_INSTALLATION_CHECK BlPnpBiosInformation;
|
||
|
PPNP_SYSTEM_DEVICE_NODE BlPnpSystemDeviceNodeList;
|
||
|
UINT32 BlPnpSystemDeviceNodeListSize;
|
||
|
PNP_ISA_CONFIGURATION BlPnpIsaConfiguration;
|
||
|
|
||
|
//
|
||
|
// The following variables are in the global data segment to ensure that
|
||
|
// they are located in legacy memory (i.e. in the 1st MB of memory) so
|
||
|
// that BIOS calls can access them.
|
||
|
//
|
||
|
|
||
|
UINT16 BlPnpCallFrame[16];
|
||
|
UINT8 BlPnpHandle;
|
||
|
UINT8 BlPnpNodeData[PAGE_SIZE];
|
||
|
UINT32 BlPnpNodeSize;
|
||
|
UINT8 BlPnpNumberOfNodes;
|
||
|
|
||
|
PNP_STATUS
|
||
|
BlPnpGetNumberOfSystemDeviceNodes(
|
||
|
PUINT8 NumberOfNodes,
|
||
|
PUINT32 NodeSize,
|
||
|
UINT16 BiosSelector
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function queries the number of PNP system device nodes.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// NumberOfNodes - Receives the number of nodes.
|
||
|
//
|
||
|
// NodeSize - Receives the size of the largest node.
|
||
|
//
|
||
|
// BiosSelector - Supplies the selector for the PNP BIOS.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// PNP BIOS status code.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BL_LEGACY_CALL_CONTEXT Context;
|
||
|
|
||
|
BlPnpNumberOfNodes = 0;
|
||
|
BlPnpNodeSize = 0;
|
||
|
|
||
|
BlPnpCallFrame[0] = 0;
|
||
|
BlRtlConvertLinearPointerToFarPointer(&BlPnpNumberOfNodes, (PFAR_POINTER) &BlPnpCallFrame[1]);
|
||
|
BlRtlConvertLinearPointerToFarPointer(&BlPnpNodeSize, (PFAR_POINTER) &BlPnpCallFrame[3]);
|
||
|
BlPnpCallFrame[5] = BiosSelector;
|
||
|
|
||
|
BlRtlZeroMemory(&Context, sizeof(BL_LEGACY_CALL_CONTEXT));
|
||
|
|
||
|
BlRtlCallLegacyFunction(BlPnpBiosInformation->RealModeCodeSegment16,
|
||
|
BlPnpBiosInformation->RealModeCodeOffset16,
|
||
|
BlPnpCallFrame,
|
||
|
6 * sizeof(UINT16),
|
||
|
&Context,
|
||
|
&Context);
|
||
|
|
||
|
if ((PNP_STATUS) Context.eax == PNP_STATUS_SUCCESS) {
|
||
|
|
||
|
*NumberOfNodes = BlPnpNumberOfNodes;
|
||
|
*NodeSize = BlPnpNodeSize;
|
||
|
}
|
||
|
|
||
|
return (PNP_STATUS) Context.eax;
|
||
|
}
|
||
|
|
||
|
PNP_STATUS
|
||
|
BlPnpGetSystemDeviceNode(
|
||
|
PUINT8 Handle,
|
||
|
PPNP_SYSTEM_DEVICE_NODE Node,
|
||
|
UINT32 NodeSize,
|
||
|
UINT16 Control,
|
||
|
UINT16 BiosSelector
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function queries the specified PNP system device nodes.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// Handle - Supplies a pointer to the variable containing
|
||
|
// the handle to query at entry and the next available
|
||
|
// handle at exit.
|
||
|
//
|
||
|
// Node - Receives node information.
|
||
|
//
|
||
|
// NodeSize - Supplies the size of the node structure.
|
||
|
//
|
||
|
// Control - Supplies query control flags.
|
||
|
//
|
||
|
// BiosSelector - Supplies the selector for the PNP BIOS.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// PNP BIOS status code.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BL_LEGACY_CALL_CONTEXT Context;
|
||
|
|
||
|
BLASSERT(NodeSize > 0);
|
||
|
|
||
|
BLASSERT(NodeSize <= sizeof(BlPnpNodeData));
|
||
|
|
||
|
BlPnpHandle = *Handle;
|
||
|
|
||
|
BlPnpCallFrame[0] = 1;
|
||
|
BlRtlConvertLinearPointerToFarPointer(&BlPnpHandle, (PFAR_POINTER) &BlPnpCallFrame[1]);
|
||
|
BlRtlConvertLinearPointerToFarPointer(BlPnpNodeData, (PFAR_POINTER) &BlPnpCallFrame[3]);
|
||
|
BlPnpCallFrame[5] = Control;
|
||
|
BlPnpCallFrame[6] = BiosSelector;
|
||
|
|
||
|
BlRtlZeroMemory(&Context, sizeof(BL_LEGACY_CALL_CONTEXT));
|
||
|
|
||
|
BlRtlCallLegacyFunction(BlPnpBiosInformation->RealModeCodeSegment16,
|
||
|
BlPnpBiosInformation->RealModeCodeOffset16,
|
||
|
BlPnpCallFrame,
|
||
|
7 * sizeof(UINT16),
|
||
|
&Context,
|
||
|
&Context);
|
||
|
|
||
|
if ((PNP_STATUS) Context.eax == PNP_STATUS_SUCCESS) {
|
||
|
|
||
|
*Handle = BlPnpHandle;
|
||
|
|
||
|
BLASSERT(((PPNP_SYSTEM_DEVICE_NODE) BlPnpNodeData)->Size <= NodeSize);
|
||
|
|
||
|
BlRtlCopyMemory(Node,
|
||
|
BlPnpNodeData,
|
||
|
((PPNP_SYSTEM_DEVICE_NODE) BlPnpNodeData)->Size);
|
||
|
}
|
||
|
|
||
|
return (PNP_STATUS) Context.eax;
|
||
|
}
|
||
|
|
||
|
PNP_STATUS
|
||
|
BlPnpGetIsaConfiguration(
|
||
|
PPNP_ISA_CONFIGURATION IsaConfiguration,
|
||
|
UINT16 BiosSelector
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function queries PNP ISA configuration.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// IsaConfiguration - Receive PNP ISA configuration.
|
||
|
//
|
||
|
// BiosSelector - Supplies the selector for the PNP BIOS.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// PNP BIOS status code.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
BL_LEGACY_CALL_CONTEXT Context;
|
||
|
|
||
|
BlRtlZeroMemory(IsaConfiguration, sizeof(PNP_ISA_CONFIGURATION));
|
||
|
|
||
|
IsaConfiguration->Revision = 1;
|
||
|
|
||
|
BlPnpCallFrame[0] = 0x40;
|
||
|
BlRtlConvertLinearPointerToFarPointer(IsaConfiguration, (PFAR_POINTER) &BlPnpCallFrame[1]);
|
||
|
BlPnpCallFrame[3] = BiosSelector;
|
||
|
|
||
|
BlRtlZeroMemory(&Context, sizeof(BL_LEGACY_CALL_CONTEXT));
|
||
|
|
||
|
BlRtlCallLegacyFunction(BlPnpBiosInformation->RealModeCodeSegment16,
|
||
|
BlPnpBiosInformation->RealModeCodeOffset16,
|
||
|
BlPnpCallFrame,
|
||
|
4 * sizeof(UINT16),
|
||
|
&Context,
|
||
|
&Context);
|
||
|
|
||
|
return (PNP_STATUS) Context.eax;
|
||
|
}
|
||
|
|
||
|
PPNP_INSTALLATION_CHECK
|
||
|
BlPnpLocateBios(
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function locates the PNP BIOS by searching the ROM area.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// PNP BIOS installation check structure, if located.
|
||
|
// NULL, otherwise.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
ULONG_PTR End;
|
||
|
PPNP_INSTALLATION_CHECK Pnp;
|
||
|
ULONG_PTR Start;
|
||
|
|
||
|
Start = 0xF0000;
|
||
|
End = 0x100000;
|
||
|
|
||
|
while (Start != End) {
|
||
|
|
||
|
Pnp = (PPNP_INSTALLATION_CHECK) Start;
|
||
|
|
||
|
if ((Pnp->Signature[0] == '$') &&
|
||
|
(Pnp->Signature[1] == 'P') &&
|
||
|
(Pnp->Signature[2] == 'n') &&
|
||
|
(Pnp->Signature[3] == 'P') &&
|
||
|
(Pnp->Version == 0x10) &&
|
||
|
(Pnp->Length == 0x21) &&
|
||
|
(BlRtlComputeChecksum8(Pnp, Pnp->Length) == 0)
|
||
|
) {
|
||
|
|
||
|
return Pnp;
|
||
|
}
|
||
|
|
||
|
Start += 16;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
BlPnpInitialize(
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
//++
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function initializes PNP BIOS support.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
{
|
||
|
UINT8 Handle;
|
||
|
PPNP_SYSTEM_DEVICE_NODE Node;
|
||
|
UINT32 NodeListSize;
|
||
|
UINT32 NodeSize;
|
||
|
UINT8 NumberOfNodes;
|
||
|
PPNP_INSTALLATION_CHECK Pnp;
|
||
|
PNP_STATUS Result;
|
||
|
|
||
|
//
|
||
|
// Initialize empty node list.
|
||
|
//
|
||
|
|
||
|
BlPnpSystemDeviceNodeList = NULL;
|
||
|
BlPnpSystemDeviceNodeListSize = 0;
|
||
|
|
||
|
//
|
||
|
// Locate PNP BIOS.
|
||
|
//
|
||
|
|
||
|
Pnp = BlPnpLocateBios();
|
||
|
|
||
|
if (Pnp == NULL) {
|
||
|
|
||
|
#if PNP_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("PNP: PNP BIOS not found!\n");
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#if PNP_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("PNP: PNP BIOS detected @ %p\n", Pnp);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
BlPnpBiosInformation = Pnp;
|
||
|
|
||
|
#if PNP_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("PNP: Real-Mode Code: %04x:%04x\n",
|
||
|
Pnp->RealModeCodeSegment16,
|
||
|
Pnp->RealModeCodeOffset16);
|
||
|
|
||
|
BlRtlPrintf("PNP: Real-Mode Data: %04x:\n", Pnp->RealModeDataSegment16);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Build PNP system device node list.
|
||
|
//
|
||
|
|
||
|
Result = BlPnpGetNumberOfSystemDeviceNodes(&NumberOfNodes,
|
||
|
&NodeSize,
|
||
|
Pnp->RealModeDataSegment16);
|
||
|
|
||
|
if (Result != PNP_STATUS_SUCCESS) {
|
||
|
|
||
|
#if PNP_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("PNP: BlPnpGetNumberOfSystemDeviceNodes failed with error %04x.\n", Result);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#if PNP_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("PNP: %u node(s), %u bytes in largest node.\n",
|
||
|
NumberOfNodes,
|
||
|
NodeSize);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
Node = (PPNP_SYSTEM_DEVICE_NODE) BlPoolAllocateBlock(NodeSize);
|
||
|
|
||
|
NodeListSize = 0;
|
||
|
|
||
|
Handle = 0;
|
||
|
|
||
|
for (;;) {
|
||
|
|
||
|
BlRtlZeroMemory(Node, sizeof(*Node));
|
||
|
|
||
|
Result = BlPnpGetSystemDeviceNode(&Handle,
|
||
|
Node,
|
||
|
NodeSize,
|
||
|
1,
|
||
|
Pnp->RealModeDataSegment16);
|
||
|
|
||
|
if (Result != PNP_STATUS_SUCCESS) {
|
||
|
|
||
|
#if PNP_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("PNP: BlPnpGetSystemDeviceNode failed with error %04x.\n", Result);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
BlPoolFreeBlock(Node);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
NodeListSize += Node->Size;
|
||
|
|
||
|
if (Handle == PNP_NO_MORE_NODES) {
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BlPnpSystemDeviceNodeList = (PPNP_SYSTEM_DEVICE_NODE)BlPoolAllocateBlock(NodeListSize);
|
||
|
BlPnpSystemDeviceNodeListSize = NodeListSize;
|
||
|
|
||
|
Node = BlPnpSystemDeviceNodeList;
|
||
|
|
||
|
Handle = 0;
|
||
|
|
||
|
for (;;) {
|
||
|
|
||
|
BlRtlZeroMemory(Node, sizeof(*Node));
|
||
|
|
||
|
Result = BlPnpGetSystemDeviceNode(&Handle,
|
||
|
Node,
|
||
|
NodeSize,
|
||
|
1,
|
||
|
Pnp->RealModeDataSegment16);
|
||
|
|
||
|
if (Result != PNP_STATUS_SUCCESS) {
|
||
|
|
||
|
BlRtlPrintf("PNP: BlPnpGetSystemDeviceNode failed with error %04x.\n", Result);
|
||
|
BlRtlHalt();
|
||
|
}
|
||
|
|
||
|
if (Handle == PNP_NO_MORE_NODES) {
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Node = (PPNP_SYSTEM_DEVICE_NODE) (((ULONG_PTR) Node) + Node->Size);
|
||
|
NodeSize -= Node->Size;
|
||
|
}
|
||
|
|
||
|
#if PNP_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("PNP: DeviceNodeList: %p ... %p\n",
|
||
|
BlPnpSystemDeviceNodeList,
|
||
|
(ULONG_PTR) BlPnpSystemDeviceNodeList + BlPnpSystemDeviceNodeListSize - 1);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Query PNP ISA configuration.
|
||
|
//
|
||
|
|
||
|
BlPnpGetIsaConfiguration(&BlPnpIsaConfiguration, Pnp->RealModeDataSegment16);
|
||
|
|
||
|
#if PNP_VERBOSE
|
||
|
|
||
|
BlRtlPrintf("PNP: ISA Configuration:\n"
|
||
|
"PNP: Revision : %u\n"
|
||
|
"PNP: # of Card Select Numbers : %u\n"
|
||
|
"PNP: Data read port : %04x\n",
|
||
|
BlPnpIsaConfiguration.Revision,
|
||
|
BlPnpIsaConfiguration.NumberOfCardSelectNumbers,
|
||
|
BlPnpIsaConfiguration.DataReadPort);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return;
|
||
|
}
|