3 DXE Dispatcher Dependency Evaluator
5 This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine
6 if a driver can be scheduled for execution. The criteria for
7 schedulability is that the dependency expression is satisfied.
9 Copyright (c) 2006 - 2008, Intel Corporation
10 All rights reserved. This program and the accompanying materials
11 are licensed and made available under the terms and conditions of the BSD License
12 which accompanies this distribution. The full text of the license may be found at
13 http://opensource.org/licenses/bsd-license.php
15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
16 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23 // Global stack used to evaluate dependency expressions
25 BOOLEAN
*mDepexEvaluationStack
= NULL
;
26 BOOLEAN
*mDepexEvaluationStackEnd
= NULL
;
27 BOOLEAN
*mDepexEvaluationStackPointer
= NULL
;
42 Grow size of the Depex stack
46 Stack - Old stack on the way in and new stack on the way out
48 StackSize - New size of the stack
52 EFI_SUCCESS - Stack successfully growed.
54 EFI_OUT_OF_RESOURCES - There is not enough system memory to grow the stack.
63 Size
= DEPEX_STACK_SIZE_INCREMENT
;
64 if (mDepexEvaluationStack
!= NULL
) {
65 Size
= Size
+ (mDepexEvaluationStackEnd
- mDepexEvaluationStack
);
68 NewStack
= CoreAllocateBootServicesPool (Size
* sizeof (BOOLEAN
));
69 if (NewStack
== NULL
) {
70 return EFI_OUT_OF_RESOURCES
;
73 if (mDepexEvaluationStack
!= NULL
) {
75 // Copy to Old Stack to the New Stack
79 mDepexEvaluationStack
,
80 (mDepexEvaluationStackEnd
- mDepexEvaluationStack
) * sizeof (BOOLEAN
)
86 CoreFreePool (mDepexEvaluationStack
);
90 // Make the Stack pointer point to the old data in the new stack
92 mDepexEvaluationStackPointer
= NewStack
+ (mDepexEvaluationStackPointer
- mDepexEvaluationStack
);
93 mDepexEvaluationStack
= NewStack
;
94 mDepexEvaluationStackEnd
= NewStack
+ Size
;
109 Push an element onto the Boolean Stack
113 Value - BOOLEAN to push.
117 EFI_SUCCESS - The value was pushed onto the stack.
119 EFI_OUT_OF_RESOURCES - There is not enough system memory to grow the stack.
126 // Check for a stack overflow condition
128 if (mDepexEvaluationStackPointer
== mDepexEvaluationStackEnd
) {
132 Status
= GrowDepexStack ();
133 if (EFI_ERROR (Status
)) {
139 // Push the item onto the stack
141 *mDepexEvaluationStackPointer
= Value
;
142 mDepexEvaluationStackPointer
++;
157 Pop an element from the Boolean stack.
161 Value - BOOLEAN to pop.
165 EFI_SUCCESS - The value was popped onto the stack.
167 EFI_ACCESS_DENIED - The pop operation underflowed the stack
172 // Check for a stack underflow condition
174 if (mDepexEvaluationStackPointer
== mDepexEvaluationStack
) {
175 return EFI_ACCESS_DENIED
;
179 // Pop the item off the stack
181 mDepexEvaluationStackPointer
--;
182 *Value
= *mDepexEvaluationStackPointer
;
188 CorePreProcessDepex (
189 IN EFI_CORE_DRIVER_ENTRY
*DriverEntry
195 Preprocess dependency expression and update DriverEntry to reflect the
196 state of Before, After, and SOR dependencies. If DriverEntry->Before
197 or DriverEntry->After is set it will never be cleared. If SOR is set
198 it will be cleared by CoreSchedule(), and then the driver can be
203 DriverEntry - DriverEntry element to update
207 EFI_SUCCESS - It always works.
213 Iterator
= DriverEntry
->Depex
;
214 if (*Iterator
== EFI_DEP_SOR
) {
215 DriverEntry
->Unrequested
= TRUE
;
217 DriverEntry
->Dependent
= TRUE
;
220 if (*Iterator
== EFI_DEP_BEFORE
) {
221 DriverEntry
->Before
= TRUE
;
222 } else if (*Iterator
== EFI_DEP_AFTER
) {
223 DriverEntry
->After
= TRUE
;
226 if (DriverEntry
->Before
|| DriverEntry
->After
) {
227 CopyMem (&DriverEntry
->BeforeAfterGuid
, Iterator
+ 1, sizeof (EFI_GUID
));
236 IN EFI_CORE_DRIVER_ENTRY
*DriverEntry
242 This is the POSTFIX version of the dependency evaluator. This code does
243 not need to handle Before or After, as it is not valid to call this
244 routine in this case. The SOR is just ignored and is a nop in the grammer.
246 POSTFIX means all the math is done on top of the stack.
250 DriverEntry - DriverEntry element to update
254 TRUE - If driver is ready to run.
256 FALSE - If driver is not ready to run or some fatal error was found.
267 if (DriverEntry
->After
|| DriverEntry
->Before
) {
269 // If Before or After Depex skip as CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter ()
275 if (DriverEntry
->Depex
== NULL
) {
277 // A NULL Depex means treat the driver like an UEFI 2.0 thing.
279 Status
= CoreAllEfiServicesAvailable ();
280 if (EFI_ERROR (Status
)) {
287 // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
288 // incorrectly formed DEPEX expressions
290 mDepexEvaluationStackPointer
= mDepexEvaluationStack
;
293 Iterator
= DriverEntry
->Depex
;
297 // Check to see if we are attempting to fetch dependency expression instructions
298 // past the end of the dependency expression.
300 if (((UINTN
)Iterator
- (UINTN
)DriverEntry
->Depex
) >= DriverEntry
->DepexSize
) {
305 // Look at the opcode of the dependency expression instruction.
311 // For a well-formed Dependency Expression, the code should never get here.
312 // The BEFORE and AFTER are processed prior to this routine's invocation.
313 // If the code flow arrives at this point, there was a BEFORE or AFTER
314 // that were not the first opcodes.
319 // These opcodes can only appear once as the first opcode. If it is found
320 // at any other location, then the dependency expression evaluates to FALSE
322 if (Iterator
!= DriverEntry
->Depex
) {
326 // Otherwise, it is the first opcode and should be treated as a NOP.
332 // Push operator is followed by a GUID. Test to see if the GUID protocol
333 // is installed and push the boolean result on the stack.
335 CopyMem (&DriverGuid
, Iterator
+ 1, sizeof (EFI_GUID
));
337 Status
= CoreLocateProtocol (&DriverGuid
, NULL
, &Interface
);
339 if (EFI_ERROR (Status
)) {
340 Status
= PushBool (FALSE
);
342 *Iterator
= EFI_DEP_REPLACE_TRUE
;
343 Status
= PushBool (TRUE
);
345 if (EFI_ERROR (Status
)) {
349 Iterator
+= sizeof (EFI_GUID
);
353 Status
= PopBool (&Operator
);
354 if (EFI_ERROR (Status
)) {
358 Status
= PopBool (&Operator2
);
359 if (EFI_ERROR (Status
)) {
363 Status
= PushBool ((BOOLEAN
)(Operator
&& Operator2
));
364 if (EFI_ERROR (Status
)) {
370 Status
= PopBool (&Operator
);
371 if (EFI_ERROR (Status
)) {
375 Status
= PopBool (&Operator2
);
376 if (EFI_ERROR (Status
)) {
380 Status
= PushBool ((BOOLEAN
)(Operator
|| Operator2
));
381 if (EFI_ERROR (Status
)) {
387 Status
= PopBool (&Operator
);
388 if (EFI_ERROR (Status
)) {
392 Status
= PushBool ((BOOLEAN
)(!Operator
));
393 if (EFI_ERROR (Status
)) {
399 Status
= PushBool (TRUE
);
400 if (EFI_ERROR (Status
)) {
406 Status
= PushBool (FALSE
);
407 if (EFI_ERROR (Status
)) {
413 Status
= PopBool (&Operator
);
414 if (EFI_ERROR (Status
)) {
419 case EFI_DEP_REPLACE_TRUE
:
420 Status
= PushBool (TRUE
);
421 if (EFI_ERROR (Status
)) {
425 Iterator
+= sizeof (EFI_GUID
);
433 // Skip over the Dependency Op Code we just processed in the switch.
434 // The math is done out of order, but it should not matter. That is
435 // we may add in the sizeof (EFI_GUID) before we account for the OP Code.
436 // This is not an issue, since we just need the correct end result. You
437 // need to be careful using Iterator in the loop as it's intermediate value