]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/AmlLib/Serialize/AmlSerialize.c
DynamicTablesPkg: Change OPTIONAL keyword usage style
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / AmlLib / Serialize / AmlSerialize.c
1 /** @file
2 AML Serialize.
3
4 Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8
9 #include <AmlNodeDefines.h>
10
11 #include <AmlCoreInterface.h>
12 #include <Stream/AmlStream.h>
13 #include <Tree/AmlNode.h>
14 #include <Tree/AmlTree.h>
15 #include <Utils/AmlUtility.h>
16
17 /** Callback function to copy the AML bytecodes contained in a node
18 to the Stream stored in the Context.
19 The SDT header data contained in the root node is not serialized
20 by this function.
21
22 @param [in] Node Pointer to the node to copy the AML bytecodes
23 from.
24 @param [in, out] Context Contains a forward Stream to write to.
25 (AML_STREAM*)Context.
26 @param [in, out] Status At entry, contains the status returned by the
27 last call to this exact function during the
28 enumeration.
29 As exit, contains the returned status of the
30 call to this function.
31 Optional, can be NULL.
32
33 @retval TRUE if the enumeration can continue or has finished without
34 interruption.
35 @retval FALSE if the enumeration needs to stopped or has stopped.
36 **/
37 STATIC
38 BOOLEAN
39 EFIAPI
40 AmlSerializeNodeCallback (
41 IN AML_NODE_HEADER * Node,
42 IN OUT VOID * Context OPTIONAL,
43 IN OUT EFI_STATUS * Status OPTIONAL
44 )
45 {
46 EFI_STATUS Status1;
47
48 CONST AML_DATA_NODE * DataNode;
49 CONST AML_OBJECT_NODE * ObjectNode;
50 AML_STREAM * FStream;
51
52 // Bytes needed to store OpCode[1] + SubOpcode[1] + MaxPkgLen[4] = 6 bytes.
53 UINT8 ObjectNodeInfoArray[6];
54 UINT32 Index;
55 BOOLEAN ContinueEnum;
56
57 CONST AML_OBJECT_NODE * ParentNode;
58 EAML_PARSE_INDEX IndexPtr;
59
60 if (!IS_AML_NODE_VALID (Node) ||
61 (Context == NULL)) {
62 ASSERT (0);
63 Status1 = EFI_INVALID_PARAMETER;
64 ContinueEnum = FALSE;
65 goto error_handler;
66 }
67
68 // Ignore the second fixed argument of method invocation nodes
69 // as the information stored there (the argument count) is not in the
70 // ACPI specification.
71 ParentNode = (CONST AML_OBJECT_NODE*)AmlGetParent ((AML_NODE_HEADER*)Node);
72 if (IS_AML_OBJECT_NODE (ParentNode) &&
73 AmlNodeCompareOpCode (ParentNode, AML_METHOD_INVOC_OP, 0) &&
74 AmlIsNodeFixedArgument (Node, &IndexPtr)) {
75 if (IndexPtr == EAmlParseIndexTerm1) {
76 if (Status != NULL) {
77 *Status = EFI_SUCCESS;
78 }
79 return TRUE;
80 }
81 }
82
83 Status1 = EFI_SUCCESS;
84 ContinueEnum = TRUE;
85 FStream = (AML_STREAM*)Context;
86
87 if (IS_AML_DATA_NODE (Node)) {
88 // Copy the content of the Buffer for a DataNode.
89 DataNode = (AML_DATA_NODE*)Node;
90 Status1 = AmlStreamWrite (
91 FStream,
92 DataNode->Buffer,
93 DataNode->Size
94 );
95 if (EFI_ERROR (Status1)) {
96 ASSERT (0);
97 ContinueEnum = FALSE;
98 goto error_handler;
99 }
100
101 } else if (IS_AML_OBJECT_NODE (Node) &&
102 !AmlNodeHasAttribute (
103 (CONST AML_OBJECT_NODE*)Node,
104 AML_IS_PSEUDO_OPCODE)) {
105 // Ignore pseudo-opcodes as they are not part of the
106 // ACPI specification.
107
108 ObjectNode = (AML_OBJECT_NODE*)Node;
109
110 Index = 0;
111 // Copy the opcode(s).
112 ObjectNodeInfoArray[Index++] = ObjectNode->AmlByteEncoding->OpCode;
113 if (ObjectNode->AmlByteEncoding->OpCode == AML_EXT_OP) {
114 ObjectNodeInfoArray[Index++] = ObjectNode->AmlByteEncoding->SubOpCode;
115 }
116
117 // Copy the PkgLen.
118 if (AmlNodeHasAttribute (ObjectNode, AML_HAS_PKG_LENGTH)) {
119 Index += AmlSetPkgLength (
120 ObjectNode->PkgLen,
121 &ObjectNodeInfoArray[Index]
122 );
123 }
124
125 Status1 = AmlStreamWrite (
126 FStream,
127 ObjectNodeInfoArray,
128 Index
129 );
130 if (EFI_ERROR (Status1)) {
131 ASSERT (0);
132 ContinueEnum = FALSE;
133 goto error_handler;
134 }
135 } // IS_AML_OBJECT_NODE (Node)
136
137 error_handler:
138 if (Status != NULL) {
139 *Status = Status1;
140 }
141 return ContinueEnum;
142 }
143
144 /** Serialize a tree to create an ACPI DSDT/SSDT table.
145
146 If:
147 - the content of BufferSize is >= to the size needed to serialize the
148 definition block;
149 - Buffer is not NULL;
150 first serialize the ACPI DSDT/SSDT header from the root node,
151 then serialize the AML blob from the rest of the tree.
152
153 The content of BufferSize is always updated to the size needed to
154 serialize the definition block.
155
156 @param [in] RootNode Pointer to a root node.
157 @param [in] Buffer Buffer to write the DSDT/SSDT table to.
158 If Buffer is NULL, the size needed to
159 serialize the DSDT/SSDT table is returned
160 in BufferSize.
161 @param [in, out] BufferSize Pointer holding the size of the Buffer.
162 Its content is always updated to the size
163 needed to serialize the DSDT/SSDT table.
164
165 @retval EFI_SUCCESS The function completed successfully.
166 @retval EFI_INVALID_PARAMETER Invalid parameter.
167 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
168 **/
169 EFI_STATUS
170 EFIAPI
171 AmlSerializeTree (
172 IN AML_ROOT_NODE * RootNode,
173 IN UINT8 * Buffer OPTIONAL,
174 IN OUT UINT32 * BufferSize
175 )
176 {
177 EFI_STATUS Status;
178 AML_STREAM FStream;
179 UINT32 TableSize;
180
181 if (!IS_AML_ROOT_NODE (RootNode) ||
182 (BufferSize == NULL)) {
183 ASSERT (0);
184 return EFI_INVALID_PARAMETER;
185 }
186
187 // Compute the total size of the AML blob.
188 Status = AmlComputeSize (
189 (CONST AML_NODE_HEADER*)RootNode,
190 &TableSize
191 );
192 if (EFI_ERROR (Status)) {
193 ASSERT (0);
194 return Status;
195 }
196
197 // Add the size of the ACPI header.
198 TableSize += (UINT32)sizeof (EFI_ACPI_DESCRIPTION_HEADER);
199
200 // Check the size against the SDT header.
201 // The Length field in the SDT Header is updated if the tree has
202 // been modified.
203 if (TableSize != RootNode->SdtHeader->Length) {
204 ASSERT (0);
205 return EFI_INVALID_PARAMETER;
206 }
207
208 // Buffer is not big enough, or NULL.
209 if ((TableSize < *BufferSize) || (Buffer == NULL)) {
210 *BufferSize = TableSize;
211 return EFI_SUCCESS;
212 }
213
214 // Initialize the stream to the TableSize that is needed.
215 Status = AmlStreamInit (
216 &FStream,
217 Buffer,
218 TableSize,
219 EAmlStreamDirectionForward
220 );
221 if (EFI_ERROR (Status)) {
222 ASSERT (0);
223 return Status;
224 }
225
226 // Serialize the header.
227 Status = AmlStreamWrite (
228 &FStream,
229 (UINT8*)RootNode->SdtHeader,
230 sizeof (EFI_ACPI_DESCRIPTION_HEADER)
231 );
232 if (EFI_ERROR (Status)) {
233 ASSERT (0);
234 return Status;
235 }
236
237 Status = EFI_SUCCESS;
238 AmlEnumTree (
239 (AML_NODE_HEADER*)RootNode,
240 AmlSerializeNodeCallback,
241 (VOID*)&FStream,
242 &Status
243 );
244 if (EFI_ERROR (Status)) {
245 ASSERT (0);
246 return Status;
247 }
248
249 // Update the checksum.
250 return AcpiPlatformChecksum ((EFI_ACPI_DESCRIPTION_HEADER*)Buffer);
251 }
252
253 /** Serialize an AML definition block.
254
255 This functions allocates memory with the "AllocateZeroPool ()"
256 function. This memory is used to serialize the AML tree and is
257 returned in the Table.
258
259 @param [in] RootNode Root node of the tree.
260 @param [out] Table On return, hold the serialized
261 definition block.
262
263 @retval EFI_SUCCESS The function completed successfully.
264 @retval EFI_INVALID_PARAMETER Invalid parameter.
265 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
266 **/
267 EFI_STATUS
268 EFIAPI
269 AmlSerializeDefinitionBlock (
270 IN AML_ROOT_NODE * RootNode,
271 OUT EFI_ACPI_DESCRIPTION_HEADER ** Table
272 )
273 {
274 EFI_STATUS Status;
275 UINT8 * TableBuffer;
276 UINT32 TableSize;
277
278 if (!IS_AML_ROOT_NODE (RootNode) ||
279 (Table == NULL)) {
280 ASSERT (0);
281 return EFI_INVALID_PARAMETER;
282 }
283
284 *Table = NULL;
285 TableBuffer = NULL;
286 TableSize = 0;
287
288 // Get the size of the SSDT table.
289 Status = AmlSerializeTree (
290 RootNode,
291 TableBuffer,
292 &TableSize
293 );
294 if (EFI_ERROR (Status)) {
295 ASSERT (0);
296 return Status;
297 }
298
299 TableBuffer = (UINT8*)AllocateZeroPool (TableSize);
300 if (TableBuffer == NULL) {
301 DEBUG ((
302 DEBUG_ERROR,
303 "ERROR: Failed to allocate memory for Table Buffer."
304 ));
305 ASSERT (0);
306 return EFI_OUT_OF_RESOURCES;
307 }
308
309 // Serialize the tree to a SSDT table.
310 Status = AmlSerializeTree (
311 RootNode,
312 TableBuffer,
313 &TableSize
314 );
315 if (EFI_ERROR (Status)) {
316 FreePool (TableBuffer);
317 ASSERT (0);
318 } else {
319 // Save the allocated Table buffer in the table list
320 *Table = (EFI_ACPI_DESCRIPTION_HEADER*)TableBuffer;
321 }
322
323 return Status;
324 }