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