/*++ 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; }