OpenCore  1.0.6
OpenCore Bootloader
Loading...
Searching...
No Matches
UserEvent.c
Go to the documentation of this file.
1
6#include <UserEvent.h>
7
8#include <stdlib.h>
9#include <stdio.h>
10
11#ifdef __MACH__
12 #include <mach/clock.h>
13 #include <mach/mach.h>
14#else
15 #include <time.h>
16#endif
17
30typedef struct {
31 BOOLEAN IsClosed;
32 BOOLEAN Signaled;
33 UINT32 Type;
34 EFI_TPL TplLevel;
35 EFI_EVENT_NOTIFY NotifyFn;
36 VOID *NotifyCtx;
37 UINT64 TimerEmit;
38 UINT64 TimerDelta;
40
48STATIC BOOLEAN mEventNeedInit = TRUE;
49STATIC EFI_TPL mCurTPL = 0;
51
55STATIC
56UINT64
58 VOID
59 )
60{
61 UINT64 TimeNow;
62
63 TimeNow = 0;
64
65 #if defined (_WIN32)
66
67 time_t TimeRes = time (NULL);
68
69 if (TimeRes < 0) {
70 return TimeNow;
71 }
72
73 TimeNow = (UINT64)TimeRes;
74 TimeNow = TimeNow*1000000000;
75
76 #elif defined (__MACH__)
77 clock_serv_t Cclock;
78 mach_timespec_t Now;
79
80 host_get_clock_service (mach_host_self (), SYSTEM_CLOCK, &Cclock);
81 clock_get_time (Cclock, &Now);
82 mach_port_deallocate (mach_task_self (), Cclock);
83
84 TimeNow = (UINT64)Now.tv_sec*1000000000 + Now.tv_nsec;
85
86 #else
87 struct timespec Now;
88
89 clock_gettime (CLOCK_MONOTONIC, &Now);
90 TimeNow = (UINT64)Now.tv_sec*1000000000 + Now.tv_nsec;
91
92 #endif
93
94 return TimeNow;
95}
96
100STATIC
103 VOID
104 )
105{
106 INTN Index;
107
108 for (Index = 0; Index < USER_EVENT_MAXNUM; Index++) {
109 if (mEvents[Index].IsClosed == TRUE) {
110 mEvents[Index].IsClosed = 0;
111 return (&(mEvents[Index]));
112 }
113 }
114
115 return NULL;
116}
117
121STATIC
122VOID
124 VOID
125 )
126{
127 UINT64 TimeNow;
128 INTN Index;
129
130 TimeNow = UserEventGetTimeNow ();
131
132 for (Index = 0; Index < USER_EVENT_MAXNUM; Index++) {
133 if (mEvents[Index].IsClosed == TRUE) {
134 //
135 // Skip unused descriptors
136 //
137 continue;
138 }
139
140 //
141 // Is it an active timer?
142 //
143 if (((mEvents[Index].Type & EVT_TIMER) != 0) && (mEvents[Index].TimerEmit != 0)) {
144 if (TimeNow >= mEvents[Index].TimerEmit) {
145 //
146 // Signal Event
147 //
148 mEvents[Index].Signaled = TRUE;
149
150 //
151 // Is it a periodic timer?
152 //
153 if (mEvents[Index].TimerDelta != 0) {
154 //
155 // Update trigger time
156 //
157 mEvents[Index].TimerEmit += mEvents[Index].TimerDelta;
158 } else {
159 mEvents[Index].TimerEmit = 0;
160 }
161 }
162 }
163
164 //
165 // Is it a signaled event?
166 //
167 if ((mEvents[Index].Signaled == TRUE) && ((mEvents[Index].Type & EVT_NOTIFY_SIGNAL) != 0)) {
168 //
169 // Is TPL of Event valid?
170 //
171 if (mCurTPL <= mEvents[Index].TplLevel) {
172 //
173 // Reset state
174 //
175 mEvents[Index].Signaled = FALSE;
176 //
177 // Call handler
178 //
179 mEvents[Index].NotifyFn ((EFI_EVENT)&mEvents[Index], mEvents[Index].NotifyCtx);
180 }
181 }
182 }
183}
184
188STATIC
189VOID
191 VOID
192 )
193{
194 INTN Index;
195
196 for (Index = 0; Index < USER_EVENT_MAXNUM; Index++) {
197 mEvents[Index].IsClosed = TRUE;
198 mEvents[Index].TplLevel = 0;
199 mEvents[Index].TimerEmit = 0;
200 }
201
202 //
203 // Init current TPL
204 //
205 mCurTPL = TPL_APPLICATION;
206}
207
211STATIC
212VOID
214 VOID
215 )
216{
217 if (mEventNeedInit == TRUE) {
218 mEventNeedInit = FALSE;
220 }
221}
222
246EFI_STATUS
247EFIAPI
249 IN UINT32 Type,
250 IN EFI_TPL NotifyTpl,
251 IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
252 IN CONST VOID *NotifyContext OPTIONAL,
253 IN CONST EFI_GUID *EventGroup OPTIONAL,
254 OUT EFI_EVENT *Event
255 )
256{
257 USER_EVENT *Ev;
258
259 UserEventInit ();
260
261 //
262 // Check input params
263 //
264 if (Event == NULL) {
265 return EFI_INVALID_PARAMETER;
266 }
267
268 if (((Type & EVT_NOTIFY_SIGNAL) != 0) && ((Type & EVT_NOTIFY_WAIT) != 0)) {
269 //
270 // The Type param can't combine EVT_NOTIFY_SIGNAL and EVT_NOTIFY_WAIT flags
271 //
272 return EFI_INVALID_PARAMETER;
273 }
274
275 if ((Type & (EVT_NOTIFY_SIGNAL | EVT_NOTIFY_WAIT)) != 0) {
276 //
277 // Event type is signal or event
278 //
279 if (NotifyFunction == NULL) {
280 //
281 // callback function isn't set
282 //
283 return EFI_INVALID_PARAMETER;
284 }
285
286 if (NotifyTpl >= USER_EVENT_MAXTPL) {
287 //
288 // Required TPL is invalid
289 //
290 return EFI_INVALID_PARAMETER;
291 }
292 }
293
294 //
295 // Try to allocate an Event descriptor
296 //
297 Ev = UserEventAlloc ();
298 if (Ev == NULL) {
299 *Event = NULL;
300 return EFI_OUT_OF_RESOURCES;
301 }
302
303 Ev->Type = Type;
304 Ev->TplLevel = NotifyTpl;
305 Ev->Signaled = 0;
306 Ev->NotifyFn = NotifyFunction;
307 Ev->NotifyCtx = (VOID *)NotifyContext;
308 Ev->TimerEmit = 0;
309
310 *Event = (EFI_EVENT)Ev;
311 return EFI_SUCCESS;
312}
313
335EFI_STATUS
336EFIAPI
338 IN UINT32 Type,
339 IN EFI_TPL NotifyTpl,
340 IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL,
341 IN VOID *NotifyContext OPTIONAL,
342 OUT EFI_EVENT *Event
343 )
344{
345 return UserCreateEventEx (
346 Type,
347 NotifyTpl,
348 NotifyFunction,
349 NotifyContext,
350 NULL,
351 Event
352 );
353}
354
362EFI_STATUS
363EFIAPI
365 IN EFI_EVENT Event
366 )
367{
368 USER_EVENT *Ev;
369
370 UserEventInit ();
371
372 ASSERT (Event != NULL);
373
374 Ev = (USER_EVENT *)Event;
375
376 Ev->IsClosed = TRUE;
377 Ev->TimerEmit = 0;
378 Ev->TplLevel = 0;
379
380 return EFI_SUCCESS;
381}
382
390EFI_STATUS
391EFIAPI
393 IN EFI_EVENT Event
394 )
395{
396 USER_EVENT *Ev;
397
398 UserEventInit ();
399
400 ASSERT (Event != NULL);
401
402 Ev = (USER_EVENT *)Event;
403 ASSERT (Ev->IsClosed == FALSE);
404
405 if (Ev->IsClosed == FALSE) {
406 Ev->Signaled = TRUE;
407 }
408
410
411 return EFI_SUCCESS;
412}
413
423EFI_STATUS
424EFIAPI
426 IN EFI_EVENT Event
427 )
428{
429 USER_EVENT *Ev;
430 EFI_STATUS Status;
431
432 UserEventInit ();
433
434 ASSERT (Event != NULL);
435
436 Ev = (USER_EVENT *)Event;
437 ASSERT (Ev->IsClosed == FALSE);
438
439 if ((Ev->Type & EVT_NOTIFY_SIGNAL) != 0) {
440 //
441 // The Event can't have the EVT_NOTIFY_SIGNAL type
442 //
443 return EFI_INVALID_PARAMETER;
444 }
445
447
448 if (Ev->Signaled == TRUE) {
449 Ev->Signaled = FALSE;
450 Status = EFI_SUCCESS;
451 } else {
452 //
453 // It isn't signaled event, but it can have the EVT_NOTIFY_WAIT type
454 // In that case, we need to emit callback function if TPL is valid
455 //
456 if (((Ev->Type & EVT_NOTIFY_WAIT) != 0) && (mCurTPL <= Ev->TplLevel)) {
457 Ev->NotifyFn ((EFI_EVENT)Ev, Ev->NotifyCtx);
458 }
459
460 Status = EFI_NOT_READY;
461 }
462
463 return Status;
464}
465
479EFI_STATUS
480EFIAPI
482 IN UINTN NumberOfEvents,
483 IN EFI_EVENT *Events,
484 OUT UINTN *Index
485 )
486{
487 USER_EVENT **Evs;
488 USER_EVENT *Ev;
489 UINTN Jndex;
490
491 UserEventInit ();
492
493 if (mCurTPL != TPL_APPLICATION) {
494 return EFI_UNSUPPORTED;
495 }
496
497 ASSERT (Events != NULL);
498 ASSERT (Index != NULL);
499
500 Evs = (USER_EVENT **)Events;
501
502 if (NumberOfEvents == 0) {
503 return EFI_INVALID_PARAMETER;
504 }
505
506 while (TRUE) {
507 //
508 // Blocking wait
509 //
510
512
513 for (Jndex = 0; Jndex < NumberOfEvents; Jndex++) {
514 Ev = Evs[Jndex];
515
516 if (Ev == NULL) {
517 continue;
518 }
519
520 if (Ev->IsClosed == TRUE) {
521 continue;
522 }
523
524 if ((Ev->Type & EVT_NOTIFY_SIGNAL) != 0) {
525 *Index = Jndex;
526 return EFI_INVALID_PARAMETER;
527 }
528
529 if (Ev->Signaled == TRUE) {
530 *Index = Jndex;
531 Ev->Signaled = FALSE;
532 return EFI_SUCCESS;
533 } else {
534 if (((Ev->Type & EVT_NOTIFY_WAIT) != 0) && (mCurTPL <= Ev->TplLevel)) {
535 Ev->NotifyFn ((EFI_EVENT)Ev, Ev->NotifyCtx);
536 }
537 }
538 }
539 }
540}
541
554EFI_STATUS
555EFIAPI
557 IN EFI_EVENT Event,
558 IN EFI_TIMER_DELAY Type,
559 IN UINT64 TriggerTime
560 )
561{
562 UINT64 TimeNow;
563 USER_EVENT *Ev;
564
565 UserEventInit ();
566
567 // check input params
568 ASSERT (Event != NULL);
569 Ev = (USER_EVENT *)Event;
570 ASSERT (Ev->IsClosed == FALSE);
571
572 if ((Ev->Type & EVT_TIMER) == 0) {
573 return EFI_INVALID_PARAMETER;
574 }
575
576 TimeNow = UserEventGetTimeNow ();
577
578 switch (Type) {
579 case TimerCancel:
580 Ev->TimerEmit = 0;
581 break;
582
583 case TimerRelative:
584 Ev->TimerEmit = TimeNow + TriggerTime * 100;
585 Ev->TimerDelta = 0;
586 break;
587
588 case TimerPeriodic:
589 Ev->TimerEmit = TimeNow + TriggerTime * 100;
590 Ev->TimerDelta = TriggerTime * 100;
591 break;
592
593 default:
594 return EFI_INVALID_PARAMETER;
595 }
596
598 return EFI_SUCCESS;
599}
600
609EFI_TPL
610EFIAPI
612 IN EFI_TPL NewTpl
613 )
614{
615 EFI_TPL Old;
616
617 UserEventInit ();
618
620
621 Old = mCurTPL;
622 if ((NewTpl >= Old) && (NewTpl < USER_EVENT_MAXTPL)) {
623 mCurTPL = NewTpl;
624 }
625
626 return Old;
627}
628
634VOID
635EFIAPI
637 IN EFI_TPL OldTpl
638 )
639{
640 UserEventInit ();
641 ASSERT (OldTpl <= mCurTPL);
642
643 if (OldTpl < USER_EVENT_MAXTPL) {
644 mCurTPL = OldTpl;
645 }
646
648}
649
656BOOLEAN
658 VOID
659 )
660{
661 UINT64 TimeNow;
662 BOOLEAN Res;
663 INTN Index;
664
665 UserEventInit ();
666
667 TimeNow = UserEventGetTimeNow ();
668
669 Res = FALSE;
670 for (Index = 0; Index < USER_EVENT_MAXNUM; Index++) {
671 if (mEvents[Index].IsClosed == TRUE) {
672 continue;
673 }
674
675 Res = TRUE;
676 if (((mEvents[Index].Type & EVT_TIMER) != 0) && (mEvents[Index].TimerEmit != 0)) {
677 if (TimeNow >= mEvents[Index].TimerEmit) {
678 mEvents[Index].Signaled = TRUE;
679 if (mEvents[Index].TimerDelta != 0) {
680 mEvents[Index].TimerEmit += mEvents[Index].TimerDelta;
681 } else {
682 mEvents[Index].TimerEmit = 0;
683 }
684 }
685 }
686
687 if ((mEvents[Index].Signaled == TRUE) && ((mEvents[Index].Type & EVT_NOTIFY_SIGNAL) != 0)) {
688 if (mCurTPL <= mEvents[Index].TplLevel) {
689 mEvents[Index].Signaled = FALSE;
690 mEvents[Index].NotifyFn ((EFI_EVENT)&mEvents[Index], mEvents[Index].NotifyCtx);
691 }
692 }
693 }
694
695 return Res;
696}
EFI_STATUS EFIAPI UserWaitForEvent(IN UINTN NumberOfEvents, IN EFI_EVENT *Events, OUT UINTN *Index)
Definition UserEvent.c:481
STATIC VOID UserEventInitializer(VOID)
Definition UserEvent.c:190
STATIC USER_EVENT mEvents[USER_EVENT_MAXNUM]
Definition UserEvent.c:50
STATIC VOID UserEventInit(VOID)
Definition UserEvent.c:213
BOOLEAN UserEventDispatchNow(VOID)
Definition UserEvent.c:657
EFI_STATUS EFIAPI UserCreateEvent(IN UINT32 Type, IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, IN VOID *NotifyContext OPTIONAL, OUT EFI_EVENT *Event)
Definition UserEvent.c:337
STATIC UINT64 UserEventGetTimeNow(VOID)
Definition UserEvent.c:57
EFI_STATUS EFIAPI UserCheckEvent(IN EFI_EVENT Event)
Definition UserEvent.c:425
STATIC EFI_TPL mCurTPL
Definition UserEvent.c:49
EFI_STATUS EFIAPI UserCreateEventEx(IN UINT32 Type, IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, IN CONST VOID *NotifyContext OPTIONAL, IN CONST EFI_GUID *EventGroup OPTIONAL, OUT EFI_EVENT *Event)
Definition UserEvent.c:248
EFI_STATUS EFIAPI UserSignalEvent(IN EFI_EVENT Event)
Definition UserEvent.c:392
EFI_STATUS EFIAPI UserCloseEvent(IN EFI_EVENT Event)
Definition UserEvent.c:364
EFI_STATUS EFIAPI UserSetTimer(IN EFI_EVENT Event, IN EFI_TIMER_DELAY Type, IN UINT64 TriggerTime)
Definition UserEvent.c:556
STATIC VOID UserEventDispatch(VOID)
Definition UserEvent.c:123
VOID EFIAPI UserRestoreTPL(IN EFI_TPL OldTpl)
Definition UserEvent.c:636
STATIC USER_EVENT * UserEventAlloc(VOID)
Definition UserEvent.c:102
STATIC BOOLEAN mEventNeedInit
Definition UserEvent.c:48
EFI_TPL EFIAPI UserRaiseTPL(IN EFI_TPL NewTpl)
Definition UserEvent.c:611
#define USER_EVENT_MAXNUM
Definition UserEvent.h:17
#define USER_EVENT_MAXTPL
Definition UserEvent.h:18
#define ASSERT(x)
Definition coder.h:55
BOOLEAN IsClosed
Definition UserEvent.c:31
UINT64 TimerDelta
Definition UserEvent.c:38
EFI_TPL TplLevel
Definition UserEvent.c:34
VOID * NotifyCtx
Definition UserEvent.c:36
BOOLEAN Signaled
Definition UserEvent.c:32
UINT32 Type
Definition UserEvent.c:33
UINT64 TimerEmit
Definition UserEvent.c:37
EFI_EVENT_NOTIFY NotifyFn
Definition UserEvent.c:35