1 | /****************************************************************************** |
2 | * |
3 | * Module Name: nsparse - namespace interface to AML parser |
4 | * |
5 | *****************************************************************************/ |
6 | |
7 | /* |
8 | * Copyright (C) 2000 - 2016, Intel Corp. |
9 | * All rights reserved. |
10 | * |
11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions |
13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions, and the following disclaimer, |
16 | * without modification. |
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
18 | * substantially similar to the "NO WARRANTY" disclaimer below |
19 | * ("Disclaimer") and any redistribution must be conditioned upon |
20 | * including a substantially similar Disclaimer requirement for further |
21 | * binary redistribution. |
22 | * 3. Neither the names of the above-listed copyright holders nor the names |
23 | * of any contributors may be used to endorse or promote products derived |
24 | * from this software without specific prior written permission. |
25 | * |
26 | * Alternatively, this software may be distributed under the terms of the |
27 | * GNU General Public License ("GPL") version 2 as published by the Free |
28 | * Software Foundation. |
29 | * |
30 | * NO WARRANTY |
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
41 | * POSSIBILITY OF SUCH DAMAGES. |
42 | */ |
43 | |
44 | #include "acpi.h" |
45 | #include "accommon.h" |
46 | #include "acnamesp.h" |
47 | #include "acparser.h" |
48 | #include "acdispat.h" |
49 | #include "actables.h" |
50 | #include "acinterp.h" |
51 | |
52 | |
53 | #define _COMPONENT ACPI_NAMESPACE |
54 | ACPI_MODULE_NAME ("nsparse" ) |
55 | |
56 | |
57 | /******************************************************************************* |
58 | * |
59 | * FUNCTION: NsExecuteTable |
60 | * |
61 | * PARAMETERS: TableDesc - An ACPI table descriptor for table to parse |
62 | * StartNode - Where to enter the table into the namespace |
63 | * |
64 | * RETURN: Status |
65 | * |
66 | * DESCRIPTION: Load ACPI/AML table by executing the entire table as a |
67 | * TermList. |
68 | * |
69 | ******************************************************************************/ |
70 | |
71 | ACPI_STATUS |
72 | AcpiNsExecuteTable ( |
73 | UINT32 TableIndex, |
74 | ACPI_NAMESPACE_NODE *StartNode) |
75 | { |
76 | ACPI_STATUS Status; |
77 | ACPI_TABLE_HEADER *Table; |
78 | ACPI_OWNER_ID OwnerId; |
79 | ACPI_EVALUATE_INFO *Info = NULL; |
80 | UINT32 AmlLength; |
81 | UINT8 *AmlStart; |
82 | ACPI_OPERAND_OBJECT *MethodObj = NULL; |
83 | |
84 | |
85 | ACPI_FUNCTION_TRACE (NsExecuteTable); |
86 | |
87 | |
88 | Status = AcpiGetTableByIndex (TableIndex, &Table); |
89 | if (ACPI_FAILURE (Status)) |
90 | { |
91 | return_ACPI_STATUS (Status); |
92 | } |
93 | |
94 | /* Table must consist of at least a complete header */ |
95 | |
96 | if (Table->Length < sizeof (ACPI_TABLE_HEADER)) |
97 | { |
98 | return_ACPI_STATUS (AE_BAD_HEADER); |
99 | } |
100 | |
101 | AmlStart = (UINT8 *) Table + sizeof (ACPI_TABLE_HEADER); |
102 | AmlLength = Table->Length - sizeof (ACPI_TABLE_HEADER); |
103 | |
104 | Status = AcpiTbGetOwnerId (TableIndex, &OwnerId); |
105 | if (ACPI_FAILURE (Status)) |
106 | { |
107 | return_ACPI_STATUS (Status); |
108 | } |
109 | |
110 | /* Create, initialize, and link a new temporary method object */ |
111 | |
112 | MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); |
113 | if (!MethodObj) |
114 | { |
115 | return_ACPI_STATUS (AE_NO_MEMORY); |
116 | } |
117 | |
118 | /* Allocate the evaluation information block */ |
119 | |
120 | Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); |
121 | if (!Info) |
122 | { |
123 | Status = AE_NO_MEMORY; |
124 | goto Cleanup; |
125 | } |
126 | |
127 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, |
128 | "Create table code block: %p\n" , MethodObj)); |
129 | |
130 | MethodObj->Method.AmlStart = AmlStart; |
131 | MethodObj->Method.AmlLength = AmlLength; |
132 | MethodObj->Method.OwnerId = OwnerId; |
133 | MethodObj->Method.InfoFlags |= ACPI_METHOD_MODULE_LEVEL; |
134 | |
135 | Info->PassNumber = ACPI_IMODE_EXECUTE; |
136 | Info->Node = StartNode; |
137 | Info->ObjDesc = MethodObj; |
138 | Info->NodeFlags = Info->Node->Flags; |
139 | Info->FullPathname = AcpiNsGetNormalizedPathname (Info->Node, TRUE); |
140 | if (!Info->FullPathname) |
141 | { |
142 | Status = AE_NO_MEMORY; |
143 | goto Cleanup; |
144 | } |
145 | |
146 | Status = AcpiPsExecuteTable (Info); |
147 | |
148 | Cleanup: |
149 | if (Info) |
150 | { |
151 | ACPI_FREE (Info->FullPathname); |
152 | Info->FullPathname = NULL; |
153 | } |
154 | ACPI_FREE (Info); |
155 | AcpiUtRemoveReference (MethodObj); |
156 | return_ACPI_STATUS (Status); |
157 | } |
158 | |
159 | |
160 | /******************************************************************************* |
161 | * |
162 | * FUNCTION: NsOneCompleteParse |
163 | * |
164 | * PARAMETERS: PassNumber - 1 or 2 |
165 | * TableDesc - The table to be parsed. |
166 | * |
167 | * RETURN: Status |
168 | * |
169 | * DESCRIPTION: Perform one complete parse of an ACPI/AML table. |
170 | * |
171 | ******************************************************************************/ |
172 | |
173 | ACPI_STATUS |
174 | AcpiNsOneCompleteParse ( |
175 | UINT32 PassNumber, |
176 | UINT32 TableIndex, |
177 | ACPI_NAMESPACE_NODE *StartNode) |
178 | { |
179 | ACPI_PARSE_OBJECT *ParseRoot; |
180 | ACPI_STATUS Status; |
181 | UINT32 AmlLength; |
182 | UINT8 *AmlStart; |
183 | ACPI_WALK_STATE *WalkState; |
184 | ACPI_TABLE_HEADER *Table; |
185 | ACPI_OWNER_ID OwnerId; |
186 | |
187 | |
188 | ACPI_FUNCTION_TRACE (NsOneCompleteParse); |
189 | |
190 | |
191 | Status = AcpiGetTableByIndex (TableIndex, &Table); |
192 | if (ACPI_FAILURE (Status)) |
193 | { |
194 | return_ACPI_STATUS (Status); |
195 | } |
196 | |
197 | /* Table must consist of at least a complete header */ |
198 | |
199 | if (Table->Length < sizeof (ACPI_TABLE_HEADER)) |
200 | { |
201 | return_ACPI_STATUS (AE_BAD_HEADER); |
202 | } |
203 | |
204 | AmlStart = (UINT8 *) Table + sizeof (ACPI_TABLE_HEADER); |
205 | AmlLength = Table->Length - sizeof (ACPI_TABLE_HEADER); |
206 | |
207 | Status = AcpiTbGetOwnerId (TableIndex, &OwnerId); |
208 | if (ACPI_FAILURE (Status)) |
209 | { |
210 | return_ACPI_STATUS (Status); |
211 | } |
212 | |
213 | /* Create and init a Root Node */ |
214 | |
215 | ParseRoot = AcpiPsCreateScopeOp (AmlStart); |
216 | if (!ParseRoot) |
217 | { |
218 | return_ACPI_STATUS (AE_NO_MEMORY); |
219 | } |
220 | |
221 | /* Create and initialize a new walk state */ |
222 | |
223 | WalkState = AcpiDsCreateWalkState (OwnerId, NULL, NULL, NULL); |
224 | if (!WalkState) |
225 | { |
226 | AcpiPsFreeOp (ParseRoot); |
227 | return_ACPI_STATUS (AE_NO_MEMORY); |
228 | } |
229 | |
230 | Status = AcpiDsInitAmlWalk (WalkState, ParseRoot, NULL, |
231 | AmlStart, AmlLength, NULL, (UINT8) PassNumber); |
232 | if (ACPI_FAILURE (Status)) |
233 | { |
234 | AcpiDsDeleteWalkState (WalkState); |
235 | goto Cleanup; |
236 | } |
237 | |
238 | /* Found OSDT table, enable the namespace override feature */ |
239 | |
240 | if (ACPI_COMPARE_NAME(Table->Signature, ACPI_SIG_OSDT) && |
241 | PassNumber == ACPI_IMODE_LOAD_PASS1) |
242 | { |
243 | WalkState->NamespaceOverride = TRUE; |
244 | } |
245 | |
246 | /* StartNode is the default location to load the table */ |
247 | |
248 | if (StartNode && StartNode != AcpiGbl_RootNode) |
249 | { |
250 | Status = AcpiDsScopeStackPush ( |
251 | StartNode, ACPI_TYPE_METHOD, WalkState); |
252 | if (ACPI_FAILURE (Status)) |
253 | { |
254 | AcpiDsDeleteWalkState (WalkState); |
255 | goto Cleanup; |
256 | } |
257 | } |
258 | |
259 | /* Parse the AML */ |
260 | |
261 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, |
262 | "*PARSE* pass %u parse\n" , PassNumber)); |
263 | AcpiExEnterInterpreter (); |
264 | Status = AcpiPsParseAml (WalkState); |
265 | AcpiExExitInterpreter (); |
266 | |
267 | Cleanup: |
268 | AcpiPsDeleteParseTree (ParseRoot); |
269 | return_ACPI_STATUS (Status); |
270 | } |
271 | |
272 | |
273 | /******************************************************************************* |
274 | * |
275 | * FUNCTION: AcpiNsParseTable |
276 | * |
277 | * PARAMETERS: TableDesc - An ACPI table descriptor for table to parse |
278 | * StartNode - Where to enter the table into the namespace |
279 | * |
280 | * RETURN: Status |
281 | * |
282 | * DESCRIPTION: Parse AML within an ACPI table and return a tree of ops |
283 | * |
284 | ******************************************************************************/ |
285 | |
286 | ACPI_STATUS |
287 | AcpiNsParseTable ( |
288 | UINT32 TableIndex, |
289 | ACPI_NAMESPACE_NODE *StartNode) |
290 | { |
291 | ACPI_STATUS Status; |
292 | |
293 | |
294 | ACPI_FUNCTION_TRACE (NsParseTable); |
295 | |
296 | |
297 | if (AcpiGbl_ParseTableAsTermList) |
298 | { |
299 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Start load pass\n" )); |
300 | |
301 | Status = AcpiNsExecuteTable (TableIndex, StartNode); |
302 | if (ACPI_FAILURE (Status)) |
303 | { |
304 | return_ACPI_STATUS (Status); |
305 | } |
306 | } |
307 | else |
308 | { |
309 | /* |
310 | * AML Parse, pass 1 |
311 | * |
312 | * In this pass, we load most of the namespace. Control methods |
313 | * are not parsed until later. A parse tree is not created. |
314 | * Instead, each Parser Op subtree is deleted when it is finished. |
315 | * This saves a great deal of memory, and allows a small cache of |
316 | * parse objects to service the entire parse. The second pass of |
317 | * the parse then performs another complete parse of the AML. |
318 | */ |
319 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Start pass 1\n" )); |
320 | |
321 | Status = AcpiNsOneCompleteParse (ACPI_IMODE_LOAD_PASS1, |
322 | TableIndex, StartNode); |
323 | if (ACPI_FAILURE (Status)) |
324 | { |
325 | return_ACPI_STATUS (Status); |
326 | } |
327 | |
328 | /* |
329 | * AML Parse, pass 2 |
330 | * |
331 | * In this pass, we resolve forward references and other things |
332 | * that could not be completed during the first pass. |
333 | * Another complete parse of the AML is performed, but the |
334 | * overhead of this is compensated for by the fact that the |
335 | * parse objects are all cached. |
336 | */ |
337 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Start pass 2\n" )); |
338 | Status = AcpiNsOneCompleteParse (ACPI_IMODE_LOAD_PASS2, |
339 | TableIndex, StartNode); |
340 | if (ACPI_FAILURE (Status)) |
341 | { |
342 | return_ACPI_STATUS (Status); |
343 | } |
344 | } |
345 | |
346 | return_ACPI_STATUS (Status); |
347 | } |
348 | |