]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Dispatcher/dependency.c
Removed CommonHeader.h from MdePkg & MdeModulePkg
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Dispatcher / dependency.c
CommitLineData
28a00297 1/*++ \r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 dependency.c\r
15\r
16Abstract:\r
17\r
18 DXE Dispatcher Dependency Evaluator\r
19\r
20 This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine\r
21 if a driver can be scheduled for execution. The criteria for\r
22 schedulability is that the dependency expression is satisfied.\r
23\r
24--*/\r
25\r
26#include <DxeMain.h>\r
27\r
28//\r
29// Global stack used to evaluate dependency expressions\r
30//\r
31BOOLEAN *mDepexEvaluationStack = NULL;\r
32BOOLEAN *mDepexEvaluationStackEnd = NULL;\r
33BOOLEAN *mDepexEvaluationStackPointer = NULL;\r
34\r
35//\r
36// Worker functions\r
37//\r
38\r
39STATIC\r
40EFI_STATUS\r
41GrowDepexStack (\r
42 VOID\r
43 )\r
44/*++\r
45\r
46Routine Description:\r
47\r
48 Grow size of the Depex stack\r
49\r
50Arguments:\r
51\r
52 Stack - Old stack on the way in and new stack on the way out\r
53\r
54 StackSize - New size of the stack\r
55\r
56Returns:\r
57\r
58 EFI_SUCCESS - Stack successfully growed.\r
59 \r
60 EFI_OUT_OF_RESOURCES - There is not enough system memory to grow the stack.\r
61 \r
62 \r
63\r
64--*/\r
65{\r
66 BOOLEAN *NewStack;\r
67 UINTN Size;\r
68\r
69 Size = DEPEX_STACK_SIZE_INCREMENT;\r
70 if (mDepexEvaluationStack != NULL) {\r
71 Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);\r
72 }\r
73\r
74 NewStack = CoreAllocateBootServicesPool (Size * sizeof (BOOLEAN));\r
75 if (NewStack == NULL) {\r
76 return EFI_OUT_OF_RESOURCES;\r
77 }\r
78\r
79 if (mDepexEvaluationStack != NULL) {\r
80 //\r
81 // Copy to Old Stack to the New Stack\r
82 //\r
83 CopyMem (\r
84 NewStack, \r
85 mDepexEvaluationStack, \r
86 (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (BOOLEAN)\r
87 );\r
88\r
89 //\r
90 // Free The Old Stack\r
91 //\r
92 CoreFreePool (mDepexEvaluationStack);\r
93 }\r
94\r
95 //\r
96 // Make the Stack pointer point to the old data in the new stack\r
97 //\r
98 mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);\r
99 mDepexEvaluationStack = NewStack;\r
100 mDepexEvaluationStackEnd = NewStack + Size;\r
101\r
102 return EFI_SUCCESS;\r
103}\r
104\r
105\r
106STATIC\r
107EFI_STATUS\r
108PushBool (\r
109 IN BOOLEAN Value\r
110 )\r
111/*++\r
112\r
113Routine Description:\r
114\r
115 Push an element onto the Boolean Stack\r
116\r
117Arguments:\r
118\r
119 Value - BOOLEAN to push.\r
120\r
121Returns:\r
122\r
123 EFI_SUCCESS - The value was pushed onto the stack.\r
124\r
125 EFI_OUT_OF_RESOURCES - There is not enough system memory to grow the stack.\r
126\r
127--*/\r
128{\r
129 EFI_STATUS Status;\r
130\r
131 //\r
132 // Check for a stack overflow condition\r
133 //\r
134 if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {\r
135 //\r
136 // Grow the stack\r
137 //\r
138 Status = GrowDepexStack ();\r
139 if (EFI_ERROR (Status)) {\r
140 return Status;\r
141 }\r
142 }\r
143\r
144 //\r
145 // Push the item onto the stack\r
146 //\r
147 *mDepexEvaluationStackPointer = Value;\r
148 mDepexEvaluationStackPointer++;\r
149\r
150 return EFI_SUCCESS;\r
151}\r
152\r
153\r
154STATIC\r
155EFI_STATUS \r
156PopBool (\r
157 OUT BOOLEAN *Value\r
158 )\r
159/*++\r
160\r
161Routine Description:\r
162\r
163 Pop an element from the Boolean stack.\r
164\r
165Arguments:\r
166\r
167 Value - BOOLEAN to pop.\r
168\r
169Returns:\r
170\r
171 EFI_SUCCESS - The value was popped onto the stack.\r
172\r
173 EFI_ACCESS_DENIED - The pop operation underflowed the stack\r
174\r
175--*/\r
176{\r
177 //\r
178 // Check for a stack underflow condition\r
179 //\r
180 if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {\r
181 return EFI_ACCESS_DENIED;\r
182 }\r
183\r
184 //\r
185 // Pop the item off the stack\r
186 //\r
187 mDepexEvaluationStackPointer--;\r
188 *Value = *mDepexEvaluationStackPointer;\r
189 return EFI_SUCCESS; \r
190}\r
191\r
192\r
193EFI_STATUS\r
194CorePreProcessDepex (\r
195 IN EFI_CORE_DRIVER_ENTRY *DriverEntry \r
196 )\r
197/*++\r
198\r
199Routine Description:\r
200\r
201 Preprocess dependency expression and update DriverEntry to reflect the\r
202 state of Before, After, and SOR dependencies. If DriverEntry->Before\r
203 or DriverEntry->After is set it will never be cleared. If SOR is set\r
204 it will be cleared by CoreSchedule(), and then the driver can be \r
205 dispatched.\r
206\r
207Arguments:\r
208\r
209 DriverEntry - DriverEntry element to update\r
210\r
211Returns:\r
212\r
213 EFI_SUCCESS - It always works.\r
214\r
215--*/\r
216{\r
217 UINT8 *Iterator;\r
218 \r
219 Iterator = DriverEntry->Depex;\r
220 if (*Iterator == EFI_DEP_SOR) {\r
221 DriverEntry->Unrequested = TRUE;\r
222 } else {\r
223 DriverEntry->Dependent = TRUE;\r
224 }\r
225 \r
226 if (*Iterator == EFI_DEP_BEFORE) {\r
227 DriverEntry->Before = TRUE;\r
228 } else if (*Iterator == EFI_DEP_AFTER) {\r
229 DriverEntry->After = TRUE;\r
230 } \r
231\r
232 if (DriverEntry->Before || DriverEntry->After) {\r
233 CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID));\r
234 }\r
235\r
236 return EFI_SUCCESS;\r
237}\r
238\r
239\r
240BOOLEAN\r
241CoreIsSchedulable (\r
242 IN EFI_CORE_DRIVER_ENTRY *DriverEntry \r
243 )\r
244/*++\r
245\r
246Routine Description:\r
247\r
248 This is the POSTFIX version of the dependency evaluator. This code does \r
249 not need to handle Before or After, as it is not valid to call this \r
250 routine in this case. The SOR is just ignored and is a nop in the grammer.\r
251\r
252 POSTFIX means all the math is done on top of the stack.\r
253\r
254Arguments:\r
255\r
256 DriverEntry - DriverEntry element to update\r
257 \r
258Returns:\r
259\r
260 TRUE - If driver is ready to run.\r
261\r
262 FALSE - If driver is not ready to run or some fatal error was found.\r
263\r
264--*/\r
265{\r
266 EFI_STATUS Status;\r
267 UINT8 *Iterator;\r
268 BOOLEAN Operator;\r
269 BOOLEAN Operator2;\r
270 EFI_GUID DriverGuid;\r
271 VOID *Interface;\r
272\r
273 if (DriverEntry->After || DriverEntry->Before) {\r
274 //\r
275 // If Before or After Depex skip as CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter ()\r
276 // processes them.\r
277 //\r
278 return FALSE;\r
279 }\r
280\r
281 if (DriverEntry->Depex == NULL) {\r
282 //\r
283 // A NULL Depex means treat the driver like an EFI 1.0 thing.\r
284 //\r
285 Status = CoreAllEfiServicesAvailable ();\r
286 if (EFI_ERROR (Status)) {\r
287 return FALSE;\r
288 }\r
289 return TRUE;\r
290 }\r
291\r
292 //\r
293 // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by\r
294 // incorrectly formed DEPEX expressions\r
295 //\r
296 mDepexEvaluationStackPointer = mDepexEvaluationStack;\r
297\r
298\r
299 Iterator = DriverEntry->Depex;\r
300 \r
301 while (TRUE) {\r
302 //\r
303 // Check to see if we are attempting to fetch dependency expression instructions\r
304 // past the end of the dependency expression.\r
305 //\r
306 if (((UINTN)Iterator - (UINTN)DriverEntry->Depex) >= DriverEntry->DepexSize) {\r
307 return FALSE;\r
308 }\r
309\r
310 //\r
311 // Look at the opcode of the dependency expression instruction.\r
312 //\r
313 switch (*Iterator) {\r
314 case EFI_DEP_BEFORE:\r
315 case EFI_DEP_AFTER:\r
316 //\r
317 // For a well-formed Dependency Expression, the code should never get here.\r
318 // The BEFORE and AFTER are processed prior to this routine's invocation.\r
319 // If the code flow arrives at this point, there was a BEFORE or AFTER\r
320 // that were not the first opcodes.\r
321 //\r
322 ASSERT (FALSE);\r
323 case EFI_DEP_SOR:\r
324 //\r
325 // These opcodes can only appear once as the first opcode. If it is found \r
326 // at any other location, then the dependency expression evaluates to FALSE\r
327 //\r
328 if (Iterator != DriverEntry->Depex) {\r
329 return FALSE;\r
330 }\r
331 //\r
332 // Otherwise, it is the first opcode and should be treated as a NOP.\r
333 //\r
334 break;\r
335\r
336 case EFI_DEP_PUSH: \r
337 //\r
338 // Push operator is followed by a GUID. Test to see if the GUID protocol\r
339 // is installed and push the boolean result on the stack.\r
340 //\r
341 CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));\r
342\r
343 Status = CoreLocateProtocol (&DriverGuid, NULL, &Interface);\r
344\r
345 if (EFI_ERROR (Status)) {\r
346 Status = PushBool (FALSE);\r
347 } else {\r
348 *Iterator = EFI_DEP_REPLACE_TRUE;\r
349 Status = PushBool (TRUE);\r
350 }\r
351 if (EFI_ERROR (Status)) {\r
352 return FALSE;\r
353 }\r
354\r
355 Iterator += sizeof (EFI_GUID);\r
356 break;\r
357\r
358 case EFI_DEP_AND: \r
359 Status = PopBool (&Operator);\r
360 if (EFI_ERROR (Status)) {\r
361 return FALSE;\r
362 }\r
363\r
364 Status = PopBool (&Operator2);\r
365 if (EFI_ERROR (Status)) {\r
366 return FALSE;\r
367 }\r
368\r
369 Status = PushBool ((BOOLEAN)(Operator && Operator2));\r
370 if (EFI_ERROR (Status)) {\r
371 return FALSE;\r
372 }\r
373 break;\r
374\r
375 case EFI_DEP_OR: \r
376 Status = PopBool (&Operator);\r
377 if (EFI_ERROR (Status)) {\r
378 return FALSE;\r
379 }\r
380\r
381 Status = PopBool (&Operator2);\r
382 if (EFI_ERROR (Status)) {\r
383 return FALSE;\r
384 }\r
385\r
386 Status = PushBool ((BOOLEAN)(Operator || Operator2));\r
387 if (EFI_ERROR (Status)) {\r
388 return FALSE;\r
389 }\r
390 break;\r
391\r
392 case EFI_DEP_NOT: \r
393 Status = PopBool (&Operator);\r
394 if (EFI_ERROR (Status)) {\r
395 return FALSE;\r
396 }\r
397\r
398 Status = PushBool ((BOOLEAN)(!Operator));\r
399 if (EFI_ERROR (Status)) {\r
400 return FALSE;\r
401 }\r
402 break;\r
403\r
404 case EFI_DEP_TRUE: \r
405 Status = PushBool (TRUE);\r
406 if (EFI_ERROR (Status)) {\r
407 return FALSE;\r
408 }\r
409 break;\r
410\r
411 case EFI_DEP_FALSE: \r
412 Status = PushBool (FALSE);\r
413 if (EFI_ERROR (Status)) {\r
414 return FALSE;\r
415 }\r
416 break;\r
417\r
418 case EFI_DEP_END: \r
419 Status = PopBool (&Operator);\r
420 if (EFI_ERROR (Status)) {\r
421 return FALSE;\r
422 }\r
423 return Operator;\r
424\r
425 case EFI_DEP_REPLACE_TRUE:\r
426 Status = PushBool (TRUE);\r
427 if (EFI_ERROR (Status)) {\r
428 return FALSE;\r
429 }\r
430\r
431 Iterator += sizeof (EFI_GUID);\r
432 break;\r
433\r
434 default: \r
435 goto Done;\r
436 }\r
437 \r
438 //\r
439 // Skip over the Dependency Op Code we just processed in the switch.\r
440 // The math is done out of order, but it should not matter. That is\r
441 // we may add in the sizeof (EFI_GUID) before we account for the OP Code.\r
442 // This is not an issue, since we just need the correct end result. You\r
443 // need to be careful using Iterator in the loop as it's intermediate value\r
444 // may be strange.\r
445 //\r
446 Iterator++;\r
447 }\r
448\r
449Done:\r
450 return FALSE;\r
451}\r
452\r