1295571Sjkim/****************************************************************************** 2295571Sjkim * 3295571Sjkim * Module Name: aslexternal - ASL External opcode compiler support 4295571Sjkim * 5295571Sjkim *****************************************************************************/ 6295571Sjkim 7295571Sjkim/* 8295571Sjkim * Copyright (C) 2000 - 2016, Intel Corp. 9295571Sjkim * All rights reserved. 10295571Sjkim * 11295571Sjkim * Redistribution and use in source and binary forms, with or without 12295571Sjkim * modification, are permitted provided that the following conditions 13295571Sjkim * are met: 14295571Sjkim * 1. Redistributions of source code must retain the above copyright 15295571Sjkim * notice, this list of conditions, and the following disclaimer, 16295571Sjkim * without modification. 17295571Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18295571Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19295571Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20295571Sjkim * including a substantially similar Disclaimer requirement for further 21295571Sjkim * binary redistribution. 22295571Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23295571Sjkim * of any contributors may be used to endorse or promote products derived 24295571Sjkim * from this software without specific prior written permission. 25295571Sjkim * 26295571Sjkim * Alternatively, this software may be distributed under the terms of the 27295571Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28295571Sjkim * Software Foundation. 29295571Sjkim * 30295571Sjkim * NO WARRANTY 31295571Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32295571Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33295571Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34295571Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35295571Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36295571Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37295571Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38295571Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39295571Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40295571Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41295571Sjkim * POSSIBILITY OF SUCH DAMAGES. 42295571Sjkim */ 43295571Sjkim 44298714Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h> 45295571Sjkim#include "aslcompiler.y.h" 46298714Sjkim#include <contrib/dev/acpica/include/acparser.h> 47298714Sjkim#include <contrib/dev/acpica/include/amlcode.h> 48298714Sjkim#include <contrib/dev/acpica/include/acnamesp.h> 49295571Sjkim 50295571Sjkim 51295571Sjkim#define _COMPONENT ACPI_COMPILER 52295571Sjkim ACPI_MODULE_NAME ("aslexternal") 53295571Sjkim 54295571Sjkim 55295571Sjkim/* Local prototypes */ 56295571Sjkim 57295571Sjkimstatic void 58295571SjkimExInsertArgCount ( 59295571Sjkim ACPI_PARSE_OBJECT *Op); 60295571Sjkim 61295571Sjkimstatic void 62295571SjkimExMoveExternals ( 63295571Sjkim ACPI_PARSE_OBJECT *DefinitionBlockOp); 64295571Sjkim 65295571Sjkim 66295571Sjkim/******************************************************************************* 67295571Sjkim * 68295571Sjkim * FUNCTION: ExDoExternal 69295571Sjkim * 70295571Sjkim * PARAMETERS: Op - Current Parse node 71295571Sjkim * 72295571Sjkim * RETURN: None 73295571Sjkim * 74295571Sjkim * DESCRIPTION: Add an External() definition to the global list. This list 75295571Sjkim * is used to generate External opcodes. 76295571Sjkim * 77295571Sjkim ******************************************************************************/ 78295571Sjkim 79295571Sjkimvoid 80295571SjkimExDoExternal ( 81295571Sjkim ACPI_PARSE_OBJECT *Op) 82295571Sjkim{ 83295571Sjkim ACPI_PARSE_OBJECT *ListOp; 84295571Sjkim ACPI_PARSE_OBJECT *Prev; 85295571Sjkim ACPI_PARSE_OBJECT *Next; 86295571Sjkim ACPI_PARSE_OBJECT *ArgCountOp; 87295571Sjkim 88295571Sjkim 89295571Sjkim ArgCountOp = Op->Asl.Child->Asl.Next->Asl.Next; 90295571Sjkim ArgCountOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE; 91295571Sjkim ArgCountOp->Asl.ParseOpcode = PARSEOP_BYTECONST; 92295571Sjkim ArgCountOp->Asl.Value.Integer = 0; 93295571Sjkim UtSetParseOpName (ArgCountOp); 94295571Sjkim 95295571Sjkim /* Create new list node of arbitrary type */ 96295571Sjkim 97295571Sjkim ListOp = TrAllocateNode (PARSEOP_DEFAULT_ARG); 98295571Sjkim 99295571Sjkim /* Store External node as child */ 100295571Sjkim 101295571Sjkim ListOp->Asl.Child = Op; 102295571Sjkim ListOp->Asl.Next = NULL; 103295571Sjkim 104295571Sjkim if (Gbl_ExternalsListHead) 105295571Sjkim { 106295571Sjkim /* Link new External to end of list */ 107295571Sjkim 108295571Sjkim Prev = Gbl_ExternalsListHead; 109295571Sjkim Next = Prev; 110295571Sjkim while (Next) 111295571Sjkim { 112295571Sjkim Prev = Next; 113295571Sjkim Next = Next->Asl.Next; 114295571Sjkim } 115295571Sjkim 116295571Sjkim Prev->Asl.Next = ListOp; 117295571Sjkim } 118295571Sjkim else 119295571Sjkim { 120295571Sjkim Gbl_ExternalsListHead = ListOp; 121295571Sjkim } 122295571Sjkim} 123295571Sjkim 124295571Sjkim 125295571Sjkim/******************************************************************************* 126295571Sjkim * 127295571Sjkim * FUNCTION: ExInsertArgCount 128295571Sjkim * 129295571Sjkim * PARAMETERS: Op - Op for a method invocation 130295571Sjkim * 131295571Sjkim * RETURN: None 132295571Sjkim * 133295571Sjkim * DESCRIPTION: Obtain the number of arguments for a control method -- from 134295571Sjkim * the actual invocation. 135295571Sjkim * 136295571Sjkim ******************************************************************************/ 137295571Sjkim 138295571Sjkimstatic void 139295571SjkimExInsertArgCount ( 140295571Sjkim ACPI_PARSE_OBJECT *Op) 141295571Sjkim{ 142295571Sjkim ACPI_PARSE_OBJECT *Next; 143295571Sjkim ACPI_PARSE_OBJECT *NameOp; 144295571Sjkim ACPI_PARSE_OBJECT *Child; 145295571Sjkim ACPI_PARSE_OBJECT *ArgCountOp; 146295571Sjkim char * ExternalName; 147295571Sjkim char * CallName; 148295571Sjkim UINT16 ArgCount = 0; 149298714Sjkim ACPI_STATUS Status; 150295571Sjkim 151295571Sjkim 152295571Sjkim CallName = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE); 153295571Sjkim 154295571Sjkim Next = Gbl_ExternalsListHead; 155295571Sjkim while (Next) 156295571Sjkim { 157295571Sjkim ArgCount = 0; 158295571Sjkim 159295571Sjkim /* Skip if External node already handled */ 160295571Sjkim 161295571Sjkim if (Next->Asl.Child->Asl.CompileFlags & NODE_VISITED) 162295571Sjkim { 163295571Sjkim Next = Next->Asl.Next; 164295571Sjkim continue; 165295571Sjkim } 166295571Sjkim 167295571Sjkim NameOp = Next->Asl.Child->Asl.Child; 168295571Sjkim ExternalName = AcpiNsGetNormalizedPathname (NameOp->Asl.Node, TRUE); 169295571Sjkim 170298714Sjkim if (strcmp (CallName, ExternalName)) 171295571Sjkim { 172298714Sjkim ACPI_FREE (ExternalName); 173298714Sjkim Next = Next->Asl.Next; 174298714Sjkim continue; 175298714Sjkim } 176295571Sjkim 177298714Sjkim Next->Asl.Child->Asl.CompileFlags |= NODE_VISITED; 178295571Sjkim 179298714Sjkim /* 180298714Sjkim * Since we will reposition Externals to the Root, set Namepath 181298714Sjkim * to the fully qualified name and recalculate the aml length 182298714Sjkim */ 183298714Sjkim Status = UtInternalizeName (ExternalName, 184298714Sjkim &NameOp->Asl.Value.String); 185295571Sjkim 186298714Sjkim ACPI_FREE (ExternalName); 187298714Sjkim if (ACPI_FAILURE (Status)) 188298714Sjkim { 189298714Sjkim AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, 190298714Sjkim NULL, "- Could not Internalize External"); 191298714Sjkim break; 192298714Sjkim } 193295571Sjkim 194298714Sjkim NameOp->Asl.AmlLength = strlen (NameOp->Asl.Value.String); 195295571Sjkim 196298714Sjkim /* Get argument count */ 197295571Sjkim 198298714Sjkim Child = Op->Asl.Child; 199298714Sjkim while (Child) 200298714Sjkim { 201298714Sjkim ArgCount++; 202298714Sjkim Child = Child->Asl.Next; 203295571Sjkim } 204295571Sjkim 205298714Sjkim /* Setup ArgCount operand */ 206298714Sjkim 207298714Sjkim ArgCountOp = Next->Asl.Child->Asl.Child->Asl.Next->Asl.Next; 208298714Sjkim ArgCountOp->Asl.Value.Integer = ArgCount; 209298714Sjkim break; 210295571Sjkim } 211298714Sjkim 212298714Sjkim ACPI_FREE (CallName); 213295571Sjkim} 214295571Sjkim 215295571Sjkim 216295571Sjkim/******************************************************************************* 217295571Sjkim * 218295571Sjkim * FUNCTION: ExAmlExternalWalkBegin 219295571Sjkim * 220295571Sjkim * PARAMETERS: ASL_WALK_CALLBACK 221295571Sjkim * 222295571Sjkim * RETURN: None 223295571Sjkim * 224295571Sjkim * DESCRIPTION: Parse tree walk to create external opcode list for methods. 225295571Sjkim * 226295571Sjkim ******************************************************************************/ 227295571Sjkim 228295571SjkimACPI_STATUS 229295571SjkimExAmlExternalWalkBegin ( 230295571Sjkim ACPI_PARSE_OBJECT *Op, 231295571Sjkim UINT32 Level, 232295571Sjkim void *Context) 233295571Sjkim{ 234295571Sjkim 235295571Sjkim /* External list head saved in the definition block op */ 236295571Sjkim 237295571Sjkim if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK) 238295571Sjkim { 239295571Sjkim Gbl_ExternalsListHead = Op->Asl.Value.Arg; 240295571Sjkim } 241295571Sjkim 242295571Sjkim if (!Gbl_ExternalsListHead) 243295571Sjkim { 244295571Sjkim return (AE_OK); 245295571Sjkim } 246295571Sjkim 247295571Sjkim if (Op->Asl.ParseOpcode != PARSEOP_METHODCALL) 248295571Sjkim { 249295571Sjkim return (AE_OK); 250295571Sjkim } 251295571Sjkim 252295571Sjkim /* 253295571Sjkim * The NameOp child under an ExternalOp gets turned into PARSE_METHODCALL 254295571Sjkim * by XfNamespaceLocateBegin(). Ignore these. 255295571Sjkim */ 256295571Sjkim if (Op->Asl.Parent && 257295571Sjkim Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_EXTERNAL) 258295571Sjkim { 259295571Sjkim return (AE_OK); 260295571Sjkim } 261295571Sjkim 262295571Sjkim ExInsertArgCount (Op); 263295571Sjkim return (AE_OK); 264295571Sjkim} 265295571Sjkim 266295571Sjkim 267295571Sjkim/******************************************************************************* 268295571Sjkim * 269295571Sjkim * FUNCTION: ExAmlExternalWalkEnd 270295571Sjkim * 271295571Sjkim * PARAMETERS: ASL_WALK_CALLBACK 272295571Sjkim * 273295571Sjkim * RETURN: None 274295571Sjkim * 275295571Sjkim * DESCRIPTION: Parse tree walk to create external opcode list for methods. 276295571Sjkim * Here, we just want to catch the case where a definition block 277295571Sjkim * has been completed. Then we move all of the externals into 278295571Sjkim * a single block in the parse tree and thus the AML code. 279295571Sjkim * 280295571Sjkim ******************************************************************************/ 281295571Sjkim 282295571SjkimACPI_STATUS 283295571SjkimExAmlExternalWalkEnd ( 284295571Sjkim ACPI_PARSE_OBJECT *Op, 285295571Sjkim UINT32 Level, 286295571Sjkim void *Context) 287295571Sjkim{ 288295571Sjkim 289295571Sjkim if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK) 290295571Sjkim { 291295571Sjkim /* 292295571Sjkim * Process any existing external list. (Support for 293295571Sjkim * multiple definition blocks in a single file/compile) 294295571Sjkim */ 295295571Sjkim ExMoveExternals (Op); 296295571Sjkim Gbl_ExternalsListHead = NULL; 297295571Sjkim } 298295571Sjkim 299295571Sjkim return (AE_OK); 300295571Sjkim} 301295571Sjkim 302295571Sjkim 303295571Sjkim/******************************************************************************* 304295571Sjkim * 305295571Sjkim * FUNCTION: ExMoveExternals 306295571Sjkim * 307295571Sjkim * PARAMETERS: DefinitionBlockOp - Op for current definition block 308295571Sjkim * 309295571Sjkim * RETURN: None 310295571Sjkim * 311295571Sjkim * DESCRIPTION: Move all externals present in the source file into a single 312295571Sjkim * block of AML code, surrounded by an "If (0)" to prevent 313295571Sjkim * AML interpreters from attempting to execute the External 314295571Sjkim * opcodes. 315295571Sjkim * 316295571Sjkim ******************************************************************************/ 317295571Sjkim 318295571Sjkimstatic void 319295571SjkimExMoveExternals ( 320295571Sjkim ACPI_PARSE_OBJECT *DefinitionBlockOp) 321295571Sjkim{ 322295571Sjkim ACPI_PARSE_OBJECT *ParentOp; 323295571Sjkim ACPI_PARSE_OBJECT *ExternalOp; 324295571Sjkim ACPI_PARSE_OBJECT *PredicateOp; 325295571Sjkim ACPI_PARSE_OBJECT *NextOp; 326295571Sjkim ACPI_PARSE_OBJECT *Prev; 327295571Sjkim ACPI_PARSE_OBJECT *Next; 328295571Sjkim ACPI_OBJECT_TYPE ObjType; 329295571Sjkim UINT32 i; 330295571Sjkim 331295571Sjkim 332295571Sjkim if (!Gbl_ExternalsListHead) 333295571Sjkim { 334295571Sjkim return; 335295571Sjkim } 336295571Sjkim 337295571Sjkim /* Remove the External nodes from the tree */ 338295571Sjkim 339295571Sjkim NextOp = Gbl_ExternalsListHead; 340295571Sjkim while (NextOp) 341295571Sjkim { 342295571Sjkim /* 343295571Sjkim * The External is stored in child pointer of each node in the 344295571Sjkim * list 345295571Sjkim */ 346295571Sjkim ExternalOp = NextOp->Asl.Child; 347295571Sjkim 348295571Sjkim /* Set line numbers (for listings, etc.) */ 349295571Sjkim 350295571Sjkim ExternalOp->Asl.LineNumber = 0; 351295571Sjkim ExternalOp->Asl.LogicalLineNumber = 0; 352295571Sjkim 353295571Sjkim Next = ExternalOp->Asl.Child; 354295571Sjkim Next->Asl.LineNumber = 0; 355295571Sjkim Next->Asl.LogicalLineNumber = 0; 356295571Sjkim 357295571Sjkim Next = Next->Asl.Next; 358295571Sjkim Next->Asl.LineNumber = 0; 359295571Sjkim Next->Asl.LogicalLineNumber = 0; 360295571Sjkim 361295571Sjkim Next = Next->Asl.Next; 362295571Sjkim Next->Asl.LineNumber = 0; 363295571Sjkim Next->Asl.LogicalLineNumber = 0; 364295571Sjkim 365295571Sjkim Next = Next->Asl.Next; 366295571Sjkim Next->Asl.LineNumber = 0; 367295571Sjkim Next->Asl.LogicalLineNumber = 0; 368295571Sjkim 369295571Sjkim ParentOp = ExternalOp->Asl.Parent; 370295571Sjkim Prev = Next = ParentOp->Asl.Child; 371295571Sjkim 372295571Sjkim /* Now find the External node's position in parse tree */ 373295571Sjkim 374295571Sjkim while (Next != ExternalOp) 375295571Sjkim { 376295571Sjkim Prev = Next; 377295571Sjkim Next = Next->Asl.Next; 378295571Sjkim } 379295571Sjkim 380295571Sjkim /* Remove the External from the parse tree */ 381295571Sjkim 382295571Sjkim if (Prev == ExternalOp) 383295571Sjkim { 384295571Sjkim /* External was the first child node */ 385295571Sjkim 386295571Sjkim ParentOp->Asl.Child = ExternalOp->Asl.Next; 387295571Sjkim } 388295571Sjkim 389295571Sjkim Prev->Asl.Next = ExternalOp->Asl.Next; 390295571Sjkim ExternalOp->Asl.Next = NULL; 391295571Sjkim ExternalOp->Asl.Parent = Gbl_ExternalsListHead; 392295571Sjkim 393295571Sjkim /* Point the External to the next in the list */ 394295571Sjkim 395295571Sjkim if (NextOp->Asl.Next) 396295571Sjkim { 397295571Sjkim ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child; 398295571Sjkim } 399295571Sjkim 400295571Sjkim NextOp = NextOp->Asl.Next; 401295571Sjkim } 402295571Sjkim 403295571Sjkim /* 404295571Sjkim * Loop again to remove MethodObj Externals for which 405295571Sjkim * a MethodCall was not found (dead external reference) 406295571Sjkim */ 407295571Sjkim Prev = Gbl_ExternalsListHead->Asl.Child; 408295571Sjkim Next = Prev; 409295571Sjkim while (Next) 410295571Sjkim { 411295571Sjkim ObjType = (ACPI_OBJECT_TYPE) 412295571Sjkim Next->Asl.Child->Asl.Next->Asl.Value.Integer; 413295571Sjkim 414295571Sjkim if (ObjType == ACPI_TYPE_METHOD && 415295571Sjkim !(Next->Asl.CompileFlags & NODE_VISITED)) 416295571Sjkim { 417295571Sjkim if (Next == Prev) 418295571Sjkim { 419295571Sjkim Gbl_ExternalsListHead->Asl.Child = Next->Asl.Next; 420295571Sjkim Next->Asl.Next = NULL; 421295571Sjkim Prev = Gbl_ExternalsListHead->Asl.Child; 422295571Sjkim Next = Prev; 423295571Sjkim continue; 424295571Sjkim } 425295571Sjkim else 426295571Sjkim { 427295571Sjkim Prev->Asl.Next = Next->Asl.Next; 428295571Sjkim Next->Asl.Next = NULL; 429295571Sjkim Next = Prev->Asl.Next; 430295571Sjkim continue; 431295571Sjkim } 432295571Sjkim } 433295571Sjkim 434295571Sjkim Prev = Next; 435295571Sjkim Next = Next->Asl.Next; 436295571Sjkim } 437295571Sjkim 438295571Sjkim /* If list is now empty, don't bother to make If (0) block */ 439295571Sjkim 440295571Sjkim if (!Gbl_ExternalsListHead->Asl.Child) 441295571Sjkim { 442295571Sjkim return; 443295571Sjkim } 444295571Sjkim 445295571Sjkim /* Convert Gbl_ExternalsListHead parent to If(). */ 446295571Sjkim 447295571Sjkim Gbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF; 448295571Sjkim Gbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP; 449295571Sjkim Gbl_ExternalsListHead->Asl.CompileFlags = NODE_AML_PACKAGE; 450295571Sjkim UtSetParseOpName (Gbl_ExternalsListHead); 451295571Sjkim 452295571Sjkim /* Create a Zero op for the If predicate */ 453295571Sjkim 454295571Sjkim PredicateOp = TrAllocateNode (PARSEOP_ZERO); 455295571Sjkim PredicateOp->Asl.AmlOpcode = AML_ZERO_OP; 456295571Sjkim 457295571Sjkim PredicateOp->Asl.Parent = Gbl_ExternalsListHead; 458295571Sjkim PredicateOp->Asl.Child = NULL; 459295571Sjkim PredicateOp->Asl.Next = Gbl_ExternalsListHead->Asl.Child; 460295571Sjkim Gbl_ExternalsListHead->Asl.Child = PredicateOp; 461295571Sjkim 462295571Sjkim /* Set line numbers (for listings, etc.) */ 463295571Sjkim 464295571Sjkim Gbl_ExternalsListHead->Asl.LineNumber = 0; 465295571Sjkim Gbl_ExternalsListHead->Asl.LogicalLineNumber = 0; 466295571Sjkim 467295571Sjkim PredicateOp->Asl.LineNumber = 0; 468295571Sjkim PredicateOp->Asl.LogicalLineNumber = 0; 469295571Sjkim 470295571Sjkim /* Insert block back in the list */ 471295571Sjkim 472295571Sjkim Prev = DefinitionBlockOp->Asl.Child; 473295571Sjkim Next = Prev; 474295571Sjkim 475295571Sjkim /* Find last default arg */ 476295571Sjkim 477295571Sjkim for (i = 0; i < 6; i++) 478295571Sjkim { 479295571Sjkim Prev = Next; 480295571Sjkim Next = Prev->Asl.Next; 481295571Sjkim } 482295571Sjkim 483295571Sjkim if (Next) 484295571Sjkim { 485295571Sjkim /* Definition Block is not empty */ 486295571Sjkim 487295571Sjkim Gbl_ExternalsListHead->Asl.Next = Next; 488295571Sjkim } 489295571Sjkim else 490295571Sjkim { 491295571Sjkim /* Definition Block is empty. */ 492295571Sjkim 493295571Sjkim Gbl_ExternalsListHead->Asl.Next = NULL; 494295571Sjkim } 495295571Sjkim 496295571Sjkim Prev->Asl.Next = Gbl_ExternalsListHead; 497295571Sjkim Gbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent; 498295571Sjkim} 499