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 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 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 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 * 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 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 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