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
|
/** @file
AML Resource Data Code Generation.
Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Glossary:
- Rd or RD - Resource Data
- Rds or RDS - Resource Data Small
- Rdl or RDL - Resource Data Large
**/
#include <AmlNodeDefines.h>
#include <CodeGen/AmlResourceDataCodeGen.h>
#include <AmlCoreInterface.h>
#include <AmlDefines.h>
#include <Api/AmlApiHelper.h>
#include <Tree/AmlNode.h>
#include <ResourceData/AmlResourceData.h>
/** If ParentNode is not NULL, append RdNode.
If NewRdNode is not NULL, update its value to RdNode.
@param [in] RdNode Newly created Resource Data node.
@param [in] ParentNode If not NULL, add the generated node
to the end of the variable list of
argument of the ParentNode, but
before the "End Tag" Resource Data.
Must be a BufferOpNode.
@param [out] NewRdNode If not NULL, update the its value to RdNode.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_INVALID_PARAMETER Invalid parameter.
**/
STATIC
EFI_STATUS
EFIAPI
LinkRdNode (
IN AML_DATA_NODE * RdNode,
IN AML_OBJECT_NODE * ParentNode,
IN AML_DATA_NODE ** NewRdNode
)
{
EFI_STATUS Status;
EFI_STATUS Status1;
if (NewRdNode != NULL) {
*NewRdNode = RdNode;
}
// Add RdNode as the last element, but before the EndTag.
if (ParentNode != NULL) {
Status = AmlAppendRdNode (ParentNode, RdNode);
if (EFI_ERROR (Status)) {
ASSERT (0);
Status1 = AmlDeleteTree ((AML_NODE_HEADER*)RdNode);
ASSERT_EFI_ERROR (Status1);
// Return original error.
return Status;
}
}
return EFI_SUCCESS;
}
/** Code generation for the "Interrupt ()" ASL function.
This function creates a Resource Data element corresponding to the
"Interrupt ()" ASL function and stores it in an AML Data Node.
The Resource Data effectively created is an Extended Interrupt Resource
Data. See ACPI 6.3 specification, s6.4.3.6 "Extended Interrupt Descriptor"
for more information about Extended Interrupt Resource Data.
This function allocates memory to create a data node. It is the caller's
responsibility to either:
- attach this node to an AML tree;
- delete this node.
@param [in] ResourceConsumer The device consumes the specified interrupt
or produces it for use by a child device.
@param [in] EdgeTriggered The interrupt is edge triggered or
level triggered.
@param [in] ActiveLow The interrupt is active-high or active-low.
@param [in] Shared The interrupt can be shared with other
devices or not (Exclusive).
@param [in] IrqList Interrupt list. Must be non-NULL.
@param [in] IrqCount Interrupt count. Must be non-zero.
@param [in] ParentNode If not NULL, add the generated node
to the end of the variable list of
argument of the ParentNode, but
before the "End Tag" Resource Data.
Must be a BufferOpNode.
@param [out] NewRdNode If success, contains the generated node.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlCodeGenInterrupt (
IN BOOLEAN ResourceConsumer,
IN BOOLEAN EdgeTriggered,
IN BOOLEAN ActiveLow,
IN BOOLEAN Shared,
IN UINT32 * IrqList,
IN UINT8 IrqCount,
IN AML_OBJECT_NODE * ParentNode, OPTIONAL
OUT AML_DATA_NODE ** NewRdNode OPTIONAL
)
{
EFI_STATUS Status;
AML_DATA_NODE * RdNode;
EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR RdInterrupt;
UINT32 * FirstInterrupt;
if ((IrqList == NULL) ||
(IrqCount == 0) ||
((ParentNode == NULL) && (NewRdNode == NULL))) {
ASSERT (0);
return EFI_INVALID_PARAMETER;
}
RdInterrupt.Header.Header.Bits.Name =
ACPI_LARGE_EXTENDED_IRQ_DESCRIPTOR_NAME;
RdInterrupt.Header.Header.Bits.Type = ACPI_LARGE_ITEM_FLAG;
RdInterrupt.Header.Length = sizeof (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR) -
sizeof (ACPI_LARGE_RESOURCE_HEADER);
RdInterrupt.InterruptVectorFlags = (ResourceConsumer ? BIT0 : 0) |
(EdgeTriggered ? BIT1 : 0) |
(ActiveLow ? BIT2 : 0) |
(Shared ? BIT3 : 0);
RdInterrupt.InterruptTableLength = IrqCount;
// Get the address of the first interrupt field.
FirstInterrupt = RdInterrupt.InterruptNumber;
// Copy the list of interrupts.
CopyMem (FirstInterrupt, IrqList, (sizeof (UINT32) * IrqCount));
Status = AmlCreateDataNode (
EAmlNodeDataTypeResourceData,
(UINT8*)&RdInterrupt,
sizeof (EFI_ACPI_EXTENDED_INTERRUPT_DESCRIPTOR),
&RdNode
);
if (EFI_ERROR (Status)) {
ASSERT (0);
return Status;
}
return LinkRdNode (RdNode, ParentNode, NewRdNode);
}
/** Add an Interrupt Resource Data node.
This function creates a Resource Data element corresponding to the
"Interrupt ()" ASL function, stores it in an AML Data Node.
It then adds it after the input CurrRdNode in the list of resource data
element.
The Resource Data effectively created is an Extended Interrupt Resource
Data. See ACPI 6.3 specification, s6.4.3.6 "Extended Interrupt Descriptor"
for more information about Extended Interrupt Resource Data.
The Extended Interrupt contains one single interrupt.
This function allocates memory to create a data node. It is the caller's
responsibility to either:
- attach this node to an AML tree;
- delete this node.
Note: The _CRS node must be defined using the ASL Name () function.
e.g. Name (_CRS, ResourceTemplate () {
...
}
@param [in] NameOpCrsNode NameOp object node defining a "_CRS" object.
Must have an OpCode=AML_NAME_OP, SubOpCode=0.
NameOp object nodes are defined in ASL
using the "Name ()" function.
@param [in] ResourceConsumer The device consumes the specified interrupt
or produces it for use by a child device.
@param [in] EdgeTriggered The interrupt is edge triggered or
level triggered.
@param [in] ActiveLow The interrupt is active-high or active-low.
@param [in] Shared The interrupt can be shared with other
devices or not (Exclusive).
@param [in] IrqList Interrupt list. Must be non-NULL.
@param [in] IrqCount Interrupt count. Must be non-zero.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
**/
EFI_STATUS
EFIAPI
AmlCodeGenCrsAddRdInterrupt (
IN AML_OBJECT_NODE_HANDLE NameOpCrsNode,
IN BOOLEAN ResourceConsumer,
IN BOOLEAN EdgeTriggered,
IN BOOLEAN ActiveLow,
IN BOOLEAN Shared,
IN UINT32 * IrqList,
IN UINT8 IrqCount
)
{
EFI_STATUS Status;
AML_OBJECT_NODE_HANDLE BufferOpNode;
if ((IrqList == NULL) ||
(IrqCount == 0) ||
(!AmlNodeHasOpCode (NameOpCrsNode, AML_NAME_OP, 0)) ||
(!AmlNameOpCompareName (NameOpCrsNode, "_CRS"))) {
ASSERT (0);
return EFI_INVALID_PARAMETER;
}
// Get the _CRS value which is represented as a BufferOp object node
// which is the 2nd fixed argument (i.e. index 1).
BufferOpNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
NameOpCrsNode,
EAmlParseIndexTerm1
);
if ((BufferOpNode == NULL) ||
(AmlGetNodeType ((AML_NODE_HANDLE)BufferOpNode) != EAmlNodeObject) ||
(!AmlNodeHasOpCode (BufferOpNode, AML_BUFFER_OP, 0))) {
ASSERT (0);
return EFI_INVALID_PARAMETER;
}
// Generate the Extended Interrupt Resource Data node,
// and attach it as the last variable argument of the BufferOpNode.
Status = AmlCodeGenInterrupt (
ResourceConsumer,
EdgeTriggered,
ActiveLow,
Shared,
IrqList,
IrqCount,
BufferOpNode,
NULL
);
if (EFI_ERROR (Status)) {
ASSERT (0);
}
return Status;
}
|