2 Supports Capsule Dependency Expression.
4 Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "Dependency.h"
13 // Define the initial size of the dependency expression evaluation stack
15 #define DEPEX_STACK_SIZE_INCREMENT 0x1000
18 // Type of stack element
26 // Value of stack element
34 // Stack element used to evaluate dependency expressions
42 // Global variable used to support dependency evaluation
44 UINTN mNumberOfFmpInstance
= 0;
45 EFI_FIRMWARE_IMAGE_DESCRIPTOR
**mFmpImageInfoBuf
= NULL
;
48 // Indicates the status of dependency check, default value is DEPENDENCIES_SATISFIED.
50 UINT8 mDependenciesCheckStatus
= DEPENDENCIES_SATISFIED
;
53 // Global stack used to evaluate dependency expressions
55 DEPEX_ELEMENT
*mDepexEvaluationStack
= NULL
;
56 DEPEX_ELEMENT
*mDepexEvaluationStackEnd
= NULL
;
57 DEPEX_ELEMENT
*mDepexEvaluationStackPointer
= NULL
;
60 Grow size of the Depex stack
62 @retval EFI_SUCCESS Stack successfully growed.
63 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
71 DEPEX_ELEMENT
*NewStack
;
74 Size
= DEPEX_STACK_SIZE_INCREMENT
;
75 if (mDepexEvaluationStack
!= NULL
) {
76 Size
= Size
+ (mDepexEvaluationStackEnd
- mDepexEvaluationStack
);
79 NewStack
= AllocatePool (Size
* sizeof (DEPEX_ELEMENT
));
80 if (NewStack
== NULL
) {
81 return EFI_OUT_OF_RESOURCES
;
84 if (mDepexEvaluationStack
!= NULL
) {
86 // Copy to Old Stack to the New Stack
90 mDepexEvaluationStack
,
91 (mDepexEvaluationStackEnd
- mDepexEvaluationStack
) * sizeof (DEPEX_ELEMENT
)
97 FreePool (mDepexEvaluationStack
);
101 // Make the Stack pointer point to the old data in the new stack
103 mDepexEvaluationStackPointer
= NewStack
+ (mDepexEvaluationStackPointer
- mDepexEvaluationStack
);
104 mDepexEvaluationStack
= NewStack
;
105 mDepexEvaluationStackEnd
= NewStack
+ Size
;
111 Push an element onto the Stack.
113 @param[in] Value Value to push.
114 @param[in] Type Element Type
116 @retval EFI_SUCCESS The value was pushed onto the stack.
117 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.
118 @retval EFI_INVALID_PARAMETER Wrong stack element type.
128 DEPEX_ELEMENT Element
;
133 if (Type
!= BooleanType
&& Type
!= VersionType
) {
134 return EFI_INVALID_PARAMETER
;
138 // Check for a stack overflow condition
140 if (mDepexEvaluationStackPointer
== mDepexEvaluationStackEnd
) {
144 Status
= GrowDepexStack ();
145 if (EFI_ERROR (Status
)) {
150 Element
.Value
.Version
= Value
;
154 // Push the item onto the stack
156 *mDepexEvaluationStackPointer
= Element
;
157 mDepexEvaluationStackPointer
++;
164 Pop an element from the stack.
166 @param[out] Element Element to pop.
167 @param[in] Type Type of element.
169 @retval EFI_SUCCESS The value was popped onto the stack.
170 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack.
171 @retval EFI_INVALID_PARAMETER Type is mismatched.
176 OUT DEPEX_ELEMENT
*Element
,
181 // Check for a stack underflow condition
183 if (mDepexEvaluationStackPointer
== mDepexEvaluationStack
) {
184 return EFI_ACCESS_DENIED
;
188 // Pop the item off the stack
190 mDepexEvaluationStackPointer
--;
191 *Element
= *mDepexEvaluationStackPointer
;
192 if ((*Element
).Type
!= Type
) {
193 return EFI_INVALID_PARAMETER
;
199 Evaluate the dependencies.
201 @param[in] Dependencies Dependency expressions.
202 @param[in] DependenciesSize Size of Dependency expressions.
204 @retval TRUE Dependency expressions evaluate to TRUE.
205 @retval FALSE Dependency expressions evaluate to FALSE.
209 EvaluateDependencies (
210 IN CONST EFI_FIRMWARE_IMAGE_DEP
* Dependencies
,
211 IN CONST UINTN DependenciesSize
217 DEPEX_ELEMENT Element1
;
218 DEPEX_ELEMENT Element2
;
222 if (Dependencies
== NULL
|| DependenciesSize
== 0) {
227 // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by
228 // incorrectly formed DEPEX expressions
230 mDepexEvaluationStackPointer
= mDepexEvaluationStack
;
232 Iterator
= (UINT8
*) Dependencies
->Dependencies
;
233 while (Iterator
< (UINT8
*) Dependencies
->Dependencies
+ DependenciesSize
) {
236 case EFI_FMP_DEP_PUSH_GUID
:
237 if (Iterator
+ sizeof (EFI_GUID
) >= (UINT8
*) Dependencies
->Dependencies
+ DependenciesSize
) {
238 Status
= EFI_INVALID_PARAMETER
;
242 CopyGuid (&ImageTypeId
, (EFI_GUID
*) (Iterator
+ 1));
243 Iterator
= Iterator
+ sizeof (EFI_GUID
);
245 for (Index
= 0; Index
< mNumberOfFmpInstance
; Index
++){
246 if (mFmpImageInfoBuf
[Index
] == NULL
) {
249 if(CompareGuid (&mFmpImageInfoBuf
[Index
]->ImageTypeId
, &ImageTypeId
)){
250 Status
= Push (mFmpImageInfoBuf
[Index
]->Version
, VersionType
);
251 if (EFI_ERROR (Status
)) {
257 if (Index
== mNumberOfFmpInstance
) {
258 Status
= EFI_NOT_FOUND
;
262 case EFI_FMP_DEP_PUSH_VERSION
:
263 if (Iterator
+ sizeof (UINT32
) >= (UINT8
*) Dependencies
->Dependencies
+ DependenciesSize
) {
264 Status
= EFI_INVALID_PARAMETER
;
268 Version
= *(UINT32
*) (Iterator
+ 1);
269 Status
= Push (Version
, VersionType
);
270 if (EFI_ERROR (Status
)) {
273 Iterator
= Iterator
+ sizeof (UINT32
);
275 case EFI_FMP_DEP_VERSION_STR
:
276 Iterator
+= AsciiStrnLenS ((CHAR8
*) Iterator
, DependenciesSize
- (Iterator
- Dependencies
->Dependencies
));
278 case EFI_FMP_DEP_AND
:
279 Status
= Pop (&Element1
, BooleanType
);
280 if (EFI_ERROR (Status
)) {
283 Status
= Pop (&Element2
, BooleanType
);
284 if (EFI_ERROR (Status
)) {
287 Status
= Push (Element1
.Value
.Boolean
& Element2
.Value
.Boolean
, BooleanType
);
288 if (EFI_ERROR (Status
)) {
293 Status
= Pop (&Element1
, BooleanType
);
294 if (EFI_ERROR (Status
)) {
297 Status
= Pop(&Element2
, BooleanType
);
298 if (EFI_ERROR (Status
)) {
301 Status
= Push (Element1
.Value
.Boolean
| Element2
.Value
.Boolean
, BooleanType
);
302 if (EFI_ERROR (Status
)) {
306 case EFI_FMP_DEP_NOT
:
307 Status
= Pop (&Element1
, BooleanType
);
308 if (EFI_ERROR (Status
)) {
311 Status
= Push (!(Element1
.Value
.Boolean
), BooleanType
);
312 if (EFI_ERROR (Status
)) {
316 case EFI_FMP_DEP_TRUE
:
317 Status
= Push (TRUE
, BooleanType
);
318 if (EFI_ERROR (Status
)) {
322 case EFI_FMP_DEP_FALSE
:
323 Status
= Push (FALSE
, BooleanType
);
324 if (EFI_ERROR (Status
)) {
329 Status
= Pop (&Element1
, VersionType
);
330 if (EFI_ERROR (Status
)) {
333 Status
= Pop (&Element2
, VersionType
);
334 if (EFI_ERROR (Status
)) {
337 Status
= (Element1
.Value
.Version
== Element2
.Value
.Version
) ? Push (TRUE
, BooleanType
) : Push (FALSE
, BooleanType
);
338 if (EFI_ERROR (Status
)) {
343 Status
= Pop (&Element1
, VersionType
);
344 if (EFI_ERROR (Status
)) {
347 Status
= Pop (&Element2
, VersionType
);
348 if (EFI_ERROR (Status
)) {
351 Status
= (Element1
.Value
.Version
> Element2
.Value
.Version
) ? Push (TRUE
, BooleanType
) : Push (FALSE
, BooleanType
);
352 if (EFI_ERROR (Status
)) {
356 case EFI_FMP_DEP_GTE
:
357 Status
= Pop (&Element1
, VersionType
);
358 if (EFI_ERROR (Status
)) {
361 Status
= Pop (&Element2
, VersionType
);
362 if (EFI_ERROR (Status
)) {
365 Status
= (Element1
.Value
.Version
>= Element2
.Value
.Version
) ? Push (TRUE
, BooleanType
) : Push (FALSE
, BooleanType
);
366 if (EFI_ERROR (Status
)) {
371 Status
= Pop (&Element1
, VersionType
);
372 if (EFI_ERROR (Status
)) {
375 Status
= Pop (&Element2
, VersionType
);
376 if (EFI_ERROR (Status
)) {
379 Status
= (Element1
.Value
.Version
< Element2
.Value
.Version
) ? Push (TRUE
, BooleanType
) : Push (FALSE
, BooleanType
);
380 if (EFI_ERROR (Status
)) {
384 case EFI_FMP_DEP_LTE
:
385 Status
= Pop (&Element1
, VersionType
);
386 if (EFI_ERROR (Status
)) {
389 Status
= Pop (&Element2
, VersionType
);
390 if (EFI_ERROR (Status
)) {
393 Status
= (Element1
.Value
.Version
<= Element2
.Value
.Version
) ? Push (TRUE
, BooleanType
) : Push (FALSE
, BooleanType
);
394 if (EFI_ERROR (Status
)) {
398 case EFI_FMP_DEP_END
:
399 Status
= Pop (&Element1
, BooleanType
);
400 if (EFI_ERROR (Status
)) {
403 return Element1
.Value
.Boolean
;
405 Status
= EFI_INVALID_PARAMETER
;
413 DEBUG ((DEBUG_ERROR
, "FmpDxe(%s): EvaluateDependencies() - RESULT = FALSE (Status = %r)\n", mImageIdName
, Status
));
418 Validate the dependency expression and output its size.
420 @param[in] ImageDepex Pointer to the EFI_FIRMWARE_IMAGE_DEP.
421 @param[in] MaxDepexSize Max size of the dependency.
422 @param[out] DepexSize Size of dependency.
424 @retval TRUE The capsule is valid.
425 @retval FALSE The capsule is invalid.
430 IN EFI_FIRMWARE_IMAGE_DEP
*ImageDepex
,
431 IN CONST UINTN MaxDepexSize
,
432 OUT UINT32
*DepexSize
438 Depex
= ImageDepex
->Dependencies
;
439 while (Depex
< ImageDepex
->Dependencies
+ MaxDepexSize
) {
442 case EFI_FMP_DEP_PUSH_GUID
:
443 Depex
+= sizeof (EFI_GUID
) + 1;
445 case EFI_FMP_DEP_PUSH_VERSION
:
446 Depex
+= sizeof (UINT32
) + 1;
448 case EFI_FMP_DEP_VERSION_STR
:
449 Depex
+= AsciiStrnLenS ((CHAR8
*) Depex
, ImageDepex
->Dependencies
+ MaxDepexSize
- Depex
) + 1;
451 case EFI_FMP_DEP_AND
:
453 case EFI_FMP_DEP_NOT
:
454 case EFI_FMP_DEP_TRUE
:
455 case EFI_FMP_DEP_FALSE
:
458 case EFI_FMP_DEP_GTE
:
460 case EFI_FMP_DEP_LTE
:
463 case EFI_FMP_DEP_END
:
465 *DepexSize
= (UINT32
)(Depex
- ImageDepex
->Dependencies
);
477 Get the size of dependencies. Assume the dependencies is validated before
478 calling this function.
480 @param[in] Dependencies Pointer to the EFI_FIRMWARE_IMAGE_DEP.
482 @retval The size of dependencies.
487 IN CONST EFI_FIRMWARE_IMAGE_DEP
*Dependencies
492 if (Dependencies
== NULL
) {
497 while (Dependencies
->Dependencies
[Index
] != EFI_FMP_DEP_END
) {
505 Check dependency for firmware update.
507 @param[in] ImageTypeId Image Type Id.
508 @param[in] Version New version.
509 @param[in] Dependencies The dependencies.
510 @param[in] DependenciesSize Size of the dependencies
511 @param[out] IsSatisfied Indicate the dependencies is satisfied or not.
513 @retval EFI_SUCCESS Dependency Evaluation is successful.
514 @retval Others Dependency Evaluation fails with unexpected error.
518 EvaluateImageDependencies (
519 IN CONST EFI_GUID ImageTypeId
,
520 IN CONST UINT32 Version
,
521 IN CONST EFI_FIRMWARE_IMAGE_DEP
*Dependencies
,
522 IN CONST UINT32 DependenciesSize
,
523 OUT BOOLEAN
*IsSatisfied
527 EFI_HANDLE
*HandleBuffer
;
529 EFI_FIRMWARE_MANAGEMENT_PROTOCOL
*Fmp
;
531 UINT32 FmpImageInfoDescriptorVer
;
532 UINT8 FmpImageInfoCount
;
533 UINTN DescriptorSize
;
534 UINT32 PackageVersion
;
535 CHAR16
*PackageVersionName
;
539 PackageVersionName
= NULL
;
542 // Get ImageDescriptors of all FMP instances, and archive them for depex evaluation.
544 Status
= gBS
->LocateHandleBuffer (
546 &gEfiFirmwareManagementProtocolGuid
,
548 &mNumberOfFmpInstance
,
551 if (EFI_ERROR (Status
)) {
555 mFmpImageInfoBuf
= AllocatePool (sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR
*) * mNumberOfFmpInstance
);
556 if (mFmpImageInfoBuf
== NULL
) {
557 return EFI_OUT_OF_RESOURCES
;
560 for (Index
= 0; Index
< mNumberOfFmpInstance
; Index
++) {
561 Status
= gBS
->HandleProtocol (
563 &gEfiFirmwareManagementProtocolGuid
,
566 if (EFI_ERROR(Status
)) {
571 Status
= Fmp
->GetImageInfo (
581 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
585 mFmpImageInfoBuf
[Index
] = AllocateZeroPool (ImageInfoSize
);
586 if (mFmpImageInfoBuf
[Index
] == NULL
) {
590 Status
= Fmp
->GetImageInfo (
592 &ImageInfoSize
, // ImageInfoSize
593 mFmpImageInfoBuf
[Index
], // ImageInfo
594 &FmpImageInfoDescriptorVer
, // DescriptorVersion
595 &FmpImageInfoCount
, // DescriptorCount
596 &DescriptorSize
, // DescriptorSize
597 &PackageVersion
, // PackageVersion
598 &PackageVersionName
// PackageVersionName
600 if (EFI_ERROR(Status
)) {
601 FreePool (mFmpImageInfoBuf
[Index
]);
602 mFmpImageInfoBuf
[Index
] = NULL
;
606 if (PackageVersionName
!= NULL
) {
607 FreePool (PackageVersionName
);
608 PackageVersionName
= NULL
;
613 // Step 1 - Evaluate firmware image's depex, against the version of other Fmp instances.
615 if (Dependencies
!= NULL
) {
616 *IsSatisfied
= EvaluateDependencies (Dependencies
, DependenciesSize
);
624 // Step 2 - Evaluate the depex of all other Fmp instances, against the new version in
625 // the firmware image.
629 // Update the new version to mFmpImageInfoBuf.
631 for (Index
= 0; Index
< mNumberOfFmpInstance
; Index
++) {
632 if (mFmpImageInfoBuf
[Index
] != NULL
) {
633 if (CompareGuid (&ImageTypeId
, &mFmpImageInfoBuf
[Index
]->ImageTypeId
)) {
634 mFmpImageInfoBuf
[Index
]->Version
= Version
;
641 // Evaluate the Dependencies one by one.
643 for (Index
= 0; Index
< mNumberOfFmpInstance
; Index
++) {
644 if (mFmpImageInfoBuf
[Index
] != NULL
) {
646 // Skip the Fmp instance to be "SetImage".
648 if (CompareGuid (&ImageTypeId
, &mFmpImageInfoBuf
[Index
]->ImageTypeId
)) {
651 if ((mFmpImageInfoBuf
[Index
]->AttributesSupported
& IMAGE_ATTRIBUTE_DEPENDENCY
) &&
652 mFmpImageInfoBuf
[Index
]->Dependencies
!= NULL
) {
654 // Get the size of depex.
655 // Assume that the dependencies in EFI_FIRMWARE_IMAGE_DESCRIPTOR is validated when PopulateDescriptor().
657 DepexSize
= GetDepexSize (mFmpImageInfoBuf
[Index
]->Dependencies
);
659 *IsSatisfied
= EvaluateDependencies (mFmpImageInfoBuf
[Index
]->Dependencies
, DepexSize
);
669 if (mFmpImageInfoBuf
!= NULL
) {
670 for (Index
= 0; Index
< mNumberOfFmpInstance
; Index
++) {
671 if (mFmpImageInfoBuf
[Index
] != NULL
) {
672 FreePool (mFmpImageInfoBuf
[Index
]);
675 FreePool (mFmpImageInfoBuf
);