You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2249 lines
45 KiB
2249 lines
45 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|