1 | /*␊ |
2 | Copyright (c) 2010, Intel Corporation␊ |
3 | All rights reserved.␊ |
4 | ␊ |
5 | Redistribution and use in source and binary forms, with or without␊ |
6 | modification, are permitted provided that the following conditions are met:␊ |
7 | ␊ |
8 | * Redistributions of source code must retain the above copyright notice,␊ |
9 | this list of conditions and the following disclaimer.␊ |
10 | * Redistributions in binary form must reproduce the above copyright notice,␊ |
11 | this list of conditions and the following disclaimer in the documentation␊ |
12 | and/or other materials provided with the distribution.␊ |
13 | * Neither the name of Intel Corporation nor the names of its contributors␊ |
14 | may be used to endorse or promote products derived from this software␊ |
15 | without specific prior written permission.␊ |
16 | ␊ |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND␊ |
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED␊ |
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE␊ |
20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR␊ |
21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES␊ |
22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;␊ |
23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON␊ |
24 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT␊ |
25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS␊ |
26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.␊ |
27 | */␊ |
28 | ␊ |
29 | #include "acpi.h"␊ |
30 | #include "acpidecode.h"␊ |
31 | ␊ |
32 | #define DEBUG_ACPI_DECODE 0␊ |
33 | ␊ |
34 | #if DEBUG_ACPI_DECODE==1␊ |
35 | #include "libsaio.h"␊ |
36 | #define DBG(x...) printf(x)␊ |
37 | #else␊ |
38 | #define DBG(x...)␊ |
39 | #endif␊ |
40 | ␊ |
41 | static U8 *parse_acpi_dataobject(const struct acpi_namespace *ns, U8 * current, U8 * end);␊ |
42 | static U8 *parse_acpi_package(const struct acpi_namespace *ns, U8 * current, U8 * end);␊ |
43 | static U8 *parse_acpi_termarg(const struct acpi_namespace *ns, U8 * current, U8 * end);␊ |
44 | static U8 *parse_acpi_termarglist(const struct acpi_namespace *ns, U8 * current, U8 * end);␊ |
45 | static U8 *parse_acpi_objectlist(const struct acpi_namespace *ns, U8 * current, U8 * end);␊ |
46 | U8* UIDPointer = (U8*)0;␊ |
47 | ␊ |
48 | void *decodeTableHeader(void *current, ACPI_TABLE_HEADER ** tableHeader)␊ |
49 | {␊ |
50 | *tableHeader = current;␊ |
51 | current = *tableHeader + 1;␊ |
52 | return current;␊ |
53 | }␊ |
54 | void dprint_nameseg(U32 i)␊ |
55 | {␊ |
56 | DBG("%c%c%c%c",␊ |
57 | (int)(i & 0x000000ff),␊ |
58 | (int)((i & 0x0000ff00) >> 8),␊ |
59 | (int)((i & 0x00ff0000) >> 16),␊ |
60 | (int)(i >> 24));␊ |
61 | }␊ |
62 | ␊ |
63 | #if DEBUG_ACPI_DECODE␊ |
64 | static void dprint_namespace(const struct acpi_namespace *ns)␊ |
65 | {␊ |
66 | U32 i;␊ |
67 | DBG( "\\");␊ |
68 | for (i = 0; i < ns->depth; i++) {␊ |
69 | if (i != 0)␊ |
70 | DBG( ".");␊ |
71 | dprint_nameseg(ns->nameseg[i]);␊ |
72 | }␊ |
73 | }␊ |
74 | #endif␊ |
75 | ␊ |
76 | static void parsePackageLength(U8 * current, U32 * length, U32 * lengthEncoding)␊ |
77 | {␊ |
78 | U32 i;␊ |
79 | U8 len0 = *current;␊ |
80 | U8 numBytes = len0 >> 6;␊ |
81 | U32 total = 0;␊ |
82 | ␊ |
83 | for (i = numBytes; i > 0; i--) {␊ |
84 | total <<= 8;␊ |
85 | total |= current[i];␊ |
86 | }␊ |
87 | ␊ |
88 | total <<= 4;␊ |
89 | total |= len0 & 0x3f;␊ |
90 | *length = total;␊ |
91 | *lengthEncoding = numBytes + 1;␊ |
92 | DBG("Package length=0x%02x\n", *length);␊ |
93 | }␊ |
94 | ␊ |
95 | static bool ns_match(struct acpi_namespace *ns1, struct acpi_namespace *ns2)␊ |
96 | {␊ |
97 | U32 i;␊ |
98 | if (ns1->depth != ns2->depth)␊ |
99 | return false;␊ |
100 | ␊ |
101 | for (i = 0; i < ns1->depth; i++)␊ |
102 | if (ns1->nameseg[i] != ns2->nameseg[i])␊ |
103 | return false;␊ |
104 | ␊ |
105 | return true;␊ |
106 | }␊ |
107 | ␊ |
108 | U32 acpi_ns_found;␊ |
109 | ␊ |
110 | static U8 *parse_acpi_namestring(const struct acpi_namespace *ns_context, struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
111 | {␊ |
112 | U8 *temp = current;␊ |
113 | struct acpi_namespace dummy_ns;␊ |
114 | ␊ |
115 | (void)end;␊ |
116 | ␊ |
117 | if (!ns)␊ |
118 | ns = &dummy_ns;␊ |
119 | *ns = *ns_context;␊ |
120 | ␊ |
121 | if (*current == AML_ROOT_PREFIX) {␊ |
122 | ns->depth = 0;␊ |
123 | current++;␊ |
124 | } else␊ |
125 | while (*current == AML_PARENT_PREFIX) {␊ |
126 | if (ns->depth == 0) {␊ |
127 | DBG( "Attempt to use parent prefix with no namespace left\n");␊ |
128 | return temp;␊ |
129 | }␊ |
130 | current++;␊ |
131 | ns->depth--;␊ |
132 | }␊ |
133 | ␊ |
134 | switch (*current) {␊ |
135 | case AML_DUAL_NAME_PREFIX:␊ |
136 | if (ns->depth + 2 > ACPI_NAMESPACE_MAX_DEPTH) {␊ |
137 | DBG( "Namespace got too deep\n");␊ |
138 | return temp;␊ |
139 | }␊ |
140 | current++;␊ |
141 | ns->nameseg[ns->depth++] = *(U32 *) current;␊ |
142 | current += 4;␊ |
143 | ns->nameseg[ns->depth++] = *(U32 *) current;␊ |
144 | current += 4;␊ |
145 | break;␊ |
146 | case AML_MULTI_NAME_PREFIX:␊ |
147 | {␊ |
148 | U8 nameseg_count;␊ |
149 | current++;␊ |
150 | nameseg_count = *current++;␊ |
151 | if (ns->depth + nameseg_count > ACPI_NAMESPACE_MAX_DEPTH) {␊ |
152 | DBG( "Namespace got too deep\n");␊ |
153 | return temp;␊ |
154 | }␊ |
155 | while (nameseg_count--) {␊ |
156 | ns->nameseg[ns->depth++] = *(U32 *) current;␊ |
157 | current += 4;␊ |
158 | }␊ |
159 | break;␊ |
160 | }␊ |
161 | case AML_NULL_NAME:␊ |
162 | current++;␊ |
163 | break;␊ |
164 | default:␊ |
165 | if (*current != '_' && (*current < 'A' || *current > 'Z')) {␊ |
166 | DBG( "Invalid nameseg lead character: 0x%02x\n", *current);␊ |
167 | return temp;␊ |
168 | }␊ |
169 | if (ns->depth + 1 > ACPI_NAMESPACE_MAX_DEPTH) {␊ |
170 | DBG( "Namespace got too deep\n");␊ |
171 | return temp;␊ |
172 | }␊ |
173 | ns->nameseg[ns->depth++] = *(U32 *) current;␊ |
174 | current += 4;␊ |
175 | break;␊ |
176 | }␊ |
177 | #if DEBUG_ACPI_DECODE␊ |
178 | DBG( "Found NameString: ");␊ |
179 | dprint_namespace(ns);␊ |
180 | DBG("\n");␊ |
181 | #endif␊ |
182 | ␉if (ns->nameseg[1] == NAMESEG("PCI0") && ns->nameseg[2] == NAMESEG("_UID")) {␊ |
183 | ␉␉UIDPointer = current;␊ |
184 | ␉}␊ |
185 | ␉␊ |
186 | if (!acpi_ns_found) {␊ |
187 | U32 index;␊ |
188 | ␊ |
189 | for (index = 0; index < acpi_processor_count; index++)␊ |
190 | if (ns_match(ns, &acpi_processors[index].ns)) {␊ |
191 | acpi_ns_found = 1;␊ |
192 | break;␊ |
193 | }␊ |
194 | }␊ |
195 | return current;␊ |
196 | }␊ |
197 | ␊ |
198 | static U8 *parse_acpi_buffer(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
199 | {␊ |
200 | U32 pkglen, lengthEncoding;␊ |
201 | (void)ns;␊ |
202 | (void)end;␊ |
203 | if (*current != AML_BUFFER_OP)␊ |
204 | return current;␊ |
205 | current++;␊ |
206 | parsePackageLength(current, &pkglen, &lengthEncoding);␊ |
207 | current += pkglen;␊ |
208 | return current;␊ |
209 | }␊ |
210 | ␊ |
211 | static U8 *parse_acpi_computationaldata(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
212 | {␊ |
213 | U8 *temp = current;␊ |
214 | ␊ |
215 | current = parse_acpi_buffer(ns, current, end);␊ |
216 | if (current != temp)␊ |
217 | return current;␊ |
218 | ␊ |
219 | switch (*current) {␊ |
220 | case AML_BYTE_OP:␊ |
221 | DBG("Found ByteOp\n");␊ |
222 | current += 1 + 1;␊ |
223 | break;␊ |
224 | case AML_WORD_OP:␊ |
225 | DBG( "Found WordOp\n");␊ |
226 | current += 1 + 2;␊ |
227 | break;␊ |
228 | case AML_DWORD_OP:␊ |
229 | DBG("Found DwordOp\n");␊ |
230 | current += 1 + 4;␊ |
231 | break;␊ |
232 | case AML_QWORD_OP:␊ |
233 | DBG( "Found QwordOp\n");␊ |
234 | current += 1 + 8;␊ |
235 | break;␊ |
236 | case AML_STRING_OP:␊ |
237 | DBG( "Found StringOp: \"");␊ |
238 | current++;␊ |
239 | while (*current)␊ |
240 | #if DEBUG_ACPI_DECODE␊ |
241 | if (*current < ' ' || *current > 0x7e)␊ |
242 | printf( "\\x%02x", *current++);␊ |
243 | else␊ |
244 | printf( "%c", *current++);␊ |
245 | #else␊ |
246 | current++;␊ |
247 | #endif␊ |
248 | current++; /* Skip the \0 */␊ |
249 | DBG( "\"\n");␊ |
250 | break;␊ |
251 | case AML_ZERO_OP:␊ |
252 | DBG( "Found ZeroOp\n");␊ |
253 | current += 1;␊ |
254 | break;␊ |
255 | case AML_ONE_OP:␊ |
256 | DBG( "Found OneOp\n");␊ |
257 | current += 1;␊ |
258 | break;␊ |
259 | case AML_ONES_OP:␊ |
260 | DBG( "Found OneOp\n");␊ |
261 | current += 1;␊ |
262 | break;␊ |
263 | case AML_EXT_OP_PREFIX:␊ |
264 | if (*(current + 1) == AML_REVISION_OP)␊ |
265 | current += 2;␊ |
266 | default:␊ |
267 | break;␊ |
268 | }␊ |
269 | ␊ |
270 | return current;␊ |
271 | }␊ |
272 | ␊ |
273 | static U8 *parse_acpi_argobj(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
274 | {␊ |
275 | (void)ns;␊ |
276 | (void)end;␊ |
277 | switch (*current) {␊ |
278 | case AML_ARG0_OP:␊ |
279 | DBG( "Found Arg0Op\n");␊ |
280 | current++;␊ |
281 | break;␊ |
282 | case AML_ARG1_OP:␊ |
283 | DBG( "Found Arg1Op\n");␊ |
284 | current++;␊ |
285 | break;␊ |
286 | case AML_ARG2_OP:␊ |
287 | DBG( "Found Arg2Op\n");␊ |
288 | current++;␊ |
289 | break;␊ |
290 | case AML_ARG3_OP:␊ |
291 | DBG( "Found Arg3Op\n");␊ |
292 | current++;␊ |
293 | break;␊ |
294 | case AML_ARG4_OP:␊ |
295 | DBG( "Found Arg4Op\n");␊ |
296 | current++;␊ |
297 | break;␊ |
298 | case AML_ARG5_OP:␊ |
299 | DBG( "Found Arg5Op\n");␊ |
300 | current++;␊ |
301 | break;␊ |
302 | case AML_ARG6_OP:␊ |
303 | DBG( "Found Arg6Op\n");␊ |
304 | current++;␊ |
305 | break;␊ |
306 | default:␊ |
307 | break;␊ |
308 | }␊ |
309 | return current;␊ |
310 | }␊ |
311 | ␊ |
312 | static U8 *parse_acpi_localobj(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
313 | {␊ |
314 | (void)ns;␊ |
315 | (void)end;␊ |
316 | switch (*current) {␊ |
317 | case AML_LOCAL0_OP:␊ |
318 | DBG( "Found Local0Op\n");␊ |
319 | current++;␊ |
320 | break;␊ |
321 | case AML_LOCAL1_OP:␊ |
322 | DBG( "Found Local1Op\n");␊ |
323 | current++;␊ |
324 | break;␊ |
325 | case AML_LOCAL2_OP:␊ |
326 | DBG( "Found Local2Op\n");␊ |
327 | current++;␊ |
328 | break;␊ |
329 | case AML_LOCAL3_OP:␊ |
330 | DBG("Found Local3Op\n");␊ |
331 | current++;␊ |
332 | break;␊ |
333 | case AML_LOCAL4_OP:␊ |
334 | DBG( "Found Local4Op\n");␊ |
335 | current++;␊ |
336 | break;␊ |
337 | case AML_LOCAL5_OP:␊ |
338 | DBG( "Found Local5Op\n");␊ |
339 | current++;␊ |
340 | break;␊ |
341 | case AML_LOCAL6_OP:␊ |
342 | DBG( "Found Local6Op\n");␊ |
343 | current++;␊ |
344 | break;␊ |
345 | case AML_LOCAL7_OP:␊ |
346 | DBG( "Found Local7Op\n");␊ |
347 | current++;␊ |
348 | break;␊ |
349 | default:␊ |
350 | break;␊ |
351 | }␊ |
352 | return current;␊ |
353 | }␊ |
354 | ␊ |
355 | static U8 *parse_acpi_debugobj(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
356 | {␊ |
357 | (void)ns;␊ |
358 | (void)end;␊ |
359 | if ((*current == AML_EXT_OP_PREFIX) && (*(current + 1) == AML_DEBUG_OP)) {␊ |
360 | current += 2;␊ |
361 | DBG( "Found DebugOp\n");␊ |
362 | }␊ |
363 | ␊ |
364 | return current;␊ |
365 | }␊ |
366 | ␊ |
367 | static U8 *parse_acpi_datarefobject(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
368 | {␊ |
369 | U8 *temp = current;␊ |
370 | ␊ |
371 | DBG( "Beginning datarefobject: 0x%02x at memory location %p\n", *current, current);␊ |
372 | current = parse_acpi_dataobject(ns, current, end);␊ |
373 | if (current != temp)␊ |
374 | return current;␊ |
375 | ␊ |
376 | return current;␊ |
377 | }␊ |
378 | ␊ |
379 | static U8 *parse_acpi_simplename(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
380 | {␊ |
381 | U8 *temp = current;␊ |
382 | ␊ |
383 | current = parse_acpi_namestring(ns, NULL, current, end);␊ |
384 | if (current != temp)␊ |
385 | return current;␊ |
386 | ␊ |
387 | current = parse_acpi_argobj(ns, current, end);␊ |
388 | if (current != temp)␊ |
389 | return current;␊ |
390 | ␊ |
391 | current = parse_acpi_localobj(ns, current, end);␊ |
392 | if (current != temp)␊ |
393 | return current;␊ |
394 | ␊ |
395 | return current;␊ |
396 | }␊ |
397 | ␊ |
398 | static U8 *parse_acpi_supername(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
399 | {␊ |
400 | U8 *temp = current;␊ |
401 | ␊ |
402 | current = parse_acpi_simplename(ns, current, end);␊ |
403 | if (current != temp)␊ |
404 | return current;␊ |
405 | ␊ |
406 | current = parse_acpi_debugobj(ns, current, end);␊ |
407 | if (current != temp)␊ |
408 | return current;␊ |
409 | ␊ |
410 | return current;␊ |
411 | }␊ |
412 | ␊ |
413 | static U8 *parse_acpi_target(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
414 | {␊ |
415 | U8 *temp = current;␊ |
416 | ␊ |
417 | current = parse_acpi_supername(ns, current, end);␊ |
418 | if (current != temp)␊ |
419 | return current;␊ |
420 | ␊ |
421 | if (*current == AML_NULL_NAME)␊ |
422 | current++;␊ |
423 | ␊ |
424 | return current;␊ |
425 | }␊ |
426 | ␊ |
427 | static U8 *parse_acpi_method(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
428 | {␊ |
429 | U8 *new_end = current;␊ |
430 | U8 *temp;␊ |
431 | U32 pkglen;␊ |
432 | U32 lengthEncoding;␊ |
433 | struct acpi_namespace new_ns;␊ |
434 | ␊ |
435 | (void)end;␊ |
436 | ␊ |
437 | parsePackageLength(current, &pkglen, &lengthEncoding);␊ |
438 | current += lengthEncoding;␊ |
439 | new_end += pkglen;␊ |
440 | ␊ |
441 | temp = current;␊ |
442 | current = parse_acpi_namestring(ns, &new_ns, current, new_end);␊ |
443 | if (current == temp)␊ |
444 | return new_end;␊ |
445 | ␉␊ |
446 | #if DEBUG_ACPI_DECODE␊ |
447 | DBG( "Found Method: ");␊ |
448 | dprint_namespace(&new_ns);␊ |
449 | DBG( "\n");␊ |
450 | #endif␊ |
451 | // U8 methodFlags␊ |
452 | current++;␊ |
453 | ␊ |
454 | parse_acpi_termlist(&new_ns, current, new_end);␊ |
455 | ␊ |
456 | #if DEBUG_ACPI_DECODE␊ |
457 | DBG( "End of Method: ");␊ |
458 | dprint_namespace(&new_ns);␊ |
459 | DBG( "\n");␊ |
460 | #endif␊ |
461 | ␊ |
462 | return new_end;␊ |
463 | }␊ |
464 | ␊ |
465 | U32 acpi_processor_count;␊ |
466 | struct acpi_processor acpi_processors[CPU_MAP_LIMIT];␊ |
467 | ␊ |
468 | static void add_processor(const struct acpi_namespace *ns, U8 id, U32 pmbase)␊ |
469 | {␊ |
470 | if (acpi_processor_count == CPU_MAP_LIMIT) {␊ |
471 | DBG( "No more room for ACPI processor structures\n");␊ |
472 | return;␊ |
473 | }␊ |
474 | acpi_processors[acpi_processor_count].ns = *ns;␊ |
475 | acpi_processors[acpi_processor_count].id = id;␊ |
476 | acpi_processors[acpi_processor_count].pmbase = pmbase;␊ |
477 | acpi_processor_count++;␊ |
478 | }␊ |
479 | ␊ |
480 | static U8 *parse_acpi_processor(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
481 | {␊ |
482 | U8 *new_end = current;␊ |
483 | U8 *temp;␊ |
484 | U32 pkglen;␊ |
485 | U32 lengthEncoding;␊ |
486 | struct acpi_namespace new_ns;␊ |
487 | U8 id;␊ |
488 | U32 pmbase;␊ |
489 | ␊ |
490 | (void)end;␊ |
491 | ␊ |
492 | parsePackageLength(current, &pkglen, &lengthEncoding);␊ |
493 | current += lengthEncoding;␊ |
494 | new_end += pkglen;␊ |
495 | ␊ |
496 | temp = current;␊ |
497 | current = parse_acpi_namestring(ns, &new_ns, current, new_end);␊ |
498 | if (current == temp)␊ |
499 | return new_end;␊ |
500 | ␊ |
501 | id = *current++;␊ |
502 | pmbase = *(U32 *) current;␊ |
503 | current += 4;␊ |
504 | ␉␊ |
505 | #if DEBUG_ACPI_DECODE␊ |
506 | DBG( "Found CPU object: ");␊ |
507 | dprint_namespace(&new_ns);␊ |
508 | DBG( " id = 0x%x pmbase = 0x%x\n", id, pmbase);␊ |
509 | #endif␊ |
510 | add_processor(&new_ns, id, pmbase);␊ |
511 | ␊ |
512 | return new_end;␊ |
513 | }␊ |
514 | ␊ |
515 | static U8 *parse_acpi_namedobj(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
516 | {␊ |
517 | DBG( "Beginning namedobj: 0x%02x at memory location %p\n", *current, current);␊ |
518 | switch (*current) {␊ |
519 | case AML_EXT_OP_PREFIX:␊ |
520 | {␊ |
521 | if (*(current + 1) == AML_MUTEX_OP) {␊ |
522 | struct acpi_namespace new_ns;␊ |
523 | ␊ |
524 | current += 2;␊ |
525 | current = parse_acpi_namestring(ns, &new_ns, current, end);␊ |
526 | #if DEBUG_ACPI_DECODE␊ |
527 | DBG( "Mutex: ");␊ |
528 | dprint_namespace(&new_ns);␊ |
529 | DBG( "\n");␊ |
530 | #endif␊ |
531 | current++; /* SyncFlags */␊ |
532 | } else if (*(current + 1) == AML_OPREGION_OP) {␊ |
533 | struct acpi_namespace new_ns;␊ |
534 | ␊ |
535 | current += 2;␊ |
536 | DBG( "OpRegion at memory location %p\n", current);␊ |
537 | current = parse_acpi_namestring(ns, &new_ns, current, end);␊ |
538 | #if DEBUG_ACPI_DECODE␊ |
539 | DBG( "OpRegion name: ");␊ |
540 | dprint_namespace(&new_ns);␊ |
541 | DBG( "\n");␊ |
542 | #endif␊ |
543 | current++;␊ |
544 | current = parse_acpi_termarg(ns, current, end);␊ |
545 | current = parse_acpi_termarg(ns, current, end);␊ |
546 | #if DEBUG_ACPI_DECODE␊ |
547 | DBG( "End OpRegion: ");␊ |
548 | dprint_namespace(&new_ns);␊ |
549 | DBG( "\n");␊ |
550 | #endif␊ |
551 | } else if (*(current + 1) == AML_FIELD_OP) {␊ |
552 | U32 pkglen;␊ |
553 | U32 lengthEncoding;␊ |
554 | ␊ |
555 | current += 2;␊ |
556 | DBG( "FieldOp at memory location %p\n", current);␊ |
557 | parsePackageLength(current, &pkglen, &lengthEncoding);␊ |
558 | current += pkglen;␊ |
559 | } else if (*(current + 1) == AML_DEVICE_OP) {␊ |
560 | U8 *new_end;␊ |
561 | U32 pkglen;␊ |
562 | U32 lengthEncoding;␊ |
563 | struct acpi_namespace new_ns;␊ |
564 | ␊ |
565 | current += 2;␊ |
566 | new_end = current;␊ |
567 | DBG( "DeviceOp at memory location %p\n", current);␊ |
568 | parsePackageLength(current, &pkglen, &lengthEncoding);␊ |
569 | current += lengthEncoding;␊ |
570 | new_end += pkglen;␊ |
571 | current = parse_acpi_namestring(ns, &new_ns, current, new_end);␊ |
572 | #if DEBUG_ACPI_DECODE␊ |
573 | DBG( "DeviceOp name: ");␊ |
574 | dprint_namespace(&new_ns);␊ |
575 | DBG( "\n");␊ |
576 | #endif␊ |
577 | ␊ |
578 | current = parse_acpi_objectlist(&new_ns, current, new_end);␊ |
579 | current = new_end;␊ |
580 | } else if (*(current + 1) == AML_PROCESSOR_OP) {␊ |
581 | current += 2;␊ |
582 | current = parse_acpi_processor(ns, current, end);␊ |
583 | } else if (*(current + 1) == AML_INDEXFIELD_OP) {␊ |
584 | U8 *new_end;␊ |
585 | U32 pkglen;␊ |
586 | U32 lengthEncoding;␊ |
587 | struct acpi_namespace new_ns;␊ |
588 | ␊ |
589 | current += 2;␊ |
590 | new_end = current;␊ |
591 | DBG( "IndexFieldOp at memory location %p\n", current);␊ |
592 | parsePackageLength(current, &pkglen, &lengthEncoding);␊ |
593 | current += lengthEncoding;␊ |
594 | new_end += pkglen;␊ |
595 | current = parse_acpi_namestring(ns, &new_ns, current, new_end);␊ |
596 | #if DEBUG_ACPI_DECODE␊ |
597 | DBG( "IndexFieldOp name: ");␊ |
598 | dprint_namespace(&new_ns);␊ |
599 | DBG( "\n");␊ |
600 | #endif␊ |
601 | current = parse_acpi_objectlist(&new_ns, current, new_end);␊ |
602 | current = new_end;␊ |
603 | }␊ |
604 | break;␊ |
605 | }␊ |
606 | case AML_METHOD_OP:␊ |
607 | {␊ |
608 | current++;␊ |
609 | current = parse_acpi_method(ns, current, end);␊ |
610 | break;␊ |
611 | }␊ |
612 | default:␊ |
613 | break;␊ |
614 | }␊ |
615 | return current;␊ |
616 | }␊ |
617 | ␊ |
618 | static U8 *parse_acpi_type1opcode(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
619 | {␊ |
620 | DBG( "Beginning type1opcode: 0x%02x at memory location %p\n", *current, current);␊ |
621 | switch (*current) {␊ |
622 | case AML_IF_OP:␊ |
623 | {␊ |
624 | U8 *new_end;␊ |
625 | U32 pkgLen;␊ |
626 | U32 lengthEncoding;␊ |
627 | ␊ |
628 | DBG( "Found IfOp\n");␊ |
629 | current++;␊ |
630 | parsePackageLength(current, &pkgLen, &lengthEncoding);␊ |
631 | new_end = current + pkgLen;␊ |
632 | current += lengthEncoding;␊ |
633 | ␊ |
634 | current = parse_acpi_termarg(ns, current, new_end);␊ |
635 | parse_acpi_termlist(ns, current, new_end);␊ |
636 | current = new_end;␊ |
637 | break;␊ |
638 | }␊ |
639 | case AML_ELSE_OP:␊ |
640 | {␊ |
641 | U8 *new_end;␊ |
642 | U32 pkgLen;␊ |
643 | U32 lengthEncoding;␊ |
644 | ␊ |
645 | DBG( "Found ElseOp\n");␊ |
646 | current++;␊ |
647 | parsePackageLength(current, &pkgLen, &lengthEncoding);␊ |
648 | new_end = current + pkgLen;␊ |
649 | current += lengthEncoding;␊ |
650 | ␊ |
651 | parse_acpi_termlist(ns, current, new_end);␊ |
652 | current = new_end;␊ |
653 | break;␊ |
654 | }␊ |
655 | case AML_RETURN_OP:␊ |
656 | {␊ |
657 | DBG( "Found ReturnOp\n");␊ |
658 | current++;␊ |
659 | current = parse_acpi_termarg(ns, current, end);␊ |
660 | break;␊ |
661 | }␊ |
662 | default:␊ |
663 | break;␊ |
664 | }␊ |
665 | return current;␊ |
666 | }␊ |
667 | ␊ |
668 | static U8 *parse_acpi_type2opcode(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
669 | {␊ |
670 | U8 *temp = current;␊ |
671 | ␊ |
672 | DBG( "Beginning type2opcode: 0x%02x at memory location %p\n", *current, current);␊ |
673 | ␊ |
674 | current = parse_acpi_package(ns, current, end);␊ |
675 | if (current != temp)␊ |
676 | return current;␊ |
677 | ␊ |
678 | switch (*current) {␊ |
679 | case AML_LNOT_OP:␊ |
680 | current++;␊ |
681 | DBG( "Found logical not operator\n");␊ |
682 | current = parse_acpi_termarg(ns, current, end);␊ |
683 | break;␊ |
684 | ␊ |
685 | case AML_LAND_OP:␊ |
686 | case AML_LOR_OP:␊ |
687 | case AML_LEQUAL_OP:␊ |
688 | case AML_LGREATER_OP:␊ |
689 | case AML_LLESS_OP:␊ |
690 | DBG( "Found logical binary operator: %c\n", "&|!=><"[*current - AML_LAND_OP]);␊ |
691 | current++;␊ |
692 | current = parse_acpi_termarg(ns, current, end);␊ |
693 | current = parse_acpi_termarg(ns, current, end);␊ |
694 | break;␊ |
695 | ␊ |
696 | case AML_EXT_OP_PREFIX:␊ |
697 | {␊ |
698 | if (*(current + 1) == AML_COND_REF_OF_OP) {␊ |
699 | DBG( "Found CondRefOf\n");␊ |
700 | current += 2;␊ |
701 | current = parse_acpi_supername(ns, current, end);␊ |
702 | current = parse_acpi_target(ns, current, end);␊ |
703 | }␊ |
704 | break;␊ |
705 | }␊ |
706 | case AML_STORE_OP:␊ |
707 | {␊ |
708 | DBG( "Found StoreOp\n");␊ |
709 | current++;␊ |
710 | current = parse_acpi_termarg(ns, current, end);␊ |
711 | current = parse_acpi_supername(ns, current, end);␊ |
712 | break;␊ |
713 | }␊ |
714 | default:␊ |
715 | {␊ |
716 | current = parse_acpi_namestring(ns, NULL, current, end);␊ |
717 | if (current == temp)␊ |
718 | break;␊ |
719 | current = parse_acpi_termarglist(ns, current, end);␊ |
720 | }␊ |
721 | }␊ |
722 | return current;␊ |
723 | }␊ |
724 | ␊ |
725 | static U8 *parse_acpi_package(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
726 | {␊ |
727 | (void)ns;␊ |
728 | (void)end;␊ |
729 | if (*current == AML_PACKAGE_OP) {␊ |
730 | U32 pkglen;␊ |
731 | U32 lengthEncoding;␊ |
732 | ␊ |
733 | DBG( "Found PackageOp\n");␊ |
734 | current++;␊ |
735 | parsePackageLength(current, &pkglen, &lengthEncoding);␊ |
736 | current += pkglen;␊ |
737 | }␊ |
738 | return current;␊ |
739 | }␊ |
740 | ␊ |
741 | static U8 *parse_acpi_dataobject(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
742 | {␊ |
743 | U8 *temp = current;␊ |
744 | ␊ |
745 | current = parse_acpi_computationaldata(ns, current, end);␊ |
746 | if (current != temp)␊ |
747 | return current;␊ |
748 | ␊ |
749 | current = parse_acpi_package(ns, current, end);␊ |
750 | if (current != temp)␊ |
751 | return current;␊ |
752 | ␊ |
753 | return current;␊ |
754 | }␊ |
755 | ␊ |
756 | static U8 *parse_acpi_termarg(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
757 | {␊ |
758 | U8 *temp = current;␊ |
759 | ␊ |
760 | DBG( "Beginning termarg: 0x%02x at memory location %p\n", *current, current);␊ |
761 | ␊ |
762 | current = parse_acpi_type2opcode(ns, current, end);␊ |
763 | if (current != temp)␊ |
764 | return current;␊ |
765 | ␊ |
766 | current = parse_acpi_dataobject(ns, current, end);␊ |
767 | if (current != temp)␊ |
768 | return current;␊ |
769 | ␊ |
770 | current = parse_acpi_argobj(ns, current, end);␊ |
771 | if (current != temp)␊ |
772 | return current;␊ |
773 | ␊ |
774 | current = parse_acpi_localobj(ns, current, end);␊ |
775 | if (current != temp)␊ |
776 | return current;␊ |
777 | ␊ |
778 | return current;␊ |
779 | }␊ |
780 | ␊ |
781 | static U8 *parse_acpi_namespacemodifierobj(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
782 | {␊ |
783 | DBG( "Beginning namespacemodifierobj: 0x%02x at memory location %p\n", *current, current);␊ |
784 | switch (*current) {␊ |
785 | case AML_SCOPE_OP:␊ |
786 | {␊ |
787 | U8 *new_end;␊ |
788 | struct acpi_namespace new_ns;␊ |
789 | U32 scopeLen;␊ |
790 | U32 lengthEncoding;␊ |
791 | ␊ |
792 | current++;␊ |
793 | parsePackageLength(current, &scopeLen, &lengthEncoding);␊ |
794 | new_end = current + scopeLen;␊ |
795 | ␊ |
796 | current = parse_acpi_namestring(ns, &new_ns, current + lengthEncoding, new_end);␊ |
797 | #if DEBUG_ACPI_DECODE␊ |
798 | DBG( "Found Scope: ");␊ |
799 | dprint_namespace(&new_ns);␊ |
800 | DBG( "\n");␊ |
801 | #endif␊ |
802 | parse_acpi_termlist(&new_ns, current, new_end);␊ |
803 | #if DEBUG_ACPI_DECODE␊ |
804 | DBG( "End Scope: ");␊ |
805 | dprint_namespace(&new_ns);␊ |
806 | DBG( "\n");␊ |
807 | #endif␊ |
808 | current = new_end;␊ |
809 | break;␊ |
810 | }␊ |
811 | case AML_NAME_OP:␊ |
812 | current++;␊ |
813 | current = parse_acpi_namestring(ns, NULL, current, end);␊ |
814 | current = parse_acpi_datarefobject(ns, current, end);␊ |
815 | break;␊ |
816 | case AML_ALIAS_OP:␊ |
817 | current++;␊ |
818 | current = parse_acpi_namestring(ns, NULL, current, end);␊ |
819 | current = parse_acpi_namestring(ns, NULL, current, end);␊ |
820 | break;␊ |
821 | default:␊ |
822 | break;␊ |
823 | }␊ |
824 | return current;␊ |
825 | }␊ |
826 | ␊ |
827 | static U8 *parse_acpi_objectlist(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
828 | {␊ |
829 | DBG( "Beginning objectlist: 0x%02x at memory location %p end=%p\n", *current, current, end);␊ |
830 | while (current < end) {␊ |
831 | U8 *temp = current;␊ |
832 | ␊ |
833 | DBG( "New iteration of objectlist: 0x%02x at memory location %p end=%p\n", *current, current, end);␊ |
834 | ␊ |
835 | current = parse_acpi_namespacemodifierobj(ns, current, end);␊ |
836 | if (current != temp)␊ |
837 | continue;␊ |
838 | ␊ |
839 | current = parse_acpi_namedobj(ns, current, end);␊ |
840 | if (current != temp)␊ |
841 | continue;␊ |
842 | ␊ |
843 | if (current == temp) {␊ |
844 | DBG( "Unhandled object in object list: 0x%02x at memory location %p\n", *current, current);␊ |
845 | #if DEBUG_ACPI_DECODE␊ |
846 | DBG( "namespace: ");␊ |
847 | dprint_namespace(ns);␊ |
848 | DBG( "\n");␊ |
849 | #endif␊ |
850 | break;␊ |
851 | }␊ |
852 | }␊ |
853 | DBG( "Ending objectlist: 0x%02x at memory location %p\n", *current, current);␊ |
854 | return current;␊ |
855 | }␊ |
856 | ␊ |
857 | static U8 *parse_acpi_termarglist(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
858 | {␊ |
859 | DBG( "Beginning termarglist: 0x%02x at memory location %p\n", *current, current);␊ |
860 | while (current < end) {␊ |
861 | U8 *temp = current;␊ |
862 | ␊ |
863 | current = parse_acpi_termarg(ns, current, end);␊ |
864 | if (current == temp) {␊ |
865 | DBG( "Unhandled item in term arg list: 0x%02x at memory location %p\n", *current, current);␊ |
866 | #if DEBUG_ACPI_DECODE␊ |
867 | DBG( "namespace: ");␊ |
868 | dprint_namespace(ns);␊ |
869 | DBG( "\n");␊ |
870 | #endif␊ |
871 | break;␊ |
872 | }␊ |
873 | }␊ |
874 | return current;␊ |
875 | }␊ |
876 | ␊ |
877 | void parse_acpi_termlist(const struct acpi_namespace *ns, U8 * current, U8 * end)␊ |
878 | {␊ |
879 | while (current < end) {␊ |
880 | U8 *temp = current;␊ |
881 | ␊ |
882 | DBG( "Beginning new term in term list: 0x%02x at memory location %p\n", *current, current);␊ |
883 | ␊ |
884 | current = parse_acpi_namespacemodifierobj(ns, current, end);␊ |
885 | if (current != temp)␊ |
886 | continue;␊ |
887 | ␊ |
888 | current = parse_acpi_namedobj(ns, current, end);␊ |
889 | if (current != temp)␊ |
890 | continue;␊ |
891 | ␊ |
892 | current = parse_acpi_type1opcode(ns, current, end);␊ |
893 | if (current != temp)␊ |
894 | continue;␊ |
895 | ␊ |
896 | current = parse_acpi_type2opcode(ns, current, end);␊ |
897 | if (current != temp)␊ |
898 | continue;␊ |
899 | ␊ |
900 | switch (*current) {␊ |
901 | default:␊ |
902 | {␊ |
903 | DBG( "Unhandled item in term list: 0x%02x at memory location %p\n", *current, current);␊ |
904 | #if DEBUG_ACPI_DECODE␊ |
905 | DBG( "namespace: ");␊ |
906 | dprint_namespace(ns);␊ |
907 | DBG( "\n");␊ |
908 | #endif␊ |
909 | return;␊ |
910 | }␊ |
911 | }␊ |
912 | }␊ |
913 | }␊ |
914 | |