]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/AmlLib/Api/AmlResourceDataApi.c
DynamicTablesPkg: AmlLib APIs
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / AmlLib / Api / AmlResourceDataApi.c
1 /** @file
2 AML Update Resource Data.
3
4 Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8
9 /* Even though this file has access to the internal Node definition,
10 i.e. AML_ROOT_NODE, AML_OBJECT_NODE, etc. Only the external node
11 handle types should be used, i.e. AML_NODE_HANDLE, AML_ROOT_NODE_HANDLE,
12 etc.
13 Indeed, the functions in the "Api" folder should be implemented only
14 using the "safe" functions available in the "Include" folder. This
15 makes the functions available in the "Api" folder easy to export.
16 */
17 #include <AmlNodeDefines.h>
18
19 #include <AmlCoreInterface.h>
20 #include <AmlInclude.h>
21 #include <Api/AmlApiHelper.h>
22 #include <CodeGen/AmlResourceDataCodeGen.h>
23
24 /** Update the first interrupt of an Interrupt resource data node.
25
26 The flags of the Interrupt resource data are left unchanged.
27
28 The InterruptRdNode corresponds to the Resource Data created by the
29 "Interrupt ()" ASL macro. It is an Extended Interrupt Resource Data.
30 See ACPI 6.3 specification, s6.4.3.6 "Extended Interrupt Descriptor"
31 for more information about Extended Interrupt Resource Data.
32
33 @param [in] InterruptRdNode Pointer to the an extended interrupt
34 resource data node.
35 @param [in] Irq Interrupt value to update.
36
37 @retval EFI_SUCCESS The function completed successfully.
38 @retval EFI_INVALID_PARAMETER Invalid parameter.
39 @retval EFI_OUT_OF_RESOURCES Out of resources.
40 **/
41 EFI_STATUS
42 EFIAPI
43 AmlUpdateRdInterrupt (
44 IN AML_DATA_NODE_HANDLE InterruptRdNode,
45 IN UINT32 Irq
46 )
47 {
48 EFI_STATUS Status;
49 UINT32 * FirstInterrupt;
50 UINT8 * QueryBuffer;
51 UINT32 QueryBufferSize;
52
53 if ((InterruptRdNode == NULL) ||
54 (AmlGetNodeType ((AML_NODE_HANDLE)InterruptRdNode) != EAmlNodeData) ||
55 (!AmlNodeHasDataType (
56 InterruptRdNode,
57 EAmlNodeDataTypeResourceData)) ||
58 (!AmlNodeHasRdDataType (
59 InterruptRdNode,
60 AML_RD_BUILD_LARGE_DESC_ID (
61 ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME)))) {
62 ASSERT (0);
63 return EFI_INVALID_PARAMETER;
64 }
65
66 QueryBuffer = NULL;
67
68 // Get the size of the InterruptRdNode buffer.
69 Status = AmlGetDataNodeBuffer (
70 InterruptRdNode,
71 NULL,
72 &QueryBufferSize
73 );
74 if (EFI_ERROR (Status)) {
75 ASSERT (0);
76 return Status;
77 }
78
79 // Check the Buffer is large enough.
80 if (QueryBufferSize < sizeof (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR)) {
81 ASSERT (0);
82 return EFI_INVALID_PARAMETER;
83 }
84
85 // Allocate a buffer to fetch the data.
86 QueryBuffer = AllocatePool (QueryBufferSize);
87 if (QueryBuffer == NULL) {
88 ASSERT (0);
89 return EFI_OUT_OF_RESOURCES;
90 }
91
92 // Get the data.
93 Status = AmlGetDataNodeBuffer (
94 InterruptRdNode,
95 QueryBuffer,
96 &QueryBufferSize
97 );
98 if (EFI_ERROR (Status)) {
99 ASSERT (0);
100 goto error_handler;
101 }
102
103 // Get the address of the first interrupt field.
104 FirstInterrupt =
105 ((EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR*)QueryBuffer)->InterruptNumber;
106
107 *FirstInterrupt = Irq;
108
109 // Update the InterruptRdNode buffer.
110 Status = AmlUpdateDataNode (
111 InterruptRdNode,
112 EAmlNodeDataTypeResourceData,
113 QueryBuffer,
114 QueryBufferSize
115 );
116 if (EFI_ERROR (Status)) {
117 ASSERT (0);
118 }
119
120 error_handler:
121 if (QueryBuffer != NULL) {
122 FreePool (QueryBuffer);
123 }
124 return Status;
125 }
126
127 /** Update the interrupt list of an interrupt resource data node.
128
129 The InterruptRdNode corresponds to the Resource Data created by the
130 "Interrupt ()" ASL function. It is an Extended Interrupt Resource Data.
131 See ACPI 6.3 specification, s6.4.3.6 "Extended Interrupt Descriptor"
132 for more information about Extended Interrupt Resource Data.
133
134 @param [in] InterruptRdNode Pointer to the an extended interrupt
135 resource data node.
136 @param [in] ResourceConsumer The device consumes the specified interrupt
137 or produces it for use by a child device.
138 @param [in] EdgeTriggered The interrupt is edge triggered or
139 level triggered.
140 @param [in] ActiveLow The interrupt is active-high or active-low.
141 @param [in] Shared The interrupt can be shared with other
142 devices or not (Exclusive).
143 @param [in] IrqList Interrupt list. Must be non-NULL.
144 @param [in] IrqCount Interrupt count. Must be non-zero.
145
146
147 @retval EFI_SUCCESS The function completed successfully.
148 @retval EFI_INVALID_PARAMETER Invalid parameter.
149 @retval EFI_OUT_OF_RESOURCES Out of resources.
150 **/
151 EFI_STATUS
152 EFIAPI
153 AmlUpdateRdInterruptEx (
154 IN AML_DATA_NODE_HANDLE InterruptRdNode,
155 IN BOOLEAN ResourceConsumer,
156 IN BOOLEAN EdgeTriggered,
157 IN BOOLEAN ActiveLow,
158 IN BOOLEAN Shared,
159 IN UINT32 * IrqList,
160 IN UINT8 IrqCount
161 )
162 {
163 EFI_STATUS Status;
164
165 EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR * RdInterrupt;
166 UINT32 * FirstInterrupt;
167 UINT8 * UpdateBuffer;
168 UINT16 UpdateBufferSize;
169
170 if ((InterruptRdNode == NULL) ||
171 (AmlGetNodeType ((AML_NODE_HANDLE)InterruptRdNode) != EAmlNodeData) ||
172 (!AmlNodeHasDataType (
173 InterruptRdNode,
174 EAmlNodeDataTypeResourceData)) ||
175 (!AmlNodeHasRdDataType (
176 InterruptRdNode,
177 AML_RD_BUILD_LARGE_DESC_ID (
178 ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME))) ||
179 (IrqList == NULL) ||
180 (IrqCount == 0)) {
181 ASSERT (0);
182 return EFI_INVALID_PARAMETER;
183 }
184
185 UpdateBuffer = NULL;
186 UpdateBufferSize = sizeof (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR) +
187 ((IrqCount - 1) * sizeof (UINT32));
188
189 // Allocate a buffer to update the data.
190 UpdateBuffer = AllocatePool (UpdateBufferSize);
191 if (UpdateBuffer == NULL) {
192 ASSERT (0);
193 return EFI_OUT_OF_RESOURCES;
194 }
195
196 // Update the Resource Data information (structure size, interrupt count).
197 RdInterrupt = (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR*)UpdateBuffer;
198 RdInterrupt->Header.Header.Byte =
199 AML_RD_BUILD_LARGE_DESC_ID (ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME);
200 RdInterrupt->Header.Length =
201 UpdateBufferSize - sizeof (ACPI_LARGE_RESOURCE_HEADER);
202 RdInterrupt->InterruptTableLength = IrqCount;
203 RdInterrupt->InterruptVectorFlags = (ResourceConsumer ? BIT0 : 0) |
204 (EdgeTriggered ? BIT1 : 0) |
205 (ActiveLow ? BIT2 : 0) |
206 (Shared ? BIT3 : 0);
207
208 // Get the address of the first interrupt field.
209 FirstInterrupt =
210 ((EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR*)UpdateBuffer)->InterruptNumber;
211
212 // Copy the input list of interrupts.
213 CopyMem (FirstInterrupt, IrqList, (sizeof (UINT32) * IrqCount));
214
215 // Update the InterruptRdNode buffer.
216 Status = AmlUpdateDataNode (
217 InterruptRdNode,
218 EAmlNodeDataTypeResourceData,
219 UpdateBuffer,
220 UpdateBufferSize
221 );
222 if (EFI_ERROR (Status)) {
223 ASSERT (0);
224 }
225
226 // Cleanup
227 FreePool (UpdateBuffer);
228
229 return Status;
230 }
231
232 /** Update the base address and length of a QWord resource data node.
233
234 @param [in] QWordRdNode Pointer a QWord resource data
235 node.
236 @param [in] BaseAddress Base address.
237 @param [in] BaseAddressLength Base address length.
238
239 @retval EFI_SUCCESS The function completed successfully.
240 @retval EFI_INVALID_PARAMETER Invalid parameter.
241 @retval EFI_OUT_OF_RESOURCES Out of resources.
242 **/
243 EFI_STATUS
244 EFIAPI
245 AmlUpdateRdQWord (
246 IN AML_DATA_NODE_HANDLE QWordRdNode,
247 IN UINT64 BaseAddress,
248 IN UINT64 BaseAddressLength
249 )
250 {
251 EFI_STATUS Status;
252 EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR * RdQWord;
253
254 UINT8 * QueryBuffer;
255 UINT32 QueryBufferSize;
256
257 if ((QWordRdNode == NULL) ||
258 (AmlGetNodeType ((AML_NODE_HANDLE)QWordRdNode) != EAmlNodeData) ||
259 (!AmlNodeHasDataType (QWordRdNode, EAmlNodeDataTypeResourceData)) ||
260 (!AmlNodeHasRdDataType (
261 QWordRdNode,
262 AML_RD_BUILD_LARGE_DESC_ID (
263 ACPI_LARGE_QWORD_ADDRESS_SPACE_DESCRIPTOR_NAME)))) {
264 ASSERT (0);
265 return EFI_INVALID_PARAMETER;
266 }
267
268 // Get the size of the QWordRdNode's buffer.
269 Status = AmlGetDataNodeBuffer (
270 QWordRdNode,
271 NULL,
272 &QueryBufferSize
273 );
274 if (EFI_ERROR (Status)) {
275 ASSERT (0);
276 return Status;
277 }
278
279 // Allocate a buffer to fetch the data.
280 QueryBuffer = AllocatePool (QueryBufferSize);
281 if (QueryBuffer == NULL) {
282 ASSERT (0);
283 return EFI_OUT_OF_RESOURCES;
284 }
285
286 // Get the data.
287 Status = AmlGetDataNodeBuffer (
288 QWordRdNode,
289 QueryBuffer,
290 &QueryBufferSize
291 );
292 if (EFI_ERROR (Status)) {
293 ASSERT (0);
294 goto error_handler;
295 }
296
297 RdQWord = (EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR*)QueryBuffer;
298
299 // Update the Base Address and Length.
300 RdQWord->AddrRangeMin = BaseAddress;
301 RdQWord->AddrRangeMax = BaseAddress + BaseAddressLength - 1;
302 RdQWord->AddrLen = BaseAddressLength;
303
304 // Update Base Address Resource Data node.
305 Status = AmlUpdateDataNode (
306 QWordRdNode,
307 EAmlNodeDataTypeResourceData,
308 QueryBuffer,
309 QueryBufferSize
310 );
311 if (EFI_ERROR (Status)) {
312 ASSERT (0);
313 }
314
315 error_handler:
316 if (QueryBuffer != NULL) {
317 FreePool (QueryBuffer);
318 }
319 return Status;
320 }