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