1138 lines
31 KiB
C
1138 lines
31 KiB
C
/*******************************************************************************
|
|
*
|
|
* Module Name: dbtest - Various debug-related tests
|
|
*
|
|
******************************************************************************/
|
|
|
|
/*
|
|
* Copyright (C) 2000 - 2014, Intel Corp.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions, and the following disclaimer,
|
|
* without modification.
|
|
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
|
* substantially similar to the "NO WARRANTY" disclaimer below
|
|
* ("Disclaimer") and any redistribution must be conditioned upon
|
|
* including a substantially similar Disclaimer requirement for further
|
|
* binary redistribution.
|
|
* 3. Neither the names of the above-listed copyright holders nor the names
|
|
* of any contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* Alternatively, this software may be distributed under the terms of the
|
|
* GNU General Public License ("GPL") version 2 as published by the Free
|
|
* Software Foundation.
|
|
*
|
|
* NO WARRANTY
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGES.
|
|
*/
|
|
|
|
#include "acpi.h"
|
|
#include "accommon.h"
|
|
#include "acdebug.h"
|
|
#include "acnamesp.h"
|
|
#include "acpredef.h"
|
|
|
|
#ifdef ACPI_DEBUGGER
|
|
|
|
#define _COMPONENT ACPI_CA_DEBUGGER
|
|
ACPI_MODULE_NAME ("dbtest")
|
|
|
|
|
|
/* Local prototypes */
|
|
|
|
static void
|
|
AcpiDbTestAllObjects (
|
|
void);
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbTestOneObject (
|
|
ACPI_HANDLE ObjHandle,
|
|
UINT32 NestingLevel,
|
|
void *Context,
|
|
void **ReturnValue);
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbTestIntegerType (
|
|
ACPI_NAMESPACE_NODE *Node,
|
|
UINT32 BitLength);
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbTestBufferType (
|
|
ACPI_NAMESPACE_NODE *Node,
|
|
UINT32 BitLength);
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbTestStringType (
|
|
ACPI_NAMESPACE_NODE *Node,
|
|
UINT32 ByteLength);
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbReadFromObject (
|
|
ACPI_NAMESPACE_NODE *Node,
|
|
ACPI_OBJECT_TYPE ExpectedType,
|
|
ACPI_OBJECT **Value);
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbWriteToObject (
|
|
ACPI_NAMESPACE_NODE *Node,
|
|
ACPI_OBJECT *Value);
|
|
|
|
static void
|
|
AcpiDbEvaluateAllPredefinedNames (
|
|
char *CountArg);
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbEvaluateOnePredefinedName (
|
|
ACPI_HANDLE ObjHandle,
|
|
UINT32 NestingLevel,
|
|
void *Context,
|
|
void **ReturnValue);
|
|
|
|
/*
|
|
* Test subcommands
|
|
*/
|
|
static ACPI_DB_ARGUMENT_INFO AcpiDbTestTypes [] =
|
|
{
|
|
{"OBJECTS"},
|
|
{"PREDEFINED"},
|
|
{NULL} /* Must be null terminated */
|
|
};
|
|
|
|
#define CMD_TEST_OBJECTS 0
|
|
#define CMD_TEST_PREDEFINED 1
|
|
|
|
#define BUFFER_FILL_VALUE 0xFF
|
|
|
|
/*
|
|
* Support for the special debugger read/write control methods.
|
|
* These methods are installed into the current namespace and are
|
|
* used to read and write the various namespace objects. The point
|
|
* is to force the AML interpreter do all of the work.
|
|
*/
|
|
#define ACPI_DB_READ_METHOD "\\_T98"
|
|
#define ACPI_DB_WRITE_METHOD "\\_T99"
|
|
|
|
static ACPI_HANDLE ReadHandle = NULL;
|
|
static ACPI_HANDLE WriteHandle = NULL;
|
|
|
|
/* ASL Definitions of the debugger read/write control methods */
|
|
|
|
#if 0
|
|
DefinitionBlock ("ssdt.aml", "SSDT", 2, "Intel", "DEBUG", 0x00000001)
|
|
{
|
|
Method (_T98, 1, NotSerialized) /* Read */
|
|
{
|
|
Return (DeRefOf (Arg0))
|
|
}
|
|
}
|
|
DefinitionBlock ("ssdt2.aml", "SSDT", 2, "Intel", "DEBUG", 0x00000001)
|
|
{
|
|
Method (_T99, 2, NotSerialized) /* Write */
|
|
{
|
|
Store (Arg1, Arg0)
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static unsigned char ReadMethodCode[] =
|
|
{
|
|
0x53,0x53,0x44,0x54,0x2E,0x00,0x00,0x00, /* 00000000 "SSDT...." */
|
|
0x02,0xC9,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 "..Intel." */
|
|
0x44,0x45,0x42,0x55,0x47,0x00,0x00,0x00, /* 00000010 "DEBUG..." */
|
|
0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
|
|
0x18,0x12,0x13,0x20,0x14,0x09,0x5F,0x54, /* 00000020 "... .._T" */
|
|
0x39,0x38,0x01,0xA4,0x83,0x68 /* 00000028 "98...h" */
|
|
};
|
|
|
|
static unsigned char WriteMethodCode[] =
|
|
{
|
|
0x53,0x53,0x44,0x54,0x2E,0x00,0x00,0x00, /* 00000000 "SSDT...." */
|
|
0x02,0x15,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 "..Intel." */
|
|
0x44,0x45,0x42,0x55,0x47,0x00,0x00,0x00, /* 00000010 "DEBUG..." */
|
|
0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
|
|
0x18,0x12,0x13,0x20,0x14,0x09,0x5F,0x54, /* 00000020 "... .._T" */
|
|
0x39,0x39,0x02,0x70,0x69,0x68 /* 00000028 "99.pih" */
|
|
};
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: AcpiDbExecuteTest
|
|
*
|
|
* PARAMETERS: TypeArg - Subcommand
|
|
*
|
|
* RETURN: None
|
|
*
|
|
* DESCRIPTION: Execute various debug tests.
|
|
*
|
|
* Note: Code is prepared for future expansion of the TEST command.
|
|
*
|
|
******************************************************************************/
|
|
|
|
void
|
|
AcpiDbExecuteTest (
|
|
char *TypeArg)
|
|
{
|
|
UINT32 Temp;
|
|
|
|
|
|
AcpiUtStrupr (TypeArg);
|
|
Temp = AcpiDbMatchArgument (TypeArg, AcpiDbTestTypes);
|
|
if (Temp == ACPI_TYPE_NOT_FOUND)
|
|
{
|
|
AcpiOsPrintf ("Invalid or unsupported argument\n");
|
|
return;
|
|
}
|
|
|
|
switch (Temp)
|
|
{
|
|
case CMD_TEST_OBJECTS:
|
|
|
|
AcpiDbTestAllObjects ();
|
|
break;
|
|
|
|
case CMD_TEST_PREDEFINED:
|
|
|
|
AcpiDbEvaluateAllPredefinedNames (NULL);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: AcpiDbTestAllObjects
|
|
*
|
|
* PARAMETERS: None
|
|
*
|
|
* RETURN: None
|
|
*
|
|
* DESCRIPTION: This test implements the OBJECTS subcommand. It exercises the
|
|
* namespace by reading/writing/comparing all data objects such
|
|
* as integers, strings, buffers, fields, buffer fields, etc.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static void
|
|
AcpiDbTestAllObjects (
|
|
void)
|
|
{
|
|
ACPI_STATUS Status;
|
|
|
|
|
|
/* Install the debugger read-object control method if necessary */
|
|
|
|
if (!ReadHandle)
|
|
{
|
|
Status = AcpiInstallMethod (ReadMethodCode);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
AcpiOsPrintf ("%s, Could not install debugger read method\n",
|
|
AcpiFormatException (Status));
|
|
return;
|
|
}
|
|
|
|
Status = AcpiGetHandle (NULL, ACPI_DB_READ_METHOD, &ReadHandle);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
AcpiOsPrintf ("Could not obtain handle for debug method %s\n",
|
|
ACPI_DB_READ_METHOD);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Install the debugger write-object control method if necessary */
|
|
|
|
if (!WriteHandle)
|
|
{
|
|
Status = AcpiInstallMethod (WriteMethodCode);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
AcpiOsPrintf ("%s, Could not install debugger write method\n",
|
|
AcpiFormatException (Status));
|
|
return;
|
|
}
|
|
|
|
Status = AcpiGetHandle (NULL, ACPI_DB_WRITE_METHOD, &WriteHandle);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
AcpiOsPrintf ("Could not obtain handle for debug method %s\n",
|
|
ACPI_DB_WRITE_METHOD);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Walk the entire namespace, testing each supported named data object */
|
|
|
|
(void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
|
|
ACPI_UINT32_MAX, AcpiDbTestOneObject, NULL, NULL, NULL);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: AcpiDbTestOneObject
|
|
*
|
|
* PARAMETERS: ACPI_WALK_CALLBACK
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Test one namespace object. Supported types are Integer,
|
|
* String, Buffer, BufferField, and FieldUnit. All other object
|
|
* types are simply ignored.
|
|
*
|
|
* Note: Support for Packages is not implemented.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbTestOneObject (
|
|
ACPI_HANDLE ObjHandle,
|
|
UINT32 NestingLevel,
|
|
void *Context,
|
|
void **ReturnValue)
|
|
{
|
|
ACPI_NAMESPACE_NODE *Node;
|
|
ACPI_OPERAND_OBJECT *ObjDesc;
|
|
ACPI_OPERAND_OBJECT *RegionObj;
|
|
ACPI_OBJECT_TYPE LocalType;
|
|
UINT32 BitLength = 0;
|
|
UINT32 ByteLength = 0;
|
|
ACPI_STATUS Status = AE_OK;
|
|
|
|
|
|
Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle);
|
|
ObjDesc = Node->Object;
|
|
|
|
/*
|
|
* For the supported types, get the actual bit length or
|
|
* byte length. Map the type to one of Integer/String/Buffer.
|
|
*/
|
|
switch (Node->Type)
|
|
{
|
|
case ACPI_TYPE_INTEGER:
|
|
|
|
/* Integer width is either 32 or 64 */
|
|
|
|
LocalType = ACPI_TYPE_INTEGER;
|
|
BitLength = AcpiGbl_IntegerBitWidth;
|
|
break;
|
|
|
|
case ACPI_TYPE_STRING:
|
|
|
|
LocalType = ACPI_TYPE_STRING;
|
|
ByteLength = ObjDesc->String.Length;
|
|
break;
|
|
|
|
case ACPI_TYPE_BUFFER:
|
|
|
|
LocalType = ACPI_TYPE_BUFFER;
|
|
ByteLength = ObjDesc->Buffer.Length;
|
|
BitLength = ByteLength * 8;
|
|
break;
|
|
|
|
case ACPI_TYPE_FIELD_UNIT:
|
|
case ACPI_TYPE_BUFFER_FIELD:
|
|
case ACPI_TYPE_LOCAL_REGION_FIELD:
|
|
case ACPI_TYPE_LOCAL_INDEX_FIELD:
|
|
case ACPI_TYPE_LOCAL_BANK_FIELD:
|
|
|
|
LocalType = ACPI_TYPE_INTEGER;
|
|
if (ObjDesc)
|
|
{
|
|
/*
|
|
* Returned object will be a Buffer if the field length
|
|
* is larger than the size of an Integer (32 or 64 bits
|
|
* depending on the DSDT version).
|
|
*/
|
|
BitLength = ObjDesc->CommonField.BitLength;
|
|
ByteLength = ACPI_ROUND_BITS_UP_TO_BYTES (BitLength);
|
|
if (BitLength > AcpiGbl_IntegerBitWidth)
|
|
{
|
|
LocalType = ACPI_TYPE_BUFFER;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Ignore all other types */
|
|
|
|
return (AE_OK);
|
|
}
|
|
|
|
/* Emit the common prefix: Type:Name */
|
|
|
|
AcpiOsPrintf ("%14s: %4.4s",
|
|
AcpiUtGetTypeName (Node->Type), Node->Name.Ascii);
|
|
if (!ObjDesc)
|
|
{
|
|
AcpiOsPrintf (" Ignoring, no attached object\n");
|
|
return (AE_OK);
|
|
}
|
|
|
|
/*
|
|
* Check for unsupported region types. Note: AcpiExec simulates
|
|
* access to SystemMemory, SystemIO, PCI_Config, and EC.
|
|
*/
|
|
switch (Node->Type)
|
|
{
|
|
case ACPI_TYPE_LOCAL_REGION_FIELD:
|
|
|
|
RegionObj = ObjDesc->Field.RegionObj;
|
|
switch (RegionObj->Region.SpaceId)
|
|
{
|
|
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
|
case ACPI_ADR_SPACE_SYSTEM_IO:
|
|
case ACPI_ADR_SPACE_PCI_CONFIG:
|
|
case ACPI_ADR_SPACE_EC:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
AcpiOsPrintf (" %s space is not supported [%4.4s]\n",
|
|
AcpiUtGetRegionName (RegionObj->Region.SpaceId),
|
|
RegionObj->Region.Node->Name.Ascii);
|
|
return (AE_OK);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* At this point, we have resolved the object to one of the major types */
|
|
|
|
switch (LocalType)
|
|
{
|
|
case ACPI_TYPE_INTEGER:
|
|
|
|
Status = AcpiDbTestIntegerType (Node, BitLength);
|
|
break;
|
|
|
|
case ACPI_TYPE_STRING:
|
|
|
|
Status = AcpiDbTestStringType (Node, ByteLength);
|
|
break;
|
|
|
|
case ACPI_TYPE_BUFFER:
|
|
|
|
Status = AcpiDbTestBufferType (Node, BitLength);
|
|
break;
|
|
|
|
default:
|
|
|
|
AcpiOsPrintf (" Ignoring, type not implemented (%2.2X)",
|
|
LocalType);
|
|
break;
|
|
}
|
|
|
|
switch (Node->Type)
|
|
{
|
|
case ACPI_TYPE_LOCAL_REGION_FIELD:
|
|
|
|
RegionObj = ObjDesc->Field.RegionObj;
|
|
AcpiOsPrintf (" (%s)",
|
|
AcpiUtGetRegionName (RegionObj->Region.SpaceId));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
AcpiOsPrintf ("\n");
|
|
return (Status);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: AcpiDbTestIntegerType
|
|
*
|
|
* PARAMETERS: Node - Parent NS node for the object
|
|
* BitLength - Actual length of the object. Used for
|
|
* support of arbitrary length FieldUnit
|
|
* and BufferField objects.
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Test read/write for an Integer-valued object. Performs a
|
|
* write/read/compare of an arbitrary new value, then performs
|
|
* a write/read/compare of the original value.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbTestIntegerType (
|
|
ACPI_NAMESPACE_NODE *Node,
|
|
UINT32 BitLength)
|
|
{
|
|
ACPI_OBJECT *Temp1 = NULL;
|
|
ACPI_OBJECT *Temp2 = NULL;
|
|
ACPI_OBJECT *Temp3 = NULL;
|
|
ACPI_OBJECT WriteValue;
|
|
UINT64 ValueToWrite;
|
|
ACPI_STATUS Status;
|
|
|
|
|
|
if (BitLength > 64)
|
|
{
|
|
AcpiOsPrintf (" Invalid length for an Integer: %u", BitLength);
|
|
return (AE_OK);
|
|
}
|
|
|
|
/* Read the original value */
|
|
|
|
Status = AcpiDbReadFromObject (Node, ACPI_TYPE_INTEGER, &Temp1);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
AcpiOsPrintf (" (%4.4X/%3.3X) %8.8X%8.8X",
|
|
BitLength, ACPI_ROUND_BITS_UP_TO_BYTES (BitLength),
|
|
ACPI_FORMAT_UINT64 (Temp1->Integer.Value));
|
|
|
|
ValueToWrite = ACPI_UINT64_MAX >> (64 - BitLength);
|
|
if (Temp1->Integer.Value == ValueToWrite)
|
|
{
|
|
ValueToWrite = 0;
|
|
}
|
|
|
|
/* Write a new value */
|
|
|
|
WriteValue.Type = ACPI_TYPE_INTEGER;
|
|
WriteValue.Integer.Value = ValueToWrite;
|
|
Status = AcpiDbWriteToObject (Node, &WriteValue);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/* Ensure that we can read back the new value */
|
|
|
|
Status = AcpiDbReadFromObject (Node, ACPI_TYPE_INTEGER, &Temp2);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (Temp2->Integer.Value != ValueToWrite)
|
|
{
|
|
AcpiOsPrintf (" MISMATCH 2: %8.8X%8.8X, expecting %8.8X%8.8X",
|
|
ACPI_FORMAT_UINT64 (Temp2->Integer.Value),
|
|
ACPI_FORMAT_UINT64 (ValueToWrite));
|
|
}
|
|
|
|
/* Write back the original value */
|
|
|
|
WriteValue.Integer.Value = Temp1->Integer.Value;
|
|
Status = AcpiDbWriteToObject (Node, &WriteValue);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/* Ensure that we can read back the original value */
|
|
|
|
Status = AcpiDbReadFromObject (Node, ACPI_TYPE_INTEGER, &Temp3);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (Temp3->Integer.Value != Temp1->Integer.Value)
|
|
{
|
|
AcpiOsPrintf (" MISMATCH 3: %8.8X%8.8X, expecting %8.8X%8.8X",
|
|
ACPI_FORMAT_UINT64 (Temp3->Integer.Value),
|
|
ACPI_FORMAT_UINT64 (Temp1->Integer.Value));
|
|
}
|
|
|
|
Exit:
|
|
if (Temp1) {AcpiOsFree (Temp1);}
|
|
if (Temp2) {AcpiOsFree (Temp2);}
|
|
if (Temp3) {AcpiOsFree (Temp3);}
|
|
return (AE_OK);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: AcpiDbTestBufferType
|
|
*
|
|
* PARAMETERS: Node - Parent NS node for the object
|
|
* BitLength - Actual length of the object.
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Test read/write for an Buffer-valued object. Performs a
|
|
* write/read/compare of an arbitrary new value, then performs
|
|
* a write/read/compare of the original value.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbTestBufferType (
|
|
ACPI_NAMESPACE_NODE *Node,
|
|
UINT32 BitLength)
|
|
{
|
|
ACPI_OBJECT *Temp1 = NULL;
|
|
ACPI_OBJECT *Temp2 = NULL;
|
|
ACPI_OBJECT *Temp3 = NULL;
|
|
UINT8 *Buffer;
|
|
ACPI_OBJECT WriteValue;
|
|
ACPI_STATUS Status;
|
|
UINT32 ByteLength;
|
|
UINT32 i;
|
|
UINT8 ExtraBits;
|
|
|
|
|
|
ByteLength = ACPI_ROUND_BITS_UP_TO_BYTES (BitLength);
|
|
if (ByteLength == 0)
|
|
{
|
|
AcpiOsPrintf (" Ignoring zero length buffer");
|
|
return (AE_OK);
|
|
}
|
|
|
|
/* Allocate a local buffer */
|
|
|
|
Buffer = ACPI_ALLOCATE_ZEROED (ByteLength);
|
|
if (!Buffer)
|
|
{
|
|
return (AE_NO_MEMORY);
|
|
}
|
|
|
|
/* Read the original value */
|
|
|
|
Status = AcpiDbReadFromObject (Node, ACPI_TYPE_BUFFER, &Temp1);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/* Emit a few bytes of the buffer */
|
|
|
|
AcpiOsPrintf (" (%4.4X/%3.3X)", BitLength, Temp1->Buffer.Length);
|
|
for (i = 0; ((i < 4) && (i < ByteLength)); i++)
|
|
{
|
|
AcpiOsPrintf (" %2.2X", Temp1->Buffer.Pointer[i]);
|
|
}
|
|
AcpiOsPrintf ("... ");
|
|
|
|
/*
|
|
* Write a new value.
|
|
*
|
|
* Handle possible extra bits at the end of the buffer. Can
|
|
* happen for FieldUnits larger than an integer, but the bit
|
|
* count is not an integral number of bytes. Zero out the
|
|
* unused bits.
|
|
*/
|
|
ACPI_MEMSET (Buffer, BUFFER_FILL_VALUE, ByteLength);
|
|
ExtraBits = BitLength % 8;
|
|
if (ExtraBits)
|
|
{
|
|
Buffer [ByteLength - 1] = ACPI_MASK_BITS_ABOVE (ExtraBits);
|
|
}
|
|
|
|
WriteValue.Type = ACPI_TYPE_BUFFER;
|
|
WriteValue.Buffer.Length = ByteLength;
|
|
WriteValue.Buffer.Pointer = Buffer;
|
|
|
|
Status = AcpiDbWriteToObject (Node, &WriteValue);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/* Ensure that we can read back the new value */
|
|
|
|
Status = AcpiDbReadFromObject (Node, ACPI_TYPE_BUFFER, &Temp2);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (ACPI_MEMCMP (Temp2->Buffer.Pointer, Buffer, ByteLength))
|
|
{
|
|
AcpiOsPrintf (" MISMATCH 2: New buffer value");
|
|
}
|
|
|
|
/* Write back the original value */
|
|
|
|
WriteValue.Buffer.Length = ByteLength;
|
|
WriteValue.Buffer.Pointer = Temp1->Buffer.Pointer;
|
|
|
|
Status = AcpiDbWriteToObject (Node, &WriteValue);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/* Ensure that we can read back the original value */
|
|
|
|
Status = AcpiDbReadFromObject (Node, ACPI_TYPE_BUFFER, &Temp3);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (ACPI_MEMCMP (Temp1->Buffer.Pointer, Temp3->Buffer.Pointer, ByteLength))
|
|
{
|
|
AcpiOsPrintf (" MISMATCH 3: While restoring original buffer");
|
|
}
|
|
|
|
Exit:
|
|
ACPI_FREE (Buffer);
|
|
if (Temp1) {AcpiOsFree (Temp1);}
|
|
if (Temp2) {AcpiOsFree (Temp2);}
|
|
if (Temp3) {AcpiOsFree (Temp3);}
|
|
return (Status);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: AcpiDbTestStringType
|
|
*
|
|
* PARAMETERS: Node - Parent NS node for the object
|
|
* ByteLength - Actual length of the object.
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Test read/write for an String-valued object. Performs a
|
|
* write/read/compare of an arbitrary new value, then performs
|
|
* a write/read/compare of the original value.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbTestStringType (
|
|
ACPI_NAMESPACE_NODE *Node,
|
|
UINT32 ByteLength)
|
|
{
|
|
ACPI_OBJECT *Temp1 = NULL;
|
|
ACPI_OBJECT *Temp2 = NULL;
|
|
ACPI_OBJECT *Temp3 = NULL;
|
|
char *ValueToWrite = "Test String from AML Debugger";
|
|
ACPI_OBJECT WriteValue;
|
|
ACPI_STATUS Status;
|
|
|
|
|
|
/* Read the original value */
|
|
|
|
Status = AcpiDbReadFromObject (Node, ACPI_TYPE_STRING, &Temp1);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
AcpiOsPrintf (" (%4.4X/%3.3X) \"%s\"", (Temp1->String.Length * 8),
|
|
Temp1->String.Length, Temp1->String.Pointer);
|
|
|
|
/* Write a new value */
|
|
|
|
WriteValue.Type = ACPI_TYPE_STRING;
|
|
WriteValue.String.Length = ACPI_STRLEN (ValueToWrite);
|
|
WriteValue.String.Pointer = ValueToWrite;
|
|
|
|
Status = AcpiDbWriteToObject (Node, &WriteValue);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/* Ensure that we can read back the new value */
|
|
|
|
Status = AcpiDbReadFromObject (Node, ACPI_TYPE_STRING, &Temp2);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (ACPI_STRCMP (Temp2->String.Pointer, ValueToWrite))
|
|
{
|
|
AcpiOsPrintf (" MISMATCH 2: %s, expecting %s",
|
|
Temp2->String.Pointer, ValueToWrite);
|
|
}
|
|
|
|
/* Write back the original value */
|
|
|
|
WriteValue.String.Length = ACPI_STRLEN (Temp1->String.Pointer);
|
|
WriteValue.String.Pointer = Temp1->String.Pointer;
|
|
|
|
Status = AcpiDbWriteToObject (Node, &WriteValue);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
/* Ensure that we can read back the original value */
|
|
|
|
Status = AcpiDbReadFromObject (Node, ACPI_TYPE_STRING, &Temp3);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (ACPI_STRCMP (Temp1->String.Pointer, Temp3->String.Pointer))
|
|
{
|
|
AcpiOsPrintf (" MISMATCH 3: %s, expecting %s",
|
|
Temp3->String.Pointer, Temp1->String.Pointer);
|
|
}
|
|
|
|
Exit:
|
|
if (Temp1) {AcpiOsFree (Temp1);}
|
|
if (Temp2) {AcpiOsFree (Temp2);}
|
|
if (Temp3) {AcpiOsFree (Temp3);}
|
|
return (Status);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: AcpiDbReadFromObject
|
|
*
|
|
* PARAMETERS: Node - Parent NS node for the object
|
|
* ExpectedType - Object type expected from the read
|
|
* Value - Where the value read is returned
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Performs a read from the specified object by invoking the
|
|
* special debugger control method that reads the object. Thus,
|
|
* the AML interpreter is doing all of the work, increasing the
|
|
* validity of the test.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbReadFromObject (
|
|
ACPI_NAMESPACE_NODE *Node,
|
|
ACPI_OBJECT_TYPE ExpectedType,
|
|
ACPI_OBJECT **Value)
|
|
{
|
|
ACPI_OBJECT *RetValue;
|
|
ACPI_OBJECT_LIST ParamObjects;
|
|
ACPI_OBJECT Params[2];
|
|
ACPI_BUFFER ReturnObj;
|
|
ACPI_STATUS Status;
|
|
|
|
|
|
Params[0].Type = ACPI_TYPE_LOCAL_REFERENCE;
|
|
Params[0].Reference.ActualType = Node->Type;
|
|
Params[0].Reference.Handle = ACPI_CAST_PTR (ACPI_HANDLE, Node);
|
|
|
|
ParamObjects.Count = 1;
|
|
ParamObjects.Pointer = Params;
|
|
|
|
ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
|
|
|
|
AcpiGbl_MethodExecuting = TRUE;
|
|
Status = AcpiEvaluateObject (ReadHandle, NULL, &ParamObjects, &ReturnObj);
|
|
AcpiGbl_MethodExecuting = FALSE;
|
|
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
AcpiOsPrintf ("Could not read from object, %s",
|
|
AcpiFormatException (Status));
|
|
return (Status);
|
|
}
|
|
|
|
RetValue = (ACPI_OBJECT *) ReturnObj.Pointer;
|
|
|
|
switch (RetValue->Type)
|
|
{
|
|
case ACPI_TYPE_INTEGER:
|
|
case ACPI_TYPE_BUFFER:
|
|
case ACPI_TYPE_STRING:
|
|
/*
|
|
* Did we receive the type we wanted? Most important for the
|
|
* Integer/Buffer case (when a field is larger than an Integer,
|
|
* it should return a Buffer).
|
|
*/
|
|
if (RetValue->Type != ExpectedType)
|
|
{
|
|
AcpiOsPrintf (" Type mismatch: Expected %s, Received %s",
|
|
AcpiUtGetTypeName (ExpectedType),
|
|
AcpiUtGetTypeName (RetValue->Type));
|
|
|
|
return (AE_TYPE);
|
|
}
|
|
|
|
*Value = RetValue;
|
|
break;
|
|
|
|
default:
|
|
|
|
AcpiOsPrintf (" Unsupported return object type, %s",
|
|
AcpiUtGetTypeName (RetValue->Type));
|
|
AcpiOsFree (ReturnObj.Pointer);
|
|
|
|
return (AE_TYPE);
|
|
}
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: AcpiDbWriteToObject
|
|
*
|
|
* PARAMETERS: Node - Parent NS node for the object
|
|
* Value - Value to be written
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Performs a write to the specified object by invoking the
|
|
* special debugger control method that writes the object. Thus,
|
|
* the AML interpreter is doing all of the work, increasing the
|
|
* validity of the test.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbWriteToObject (
|
|
ACPI_NAMESPACE_NODE *Node,
|
|
ACPI_OBJECT *Value)
|
|
{
|
|
ACPI_OBJECT_LIST ParamObjects;
|
|
ACPI_OBJECT Params[2];
|
|
ACPI_STATUS Status;
|
|
|
|
|
|
Params[0].Type = ACPI_TYPE_LOCAL_REFERENCE;
|
|
Params[0].Reference.ActualType = Node->Type;
|
|
Params[0].Reference.Handle = ACPI_CAST_PTR (ACPI_HANDLE, Node);
|
|
|
|
/* Copy the incoming user parameter */
|
|
|
|
ACPI_MEMCPY (&Params[1], Value, sizeof (ACPI_OBJECT));
|
|
|
|
ParamObjects.Count = 2;
|
|
ParamObjects.Pointer = Params;
|
|
|
|
AcpiGbl_MethodExecuting = TRUE;
|
|
Status = AcpiEvaluateObject (WriteHandle, NULL, &ParamObjects, NULL);
|
|
AcpiGbl_MethodExecuting = FALSE;
|
|
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
AcpiOsPrintf ("Could not write to object, %s",
|
|
AcpiFormatException (Status));
|
|
}
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: AcpiDbEvaluateAllPredefinedNames
|
|
*
|
|
* PARAMETERS: CountArg - Max number of methods to execute
|
|
*
|
|
* RETURN: None
|
|
*
|
|
* DESCRIPTION: Namespace batch execution. Execute predefined names in the
|
|
* namespace, up to the max count, if specified.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static void
|
|
AcpiDbEvaluateAllPredefinedNames (
|
|
char *CountArg)
|
|
{
|
|
ACPI_DB_EXECUTE_WALK Info;
|
|
|
|
|
|
Info.Count = 0;
|
|
Info.MaxCount = ACPI_UINT32_MAX;
|
|
|
|
if (CountArg)
|
|
{
|
|
Info.MaxCount = ACPI_STRTOUL (CountArg, NULL, 0);
|
|
}
|
|
|
|
/* Search all nodes in namespace */
|
|
|
|
(void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
|
|
AcpiDbEvaluateOnePredefinedName, NULL, (void *) &Info, NULL);
|
|
|
|
AcpiOsPrintf ("Evaluated %u predefined names in the namespace\n", Info.Count);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: AcpiDbEvaluateOnePredefinedName
|
|
*
|
|
* PARAMETERS: Callback from WalkNamespace
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Batch execution module. Currently only executes predefined
|
|
* ACPI names.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static ACPI_STATUS
|
|
AcpiDbEvaluateOnePredefinedName (
|
|
ACPI_HANDLE ObjHandle,
|
|
UINT32 NestingLevel,
|
|
void *Context,
|
|
void **ReturnValue)
|
|
{
|
|
ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
|
|
ACPI_DB_EXECUTE_WALK *Info = (ACPI_DB_EXECUTE_WALK *) Context;
|
|
char *Pathname;
|
|
const ACPI_PREDEFINED_INFO *Predefined;
|
|
ACPI_DEVICE_INFO *ObjInfo;
|
|
ACPI_OBJECT_LIST ParamObjects;
|
|
ACPI_OBJECT Params[ACPI_METHOD_NUM_ARGS];
|
|
ACPI_OBJECT *ThisParam;
|
|
ACPI_BUFFER ReturnObj;
|
|
ACPI_STATUS Status;
|
|
UINT16 ArgTypeList;
|
|
UINT8 ArgCount;
|
|
UINT8 ArgType;
|
|
UINT32 i;
|
|
|
|
|
|
/* The name must be a predefined ACPI name */
|
|
|
|
Predefined = AcpiUtMatchPredefinedMethod (Node->Name.Ascii);
|
|
if (!Predefined)
|
|
{
|
|
return (AE_OK);
|
|
}
|
|
|
|
if (Node->Type == ACPI_TYPE_LOCAL_SCOPE)
|
|
{
|
|
return (AE_OK);
|
|
}
|
|
|
|
Pathname = AcpiNsGetExternalPathname (Node);
|
|
if (!Pathname)
|
|
{
|
|
return (AE_OK);
|
|
}
|
|
|
|
/* Get the object info for number of method parameters */
|
|
|
|
Status = AcpiGetObjectInfo (ObjHandle, &ObjInfo);
|
|
if (ACPI_FAILURE (Status))
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
ParamObjects.Count = 0;
|
|
ParamObjects.Pointer = NULL;
|
|
|
|
if (ObjInfo->Type == ACPI_TYPE_METHOD)
|
|
{
|
|
/* Setup default parameters (with proper types) */
|
|
|
|
ArgTypeList = Predefined->Info.ArgumentList;
|
|
ArgCount = METHOD_GET_ARG_COUNT (ArgTypeList);
|
|
|
|
/*
|
|
* Setup the ACPI-required number of arguments, regardless of what
|
|
* the actual method defines. If there is a difference, then the
|
|
* method is wrong and a warning will be issued during execution.
|
|
*/
|
|
ThisParam = Params;
|
|
for (i = 0; i < ArgCount; i++)
|
|
{
|
|
ArgType = METHOD_GET_NEXT_TYPE (ArgTypeList);
|
|
ThisParam->Type = ArgType;
|
|
|
|
switch (ArgType)
|
|
{
|
|
case ACPI_TYPE_INTEGER:
|
|
|
|
ThisParam->Integer.Value = 1;
|
|
break;
|
|
|
|
case ACPI_TYPE_STRING:
|
|
|
|
ThisParam->String.Pointer = "This is the default argument string";
|
|
ThisParam->String.Length = ACPI_STRLEN (ThisParam->String.Pointer);
|
|
break;
|
|
|
|
case ACPI_TYPE_BUFFER:
|
|
|
|
ThisParam->Buffer.Pointer = (UINT8 *) Params; /* just a garbage buffer */
|
|
ThisParam->Buffer.Length = 48;
|
|
break;
|
|
|
|
case ACPI_TYPE_PACKAGE:
|
|
|
|
ThisParam->Package.Elements = NULL;
|
|
ThisParam->Package.Count = 0;
|
|
break;
|
|
|
|
default:
|
|
|
|
AcpiOsPrintf ("%s: Unsupported argument type: %u\n",
|
|
Pathname, ArgType);
|
|
break;
|
|
}
|
|
|
|
ThisParam++;
|
|
}
|
|
|
|
ParamObjects.Count = ArgCount;
|
|
ParamObjects.Pointer = Params;
|
|
}
|
|
|
|
ACPI_FREE (ObjInfo);
|
|
ReturnObj.Pointer = NULL;
|
|
ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
|
|
|
|
/* Do the actual method execution */
|
|
|
|
AcpiGbl_MethodExecuting = TRUE;
|
|
|
|
Status = AcpiEvaluateObject (Node, NULL, &ParamObjects, &ReturnObj);
|
|
|
|
AcpiOsPrintf ("%-32s returned %s\n", Pathname, AcpiFormatException (Status));
|
|
AcpiGbl_MethodExecuting = FALSE;
|
|
ACPI_FREE (Pathname);
|
|
|
|
/* Ignore status from method execution */
|
|
|
|
Status = AE_OK;
|
|
|
|
/* Update count, check if we have executed enough methods */
|
|
|
|
Info->Count++;
|
|
if (Info->Count >= Info->MaxCount)
|
|
{
|
|
Status = AE_CTRL_TERMINATE;
|
|
}
|
|
|
|
return (Status);
|
|
}
|
|
|
|
#endif /* ACPI_DEBUGGER */
|