Skip to content

Commit

Permalink
Introduce notification callbacks for the Policy Service (#433)
Browse files Browse the repository at this point in the history
## Description

Introduces a mechanism by which consumers can register for notifications
on a given policy. Unlike the protocol/PPI notification system, this
callback allows for a priority, pre-finalized notifications, removal
notifications, etc. The existing protocols/PPI installs will now only be
done on a finalization of a policy.

>
> NOTE: All consumers depending on the existing notification system may
need to switch to the callbacks if they rely on a non-finalized policy.
 >

Feature Request: #411 

- [x] Impacts functionality?
- [ ] Impacts security?
- [x] Breaking change?
- [x] Includes tests?
- [x] Includes documentation?

## How This Was Tested

Tested with provided unit tests and leveraged tests of
mu_feature_config.

## Integration Instructions

N/A
  • Loading branch information
cfernald authored and kenlautner committed Dec 18, 2023
1 parent c0dad8e commit fbb9af5
Show file tree
Hide file tree
Showing 22 changed files with 2,125 additions and 37 deletions.
43 changes: 43 additions & 0 deletions PolicyServicePkg/Include/Library/PolicyLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#ifndef _POLICY_LIB_H_
#define _POLICY_LIB_H_

#include <PolicyInterface.h>

#define VERIFIED_POLICY_LIB_VERSION 1

#pragma pack(1)
Expand Down Expand Up @@ -84,6 +86,47 @@ RemovePolicy (
IN CONST EFI_GUID *PolicyGuid
);

/**
Registers a callback for a policy event notification. The provided routine
will be invoked when one of multiple of the provided event types for the specified
guid occurs.
@param[in] PolicyGuid The GUID of the policy the being watched.
@param[in] EventTypes The events to notify the callback for.
@param[in] Priority The priority of the callback where the lower values
will be called first.
@param[in] CallbackRoutine The function pointer of the callback to be invoked.
@param[out] Handle Returns the handle to this callback entry.
@retval EFI_SUCCESS The callback notification as successfully registered.
@retval EFI_INVALID_PARAMETER EventTypes was 0 or Callback routine is invalid.
@retval Other The callback registration failed.
**/
EFI_STATUS
EFIAPI
RegisterPolicyNotify (
IN CONST EFI_GUID *PolicyGuid,
IN CONST UINT32 EventTypes,
IN CONST UINT32 Priority,
IN POLICY_HANDLER_CALLBACK CallbackRoutine,
OUT VOID **Handle
);

/**
Removes a registered notification callback.
@param[in] Handle The handle for the registered callback.
@retval EFI_SUCCESS The callback notification as successfully removed.
@retval EFI_INVALID_PARAMETER The provided handle is invalid.
@retval EFI_NOT_FOUND The provided handle could not be found.
**/
EFI_STATUS
EFIAPI
UnregisterPolicyNotify (
IN VOID *Handle
);

/**
Retrieves a verified policy of the given type from the policy store.
Expand Down
81 changes: 78 additions & 3 deletions PolicyServicePkg/Include/PolicyInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,85 @@ EFI_STATUS
IN CONST EFI_GUID *PolicyGuid
);

/**
Callback for a policy notification event.
@param[in] PolicyGuid The GUID of the policy being notified.
@param[in] EventTypes The events that occurred for the notification.
@param[in] CallbackHandle The handle for the callback being invoked.
**/
typedef
VOID
(EFIAPI *POLICY_HANDLER_CALLBACK)(
IN CONST EFI_GUID *PolicyGuid,
IN UINT32 EventTypes,
IN VOID *CallbackHandle
);

/**
Flags used for policy callbacks.
POLICY_NOTIFY_SET - The policy content and/or attributes were set.
POLICY_NOTIFY_FINALIZED - The policy was set with the POLICY_ATTRIBUTE_FINALIZED set.
POLICY_NOTIFY_REMOVED - The policy was removed.
**/
#define POLICY_NOTIFY_SET (BIT0)
#define POLICY_NOTIFY_FINALIZED (BIT1)
#define POLICY_NOTIFY_REMOVED (BIT2)
#define POLICY_NOTIFY_ALL (POLICY_NOTIFY_SET | \
POLICY_NOTIFY_FINALIZED | \
POLICY_NOTIFY_REMOVED)

#define POLICY_NOTIFY_DEFAULT_PRIORITY (512)

/**
Registers a callback for a policy event notification. The provided routine
will be invoked when one of multiple of the provided event types for the specified
guid occurs.
@param[in] PolicyGuid The GUID of the policy the being watched.
@param[in] EventTypes The events to notify the callback for.
@param[in] Priority The priority of the callback where the lower values
will be called first.
@param[in] CallbackRoutine The function pointer of the callback to be invoked.
@param[out] Handle Returns the handle to this callback entry.
@retval EFI_SUCCESS The callback notification as successfully registered.
@retval EFI_INVALID_PARAMETER EventTypes was 0 or Callback routine is invalid.
@retval Other The callback registration failed.
**/
typedef
EFI_STATUS
(EFIAPI *POLICY_REGISTER_CALLBACK)(
IN CONST EFI_GUID *PolicyGuid,
IN CONST UINT32 EventTypes,
IN CONST UINT32 Priority,
IN POLICY_HANDLER_CALLBACK CallbackRoutine,
OUT VOID **Handle
);

/**
Removes a registered notification callback.
@param[in] Handle The handle for the registered callback.
@retval EFI_SUCCESS The callback notification as successfully removed.
@retval EFI_INVALID_PARAMETER The provided handle is invalid.
@retval EFI_NOT_FOUND The provided handle could not be found.
**/
typedef
EFI_STATUS
(EFIAPI *POLICY_UNREGISTER_CALLBACK)(
IN VOID *Handle
);

typedef struct _POLICY_INTERFACE {
POLICY_SET_POLICY SetPolicy;
POLICY_GET_POLICY GetPolicy;
POLICY_REMOVE_POLICY RemovePolicy;
POLICY_SET_POLICY SetPolicy;
POLICY_GET_POLICY GetPolicy;
POLICY_REMOVE_POLICY RemovePolicy;
POLICY_REGISTER_CALLBACK RegisterNotify;
POLICY_UNREGISTER_CALLBACK UnregisterNotify;
} POLICY_INTERFACE;

#endif
82 changes: 82 additions & 0 deletions PolicyServicePkg/Library/DxePolicyLib/DxePolicy.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@

#include "../PolicyLibCommon.h"

STATIC EFI_EVENT mPolicyExitBootServicesEvent;
STATIC BOOLEAN mPolicyAtRuntime = FALSE;

/**
A private helper function to retrieve the policy service protocol.
@param[out] PolicyInterface Returns with the pointer to the protocol.
@retval EFI_SUCCESS Policy protocol was found.
@retval EFI_NOT_FOUND Policy protocol was not found.
@retval EFI_UNSUPPORTED Policy service was called at runtime.
**/
EFI_STATUS
GetPolicyInterface (
Expand All @@ -32,6 +36,11 @@ GetPolicyInterface (
EFI_STATUS Status;
STATIC POLICY_PROTOCOL *mPolicyProtocol = NULL;

if (mPolicyAtRuntime) {
mPolicyProtocol = NULL;
return EFI_UNSUPPORTED;
}

Status = EFI_SUCCESS;
if (mPolicyProtocol == NULL) {
Status = gBS->LocateProtocol (
Expand All @@ -51,3 +60,76 @@ GetPolicyInterface (

return Status;
}

/**
Set AtRuntime flag as TRUE after ExitBootServices.
@param[in] Event The Event that is being processed.
@param[in] Context The Event Context.
**/
VOID
EFIAPI
RuntimeLibExitBootServicesEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
mPolicyAtRuntime = TRUE;
}

/**
This constructor sets up a callback for ExitBootServices to ensure policy
service is not used at runtime.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS Successfully initialized the policy library.
@retval Other Error returned by a subroutine.
**/
EFI_STATUS
EFIAPI
PolicyLibConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;

Status = gBS->CreateEvent (
EVT_SIGNAL_EXIT_BOOT_SERVICES,
TPL_NOTIFY,
RuntimeLibExitBootServicesEvent,
NULL,
&mPolicyExitBootServicesEvent
);

ASSERT_EFI_ERROR (Status);
return Status;
}

/**
This destructor closes the exit boot services event.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS Successfully initialized the policy library.
@retval Other Error returned by a subroutine.
**/
EFI_STATUS
EFIAPI
PolicyLibDestructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;

Status = gBS->CloseEvent (mPolicyExitBootServicesEvent);
ASSERT_EFI_ERROR (Status);
return Status;
}
4 changes: 3 additions & 1 deletion PolicyServicePkg/Library/DxePolicyLib/DxePolicyLib.inf
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
FILE_GUID = 66BE3195-F6D0-49D5-9C47-D3D7A6F7CC26
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = PolicyLib | DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION
LIBRARY_CLASS = PolicyLib | DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION DXE_RUNTIME_DRIVER
CONSTRUCTOR = PolicyLibConstructor
DESTRUCTOR = PolicyLibDestructor

[Sources]
../PolicyLibCommon.c
Expand Down
38 changes: 38 additions & 0 deletions PolicyServicePkg/Library/PolicyLibCommon.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,44 @@ RemovePolicy (
return Status;
}

EFI_STATUS
EFIAPI
RegisterPolicyNotify (
IN CONST EFI_GUID *PolicyGuid,
IN CONST UINT32 EventTypes,
IN CONST UINT32 Priority,
IN POLICY_HANDLER_CALLBACK CallbackRoutine,
OUT VOID **Handle
)
{
POLICY_INTERFACE *PolicyService;
EFI_STATUS Status;

Status = GetPolicyInterface (&PolicyService);
if (!EFI_ERROR (Status)) {
Status = PolicyService->RegisterNotify (PolicyGuid, EventTypes, Priority, CallbackRoutine, Handle);
}

return Status;
}

EFI_STATUS
EFIAPI
UnregisterPolicyNotify (
IN VOID *Handle
)
{
POLICY_INTERFACE *PolicyService;
EFI_STATUS Status;

Status = GetPolicyInterface (&PolicyService);
if (!EFI_ERROR (Status)) {
Status = PolicyService->UnregisterNotify (Handle);
}

return Status;
}

/**
Retrieves a verified policy of the given type from the policy store.
Expand Down
Loading

0 comments on commit fbb9af5

Please sign in to comment.