2250 lines
43 KiB
C
2250 lines
43 KiB
C
/*++
|
||
|
||
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;
|
||
}
|
||
|