/*** tables.c - Dump various ACPI tables
 *
 *  This module provides the functions to dump various ACPI tables.
 *
 *  Copyright (c) 1999 Microsoft Corporation
 *  Author:     Michael Tsang (MikeTs)
 *  Created     04/08/99
 *
 *  MODIFICATION HISTORY
 */

#ifdef __UNASM

#pragma warning (disable: 4201 4214 4514)

typedef unsigned __int64 ULONGLONG;
#define LOCAL   __cdecl
#define EXPORT  __cdecl
#include <stdarg.h>
//#define _X86_
#include <windef.h>
#include <winbase.h>
#include <winreg.h>
#define ULONG_PTR ULONG
#define EXCL_BASEDEF
#include "pch.h"
#include "fmtdata.h"

#define BYTEOF(d,i)	(((BYTE *)&(d))[i])

/***LP  IsWinNT - check if OS is NT
 *
 *  ENTRY
 *      None
 *
 *  EXIT-SUCCESS
 *      returns TRUE - OS is NT
 *  EXIT-FAILURE
 *      returns FALSE - OS is not NT
 */

BOOL LOCAL IsWinNT(VOID)
{
    BOOL rc = FALSE;
    OSVERSIONINFO osinfo;

    ENTER((2, "IsWinNT()\n"));

    osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    if (GetVersionEx(&osinfo) && (osinfo.dwPlatformId == VER_PLATFORM_WIN32_NT))
    {
        rc = TRUE;
    }

    EXIT((2, "IsWinNT=%x\n", rc));
    return rc;
}       //IsWinNT

#ifndef WINNT
/***LP  OpenVxD - Open ACPITAB.VXD
 *
 *  ENTRY
 *      None
 *
 *  EXIT-SUCCESS
 *      returns VxD handle
 *  EXIT-FAILURE
 *      returns NULL
 */

HANDLE LOCAL OpenVxD(VOID)
{
    HANDLE hVxD;
    DWORD dwVersion;

    ENTER((2, "OpenVxD()\n"));

    if ((hVxD = CreateFile(ACPITAB_VXD_NAME, 0, 0, NULL, 0,
                           FILE_FLAG_DELETE_ON_CLOSE, NULL)) ==
        INVALID_HANDLE_VALUE)
    {
	ERROR(("OpenVxD: failed to open VxD %s (rc=%x)",
	       ACPITAB_VXD_NAME, GetLastError()));
        hVxD = NULL;
    }
    else if (!DeviceIoControl(hVxD, ACPITAB_DIOC_GETVERSION, NULL, 0,
                              &dwVersion, sizeof(dwVersion), NULL, NULL))
    {
        ERROR(("OpenVxD: failed to get VxD version. (rc=%x)", GetLastError()));
        CloseVxD(hVxD);
        hVxD = NULL;
    }
    else if (dwVersion != ((ACPITAB_MAJOR_VER << 8) | ACPITAB_MINOR_VER))
    {
        ERROR(("OpenVxD: version error (Ver=%x)", dwVersion));
        CloseVxD(hVxD);
        hVxD = NULL;
    }

    EXIT((2, "OpenVxD=%x\n", hVxD));
    return hVxD;
}       //OpenVxD

/***LP  CloseVxD - Close the VxD
 *
 *  ENTRY
 *      hVxD - VxD handle
 *
 *  EXIT
 *      None
 */

VOID LOCAL CloseVxD(HANDLE hVxD)
{
    ENTER((2, "CloseVxD(hVxD=%x)\n", hVxD));

    CloseHandle(hVxD);

    EXIT((2, "CloseVxD!\n"));
}       //CloseVxD

/***LP  VxDGetTableBySig - Get table by its signature
 *
 *  ENTRY
 *      dwTabSig - table signature
 *      pdwTableAddr -> to hold physical address of table (can be NULL)
 *
 *  EXIT-SUCCESS
 *      returns pointer to table
 *  EXIT-FAILURE
 *      returns NULL
 */

PBYTE LOCAL VxDGetTableBySig(DWORD dwTabSig, PDWORD pdwTableAddr)
{
    PBYTE pb = NULL;
    TABINFO TabInfo;

    ENTER((2, "VxDGetTableBySig(TabSig=%x,pdwAddr=%p)\n",
           dwTabSig, pdwTableAddr));

    TabInfo.dwTabSig = dwTabSig;
    if (DeviceIoControl(ghVxD, ACPITAB_DIOC_GETTABINFO, NULL, 0, &TabInfo,
                        sizeof(TabInfo), NULL, NULL))
    {
        if (dwTabSig == SIG_RSDP)
        {
            //
            // We are getting RSD PTR
            //
            if ((pb = MEMALLOC(sizeof(RSDP))) != NULL)
            {
                memcpy(pb, &TabInfo.rsdp, sizeof(RSDP));
                if (pdwTableAddr != NULL)
                {
                    *pdwTableAddr = TabInfo.dwPhyAddr;
                }
            }
            else
            {
                ERROR(("VxDGetTableBySig: failed to allocate RSDP buffer"));
            }
        }
        else if (dwTabSig == FACS_SIGNATURE)
        {
            if ((pb = MEMALLOC(sizeof(FACS))) != NULL)
            {
                memcpy(pb, &TabInfo.facs, sizeof(FACS));
                if (pdwTableAddr != NULL)
                {
                    *pdwTableAddr = TabInfo.dwPhyAddr;
                }
            }
            else
            {
                ERROR(("VxDGetTableBySig: failed to allocate FACS buffer"));
            }
        }
        else if ((pb = MEMALLOC(TabInfo.dh.Length)) != NULL)
        {
            if (DeviceIoControl(ghVxD, ACPITAB_DIOC_GETTABLE,
                                (PVOID)TabInfo.dwPhyAddr, 0, pb,
                                TabInfo.dh.Length, NULL, NULL) == 0)
            {
                ERROR(("VxDGetTableBySig: failed to get table %s. (rc=%x)",
                       GetTableSigStr(dwTabSig), GetLastError()));
                MEMFREE(pb);
                pb = NULL;
            }
	    else
	    {
		if (pdwTableAddr != NULL)
		{
                    *pdwTableAddr = TabInfo.dwPhyAddr;
		}

		ValidateTable(pb, TabInfo.dh.Length);
	    }
        }
        else
        {
            ERROR(("VxDGetTableBySig: failed to allocate table buffer (len=%d)",
                   TabInfo.dh.Length));
        }
    }
    else
    {
        ERROR(("VxDGetTableBySig: failed to get table info %s. (rc=%x)",
               GetTableSigStr(dwTabSig), GetLastError()));
    }

    EXIT((2, "VxDGetTableBySig=%x\n", pb));
    return pb;
}       //VxDGetTableBySig

/***LP  VxDGetTableByAddr - Get table by its physical address
 *
 *  ENTRY
 *      dwTableAddr - physical address of table
 *      pdwTableSig -> to hold signature of table (can be NULL)
 *
 *  EXIT-SUCCESS
 *      returns pointer to table
 *  EXIT-FAILURE
 *      returns NULL
 */

PBYTE LOCAL VxDGetTableByAddr(DWORD dwTableAddr, PDWORD pdwTableSig)
{
    PBYTE pb = NULL;
    DESCRIPTION_HEADER dh;

    ENTER((2, "VxDGetTableByAddr(TabAddr=%x,pdwSig=%p)\n",
           dwTableAddr, pdwTableSig));

    if (DeviceIoControl(ghVxD, ACPITAB_DIOC_GETTABLE, (PVOID)dwTableAddr, 0,
                        &dh, sizeof(dh), NULL, NULL))
    {
        DWORD dwLen = (dh.Signature == SIG_LOW_RSDP)? sizeof(RSDP): dh.Length;

        if ((pb = MEMALLOC(dwLen)) != NULL)
        {
            if (DeviceIoControl(ghVxD, ACPITAB_DIOC_GETTABLE,
                                (PVOID)dwTableAddr, 0, pb, dwLen, NULL, NULL)
                == 0)
            {
                ERROR(("VxDGetTableByAddr: failed to get table %s at %x. (rc=%x)",
                       GetTableSigStr(dh.Signature), dwTableAddr,
		       GetLastError()));
                MEMFREE(pb);
                pb = NULL;
            }
            else if (pdwTableSig != NULL)
            {
		if (pdwTableSig != NULL)
		{
                    *pdwTableSig = (dh.Signature == SIG_LOW_RSDP)?
                                    SIG_RSDP: dh.Signature;
		}

		ValidateTable(pb, dwLen);
            }
        }
        else
        {
            ERROR(("VxDGetTableByAddr: failed to allocate table buffer (len=%d)",
                   dh.Length));
        }
    }
    else
    {
        ERROR(("VxDGetTableByAddr: failed to get table %s header (rc=%x)",
               GetTableSigStr(dh.Signature), GetLastError()));
    }

    EXIT((2, "VxDGetTableByAddr=%x\n", pb));
    return pb;
}       //VxDGetTableByAddr
#endif  //ifndef WINNT

/***LP  EnumSubKey - enumerate subkey
 *
 *  ENTRY
 *      hkey - key to enumerate
 *      dwIndex - subkey index
 *
 *  EXIT-SUCCESS
 *      returns subkey
 *  EXIT-FAILURE
 *      returns NULL
 */

HKEY LOCAL EnumSubKey(HKEY hkey, DWORD dwIndex)
{
    HKEY hkeySub = NULL;
    char szSubKey[32];
    DWORD dwSubKeySize = sizeof(szSubKey);

    ENTER((2, "EnumSubKey(hkey=%x,Index=%d)\n", hkey, dwIndex));

    if ((RegEnumKeyEx(hkey, dwIndex, szSubKey, &dwSubKeySize, NULL, NULL, NULL,
                      NULL) == ERROR_SUCCESS) &&
        (RegOpenKeyEx(hkey, szSubKey, 0, KEY_READ, &hkeySub) != ERROR_SUCCESS))
    {
        hkeySub = NULL;
    }

    EXIT((2, "EnumSubKey=%x\n", hkeySub));
    return hkeySub;
}       //EnumSubKey

/***LP  OpenNTTable - Open ACPI table in NT registry
 *
 *  ENTRY
 *      dwTabSig - table signature
 *
 *  EXIT-SUCCESS
 *      returns table registry handle
 *  EXIT-FAILURE
 *      returns NULL
 */

HKEY LOCAL OpenNTTable(DWORD dwTabSig)
{
    HKEY hkeyTab = NULL, hkey1 = NULL, hkey2 = NULL;
    static char szTabKey[] = "Hardware\\ACPI\\xxxx";

    ENTER((2, "OpenNTTable(TabSig=%s)\n", GetTableSigStr(dwTabSig)));

    if (dwTabSig == FADT_SIGNATURE)
    {
        memcpy(&szTabKey[strlen(szTabKey) - 4], "FADT", sizeof(ULONG));
    }
    else
    {
        memcpy(&szTabKey[strlen(szTabKey) - 4], &dwTabSig, sizeof(ULONG));
    }

    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szTabKey, 0, KEY_READ, &hkey1) ==
        ERROR_SUCCESS)
    {
        //
        // hkey1 is now "Hardware\ACPI\<TabSig>"
        //
        if ((hkey2 = EnumSubKey(hkey1, 0)) != NULL)
        {
            //
            // hkey2 is now "Hardware\ACPI\<TabSig>\<OEMID>"
            //
            RegCloseKey(hkey1);
            if ((hkey1 = EnumSubKey(hkey2, 0)) != NULL)
            {
                //
                // hkey1 is now "Hardware\ACPI\<TabSig>\<OEMID>\<OEMTabID>"
                //
                RegCloseKey(hkey2);
                if ((hkey2 = EnumSubKey(hkey1, 0)) != NULL)
                {
                    //
                    // hkey2 is now
                    // "Hardware\ACPI\<TabSig>\<OEMID>\<OEMTabID>\<OEMRev>"
                    //
                    hkeyTab = hkey2;
                }
            }
        }
    }

    if (hkey1 != NULL)
    {
        RegCloseKey(hkey1);
    }

    if ((hkey2 != NULL) && (hkeyTab != hkey2))
    {
        RegCloseKey(hkey2);
    }

    EXIT((2, "OpenNTTable=%x\n", hkeyTab));
    return hkeyTab;
}       //OpenNTTable

/***LP  GetNTTable - Get ACPI table from NT registry
 *
 *  ENTRY
 *      dwTabSig - table signature
 *
 *  EXIT-SUCCESS
 *      returns pointer to table
 *  EXIT-FAILURE
 *      returns NULL
 */

PBYTE LOCAL GetNTTable(DWORD dwTabSig)
{
    PBYTE pb = NULL;
    HKEY hkeyTab;

    ENTER((2, "GetNTTable(TabSig=%s)\n", GetTableSigStr(dwTabSig)));

    if ((hkeyTab = OpenNTTable(dwTabSig)) != NULL)
    {
        DWORD dwLen = 0;
        PSZ pszTabKey = "00000000";

        if (RegQueryValueEx(hkeyTab, pszTabKey, NULL, NULL, NULL, &dwLen) ==
            ERROR_SUCCESS)
        {
            if ((pb = MEMALLOC(dwLen)) != NULL)
            {
                if (RegQueryValueEx(hkeyTab, pszTabKey, NULL, NULL, pb, &dwLen)
                    != ERROR_SUCCESS)
                {
                    ERROR(("GetNTTable: failed to read table"));
                }
            }
            else
            {
                ERROR(("GetNTTable: failed to allocate table buffer"));
            }
        }
        else
        {
            ERROR(("GetNTTable: failed to read table key"));
        }
        RegCloseKey(hkeyTab);
    }
    else
    {
        ERROR(("GetNTTable: failed to get table %s", GetTableSigStr(dwTabSig)));
    }

    EXIT((2, "GetNTTable=%x\n", pb));
    return pb;
}       //GetNTTable

/***LP  GetTableBySig - Get table by its signature
 *
 *  ENTRY
 *      dwTabSig - table signature
 *      pdwTableAddr -> to hold physical address of table (can be NULL)
 *
 *  EXIT-SUCCESS
 *      returns pointer to table
 *  EXIT-FAILURE
 *      returns NULL
 */

PBYTE LOCAL GetTableBySig(DWORD dwTabSig, PDWORD pdwTableAddr)
{
    PBYTE pb = NULL;

    ENTER((2, "GetTableBySig(TabSig=%x,pdwAddr=%p)\n", dwTabSig, pdwTableAddr));

    if (gdwfASL & ASLF_NT)
    {
        if (((pb = GetNTTable(dwTabSig)) != NULL) && (pdwTableAddr != NULL))
        {
            *pdwTableAddr = 0;
        }
    }
  #ifndef WINNT
    else
    {
        pb = VxDGetTableBySig(dwTabSig, pdwTableAddr);
    }
  #endif

    EXIT((2, "GetTableBySig=%x\n", pb));
    return pb;
}       //GetTableBySig

/***LP  GetTableByAddr - Get table by its physical address
 *
 *  ENTRY
 *      dwTableAddr - physical address of table
 *      pdwTableSig -> to hold signature of table (can be NULL)
 *
 *  EXIT-SUCCESS
 *      returns pointer to table
 *  EXIT-FAILURE
 *      returns NULL
 */

PBYTE LOCAL GetTableByAddr(DWORD dwTableAddr, PDWORD pdwTableSig)
{
    PBYTE pb = NULL;

    ENTER((2, "GetTableByAddr(TabAddr=%x,pdwSig=%p)\n",
           dwTableAddr, pdwTableSig));

    if (gdwfASL & ASLF_NT)
    {
        ERROR(("GetTableByAddr: not supported by NT"));
    }
  #ifndef WINNT
    else
    {
        pb = VxDGetTableByAddr(dwTableAddr, pdwTableSig);
    }
  #endif

    EXIT((2, "GetTableByAddr=%x\n", pb));
    return pb;
}       //GetTableByAddr

/***LP  DumpAllTables - Dump all ACPI tables
 *
 *  ENTRY
 *	pfileOut -> output file
 *
 *  EXIT-SUCCESS
 *      returns ASLERR_NONE
 *  EXIT-FAILURE
 *      returns negative error code
 */

int LOCAL DumpAllTables(FILE *pfileOut)
{
    int rc = ASLERR_NONE;
    PBYTE pb;
    DWORD dwAddr;

    ENTER((1, "DumpAllTables(pfileOut=%p)\n", pfileOut));

    if (gdwfASL & ASLF_NT)
    {
        DumpTableBySig(pfileOut, RSDT_SIGNATURE);
        DumpTableBySig(pfileOut, FADT_SIGNATURE);
        DumpTableBySig(pfileOut, FACS_SIGNATURE);
        DumpTableBySig(pfileOut, SBST_SIGNATURE);
        DumpTableBySig(pfileOut, APIC_SIGNATURE);
        DumpTableBySig(pfileOut, SIG_BOOT);
	DumpTableBySig(pfileOut, SIG_DBGP);
        DumpTableBySig(pfileOut, DSDT_SIGNATURE);
        DumpTableBySig(pfileOut, SSDT_SIGNATURE);
        DumpTableBySig(pfileOut, PSDT_SIGNATURE);
    }
    else if ((pb = GetTableBySig(SIG_RSDP, &dwAddr)) != NULL)
    {
        if ((rc = DumpRSDP(pfileOut, pb, dwAddr)) == ASLERR_NONE)
        {
            DWORD dwRSDTAddr = ((PRSDP)pb)->RsdtAddress;
            DWORD dwTableSig;

            MEMFREE(pb);
            if ((pb = GetTableByAddr(dwRSDTAddr, &dwTableSig)) != NULL)
            {
                if ((rc = DumpTable(pfileOut, pb, dwRSDTAddr, dwTableSig)) ==
                    ASLERR_NONE)
                {
                    PRSDT pRSDT = (PRSDT)pb;
                    DWORD i, dwcEntries;

                    dwcEntries = (pRSDT->Header.Length -
                                  sizeof(DESCRIPTION_HEADER))/sizeof(ULONG);

                    for (i = 0; i < dwcEntries; ++i)
                    {
                        if ((rc = DumpTableByAddr(pfileOut, pRSDT->Tables[i]))
                            != ASLERR_NONE)
                        {
                            break;
                        }
                    }
                }

                if ((rc == ASLERR_NONE) &&
                    ((rc = DumpTableBySig(pfileOut, FACS_SIGNATURE)) ==
                     ASLERR_NONE))
                {
                    rc = DumpTableBySig(pfileOut, DSDT_SIGNATURE);
                }
            }
            else
            {
                rc = ASLERR_GET_TABLE;
            }
        }

        if (pb != NULL)
        {
            MEMFREE(pb);
        }
    }
    else
    {
	rc = ASLERR_GET_TABLE;
    }

    EXIT((1, "DumpAllTables=%d\n", rc));
    return rc;
}	//DumpAllTables

/***LP  DumpTableBySig - Dump an ACPI table by its Table Signature
 *
 *  ENTRY
 *	pfileOut -> output file
 *      dwTableSig - table signature
 *
 *  EXIT-SUCCESS
 *      returns ASLERR_NONE
 *  EXIT-FAILURE
 *      returns negative error code
 */

int LOCAL DumpTableBySig(FILE *pfileOut, DWORD dwTableSig)
{
    int rc = ASLERR_NONE;
    PBYTE pb;
    DWORD dwTableAddr;

    ENTER((1, "DumpTableBySig(pfileOut=%p,TableSig=%s)\n",
           pfileOut, GetTableSigStr(dwTableSig)));

    if (((PSZ)&dwTableSig)[0] == '*')
    {
        rc = DumpAllTables(pfileOut);
    }
    else if ((pb = GetTableBySig(dwTableSig, &dwTableAddr)) != NULL)
    {
        rc = DumpTable(pfileOut, pb, dwTableAddr, dwTableSig);
        MEMFREE(pb);
    }
    else
    {
        rc = ASLERR_GET_TABLE;
    }

    EXIT((1, "DumpTableBySig=%d\n", rc));
    return rc;
}       //DumpTableBySig

/***LP  DumpTableByAddr - Dump an ACPI table by its address
 *
 *  ENTRY
 *	pfileOut -> output file
 *      dwTableAddr - physical address of the table
 *
 *  EXIT-SUCCESS
 *      returns ASLERR_NONE
 *  EXIT-FAILURE
 *      returns negative error code
 */

int LOCAL DumpTableByAddr(FILE *pfileOut, DWORD dwTableAddr)
{
    int rc = ASLERR_NONE;
    PBYTE pb;
    DWORD dwTableSig;

    ENTER((1, "DumpTableByAddr(pfileOut=%p,TableAddr=%x)\n",
           pfileOut, dwTableAddr));

    if ((pb = GetTableByAddr(dwTableAddr, &dwTableSig)) != NULL)
    {
        rc = DumpTable(pfileOut, pb, dwTableAddr, dwTableSig);
        MEMFREE(pb);
    }
    else
    {
        rc = ASLERR_GET_TABLE;
    }

    EXIT((1, "DumpTableByAddr=%d\n", rc));
    return rc;
}       //DumpTableByAddr

/***LP  DumpRSDP - Dump the RSD PTR table
 *
 *  ENTRY
 *	pfileOut -> output file
 *      pb -> RSDP structure
 *      dwAddr - physical address of RSDP
 *
 *  EXIT-SUCCESS
 *      returns ASLERR_NONE
 *  EXIT-FAILURE
 *      returns negative error code
 */

int LOCAL DumpRSDP(FILE *pfileOut, PBYTE pb, DWORD dwAddr)
{
    int rc = ASLERR_NONE;

    ENTER((1, "DumpRSDP(pfileOut=%p,Addr=%x,pRSDP=%p)\n",
           pfileOut, dwAddr, pb));

    if (pfileOut != NULL)
    {
        DWORD dwOffset = 0;

        fprintf(pfileOut, szSectFmt, dwAddr, "RSD PTR");
        if (BinFPrintf(pfileOut, NULL, afmtRSDPTR, pb, &dwOffset, szOffsetFmt)
            != FERR_NONE)
        {
            ERROR(("DumpRSDP: failed to dump RSD PTR structure"));
            rc = ASLERR_INTERNAL_ERROR;
        }
    }
    else
    {
        rc = DumpTableBin(SIG_RSDP, dwAddr, pb, sizeof(RSDP));
    }

    EXIT((1, "DumpRSDP=%d\n", rc));
    return rc;
}       //DumpRSDP

/***LP  DumpTable - Dump an ACPI table
 *
 *  ENTRY
 *	pfileOut -> output file
 *      pb -> ACPI table
 *      dwTableAddr - physical address of table
 *      dwTableSig - signature of table
 *
 *  EXIT-SUCCESS
 *      returns ASLERR_NONE
 *  EXIT-FAILURE
 *      returns negative error code
 */

int LOCAL DumpTable(FILE *pfileOut, PBYTE pb, DWORD dwTableAddr,
                    DWORD dwTableSig)
{
    int rc = ASLERR_NONE;

    ENTER((1, "DumpTable(pfileOut=%p,pb=%p,TableAddr=%x,TableSig=%s)\n",
           pfileOut, pb, dwTableAddr, GetTableSigStr(dwTableSig)));

    if (dwTableSig == SIG_RSDP)
    {
        rc = DumpRSDP(pfileOut, pb, dwTableAddr);
    }
    else if (pfileOut != NULL)
    {
        rc = DumpTableTxt(pfileOut, pb, dwTableAddr, dwTableSig);
    }
    else
    {
        rc = DumpTableBin(dwTableSig, dwTableAddr, pb,
                          (dwTableSig == FACS_SIGNATURE)?
                            sizeof(FACS):
                            ((PDESCRIPTION_HEADER)pb)->Length);
    }

    EXIT((1, "DumpTable=%d\n", rc));
    return rc;
}       //DumpTable

/***LP  DumpTableTxt - Dump an ACPI table to a text file
 *
 *  ENTRY
 *	pfileOut -> output file
 *      pb -> ACPI table
 *      dwTableAddr - physical address of table
 *      dwTableSig - signature of table
 *
 *  EXIT-SUCCESS
 *      returns ASLERR_NONE
 *  EXIT-FAILURE
 *      returns negative error code
 */

int LOCAL DumpTableTxt(FILE *pfileOut, PBYTE pb, DWORD dwTableAddr,
                       DWORD dwTableSig)
{
    int rc = ASLERR_NONE;
    PFMT pfmt;
    DWORD dwFlags;

    ENTER((1, "DumpTableTxt(pfileOut=%p,pb=%p,TableAddr=%x,TableSig=%s)\n",
           pfileOut, pb, dwTableAddr, GetTableSigStr(dwTableSig)));

    if ((rc = FindTableFmt(dwTableSig, &pfmt, &dwFlags)) ==
        ASLERR_SIG_NOT_FOUND)
    {
        rc = ASLERR_NONE;
    }

    if (rc == ASLERR_NONE)
    {
        DWORD dwOffset = 0;

        fprintf(pfileOut, szSectFmt, dwTableAddr, GetTableSigStr(dwTableSig));
        if (!(dwFlags & TF_NOHDR) &&
            (BinFPrintf(pfileOut, NULL, afmtTableHdr, pb, &dwOffset,
                        szOffsetFmt) != FERR_NONE))
        {
            ERROR(("DumpTableTxt: failed to dump %s structure header",
                   GetTableSigStr(dwTableSig)));
            rc = ASLERR_INTERNAL_ERROR;
        }
        else if (pfmt != NULL)
        {
            if (BinFPrintf(pfileOut, NULL, pfmt, pb, &dwOffset, szOffsetFmt) !=
                FERR_NONE)
            {
                ERROR(("DumpTableTxt: failed to dump %s structure",
                       GetTableSigStr(dwTableSig)));
                rc = ASLERR_INTERNAL_ERROR;
            }
            else if ((dwTableSig == FADT_SIGNATURE) &&
                     (((PDESCRIPTION_HEADER)pb)->Revision > 1))
            {
                /*
                pfmt = (((PGRAS)pb)->id == REGSPACE_PCICFG)? afmtGRASPCICS:
                                                             afmtGRASRegAddr;*/
                fprintf(pfileOut, "; Reset Register\n");
                if ((BinFPrintf(pfileOut, NULL, afmtGRASCommon, pb, &dwOffset,
                                szOffsetFmt) != FERR_NONE) ||
                    (BinFPrintf(pfileOut, NULL, pfmt, pb, &dwOffset,
                                szOffsetFmt) != FERR_NONE) ||
                    (BinFPrintf(pfileOut, NULL, afmtFACP2, pb, &dwOffset,
                                szOffsetFmt) != FERR_NONE))
                {
                    ERROR(("DumpTableTxt: failed to dump extended %s structure",
                           GetTableSigStr(dwTableSig)));
                    rc = ASLERR_INTERNAL_ERROR;
                }
            }
            else if (dwTableSig == SIG_DBGP)
            {

                /*
                pfmt = (((PGRAS)pb)->id == REGSPACE_PCICFG)? afmtGRASPCICS:
                                                             afmtGRASRegAddr;*/

                fprintf(pfileOut, "; Debug Port Base Address\n");
                if ((BinFPrintf(pfileOut, NULL, afmtGRASCommon, pb, &dwOffset,
                                szOffsetFmt) != FERR_NONE) ||
                    (BinFPrintf(pfileOut, NULL, pfmt, pb, &dwOffset,
                                szOffsetFmt) != FERR_NONE))
                {
                    ERROR(("DumpTableTxt: failed to dump extended %s structure",
                           GetTableSigStr(dwTableSig)));
                    rc = ASLERR_INTERNAL_ERROR;
                }
            }
        }
        else
        {
            #define NUM_COLS    16
            PRSDT pRSDT;
            DWORD i, dwcEntries;
            PBYTE pbEnd;
            char szAMLName[_MAX_FNAME];
            char szBytes[NUM_COLS + 1];

            switch (dwTableSig)
            {
                case RSDT_SIGNATURE:
                    pRSDT = (PRSDT)pb;
                    dwcEntries = (pRSDT->Header.Length -
                                  sizeof(DESCRIPTION_HEADER))/sizeof(ULONG);
                    for (i = 0; i < dwcEntries; ++i)
                    {
                        fprintf(pfileOut, szOffsetFmt, dwOffset);
                        fprintf(pfileOut, "[%02d] %08lx\n",
                                i, pRSDT->Tables[i]);
                        dwOffset += sizeof(ULONG);
                    }
                    break;

                case DSDT_SIGNATURE:
                case SSDT_SIGNATURE:
                case PSDT_SIGNATURE:
                    strncpy(szAMLName, (PSZ)&dwTableSig, sizeof(DWORD));
                    strcpy(&szAMLName[sizeof(DWORD)], ".AML");
                    rc = UnAsmAML(szAMLName, dwTableAddr, pb,
                                  (PFNPRINT)fprintf, pfileOut);
                    break;

                default:
                    //
                    // Don't return error because we want to continue.
                    //
                    WARN(("DumpTableTxt: unexpected table signature %s",
                          GetTableSigStr(dwTableSig)));

                    pbEnd = pb + ((PDESCRIPTION_HEADER)pb)->Length;
                    pb += sizeof(DESCRIPTION_HEADER);
                    i = 0;
                    while (pb < pbEnd)
                    {
                        szBytes[i] = (char)(isprint(*pb)? *pb: '.');
                        if (i == 0)
                        {
                            fprintf(pfileOut, szOffsetFmt, dwOffset);
                            fprintf(pfileOut, "%02x", *pb);
                        }
                        else if (i == NUM_COLS/2)
                        {
                            fprintf(pfileOut, "-%02x", *pb);
                        }
                        else
                        {
                            fprintf(pfileOut, ",%02x", *pb);
                        }
                        i++;
                        if (i == NUM_COLS)
                        {
                            szBytes[i] = '\0';
                            fprintf(pfileOut, "  ;%s\n", szBytes);
                            i = 0;
                        }
                        dwOffset += sizeof(BYTE);
                        pb += sizeof(BYTE);
                    }

                    if (i < NUM_COLS)
                    {
                        szBytes[i] = '\0';
                        while (i < NUM_COLS)
                        {
                            fprintf(pfileOut, "   ");
                            i++;
                        }
                        fprintf(pfileOut, "  ;%s\n", szBytes);
                    }
            }
        }
    }

    EXIT((1, "DumpTableTxt=%d\n", rc));
    return rc;
}       //DumpTableTxt

/***LP  DumpTableBin - Dump an ACPI table to a binary file
 *
 *  ENTRY
 *      dwTableSig - table signature
 *      dwAddr - physical address of table
 *      pb -> ACPI table
 *      dwLen - length of table
 *
 *  EXIT-SUCCESS
 *      returns ASLERR_NONE
 *  EXIT-FAILURE
 *      returns negative error code
 */

int LOCAL DumpTableBin(DWORD dwTableSig, DWORD dwAddr, PBYTE pb, DWORD dwLen)
{
    int rc = ASLERR_NONE;
    char szBinFile[_MAX_FNAME];
    FILE *pfile;

    ENTER((1, "DumpTableBin(TableSig=%s,Addr=%x,pb=%p,Len=%d)\n",
           GetTableSigStr(dwTableSig), dwAddr, pb, dwLen));

    strncpy(szBinFile, (PSZ)&dwTableSig, sizeof(DWORD));
    sprintf(&szBinFile[sizeof(DWORD)], "%04x", (WORD)dwAddr);
    strcpy(&szBinFile[sizeof(DWORD) + 4], ".BIN");
    if ((pfile = fopen(szBinFile, "wb")) == NULL)
    {
        ERROR(("DumpTableBin: failed to create file %s", szBinFile));
        rc = ASLERR_CREATE_FILE;
    }
    else
    {
        if (fwrite(pb, dwLen, 1, pfile) != 1)
        {
            ERROR(("DumpTableBin: failed to write to file %s", szBinFile));
            rc = ASLERR_WRITE_FILE;
        }
        fclose(pfile);
    }

    EXIT((1, "DumpTableBin=%d\n", rc));
    return rc;
}       //DumpTableBin

/***LP  FindTableFmt - Find the appropriate table format structure
 *
 *  ENTRY
 *      dwTableSig - table signature
 *      ppfmt -> to hold pfmt found
 *      pdwFlags -> to hold table flags
 *
 *  EXIT-SUCCESS
 *      returns ASLERR_NONE
 *  EXIT-FAILURE
 *      returns negative error code
 */

int LOCAL FindTableFmt(DWORD dwTableSig, PFMT *ppfmt, PDWORD pdwFlags)
{
    int rc = ASLERR_NONE;
    int i;

    ENTER((1, "FindTableFmt(TableSig=%s,ppfmt=%p,pdwFlags=%p)\n",
           GetTableSigStr(dwTableSig), ppfmt, pdwFlags));

    for (i = 0; FmtTable[i].dwTableSig != 0; ++i)
    {
        if (dwTableSig == FmtTable[i].dwTableSig)
        {
            *ppfmt = FmtTable[i].pfmt;
            *pdwFlags = FmtTable[i].dwFlags;
            break;
        }
    }

    if (FmtTable[i].dwTableSig == 0)
    {
        *ppfmt = NULL;
        *pdwFlags = 0;
        rc = ASLERR_SIG_NOT_FOUND;
    }

    EXIT((1, "FindTableFmt=%d (pfmt=%p,Flags=%x)\n", rc, *ppfmt, *pdwFlags));
    return rc;
}       //FindTableFmt

/***LP  GetTableSigStr - Get table signature string
 *
 *  ENTRY
 *      dwTableSig - table signature
 *
 *  EXIT
 *      returns the table signature string
 */

PSZ LOCAL GetTableSigStr(DWORD dwTableSig)
{
    static char szTableSig[5] = {0};

    ENTER((2, "GetTableSigStr(TableSig=%08x)\n", dwTableSig));

    strncpy(szTableSig, (PSZ)&dwTableSig, sizeof(DWORD));

    EXIT((2, "GetTableSigStr=%s\n", szTableSig));
    return szTableSig;
}       //GetTableSigStr

/***LP	ValidateTable - Validate the given table
 *
 *  ENTRY
 *	pbTable -> Table
 *	dwLen - Table length
 *
 *  EXIT-SUCCESS
 *	returns TRUE
 *  EXIT-FAILURE
 *	returns FALSE
 */

BOOL LOCAL ValidateTable(PBYTE pbTable, DWORD dwLen)
{
    BOOL rc = TRUE;
    DWORD dwTableSig, dwTableLen = 0;
    BOOL fNeedChkSum = FALSE;

    ENTER((2, "ValidateTable(pbTable=%x,Len=%d)\n", pbTable, dwLen));

    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:
	case SIG_DBGP:
	    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
	    {
		WARN(("ValidateTable: invalid table signature %s",
                      GetTableSigStr(dwTableSig)));
		rc = FALSE;
	    }
    }

    if (dwTableLen > dwLen)
    {
        WARN(("ValidateTable: invalid length %d in table %s",
              dwTableLen, GetTableSigStr(dwTableSig)));
	rc = FALSE;
    }

    if ((rc == TRUE) && fNeedChkSum &&
        (ComputeDataChkSum(pbTable, dwTableLen) != 0))
    {
        WARN(("ValidateTable: invalid checksum in table %s",
              GetTableSigStr(dwTableSig)));
	rc = FALSE;
    }

    EXIT((2, "ValidateTable=%x\n", rc));
    return rc;
}	//ValidateTable

/***LP	IsALikelySig - Check if a table signature is possibly valid
 *
 *  ENTRY
 *	dwTableSig - table signature
 *
 *  EXIT-SUCCESS
 *	returns TRUE
 *  EXIT-FAILURE
 *	returns FALSE
 */

BOOL LOCAL IsALikelySig(DWORD dwTableSig)
{
    BOOL rc = TRUE;
    int i, ch;

    ENTER((2, "IsALikelySig(dwTableSig=%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

#endif  //ifdef __UNASM