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