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