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