1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
|
/** @file
AML Field List Parser.
Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Parser/AmlFieldListParser.h>
#include <AmlCoreInterface.h>
#include <AmlDbgPrint/AmlDbgPrint.h>
#include <Parser/AmlMethodParser.h>
#include <Parser/AmlParser.h>
#include <Tree/AmlNode.h>
#include <Tree/AmlTree.h>
/** Parse a field element.
The field elements this function can parse are one of:
- ReservedField;
- AccessField;
- ConnectField;
- ExtendedAccessField.
Indeed, the NamedField field element doesn't have an OpCode. Thus it needs
to be parsed differently.
@param [in] FieldByteEncoding Field byte encoding to parse.
@param [in, out] FieldNode Field node to attach the field
element to.
Must have the AML_HAS_FIELD_LIST
attribute.
@param [in, out] FStream Forward stream pointing to a field
element not being a named field.
The stream must not be at its end.
@param [in, out] NameSpaceRefList List of namespace reference nodes,
allowing to associate an absolute
path to a node in the tree.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
@retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
**/
STATIC
EFI_STATUS
EFIAPI
AmlParseFieldElement (
IN CONST AML_BYTE_ENCODING *FieldByteEncoding,
IN OUT AML_OBJECT_NODE *FieldNode,
IN OUT AML_STREAM *FStream,
IN OUT LIST_ENTRY *NameSpaceRefList
)
{
EFI_STATUS Status;
UINT8 *CurrPos;
AML_OBJECT_NODE *NewNode;
UINT32 PkgLenOffset;
UINT32 PkgLenSize;
// Check whether the node is an Object Node and has a field list.
// The byte encoding must be a field element.
if ((FieldByteEncoding == NULL) ||
((FieldByteEncoding->Attribute & AML_IS_FIELD_ELEMENT) == 0) ||
((FieldByteEncoding->Attribute & AML_IS_PSEUDO_OPCODE) ==
AML_IS_PSEUDO_OPCODE) ||
!AmlNodeHasAttribute (FieldNode, AML_HAS_FIELD_LIST) ||
!IS_STREAM (FStream) ||
IS_END_OF_STREAM (FStream) ||
!IS_STREAM_FORWARD (FStream) ||
(NameSpaceRefList == NULL))
{
ASSERT (0);
return EFI_INVALID_PARAMETER;
}
CurrPos = AmlStreamGetCurrPos (FStream);
if (CurrPos == NULL) {
ASSERT (0);
return EFI_INVALID_PARAMETER;
}
// Skip the field opcode (1 byte) as it is already in the FieldByteEncoding.
AMLDBG_DUMP_RAW (CurrPos, 1);
Status = AmlStreamProgress (FStream, 1);
if (EFI_ERROR (Status)) {
ASSERT (0);
return Status;
}
CurrPos = AmlStreamGetCurrPos (FStream);
if (CurrPos == NULL) {
ASSERT (0);
return EFI_INVALID_PARAMETER;
}
// Parse the PkgLen if available.
PkgLenSize = 0;
if ((FieldByteEncoding->Attribute & AML_HAS_PKG_LENGTH) ==
AML_HAS_PKG_LENGTH)
{
PkgLenOffset = AmlGetPkgLength (CurrPos, &PkgLenSize);
if (PkgLenOffset == 0) {
ASSERT (0);
return EFI_INVALID_PARAMETER;
}
// Move stream forward as the PkgLen has been read.
AMLDBG_DUMP_RAW (CurrPos, PkgLenOffset);
Status = AmlStreamProgress (FStream, PkgLenOffset);
if (EFI_ERROR (Status)) {
ASSERT (0);
return Status;
}
// Update the current position as PkgLen has been parsed.
CurrPos = AmlStreamGetCurrPos (FStream);
}
Status = AmlCreateObjectNode (
FieldByteEncoding,
PkgLenSize,
&NewNode
);
if (EFI_ERROR (Status)) {
ASSERT (0);
return Status;
}
// Add the FieldElement to the Variable Argument List.
Status = AmlVarListAddTailInternal (
(AML_NODE_HEADER *)FieldNode,
(AML_NODE_HEADER *)NewNode
);
if (EFI_ERROR (Status)) {
ASSERT (0);
// Delete the sub-tree if the insertion failed.
// Otherwise its reference will be lost.
AmlDeleteTree ((AML_NODE_HEADER *)NewNode);
return Status;
}
// Some field elements do not have fixed arguments.
if (!IS_END_OF_STREAM (FStream)) {
// Parse the fixed arguments of the field element.
Status = AmlParseFixedArguments (
NewNode,
FStream,
NameSpaceRefList
);
if (EFI_ERROR (Status)) {
ASSERT (0);
}
}
return Status;
}
/** Parse a named field element.
Indeed, the NamedField field element doesn't have an OpCode. Thus it needs
to be parsed differently. NamedField field element start with a char.
@param [in] NamedFieldByteEncoding Field byte encoding to parse.
@param [in, out] FieldNode Field node to attach the field
element to.
Must have the AML_HAS_FIELD_LIST
attribute.
@param [in, out] FStream Forward stream pointing to a named
field element.
The stream must not be at its end.
@param [in, out] NameSpaceRefList List of namespace reference nodes,
allowing to associate an absolute
path to a node in the tree.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
@retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
**/
STATIC
EFI_STATUS
EFIAPI
AmlParseNamedFieldElement (
IN CONST AML_BYTE_ENCODING *NamedFieldByteEncoding,
IN OUT AML_OBJECT_NODE *FieldNode,
IN OUT AML_STREAM *FStream,
IN OUT LIST_ENTRY *NameSpaceRefList
)
{
EFI_STATUS Status;
AML_OBJECT_NODE *NewNode;
// Check whether the node is an Object Node and has a field list.
// The byte encoding must be a char.
if ((NamedFieldByteEncoding == NULL) ||
((NamedFieldByteEncoding->Attribute & AML_IS_NAME_CHAR) == 0) ||
!AmlNodeHasAttribute (FieldNode, AML_HAS_FIELD_LIST) ||
!IS_STREAM (FStream) ||
IS_END_OF_STREAM (FStream) ||
!IS_STREAM_FORWARD (FStream) ||
(NameSpaceRefList == NULL))
{
ASSERT (0);
return EFI_INVALID_PARAMETER;
}
// Create a NamedField node.
Status = AmlCreateObjectNode (
AmlGetFieldEncodingByOpCode (AML_FIELD_NAMED_OP, 0),
0,
&NewNode
);
if (EFI_ERROR (Status)) {
ASSERT (0);
return Status;
}
// Add the NamedField node to the variable argument list.
Status = AmlVarListAddTailInternal (
(AML_NODE_HEADER *)FieldNode,
(AML_NODE_HEADER *)NewNode
);
if (EFI_ERROR (Status)) {
ASSERT (0);
// Delete the sub-tree if the insertion failed.
// Otherwise its reference will be lost.
AmlDeleteTree ((AML_NODE_HEADER *)NewNode);
return Status;
}
// Parse the fixed arguments: [0]NameSeg, [1]PkgLen.
Status = AmlParseFixedArguments (
NewNode,
FStream,
NameSpaceRefList
);
if (EFI_ERROR (Status)) {
ASSERT (0);
return Status;
}
// Add the NamedField to the namespace reference list.
Status = AmlAddNameSpaceReference (
NewNode,
NameSpaceRefList
);
ASSERT_EFI_ERROR (Status);
return Status;
}
/** Parse the FieldList contained in the stream.
Create an object node for each field element parsed in the field list
available in the Stream, and add them to the variable list of arguments
of the FieldNode.
Nodes that can have a field list are referred as field nodes. They have the
AML_HAS_FIELD_LIST attribute.
According to the ACPI 6.3 specification, s20.2.5.2 "Named Objects Encoding",
field elements can be:
- NamedField := NameSeg PkgLength;
- ReservedField := 0x00 PkgLength;
- AccessField := 0x01 AccessType AccessAttrib;
- ConnectField := <0x02 NameString> | <0x02 BufferData>;
- ExtendedAccessField := 0x03 AccessType ExtendedAccessAttrib AccessLength.
A small set of opcodes describes the field elements. They are referred as
field opcodes. An AML_BYTE_ENCODING table has been created for field OpCodes.
Field elements:
- don't have a SubOpCode;
- have at most 3 fixed arguments (as opposed to 6 for standard AML objects);
- don't have a variable list of arguments;
- only the NamedField field element is part of the AML namespace.
ConnectField's BufferData is a buffer node containing a single
resource data element.
NamedField field elements don't have an AML OpCode. NameSeg starts with a
Char type and can thus be differentiated from the Opcodes for other fields.
A pseudo OpCode has been created to simplify the parser.
The branch created from parsing a field node is as:
(FieldNode)
\
|- [FixedArg[0]][FixedArg[1]] # Fixed Arguments
|- {(FieldElement[0])->(FieldElement[1])->...)} # Variable Arguments
With FieldElement[n] being one of NamedField, ReservedField, AccessField,
ConnectField, ExtendedAccessField.
@param [in] FieldNode Field node.
Must have the AML_HAS_FIELD_LIST
attribute.
@param [in] FStream Forward stream pointing to a field list.
The stream must not be at its end.
@param [in] NameSpaceRefList List of namespace reference nodes,
allowing to associate an absolute
path to a node in the tree.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
@retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlParseFieldList (
IN AML_OBJECT_NODE *FieldNode,
IN AML_STREAM *FStream,
IN LIST_ENTRY *NameSpaceRefList
)
{
EFI_STATUS Status;
UINT8 *CurrPos;
CONST AML_BYTE_ENCODING *FieldByteEncoding;
CONST AML_BYTE_ENCODING *NamedFieldByteEncoding;
// Check whether the node is an Object Node and has a field list.
if (!AmlNodeHasAttribute (FieldNode, AML_HAS_FIELD_LIST) ||
!IS_STREAM (FStream) ||
IS_END_OF_STREAM (FStream) ||
!IS_STREAM_FORWARD (FStream) ||
(NameSpaceRefList == NULL))
{
ASSERT (0);
return EFI_INVALID_PARAMETER;
}
// Iterate through the field elements, creating nodes
// and adding them to the variable list of elements of Node.
while (!IS_END_OF_STREAM (FStream)) {
CurrPos = AmlStreamGetCurrPos (FStream);
// Check for a field opcode.
FieldByteEncoding = AmlGetFieldEncoding (CurrPos);
if (FieldByteEncoding != NULL) {
Status = AmlParseFieldElement (
FieldByteEncoding,
FieldNode,
FStream,
NameSpaceRefList
);
if (EFI_ERROR (Status)) {
ASSERT (0);
return Status;
}
} else {
// Handle the case of Pseudo OpCodes.
// NamedField has a Pseudo OpCode and starts with a NameChar. Therefore,
// call AmlGetByteEncoding() to check that the encoding is NameChar.
NamedFieldByteEncoding = AmlGetByteEncoding (CurrPos);
if ((NamedFieldByteEncoding != NULL) &&
(NamedFieldByteEncoding->Attribute & AML_IS_NAME_CHAR))
{
// This is a NamedField field element since it is starting with a char.
Status = AmlParseNamedFieldElement (
NamedFieldByteEncoding,
FieldNode,
FStream,
NameSpaceRefList
);
if (EFI_ERROR (Status)) {
ASSERT (0);
return Status;
}
} else {
// A field opcode or an AML byte encoding is expected.
ASSERT (0);
return EFI_INVALID_PARAMETER;
}
}
} // while
return EFI_SUCCESS;
}
|