windows-nt/Source/XPSP1/NT/base/busdrv/acpi/tools/unasm/parser.c
2020-09-26 16:20:57 +08:00

2250 lines
43 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
parser.c
Abstract:
The aml parser
Author:
Michael Tsang
Stephane Plante
Environment:
Any
Revision History:
--*/
#include "pch.h"
//
// This is a dispatch table
//
typedef NTSTATUS (*PARSE_STATE_FUNCTION) (PSTACK *Stack);
PARSE_STATE_FUNCTION ScopeStates[] = {
ParseFunctionHandler,
ParseArgument,
ParseArgumentObject,
ParseBuffer,
ParseByte,
ParseCodeObject,
ParseConstObject,
ParseData,
ParseDelimiter,
ParseDWord,
ParseField,
ParseLocalObject,
ParseName,
ParseNameObject,
ParseOpcode,
ParsePackage,
ParsePop,
ParsePush,
ParseSuperName,
ParseTrailingArgument,
ParseTrailingBuffer,
ParseTrailingPackage,
ParseVariableObject,
ParseWord
};
NTSTATUS
ParseArgument(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine parses the arguments to a function
Arguments:
Stack - The stack for the current thread
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_AMLTERM amlTerm;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
UCHAR action;
ASSERT( Stack != NULL && *Stack != NULL);
//
// Step 1: Get the current scopes
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Check to see if we still need to process arguments?
//
amlTerm = localScope->AmlTerm;
if ( localScope->Context1 == 0) {
UCHAR actionList[2] = {
SC_PARSE_ARGUMENT,
SC_PARSE_DELIMITER
};
ULONG i;
//
// Step 2.1.1: Push an opening "(" onto the stack
//
StringStackPush( &(rootScope->StringStack), 1, "(" );
//
// Step 2.1.2: Make sure to call the thing to handle the trailing
// argument
//
action = SC_PARSE_TRAILING_ARGUMENT;
StringStackPush( &(rootScope->ParseStack), 1, &action );
//
// Step 2.1.3: This is the first that we have seen of the argument
// Determine the number of bytes to process
//
localScope->Context2 = STRING_LENGTH( amlTerm->ArgumentTypes );
//
// Step 2.1.4: Setup the stack with the appropriate number of
// calls to this function.
//
if (localScope->Context2 >= 2) {
for (i = 0; i < localScope->Context2 - 1; i++) {
StringStackPush( &(rootScope->ParseStack), 2, actionList );
}
}
} else if ( localScope->Context1 >= localScope->Context2 ) {
//
// Step 2.2.1: BAD!!
//
return STATUS_UNSUCCESSFUL;
}
//
// Step 3: Handle the current argument
//
switch( amlTerm->ArgumentTypes[ localScope->Context1 ] ) {
case ARGTYPE_NAME:
action = SC_PARSE_NAME;
break;
case ARGTYPE_DATAOBJECT:
action = SC_PARSE_DATA;
break;
case ARGTYPE_WORD:
action = SC_PARSE_WORD;
break;
case ARGTYPE_DWORD:
action = SC_PARSE_DWORD;
break;
case ARGTYPE_BYTE:
action = SC_PARSE_BYTE;
break;
case ARGTYPE_SUPERNAME:
action = SC_PARSE_SUPER_NAME;
break;
case ARGTYPE_OPCODE: {
UCHAR actionList[2] = {
SC_PARSE_POP,
SC_PARSE_OPCODE
};
//
// Step 3.1: Increment the argument count
//
localScope->Context1++;
//
// Step 3.2: Set up what wee need next
//
StringStackPush( &(rootScope->ParseStack), 2, actionList );
//
// Step 3.3: Push a new scope
//
status = ParsePush( Stack );
if (!NT_SUCCESS(status) ) {
return status;
}
//
// Step 3.4: Make sure to note that we are now nesting things
//
status = StackTop( Stack, &localScope );
if (!NT_SUCCESS( status ) ) {
return status;
}
localScope->Flags |= SC_FLAG_NESTED;
//
// Step 3.5: Done
//
return STATUS_SUCCESS;
}
default:
return STATUS_INVALID_PARAMETER;
}
//
// Step 4: Push the action onto the stack and setup for the next call
//
StringStackPush( &(rootScope->ParseStack), 1, &action );
localScope->Context1++;
//
// Step 5: Done
//
return STATUS_SUCCESS;
}
NTSTATUS
ParseArgumentObject(
IN PSTACK *Stack
)
/*++
Routine Description:
This parses and executes the ArgX instruction
Arguments:
Stack - The stack for the current thread
Return Value:
NTSTATUS
--*/
{
CHAR i;
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
PSTRING_STACK *stringStack;
UCHAR buffer[5];
ASSERT( Stack != NULL && *Stack != NULL );
//
// Step 1: Grab the current and root scope
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Find the string stack to use
//
stringStack = &(rootScope->StringStack);
//
// Step 3: Determine which argument we are looking at
//
i = *(localScope->CurrentByte) - OP_ARG0;
if (i < 0 || i > 7) {
return STATUS_INVALID_PARAMETER;
}
//
// Step 4: Show the argument number to the user
//
STRING_PRINT( buffer, "Arg%1d", i );
StringStackPush( stringStack, 4, buffer );
//
// Step 5: Setup for next state
//
localScope->CurrentByte++;
//
// Step 6: Done
//
return STATUS_SUCCESS;
}
NTSTATUS
ParseBuffer(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine handles buffers
Arguments:
Stack - The stack for the current thread
Return Value:
NTSTATUS;
--*/
{
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
UCHAR actionList[2] = { SC_PARSE_BYTE, SC_PARSE_TRAILING_BUFFER };
ULONG numBytes;
ULONG i;
//
// Step 1: Grab the current scopes
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Determine the number of bytes that we have
//
numBytes = localScope->LastByte - localScope->CurrentByte + 1;
if (numBytes) {
//
// Step 3: Push the leading delimiter
//
StringStackPush( &(rootScope->StringStack), 2, " {" );
//
// Step 4: This handles the last byte in the stream. We assume that
// we have at least one byte otherwise we would not be here
//
StringStackPush( &(rootScope->ParseStack), 1, &(actionList[1]) );
//
// Make sure that we process the right number of bytes
//
actionList[1] = SC_PARSE_DELIMITER;
if (numBytes > 1) {
for (i = 0; i < numBytes - 1; i++) {
StringStackPush( &(rootScope->ParseStack), 2, actionList );
}
}
StringStackPush( &(rootScope->ParseStack),1, actionList );
}
//
// Step 4: Done
//
return STATUS_SUCCESS;
}
NTSTATUS
ParseByte(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine handles bytes
Arguments:
Stack - The stack for the current thread
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
UCHAR localBuffer[6];
ASSERT( Stack != NULL && *Stack != NULL );
//
// Step 1: Grab the current and root scope
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Build the string
//
STRING_PRINT( localBuffer, "0x%02x", *(localScope->CurrentByte) );
//
// Step 3: Move the instruction pointer as appropriate, and setup
// for the next instructions
//
localScope->CurrentByte += 1;
//
// Step 4: Now push the byte onto the string stack
//
StringStackPush(
&(rootScope->StringStack),
STRING_LENGTH( localBuffer ),
localBuffer
);
//
// Step 5: Done
//
return status;
}
NTSTATUS
ParseCodeObject(
IN PSTACK *Stack
)
/*++
Routine Description:
This parses code
Arguments:
Stack - The stack for the current thread
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
PSTRING_STACK *stringStack;
UCHAR action;
ULONG i;
ULONG len;
ASSERT( Stack != NULL && *Stack != NULL);
//
// Step 1: Grab the scope that we will process
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Push a token onto the string stack to present the term
// name
//
StringStackPush(
&(rootScope->StringStack),
STRING_LENGTH( localScope->AmlTerm->TermName ),
localScope->AmlTerm->TermName
);
//
// Step 3: This is guaranteed to be called after all arguments are
// parsed
//
action = SC_FUNCTION_HANDLER;
StringStackPush( &(rootScope->ParseStack), 1, &action );
//
// Step 4: Determine if we have any arguments
//
if (localScope->AmlTerm->ArgumentTypes != NULL) {
//
// Step 4.1.1: Parse the Arguments
//
action = SC_PARSE_ARGUMENT;
StringStackPush( &(rootScope->ParseStack), 1, &action );
//
// Step 4.1.2: Make sure to start the argument index at zero
//
localScope->Context1 = localScope->Context2 = 0;
}
//
// Step 5: Done
//
return STATUS_SUCCESS;
}
NTSTATUS
ParseConstObject(
IN PSTACK *Stack
)
/*++
Routine Description:
This parses constants
Arguments:
Stack - The stack for the current thread
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
PSTRING_STACK *stringStack;
ASSERT( Stack != NULL && *Stack != NULL );
//
// Step 1: Grab the current and root scope
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Find the string stack to use
//
stringStack = &(rootScope->StringStack);
//
// Step 3: Action depends on what the current byte value is:
//
switch ( *(localScope->CurrentByte) ) {
case OP_ZERO:
StringStackPush( stringStack, 4, "Zero" );
break;
case OP_ONE:
StringStackPush( stringStack, 3, "One" );
break;
case OP_ONES:
StringStackPush( stringStack, 4, "Ones" );
break;
case OP_REVISION:
StringStackPush( stringStack, 8, "Revision" );
break;
default:
return STATUS_INVALID_PARAMETER;
}
//
// Step 4: Done with the current byte
//
localScope->CurrentByte++;
//
// Step 5: Done
//
return status;
}
NTSTATUS
ParseData(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine handles data arguments
Arguments:
Stack - The stack for the current thread
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
UCHAR action;
UCHAR currentDataType;
ULONG i;
ULONG num;
ASSERT( Stack != NULL && *Stack != NULL );
//
// Step 1: Grab the current scopes
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Grab the current byte and decide what type of
// data we are looking at based on that value
//
currentDataType = *(localScope->CurrentByte);
localScope->CurrentByte++;
switch( currentDataType ) {
case OP_BYTE:
action = SC_PARSE_BYTE;
break;
case OP_WORD:
action = SC_PARSE_WORD;
break;
case OP_DWORD:
action = SC_PARSE_DWORD;
break;
case OP_STRING:
//
// Step 2.2.1: Determine how long the string is
//
num = STRING_LENGTH( localScope->CurrentByte );
//
// Step 2.2.2: Push that number of bytes onto the string stack
//
StringStackPush( &(rootScope->StringStack), 1, "\"" );
StringStackPush(
&(rootScope->StringStack),
num,
localScope->CurrentByte
);
StringStackPush( &(rootScope->StringStack), 1, "\"" );
//
// Step 2.2.3: Update the current byte pointer and prepare for
// next instructions
//
localScope->CurrentByte += (num + 1);
//
// Step 2.2.4: we don't have a next step, so we just return here
//
return STATUS_SUCCESS;
case OP_BUFFER: {
//
// Step 2.1.1: This is an array of actions that we are about to
// undertake. This reduces the number of calls to StringStackPush
//
UCHAR actionList[4] = {
SC_PARSE_POP,
SC_PARSE_BUFFER,
SC_PARSE_OPCODE,
SC_PARSE_VARIABLE_OBJECT
};
//
// Step 2.1.2: Push this array onto the stack
//
StringStackPush( &(rootScope->ParseStack), 4, actionList );
//
// Step 2.1.3: Display a name
//
StringStackPush( &(rootScope->StringStack), 7, "Buffer=");
//
// Step 2.1.3: Done
//
return STATUS_SUCCESS;
}
case OP_PACKAGE: {
//
// Step 2.3.1: Array of instructions to execute
//
UCHAR actionList[3] = {
SC_PARSE_POP,
SC_PARSE_PACKAGE,
SC_PARSE_VARIABLE_OBJECT
};
//
// Step 2.3.2: Push those instructions onto the stack
StringStackPush( &(rootScope->ParseStack), 3, actionList );
//
//
// Step 2.3.3: Done
//
return STATUS_SUCCESS;
}
default:
localScope->CurrentByte--;
return STATUS_ILLEGAL_INSTRUCTION;
} // switch
//
// Step 3: Push action onto the stack
//
StringStackPush( &(rootScope->ParseStack), 1, &action);
//
// Step 4: done
//
return STATUS_SUCCESS;
}
NTSTATUS
ParseDelimiter(
IN PSTACK *Stack
)
/*--
Routine Description:
This routine is between elements. It is responsible for adding commas
on the string stack
Arguments:
Stack - The current thread of execution
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE rootScope;
//
// Step 1: Get the scope
//
status = StackRoot( Stack, &rootScope );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Step 2: Push the trailer
//
StringStackPush( &(rootScope->StringStack), 1, "," );
//
// Step 3: Done
//
return status;
}
NTSTATUS
ParseDWord(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine handles double words
Arguments:
Stack - The stack for the current thread
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
UCHAR localBuffer[12];
ASSERT( Stack != NULL && *Stack != NULL );
//
// Step 1: Grab the current and root scope
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Build the string
//
STRING_PRINT( localBuffer, "0x%08x", *((PULONG)localScope->CurrentByte));
//
// Step 3: Move the instruction pointer as appropriate, and setup
// for the next instructions
//
localScope->CurrentByte += 4;
//
// Step 4: Now push the byte onto the string stack
//
StringStackPush(
&(rootScope->StringStack),
STRING_LENGTH( localBuffer ),
localBuffer
);
//
// Step 5: Done
//
return status;
}
NTSTATUS
ParseField(
IN PSTACK *Stack
)
/*++
Routine Description:
This is the code that actually parses a field
Arguments:
The current thread's stack
Return Value:
None:
--*/
{
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
UCHAR action;
UCHAR followBits;
UCHAR i;
UCHAR buffer[32];
ULONG size;
//
// Step 1: Grab the current scopes
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Make sure that we still have some room to work with
//
if (localScope->CurrentByte > localScope->LastByte) {
return STATUS_SUCCESS;
}
//
// Step 3: This is the first byte in something that we will print out
// And lets increment the count so that we have an idea of how many
// items we have processed
//
localScope->TermByte = localScope->CurrentByte;
localScope->Context1 += 1;
//
// Step 4: Action depends on current byte
//
if ( *(localScope->CurrentByte) == 0x01) {
UCHAR b1;
UCHAR b2;
//
// Step 4.1.1: Get the two bytes that we are going to use
//
localScope->CurrentByte++;
b1 = *(localScope->CurrentByte++);
b2 = *(localScope->CurrentByte++);
//
// Step 4.1.2: Make the string
//
STRING_PRINT( buffer,"AccessAs: (0x%2x,0x%2x)\n", b1, b2 );
//
// Step 4.1.3: Dump this to the string stack
//
StringStackPush(
&(rootScope->StringStack),
STRING_LENGTH( buffer ),
buffer
);
} else {
//
// Step 4.2.1: Otherwise we have an encoded name
//
if ( *(localScope->CurrentByte) == 0x00 ) {
StringStackPush(
&(rootScope->StringStack),
10,
"(Reserved)"
);
localScope->CurrentByte++;
} else {
StringStackPush(
&(rootScope->StringStack),
sizeof(NAMESEG),
localScope->CurrentByte
);
localScope->CurrentByte += sizeof(NAMESEG);
}
//
// Step 4.2.2: Dump a seperator
//
StringStackPush(
&(rootScope->StringStack),
4,
": 0x"
);
//
// Step 4.2.3: Calculate the size of the field
//
size = (ULONG) *(localScope->CurrentByte);
localScope->CurrentByte++;
followBits = (UCHAR) ( (size & 0xc0) >> 6);
if (followBits) {
size &= 0xf;
for (i = 0; i < followBits; i++) {
size |= (ULONG) *(localScope->CurrentByte) << (i * 8 + 4);
localScope->CurrentByte++;
}
}
//
// Step 4.2.4: Dump a string that is correspondent to the size
// of the number
//
STRING_PRINT( buffer,"%x", size );
//
// Step 4.2.5: Dump the length of the thing
//
StringStackPush(
&(rootScope->StringStack),
STRING_LENGTH( buffer ),
buffer
);
//
// Step 5.4: Print the string out
//
StringStackPush( &(rootScope->StringStack), 1, "\n" );
}
//
// Step 5: Dump the string we generated
//
ScopePrint( Stack );
//
// Step 6: If there are still more thing to processe, we should
// call this function again
//
if (localScope->CurrentByte <= localScope->LastByte) {
action = SC_PARSE_FIELD;
StringStackPush( &(rootScope->ParseStack), 1, &action );
}
//
// Step 7: Done
//
return STATUS_SUCCESS;
}
NTSTATUS
ParseFunctionHandler(
IN PSTACK *Stack
)
/*++
Routine Description:
This code is actually something that transfers control to the term
specific handler
Arguments:
The current thread's stack
Return Value:
None
--*/
{
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
//
// Step 1: Grab the current scopes
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Check to see if we are at the end of the current nest
//
if (!(localScope->Flags & SC_FLAG_NESTED) ) {
//
// Step 2.1: Dump the string
//
StringStackPush( &(rootScope->StringStack), 2, "\n" );
ScopePrint( Stack );
}
//
// Step 4: Call the function handler if there is one
//
if ( localScope->AmlTerm->FunctionHandler != NULL) {
status = (localScope->AmlTerm->FunctionHandler)( Stack );
}
//
// Step 5: Done
//
return status;
}
NTSTATUS
ParseLocalObject(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine handles the LocalX instruction
Arguments:
Stack - The stack for the current thread
Return Value:
NTSTATUS
--*/
{
CHAR i;
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
UCHAR buffer[7];
ASSERT( Stack != NULL && *Stack != NULL );
//
// Step 1: Grab the current and root scope
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Which local are we talking about
//
i = *(localScope->CurrentByte) - OP_LOCAL0;
if ( i < 0 || i > 7) {
return STATUS_INVALID_PARAMETER;
}
//
// Step 3: Display this to the user
//
STRING_PRINT( buffer, "Local%1d", i );
StringStackPush( &(rootScope->StringStack), 6, buffer );
//
// Step 4: Setup for next state
//
localScope->CurrentByte++;
//
// Step 5: Done
//
return status;
}
NTSTATUS
ParseName(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine handles generating the argument name
Arguments:
Stack - The Stack for the current thread
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
PSTRING_STACK *stringStack;
ULONG nameSegmentCount = 1;
ASSERT( Stack != NULL && *Stack != NULL );
//
// Step 1: Grab the current and local scope
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Delimit the String
//
stringStack = &(rootScope->StringStack);
StringStackPush( stringStack, 1, "\"");
//
// Step 3: Action depends on what the current byte value is:
//
switch ( *(localScope->CurrentByte) ) {
case OP_ROOT_PREFIX:
StringStackPush( stringStack, 1, "\\" );
localScope->CurrentByte++;
break;
case OP_PARENT_PREFIX:
while ( *(localScope->CurrentByte) == OP_PARENT_PREFIX ) {
StringStackPush( stringStack, 1, "^" );
localScope->CurrentByte++;
}
break;
}
//
// Step 4: Determine the number of Name segments we are adding
//
switch ( *(localScope->CurrentByte) ) {
case '\0':
nameSegmentCount = 0;
localScope->CurrentByte++;
break;
case OP_MULTI_NAME_PREFIX:
//
// The next byte contains the number of name segments
//
localScope->CurrentByte++;
nameSegmentCount = (ULONG) *(localScope->CurrentByte);
localScope->CurrentByte++;
break;
case OP_DUAL_NAME_PREFIX:
//
// There are two name segments
//
nameSegmentCount = 2;
localScope->CurrentByte++;
break;
}
//
// Step 5: Push the name segments onto the stack
//
while (nameSegmentCount > 0) {
//
// Step 5.1 Add the segment onto the stack
//
StringStackPush(
stringStack,
sizeof( NAMESEG ),
localScope->CurrentByte
);
//
// Step 5.2: Decrement the number of remaining segments and
// move the current byte pointer to point to the next
// interesting thing
//
nameSegmentCount--;
localScope->CurrentByte += sizeof(NAMESEG);
//
// Step 5.3: Check to see if we should add a seperator
//
if (nameSegmentCount) {
StringStackPush( stringStack, 1, "." );
}
}
//
// Step 6: Push the closing delimiter
//
StringStackPush( stringStack, 1, "\"" );
//
// Step 7: done
//
return STATUS_SUCCESS;
}
NTSTATUS
ParseNameObject(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine handles name objects
Arguments:
Stack - The stack for the current thread
Return Value:
NTSTATUS
--*/
{
//
// Note: at this time, this function is just a wrapper for
// ParseName(). If that was an assembler, it would have to execute
// something here
//
return ParseName( Stack );
}
NTSTATUS
ParseOpcode(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine is the main parsing point for AML opcode
Arguments:
Stack - The stack for the current thread
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_AMLTERM amlTerm;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
UCHAR action;
ULONG termGroup;
ASSERT( Stack != NULL && *Stack != NULL );
//
// Step 1: Grab the current scopes
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Check to see if we are past the end byte?
//
if (localScope->CurrentByte > localScope->LastByte) {
return STATUS_SUCCESS;
}
//
// Step 3: Remember which byte demarked the start of the
// instruction
//
localScope->TermByte = localScope->CurrentByte;
//
// Step 4: Check to see if this is an extended instruction
//
if ( *(localScope->CurrentByte) == OP_EXT_PREFIX) {
//
// Step 4.1.1: Extended opcode. Next instruction will let us find the
// AML term to use for the evaluation
//
localScope->CurrentByte++;
//
// Step 4.1.2: Grab the AML term for the extended operation
//
amlTerm = localScope->AmlTerm = ScopeFindExtendedOpcode( Stack );
} else {
//
// Step 4.2.1: Grab the AML term for the current operation
//
amlTerm = localScope->AmlTerm =
OpcodeTable[ *(localScope->CurrentByte) ];
}
localScope->Context1 = localScope->Context2 = 0;
//
// Step 5: Check to see if we have a valid AML term
//
if (localScope->AmlTerm == NULL) {
return STATUS_UNSUCCESSFUL;
}
//
// Step 6: Farm out the real work to functions that are better capable
// of handling the current AML term
//
termGroup = (amlTerm->OpCodeFlags & 0xFF);
switch( termGroup ) {
case OF_NORMAL_OBJECT:
case OF_VARIABLE_LIST:
case OF_REF_OBJECT:
//
// Step 6.1: If we are going to handle a variable length instruction
// than we must also pop it from the stack
//
if (amlTerm->OpCodeFlags == OF_VARIABLE_LIST) {
UCHAR actionList[5] = {
SC_PARSE_OPCODE,
SC_PARSE_POP,
SC_PARSE_OPCODE,
SC_PARSE_CODE_OBJECT,
SC_PARSE_VARIABLE_OBJECT
};
StringStackPush( &(rootScope->ParseStack), 5, actionList );
} else {
//
// If we are already nested, we know that there is an ParseOpcode
// just waiting for us...
//
if (!(localScope->Flags & SC_FLAG_NESTED)) {
action = SC_PARSE_OPCODE;
StringStackPush( &(rootScope->ParseStack), 1, &action);
}
action = SC_PARSE_CODE_OBJECT;
StringStackPush( &(rootScope->ParseStack), 1, &action);
}
//
// Step 6.2: This is a code byte. Ergo we eat it since we just
// processed it
//
localScope->CurrentByte++;
//
// Step 6.3: Done
//
return STATUS_SUCCESS;
case OF_NAME_OBJECT:
action = SC_PARSE_NAME_OBJECT;
break;
case OF_DATA_OBJECT:
action = SC_PARSE_DATA;
break;
case OF_CONST_OBJECT:
action = SC_PARSE_CONST_OBJECT;
break;
case OF_ARG_OBJECT:
action = SC_PARSE_ARGUMENT_OBJECT;
break;
case OF_LOCAL_OBJECT:
action = SC_PARSE_LOCAL_OBJECT;
break;
default:
return STATUS_NOT_SUPPORTED;
}
//
// Step 7: Actually push the action to execute next on to the stack
//
StringStackPush( &(rootScope->ParseStack), 1, &action );
//
// Step 8: Done
//
return STATUS_SUCCESS;
}
NTSTATUS
ParsePackage(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine parses the stages of a package
Arguments:
The current thread's stack
Note: Caller needs to push a stack location before calling this and they
have to pop it when it finishes
Return Value:
NTSTATUS:
--*/
{
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
UCHAR action;
//
// Step 1: Grab the current scopes
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Context1 is the current index in the package...
//
if (localScope->Context1 == 0) {
UCHAR actionList[2] = {
SC_PARSE_PACKAGE,
SC_PARSE_DELIMITER
};
ULONG i;
//
// Step 2.1.1: This is the first call to parse package...
// What we need to do here is handle the first argument here,
// and make sure that we get called again for the remaining
// arguments
//
StringStackPush( &(rootScope->StringStack), 1, "[" );
//
// Step 2.1.2: This byte contains the number of arguments to handle
//
localScope->Context2 = *(localScope->CurrentByte);
localScope->CurrentByte++;
//
// Step 2.1.3: Make sure that we close that bracket above
//
action = SC_PARSE_TRAILING_PACKAGE;
StringStackPush( &(rootScope->ParseStack), 1, &action );
//
// Step 2.1.3: Setup all the remaining calls to this function
//
if (localScope->Context2 >= 2) {
for (i=0; i < localScope->Context2 - 1; i++) {
StringStackPush( &(rootScope->ParseStack), 2, actionList );
}
}
} else if (localScope->Context1 >= localScope->Context2) {
//
// Step 2.2.1: We are at the end of the package
//
return STATUS_UNSUCCESSFUL;
}
//
// Step 3: Farm out the work depending on what the current byte is
// This looks a lot like ParseData, but note the new default case
//
switch ( *(localScope->CurrentByte) ) {
case OP_BYTE:
case OP_WORD:
case OP_DWORD:
case OP_BUFFER:
case OP_STRING:
case OP_PACKAGE:
action = SC_PARSE_DATA;
break;
default:
action = SC_PARSE_NAME;
}
//
// Step 4: Push the next action onto the stack
//
StringStackPush( &(rootScope->ParseStack), 1, &action );
localScope->Context1++;
//
// Step 5: done
//
return STATUS_SUCCESS;
}
NTSTATUS
ParsePop(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine removes the top level of the stack and updates the
current byte as appropriate
Arguments:
The current thread's stack
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE topScope;
PUNASM_SCOPE prevScope;
//
// Step 1: Get the top scope
//
status = StackTop( Stack, &topScope );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Step 2: Get the previous scope
//
status = StackParent( Stack, topScope, &prevScope );
if (!NT_SUCCESS(status)) {
//
// Step 2.1: There is actually no parent to this function ...
// Just pop the top and return
//
return StackPop( Stack );
}
//
// Step 3: Make sure to update the prevScope's current byte
//
if (topScope->CurrentByte > prevScope->CurrentByte) {
prevScope->CurrentByte = topScope->CurrentByte;
}
//
// Step 4: Pop the top stack and return
//
return StackPop( Stack );
}
NTSTATUS
ParsePush(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine handles adding a level to the stack
Arguments:
The thread's current stack
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE curScope;
PUNASM_SCOPE newScope;
//
// Step 1: Create a new scope on the stack
//
status = StackPush( Stack, &newScope );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Step 2: Grab the parent from the stack
//
status = StackParent( Stack, newScope, &curScope );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Step 3: Copy the important values
//
newScope->CurrentByte = curScope->CurrentByte;
newScope->TermByte = curScope->TermByte;
newScope->LastByte = curScope->LastByte;
newScope->StringStack = curScope->StringStack;
newScope->IndentLevel = curScope->IndentLevel;
newScope->AmlTerm = curScope->AmlTerm;
newScope->Flags = curScope->Flags;
//
// Step 4: Done
//
return STATUS_SUCCESS;
}
NTSTATUS
ParseScope(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine handles super names
Arguments:
Stack - The current thread of execution
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
PUCHAR action;
UCHAR defAction = SC_PARSE_OPCODE;
ASSERT( Stack != NULL && *Stack != NULL);
//
// Step 1: Loop forever
//
while (1) {
//
// Step 2: Get the top of stack, and while it exits, process
// the current operation
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 3: We are done if we are in the root scope and the
// current byte exceeds the last byte
//
if (localScope == rootScope &&
localScope->CurrentByte > localScope->LastByte) {
//
// Step 3.1 Done!
//
return STATUS_SUCCESS;
}
//
// Step 4: Fetch thing to execute
//
status = StringStackPop( &(rootScope->ParseStack), 1, &action );
if (!NT_SUCCESS(status)) {
//
// Step 4.1.1: This is fixed in the look up table
//
status = (ScopeStates[ SC_PARSE_OPCODE ])( Stack );
} else {
//
// Step 4.1.2: Determine what to execute
//
ASSERT( *action <= SC_MAX_TABLE );
status = (ScopeStates[ *action ])( Stack );
}
if (!NT_SUCCESS(status)) {
break;
}
}
//
// Step 5: Show the user the error
//
PRINTF("Error Code: %x\n", status );
return status;
}
NTSTATUS
ParseSuperName(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine handles super names
Arguments:
Stack - The current thread of execution
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_AMLTERM amlTerm;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
UCHAR action;
ASSERT( Stack != NULL && *Stack != NULL);
//
// Step 1: Get the scopes
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: What we do next depend on the current byte
//
if ( *(localScope->CurrentByte) == 0) {
//
// Unknown
//
localScope->CurrentByte++;
return STATUS_SUCCESS;
} else if ( *(localScope->CurrentByte) == OP_EXT_PREFIX &&
*(localScope->CurrentByte + 1) == EXOP_DEBUG) {
//
// Debug Object
//
localScope->CurrentByte += 2;
return STATUS_SUCCESS;
} else if ( OpcodeTable[ *(localScope->CurrentByte) ] == NULL) {
return STATUS_INVALID_PARAMETER;
}
//
// Step 3: Now, our action depends on the current AML Term
//
amlTerm = OpcodeTable[ *(localScope->CurrentByte) ];
if ( amlTerm->OpCodeFlags == OF_NAME_OBJECT) {
//
// We have a name to parse
//
action = SC_PARSE_NAME;
} else if ( amlTerm->OpCodeFlags == OF_ARG_OBJECT) {
//
// We have an argument to parse
//
action = SC_PARSE_ARGUMENT_OBJECT;
} else if ( amlTerm->OpCodeFlags == OF_LOCAL_OBJECT) {
//
// We have a local object...
//
action = SC_PARSE_LOCAL_OBJECT;
} else if ( amlTerm->OpCodeFlags == OF_REF_OBJECT) {
UCHAR actionList[3] = {
SC_PARSE_OPCODE,
SC_PARSE_POP,
SC_PARSE_OPCODE
};
//
// Step 3.1: Set up the initial task of the new scope
//
StringStackPush( &(rootScope->ParseStack), 3, actionList );
//
// Step 3.2: Push a new scope
//
status = ParsePush( Stack );
if (!NT_SUCCESS(status) ) {
return status;
}
//
// Step 3.3: Done
//
return STATUS_SUCCESS;
} else {
return STATUS_INVALID_PARAMETER;
}
//
// Step 4: Push the action onto the stack
//
StringStackPush( &(rootScope->ParseStack), 1, &action );
//
// Step 5: Done
//
return STATUS_SUCCESS;
}
NTSTATUS
ParseTrailingArgument(
IN PSTACK *Stack
)
/*--
Routine Description:
This routine is run at after all arguments are parsed. It is responsible
for placing a trailing parentheses on the string stack
Arguments:
Stack - The current thread of execution
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE rootScope;
//
// Step 1: Get the scope
//
status = StackRoot( Stack, &rootScope );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Step 2: Push the trailer
//
StringStackPush( &(rootScope->StringStack), 1, ")" );
//
// Step 3: Done
//
return status;
}
NTSTATUS
ParseTrailingBuffer(
IN PSTACK *Stack
)
/*--
Routine Description:
This routine is run at after the buffer is parsed. It is responsible
for placing a trailing curly brace on the string stack
Arguments:
Stack - The current thread of execution
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE rootScope;
//
// Step 1: Get the scope
//
status = StackRoot( Stack, &rootScope );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Step 2: Push the trailer
//
StringStackPush( &(rootScope->StringStack), 1, "}" );
//
// Step 3: Done
//
return status;
}
NTSTATUS
ParseTrailingPackage(
IN PSTACK *Stack
)
/*--
Routine Description:
This routine is run at after all elements are parsed. It is responsible
for placing a trailing brace on the string stack
Arguments:
Stack - The current thread of execution
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE rootScope;
//
// Step 1: Get the scope
//
status = StackRoot( Stack, &rootScope );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Step 2: Push the trailer
//
StringStackPush( &(rootScope->StringStack), 1, "]" );
//
// Step 3: Done
//
return status;
}
NTSTATUS
ParseVariableObject(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine creates another scope level on the stack to process the
current variable length instruction. It modifies the current scope
to (correctly) point to the next instruction
Note: Callers of this function are expected to pop off the stack
when it is no longer required!!!
Arguments:
Stack - The current thread of execution
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE newScope;
PUNASM_SCOPE oldScope;
PUCHAR nextOpcode;
UCHAR i;
UCHAR lengthBytes;
ULONG packageLength;
ASSERT( Stack != NULL && *Stack != NULL);
//
// Step 1: Create a new scope on the stack
//
status = ParsePush( Stack );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Step 2: Get the new top scope and its parent
//
status = StackTop( Stack, &newScope );
if (!NT_SUCCESS( status ) ) {
return status;
}
status = StackParent( Stack, newScope, &oldScope );
if (!NT_SUCCESS( status ) ) {
return status;
}
//
// Step 3: Determine how bytes the current instruction takes
//
packageLength = (ULONG) *(newScope->CurrentByte);
newScope->CurrentByte++;
//
// Step 4: If the the high 2 bits are set, this indicates that some
// follow on bits are also used in calculating the length
//
lengthBytes = (UCHAR) ( ( packageLength & 0xC0) >> 6);
if (lengthBytes) {
//
// Step 4.1: Mask off the non-length bits in the packageLength
//
packageLength &= 0xF;
//
// Step 4.2: Add the follow-on lengths
//
for (i = 0; i < lengthBytes; i++) {
packageLength |= ( (ULONG) *(newScope->CurrentByte) << (i*8 + 4) );
newScope->CurrentByte++;
}
}
//
// Step 5: We can calculate the start of the next opcode as the
// opcode in the old scope plus the calculated length. The end of
// new scope is the byte previous to this one
//
oldScope->CurrentByte += packageLength;
newScope->LastByte = oldScope->CurrentByte - 1;
//
// Step 6: Done
//
return STATUS_SUCCESS;
}
NTSTATUS
ParseWord(
IN PSTACK *Stack
)
/*++
Routine Description:
This routine handles words
Arguments:
Stack - The stack for the current thread
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PUNASM_SCOPE localScope;
PUNASM_SCOPE rootScope;
UCHAR localBuffer[8];
ASSERT( Stack != NULL && *Stack != NULL );
//
// Step 1: Grab the current and root scope
//
ScopeFindLocalScope( Stack, &localScope, &rootScope, status );
//
// Step 2: Build the string
//
STRING_PRINT( localBuffer, "0x%04x", *((PUSHORT)localScope->CurrentByte));
//
// Step 3: Move the instruction pointer as appropriate, and setup
// for the next instructions
//
localScope->CurrentByte += 2;
//
// Step 4: Now push the byte onto the string stack
//
StringStackPush(
&(rootScope->StringStack),
STRING_LENGTH( localBuffer ),
localBuffer
);
//
// Step 5: Done
//
return status;
}