/******************************************************************************
 *
 * Module Name: atexec - Support routines for ACPICA API test suite
 *                       based on AcpiExec aeexec.c
 *
 *****************************************************************************/

/******************************************************************************
 *
 * 1. Copyright Notice
 *
 * Some or all of this work - Copyright (c) 1999 - 2015, Intel Corp.
 * All rights reserved.
 *
 * 2. License
 *
 * 2.1. This is your license from Intel Corp. under its intellectual property
 * rights. You may have additional license terms from the party that provided
 * you this software, covering your right to use that party's intellectual
 * property rights.
 *
 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
 * copy of the source code appearing in this file ("Covered Code") an
 * irrevocable, perpetual, worldwide license under Intel's copyrights in the
 * base code distributed originally by Intel ("Original Intel Code") to copy,
 * make derivatives, distribute, use and display any portion of the Covered
 * Code in any form, with the right to sublicense such rights; and
 *
 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
 * license (with the right to sublicense), under only those claims of Intel
 * patents that are infringed by the Original Intel Code, to make, use, sell,
 * offer to sell, and import the Covered Code and derivative works thereof
 * solely to the minimum extent necessary to exercise the above copyright
 * license, and in no event shall the patent license extend to any additions
 * to or modifications of the Original Intel Code. No other license or right
 * is granted directly or by implication, estoppel or otherwise;
 *
 * The above copyright and patent license is granted only if the following
 * conditions are met:
 *
 * 3. Conditions
 *
 * 3.1. Redistribution of Source with Rights to Further Distribute Source.
 * Redistribution of source code of any substantial portion of the Covered
 * Code or modification with rights to further distribute source must include
 * the above Copyright Notice, the above License, this list of Conditions,
 * and the following Disclaimer and Export Compliance provision. In addition,
 * Licensee must cause all Covered Code to which Licensee contributes to
 * contain a file documenting the changes Licensee made to create that Covered
 * Code and the date of any change. Licensee must include in that file the
 * documentation of any changes made by any predecessor Licensee. Licensee
 * must include a prominent statement that the modification is derived,
 * directly or indirectly, from Original Intel Code.
 *
 * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
 * Redistribution of source code of any substantial portion of the Covered
 * Code or modification without rights to further distribute source must
 * include the following Disclaimer and Export Compliance provision in the
 * documentation and/or other materials provided with distribution. In
 * addition, Licensee may not authorize further sublicense of source of any
 * portion of the Covered Code, and must include terms to the effect that the
 * license from Licensee to its licensee is limited to the intellectual
 * property embodied in the software Licensee provides to its licensee, and
 * not to intellectual property embodied in modifications its licensee may
 * make.
 *
 * 3.3. Redistribution of Executable. Redistribution in executable form of any
 * substantial portion of the Covered Code or modification must reproduce the
 * above Copyright Notice, and the following Disclaimer and Export Compliance
 * provision in the documentation and/or other materials provided with the
 * distribution.
 *
 * 3.4. Intel retains all right, title, and interest in and to the Original
 * Intel Code.
 *
 * 3.5. Neither the name Intel nor any other trademark owned or controlled by
 * Intel shall be used in advertising or otherwise to promote the sale, use or
 * other dealings in products derived from or relating to the Covered Code
 * without prior written authorization from Intel.
 *
 * 4. Disclaimer and Export Compliance
 *
 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
 * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
 * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
 * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
 * PARTICULAR PURPOSE.
 *
 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
 * LIMITED REMEDY.
 *
 * 4.3. Licensee shall not export, either directly or indirectly, any of this
 * software or system incorporating such software without first obtaining any
 * required license or other approval from the U. S. Department of Commerce or
 * any other agency or department of the United States Government. In the
 * event Licensee exports any such software from the United States or
 * re-exports any such software from a foreign destination, Licensee shall
 * ensure that the distribution and export/re-export of the software is in
 * compliance with all laws, regulations, orders, or other restrictions of the
 * U.S. Export Administration Regulations. Licensee agrees that neither it nor
 * any of its subsidiaries will export/re-export any technical data, process,
 * software, or service, directly or indirectly, to any country for which the
 * United States government or any agency thereof requires an export license,
 * other governmental approval, or letter of assurance, without first obtaining
 * such license, approval or letter.
 *
 *****************************************************************************/

#include "acpi.h"
#include "accommon.h"
#include "acparser.h"
#include "amlcode.h"
#include "acnamesp.h"
#include "acdebug.h"
#include "actables.h"
#include "atcommon.h"

#include <stdio.h>
#include <signal.h>

#define _COMPONENT          ACPI_TOOLS
        ACPI_MODULE_NAME    ("atexec")

/*
#define EXAMPLE1_SSDT
*/
#ifdef EXAMPLE1_SSDT
#include "at_ssdt2_1.c"
#include "at_ssdt2_2.c"
#include "at_ssdt2_3.c"
#else
static unsigned char Ssdt1Code[] =
{
    0x53,0x53,0x44,0x54,0x30,0x00,0x00,0x00, /* 00000000    "SSDT0..." */
    0x01,0xB8,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008    "..Intel." */
    0x4D,0x61,0x6E,0x79,0x00,0x00,0x00,0x00, /* 00000010    "Many...." */
    0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018    "....INTL" */
    0x24,0x04,0x03,0x20,0x14,0x0B,0x5F,0x54, /* 00000020    "$.. .._T" */
    0x39,0x38,0x00,0x70,0x0A,0x04,0x60,0xA4, /* 00000028    "98.p..`." */
};

static unsigned char Ssdt2Code[] =
{
    0x53,0x53,0x44,0x54,0x30,0x00,0x00,0x00, /* 00000000    "SSDT0..." */
    0x01,0xB7,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008    "..Intel." */
    0x4D,0x61,0x6E,0x79,0x00,0x00,0x00,0x00, /* 00000010    "Many...." */
    0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018    "....INTL" */
    0x24,0x04,0x03,0x20,0x14,0x0B,0x5F,0x54, /* 00000020    "$.. .._T" */
    0x39,0x39,0x00,0x70,0x0A,0x04,0x60,0xA4, /* 00000028    "99.p..`." */
};

static unsigned char Ssdt3Code[] =
{
    0x53,0x53,0x44,0x54,0x30,0x00,0x00,0x00, /* 00000000    "SSDT0..." */
    0x01,0xAF,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008    "..Intel." */
    0x4D,0x61,0x6E,0x79,0x00,0x00,0x00,0x00, /* 00000010    "Many...." */
    0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018    "....INTL" */
    0x24,0x04,0x03,0x20,0x14,0x0B,0x5F,0x54, /* 00000020    "$.. .._T" */
    0x39,0x41,0x00,0x70,0x0A,0x04,0x60,0xA4, /* 00000028    "9A.p..`." */
};
#endif

static unsigned char Psdt1Code[] =
{
    0x50,0x53,0x44,0x54,0x30,0x00,0x00,0x00, /* 00000000    "PSDT0..." */
    0x01,0xB1,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008    "..Intel." */
    0x4D,0x61,0x6E,0x79,0x00,0x00,0x00,0x00, /* 00000010    "Many...." */
    0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018    "....INTL" */
    0x24,0x04,0x03,0x20,0x14,0x0B,0x5F,0x54, /* 00000020    "$.. .._T" */
    0x39,0x42,0x00,0x70,0x0A,0x04,0x60,0xA4, /* 00000028    "9B.p..`." */
};

static unsigned char Oem1Code[] =
{
    0x4F,0x45,0x4D,0x31,0x38,0x00,0x00,0x00, /* 00000000    "OEM18..." */
    0x01,0x4B,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008    ".KIntel." */
    0x4D,0x61,0x6E,0x79,0x00,0x00,0x00,0x00, /* 00000010    "Many...." */
    0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018    "....INTL" */
    0x18,0x09,0x03,0x20,0x08,0x5F,0x58,0x54, /* 00000020    "... ._XT" */
    0x32,0x0A,0x04,0x14,0x0C,0x5F,0x58,0x54, /* 00000028    "2...._XT" */
    0x31,0x00,0x70,0x01,0x5F,0x58,0x54,0x32, /* 00000030    "1.p._XT2" */

};

#define FADT_DESCRIPTOR_REV2    ACPI_TABLE_FADT
#define RSDT_DESCRIPTOR_REV1    ACPI_TABLE_RSDT


/*
 * We need a local FADT so that the hardware subcomponent will function,
 * even though the underlying OSD HW access functions don't do
 * anything.
 */
static ACPI_TABLE_RSDP      LocalRSDP;
static ACPI_TABLE_FADT      LocalFADT;
static ACPI_TABLE_FACS      LocalFACS;
static ACPI_TABLE_HEADER    LocalDSDT;
static ACPI_TABLE_HEADER    LocalTEST;
static ACPI_TABLE_HEADER    LocalBADTABLE;

#define RSDT_TABLES             9
/* Covers both 32-bit and 64-bit addresses */
#define RSDT_SIZE               (sizeof (ACPI_TABLE_XSDT) +\
        ((RSDT_TABLES -1) * sizeof (UINT64)))

static UINT8                    MemRSDT[RSDT_SIZE];
static RSDT_DESCRIPTOR_REV1     *LocalRSDT = (RSDT_DESCRIPTOR_REV1 *)MemRSDT;

static FADT_DESCRIPTOR_REV2     LocalFADT2;

#define ACPI_MAX_INIT_TABLES (10)
static ACPI_TABLE_DESC      Tables[ACPI_MAX_INIT_TABLES];

/* Like AeCtrlCHandler */
void __cdecl
AtSigHandler (
    int                     Sig)
{
    if (Sig == SIGINT)
    {
        signal (SIGINT, SIG_IGN);
        printf ("Caught a ctrl-c\n\n");
#ifdef ACPI_DEBUGGER
        if (AcpiGbl_MethodExecuting)
        {
            AcpiGbl_AbortMethod = TRUE;
            signal (SIGINT, AtSigHandler);
            return;
        }
#endif
    }
    else
    {
        printf ("Caught Signal %d\n\n", Sig);
    }
    exit (AtRetSigTerm);
}


/*******************************************************************************
 *
 * FUNCTION:    AtInitializeTables
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Wrappper for AcpiInitializeTables()
 *
 ******************************************************************************/
ACPI_STATUS
AtInitializeTables (
    BOOLEAN                 AllowResize)
{
    return (AcpiInitializeTables(Tables, ACPI_MAX_INIT_TABLES, AllowResize));
}


/* Copy of AcpiTbInitGenericAddress */
static void
AtTbInitGenericAddress (
    ACPI_GENERIC_ADDRESS    *NewGasStruct,
    UINT8                   BitWidth,
    ACPI_PHYSICAL_ADDRESS   Address)
{

    NewGasStruct->Address = Address;
    NewGasStruct->SpaceId = ACPI_ADR_SPACE_SYSTEM_IO;
    NewGasStruct->BitWidth = BitWidth;
    NewGasStruct->BitOffset = 0;
    NewGasStruct->AccessWidth = 0;
}


/*******************************************************************************
 *
 * FUNCTION:    AtBuildLocalDSDT
 *
 * PARAMETERS:  UserTable       - Pointer to User's DSDT AML code or NULL
 *              BldTask         - Build Task for errors intrusion
 *              Actual_DSDT     - Where a pointer to the table is returned
 *
 * RETURN:      None
 *
 * DESCRIPTION: Get an DSDT either from User supplied table or use
 *              the simle local one. Perform errors intrusion handling.
 *
 ******************************************************************************/

static void
AtBuildLocalDSDT (
    ACPI_TABLE_HEADER       *UserTable,
    BLD_TABLES_TASK         BldTask,
    ACPI_TABLE_HEADER       **Actual_DSDT)
{
    /*
     * Examine the incoming user table. At this point, it has been verified
     * to be either a DSDT, SSDT, or a PSDT, but they must be handled differently
     */
    if (UserTable && !strncmp ((char *) UserTable->Signature, ACPI_SIG_DSDT, 4))
    {
        /* User DSDT is installed directly into the FADT */

        *Actual_DSDT = UserTable;
    }
    else
    {
        /*
         * Build a local DSDT because either there is no incoming table
         * or it is an SSDT or PSDT
         */

        memset (&LocalDSDT, 0, sizeof (ACPI_TABLE_HEADER));
        strncpy (LocalDSDT.Signature, ACPI_SIG_DSDT, 4);
        LocalDSDT.Revision = 1;
        LocalDSDT.Length = sizeof (ACPI_TABLE_HEADER);
        LocalDSDT.Checksum = (UINT8)(0 - AcpiTbChecksum
            ((UINT8 *)&LocalDSDT, LocalDSDT.Length));
        *Actual_DSDT = &LocalDSDT;
    }

    if (BldTask.ErrScale & BAD_SIGNATURE_DSDT)
    {
        strncpy ((*Actual_DSDT)->Signature, "BADS", 4);
    }
    if (BldTask.ErrScale & BAD_CHECKSUM_DSDT)
    {
        (*Actual_DSDT)->Checksum = (UINT8)~(*Actual_DSDT)->Checksum;
    }
    if (BldTask.ErrScale & BAD_LENGTH_HDR_DSDT)
    {
        (*Actual_DSDT)->Length = sizeof (ACPI_TABLE_HEADER) - 1;
    }
}


/*******************************************************************************
 *
 * FUNCTION:    AtBuildLocalFACS1
 *
 * PARAMETERS:  LocalFACS       - Pointer to the local FACS template
 *              BldTask         - Build Task for errors intrusion
 *
 * RETURN:      None
 *
 * DESCRIPTION: Build Revision 1 FACS image, perform errors intrusion handling.
 *
 ******************************************************************************/

static void
AtBuildLocalFACS1 (
    ACPI_TABLE_FACS    *LocalFACS,
    BLD_TABLES_TASK         BldTask)
{
    memset (LocalFACS, 0, sizeof (ACPI_TABLE_FACS));

    strncpy (LocalFACS->Signature, ACPI_SIG_FACS, 4);
    if (BldTask.ErrScale & BAD_SIGNATURE_FACS)
    {
        strncpy (LocalFACS->Signature, "BADS", 4);
    }

    LocalFACS->Length = sizeof (ACPI_TABLE_FACS);
    if (BldTask.ErrScale & BAD_LENGTH_HDR_FACS)
    {
        LocalFACS->Length = sizeof (ACPI_TABLE_HEADER) - 1;
    }
    if (BldTask.ErrScale & BAD_LENGTH_DSC_FACS)
    {
        LocalFACS->Length = sizeof (ACPI_TABLE_FACS) - 1;
    }

    LocalFACS->GlobalLock = 0x11AA0011;
//    LocalFACS->GlobalLock = 0;

    LocalFACS->FirmwareWakingVector = 0xAFAEADAC;
}


/*******************************************************************************
 *
 * FUNCTION:    AtBuildLocalFADT1
 *
 * PARAMETERS:  LocalFADT       - Pointer to the local FADT template
 *              LocalFACS       - Pointer to the local FACS template
 *              ActualDSDT      - Where a pointer to the table is returned
 *              UserTable       - Pointer to User's DSDT AML code or NULL
 *              BldTask         - Build Task for errors intrusion
 *
 * RETURN:      None
 *
 * DESCRIPTION: Build Revision 1 FADT image, perform errors intrusion handling.
 *
 ******************************************************************************/

static void
AtBuildLocalFADT1 (
    ACPI_TABLE_FADT         *LocalFADT,
    ACPI_TABLE_FACS         *LocalFACS,
    ACPI_TABLE_HEADER       **ActualDSDT,
    ACPI_TABLE_HEADER       *UserTable,
    BLD_TABLES_TASK         BldTask)
{
    if (BldTask.NoTableScale & BLD_NO_FACS)
    {
        BldTask.ErrScale |= NULL_ADDRESS_FACS;
    }
    if (!(BldTask.ErrScale & NULL_ADDRESS_FACS))
    {
        /* Build a FACS */
        AtBuildLocalFACS1(LocalFACS, BldTask);
    }

    if (BldTask.NoTableScale & BLD_NO_DSDT)
    {
        BldTask.ErrScale |= NULL_ADDRESS_DSDT;
    }
    if (!(BldTask.ErrScale & NULL_ADDRESS_DSDT))
    {
        /* Build a DSDT */
        AtBuildLocalDSDT(UserTable, BldTask, ActualDSDT);
    }

    memset (LocalFADT, 0, sizeof (ACPI_TABLE_FADT));
    strncpy (LocalFADT->Header.Signature, ACPI_SIG_FADT, 4);

    if (BldTask.ErrScale & BAD_SIGNATURE_FADT)
    {
        strncpy (LocalFADT->Header.Signature, "BADS", 4);
    }

    if (BldTask.ErrScale & NULL_ADDRESS_FACS)
    {
        LocalFADT->Facs = ACPI_PTR_TO_PHYSADDR(NULL);
    }
    else
    {
        LocalFADT->Facs = ACPI_PTR_TO_PHYSADDR (LocalFACS);
    }
    if (BldTask.ErrScale & NULL_ADDRESS_DSDT)
    {
        LocalFADT->Dsdt = ACPI_PTR_TO_PHYSADDR(NULL);
    }
    else
    {
        LocalFADT->Dsdt = ACPI_PTR_TO_PHYSADDR (*ActualDSDT);
    }

    /* System port address of the SMI Command Port */
    if (BldTask.ErrScale & ZERO_SMICMD_FADT)
    {
        LocalFADT->SmiCommand = 0;
    }
    else
    {
        LocalFADT->SmiCommand = 0x10;
    }

    LocalFADT->AcpiEnable = 0x01;
    LocalFADT->AcpiDisable = 0x02;
    LocalFADT->Header.Revision = 1;
    LocalFADT->Header.Length = ACPI_FADT_OFFSET (ResetRegister); //sizeof (FADT_DESCRIPTOR);
    LocalFADT->Gpe0BlockLength = 16;
    LocalFADT->Gpe1BlockLength = 6;
    LocalFADT->Gpe1Base = 96;

    LocalFADT->Pm1EventLength = 4;
    LocalFADT->Pm1ControlLength = 2;
    LocalFADT->Pm2ControlLength = 1; /* optional */
    LocalFADT->PmTimerLength = 4;

    LocalFADT->Gpe0Block = 0x00001234;
    LocalFADT->Gpe1Block = 0x00005678;

    LocalFADT->Pm1aEventBlock = 0x00001aaa;
    LocalFADT->Pm1bEventBlock = 0;
    LocalFADT->PmTimerBlock = 0xA00;
    LocalFADT->Pm1aControlBlock = 0xB00;
    LocalFADT->Pm2ControlBlock = 0xD00; /* optional */

    if (BldTask.ErrScale & BAD_LENGTH_HDR_FADT)
    {
        LocalFADT->Header.Length = sizeof (ACPI_TABLE_HEADER) - 1;
    }
    if (BldTask.ErrScale & BAD_LENGTH_DSC_FADT)
    {
        LocalFADT->Header.Length = ACPI_FADT_OFFSET (ResetRegister) - 1;
    }

    /* Complete the FADT with the checksum */

    LocalFADT->Header.Checksum = (UINT8)(0 - AcpiTbChecksum
        ((UINT8 *)&LocalFADT->Header, LocalFADT->Header.Length));
    if (BldTask.ErrScale & BAD_CHECKSUM_FADT)
    {
        LocalFADT->Header.Checksum = (UINT8)~LocalFADT->Header.Checksum;
    }
}

/*******************************************************************************
 *
 * FUNCTION:    AtBuildLocalFADT2
 *
 * PARAMETERS:  LocalFADT       - Pointer to the local FADT template
 *              LocalFACS       - Pointer to the local FACS template
 *              ActualDSDT      - Where a pointer to the table is returned
 *              UserTable       - Pointer to User's DSDT AML code or NULL
 *              BldTask         - Build Task for errors intrusion
 *
 * RETURN:      None
 *
 * DESCRIPTION: Build Revision 2 FADT image, perform errors intrusion handling.
 *
 ******************************************************************************/

static void
AtBuildLocalFADT2 (
    FADT_DESCRIPTOR_REV2    *LocalFADT,
    ACPI_TABLE_FACS    *LocalFACS,
    ACPI_TABLE_HEADER       **ActualDSDT,
    ACPI_TABLE_HEADER       *UserTable,
    BLD_TABLES_TASK         BldTask)
{
    if (BldTask.NoTableScale & BLD_NO_FACS)
    {
        BldTask.ErrScale |= NULL_ADDRESS_FACS;
    }
    if (!(BldTask.ErrScale & NULL_ADDRESS_FACS))
    {
        /* Build a FACS */
        AtBuildLocalFACS1(LocalFACS, BldTask);
    }

    if (BldTask.NoTableScale & BLD_NO_DSDT)
    {
        BldTask.ErrScale |= NULL_ADDRESS_DSDT;
    }
    if (!(BldTask.ErrScale & NULL_ADDRESS_DSDT))
    {
        /* Build a DSDT */
        AtBuildLocalDSDT(UserTable, BldTask, ActualDSDT);
    }

    memset (LocalFADT, 0, sizeof (ACPI_TABLE_FADT));
    strncpy (LocalFADT->Header.Signature, ACPI_SIG_FADT, 4);

    if (BldTask.ErrScale & BAD_SIGNATURE_FADT)
    {
        strncpy (LocalFADT->Header.Signature, "BADS", 4);
    }

    if (BldTask.ErrScale & NULL_ADDRESS_FACS)
    {
        LocalFADT->XFacs = ACPI_PTR_TO_PHYSADDR(NULL);
    }
    else
    {
        LocalFADT->XFacs = ACPI_PTR_TO_PHYSADDR (LocalFACS);
    }
    if (BldTask.ErrScale & NULL_ADDRESS_DSDT)
    {
        LocalFADT->XDsdt = ACPI_PTR_TO_PHYSADDR(NULL);
    }
    else
    {
        LocalFADT->XDsdt = ACPI_PTR_TO_PHYSADDR (*ActualDSDT);
    }

    /* System port address of the SMI Command Port */
    if (BldTask.ErrScale & ZERO_SMICMD_FADT)
    {
        LocalFADT->SmiCommand = 0;
    }
    else
    {
        LocalFADT->SmiCommand = 0x10;
    }

    LocalFADT->AcpiEnable = 0x01;
    LocalFADT->AcpiDisable = 0x02;
    LocalFADT->Header.Revision = 3;
    LocalFADT->Header.Length = sizeof (FADT_DESCRIPTOR_REV2);
    LocalFADT->Gpe0BlockLength = 16;
    LocalFADT->Gpe1BlockLength = 6;
    LocalFADT->Gpe1Base = 96;

    LocalFADT->Pm1EventLength = 4;
    LocalFADT->Pm1ControlLength = 4;
    LocalFADT->Pm2ControlLength = 1; /* optional */
    LocalFADT->PmTimerLength = 8;

    /*
     * Convert the addresses to V2.0 GAS structures
     */

    AtTbInitGenericAddress (&LocalFADT->XGpe0Block, 0,
                             (ACPI_PHYSICAL_ADDRESS)   0x12340000);
    AtTbInitGenericAddress (&LocalFADT->XGpe1Block, 0,
                             (ACPI_PHYSICAL_ADDRESS)   0x56780000);

    AtTbInitGenericAddress (&LocalFADT->XPm1aEventBlock, LocalFADT->Pm1EventLength,
                             (ACPI_PHYSICAL_ADDRESS)   0x1aaa0000);
    AtTbInitGenericAddress (&LocalFADT->XPm1bEventBlock, LocalFADT->Pm1EventLength,
                             (ACPI_PHYSICAL_ADDRESS)   0);
    AtTbInitGenericAddress (&LocalFADT->XPm1aControlBlock, LocalFADT->Pm1ControlLength,
                             (ACPI_PHYSICAL_ADDRESS)   0xB0);
    AtTbInitGenericAddress (&LocalFADT->XPm1bControlBlock, LocalFADT->Pm1ControlLength,
                             (ACPI_PHYSICAL_ADDRESS)   0);
    AtTbInitGenericAddress (&LocalFADT->XPm2ControlBlock, LocalFADT->Pm2ControlLength,
                             (ACPI_PHYSICAL_ADDRESS)   0xD0);
    AtTbInitGenericAddress (&LocalFADT->XPmTimerBlock, LocalFADT->PmTimerLength,
                             (ACPI_PHYSICAL_ADDRESS)   0xA0);

    if (BldTask.ErrScale & BAD_LENGTH_HDR_FADT)
    {
        LocalFADT->Header.Length = sizeof (ACPI_TABLE_HEADER) - 1;
    }
    if (BldTask.ErrScale & BAD_LENGTH_DSC_FADT)
    {
        LocalFADT->Header.Length = sizeof (FADT_DESCRIPTOR_REV2) - 1;
    }

    /* Complete the FADT with the checksum */

    LocalFADT->Header.Checksum = (UINT8)(0 - AcpiTbChecksum
        ((UINT8 *)&LocalFADT->Header, LocalFADT->Header.Length));
    if (BldTask.ErrScale & BAD_CHECKSUM_FADT)
    {
        LocalFADT->Header.Checksum = (UINT8)~LocalFADT->Header.Checksum;
    }
}


/*******************************************************************************
 *
 * FUNCTION:    AtBuildLocalRSDT
 *
 * PARAMETERS:  LocalRSDT       - Pointer to the local FADT template
 *              UserTable       - Pointer to User's DSDT AML code or NULL
 *              BldTask         - Build Task for errors intrusion
 *
 * RETURN:      None
 *
 * DESCRIPTION: Build Revision 1 RSDT image, perform errors intrusion handling.
 *
 ******************************************************************************/

static void
AtBuildLocalRSDT (
    RSDT_DESCRIPTOR_REV1    *LocalRSDT,
    ACPI_TABLE_HEADER       *UserTable,
    BLD_TABLES_TASK         BldTask)
{
    ACPI_TABLE_HEADER       *Actual_DSDT = NULL;
    int                     i = 0;

    if (BldTask.ErrScale & NOT_PRESENT_FADT)
    {
        BldTask.NoTableScale |= BLD_NO_FADT;
    }

    memset (LocalRSDT, 0, RSDT_SIZE);

    strncpy (LocalRSDT->Header.Signature, ACPI_SIG_RSDT, 4);
    if (BldTask.ErrScale & BAD_SIGNATURE_RSDT)
    {
        strncpy (LocalRSDT->Header.Signature, "BADS", 4);
    }

    if (!(BldTask.NoTableScale & BLD_NO_FADT))
    {
        /* Build a FADT so we can test the hardware/event init */
        AtBuildLocalFADT1(&LocalFADT, &LocalFACS, &Actual_DSDT, UserTable, BldTask);

        LocalRSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&LocalFADT);
    }

    if (Actual_DSDT &&
        (!strncmp ((char *) Actual_DSDT->Signature, ACPI_SIG_SSDT, 4) ||
         !strncmp ((char *) Actual_DSDT->Signature, ACPI_SIG_PSDT, 4)))
    {
        LocalRSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (UserTable);
    }

    if (!(BldTask.NoTableScale & BLD_NO_BADT))
    {
        /*
         * Build a fake table with a bad signature so that
         * we make sure that the CA core ignores it
         */

        memset (&LocalBADTABLE, 0, sizeof (ACPI_TABLE_HEADER));
        strncpy (LocalBADTABLE.Signature, "BAD!", 4);

        LocalBADTABLE.Revision = 1;
        LocalBADTABLE.Length = sizeof (ACPI_TABLE_HEADER);

        LocalRSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&LocalBADTABLE);
    }

    /* Install two SSDTs to test multiple table support */

    if (!(BldTask.NoTableScale & BLD_NO_SSDT1))
    {
        LocalRSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&Ssdt1Code);
        LocalRSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&Psdt1Code);
    }
    if (!(BldTask.NoTableScale & BLD_NO_SSDT2))
    {
        LocalRSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&Ssdt2Code);
        LocalRSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&Ssdt3Code);
    }

    /* Install the OEM1 table to test LoadTable */

    if (!(BldTask.NoTableScale & BLD_NO_OEM1))
    {
        LocalRSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&Oem1Code);
    }


    /* Build a fake table so that we make sure that the CA core ignores it */

    if (!(BldTask.NoTableScale & BLD_NO_TEST))
    {
        memset (&LocalTEST, 0, sizeof (ACPI_TABLE_HEADER));
        strncpy (LocalTEST.Signature, "TEST", 4);

        LocalTEST.Revision = 1;
        LocalTEST.Length = sizeof (ACPI_TABLE_HEADER);

        LocalRSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&LocalTEST);
    }

    LocalRSDT->Header.Length = sizeof (RSDT_DESCRIPTOR_REV1) +
        (i - 1) * sizeof (UINT32);

    if (BldTask.ErrScale & BAD_LENGTH_HDR_RSDT)
    {
        LocalRSDT->Header.Length = sizeof (ACPI_TABLE_HEADER) - 1;
    }

    /* Set checksums for RSDT */

    LocalRSDT->Header.Checksum = (UINT8)(0 - AcpiTbChecksum
        ((UINT8 *)&LocalRSDT->Header, LocalRSDT->Header.Length));
    if (BldTask.ErrScale & BAD_CHECKSUM_RSDT)
    {
        LocalRSDT->Header.Checksum = (UINT8)~LocalRSDT->Header.Checksum;
    }
}


/*******************************************************************************
 *
 * FUNCTION:    AtBuildLocalXSDT
 *
 * PARAMETERS:  LocalXSDT       - Pointer to the local XSDT template
 *              UserTable       - Pointer to User's DSDT AML code or NULL
 *              BldTask         - Build Task for errors intrusion
 *
 * RETURN:      None
 *
 * DESCRIPTION: Build Revision 2 XSDT image, perform errors intrusion handling.
 *
 ******************************************************************************/

static ACPI_STATUS
AtBuildLocalXSDT (
    ACPI_TABLE_XSDT    *LocalXSDT,
    ACPI_TABLE_HEADER       *UserTable,
    BLD_TABLES_TASK         BldTask)
{
    ACPI_TABLE_HEADER       *Actual_DSDT = NULL;
    int                     i = 0;

    if (BldTask.ErrScale & NOT_PRESENT_FADT)
    {
        BldTask.NoTableScale |= BLD_NO_FADT;
    }

    memset (LocalXSDT, 0, RSDT_SIZE);

    strncpy (LocalXSDT->Header.Signature, ACPI_SIG_XSDT, 4);
    if (BldTask.ErrScale & BAD_SIGNATURE_RSDT)
    {
        strncpy (LocalXSDT->Header.Signature, "BADS", 4);
    }

    if (!(BldTask.NoTableScale & BLD_NO_BADT))
    {
        /*
         * Build a fake table with a bad signature so that
         * we make sure that the CA core ignores it
         */

        memset (&LocalBADTABLE, 0, sizeof (ACPI_TABLE_HEADER));
        strncpy (LocalBADTABLE.Signature, "BAD!", 4);

        LocalBADTABLE.Revision = 1;
        LocalBADTABLE.Length = sizeof (ACPI_TABLE_HEADER);

        LocalXSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&LocalBADTABLE);
    }

    if (!(BldTask.NoTableScale & BLD_NO_FADT))
    {
        /* Build a FADT so we can test the hardware/event init */
        AtBuildLocalFADT2(&LocalFADT2, &LocalFACS, &Actual_DSDT, UserTable, BldTask);
        LocalXSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&LocalFADT2);
    }

    if (Actual_DSDT &&
        (!strncmp ((char *) Actual_DSDT->Signature, ACPI_SIG_SSDT, 4) ||
         !strncmp ((char *) Actual_DSDT->Signature, ACPI_SIG_PSDT, 4)))
    {
        LocalXSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (UserTable);
    }

    /* Install two SSDTs to test multiple table support */

    if (!(BldTask.NoTableScale & BLD_NO_SSDT1))
    {
        LocalXSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&Ssdt1Code);
        LocalXSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&Psdt1Code);
    }
    if (!(BldTask.NoTableScale & BLD_NO_SSDT2))
    {
        LocalXSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&Ssdt2Code);
        LocalXSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&Ssdt3Code);
    }

    /* Install the OEM1 table to test LoadTable */

    if (!(BldTask.NoTableScale & BLD_NO_OEM1))
    {
        LocalXSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&Oem1Code);
    }


    /* Build a fake table so that we make sure that the CA core ignores it */

    if (!(BldTask.NoTableScale & BLD_NO_TEST))
    {
        memset (&LocalTEST, 0, sizeof (ACPI_TABLE_HEADER));
        strncpy (LocalTEST.Signature, "TEST", 4);

        LocalTEST.Revision = 1;
        LocalTEST.Length = sizeof (ACPI_TABLE_HEADER);

        LocalXSDT->TableOffsetEntry[i++] = ACPI_PTR_TO_PHYSADDR (&LocalTEST);
    }

    if (i > RSDT_TABLES)
    {
        TestErrors++;
        printf ("Test Error in AtBuildLocalXSDT: instances"
            " for RSDP (%d) should be < %d\n",
            i, RSDT_TABLES);
        return (AE_ERROR);
    }

    LocalXSDT->Header.Length = ((ACPI_SIZE) i * sizeof (UINT64)) +
                    sizeof (ACPI_TABLE_HEADER);

    if (BldTask.ErrScale & BAD_LENGTH_HDR_RSDT)
    {
        LocalXSDT->Header.Length = sizeof (ACPI_TABLE_HEADER) - 1;
    }

    /* Set checksums for RSDT */

    LocalXSDT->Header.Checksum = (UINT8)(0 - AcpiTbChecksum
        ((UINT8 *)&LocalXSDT->Header, LocalXSDT->Header.Length));
    if (BldTask.ErrScale & BAD_CHECKSUM_RSDT)
    {
        LocalXSDT->Header.Checksum = (UINT8)~LocalXSDT->Header.Checksum;
    }

    return (AE_OK);
}


/******************************************************************************
 *
 * FUNCTION:    AtBuildLocalTables
 *
 * PARAMETERS:  UserTable       - Pointer to User's DSDT AML code or NULL
 *              BldTask         - Build Task for errors intrusion
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Build the ACPI tables and file in RSDP structure.
 *
 *****************************************************************************/

ACPI_STATUS
AtBuildLocalTables (
    ACPI_TABLE_HEADER       *UserTable,
    BLD_TABLES_TASK         BldTask)
{
    /* Build an RSDT and its members */
#if ACPI_MACHINE_WIDTH == 64
    AtBuildLocalXSDT((ACPI_TABLE_XSDT *)LocalRSDT, UserTable, BldTask);
#else
    AtBuildLocalRSDT(LocalRSDT, UserTable, BldTask);
#endif

    /* Build an RSDP */

    memset (&LocalRSDP, 0, sizeof (ACPI_TABLE_RSDP));
    strncpy (LocalRSDP.Signature, ACPI_SIG_RSDP, 8);
    if (BldTask.ErrScale & BAD_SIGNATURE_RSDP)
    {
        strncpy (LocalRSDP.Signature, "BAD SIGN", 8);
    }
#if ACPI_MACHINE_WIDTH == 64
    LocalRSDP.Revision = 2;
    LocalRSDP.XsdtPhysicalAddress = ACPI_PTR_TO_PHYSADDR (LocalRSDT);
#else
    LocalRSDP.Revision = 1;
    LocalRSDP.RsdtPhysicalAddress = ACPI_PTR_TO_PHYSADDR (LocalRSDT);
#endif

    /* Set checksums for RSDP */

    LocalRSDP.Checksum = (UINT8) (0 - AcpiTbChecksum
        ((UINT8 *) &LocalRSDP, ACPI_RSDP_CHECKSUM_LENGTH));
    if (BldTask.ErrScale & BAD_CHECKSUM_RSDP)
    {
        LocalRSDP.Checksum = (UINT8)~LocalRSDP.Checksum;
    }
#if ACPI_MACHINE_WIDTH == 64
    LocalRSDP.ExtendedChecksum = (UINT8) (0 - AcpiTbChecksum
        ((UINT8 *) &LocalRSDP, ACPI_RSDP_XCHECKSUM_LENGTH));
#endif

    return (AE_OK);
}


/******************************************************************************
 *
 * FUNCTION:    AtGetTableHeader
 *
 * PARAMETERS:  Type            - Type of the requested table
 *              Instance        - Can be not 1 if Type supports multiple tables
 *              Table           - Where a pointer to the table is returned
 *              BldTask         - Build Task for errors intrusion
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Build the ACPI tables and file in RSDP structure.
 *
 *****************************************************************************/

ACPI_STATUS
AtGetTableHeader (
    char                    *Type,
    UINT32                  Instance,
    ACPI_TABLE_HEADER       **Table,
    BLD_TABLES_TASK         BldTask)
{
    ACPI_STATUS             Status = AE_OK;
    ACPI_TABLE_HEADER       *Actual_DSDT = NULL;

    if (!ACPI_COMPARE_NAME(Type, ACPI_SIG_SSDT) && (Instance != 1))
    {
        TestErrors++;
        printf ("Test Error in AtGetTableHeader: for Type %s"
            " Instance should be 1, not %d\n",
            Type, Instance);
        *Table = NULL;
        return (AE_ERROR);
    }

    if (ACPI_COMPARE_NAME(Type, ACPI_SIG_RSDP))
    {
        AtBuildLocalTables(NULL, BldTask);
        *Table = (ACPI_TABLE_HEADER *)&LocalRSDP;
    } else if (ACPI_COMPARE_NAME(Type, ACPI_SIG_DSDT))
    {
        AtBuildLocalDSDT(NULL, BldTask, &Actual_DSDT);
        *Table = Actual_DSDT;
    } else if (ACPI_COMPARE_NAME(Type, ACPI_SIG_FACS))
    {
        AtBuildLocalFACS1(&LocalFACS, BldTask);
        *Table = (ACPI_TABLE_HEADER *)&LocalFACS;
    } else if (ACPI_COMPARE_NAME(Type, ACPI_SIG_FADT))
    {
        BldTask.NoTableScale &= ~(BLD_NO_FACS | BLD_NO_DSDT);
        AtBuildLocalFADT1(&LocalFADT, &LocalFACS, &Actual_DSDT, NULL, BldTask);
        *Table = (ACPI_TABLE_HEADER *)&LocalFADT;
    } else if (ACPI_COMPARE_NAME(Type, ACPI_SIG_PSDT))
    {
        *Table = (ACPI_TABLE_HEADER *)&Psdt1Code;
    } else if (ACPI_COMPARE_NAME(Type, ACPI_SIG_SSDT))
    {
        switch (Instance)
        {
        case 1:
            *Table = (ACPI_TABLE_HEADER *)&Ssdt1Code;
            break;
        case 2:
            *Table = (ACPI_TABLE_HEADER *)&Ssdt2Code;
            break;
        case 3:
            *Table = (ACPI_TABLE_HEADER *)&Ssdt3Code;
            break;
        default:
            TestErrors++;
            printf ("Test Error in AtGetTableHeader: for SSDT"
                " Instance should be in range 1-3, not %d\n",
                Instance);
            *Table = NULL;
            Status = AE_ERROR;
            break;
        }
    } else if (ACPI_COMPARE_NAME(Type, ACPI_SIG_XSDT))
    {
//        BldTask.NoTableScale &= ~(BLD_NO_FACS | BLD_NO_DSDT | BLD_NO_FADT);
        AtBuildLocalDSDT(NULL, BldTask, &Actual_DSDT);
        Status = AtBuildLocalXSDT((ACPI_TABLE_XSDT *)LocalRSDT,
            Actual_DSDT, BldTask);
/*
        AtBuildLocalRSDT(LocalRSDT, NULL, BldTask);
*/
        if (ACPI_FAILURE(Status))
        {
            *Table = NULL;
        }
        else
        {
            *Table = (ACPI_TABLE_HEADER *)LocalRSDT;
        }
    } else
    {
        TestErrors++;
        printf ("Test Error in AtGetTableHeader: unexpected table Type '%s'\n",
            Type);
        *Table = NULL;
        Status = AE_ERROR;
   }

    return (Status);
}


/******************************************************************************
 *
 * FUNCTION:    AeLocalGetRootPointer
 *
 * PARAMETERS:
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Return a local RSDP, used to dynamically load tables via the
 *              standard ACPI mechanism.
 *
 *****************************************************************************/
/*
ACPI_STATUS
AeLocalGetRootPointer (
    UINT32                  Flags,
    ACPI_POINTER            *Address)
{
    if (Flags != ACPI_LOGICAL_ADDRESSING)
    {
        printf ("AtLocalGetRootPointer: Flags (0x%x) !="
            " ACPI_LOGICAL_ADDRESSING (0x%x)\n",
            Flags, ACPI_LOGICAL_ADDRESSING);
        return (AE_ERROR);
    }

    Address->PointerType = ACPI_LOGICAL_POINTER;
    Address->Pointer.Logical = &LocalRSDP;
    return (AE_OK);
}
*/
ACPI_PHYSICAL_ADDRESS
AeLocalGetRootPointer (
    void)
{

    return ((ACPI_PHYSICAL_ADDRESS) &LocalRSDP);
}


typedef struct Region
{
    ACPI_PHYSICAL_ADDRESS   Address;
    UINT32                  Length;
    void                    *Buffer;
    void                    *NextRegion;

} REGION;

typedef struct DebugRegions
{
    UINT32                  NumberOfRegions;
    REGION                  *RegionList;

} DEBUG_REGIONS;

#define GET_SEGMENT(ptr)                ((UINT16)(_segment)(ptr))
#define GET_OFFSET(ptr)                 ((UINT16)(UINT32) (ptr))
#define GET_PHYSICAL_ADDRESS(ptr)       (((((UINT32)GET_SEGMENT(ptr)) << 4)) + GET_OFFSET(ptr))
#define PTR_OVL_BUILD_PTR(p,b,o)        {p.ovl.base=b;p.ovl.offset=o;}


#define TEST_OUTPUT_LEVEL(lvl)          if ((lvl) & OutputLevel)

#define OSD_PRINT(lvl,fp)               TEST_OUTPUT_LEVEL(lvl) {\
                                            AcpiOsPrintf PARAM_LIST(fp);}

DEBUG_REGIONS               AeRegions;


/******************************************************************************
 *
 * FUNCTION:    AeGetRegionBufferAddress
 *
 * PARAMETERS:  RegionObject
 *
 * RETURN:      Address
 *
 * DESCRIPTION: Returns the address of the Region's first byte
 *              in the respective emulation buffer.
 *
 *****************************************************************************/

ACPI_PHYSICAL_ADDRESS
AeGetRegionBufferAddress (
    ACPI_OPERAND_OBJECT     *RegionObject)
{

    ACPI_PHYSICAL_ADDRESS   BaseAddress;
    ACPI_PHYSICAL_ADDRESS   RetAddress = (ACPI_PHYSICAL_ADDRESS) NULL;
    ACPI_SIZE               Length;
    REGION                  *RegionElement;


    ACPI_FUNCTION_NAME (AeGetRegionBufferAddress);


    /*
     * If the object is not a region, return NULL
     */
    if ((RegionObject->Region.Type != ACPI_TYPE_REGION) ||
        (RegionObject->Region.SpaceId == ACPI_ADR_SPACE_SMBUS))
    {
        return (RetAddress);
    }

    /*
     * Find the region's address space and length before searching
     * the linked list.
     */
    BaseAddress = RegionObject->Region.Address;
    Length = (ACPI_SIZE) RegionObject->Region.Length;

    ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "OpRegion Address request on %s\n",
            AcpiUtGetRegionName (RegionObject->Region.SpaceId)));

    /*
     * Search through the linked list for this region's buffer
     */
    RegionElement = AeRegions.RegionList;

    if (AeRegions.NumberOfRegions)
    {
        while (RegionElement)
        {
            if (RegionElement->Address == BaseAddress &&
                RegionElement->Length == Length)
            {
                RetAddress = (ACPI_PHYSICAL_ADDRESS) RegionElement->Buffer;
                break;
            }
            else
            {
                RegionElement = RegionElement->NextRegion;
            }
        }
    }

    /*
     * If the Region buffer does not exist, create it now
     */
    if (!RetAddress)
    {
        /*
         * Do the memory allocations first
         */
/*
        RegionElement = AcpiOsAllocate (sizeof (REGION));
*/
        RegionElement = malloc (sizeof (REGION));
        if (!RegionElement)
        {
            return (RetAddress);
        }

/*
        RegionElement->Buffer = AcpiOsAllocate (Length);
*/
        RegionElement->Buffer = malloc (Length);
        if (!RegionElement->Buffer)
        {
/*
            AcpiOsFree (RegionElement);
*/
            free (RegionElement);
            return (RetAddress);
        }

        memset (RegionElement->Buffer, 0, Length);
        RegionElement->Address = BaseAddress;
        RegionElement->Length = Length;
        RegionElement->NextRegion = NULL;

        /*
         * Increment the number of regions and put this one
         *  at the head of the list as it will probably get accessed
         *  more often anyway.
         */
        AeRegions.NumberOfRegions += 1;

        if (AeRegions.RegionList)
        {
            RegionElement->NextRegion = AeRegions.RegionList;
        }

        AeRegions.RegionList = RegionElement;

        RetAddress = (ACPI_PHYSICAL_ADDRESS) RegionElement->Buffer;
    }

    return (RetAddress);
}


/******************************************************************************
 *
 * FUNCTION:    AeSmbusRegionHandler
 *
 * PARAMETERS:  Standard region handler parameters
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Test handler - Handles some dummy regions via memory that can
 *              be manipulated in Ring 3.
 *
 *****************************************************************************/

ACPI_STATUS
AeSmbusRegionHandler (
    UINT32                  Function,
    ACPI_INTEGER            *Value)
{
    ACPI_SIZE               Length;
    UINT32                  i;


    Length = 0;

    switch (Function & ACPI_IO_MASK)
    {
    case ACPI_READ:
        switch (Function >> 16)
        {
        case AML_FIELD_ATTRIB_QUICK:
        case AML_FIELD_ATTRIB_SEND_RCV:
        case AML_FIELD_ATTRIB_BYTE:
            Length = 1;
            break;

        case AML_FIELD_ATTRIB_WORD:
        case AML_FIELD_ATTRIB_WORD_CALL:
            Length = 2;
            break;

        case AML_FIELD_ATTRIB_BLOCK:
        case AML_FIELD_ATTRIB_BLOCK_CALL:
            Length = 32;
            break;

        default:
            break;
        }
        break;

    case ACPI_WRITE:
        switch (Function >> 16)
        {
        case AML_FIELD_ATTRIB_QUICK:
        case AML_FIELD_ATTRIB_SEND_RCV:
        case AML_FIELD_ATTRIB_BYTE:
        case AML_FIELD_ATTRIB_WORD:
        case AML_FIELD_ATTRIB_BLOCK:
            Length = 0;
            break;

        case AML_FIELD_ATTRIB_WORD_CALL:
            Length = 2;
            break;

        case AML_FIELD_ATTRIB_BLOCK_CALL:
            Length = 32;
            break;

        default:
            break;
        }
        break;

    default:
        break;
    }

    for (i = 0; i < Length; i++)
    {
        ((UINT8 *) Value)[i+2] = (UINT8) (0xA0 + i);
    }

    ((UINT8 *) Value)[0] = 0x7A;
    ((UINT8 *) Value)[1] = (UINT8) Length;

    return (AE_OK);
}


/******************************************************************************
 *
 * FUNCTION:    AeRegionHandler
 *
 * PARAMETERS:  Standard region handler parameters
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Test handler - Handles some dummy regions via memory that can
 *              be manipulated in Ring 3.
 *
 *****************************************************************************/

ACPI_STATUS
AeRegionHandler (
    UINT32                  Function,
    ACPI_PHYSICAL_ADDRESS   Address,
    UINT32                  BitWidth,
    ACPI_INTEGER            *Value,
    void                    *HandlerContext,
    void                    *RegionContext)
{
    ACPI_OPERAND_OBJECT     *RegionObject = (ACPI_OPERAND_OBJECT*) RegionContext;
    ACPI_PHYSICAL_ADDRESS   BaseAddress;
    ACPI_PHYSICAL_ADDRESS   BufferAddress;
    ACPI_SIZE               Length;
    void                    *BufferValue;
    UINT32                  ByteWidth;


    ACPI_FUNCTION_NAME ("AeRegionHandler");


    /*
     * If the object is not a region, simply return
     */
    if (RegionObject->Region.Type != ACPI_TYPE_REGION)
    {
        return (AE_OK);
    }

    /*
     * Find the region's address space and length before searching
     * the linked list.
     */
    BaseAddress = RegionObject->Region.Address;
    Length = (ACPI_SIZE) RegionObject->Region.Length;

    ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Operation Region request on %s at 0x%X\n",
            AcpiUtGetRegionName (RegionObject->Region.SpaceId),
            (UINT32) Address));

    if (RegionObject->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
    {
        return (AeSmbusRegionHandler(Function, Value));
    }

    BufferAddress = AeGetRegionBufferAddress(RegionObject);
    if (!BufferAddress)
    {
        return (AE_NO_MEMORY);
    }

    /*
     * Calculate the size of the memory copy
     */
    ByteWidth = (BitWidth / 8);

    if (BitWidth % 8)
    {
        ByteWidth += 1;
    }

    /*
     * The buffer exists and is pointed to by RegionElement.
     * We now need to verify the request is valid and perform the operation.
     *
     * NOTE: RegionElement->Header.Length is in bytes, therefore it we compare against
     * ByteWidth (see above)
     */
    if (((ACPI_INTEGER) Address + ByteWidth) >
        ((ACPI_INTEGER)(BufferAddress) + Length))
    {
        ACPI_WARNING ((AE_INFO,
            "Request on [%4.4s] is beyond region limit Req-%X+%X, Base=%X, Len-%X\n",
            (RegionObject->Region.Node)->Name.Ascii, (UINT32) Address,
            ByteWidth, (UINT32) BufferAddress, Length));

        return (AE_AML_REGION_LIMIT);
    }

    /*
     * Get BufferValue to point to the "address" in the buffer
     */
    BufferValue = (ACPI_CAST_PTR (UINT8, ACPI_PHYSADDR_TO_PTR (BufferAddress)) +
                    ((ACPI_INTEGER) Address - (ACPI_INTEGER) BaseAddress));

    /*
     * Perform a read or write to the buffer space
     */
    switch (Function)
    {
    case ACPI_READ:
        /*
         * Set the pointer Value to whatever is in the buffer
         */
        memcpy (Value, BufferValue, ByteWidth);
        break;

    case ACPI_WRITE:
        /*
         * Write the contents of Value to the buffer
         */
        memcpy (BufferValue, Value, ByteWidth);
        break;

    default:
        return (AE_BAD_PARAMETER);
    }
    return (AE_OK);
}


/******************************************************************************
 *
 * FUNCTION:    AeRegionInit
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Opregion init function.
 *
 *****************************************************************************/

ACPI_STATUS
AeRegionInit (
    ACPI_HANDLE                 RegionHandle,
    UINT32                      Function,
    void                        *HandlerContext,
    void                        **RegionContext)
{
    /*
     * Real simple, set the RegionContext to the RegionHandle
     */
    *RegionContext = RegionHandle;

    return (AE_OK);
}


/******************************************************************************
 *
 * FUNCTION:    AtRegionCleanup
 *
 * PARAMETERS:  None
 *
 * RETURN:      None
 *
 * DESCRIPTION: OpRegions cleanup function.
 *
 *****************************************************************************/

void
AtRegionCleanup (void)
{
    REGION                  *RegionElement;

    while (AeRegions.NumberOfRegions)
    {
        AeRegions.NumberOfRegions--;
        RegionElement = AeRegions.RegionList;
        AeRegions.RegionList = RegionElement->NextRegion;
        free(RegionElement->Buffer);
        free(RegionElement);
    }

    return;
}

/******************************************************************************
 *
 * FUNCTION:    AeInstallHandlers
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Install handlers for the AAPITS likely AcpiExec utility.
 *              NOTE: Only AdrSpace handlers are installed.
 *
 *****************************************************************************/

ACPI_ADR_SPACE_TYPE         SpaceId[] = {0, 1, 2, 3, 4, 0x80};
#define AEXEC_NUM_REGIONS   6

ACPI_STATUS
AeInstallHandlers (void)
{
    ACPI_STATUS             Status = AE_OK;
    UINT32                  i;

    ACPI_FUNCTION_NAME ("AeInstallHandlers");

    AtRegionCleanup();

    /*
    */
    for (i = 0; i < AEXEC_NUM_REGIONS; i++)
    {
        if (i == 2)
        {
            continue;
        }

        Status = AcpiRemoveAddressSpaceHandler (ACPI_ROOT_OBJECT,
                        SpaceId[i], AeRegionHandler);

        /* Install handler at the root object.
         * TBD: all default handlers should be installed here!
         */
        Status = AcpiInstallAddressSpaceHandler (ACPI_ROOT_OBJECT,
                        SpaceId[i], AeRegionHandler, AeRegionInit, NULL);
        if (ACPI_FAILURE (Status))
        {
            ACPI_ERROR ((AE_INFO,
                "Could not install an OpRegion handler for %s space(%d), %s\n",
                AcpiUtGetRegionName((UINT8) SpaceId[i]), SpaceId[i],
                AcpiFormatException (Status)));
            return (Status);
        }
    }

    /*
     * Initialize the global Region Handler space
     * MCW 3/23/00
     */
    AeRegions.NumberOfRegions = 0;
    AeRegions.RegionList = NULL;

    return (Status);
}


/*******************************************************************************
 *
 * FUNCTION:    AtReadTableFromFile
 *
 * PARAMETERS:  Filename         - File where table is located
 *              Table            - Where a pointer to the table is returned
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Get an ACPI table from a file, AcpiDbReadTableFromFile and
 *              AcpiDbReadTable do the same but this routine manages without
 *              OSL functions usage and does not require any validation.
 *
 ******************************************************************************/

ACPI_STATUS
AtReadTableFromFile (
    char                    *Filename,
    ACPI_TABLE_HEADER       **Table)
{
    FILE                    *fp;
    ACPI_TABLE_HEADER       TableHeader;
    UINT32                  Actual;
    UINT32                  FileSize;
    ACPI_STATUS             Status = AE_OK;


    printf ("Reading Acpi table from file %s\n", Filename);

    /* Open the file */

    fp = fopen (Filename, "rb");
    if (!fp)
    {
        printf ("Could not open input file %s\n", Filename);
        return (AE_ERROR);
    }

    fseek (fp, 0, SEEK_END);
    FileSize = ftell (fp);
    fseek (fp, 0, SEEK_SET);

    /* Read the table header */

    if (fread (&TableHeader, 1, sizeof (TableHeader), fp) !=
            sizeof (ACPI_TABLE_HEADER))
    {
        printf ("Could not read the table header\n");
        Status = AE_BAD_HEADER;
        goto CleanupAndExit;
    }

    if (TableHeader.Length < sizeof (ACPI_TABLE_HEADER))
    {
        printf ("Error: TableHeader.Length (%d) < sizeof (ACPI_TABLE_HEADER) (%d)\n",
            TableHeader.Length, (UINT32) sizeof (ACPI_TABLE_HEADER));
        Status = AE_BAD_HEADER;
        goto CleanupAndExit;
    }

    /* Allocate a buffer for the table */

    *Table = (void *) malloc ((size_t) TableHeader.Length);
    if (!*Table)
    {
        printf (
            "Could not allocate memory for ACPI table %4.4s (size=0x%X)\n",
            TableHeader.Signature, TableHeader.Length);
        Status = AE_NO_MEMORY;
        goto CleanupAndExit;
    }

    /* Get the entire table */

    if (TableHeader.Length < FileSize)
    {
        FileSize = TableHeader.Length;
    }

    fseek (fp, 0, SEEK_SET);
    Actual = fread (*Table, 1, (size_t) FileSize, fp);
    if (Actual != FileSize)
    {
        printf ("Error - could not read the table file\n");
        free (*Table);
        *Table = NULL;
        Status = AE_ERROR;
    }

CleanupAndExit:
    fclose (fp);
    return (Status);
}


static char             PathName[AT_PATHNAME_MAX];

/*******************************************************************************
 *
 * FUNCTION:    AtAMLcodeFileNameSet
 *
 * PARAMETERS:  CodeName         - Relative Name of AML code file
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Concatenate CodeName with the DirName specified by User.
 *
 ******************************************************************************/

ACPI_STATUS
AtAMLcodeFileNameSet(
    char                    *CodeName)
{
    if (!AtAMLcodeFileDir)
    {
        TestErrors++;
        printf ("Test Error: AML code FileDir Name path is not specified\n");
        return (AE_ERROR);
    }

    if (strlen(AtAMLcodeFileDir) + strlen(CodeName) + 1 >= AT_PATHNAME_MAX)
    {
        TestErrors++;
        printf ("Test Error: AML code FileName path (%s + %s) is too long\n",
            AtAMLcodeFileDir, CodeName);
        return (AE_ERROR);
    }

    strcpy(PathName, AtAMLcodeFileDir);
    strcat(PathName, "/");
    strcat(PathName, CodeName);
    AtAMLcodeFileName = PathName;

    return (AE_OK);
}


/*******************************************************************************
 *
 * FUNCTION:    AtCheckInteger
 *
 * PARAMETERS:  ObjHandle       - Checked Object ACPI handle or NULL
 *              ObjPath         - Checked Object ACPI Path
 *              Value           - Benchmark value
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Check specified Integer value in ACPI namespace
 *
 ******************************************************************************/

ACPI_STATUS
AtCheckInteger(
    ACPI_HANDLE             ObjHandle,
    ACPI_STRING             ObjPath,
    ACPI_INTEGER            Value)
{
    ACPI_STATUS             Status;
    ACPI_STRING             Path;
    ACPI_BUFFER             Results;
    ACPI_OBJECT             Obj, *Object = &Obj;
    ACPI_BUFFER             OutName = {AT_PATHNAME_MAX, PathName};

    /* Initialize the return buffer structure */
    Results.Length = sizeof (Obj);
    Results.Pointer = Object;
    memset(Results.Pointer, 0, Results.Length);

    if (ObjHandle)
    {
        Path = NULL;
    }
    else
    {
        Path = ObjPath;
    }

    Status = AcpiEvaluateObject (ObjHandle, Path, NULL, &Results);

    if (ObjHandle)
    {
        Status = AcpiGetName (ObjHandle, ACPI_FULL_PATHNAME, &OutName);

        if (ACPI_FAILURE(Status))
        {
            AapiErrors++;
            printf ("API Error: AcpiGetName(0x%p) returned %s\n",
                ObjHandle, AcpiFormatException(Status));
            return (Status);
        }
        Path = (ACPI_STRING) OutName.Pointer;
    }

    if (ACPI_FAILURE(Status))
    {
        AapiErrors++;
        printf ("API Error: AcpiEvaluateObject(%s) returned %s\n",
            Path, AcpiFormatException(Status));
        return (Status);
    }

    Status = AE_OK;
    if (Obj.Type != 1)
    {
        AapiErrors++;
        printf ("API Error: Type of %s (%d) is not Integer (1)\n",
            Path, Obj.Type);
        Status = AE_ERROR;
    }
    else if (Obj.Integer.Value != Value)
    {
        AapiErrors++;
#ifdef    _MSC_VER
        printf ("API Error: Value of %s is 0x%I64x instead of expected 0x%I64x\n",
            Path, Obj.Integer.Value, Value);
#else
        printf ("API Error: Value of %s is 0x%llx instead of expected 0x%llx\n",
            Path, Obj.Integer.Value, Value);
#endif
        Status = AE_ERROR;
    }

    return (Status);
}


/*******************************************************************************
 *
 * FUNCTION:    AtCheckBytes
 *
 * PARAMETERS:  Name            - Checked Object name
 *              Pointer         - Pointer to the Checked Object memory
 *              Benchmark       - Pointer to the Benchmark memory
 *              Length          - Length of memory ranges
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Check specified memory ranges if they are identical
 *
 ******************************************************************************/

ACPI_STATUS
AtCheckBytes(
    ACPI_STRING             Name,
    UINT8                   *Pointer,
    UINT8                   *Benchmark,
    UINT32                  Length)
{
    ACPI_STATUS             Status = AE_OK;
    UINT32                  i;

    for (i = 0; i < Length; i++)
    {
        if (Pointer[i] != Benchmark[i])
        {
            AapiErrors++;
            printf ("API Error: Element %d of %s is 0x%x instead of expected 0x%x\n",
                i, Name, Pointer[i], Benchmark[i]);
            Status = AE_ERROR;
            break;
        }
    }
    return (Status);
}


/*******************************************************************************
 *
 * FUNCTION:    AtCheckString
 *
 * PARAMETERS:  Path            - Checked Object ACPI Path
 *              Pointer         - Pointer to the Benchmark String
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Check specified String value in ACPI namespace
 *
 ******************************************************************************/

ACPI_STATUS
AtCheckString(
    ACPI_STRING             Path,
    UINT8                   *Pointer)
{
    ACPI_STATUS             Status;
    UINT32                  Length = strlen((char *)Pointer);
    ACPI_BUFFER             Results;
    ACPI_OBJECT             *Object;

    /* Initialize the return buffer structure */
    Results.Length = ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof (ACPI_OBJECT) + Length + 1);
    Object = (ACPI_OBJECT    *)malloc((size_t)Results.Length);
    if (!Object)
    {
        TestErrors++;
        printf ("Test Error: cannot allocate buffer of %d bytes\n",
            Results.Length);
        return (AE_NO_MEMORY);
    }
    Results.Pointer = Object;
    memset(Results.Pointer, 0, Results.Length);

    Status = AcpiEvaluateObject (NULL, Path, NULL, &Results);

    if (ACPI_FAILURE(Status))
    {
        AapiErrors++;
        printf ("API Error: AcpiEvaluateObject(%s) returned %s\n",
            Path, AcpiFormatException(Status));
        goto Cleanup;
    }

    Status = AE_OK;
    if (Object->Type != 2)
    {
        AapiErrors++;
        printf ("API Error: Type of %s (%d) is not String (2)\n",
            Path, Object->Type);
        Status = AE_ERROR;
    }
    else if (Object->Buffer.Length != Length)
    {
        AapiErrors++;
        printf ("API Error: Length of %s is %d instead of expected %d\n",
            Path, Object->Buffer.Length, Length);
        Status = AE_ERROR;
    }
    else
    {
        Status = AtCheckBytes(Path, Object->Buffer.Pointer, Pointer, Length);
    }

Cleanup:
    free(Object);

    return (AE_OK);
}


/*******************************************************************************
 *
 * FUNCTION:    AtCheckBuffer
 *
 * PARAMETERS:  Path            - Checked Object ACPI Path
 *              Length          - Length of the Benchmark buffer
 *              Pointer         - Pointer to the Benchmark buffer
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Check specified Buffer value in ACPI namespace
 *
 ******************************************************************************/

ACPI_STATUS
AtCheckBuffer(
    ACPI_STRING             Path,
    UINT32                  Length,
    UINT8                   *Pointer)
{
    ACPI_STATUS             Status;
    ACPI_BUFFER             Results = {0, NULL};
    ACPI_OBJECT             *Object;

    Status = AcpiEvaluateObject (NULL, Path, NULL, &Results);

    if (Status != AE_BUFFER_OVERFLOW)
    {
        AapiErrors++;
        printf ("API Error: AcpiEvaluateObject(%s) returned %s\n",
            Path, AcpiFormatException(Status));
        return (Status);
    }

    if (Results.Length != ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof (ACPI_OBJECT) + Length))
    {
        printf ("AtCheckBuffer: unexpected length %d of Buffer vs"
            " calculated %d bytes\n",
            Results.Length, ACPI_ROUND_UP_TO_NATIVE_WORD(sizeof (ACPI_OBJECT) + Length));
    }

    /* Initialize the return buffer structure */
    Object = (ACPI_OBJECT    *)malloc((size_t)Results.Length);
    if (!Object)
    {
        TestErrors++;
        printf ("Test Error: cannot allocate buffer of %d bytes\n",
            Results.Length);
        return (AE_NO_MEMORY);
    }
    Results.Pointer = Object;
    memset(Results.Pointer, 0, Results.Length);

    Status = AcpiEvaluateObject (NULL, Path, NULL, &Results);

    if (ACPI_FAILURE(Status))
    {
        AapiErrors++;
        printf ("API Error: AcpiEvaluateObject(%s) returned %s\n",
            Path, AcpiFormatException(Status));
        goto Cleanup;
    }

    Status = AE_OK;
    if (Object->Type != 3)
    {
        AapiErrors++;
        printf ("API Error: Type of %s (%d) is not Buffer (3)\n",
            Path, Object->Type);
        Status = AE_ERROR;
    }
    else if (Object->Buffer.Length != Length)
    {
        AapiErrors++;
        printf ("API Error: Length of %s is %d instead of expected %d\n",
            Path, Object->Buffer.Length, Length);
        Status = AE_ERROR;
        if (Object->Buffer.Length < Length)
        {
            Length = Object->Buffer.Length;
        }
        (void)AtCheckBytes(Path, Object->Buffer.Pointer, Pointer, Length);
    }
    else
    {
        Status = AtCheckBytes(Path, Object->Buffer.Pointer, Pointer, Length);
    }

Cleanup:
    free(Object);

    return (Status);
}


/*******************************************************************************
 *
 * FUNCTION:    AtCheckName
 *
 * PARAMETERS:  ObjHandle       - Checked Object ACPI handle or NULL
 *              CheckName       - Pointer to the expected name
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Check NS Object specified by the ObjHandle to have the name
 *
 ******************************************************************************/

ACPI_STATUS
AtCheckName(
    ACPI_HANDLE             ObjHandle,
    ACPI_STRING             CheckName)
{
    ACPI_STATUS             Status;
    ACPI_BUFFER             OutName = {ACPI_ALLOCATE_BUFFER};

    Status = AcpiGetName (ObjHandle, ACPI_FULL_PATHNAME, &OutName);

    if (ACPI_FAILURE(Status))
    {
        AapiErrors++;
        printf ("API Error: AcpiGetName(0x%p) returned %s\n",
            ObjHandle, AcpiFormatException(Status));
        return (Status);
    }

    if (strcmp(CheckName, (char *)OutName.Pointer))
    {
        AapiErrors++;
        Status = AE_ERROR;
        printf ("AtCheckName: AcpiGetName() returned Name %s,"
            " expected %s\n",
            CheckName, (char *)OutName.Pointer);
    }

    AcpiOsFree(OutName.Pointer);

    return (Status);
}


ACPI_STATUS
AeIndexFieldHandler (
    ACPI_OBJECT_INDEX_FIELD *IndexField,
    UINT32                  ReadWrite)
{
    return (AE_OK);
}

ACPI_STATUS
AeBankFieldHandler (
    ACPI_OPERAND_OBJECT     *ObjDesc)
{
    return (AE_OK);
}


/*
 * Auxiliary Ssdt Load/Unload
 */
ACPI_STATUS
AtAuxiliarySsdt(
    UINT32                  Action)
{
    ACPI_STATUS             Status = AE_OK;

    if (Action == AT_LOAD)
    {
        Status = AcpiEvaluateObject (NULL, "\\AUX0.INIT",
            NULL, NULL);
        if (ACPI_FAILURE(Status))
        {
            AapiErrors++;
            printf ("API Error: AcpiEvaluateObject(AUX0.INIT) returned %s\n",
                AcpiFormatException(Status));
        }
        else
        {
            Status = AcpiEvaluateObject (NULL, "\\AUX0.LD__",
                NULL, NULL);
            if (ACPI_FAILURE(Status))
            {
                AapiErrors++;
                printf ("API Error: AcpiEvaluateObject(AUX0.LD) returned %s\n",
                    AcpiFormatException(Status));
            }
        }
    }
    else /* AT_UNLOAD */
    {
        Status = AcpiEvaluateObject (NULL, "\\AUX0.UNLD",
            NULL, NULL);
        if (ACPI_FAILURE(Status))
        {
            AapiErrors++;
            printf ("API Error: AcpiEvaluateObject(AUX0.UNLD) returned %s\n",
                AcpiFormatException(Status));
        }
    }
    return (Status);
}
