microsoft/mu_feature_ffa

Public

mirrored fromhttps://github.com/microsoft/mu_feature_ffaAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
818f98457c414ab23fe870089c633ad464a8216d

Branches

Tags

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

Clone

HTTPS

Download ZIP

FfaFeaturePkg/Library/NotificationServiceLib/NotificationServiceLib.c

536lines · 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_MAPPINGS (64)
18#define NOTIFICATION_NOT_FOUND (-1)
19
20#define MESSAGE_INFO_DIR_RESP (0x100)
21#define MESSAGE_INFO_ID_MASK (0x03)
22
23#define RETURN_STATUS_MASK (0xFF)
24
25#define MAPPING_MIN (0x01)
26#define MAPPING_MAX (0x07)
27
28#define PER_VCPU_BIT_POS (0)
29
30/* Notification Service Structures */
31typedef struct {
32 UINT32 Cookie; // SW defined value
33 UINT16 Id; // Global bitmask value
34 BOOLEAN PerVcpu; // Notification flag
35 UINT16 SourceId;
36 BOOLEAN InUse;
37} NotifInfo;
38
39typedef struct {
40 UINT8 ServiceUuid[16];
41 NotifInfo ServiceInfo[NOTIFICATION_MAX_MAPPINGS];
42 BOOLEAN InUse;
43} NotifService;
44
45/* Notification Service Variables */
46STATIC UINT64 GlobalBitmask;
47STATIC NotifService NotificationServices[NOTIFICATION_MAX_SERVICES];
48
49/**
50 Checks if the cookie passed in matches one stored within the service structure
51
52 @param Cookie The cookie value to search for
53 @param Service The service to search for the given ID
54
55 @return The index of the cookie if found, otherwise -1 (NOTIFICATION_NOT_FOUND)
56
57**/
58STATIC
59INT8
60IsMatchingCookie (
61 UINT32 Cookie,
62 NotifService *Service
63 )
64{
65 UINT8 Index;
66
67 /* Validate the incoming function parameters */
68 if (Service == NULL) {
69 return NOTIFICATION_NOT_FOUND;
70 }
71
72 for (Index = 0; Index < NOTIFICATION_MAX_MAPPINGS; Index++) {
73 if (Service->ServiceInfo[Index].InUse && (Service->ServiceInfo[Index].Cookie == Cookie)) {
74 return Index;
75 }
76 }
77
78 return NOTIFICATION_NOT_FOUND;
79}
80
81/**
82 Adds or removes service bit information to the local notification services struct array
83
84 @param Unregister Whether or not we are adding or removing bit information
85 @param Request The incoming message containing the bit information
86 @param Service The service we are updating bit information for
87
88 @retval NOTIFICATION_STATUS_SUCCESS Success
89 @retval NOTIFICATION_STATUS_INVALID_PARAMETER Invalid parameter
90
91**/
92STATIC
93NotificationStatus
94UpdateServiceInfo (
95 BOOLEAN Unregister,
96 DIRECT_MSG_ARGS_EX *Request,
97 NotifService *Service
98 )
99{
100 NotificationStatus ReturnVal;
101 INT8 FoundIndex;
102 UINT8 ReqNumMappings;
103 NotificationMapping *ReqMappings;
104 UINT8 ReqMappingIndex;
105 UINT16 MappingId;
106 UINT32 Cookie;
107 UINT8 PerVcpu;
108 UINT8 EmptyIndex;
109 BOOLEAN EmptyFound;
110 NotifService TempService;
111 UINT64 TempBitmask;
112
113 /* Validate the incoming function parameters */
114 if ((Request == NULL) || (Service == NULL)) {
115 return NOTIFICATION_STATUS_INVALID_PARAMETER;
116 }
117
118 /* Number of cookie/ID pairs = x10. Cookie/ID pairs = x11 (i.e. Arg6/Arg7) */
119 ReqNumMappings = Request->Arg6;
120 ReqMappings = (NotificationMapping *)&Request->Arg7;
121
122 /* You must be adding/removing at least one bit and no more than a transaction supports */
123 if ((ReqNumMappings < MAPPING_MIN) || (ReqNumMappings > MAPPING_MAX)) {
124 DEBUG ((DEBUG_ERROR, "Invalid Number of Mappings: %x\n", ReqNumMappings));
125 return NOTIFICATION_STATUS_INVALID_PARAMETER;
126 }
127
128 /* Copy the current service structure and global bitmask to the temporaries */
129 CopyMem (&TempService, Service, sizeof (NotifService));
130 TempBitmask = GlobalBitmask;
131
132 /* Need to go through all of the setup bits and update the structure */
133 ReturnVal = NOTIFICATION_STATUS_SUCCESS;
134 for (ReqMappingIndex = 0; ReqMappingIndex < ReqNumMappings; ReqMappingIndex++) {
135 MappingId = ReqMappings[ReqMappingIndex].Bits.Id;
136 Cookie = ReqMappings[ReqMappingIndex].Bits.Cookie;
137 PerVcpu = ReqMappings[ReqMappingIndex].Bits.PerVcpu;
138 FoundIndex = IsMatchingCookie (Cookie, &TempService);
139
140 /* Check if we are doing an unregister */
141 if (Unregister) {
142 /* If we can not find the cookie to unregister, it is an error */
143 if (FoundIndex == NOTIFICATION_NOT_FOUND) {
144 DEBUG ((DEBUG_ERROR, "Invalid Unregister - Cookie: %x Not Registered\n", Cookie));
145 ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
146 break;
147 /* If the IDs do not match, it is an error */
148 } else if (TempService.ServiceInfo[FoundIndex].Id != MappingId) {
149 DEBUG ((
150 DEBUG_ERROR,
151 "Invalid Unregister - ID Registered: %x Mismatch\n",
152 TempService.ServiceInfo[FoundIndex].Id
153 ));
154 ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
155 break;
156 /* If the Source IDs do not match, it is an error */
157 } else if (TempService.ServiceInfo[FoundIndex].SourceId != Request->SourceId) {
158 DEBUG ((
159 DEBUG_ERROR,
160 "Invalid Unregister - Source ID: %x Mismatch\n",
161 TempService.ServiceInfo[FoundIndex].SourceId
162 ));
163 ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
164 break;
165 /* Otherwise, clear the data */
166 } else {
167 TempService.ServiceInfo[FoundIndex].Cookie = 0;
168 TempService.ServiceInfo[FoundIndex].Id = 0;
169 TempService.ServiceInfo[FoundIndex].InUse = FALSE;
170 TempService.ServiceInfo[FoundIndex].PerVcpu = FALSE;
171 TempService.ServiceInfo[FoundIndex].SourceId = 0;
172 TempBitmask &= ~(1 << MappingId);
173 }
174
175 /* Otherwise, we are doing a register */
176 } else {
177 /* If we can find the cookie to register, it is an error */
178 if (FoundIndex != NOTIFICATION_NOT_FOUND) {
179 DEBUG ((DEBUG_ERROR, "Invalid Register - Cookie: %x Already Registered\n", Cookie));
180 ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
181 break;
182 /* If the Bitmask bit is set, it is an error */
183 } else if (TempBitmask & (1 << MappingId)) {
184 DEBUG ((DEBUG_ERROR, "Invalid Register - ID: %x Already Registered\n", MappingId));
185 ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
186 break;
187 /* Otherwise, set the data */
188 } else {
189 /* Need to loop through the bits within the structure and find an empty location */
190 EmptyFound = FALSE;
191 for (EmptyIndex = 0; EmptyIndex < NOTIFICATION_MAX_MAPPINGS; EmptyIndex++) {
192 if (!TempService.ServiceInfo[EmptyIndex].InUse) {
193 EmptyFound = TRUE;
194 break;
195 }
196 }
197
198 /* If we can not find an empty space, it is an error */
199 if (!EmptyFound) {
200 DEBUG ((DEBUG_ERROR, "Register Failed - No Memory Available\n"));
201 ReturnVal = NOTIFICATION_STATUS_NO_MEM;
202 break;
203 /* Otherwise, update the data */
204 } else {
205 TempService.ServiceInfo[EmptyIndex].Cookie = Cookie;
206 TempService.ServiceInfo[EmptyIndex].Id = MappingId;
207 TempService.ServiceInfo[EmptyIndex].InUse = TRUE;
208 TempService.ServiceInfo[EmptyIndex].PerVcpu = (PerVcpu) ? TRUE : FALSE;
209 TempService.ServiceInfo[EmptyIndex].SourceId = Request->SourceId;
210 TempBitmask |= (1 << MappingId);
211 }
212 }
213 }
214
215 /* Copy the temporaries back if everything was successful */
216 if (ReturnVal == NOTIFICATION_STATUS_SUCCESS) {
217 CopyMem (Service, &TempService, sizeof (NotifService));
218 GlobalBitmask = TempBitmask;
219 }
220 }
221
222 return ReturnVal;
223}
224
225/**
226 Searches the NotificationServices structure for the provided UUID or an
227 empty location to place a new service.
228
229 @param Uuid The UUID to search for
230 @param LocateEmpty Whether or not to search for an empty location
231
232 @retval A pointer to the service that matches the UUID, an empty location
233 or NULL if no match could be found.
234
235**/
236STATIC
237NotifService *
238LocateService (
239 UINT8 *Uuid,
240 BOOLEAN LocateEmpty
241 )
242{
243 UINT8 Index;
244 NotifService *Service;
245
246 Service = NULL;
247
248 /* Traverse the NotificationServices structure */
249 for (Index = 0; Index < NOTIFICATION_MAX_SERVICES; Index++) {
250 /* If looking for a UUID, check if the service is marked as InUse */
251 if (!LocateEmpty && NotificationServices[Index].InUse) {
252 /* Check if the UUID matches */
253 if (!CompareMem (Uuid, NotificationServices[Index].ServiceUuid, sizeof (Uuid))) {
254 Service = &NotificationServices[Index];
255 break;
256 }
257
258 /* If looking for an empty location, check if the service is not marked as InUse */
259 } else if (LocateEmpty && !NotificationServices[Index].InUse) {
260 Service = &NotificationServices[Index];
261 break;
262 }
263 }
264
265 return Service;
266}
267
268/**
269 Handler for Notification Register command
270
271 @param Request The incoming message
272 @param Response The outgoing message
273
274 @retval NOTIFICATION_STATUS_SUCCESS Success
275 @retval NOTIFICATION_STATUS_INVALID_PARAMETER Invalid parameter
276 @retval NOTIFICATION_STATUS_NO_MEM Out of resources
277
278**/
279STATIC
280NotificationStatus
281RegisterHandler (
282 DIRECT_MSG_ARGS_EX *Request
283 )
284{
285 NotifService *Service;
286 UINT8 Uuid[16];
287 NotificationStatus ReturnVal;
288
289 ReturnVal = NOTIFICATION_STATUS_NO_MEM;
290
291 /* Extract the UUID from the message x7-x8 (i.e. Arg3-Arg4) */
292 NotificationServiceExtractUuid (Request->Arg3, Request->Arg4, Uuid);
293
294 /* Attempt to locate the service via the UUID provided */
295 Service = LocateService (Uuid, FALSE);
296
297 /* The UUID was not found in the list, attempt to find an empty location to add it */
298 if (Service == NULL) {
299 Service = LocateService (Uuid, TRUE);
300 }
301
302 /* Check for a valid UUID */
303 if (Service != NULL) {
304 ReturnVal = UpdateServiceInfo (FALSE, Request, Service);
305 /* Check if the update was successful and this was a new addition */
306 if ((ReturnVal == NOTIFICATION_STATUS_SUCCESS) && (!Service->InUse)) {
307 /* Update the UUID and set the location to InUse */
308 CopyMem (Service->ServiceUuid, Uuid, sizeof (Uuid));
309 Service->InUse = TRUE;
310 }
311 } else {
312 DEBUG ((DEBUG_ERROR, "Service Register Failed - Error Code: %d\n", ReturnVal));
313 }
314
315 return ReturnVal;
316}
317
318/**
319 Handler for Notification Unregister command
320
321 @param Request The incoming message
322 @param Response The outgoing message
323
324 @retval NOTIFICATION_STATUS_SUCCESS Success
325 @retval NOTIFICATION_STATUS_INVALID_PARAMETER Invalid parameter
326
327**/
328STATIC
329NotificationStatus
330UnregisterHandler (
331 DIRECT_MSG_ARGS_EX *Request
332 )
333{
334 NotifService *Service;
335 UINT8 Uuid[16];
336 NotificationStatus ReturnVal;
337
338 ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
339
340 /* Extract the UUID from the message x7-x8 (i.e. Arg3-Arg4) */
341 NotificationServiceExtractUuid (Request->Arg3, Request->Arg4, Uuid);
342
343 /* Attempt to locate the service via the UUID provided */
344 Service = LocateService (Uuid, FALSE);
345
346 /* Check for a valid UUID */
347 if (Service != NULL) {
348 ReturnVal = UpdateServiceInfo (TRUE, Request, Service);
349 } else {
350 DEBUG ((DEBUG_ERROR, "Service Unregister Failed - Error Code: %d\n", ReturnVal));
351 }
352
353 return ReturnVal;
354}
355
356/**
357 Initializes the Notification service
358
359**/
360VOID
361NotificationServiceInit (
362 VOID
363 )
364{
365 /* Initialize Global Bitmask */
366 GlobalBitmask = 0;
367
368 /* Initialize the Notification Service structure */
369 ZeroMem (&NotificationServices[0], sizeof (NotificationServices));
370}
371
372/**
373 Deinitializes the Notification service
374
375**/
376VOID
377NotificationServiceDeInit (
378 VOID
379 )
380{
381 /* Nothing to DeInit */
382}
383
384/**
385 Handler for Notification service commands
386
387 @param Request The incoming message
388 @param Response The outgoing message
389
390**/
391VOID
392NotificationServiceHandle (
393 DIRECT_MSG_ARGS_EX *Request,
394 DIRECT_MSG_ARGS_EX *Response
395 )
396{
397 NotificationStatus ReturnVal;
398
399 /* Validate the input parameters before attempting to dereference or pass them along */
400 if ((Request == NULL) || (Response == NULL)) {
401 return;
402 }
403
404 /* TODO: Figure out how to set x5-x8 */
405 /* Set common response register values */
406 Response->Arg1 = Request->Arg1;
407 Response->Arg2 = Request->Arg2;
408 Response->Arg3 = Request->Arg3;
409 Response->Arg4 = Request->Arg4;
410 Response->Arg5 = Request->Arg5 | MESSAGE_INFO_DIR_RESP;
411
412 /* Message ID = Bits[0:1] of x9 (i.e. Arg5)*/
413 switch (Request->Arg5 & MESSAGE_INFO_ID_MASK) {
414 case NOTIFICATION_OPCODE_ADD:
415 case NOTIFICATION_OPCODE_REMOVE:
416 ReturnVal = NOTIFICATION_STATUS_NOT_SUPPORTED;
417 DEBUG ((DEBUG_ERROR, "Add/Remove Unsupported\n"));
418 break;
419
420 case NOTIFICATION_OPCODE_MEM_ASSIGN:
421 case NOTIFICATION_OPCODE_MEM_UNASSIGN:
422 ReturnVal = NOTIFICATION_STATUS_NOT_SUPPORTED;
423 DEBUG ((DEBUG_ERROR, "Memory Assign/Unassign Unsupported\n"));
424 break;
425
426 case NOTIFICATION_OPCODE_REGISTER:
427 ReturnVal = RegisterHandler (Request);
428 break;
429
430 case NOTIFICATION_OPCODE_UNREGISTER:
431 ReturnVal = UnregisterHandler (Request);
432 break;
433
434 default:
435 ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
436 DEBUG ((DEBUG_ERROR, "Invalid Notification Service Opcode\n"));
437 break;
438 }
439
440 /* Update the return status - Bits[0:7] of x10 (i.e. Arg6) */
441 Response->Arg6 = (((UINTN)(UINT8)ReturnVal) & RETURN_STATUS_MASK);
442}
443
444/**
445 Calls NotificationSet on the given ID with the given flag
446
447 @param Id The ID to trigger the event on
448 @param ServiceUuid The service containing the ID to trigger
449 @param Flag The NotificationSet flag to use
450
451 @retval NOTIFICATION_STATUS_SUCCESS Success
452 @retval NOTIFICATION_STATUS_INVALID_PARAMETER Invalid parameter
453
454**/
455NotificationStatus
456NotificationServiceIdSet (
457 UINT32 Cookie,
458 UINT8 *ServiceUuid,
459 UINT32 Flag
460 )
461{
462 NotifService *Service;
463 NotificationStatus ReturnVal;
464 UINT8 Index;
465 UINT64 Bitmask;
466 EFI_STATUS Status;
467
468 /* Validate the incoming function parameters */
469 if (ServiceUuid == NULL) {
470 return NOTIFICATION_STATUS_INVALID_PARAMETER;
471 }
472
473 ReturnVal = NOTIFICATION_STATUS_INVALID_PARAMETER;
474
475 /* Attempt to locate the service via the UUID provided */
476 Service = LocateService (ServiceUuid, FALSE);
477
478 /* Check for a valid UUID */
479 if (Service != NULL) {
480 /* Attempt to find the cookie within the mapped list */
481 for (Index = 0; Index < NOTIFICATION_MAX_MAPPINGS; Index++) {
482 if (Service->ServiceInfo[Index].Cookie == Cookie) {
483 Bitmask = (1 << Service->ServiceInfo[Index].Id);
484 if (Service->ServiceInfo[Index].PerVcpu) {
485 Flag |= (1 << PER_VCPU_BIT_POS);
486 }
487
488 Status = FfaNotificationSet (Service->ServiceInfo[Index].SourceId, Flag, Bitmask);
489 if (!EFI_ERROR (Status)) {
490 ReturnVal = NOTIFICATION_STATUS_SUCCESS;
491 }
492
493 break;
494 }
495 }
496 }
497
498 return ReturnVal;
499}
500
501/**
502 Extracts the UUID from the message arguments
503
504 @param UuidLo The lower bytes of the UUID
505 @param UuidHi The higher bytes of the UUID
506 @param Uuid The UUID to populate
507
508**/
509VOID
510NotificationServiceExtractUuid (
511 UINT64 UuidLo,
512 UINT64 UuidHi,
513 UINT8 *Uuid
514 )
515{
516 UINT8 Index;
517 UINT8 UuidHiByte;
518 UINT8 UuidLoByte;
519
520 /* Validate the incoming function parameters */
521 if (Uuid == NULL) {
522 return;
523 }
524
525 /* Copy the upper 8 bytes */
526 for (Index = 0; Index < 8; Index++) {
527 UuidHiByte = (UINT8)(UuidHi >> ((7 - Index) * 8));
528 Uuid[Index] = UuidHiByte;
529 }
530
531 /* Copy the lower 8 bytes */
532 for (Index = 8; Index < 16; Index++) {
533 UuidLoByte = (UINT8)(UuidLo >> ((15 - Index) * 8));
534 Uuid[Index] = UuidLoByte;
535 }
536}
537