1 /** @file
2 ACPI Sdt Protocol Driver
3
4 Copyright (c) 2010, Intel Corporation. All rights reserved. <BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "AcpiTable.h"
16
17 /**
18 Retrieve option term according to AmlByteEncoding and Buffer.
19
20 @param[in] AmlByteEncoding AML Byte Encoding.
21 @param[in] Buffer AML buffer.
22 @param[in] MaxBufferSize AML buffer MAX size. The parser can not parse any data exceed this region.
23 @param[in] TermIndex Index of the data to retrieve from the object.
24 @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
25 for the specified index.
26 @param[out] Data Upon return, points to the pointer to the data.
27 @param[out] DataSize Upon return, points to the size of Data.
28
29 @retval EFI_SUCCESS Success.
30 @retval EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object.
31 **/
32 EFI_STATUS
AmlParseOptionTerm(IN AML_BYTE_ENCODING * AmlByteEncoding,IN UINT8 * Buffer,IN UINTN MaxBufferSize,IN AML_OP_PARSE_INDEX TermIndex,OUT EFI_ACPI_DATA_TYPE * DataType,OUT VOID ** Data,OUT UINTN * DataSize)33 AmlParseOptionTerm (
34 IN AML_BYTE_ENCODING *AmlByteEncoding,
35 IN UINT8 *Buffer,
36 IN UINTN MaxBufferSize,
37 IN AML_OP_PARSE_INDEX TermIndex,
38 OUT EFI_ACPI_DATA_TYPE *DataType,
39 OUT VOID **Data,
40 OUT UINTN *DataSize
41 )
42 {
43 AML_BYTE_ENCODING *ChildAmlByteEncoding;
44 EFI_STATUS Status;
45
46 if (DataType != NULL) {
47 *DataType = AmlTypeToAcpiType (AmlByteEncoding->Format[TermIndex - 1]);
48 }
49 if (Data != NULL) {
50 *Data = Buffer;
51 }
52 //
53 // Parse term according to AML type
54 //
55 switch (AmlByteEncoding->Format[TermIndex - 1]) {
56 case AML_UINT8:
57 *DataSize = sizeof(UINT8);
58 break;
59 case AML_UINT16:
60 *DataSize = sizeof(UINT16);
61 break;
62 case AML_UINT32:
63 *DataSize = sizeof(UINT32);
64 break;
65 case AML_UINT64:
66 *DataSize = sizeof(UINT64);
67 break;
68 case AML_STRING:
69 *DataSize = AsciiStrSize((CHAR8 *)Buffer);
70 break;
71 case AML_NAME:
72 Status = AmlGetNameStringSize (Buffer, DataSize);
73 if (EFI_ERROR (Status)) {
74 return EFI_INVALID_PARAMETER;
75 }
76 break;
77 case AML_OBJECT:
78 ChildAmlByteEncoding = AmlSearchByOpByte (Buffer);
79 if (ChildAmlByteEncoding == NULL) {
80 return EFI_INVALID_PARAMETER;
81 }
82
83 //
84 // NOTE: We need override DataType here, if there is a case the AML_OBJECT is AML_NAME.
85 // We need convert type from EFI_ACPI_DATA_TYPE_CHILD to EFI_ACPI_DATA_TYPE_NAME_STRING.
86 // We should not return CHILD because there is NO OpCode for NameString.
87 //
88 if ((ChildAmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
89 if (DataType != NULL) {
90 *DataType = AmlTypeToAcpiType (AML_NAME);
91 }
92 Status = AmlGetNameStringSize (Buffer, DataSize);
93 if (EFI_ERROR (Status)) {
94 return EFI_INVALID_PARAMETER;
95 }
96 break;
97 }
98
99 //
100 // It is real AML_OBJECT
101 //
102 *DataSize = AmlGetObjectSize (
103 ChildAmlByteEncoding,
104 Buffer,
105 MaxBufferSize
106 );
107 if (*DataSize == 0) {
108 return EFI_INVALID_PARAMETER;
109 }
110 break;
111 case AML_NONE:
112 //
113 // No term
114 //
115 case AML_OPCODE:
116 default:
117 ASSERT (FALSE);
118 return EFI_INVALID_PARAMETER;
119 }
120 if (*DataSize > MaxBufferSize) {
121 return EFI_INVALID_PARAMETER;
122 }
123 return EFI_SUCCESS;
124 }
125
126 /**
127 Retrieve information according to AmlByteEncoding and Buffer.
128
129 @param[in] AmlByteEncoding AML Byte Encoding.
130 @param[in] Buffer AML buffer.
131 @param[in] MaxBufferSize AML buffer MAX size. The parser can not parse any data exceed this region.
132 @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
133 in the ACPI encoding, with index 0 always being the ACPI opcode.
134 @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
135 for the specified index.
136 @param[out] Data Upon return, points to the pointer to the data.
137 @param[out] DataSize Upon return, points to the size of Data.
138
139 @retval EFI_SUCCESS Success.
140 @retval EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object.
141 **/
142 EFI_STATUS
AmlParseOptionCommon(IN AML_BYTE_ENCODING * AmlByteEncoding,IN UINT8 * Buffer,IN UINTN MaxBufferSize,IN AML_OP_PARSE_INDEX Index,OUT EFI_ACPI_DATA_TYPE * DataType,OUT VOID ** Data,OUT UINTN * DataSize)143 AmlParseOptionCommon (
144 IN AML_BYTE_ENCODING *AmlByteEncoding,
145 IN UINT8 *Buffer,
146 IN UINTN MaxBufferSize,
147 IN AML_OP_PARSE_INDEX Index,
148 OUT EFI_ACPI_DATA_TYPE *DataType,
149 OUT VOID **Data,
150 OUT UINTN *DataSize
151 )
152 {
153 UINT8 *CurrentBuffer;
154 UINTN PkgLength;
155 UINTN OpLength;
156 UINTN PkgOffset;
157 AML_OP_PARSE_INDEX TermIndex;
158 EFI_STATUS Status;
159
160 ASSERT ((Index <= AmlByteEncoding->MaxIndex) || (Index == AML_OP_PARSE_INDEX_GET_SIZE));
161
162 //
163 // 0. Check if this is NAME string.
164 //
165 if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
166 //
167 // Only allow GET_SIZE
168 //
169 if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
170 return EFI_INVALID_PARAMETER;
171 }
172 //
173 // return NameString size
174 //
175 Status = AmlGetNameStringSize (Buffer, DataSize);
176 if (EFI_ERROR (Status)) {
177 return EFI_INVALID_PARAMETER;
178 }
179 if (*DataSize > MaxBufferSize) {
180 return EFI_INVALID_PARAMETER;
181 }
182 return EFI_SUCCESS;
183 }
184
185 //
186 // Not NAME string, start parsing
187 //
188 CurrentBuffer = Buffer;
189
190 //
191 // 1. Get OpCode
192 //
193 if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
194 *DataType = EFI_ACPI_DATA_TYPE_OPCODE;
195 *Data = (VOID *)CurrentBuffer;
196 }
197 if (*CurrentBuffer == AML_EXT_OP) {
198 OpLength = 2;
199 } else {
200 OpLength = 1;
201 }
202 *DataSize = OpLength;
203 if (Index == AML_OP_PARSE_INDEX_GET_OPCODE) {
204 return EFI_SUCCESS;
205 }
206 if (OpLength > MaxBufferSize) {
207 return EFI_INVALID_PARAMETER;
208 }
209 CurrentBuffer += OpLength;
210
211 //
212 // 2. Skip PkgLength field, if have
213 //
214 if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
215 PkgOffset = AmlGetPkgLength(CurrentBuffer, &PkgLength);
216 //
217 // Override MaxBufferSize if it is valid PkgLength
218 //
219 if (OpLength + PkgLength > MaxBufferSize) {
220 return EFI_INVALID_PARAMETER;
221 } else {
222 MaxBufferSize = OpLength + PkgLength;
223 }
224 } else {
225 PkgOffset = 0;
226 PkgLength = 0;
227 }
228 CurrentBuffer += PkgOffset;
229
230 //
231 // 3. Get Term one by one.
232 //
233 TermIndex = AML_OP_PARSE_INDEX_GET_TERM1;
234 while ((Index >= TermIndex) && (TermIndex <= AmlByteEncoding->MaxIndex) && ((UINTN)CurrentBuffer < (UINTN)Buffer + MaxBufferSize)) {
235 Status = AmlParseOptionTerm (
236 AmlByteEncoding,
237 CurrentBuffer,
238 (UINTN)Buffer + MaxBufferSize - (UINTN)CurrentBuffer,
239 TermIndex,
240 DataType,
241 Data,
242 DataSize
243 );
244 if (EFI_ERROR (Status)) {
245 return EFI_INVALID_PARAMETER;
246 }
247
248 if (Index == TermIndex) {
249 //
250 // Done
251 //
252 return EFI_SUCCESS;
253 }
254
255 //
256 // Parse next one
257 //
258 CurrentBuffer += *DataSize;
259 TermIndex ++;
260 }
261
262 //
263 // Finish all options, but no option found.
264 //
265 if ((UINTN)CurrentBuffer > (UINTN)Buffer + MaxBufferSize) {
266 return EFI_INVALID_PARAMETER;
267 }
268 if ((UINTN)CurrentBuffer == (UINTN)Buffer + MaxBufferSize) {
269 if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
270 return EFI_INVALID_PARAMETER;
271 }
272 }
273
274 //
275 // 4. Finish parsing all node, return size
276 //
277 ASSERT (Index == AML_OP_PARSE_INDEX_GET_SIZE);
278 if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
279 *DataSize = OpLength + PkgLength;
280 } else {
281 *DataSize = (UINTN)CurrentBuffer - (UINTN)Buffer;
282 }
283
284 return EFI_SUCCESS;
285 }
286
287 /**
288 Return object size.
289
290 @param[in] AmlByteEncoding AML Byte Encoding.
291 @param[in] Buffer AML object buffer.
292 @param[in] MaxBufferSize AML object buffer MAX size. The parser can not parse any data exceed this region.
293
294 @return Size of the object.
295 **/
296 UINTN
AmlGetObjectSize(IN AML_BYTE_ENCODING * AmlByteEncoding,IN UINT8 * Buffer,IN UINTN MaxBufferSize)297 AmlGetObjectSize (
298 IN AML_BYTE_ENCODING *AmlByteEncoding,
299 IN UINT8 *Buffer,
300 IN UINTN MaxBufferSize
301 )
302 {
303 EFI_STATUS Status;
304 UINTN DataSize;
305
306 Status = AmlParseOptionCommon (
307 AmlByteEncoding,
308 Buffer,
309 MaxBufferSize,
310 AML_OP_PARSE_INDEX_GET_SIZE,
311 NULL,
312 NULL,
313 &DataSize
314 );
315 if (EFI_ERROR (Status)) {
316 return 0;
317 } else {
318 return DataSize;
319 }
320 }
321
322 /**
323 Return object name.
324
325 @param[in] AmlHandle AML handle.
326
327 @return Name of the object.
328 **/
329 CHAR8 *
AmlGetObjectName(IN EFI_AML_HANDLE * AmlHandle)330 AmlGetObjectName (
331 IN EFI_AML_HANDLE *AmlHandle
332 )
333 {
334 AML_BYTE_ENCODING *AmlByteEncoding;
335 VOID *NameString;
336 UINTN NameSize;
337 AML_OP_PARSE_INDEX TermIndex;
338 EFI_STATUS Status;
339 EFI_ACPI_DATA_TYPE DataType;
340
341 AmlByteEncoding = AmlHandle->AmlByteEncoding;
342
343 ASSERT ((AmlByteEncoding->Attribute & AML_IN_NAMESPACE) != 0);
344
345 //
346 // Find out Last Name index, according to OpCode table.
347 // The last name will be the node name by design.
348 //
349 TermIndex = AmlByteEncoding->MaxIndex;
350 for (TermIndex = AmlByteEncoding->MaxIndex; TermIndex > 0; TermIndex--) {
351 if (AmlByteEncoding->Format[TermIndex - 1] == AML_NAME) {
352 break;
353 }
354 }
355 ASSERT (TermIndex != 0);
356
357 //
358 // Get Name for this node.
359 //
360 Status = AmlParseOptionHandleCommon (
361 AmlHandle,
362 TermIndex,
363 &DataType,
364 &NameString,
365 &NameSize
366 );
367 if (EFI_ERROR (Status)) {
368 return NULL;
369 }
370 ASSERT (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING);
371
372 return NameString;
373 }
374
375 /**
376 Return offset of last option.
377
378 @param[in] AmlHandle AML Handle.
379 @param[out] Buffer Upon return, points to the offset after last option.
380
381 @retval EFI_SUCCESS Success.
382 @retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
383 **/
384 EFI_STATUS
AmlGetOffsetAfterLastOption(IN EFI_AML_HANDLE * AmlHandle,OUT UINT8 ** Buffer)385 AmlGetOffsetAfterLastOption (
386 IN EFI_AML_HANDLE *AmlHandle,
387 OUT UINT8 **Buffer
388 )
389 {
390 EFI_ACPI_DATA_TYPE DataType;
391 VOID *Data;
392 UINTN DataSize;
393 EFI_STATUS Status;
394
395 Status = AmlParseOptionHandleCommon (
396 AmlHandle,
397 AmlHandle->AmlByteEncoding->MaxIndex,
398 &DataType,
399 &Data,
400 &DataSize
401 );
402 if (EFI_ERROR (Status)) {
403 return EFI_INVALID_PARAMETER;
404 }
405
406 //
407 // We need to parse the rest buffer after last node.
408 //
409 *Buffer = (UINT8 *)((UINTN)Data + DataSize);
410
411 //
412 // We need skip PkgLength if no Option
413 //
414 if (DataType == EFI_ACPI_DATA_TYPE_OPCODE) {
415 *Buffer += AmlGetPkgLength (*Buffer, &DataSize);
416 }
417 return EFI_SUCCESS;
418 }
419
420 /**
421 Retrieve information according to AmlHandle
422
423 @param[in] AmlHandle AML handle.
424 @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right
425 in the ACPI encoding, with index 0 always being the ACPI opcode.
426 @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
427 for the specified index.
428 @param[out] Data Upon return, points to the pointer to the data.
429 @param[out] DataSize Upon return, points to the size of Data.
430
431 @retval EFI_SUCCESS Success.
432 @retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
433 **/
434 EFI_STATUS
AmlParseOptionHandleCommon(IN EFI_AML_HANDLE * AmlHandle,IN AML_OP_PARSE_INDEX Index,OUT EFI_ACPI_DATA_TYPE * DataType,OUT VOID ** Data,OUT UINTN * DataSize)435 AmlParseOptionHandleCommon (
436 IN EFI_AML_HANDLE *AmlHandle,
437 IN AML_OP_PARSE_INDEX Index,
438 OUT EFI_ACPI_DATA_TYPE *DataType,
439 OUT VOID **Data,
440 OUT UINTN *DataSize
441 )
442 {
443 return AmlParseOptionCommon (
444 AmlHandle->AmlByteEncoding,
445 AmlHandle->Buffer,
446 AmlHandle->Size,
447 Index,
448 DataType,
449 Data,
450 DataSize
451 );
452 }
453