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