microsoft/mu_feature_ffa

Public

mirrored from https://github.com/microsoft/mu_feature_ffaAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
89ca181ebb27a1bf7b8d4e233fb5945e10880437

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

FfaFeaturePkg/Library/NotificationServiceLib/NotificationServiceLib.c

519lines · modecode

1/** @file
2 Implementation for the Notification Service
3
4 Copyright (c), Microsoft Corporation.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7**/
8
9#include <Uefi.h>
10#include <Library/DebugLib.h>
11#include <Library/BaseMemoryLib.h>
12#include <Library/NotificationServiceLib.h>
13#include <Guid/NotificationServiceFfa.h>
14
15/* Notification Service Defines */
16#define NOTIFICATION_MAX_SERVICES (16)
17#define NOTIFICATION_MAX_IDS (64)
18#define NOTIFICATION_ID_NOT_FOUND (-1)
19
20/* Notification Service Structures */
21typedef struct {
22 UINT32 BitNum; // The OS translation bitmap value
23 UINT32 IdNum; // The logical ID for the service
24 BOOLEAN InUse;
25} NotifBits;
26
27typedef struct {
28 UINT8 ServiceUuid[16];
29 NotifBits ServiceBits[NOTIFICATION_MAX_IDS];
30 BOOLEAN InUse;
31} NotifService;
32
33/* Notification Service Variables */
34STATIC BOOLEAN IdsAcquired = FALSE;
35STATIC UINT16 SourceId = 0;
36STATIC UINT16 DestinationId = 0;
37STATIC UINT64 GlobalBitmask = 0;
38STATIC NotifService NotificationServices[NOTIFICATION_MAX_SERVICES] = { 0 };
39
40/**
41 Checks if the ID passed in matches one stored within the service structure
42
43 @param IdNum The ID number to look for
44 @param Service The service to search for the given ID
45
46 @return The index of the ID if found, otherwise -1 (NOTIFICATION_ID_NOT_FOUND)
47
48**/
49STATIC
50INT8
51IsMatchingId (
52 UINT32 IdNum,
53 NotifService *Service
54 )
55{
56 /* Validate the incoming function parameters */
57 if (Service == NULL) {
58 return NOTIFICATION_ID_NOT_FOUND;
59 }
60
61 for (UINT8 i = 0; i < NOTIFICATION_MAX_IDS; i++) {
62 if (Service->ServiceBits[i].InUse && (Service->ServiceBits[i].IdNum == IdNum)) {
63 return i;
64 }
65 }
66
67 return NOTIFICATION_ID_NOT_FOUND;
68}
69
70/**
71 Validates the incoming message parameters
72
73 @param Destroy Whether or not we are adding or removing bit information
74 @param Request The incoming message containing the bit information to validate
75 @param Service The service we are updating bit information for
76
77 @retval TRUE Parameters are valid
78 @retval FALSE Parameters are invalid
79
80**/
81STATIC
82BOOLEAN
83ValidParameters (
84 BOOLEAN Destroy,
85 DIRECT_MSG_ARGS_EX *Request,
86 NotifService *Service
87 )
88{
89 /* Validate the incoming function parameters */
90 if ((Request == NULL) || (Service == NULL)) {
91 return FALSE;
92 }
93
94 /* Validate the setup and destroy parameters for the service. You must be setting/destroying at
95 * least one bit and you can't set more than the service supports. */
96 UINT8 NumBits = Request->Arg3;
97
98 if ((NumBits <= 0) || (NumBits > NOTIFICATION_MAX_IDS)) {
99 return FALSE;
100 }
101
102 UINTN *Mappings = &Request->Arg4;
103
104 for (UINT8 i = 0; i < NumBits; i++) {
105 /* Validate that a user is not trying to setup an ID that has already been setup previously or
106 * attempting to destroy an ID that doesn't exist. */
107 UINT32 NotificationId = Mappings[i];
108 INT8 IdIndex = IsMatchingId (NotificationId, Service);
109 if (!Destroy && (IdIndex != NOTIFICATION_ID_NOT_FOUND)) {
110 return FALSE;
111 } else if (Destroy && (IdIndex == NOTIFICATION_ID_NOT_FOUND)) {
112 return FALSE;
113 }
114
115 /* Validate that a user is not trying to set a bit that is already in use or destroy a bit
116 * they haven't previously set up. */
117 UINT32 BitmapBitNum = ((UINT64)Mappings[i] >> 32);
118 if (!Destroy && (GlobalBitmask & (1 << BitmapBitNum))) {
119 return FALSE;
120 } else if (Destroy && (Service->ServiceBits[IdIndex].BitNum != BitmapBitNum)) {
121 return FALSE;
122 }
123 }
124
125 return TRUE;
126}
127
128/**
129 Adds or removes service bit information to the local notification services struct array
130
131 @param Destroy Whether or not we are adding or removing bit information
132 @param Request The incoming message containing the bit information
133 @param Service The service we are updating bit information for
134
135 @retval NOTIFICATION_STATUS_SUCCESS Success
136 @retval NOTIFICATION_STATUS_INVALID_PARAMETER Invalid parameter
137
138**/
139STATIC
140NotificationStatus
141UpdateServiceBits (
142 BOOLEAN Destroy,
143 DIRECT_MSG_ARGS_EX *Request,
144 NotifService *Service
145 )
146{
147 /* Validate the incoming function parameters */
148 if ((Request == NULL) || (Service == NULL)) {
149 return NOTIFICATION_STATUS_INVALID_PARAMETER;
150 }
151
152 NotificationStatus ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
153 UINT8 NumBits = Request->Arg3;
154
155 /* Need to go through all of the setup bits and update the structure */
156 UINTN *Mappings = &Request->Arg4;
157
158 for (UINT8 i = 0; i < NumBits; i++) {
159 UINT32 NotificationId = Mappings[i];
160 UINT32 BitmapBitNum = (UINT64)Mappings[i] >> 32;
161
162 if (Destroy) {
163 /* If we can not find the ID to destroy, it is an error */
164 INT8 Index = IsMatchingId (NotificationId, Service);
165 if (Index != NOTIFICATION_ID_NOT_FOUND) {
166 Service->ServiceBits[Index].BitNum = 0;
167 Service->ServiceBits[Index].IdNum = 0;
168 Service->ServiceBits[Index].InUse = FALSE;
169
170 /* Clear the global bitmask bit */
171 GlobalBitmask &= ~(1 << BitmapBitNum);
172 ReturnVal = NOTIFICATION_STATUS_SUCCESS;
173 }
174 } else {
175 /* Need to loop through the bits within the structure and find an empty location, if
176 * unable to, we ran out of room, return an error */
177 UINT8 Index;
178 BOOLEAN EmptyFound = FALSE;
179 for (Index = 0; Index < NOTIFICATION_MAX_IDS; Index++) {
180 if (!Service->ServiceBits[Index].InUse) {
181 EmptyFound = TRUE;
182 break;
183 }
184 }
185
186 /* If we can not find an empty space, it is an error */
187 if (EmptyFound) {
188 Service->ServiceBits[Index].BitNum = BitmapBitNum;
189 Service->ServiceBits[Index].IdNum = NotificationId;
190 Service->ServiceBits[Index].InUse = TRUE;
191
192 /* Set the global bitmask bit */
193 GlobalBitmask |= (1 << BitmapBitNum);
194 ReturnVal = NOTIFICATION_STATUS_SUCCESS;
195 }
196 }
197 }
198
199 return ReturnVal;
200}
201
202/**
203 Handler for Notification Query command
204
205 @param Request The incoming message
206 @param Response The outgoing message
207
208 @retval NOTIFICATION_STATUS_GENERIC_ERROR Unsupported Function
209
210**/
211STATIC
212NotificationStatus
213QueryHandler (
214 DIRECT_MSG_ARGS_EX *Request,
215 DIRECT_MSG_ARGS_EX *Response
216 )
217{
218 /* TODO: Remove when/if we decided to support Query */
219 Response->Arg0 = NOTIFICATION_STATUS_GENERIC_ERROR;
220 DEBUG ((DEBUG_ERROR, "Notification Service Query Unsupported\n"));
221 return NOTIFICATION_STATUS_GENERIC_ERROR;
222
223 NotifService *Service = NULL;
224 UINT8 Uuid[16] = { 0 };
225 NotificationStatus ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
226
227 /* Extract the UUID from the message */
228 NotificationServiceExtractUuid (Request, Uuid);
229
230 /* Attempt to find the UUID within our list */
231 for (UINT8 i = 0; i < NOTIFICATION_MAX_SERVICES; i++) {
232 if (!CompareMem (Uuid, NotificationServices[i].ServiceUuid, sizeof (Uuid))) {
233 Service = &NotificationServices[i];
234 break;
235 }
236 }
237
238 /* Check for a valid UUID */
239 if (Service != NULL) {
240 /* Count the number of IDs that are in use */
241 UINT8 NumIds = 0;
242 for (UINT8 i = 0; i < NOTIFICATION_MAX_IDS; i++) {
243 if (Service->ServiceBits[NumIds].InUse) {
244 NumIds++;
245 }
246 }
247
248 Response->Arg1 = NumIds;
249 ReturnVal = NOTIFICATION_STATUS_SUCCESS;
250 } else {
251 DEBUG ((DEBUG_ERROR, "Invalid Notification Service UUID\n"));
252 }
253
254 Response->Arg0 = ReturnVal;
255 return ReturnVal;
256}
257
258/**
259 Handler for Notification Setup command
260
261 @param Request The incoming message
262 @param Response The outgoing message
263
264 @retval NOTIFICATION_STATUS_SUCCESS Success
265 @retval NOTIFICATION_STATUS_INVALID_PARAMETER Invalid parameter
266
267**/
268STATIC
269NotificationStatus
270SetupHandler (
271 DIRECT_MSG_ARGS_EX *Request,
272 DIRECT_MSG_ARGS_EX *Response
273 )
274{
275 NotifService *Service = NULL;
276 UINT8 Uuid[16] = { 0 };
277 NotificationStatus ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
278
279 /* Extract the UUID from the message */
280 NotificationServiceExtractUuid (Request, Uuid);
281
282 /* If we haven't stored the source and destination IDs, store them */
283 if (!IdsAcquired) {
284 SourceId = Request->SourceId;
285 DestinationId = Request->DestinationId;
286 IdsAcquired = TRUE;
287 }
288
289 /* Attempt to find the UUID within our list */
290 for (UINT8 i = 0; i < NOTIFICATION_MAX_SERVICES; i++) {
291 if (!CompareMem (Uuid, NotificationServices[i].ServiceUuid, sizeof (Uuid))) {
292 Service = &NotificationServices[i];
293 break;
294 }
295 }
296
297 /* The UUID was not found in the list, attempt to find an empty location to add it */
298 if (Service == NULL) {
299 for (UINT8 i = 0; i < NOTIFICATION_MAX_SERVICES; i++) {
300 if (!NotificationServices[i].InUse) {
301 Service = &NotificationServices[i];
302 CopyMem (Service->ServiceUuid, Uuid, sizeof (Uuid));
303 Service->InUse = TRUE;
304 break;
305 }
306 }
307 }
308
309 /* Check for a valid UUID and validate the input parameters */
310 if ((Service != NULL) && (ValidParameters (FALSE, Request, Service))) {
311 ReturnVal = UpdateServiceBits (FALSE, Request, Service);
312 } else if (Service != NULL) {
313 DEBUG ((DEBUG_ERROR, "Invalid Parameters\n"));
314 } else {
315 DEBUG ((DEBUG_ERROR, "Invalid Notification Service UUID\n"));
316 }
317
318 Response->Arg0 = ReturnVal;
319 return ReturnVal;
320}
321
322/**
323 Handler for Notification Destroy command
324
325 @param Request The incoming message
326 @param Response The outgoing message
327
328 @retval NOTIFICATION_STATUS_SUCCESS Success
329 @retval NOTIFICATION_STATUS_INVALID_PARAMETER Invalid parameter
330
331**/
332STATIC
333NotificationStatus
334DestroyHandler (
335 DIRECT_MSG_ARGS_EX *Request,
336 DIRECT_MSG_ARGS_EX *Response
337 )
338{
339 NotifService *Service = NULL;
340 UINT8 Uuid[16] = { 0 };
341 NotificationStatus ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
342
343 /* Extract the UUID from the message */
344 NotificationServiceExtractUuid (Request, Uuid);
345
346 /* Attempt to find the UUID within our list */
347 for (UINT8 i = 0; i < NOTIFICATION_MAX_SERVICES; i++) {
348 if (!CompareMem (Uuid, NotificationServices[i].ServiceUuid, sizeof (Uuid))) {
349 Service = &NotificationServices[i];
350 break;
351 }
352 }
353
354 /* Check for a valid UUID and validate the input parameters */
355 if ((Service != NULL) && (ValidParameters (TRUE, Request, Service))) {
356 ReturnVal = UpdateServiceBits (TRUE, Request, Service);
357 } else if (Service != NULL) {
358 DEBUG ((DEBUG_ERROR, "Invalid Parameters\n"));
359 } else {
360 DEBUG ((DEBUG_ERROR, "Invalid Notification Service UUID\n"));
361 }
362
363 Response->Arg0 = ReturnVal;
364 return ReturnVal;
365}
366
367/**
368 Initializes the Notification service
369
370**/
371VOID
372NotificationServiceInit (
373 VOID
374 )
375{
376 /* Nothing to Init */
377}
378
379/**
380 Deinitializes the Notification service
381
382**/
383VOID
384NotificationServiceDeInit (
385 VOID
386 )
387{
388 /* Nothing to DeInit */
389}
390
391/**
392 Handler for Notification service commands
393
394 @param Request The incoming message
395 @param Response The outgoing message
396
397**/
398VOID
399NotificationServiceHandle (
400 DIRECT_MSG_ARGS_EX *Request,
401 DIRECT_MSG_ARGS_EX *Response
402 )
403{
404 /* Validate the input parameters before attempting to dereference or pass them along */
405 if ((Request == NULL) || (Response == NULL)) {
406 return;
407 }
408
409 UINT64 Opcode = Request->Arg0;
410
411 switch (Opcode) {
412 case NOTIFICATION_OPCODE_QUERY:
413 QueryHandler (Request, Response);
414 break;
415
416 case NOTIFICATION_OPCODE_SETUP:
417 SetupHandler (Request, Response);
418 break;
419
420 case NOTIFICATION_OPCODE_DESTROY:
421 DestroyHandler (Request, Response);
422 break;
423
424 default:
425 Response->Arg0 = NOTIFICATION_STATUS_INVALID_PARAMETER;
426 DEBUG ((DEBUG_ERROR, "Invalid Notification Service Opcode\n"));
427 break;
428 }
429}
430
431/**
432 Calls NotificationSet on the given ID with the given flag
433
434 @param Id The ID to trigger the event on
435 @param ServiceUuid The service containing the ID to trigger
436 @param Flag The NotificationSet flag to use
437
438 @retval NOTIFICATION_STATUS_SUCCESS Success
439 @retval NOTIFICATION_STATUS_INVALID_PARAMETER Invalid parameter
440 @retval NOTIFICATION_STATUS_GENERIC_ERROR NotificationSet failed
441
442**/
443NotificationStatus
444NotificationServiceIdSet (
445 UINT32 Id,
446 UINT8 *ServiceUuid,
447 UINT32 Flag
448 )
449{
450 /* Validate the incoming function parameters */
451 if (ServiceUuid == NULL) {
452 return NOTIFICATION_STATUS_INVALID_PARAMETER;
453 }
454
455 NotifService *Service = NULL;
456 NotificationStatus ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
457
458 /* Attempt to find the UUID within our list */
459 for (UINT8 i = 0; i < NOTIFICATION_MAX_SERVICES; i++) {
460 if (!CompareMem (ServiceUuid, NotificationServices[i].ServiceUuid, sizeof (NotificationServices[i].ServiceUuid))) {
461 Service = &NotificationServices[i];
462 break;
463 }
464 }
465
466 /* UUID was found */
467 if (Service != NULL) {
468 /* Attempt to find the logical ID within the mapped list */
469 for (UINT8 i = 0; i < NOTIFICATION_MAX_IDS; i++) {
470 if (Service->ServiceBits[i].IdNum == Id) {
471 UINT64 Bitmask = (1 << Service->ServiceBits[i].BitNum);
472 EFI_STATUS Status = FfaNotificationSet (SourceId, Flag, Bitmask);
473 if (EFI_ERROR (Status)) {
474 ReturnVal = NOTIFICATION_STATUS_GENERIC_ERROR;
475 } else {
476 ReturnVal = NOTIFICATION_STATUS_SUCCESS;
477 }
478
479 break;
480 }
481 }
482 }
483
484 return ReturnVal;
485}
486
487/**
488 Extracts the UUID from the message arguments
489
490 @param Request The incoming message to extract the UUID from
491 @param Uuid The UUID to populate
492
493**/
494VOID
495NotificationServiceExtractUuid (
496 DIRECT_MSG_ARGS_EX *Request,
497 UINT8 *Uuid
498 )
499{
500 /* Validate the incoming function parameters */
501 if ((Request == NULL) || (Uuid == NULL)) {
502 return;
503 }
504
505 UINT64 UuidLo = Request->Arg1;
506 UINT64 UuidHi = Request->Arg2;
507
508 /* Copy the upper 8 bytes */
509 for (UINT8 i = 0; i < 8; i++) {
510 UINT8 UuidHiByte = (UINT8)(UuidHi >> ((7 - i) * 8));
511 Uuid[i] = UuidHiByte;
512 }
513
514 /* Copy the lower 8 bytes */
515 for (UINT8 i = 8; i < 16; i++) {
516 UINT8 UuidLoByte = (UINT8)(UuidLo >> ((15 - i) * 8));
517 Uuid[i] = UuidLoByte;
518 }
519}
520