505 lines
13 KiB
C
505 lines
13 KiB
C
/*** acpitab.c - ACPI VXD to provide table access IOCTLs
|
|
*
|
|
* Author: Michael Tsang (MikeTs)
|
|
* Created 10/08/97
|
|
*
|
|
* MODIFICATION HISTORY
|
|
*/
|
|
|
|
#include "acpitabp.h"
|
|
|
|
/*** Function prototypes
|
|
*/
|
|
|
|
CM_VXD_RESULT CM_SYSCTRL ACPITabIOCtrl(PDIOCPARAMETERS pdioc);
|
|
PRSDT LOCAL FindRSDT(PDWORD pdwRSDPAddr, PDWORD pdwRSDTAddr);
|
|
DWORD LOCAL FindTable(DWORD dwSig, PDWORD pdwLen);
|
|
BOOL LOCAL ValidateTable(DWORD dwTableAddr, DWORD dwLen);
|
|
BOOL LOCAL IsALikelySig(DWORD dwTableSig);
|
|
VOID LOCAL CopyROM(DWORD dwPhyAddr, PBYTE pbBuff, DWORD dwLen);
|
|
BYTE LOCAL CheckSum(PBYTE pb, DWORD dwLen);
|
|
#ifdef TRACING
|
|
PSZ LOCAL SigStr(DWORD dwSig);
|
|
#endif
|
|
|
|
#pragma VXD_PAGEABLE_DATA
|
|
#pragma VXD_PAGEABLE_CODE
|
|
|
|
/***EP ACPITabIOCtrl - Win32 Device IO Control entry point
|
|
*
|
|
* ENTRY
|
|
* pioc -> DIOC structure
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns ERROR_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns ERROR_*
|
|
*/
|
|
|
|
CM_VXD_RESULT CM_SYSCTRL ACPITabIOCtrl(PDIOCPARAMETERS pdioc)
|
|
{
|
|
TRACENAME("ACPITabIOCTRL")
|
|
CM_VXD_RESULT rc = ERROR_SUCCESS;
|
|
|
|
ENTER(1, ("ACPITabIOCtrl(hVM=%lx,hDev=%lx,Code=%lx)\n",
|
|
pdioc->VMHandle, pdioc->hDevice, pdioc->dwIoControlCode));
|
|
|
|
switch (pdioc->dwIoControlCode)
|
|
{
|
|
case ACPITAB_DIOC_GETVERSION:
|
|
if ((pdioc->cbOutBuffer < sizeof(DWORD)) ||
|
|
(pdioc->lpvOutBuffer == NULL))
|
|
{
|
|
DBG_ERR(("ACPITabIOCtrl: invalid parameter on GetVersion"));
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
PVMMDDB pddb = (PVMMDDB)pdioc->Internal2;
|
|
|
|
*((PDWORD)pdioc->lpvOutBuffer) =
|
|
(pddb->DDB_Dev_Major_Version << 8) |
|
|
pddb->DDB_Dev_Minor_Version;
|
|
|
|
if (pdioc->lpcbBytesReturned != NULL)
|
|
*((PDWORD)pdioc->lpcbBytesReturned) = sizeof(DWORD);
|
|
}
|
|
break;
|
|
|
|
case ACPITAB_DIOC_GETTABINFO:
|
|
if ((pdioc->lpvOutBuffer == NULL) ||
|
|
(pdioc->cbOutBuffer != sizeof(TABINFO)))
|
|
{
|
|
DBG_ERR(("ACPITabIOCtrl: invalid parameter on GetTabInfo"));
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
PTABINFO pTabInfo = (PTABINFO)pdioc->lpvOutBuffer;
|
|
DWORD dwLen;
|
|
|
|
if ((pTabInfo->dwPhyAddr = FindTable(pTabInfo->dwTabSig, NULL))
|
|
!= 0)
|
|
{
|
|
if (pTabInfo->dwTabSig == SIG_RSDP)
|
|
{
|
|
dwLen = sizeof(RSDP);
|
|
}
|
|
else if (pTabInfo->dwTabSig == FACS_SIGNATURE)
|
|
{
|
|
dwLen = sizeof(FACS);
|
|
}
|
|
else
|
|
{
|
|
dwLen = sizeof(DESCRIPTION_HEADER);
|
|
}
|
|
CopyROM(pTabInfo->dwPhyAddr, (PBYTE)&pTabInfo->dh, dwLen);
|
|
}
|
|
else
|
|
{
|
|
DBG_ERR(("ACPITabIOCtrl: failed to get table info"));
|
|
rc = ERROR_GEN_FAILURE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ACPITAB_DIOC_GETTABLE:
|
|
if ((pdioc->lpvInBuffer == NULL) || (pdioc->lpvOutBuffer == NULL) ||
|
|
(pdioc->cbOutBuffer == 0) ||
|
|
!ValidateTable((DWORD)pdioc->lpvInBuffer, pdioc->cbOutBuffer))
|
|
{
|
|
DBG_ERR(("ACPITabIOCtrl: invalid parameter on GetTable"));
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
CopyROM((DWORD)pdioc->lpvInBuffer, (PBYTE)pdioc->lpvOutBuffer,
|
|
pdioc->cbOutBuffer);
|
|
}
|
|
break;
|
|
}
|
|
|
|
EXIT(1, ("ACPITabIOCtrl=%x\n", rc));
|
|
return rc;
|
|
} //ACPITabIOCtrl
|
|
|
|
/***LP FindRSDT - Find the RSDT
|
|
*
|
|
* ENTRY
|
|
* pdwRSDPAddr -> to hold the physical address of RSDP
|
|
* pdwRSDTAddr -> to hold the physical address of RSDT
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns the RSDT pointer
|
|
* EXIT-FAILURE
|
|
* returns NULL
|
|
*/
|
|
|
|
PRSDT LOCAL FindRSDT(PDWORD pdwRSDPAddr, PDWORD pdwRSDTAddr)
|
|
{
|
|
TRACENAME("FINDRSDT")
|
|
PRSDT pRSDT = NULL;
|
|
PBYTE pbROM;
|
|
|
|
ENTER(2, ("FindRSDT(pdwRSDPAddr=%p,pdwRSDTAddr=%p)\n",
|
|
pdwRSDPAddr, pdwRSDTAddr));
|
|
|
|
if ((pbROM = (PBYTE)_MapPhysToLinear(RSDP_SEARCH_RANGE_BEGIN,
|
|
RSDP_SEARCH_RANGE_LENGTH, 0)) !=
|
|
(PBYTE)0xffffffff)
|
|
{
|
|
PBYTE pbROMEnd;
|
|
|
|
pbROMEnd = pbROM + RSDP_SEARCH_RANGE_LENGTH - RSDP_SEARCH_INTERVAL;
|
|
while (pbROM != NULL)
|
|
{
|
|
if ((((PRSDP)pbROM)->Signature == RSDP_SIGNATURE) &&
|
|
(CheckSum(pbROM, sizeof(RSDP)) == 0))
|
|
{
|
|
*pdwRSDPAddr = (RSDP_SEARCH_RANGE_BEGIN +
|
|
RSDP_SEARCH_RANGE_LENGTH) -
|
|
(pbROMEnd + RSDP_SEARCH_INTERVAL - pbROM);
|
|
*pdwRSDTAddr = ((PRSDP)pbROM)->RsdtAddress;
|
|
if (((pbROM = (PBYTE)_MapPhysToLinear(*pdwRSDTAddr,
|
|
sizeof(DESCRIPTION_HEADER),
|
|
0)) ==
|
|
(PBYTE)0xffffffff) ||
|
|
(((PDESCRIPTION_HEADER)pbROM)->Signature != RSDT_SIGNATURE))
|
|
{
|
|
pbROM = NULL;
|
|
*pdwRSDTAddr = 0;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
pbROM += RSDP_SEARCH_INTERVAL;
|
|
if (pbROM > pbROMEnd)
|
|
{
|
|
pbROM = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pbROM != NULL)
|
|
{
|
|
DWORD dwLen = ((PDESCRIPTION_HEADER)pbROM)->Length;
|
|
|
|
pRSDT = (PRSDT)_MapPhysToLinear(*pdwRSDTAddr, dwLen, 0);
|
|
if ((pRSDT == (PRSDT)0xffffffff) ||
|
|
(CheckSum((PBYTE)pRSDT, dwLen) != 0))
|
|
{
|
|
pRSDT = NULL;
|
|
*pdwRSDTAddr = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
EXIT(2, ("FindRSDT=%x (RSDPAddr=%x,RSDTAddr=%x)\n",
|
|
pRSDT, *pdwRSDPAddr, *pdwRSDTAddr));
|
|
return pRSDT;
|
|
} //FindRSDT
|
|
|
|
/***LP FindTable - Find an ACPI Table
|
|
*
|
|
* ENTRY
|
|
* dwSig - signature of the table
|
|
* pdwLen -> to hold length of table (can be NULL)
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns physical address of table
|
|
* EXIT-FAILURE
|
|
* returns 0
|
|
*/
|
|
|
|
DWORD LOCAL FindTable(DWORD dwSig, PDWORD pdwLen)
|
|
{
|
|
TRACENAME("FINDTABLE")
|
|
DWORD dwPhyAddr = 0, dwTableLen = 0;
|
|
static PRSDT pRSDT = (PRSDT)0xffffffff;
|
|
static DWORD dwRSDPAddr = 0, dwRSDTAddr = 0;
|
|
|
|
ENTER(2, ("FindTable(Sig=%s,pdwLen=%x)\n", SigStr(dwSig), pdwLen));
|
|
|
|
if (pRSDT == (PRSDT)0xffffffff)
|
|
{
|
|
pRSDT = FindRSDT(&dwRSDPAddr, &dwRSDTAddr);
|
|
}
|
|
|
|
if (pRSDT != NULL)
|
|
{
|
|
PVOID pv;
|
|
|
|
if (dwSig == SIG_RSDP)
|
|
{
|
|
//
|
|
// We are looking for "RSD PTR"
|
|
//
|
|
dwPhyAddr = dwRSDPAddr;
|
|
dwTableLen = sizeof(RSDP);
|
|
}
|
|
else if (dwSig == RSDT_SIGNATURE)
|
|
{
|
|
dwPhyAddr = dwRSDTAddr;
|
|
dwTableLen = pRSDT->Header.Length;
|
|
}
|
|
else if ((dwSig == DSDT_SIGNATURE) || (dwSig == FACS_SIGNATURE))
|
|
{
|
|
PFADT pFADT;
|
|
|
|
if (((dwPhyAddr = FindTable(FADT_SIGNATURE, &dwTableLen)) != 0) &&
|
|
((pFADT = (PFADT)_MapPhysToLinear(dwPhyAddr, dwTableLen, 0)) !=
|
|
(PFADT)0xffffffff))
|
|
{
|
|
if (dwSig == DSDT_SIGNATURE)
|
|
{
|
|
dwPhyAddr = pFADT->dsdt;
|
|
if ((pv = _MapPhysToLinear(dwPhyAddr,
|
|
sizeof(DESCRIPTION_HEADER), 0))
|
|
!= (PVOID)0xffffffff)
|
|
{
|
|
dwTableLen = ((PDESCRIPTION_HEADER)pv)->Length;
|
|
}
|
|
else
|
|
{
|
|
dwPhyAddr = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwPhyAddr = pFADT->facs;
|
|
if ((pv = _MapPhysToLinear(dwPhyAddr, sizeof(FACS), 0)) !=
|
|
(PVOID)0xffffffff)
|
|
{
|
|
dwTableLen = ((PFACS)pv)->Length;
|
|
}
|
|
else
|
|
{
|
|
dwPhyAddr = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwPhyAddr = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int i, iNumTables = NumTableEntriesFromRSDTPointer(pRSDT);
|
|
|
|
for (i = 0; i < iNumTables; ++i)
|
|
{
|
|
if (((pv = _MapPhysToLinear(pRSDT->Tables[i],
|
|
sizeof(DESCRIPTION_HEADER), 0)) !=
|
|
(PVOID)0xffffffff) &&
|
|
(((PDESCRIPTION_HEADER)pv)->Signature == dwSig))
|
|
{
|
|
dwPhyAddr = pRSDT->Tables[i];
|
|
dwTableLen = ((PDESCRIPTION_HEADER)pv)->Length;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((dwPhyAddr != 0) && (pdwLen != NULL))
|
|
{
|
|
*pdwLen = dwTableLen;
|
|
}
|
|
}
|
|
|
|
EXIT(2, ("FindTable=%x (Len=%x)\n", dwPhyAddr, pdwLen? *pdwLen: 0));
|
|
return dwPhyAddr;
|
|
} //FindTable
|
|
|
|
/***LP ValidateTable - Validate the table
|
|
*
|
|
* ENTRY
|
|
* dwTableAddr - physical address of table
|
|
* dwLen - table length
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns TRUE
|
|
* EXIT-FAILURE
|
|
* returns FALSE
|
|
*/
|
|
|
|
BOOL LOCAL ValidateTable(DWORD dwTableAddr, DWORD dwLen)
|
|
{
|
|
TRACENAME("VALIDATETABLE")
|
|
BOOL rc = TRUE;
|
|
PBYTE pbTable;
|
|
|
|
ENTER(2, ("ValidateTable(TableAddr=%x,Len=%d)\n", dwTableAddr, dwLen));
|
|
|
|
if ((pbTable = (PBYTE)_MapPhysToLinear(dwTableAddr, dwLen, 0)) !=
|
|
(PBYTE)0xffffffff)
|
|
{
|
|
DWORD dwTableSig, dwTableLen = 0;
|
|
BOOL fNeedChkSum = FALSE;
|
|
|
|
dwTableSig = ((PDESCRIPTION_HEADER)pbTable)->Signature;
|
|
switch (dwTableSig)
|
|
{
|
|
case SIG_LOW_RSDP:
|
|
dwTableLen = sizeof(RSDP);
|
|
fNeedChkSum = TRUE;
|
|
break;
|
|
|
|
case RSDT_SIGNATURE:
|
|
case FADT_SIGNATURE:
|
|
case DSDT_SIGNATURE:
|
|
case SSDT_SIGNATURE:
|
|
case PSDT_SIGNATURE:
|
|
case APIC_SIGNATURE:
|
|
case SBST_SIGNATURE:
|
|
case SIG_BOOT:
|
|
dwTableLen = ((PDESCRIPTION_HEADER)pbTable)->Length;
|
|
fNeedChkSum = TRUE;
|
|
break;
|
|
|
|
case FACS_SIGNATURE:
|
|
dwTableLen = ((PFACS)pbTable)->Length;
|
|
break;
|
|
|
|
default:
|
|
if (IsALikelySig(dwTableSig) &&
|
|
(((PDESCRIPTION_HEADER)pbTable)->Length < 256))
|
|
{
|
|
dwTableLen = ((PDESCRIPTION_HEADER)pbTable)->Length;
|
|
fNeedChkSum = TRUE;
|
|
}
|
|
else
|
|
{
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
|
|
if ((rc == TRUE) && fNeedChkSum)
|
|
{
|
|
if (((pbTable = (PBYTE)_MapPhysToLinear(dwTableAddr, dwTableLen, 0))
|
|
== (PBYTE)0xffffffff) ||
|
|
(CheckSum(pbTable, dwTableLen) != 0))
|
|
{
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = FALSE;
|
|
}
|
|
|
|
EXIT(2, ("ValidateTable=%x\n", rc));
|
|
return rc;
|
|
} //ValidateTable
|
|
|
|
/***LP IsALikelySig - Check if it looks like a table signature
|
|
*
|
|
* ENTRY
|
|
* dwTableSig - table signature
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns TRUE
|
|
* EXIT-FAILURE
|
|
* returns FALSE
|
|
*/
|
|
|
|
BOOL LOCAL IsALikelySig(DWORD dwTableSig)
|
|
{
|
|
TRACENAME("ISALIKELYSIG")
|
|
BOOL rc = TRUE;
|
|
int i, ch;
|
|
|
|
ENTER(2, ("IsALikelySig(TableSig=%x)\n", dwTableSig));
|
|
|
|
for (i = 0; i < sizeof(DWORD); ++i)
|
|
{
|
|
ch = BYTEOF(dwTableSig, i);
|
|
if ((ch < 'A') || (ch > 'Z'))
|
|
{
|
|
rc = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
EXIT(2, ("IsALikelySig=%x\n", rc));
|
|
return rc;
|
|
} //IsALikelySig
|
|
|
|
/***LP CopyROM - Copy ROM memory to buffer
|
|
*
|
|
* ENTRY
|
|
* dwPhyAddr - physical address of ROM location
|
|
* pbBuff -> buffer
|
|
* dwLen - buffer length
|
|
*
|
|
* EXIT
|
|
* None
|
|
*/
|
|
|
|
VOID LOCAL CopyROM(DWORD dwPhyAddr, PBYTE pbBuff, DWORD dwLen)
|
|
{
|
|
TRACENAME("COPYROM")
|
|
PBYTE pbROM;
|
|
|
|
ENTER(2, ("CopyROM(PhyAddr=%x,pbBuff=%x,Len=%x)\n",
|
|
dwPhyAddr, pbBuff, dwLen));
|
|
|
|
if ((pbROM = (PBYTE)_MapPhysToLinear(dwPhyAddr, dwLen, 0)) !=
|
|
(PBYTE)0xffffffff)
|
|
{
|
|
memcpy(pbBuff, pbROM, dwLen);
|
|
}
|
|
|
|
EXIT(2, ("CopyROM!\n"));
|
|
} //CopyROM
|
|
|
|
/***LP CheckSum - Calculate checksum of a buffer
|
|
*
|
|
* ENTRY
|
|
* pb -> buffer
|
|
* dwLen - length of buffer
|
|
*
|
|
* EXIT
|
|
* returns checksum
|
|
*/
|
|
|
|
BYTE LOCAL CheckSum(PBYTE pb, DWORD dwLen)
|
|
{
|
|
TRACENAME("CHECKSUM")
|
|
BYTE bChkSum = 0;
|
|
|
|
ENTER(2, ("CheckSum(pb=%x,Len=%x)\n", pb, dwLen));
|
|
|
|
while (dwLen > 0)
|
|
{
|
|
bChkSum = (BYTE)(bChkSum + *pb);
|
|
pb++;
|
|
dwLen--;
|
|
}
|
|
|
|
EXIT(2, ("CheckSum=%x\n", bChkSum));
|
|
return bChkSum;
|
|
} //CheckSum
|
|
|
|
#ifdef TRACING
|
|
/***LP SigStr - return string of DWORD signature
|
|
*
|
|
* ENTRY
|
|
* dwSig - signature
|
|
*
|
|
* EXIT
|
|
* returns signature string
|
|
*/
|
|
|
|
PSZ LOCAL SigStr(DWORD dwSig)
|
|
{
|
|
static char szSig[sizeof(DWORD) + 1] = {0};
|
|
|
|
memcpy(szSig, &dwSig, sizeof(DWORD));
|
|
|
|
return (PSZ)szSig;
|
|
} //SigStr
|
|
#endif
|