TianoCore EDK2 master
Loading...
Searching...
No Matches
Dpc.c
Go to the documentation of this file.
1
15#include "Dpc.h"
16
17//
18// Handle for the EFI_DPC_PROTOCOL instance
19//
20EFI_HANDLE mDpcHandle = NULL;
21
22//
23// The EFI_DPC_PROTOCOL instances that is installed onto mDpcHandle
24//
25EFI_DPC_PROTOCOL mDpc = {
28};
29
30//
31// Global variables used to measure the DPC Queue Depths
32//
33UINTN mDpcQueueDepth = 0;
34UINTN mMaxDpcQueueDepth = 0;
35
36//
37// Free list of DPC entries. As DPCs are queued, entries are removed from this
38// free list. As DPC entries are dispatched, DPC entries are added to the free list.
39// If the free list is empty and a DPC is queued, the free list is grown by allocating
40// an additional set of DPC entries.
41//
42LIST_ENTRY mDpcEntryFreeList = INITIALIZE_LIST_HEAD_VARIABLE (mDpcEntryFreeList);
43
44//
45// An array of DPC queues. A DPC queue is allocated for every level EFI_TPL value.
46// As DPCs are queued, they are added to the end of the linked list.
47// As DPCs are dispatched, they are removed from the beginning of the linked list.
48//
49LIST_ENTRY mDpcQueue[TPL_HIGH_LEVEL + 1];
50
68EFIAPI
70 IN EFI_DPC_PROTOCOL *This,
71 IN EFI_TPL DpcTpl,
72 IN EFI_DPC_PROCEDURE DpcProcedure,
73 IN VOID *DpcContext OPTIONAL
74 )
75{
76 EFI_STATUS ReturnStatus;
77 EFI_TPL OriginalTpl;
78 DPC_ENTRY *DpcEntry;
79 UINTN Index;
80
81 //
82 // Make sure DpcTpl is valid
83 //
84 if ((DpcTpl < TPL_APPLICATION) || (DpcTpl > TPL_HIGH_LEVEL)) {
85 return EFI_INVALID_PARAMETER;
86 }
87
88 //
89 // Make sure DpcProcedure is valid
90 //
91 if (DpcProcedure == NULL) {
92 return EFI_INVALID_PARAMETER;
93 }
94
95 //
96 // Assume this function will succeed
97 //
98 ReturnStatus = EFI_SUCCESS;
99
100 //
101 // Raise the TPL level to TPL_HIGH_LEVEL for DPC list operation and save the
102 // current TPL value so it can be restored when this function returns.
103 //
104 OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
105
106 //
107 // Check to see if there are any entries in the DPC free list
108 //
109 if (IsListEmpty (&mDpcEntryFreeList)) {
110 //
111 // If the current TPL is greater than TPL_NOTIFY, then memory allocations
112 // can not be performed, so the free list can not be expanded. In this case
113 // return EFI_OUT_OF_RESOURCES.
114 //
115 if (OriginalTpl > TPL_NOTIFY) {
116 ReturnStatus = EFI_OUT_OF_RESOURCES;
117 goto Done;
118 }
119
120 //
121 // Add 64 DPC entries to the free list
122 //
123 for (Index = 0; Index < 64; Index++) {
124 //
125 // Lower the TPL level to perform a memory allocation
126 //
127 gBS->RestoreTPL (OriginalTpl);
128
129 //
130 // Allocate a new DPC entry
131 //
132 DpcEntry = AllocatePool (sizeof (DPC_ENTRY));
133
134 //
135 // Raise the TPL level back to TPL_HIGH_LEVEL for DPC list operations
136 //
137 gBS->RaiseTPL (TPL_HIGH_LEVEL);
138
139 //
140 // If the allocation of a DPC entry fails, and the free list is empty,
141 // then return EFI_OUT_OF_RESOURCES.
142 //
143 if (DpcEntry == NULL) {
144 if (IsListEmpty (&mDpcEntryFreeList)) {
145 ReturnStatus = EFI_OUT_OF_RESOURCES;
146 goto Done;
147 }
148 }
149
150 //
151 // Add the newly allocated DPC entry to the DPC free list
152 //
153 InsertTailList (&mDpcEntryFreeList, &DpcEntry->ListEntry);
154 }
155 }
156
157 //
158 // Retrieve the first node from the free list of DPCs
159 //
160 DpcEntry = (DPC_ENTRY *)(GetFirstNode (&mDpcEntryFreeList));
161
162 //
163 // Remove the first node from the free list of DPCs
164 //
165 RemoveEntryList (&DpcEntry->ListEntry);
166
167 //
168 // Fill in the DPC entry with the DpcProcedure and DpcContext
169 //
170 DpcEntry->DpcProcedure = DpcProcedure;
171 DpcEntry->DpcContext = DpcContext;
172
173 //
174 // Add the DPC entry to the end of the list for the specified DplTpl.
175 //
176 InsertTailList (&mDpcQueue[DpcTpl], &DpcEntry->ListEntry);
177
178 //
179 // Increment the measured DPC queue depth across all TPLs
180 //
181 mDpcQueueDepth++;
182
183 //
184 // Measure the maximum DPC queue depth across all TPLs
185 //
186 if (mDpcQueueDepth > mMaxDpcQueueDepth) {
187 mMaxDpcQueueDepth = mDpcQueueDepth;
188 }
189
190Done:
191 //
192 // Restore the original TPL level when this function was called
193 //
194 gBS->RestoreTPL (OriginalTpl);
195
196 return ReturnStatus;
197}
198
212EFIAPI
214 IN EFI_DPC_PROTOCOL *This
215 )
216{
217 EFI_STATUS ReturnStatus;
218 EFI_TPL OriginalTpl;
219 EFI_TPL Tpl;
220 DPC_ENTRY *DpcEntry;
221
222 //
223 // Assume that no DPCs will be invoked
224 //
225 ReturnStatus = EFI_NOT_FOUND;
226
227 //
228 // Raise the TPL level to TPL_HIGH_LEVEL for DPC list operation and save the
229 // current TPL value so it can be restored when this function returns.
230 //
231 OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
232
233 //
234 // Check to see if there are 1 or more DPCs currently queued
235 //
236 if (mDpcQueueDepth > 0) {
237 //
238 // Loop from TPL_HIGH_LEVEL down to the current TPL value
239 //
240 for (Tpl = TPL_HIGH_LEVEL; Tpl >= OriginalTpl; Tpl--) {
241 //
242 // Check to see if the DPC queue is empty
243 //
244 while (!IsListEmpty (&mDpcQueue[Tpl])) {
245 //
246 // Retrieve the first DPC entry from the DPC queue specified by Tpl
247 //
248 DpcEntry = (DPC_ENTRY *)(GetFirstNode (&mDpcQueue[Tpl]));
249
250 //
251 // Remove the first DPC entry from the DPC queue specified by Tpl
252 //
253 RemoveEntryList (&DpcEntry->ListEntry);
254
255 //
256 // Decrement the measured DPC Queue Depth across all TPLs
257 //
258 mDpcQueueDepth--;
259
260 //
261 // Lower the TPL to TPL value of the current DPC queue
262 //
263 gBS->RestoreTPL (Tpl);
264
265 //
266 // Invoke the DPC passing in its context
267 //
268 (DpcEntry->DpcProcedure)(DpcEntry->DpcContext);
269
270 //
271 // At least one DPC has been invoked, so set the return status to EFI_SUCCESS
272 //
273 ReturnStatus = EFI_SUCCESS;
274
275 //
276 // Raise the TPL level back to TPL_HIGH_LEVEL for DPC list operations
277 //
278 gBS->RaiseTPL (TPL_HIGH_LEVEL);
279
280 //
281 // Add the invoked DPC entry to the DPC free list
282 //
283 InsertTailList (&mDpcEntryFreeList, &DpcEntry->ListEntry);
284 }
285 }
286 }
287
288 //
289 // Restore the original TPL level when this function was called
290 //
291 gBS->RestoreTPL (OriginalTpl);
292
293 return ReturnStatus;
294}
295
308EFIAPI
310 IN EFI_HANDLE ImageHandle,
311 IN EFI_SYSTEM_TABLE *SystemTable
312 )
313{
314 EFI_STATUS Status;
315 UINTN Index;
316
317 //
318 // ASSERT() if the EFI_DPC_PROTOCOL is already present in the handle database
319 //
321
322 //
323 // Initialize the DPC queue for all possible TPL values
324 //
325 for (Index = 0; Index <= TPL_HIGH_LEVEL; Index++) {
326 InitializeListHead (&mDpcQueue[Index]);
327 }
328
329 //
330 // Install the EFI_DPC_PROTOCOL instance onto a new handle
331 //
332 Status = gBS->InstallMultipleProtocolInterfaces (
333 &mDpcHandle,
335 &mDpc,
336 NULL
337 );
338 ASSERT_EFI_ERROR (Status);
339
340 return Status;
341}
UINT64 UINTN
BOOLEAN EFIAPI IsListEmpty(IN CONST LIST_ENTRY *ListHead)
Definition: LinkedList.c:403
LIST_ENTRY *EFIAPI GetFirstNode(IN CONST LIST_ENTRY *List)
Definition: LinkedList.c:298
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
#define INITIALIZE_LIST_HEAD_VARIABLE(ListHead)
Definition: BaseLib.h:2904
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
EFI_STATUS EFIAPI DpcDriverEntryPoint(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: Dpc.c:309
EFI_STATUS EFIAPI DpcDispatchDpc(IN EFI_DPC_PROTOCOL *This)
Definition: Dpc.c:213
EFI_STATUS EFIAPI DpcQueueDpc(IN EFI_DPC_PROTOCOL *This, IN EFI_TPL DpcTpl, IN EFI_DPC_PROCEDURE DpcProcedure, IN VOID *DpcContext OPTIONAL)
Definition: Dpc.c:69
VOID(EFIAPI * EFI_DPC_PROCEDURE)(IN VOID *DpcContext)
Definition: Dpc.h:35
EFI_GUID gEfiDpcProtocolGuid
#define NULL
Definition: Base.h:319
#define IN
Definition: Base.h:279
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define ASSERT_PROTOCOL_ALREADY_INSTALLED(Handle, Guid)
Definition: DebugLib.h:535
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
UINTN EFI_TPL
Definition: UefiBaseType.h:41
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
Definition: Dpc.h:30