event.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. event.c
  5. Abstract:
  6. This module implements UEFI core event services.
  7. Author:
  8. Evan Green 4-Mar-2014
  9. Environment:
  10. Firmware
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "ueficore.h"
  16. #include <minoca/uefi/guid/eventgrp.h>
  17. //
  18. // ---------------------------------------------------------------- Definitions
  19. //
  20. #define EFI_EVENT_MAGIC 0x746F7645 // 'tnvE'
  21. //
  22. // ------------------------------------------------------ Data Type Definitions
  23. //
  24. /*++
  25. Structure Description:
  26. This structure stores timing information about a timer event.
  27. Members:
  28. ListEntry - Stores pointers to the next and previous timer event structures.
  29. DueTime - Stores the time when the timer expires.
  30. Period - Stores the period of the timer, if periodic.
  31. --*/
  32. typedef struct _EFI_TIMER_EVENT {
  33. LIST_ENTRY ListEntry;
  34. UINT64 DueTime;
  35. UINT64 Period;
  36. } EFI_TIMER_EVENT, *PEFI_TIMER_EVENT;
  37. /*++
  38. Structure Description:
  39. This structure stores the internal structure of an EFI event.
  40. Members:
  41. Magic - Stores the magic constant EFI_EVENT_MAGIC.
  42. Type - Stores the type of event.
  43. SignalCount - Stores the number of times this event has been signaled.
  44. SignalListEntry - Stores pointers to the next and previous events in the
  45. signal queue.
  46. NotifyTpl - Stores the task priority level of the event.
  47. NotifyFunction - Stores a pointer to a function called when the event fires.
  48. NotifyContext - Stores a pointer's worth of data passed to the notify
  49. function.
  50. EventGroup - Stores the GUID of the event group this timer is in.
  51. NotifyListEntry - Stores pointers to the next and previous entries in the
  52. notify list.
  53. EventEx - Stores a boolean indicating if this event was created with the
  54. Ex function or the regular one.
  55. RuntimeData - Stores runtime data about the event.
  56. TimerData - Stores timer event data.
  57. --*/
  58. typedef struct _EFI_EVENT_DATA {
  59. UINTN Magic;
  60. UINT32 Type;
  61. UINT32 SignalCount;
  62. LIST_ENTRY SignalListEntry;
  63. EFI_TPL NotifyTpl;
  64. EFI_EVENT_NOTIFY NotifyFunction;
  65. VOID *NotifyContext;
  66. EFI_GUID EventGroup;
  67. LIST_ENTRY NotifyListEntry;
  68. BOOLEAN EventEx;
  69. EFI_RUNTIME_EVENT_ENTRY RuntimeData;
  70. EFI_TIMER_EVENT TimerData;
  71. } EFI_EVENT_DATA, *PEFI_EVENT_DATA;
  72. //
  73. // ----------------------------------------------- Internal Function Prototypes
  74. //
  75. EFI_STATUS
  76. EfipCoreCreateEvent (
  77. UINT32 Type,
  78. EFI_TPL NotifyTpl,
  79. EFI_EVENT_NOTIFY NotifyFunction,
  80. VOID *NotifyContext,
  81. EFI_GUID *EventGroup,
  82. EFI_EVENT *Event
  83. );
  84. VOID
  85. EfipCoreNotifyEvent (
  86. PEFI_EVENT_DATA Event
  87. );
  88. VOID
  89. EfipCoreInsertEventTimer (
  90. PEFI_EVENT_DATA Event
  91. );
  92. EFIAPI
  93. VOID
  94. EfipCoreCheckTimers (
  95. EFI_EVENT CheckEvent,
  96. VOID *Context
  97. );
  98. EFIAPI
  99. VOID
  100. EfipCoreEmptyCallbackFunction (
  101. EFI_EVENT Event,
  102. VOID *Context
  103. );
  104. //
  105. // -------------------------------------------------------------------- Globals
  106. //
  107. //
  108. // Store some well known event GUIDs.
  109. //
  110. EFI_GUID EfiEventExitBootServicesGuid = EFI_EVENT_GROUP_EXIT_BOOT_SERVICES;
  111. EFI_GUID EfiEventVirtualAddressChangeGuid =
  112. EFI_EVENT_GROUP_VIRTUAL_ADDRESS_CHANGE;
  113. EFI_GUID EfiEventMemoryMapChangeGuid = EFI_EVENT_GROUP_MEMORY_MAP_CHANGE;
  114. EFI_GUID EfiEventReadyToBootGuid = EFI_EVENT_GROUP_READY_TO_BOOT;
  115. //
  116. // Store the idle loop event, which is signaled when there's nothing to do.
  117. //
  118. EFI_GUID EfiIdleLoopEventGuid = EFI_IDLE_LOOP_EVENT_GUID;
  119. EFI_EVENT EfiIdleLoopEvent;
  120. //
  121. // Store the event queue.
  122. //
  123. EFI_LOCK EfiEventQueueLock;
  124. LIST_ENTRY EfiEventQueue[TPL_HIGH_LEVEL + 1];
  125. UINTN EfiEventsPending;
  126. LIST_ENTRY EfiEventSignalQueue;
  127. //
  128. // Store the timer list.
  129. //
  130. EFI_LOCK EfiTimerLock;
  131. LIST_ENTRY EfiTimerList;
  132. EFI_EVENT EfiCheckTimerEvent;
  133. //
  134. // Store a table of valid event creation flags.
  135. //
  136. UINT32 EfiValidEventFlags[] = {
  137. EVT_TIMER | EVT_NOTIFY_SIGNAL,
  138. EVT_TIMER,
  139. EVT_NOTIFY_WAIT,
  140. EVT_NOTIFY_SIGNAL,
  141. EVT_SIGNAL_EXIT_BOOT_SERVICES,
  142. EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
  143. 0,
  144. EVT_TIMER | EVT_NOTIFY_WAIT,
  145. };
  146. //
  147. // ------------------------------------------------------------------ Functions
  148. //
  149. EFIAPI
  150. EFI_STATUS
  151. EfiCoreCreateEvent (
  152. UINT32 Type,
  153. EFI_TPL NotifyTpl,
  154. EFI_EVENT_NOTIFY NotifyFunction,
  155. VOID *NotifyContext,
  156. EFI_EVENT *Event
  157. )
  158. /*++
  159. Routine Description:
  160. This routine creates an event.
  161. Arguments:
  162. Type - Supplies the type of event to create, as well as its mode and
  163. attributes.
  164. NotifyTpl - Supplies an optional task priority level of event notifications.
  165. NotifyFunction - Supplies an optional pointer to the event's notification
  166. function.
  167. NotifyContext - Supplies an optional context pointer that will be passed
  168. to the notify function when the event is signaled.
  169. Event - Supplies a pointer where the new event will be returned on success.
  170. Return Value:
  171. EFI_SUCCESS on success.
  172. EFI_INVALID_PARAMETER if one or more parameters are not valid.
  173. EFI_OUT_OF_RESOURCES if memory could not be allocated.
  174. --*/
  175. {
  176. EFI_STATUS Status;
  177. Status = EfiCoreCreateEventEx(Type,
  178. NotifyTpl,
  179. NotifyFunction,
  180. NotifyContext,
  181. NULL,
  182. Event);
  183. return Status;
  184. }
  185. EFIAPI
  186. EFI_STATUS
  187. EfiCoreCreateEventEx (
  188. UINT32 Type,
  189. EFI_TPL NotifyTpl,
  190. EFI_EVENT_NOTIFY NotifyFunction,
  191. VOID *NotifyContext,
  192. EFI_GUID *EventGroup,
  193. EFI_EVENT *Event
  194. )
  195. /*++
  196. Routine Description:
  197. This routine creates an event.
  198. Arguments:
  199. Type - Supplies the type of event to create, as well as its mode and
  200. attributes.
  201. NotifyTpl - Supplies an optional task priority level of event notifications.
  202. NotifyFunction - Supplies an optional pointer to the event's notification
  203. function.
  204. NotifyContext - Supplies an optional context pointer that will be passed
  205. to the notify function when the event is signaled.
  206. EventGroup - Supplies an optional pointer to the unique identifier of the
  207. group to which this event belongs. If this is NULL, the function
  208. behaves as if the parameters were passed to the original create event
  209. function.
  210. Event - Supplies a pointer where the new event will be returned on success.
  211. Return Value:
  212. EFI_SUCCESS on success.
  213. EFI_INVALID_PARAMETER if one or more parameters are not valid.
  214. EFI_OUT_OF_RESOURCES if memory could not be allocated.
  215. --*/
  216. {
  217. EFI_STATUS Status;
  218. if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
  219. if ((NotifyTpl != TPL_APPLICATION) &&
  220. (NotifyTpl != TPL_CALLBACK) &&
  221. (NotifyTpl != TPL_NOTIFY)) {
  222. return EFI_INVALID_PARAMETER;
  223. }
  224. }
  225. Status = EfipCoreCreateEvent(Type,
  226. NotifyTpl,
  227. NotifyFunction,
  228. NotifyContext,
  229. EventGroup,
  230. Event);
  231. return Status;
  232. }
  233. EFIAPI
  234. EFI_STATUS
  235. EfiCoreCloseEvent (
  236. EFI_EVENT Event
  237. )
  238. /*++
  239. Routine Description:
  240. This routine closes an event.
  241. Arguments:
  242. Event - Supplies the event to close.
  243. Return Value:
  244. EFI_SUCCESS on success.
  245. EFI_INVALID_PARAMETER if the given event is invalid.
  246. --*/
  247. {
  248. PEFI_EVENT_DATA EventData;
  249. EFI_STATUS Status;
  250. EventData = Event;
  251. if (EventData == NULL) {
  252. return EFI_INVALID_PARAMETER;
  253. }
  254. if (EventData->Magic != EFI_EVENT_MAGIC) {
  255. return EFI_INVALID_PARAMETER;
  256. }
  257. //
  258. // If it's a timer event, cancel it.
  259. //
  260. if ((EventData->Type & EVT_TIMER) != 0) {
  261. EfiCoreSetTimer(EventData, TimerCancel, 0);
  262. }
  263. EfiCoreAcquireLock(&EfiEventQueueLock);
  264. if (EventData->RuntimeData.ListEntry.Next != NULL) {
  265. LIST_REMOVE(&(EventData->RuntimeData.ListEntry));
  266. }
  267. if (EventData->NotifyListEntry.Next != NULL) {
  268. LIST_REMOVE(&(EventData->NotifyListEntry));
  269. }
  270. if (EventData->SignalListEntry.Next != NULL) {
  271. LIST_REMOVE(&(EventData->SignalListEntry));
  272. }
  273. EfiCoreReleaseLock(&EfiEventQueueLock);
  274. //
  275. // If the event is registered on a protocol notify, remove it from the
  276. // protocol database.
  277. //
  278. EfipCoreUnregisterProtocolNotify(Event);
  279. Status = EfiCoreFreePool(EventData);
  280. ASSERT(!EFI_ERROR(Status));
  281. return Status;
  282. }
  283. EFIAPI
  284. EFI_STATUS
  285. EfiCoreSignalEvent (
  286. EFI_EVENT Event
  287. )
  288. /*++
  289. Routine Description:
  290. This routine signals an event.
  291. Arguments:
  292. Event - Supplies the event to signal.
  293. Return Value:
  294. EFI_SUCCESS on success.
  295. EFI_INVALID_PARAMETER if the given event is not valid.
  296. --*/
  297. {
  298. PEFI_EVENT_DATA EventData;
  299. EventData = Event;
  300. if ((EventData == NULL) || (EventData->Magic != EFI_EVENT_MAGIC)) {
  301. return EFI_INVALID_PARAMETER;
  302. }
  303. EfiCoreAcquireLock(&EfiEventQueueLock);
  304. if (EventData->SignalCount == 0) {
  305. EventData->SignalCount += 1;
  306. //
  307. // If the signal type is a notify function, queue it.
  308. //
  309. if ((EventData->Type & EVT_NOTIFY_SIGNAL) != 0) {
  310. //
  311. // If it's an event "Ex", then signal all members of the event
  312. // group.
  313. //
  314. if (EventData->EventEx != FALSE) {
  315. EfiCoreReleaseLock(&EfiEventQueueLock);
  316. EfipCoreNotifySignalList(&(EventData->EventGroup));
  317. EfiCoreAcquireLock(&EfiEventQueueLock);
  318. } else {
  319. EfipCoreNotifyEvent(EventData);
  320. }
  321. }
  322. }
  323. EfiCoreReleaseLock(&EfiEventQueueLock);
  324. return EFI_SUCCESS;
  325. }
  326. EFIAPI
  327. EFI_STATUS
  328. EfiCoreCheckEvent (
  329. EFI_EVENT Event
  330. )
  331. /*++
  332. Routine Description:
  333. This routine checks whether or not an event is in the signaled state.
  334. Arguments:
  335. Event - Supplies the event to check.
  336. Return Value:
  337. EFI_SUCCESS on success.
  338. EFI_NOT_READY if the event is not signaled.
  339. EFI_INVALID_PARAMETER if the event is of type EVT_NOTIFY_SIGNAL.
  340. --*/
  341. {
  342. PEFI_EVENT_DATA EventData;
  343. EFI_STATUS Status;
  344. EventData = Event;
  345. if ((EventData == NULL) || (EventData->Magic != EFI_EVENT_MAGIC) ||
  346. ((EventData->Type & EVT_NOTIFY_SIGNAL) != 0)) {
  347. return EFI_INVALID_PARAMETER;
  348. }
  349. Status = EFI_NOT_READY;
  350. if ((EventData->SignalCount == 0) &&
  351. ((EventData->Type & EVT_NOTIFY_WAIT) != 0)) {
  352. //
  353. // Queue the wait notify function.
  354. //
  355. EfiCoreAcquireLock(&EfiEventQueueLock);
  356. if (EventData->SignalCount == 0) {
  357. EfipCoreNotifyEvent(EventData);
  358. }
  359. EfiCoreReleaseLock(&EfiEventQueueLock);
  360. }
  361. if (EventData->SignalCount != 0) {
  362. EfiCoreAcquireLock(&EfiEventQueueLock);
  363. if (EventData->SignalCount != 0) {
  364. EventData->SignalCount = 0;
  365. Status = EFI_SUCCESS;
  366. }
  367. EfiCoreReleaseLock(&EfiEventQueueLock);
  368. }
  369. return Status;
  370. }
  371. EFIAPI
  372. EFI_STATUS
  373. EfiCoreWaitForEvent (
  374. UINTN NumberOfEvents,
  375. EFI_EVENT *Event,
  376. UINTN *Index
  377. )
  378. /*++
  379. Routine Description:
  380. This routine stops execution until an event is signaled.
  381. Arguments:
  382. NumberOfEvents - Supplies the number of events in the event array.
  383. Event - Supplies the array of EFI_EVENTs.
  384. Index - Supplies a pointer where the index of the event which satisfied the
  385. wait will be returned.
  386. Return Value:
  387. EFI_SUCCESS on success.
  388. EFI_INVALID_PARAMETER if the number of events is zero, or the event
  389. indicated by the index return parameter is of type EVT_NOTIFY_SIGNAL.
  390. EFI_UNSUPPORTED if the current TPL is not TPL_APPLICATION.
  391. --*/
  392. {
  393. UINTN EventIndex;
  394. EFI_STATUS Status;
  395. if (NumberOfEvents == 0) {
  396. return EFI_INVALID_PARAMETER;
  397. }
  398. if (EfiCurrentTpl != TPL_APPLICATION) {
  399. return EFI_UNSUPPORTED;
  400. }
  401. while (TRUE) {
  402. for (EventIndex = 0; EventIndex < NumberOfEvents; EventIndex += 1) {
  403. Status = EfiCoreCheckEvent(Event[EventIndex]);
  404. if (Status != EFI_NOT_READY) {
  405. *Index = EventIndex;
  406. return Status;
  407. }
  408. }
  409. EfiCoreSignalEvent(&EfiIdleLoopEvent);
  410. }
  411. //
  412. // Execution never gets here.
  413. //
  414. ASSERT(FALSE);
  415. return EFI_NOT_READY;
  416. }
  417. EFIAPI
  418. EFI_STATUS
  419. EfiCoreSetTimer (
  420. EFI_EVENT Event,
  421. EFI_TIMER_DELAY Type,
  422. UINT64 TriggerTime
  423. )
  424. /*++
  425. Routine Description:
  426. This routine sets the type of timer and trigger time for a timer event.
  427. Arguments:
  428. Event - Supplies the timer to set.
  429. Type - Supplies the type of trigger to set.
  430. TriggerTime - Supplies the number of 100ns units until the timer expires.
  431. Zero is legal, and means the timer will be signaled on the next timer
  432. tick.
  433. Return Value:
  434. EFI_SUCCESS on success.
  435. EFI_INVALID_PARAMETER if the event or type is not valid.
  436. --*/
  437. {
  438. PEFI_EVENT_DATA EventData;
  439. UINT64 Frequency;
  440. EventData = Event;
  441. if ((EventData == NULL) || (EventData->Magic != EFI_EVENT_MAGIC)) {
  442. return EFI_INVALID_PARAMETER;
  443. }
  444. if (((UINT32)Type > TimerRelative) ||
  445. ((EventData->Type & EVT_TIMER) == 0)) {
  446. return EFI_INVALID_PARAMETER;
  447. }
  448. EfiCoreAcquireLock(&EfiTimerLock);
  449. //
  450. // If the timer is queued to a database, remove it.
  451. //
  452. if (EventData->TimerData.ListEntry.Next != NULL) {
  453. LIST_REMOVE(&(EventData->TimerData.ListEntry));
  454. EventData->TimerData.ListEntry.Next = NULL;
  455. }
  456. EventData->TimerData.DueTime = 0;
  457. EventData->TimerData.Period = 0;
  458. if (Type != TimerCancel) {
  459. Frequency = EfiCoreGetTimeCounterFrequency();
  460. TriggerTime = (TriggerTime * Frequency) / 10000000ULL;
  461. if (Type == TimerPeriodic) {
  462. if (TriggerTime == 0) {
  463. EventData->TimerData.Period = 1;
  464. } else {
  465. EventData->TimerData.Period = TriggerTime;
  466. }
  467. }
  468. EventData->TimerData.DueTime = EfiCoreReadTimeCounter() + TriggerTime;
  469. EfipCoreInsertEventTimer(EventData);
  470. if (TriggerTime == 0) {
  471. EfiCoreSignalEvent(&EfiCheckTimerEvent);
  472. }
  473. }
  474. EfiCoreReleaseLock(&EfiTimerLock);
  475. return EFI_SUCCESS;
  476. }
  477. EFI_STATUS
  478. EfiCoreInitializeEventServices (
  479. UINTN Phase
  480. )
  481. /*++
  482. Routine Description:
  483. This routine initializes event support.
  484. Arguments:
  485. Phase - Supplies the initialization phase. Valid values are 0 and 1.
  486. Return Value:
  487. EFI Status code.
  488. --*/
  489. {
  490. UINTN Index;
  491. if (Phase == 0) {
  492. EfiCoreInitializeLock(&EfiEventQueueLock, TPL_HIGH_LEVEL);
  493. EfiCoreInitializeLock(&EfiTimerLock, TPL_HIGH_LEVEL - 1);
  494. for (Index = 0; Index <= TPL_HIGH_LEVEL; Index += 1) {
  495. INITIALIZE_LIST_HEAD(&(EfiEventQueue[Index]));
  496. }
  497. INITIALIZE_LIST_HEAD(&EfiEventSignalQueue);
  498. INITIALIZE_LIST_HEAD(&EfiTimerList);
  499. } else {
  500. ASSERT(Phase == 1);
  501. EfiCoreCreateEventEx(EVT_NOTIFY_SIGNAL,
  502. TPL_NOTIFY,
  503. EfipCoreEmptyCallbackFunction,
  504. NULL,
  505. &EfiIdleLoopEventGuid,
  506. &EfiIdleLoopEvent);
  507. EfipCoreCreateEvent(EVT_NOTIFY_SIGNAL,
  508. TPL_HIGH_LEVEL - 1,
  509. EfipCoreCheckTimers,
  510. NULL,
  511. NULL,
  512. &EfiCheckTimerEvent);
  513. }
  514. return EFI_SUCCESS;
  515. }
  516. VOID
  517. EfiCoreDispatchEventNotifies (
  518. EFI_TPL Priority
  519. )
  520. /*++
  521. Routine Description:
  522. This routine dispatches all pending events.
  523. Arguments:
  524. Priority - Supplies the task priority level of the event notifications to
  525. dispatch.
  526. Return Value:
  527. None.
  528. --*/
  529. {
  530. PEFI_EVENT_DATA Event;
  531. PLIST_ENTRY ListHead;
  532. EfiCoreAcquireLock(&EfiEventQueueLock);
  533. ASSERT(EfiEventQueueLock.OwnerTpl == Priority);
  534. ListHead = &(EfiEventQueue[Priority]);
  535. while (LIST_EMPTY(ListHead) == FALSE) {
  536. Event = LIST_VALUE(ListHead->Next, EFI_EVENT_DATA, NotifyListEntry);
  537. ASSERT(Event->Magic == EFI_EVENT_MAGIC);
  538. LIST_REMOVE(&(Event->NotifyListEntry));
  539. Event->NotifyListEntry.Next = NULL;
  540. //
  541. // Only clear the signal status if it is a signal type event. Wait type
  542. // events are cleared in the check event function.
  543. //
  544. if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) {
  545. Event->SignalCount = 0;
  546. }
  547. //
  548. // Call the notification function without the lock held.
  549. //
  550. EfiCoreReleaseLock(&EfiEventQueueLock);
  551. Event->NotifyFunction(Event, Event->NotifyContext);
  552. EfiCoreAcquireLock(&EfiEventQueueLock);
  553. }
  554. EfiEventsPending &= ~(1 << Priority);
  555. EfiCoreReleaseLock(&EfiEventQueueLock);
  556. return;
  557. }
  558. VOID
  559. EfipCoreTimerTick (
  560. UINT64 CurrentTime
  561. )
  562. /*++
  563. Routine Description:
  564. This routine is called when a clock interrupt comes in.
  565. Arguments:
  566. CurrentTime - Supplies the new current time.
  567. Return Value:
  568. None.
  569. --*/
  570. {
  571. PEFI_EVENT_DATA Event;
  572. if (LIST_EMPTY(&EfiTimerList) == FALSE) {
  573. Event = LIST_VALUE(EfiTimerList.Next,
  574. EFI_EVENT_DATA,
  575. TimerData.ListEntry);
  576. if (Event->TimerData.DueTime <= CurrentTime) {
  577. EfiCoreSignalEvent(EfiCheckTimerEvent);
  578. }
  579. }
  580. return;
  581. }
  582. VOID
  583. EfipCoreNotifySignalList (
  584. EFI_GUID *EventGroup
  585. )
  586. /*++
  587. Routine Description:
  588. This routine signals all events in the given event group.
  589. Arguments:
  590. EventGroup - Supplies a pointer to the GUID identifying the event group
  591. to signal.
  592. Return Value:
  593. None.
  594. --*/
  595. {
  596. PLIST_ENTRY CurrentEntry;
  597. PEFI_EVENT_DATA Event;
  598. EfiCoreAcquireLock(&EfiEventQueueLock);
  599. CurrentEntry = EfiEventSignalQueue.Next;
  600. while (CurrentEntry != &EfiEventSignalQueue) {
  601. Event = LIST_VALUE(CurrentEntry, EFI_EVENT_DATA, SignalListEntry);
  602. CurrentEntry = CurrentEntry->Next;
  603. if (EfiCoreCompareGuids(&(Event->EventGroup), EventGroup) != FALSE) {
  604. EfipCoreNotifyEvent(Event);
  605. }
  606. }
  607. EfiCoreReleaseLock(&EfiEventQueueLock);
  608. return;
  609. }
  610. //
  611. // --------------------------------------------------------- Internal Functions
  612. //
  613. EFI_STATUS
  614. EfipCoreCreateEvent (
  615. UINT32 Type,
  616. EFI_TPL NotifyTpl,
  617. EFI_EVENT_NOTIFY NotifyFunction,
  618. VOID *NotifyContext,
  619. EFI_GUID *EventGroup,
  620. EFI_EVENT *Event
  621. )
  622. /*++
  623. Routine Description:
  624. This routine creates an event.
  625. Arguments:
  626. Type - Supplies the type of event to create, as well as its mode and
  627. attributes.
  628. NotifyTpl - Supplies an optional task priority level of event notifications.
  629. NotifyFunction - Supplies an optional pointer to the event's notification
  630. function.
  631. NotifyContext - Supplies an optional context pointer to pass when the event
  632. is signaled.
  633. EventGroup - Supplies an optional pointer to the unique identifier of the
  634. group to which this event belongs. If this is NULL, the function
  635. behaves as if the parameters were passed to the original create event
  636. function.
  637. Event - Supplies a pointer where the new event will be returned on success.
  638. Return Value:
  639. EFI_SUCCESS on success.
  640. EFI_INVALID_PARAMETER if one or more parameters are not valid.
  641. EFI_OUT_OF_RESOURCES if memory could not be allocated.
  642. --*/
  643. {
  644. UINTN EntryCount;
  645. UINTN Index;
  646. BOOLEAN Match;
  647. EFI_EVENT_DATA *NewEvent;
  648. EFI_STATUS Status;
  649. if (Event == NULL) {
  650. return EFI_INVALID_PARAMETER;
  651. }
  652. //
  653. // Check to make sure a valid combination of flags is set.
  654. //
  655. EntryCount = sizeof(EfiValidEventFlags) / sizeof(EfiValidEventFlags[0]);
  656. Status = EFI_INVALID_PARAMETER;
  657. for (Index = 0; Index < EntryCount; Index += 1) {
  658. if (Type == EfiValidEventFlags[Index]) {
  659. Status = EFI_SUCCESS;
  660. break;
  661. }
  662. }
  663. if (EFI_ERROR(Status)) {
  664. return Status;
  665. }
  666. //
  667. // Convert the event type for pre-existing event groups.
  668. //
  669. if (EventGroup != NULL) {
  670. if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) ||
  671. (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {
  672. return EFI_INVALID_PARAMETER;
  673. }
  674. if (EfiCoreCompareGuids(EventGroup, &EfiEventExitBootServicesGuid) !=
  675. FALSE) {
  676. Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;
  677. } else {
  678. Match = EfiCoreCompareGuids(EventGroup,
  679. &EfiEventVirtualAddressChangeGuid);
  680. if (Match != FALSE) {
  681. Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;
  682. }
  683. }
  684. } else {
  685. if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {
  686. EventGroup = &EfiEventExitBootServicesGuid;
  687. } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {
  688. EventGroup = &EfiEventVirtualAddressChangeGuid;
  689. }
  690. }
  691. //
  692. // If it's a notify type event, check parameters.
  693. //
  694. if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {
  695. if ((NotifyFunction == NULL) ||
  696. (NotifyTpl <= TPL_APPLICATION) ||
  697. (NotifyTpl >= TPL_HIGH_LEVEL)) {
  698. return EFI_INVALID_PARAMETER;
  699. }
  700. //
  701. // No notifications are needed.
  702. //
  703. } else {
  704. NotifyTpl = 0;
  705. NotifyFunction = NULL;
  706. NotifyContext = NULL;
  707. }
  708. //
  709. // Allocate and initialize the new event.
  710. //
  711. if ((Type & EVT_RUNTIME) != 0) {
  712. NewEvent = EfiCoreAllocateRuntimePool(sizeof(EFI_EVENT_DATA));
  713. } else {
  714. NewEvent = EfiCoreAllocateBootPool(sizeof(EFI_EVENT_DATA));
  715. }
  716. if (NewEvent == NULL) {
  717. return EFI_OUT_OF_RESOURCES;
  718. }
  719. EfiCoreSetMemory(NewEvent, sizeof(EFI_EVENT_DATA), 0);
  720. NewEvent->Magic = EFI_EVENT_MAGIC;
  721. NewEvent->Type = Type;
  722. NewEvent->NotifyTpl = NotifyTpl;
  723. NewEvent->NotifyFunction = NotifyFunction;
  724. NewEvent->NotifyContext = NotifyContext;
  725. if (EventGroup != NULL) {
  726. EfiCoreCopyMemory(&(NewEvent->EventGroup),
  727. EventGroup,
  728. sizeof(EFI_GUID));
  729. NewEvent->EventEx = TRUE;
  730. }
  731. *Event = NewEvent;
  732. //
  733. // Keep a list of all the runtime events specifically.
  734. //
  735. if ((Type & EVT_RUNTIME) != 0) {
  736. NewEvent->RuntimeData.Type = Type;
  737. NewEvent->RuntimeData.NotifyTpl = NotifyTpl;
  738. NewEvent->RuntimeData.NotifyFunction = NotifyFunction;
  739. NewEvent->RuntimeData.NotifyContext = NotifyContext;
  740. NewEvent->RuntimeData.Event = (EFI_EVENT *)NewEvent;
  741. INSERT_BEFORE(&(NewEvent->RuntimeData.ListEntry),
  742. &(EfiRuntimeProtocol->EventListHead));
  743. }
  744. EfiCoreAcquireLock(&EfiEventQueueLock);
  745. if ((Type & EVT_NOTIFY_SIGNAL) != 0) {
  746. INSERT_AFTER(&(NewEvent->SignalListEntry), &EfiEventSignalQueue);
  747. }
  748. EfiCoreReleaseLock(&EfiEventQueueLock);
  749. return EFI_SUCCESS;
  750. }
  751. VOID
  752. EfipCoreNotifyEvent (
  753. PEFI_EVENT_DATA Event
  754. )
  755. /*++
  756. Routine Description:
  757. This routine notifies the given event.
  758. Arguments:
  759. Event - Supplies the event to notify.
  760. Return Value:
  761. None.
  762. --*/
  763. {
  764. ASSERT(EfiCoreIsLockHeld(&EfiEventQueueLock) != FALSE);
  765. //
  766. // If the event is queued somewhere, remove it.
  767. //
  768. if (Event->NotifyListEntry.Next != NULL) {
  769. LIST_REMOVE(&(Event->NotifyListEntry));
  770. Event->NotifyListEntry.Next = NULL;
  771. }
  772. INSERT_BEFORE(&(Event->NotifyListEntry),
  773. &(EfiEventQueue[Event->NotifyTpl]));
  774. EfiEventsPending = 1 << Event->NotifyTpl;
  775. return;
  776. }
  777. VOID
  778. EfipCoreInsertEventTimer (
  779. PEFI_EVENT_DATA Event
  780. )
  781. /*++
  782. Routine Description:
  783. This routine inserts the given timer event into the global list.
  784. Arguments:
  785. Event - Supplies the timer event to insert.
  786. Return Value:
  787. None.
  788. --*/
  789. {
  790. PLIST_ENTRY CurrentEntry;
  791. PEFI_EVENT_DATA SearchEvent;
  792. ASSERT(EfiCoreIsLockHeld(&EfiTimerLock) != FALSE);
  793. CurrentEntry = EfiTimerList.Next;
  794. while (CurrentEntry != &EfiTimerList) {
  795. SearchEvent = LIST_VALUE(CurrentEntry,
  796. EFI_EVENT_DATA,
  797. TimerData.ListEntry);
  798. if (SearchEvent->TimerData.DueTime > Event->TimerData.DueTime) {
  799. break;
  800. }
  801. CurrentEntry = CurrentEntry->Next;
  802. }
  803. INSERT_BEFORE(&(Event->TimerData.ListEntry), CurrentEntry);
  804. return;
  805. }
  806. EFIAPI
  807. VOID
  808. EfipCoreCheckTimers (
  809. EFI_EVENT CheckEvent,
  810. VOID *Context
  811. )
  812. /*++
  813. Routine Description:
  814. This routine checks the sorted timer list against the current system time,
  815. and signals any expired timers.
  816. Arguments:
  817. CheckEvent - Supplies the event that fired, the EFI check timer event.
  818. Context - Supplies a context pointer associated with the event, which is
  819. not used.
  820. Return Value:
  821. None.
  822. --*/
  823. {
  824. PEFI_EVENT_DATA Event;
  825. UINT64 TimeCounter;
  826. TimeCounter = EfiCoreReadTimeCounter();
  827. EfiCoreAcquireLock(&EfiTimerLock);
  828. while (LIST_EMPTY(&EfiTimerList) == FALSE) {
  829. Event = LIST_VALUE(EfiTimerList.Next,
  830. EFI_EVENT_DATA,
  831. TimerData.ListEntry);
  832. //
  833. // If this timer is not expired, then neither is anything after it,
  834. // so break.
  835. //
  836. if (Event->TimerData.DueTime > TimeCounter) {
  837. break;
  838. }
  839. LIST_REMOVE(&(Event->TimerData.ListEntry));
  840. Event->TimerData.ListEntry.Next = NULL;
  841. EfiCoreSignalEvent(Event);
  842. //
  843. // If this is a periodic timer, compute the next due time and set it
  844. // again.
  845. //
  846. if (Event->TimerData.Period != 0) {
  847. Event->TimerData.DueTime += Event->TimerData.Period;
  848. //
  849. // If the new due time is still in the past, reset the timer to
  850. // start from now.
  851. //
  852. if (Event->TimerData.DueTime < TimeCounter) {
  853. Event->TimerData.DueTime = TimeCounter;
  854. EfiCoreSignalEvent(EfiCheckTimerEvent);
  855. }
  856. EfipCoreInsertEventTimer(Event);
  857. }
  858. }
  859. EfiCoreReleaseLock(&EfiTimerLock);
  860. return;
  861. }
  862. EFIAPI
  863. VOID
  864. EfipCoreEmptyCallbackFunction (
  865. EFI_EVENT Event,
  866. VOID *Context
  867. )
  868. /*++
  869. Routine Description:
  870. This routine implements a null callback that does nothing but returns.
  871. Arguments:
  872. Event - Supplies the event that fired.
  873. Context - Supplies a context pointer associated with the event.
  874. Return Value:
  875. None.
  876. --*/
  877. {
  878. return;
  879. }