singrdk/base/boot/SingLdrPc/blpnp.cpp

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;
}