1 /** @file
2   Library functions that abstract areas of conflict between framework and UEFI 2.0.
3 
4   Help Port Framework code that has conflicts with UEFI 2.0 by hiding the
5   old conflicts with library functions and supporting implementations of the old
6   (EDK/EFI 1.10) and new (EDK II/UEFI 2.0) way. This module is a DXE driver as
7   it contains DXE enum extensions for EFI event services.
8 
9 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
10 SPDX-License-Identifier: BSD-2-Clause-Patent
11 
12 **/
13 
14 
15 
16 #include "UefiLibInternal.h"
17 
18 /**
19   Creates an EFI event in the Legacy Boot Event Group.
20 
21   Prior to UEFI 2.0 this was done via a non blessed UEFI extensions and this library
22   abstracts the implementation mechanism of this event from the caller. This function
23   abstracts the creation of the Legacy Boot Event. The Framework moved from a proprietary
24   to UEFI 2.0 based mechanism.  This library abstracts the caller from how this event
25   is created to prevent to code form having to change with the version of the
26   specification supported.
27   If LegacyBootEvent is NULL, then ASSERT().
28 
29   @param  LegacyBootEvent   Returns the EFI event returned from gBS->CreateEvent(Ex).
30 
31   @retval EFI_SUCCESS       Event was created.
32   @retval Other             Event was not created.
33 
34 **/
35 EFI_STATUS
36 EFIAPI
EfiCreateEventLegacyBoot(OUT EFI_EVENT * LegacyBootEvent)37 EfiCreateEventLegacyBoot (
38   OUT EFI_EVENT  *LegacyBootEvent
39   )
40 {
41   return EfiCreateEventLegacyBootEx (
42            TPL_CALLBACK,
43            EfiEventEmptyFunction,
44            NULL,
45            LegacyBootEvent
46            );
47 }
48 
49 /**
50   Create an EFI event in the Legacy Boot Event Group and allows
51   the caller to specify a notification function.
52 
53   This function abstracts the creation of the Legacy Boot Event.
54   The Framework moved from a proprietary to UEFI 2.0 based mechanism.
55   This library abstracts the caller from how this event is created to prevent
56   to code form having to change with the version of the specification supported.
57   If LegacyBootEvent is NULL, then ASSERT().
58 
59   @param  NotifyTpl         The task priority level of the event.
60   @param  NotifyFunction    The notification function to call when the event is signaled.
61   @param  NotifyContext     The content to pass to NotifyFunction when the event is signaled.
62   @param  LegacyBootEvent   Returns the EFI event returned from gBS->CreateEvent(Ex).
63 
64   @retval EFI_SUCCESS       Event was created.
65   @retval Other             Event was not created.
66 
67 **/
68 EFI_STATUS
69 EFIAPI
EfiCreateEventLegacyBootEx(IN EFI_TPL NotifyTpl,IN EFI_EVENT_NOTIFY NotifyFunction,OPTIONAL IN VOID * NotifyContext,OPTIONAL OUT EFI_EVENT * LegacyBootEvent)70 EfiCreateEventLegacyBootEx (
71   IN  EFI_TPL           NotifyTpl,
72   IN  EFI_EVENT_NOTIFY  NotifyFunction,  OPTIONAL
73   IN  VOID              *NotifyContext,  OPTIONAL
74   OUT EFI_EVENT         *LegacyBootEvent
75   )
76 {
77   EFI_STATUS        Status;
78   EFI_EVENT_NOTIFY  WorkerNotifyFunction;
79 
80   ASSERT (LegacyBootEvent != NULL);
81 
82   if (gST->Hdr.Revision < EFI_2_00_SYSTEM_TABLE_REVISION) {
83     DEBUG ((EFI_D_ERROR, "EFI1.1 can't support LegacyBootEvent!"));
84     ASSERT (FALSE);
85 
86     return EFI_UNSUPPORTED;
87   } else {
88     //
89     // For UEFI 2.0 and the future use an Event Group
90     //
91     if (NotifyFunction == NULL) {
92       //
93       // CreateEventEx will check NotifyFunction is NULL or not and return error.
94       // Use dummy routine for the case NotifyFunction is NULL.
95       //
96       WorkerNotifyFunction = EfiEventEmptyFunction;
97     } else {
98       WorkerNotifyFunction = NotifyFunction;
99     }
100     Status = gBS->CreateEventEx (
101                     EVT_NOTIFY_SIGNAL,
102                     NotifyTpl,
103                     WorkerNotifyFunction,
104                     NotifyContext,
105                     &gEfiEventLegacyBootGuid,
106                     LegacyBootEvent
107                     );
108   }
109 
110   return Status;
111 }
112 
113 /**
114   Create an EFI event in the Ready To Boot Event Group.
115 
116   Prior to UEFI 2.0 this was done via a non-standard UEFI extension, and this library
117   abstracts the implementation mechanism of this event from the caller.
118   This function abstracts the creation of the Ready to Boot Event.  The Framework
119   moved from a proprietary to UEFI 2.0-based mechanism.  This library abstracts
120   the caller from how this event is created to prevent the code form having to
121   change with the version of the specification supported.
122   If ReadyToBootEvent is NULL, then ASSERT().
123 
124   @param  ReadyToBootEvent  Returns the EFI event returned from gBS->CreateEvent(Ex).
125 
126   @retval EFI_SUCCESS       Event was created.
127   @retval Other             Event was not created.
128 
129 **/
130 EFI_STATUS
131 EFIAPI
EfiCreateEventReadyToBoot(OUT EFI_EVENT * ReadyToBootEvent)132 EfiCreateEventReadyToBoot (
133   OUT EFI_EVENT  *ReadyToBootEvent
134   )
135 {
136   return EfiCreateEventReadyToBootEx (
137            TPL_CALLBACK,
138            EfiEventEmptyFunction,
139            NULL,
140            ReadyToBootEvent
141            );
142 }
143 
144 /**
145   Create an EFI event in the Ready To Boot Event Group and allows
146   the caller to specify a notification function.
147 
148   This function abstracts the creation of the Ready to Boot Event.
149   The Framework moved from a proprietary to UEFI 2.0 based mechanism.
150   This library abstracts the caller from how this event is created to prevent
151   to code form having to change with the version of the specification supported.
152   If ReadyToBootEvent is NULL, then ASSERT().
153 
154   @param  NotifyTpl         The task priority level of the event.
155   @param  NotifyFunction    The notification function to call when the event is signaled.
156   @param  NotifyContext     The content to pass to NotifyFunction when the event is signaled.
157   @param  ReadyToBootEvent  Returns the EFI event returned from gBS->CreateEvent(Ex).
158 
159   @retval EFI_SUCCESS       Event was created.
160   @retval Other             Event was not created.
161 
162 **/
163 EFI_STATUS
164 EFIAPI
EfiCreateEventReadyToBootEx(IN EFI_TPL NotifyTpl,IN EFI_EVENT_NOTIFY NotifyFunction,OPTIONAL IN VOID * NotifyContext,OPTIONAL OUT EFI_EVENT * ReadyToBootEvent)165 EfiCreateEventReadyToBootEx (
166   IN  EFI_TPL           NotifyTpl,
167   IN  EFI_EVENT_NOTIFY  NotifyFunction,  OPTIONAL
168   IN  VOID              *NotifyContext,  OPTIONAL
169   OUT EFI_EVENT         *ReadyToBootEvent
170   )
171 {
172   EFI_STATUS        Status;
173   EFI_EVENT_NOTIFY  WorkerNotifyFunction;
174 
175   ASSERT (ReadyToBootEvent != NULL);
176 
177   if (gST->Hdr.Revision < EFI_2_00_SYSTEM_TABLE_REVISION) {
178     DEBUG ((EFI_D_ERROR, "EFI1.1 can't support ReadyToBootEvent!"));
179     ASSERT (FALSE);
180 
181     return EFI_UNSUPPORTED;
182   } else {
183     //
184     // For UEFI 2.0 and the future use an Event Group
185     //
186     if (NotifyFunction == NULL) {
187       //
188       // CreateEventEx will check NotifyFunction is NULL or not and return error.
189       // Use dummy routine for the case NotifyFunction is NULL.
190       //
191       WorkerNotifyFunction = EfiEventEmptyFunction;
192     } else {
193       WorkerNotifyFunction = NotifyFunction;
194     }
195     Status = gBS->CreateEventEx (
196                     EVT_NOTIFY_SIGNAL,
197                     NotifyTpl,
198                     WorkerNotifyFunction,
199                     NotifyContext,
200                     &gEfiEventReadyToBootGuid,
201                     ReadyToBootEvent
202                     );
203   }
204 
205   return Status;
206 }
207 
208 
209 /**
210   Create, Signal, and Close the Ready to Boot event using EfiSignalEventReadyToBoot().
211 
212   This function abstracts the signaling of the Ready to Boot Event. The Framework moved
213   from a proprietary to UEFI 2.0 based mechanism. This library abstracts the caller
214   from how this event is created to prevent to code form having to change with the
215   version of the specification supported.
216 
217 **/
218 VOID
219 EFIAPI
EfiSignalEventReadyToBoot(VOID)220 EfiSignalEventReadyToBoot (
221   VOID
222   )
223 {
224   EFI_STATUS    Status;
225   EFI_EVENT     ReadyToBootEvent;
226 
227   Status = EfiCreateEventReadyToBoot (&ReadyToBootEvent);
228   if (!EFI_ERROR (Status)) {
229     gBS->SignalEvent (ReadyToBootEvent);
230     gBS->CloseEvent (ReadyToBootEvent);
231   }
232 }
233 
234 /**
235   Create, Signal, and Close the Ready to Boot event using EfiSignalEventLegacyBoot().
236 
237   This function abstracts the signaling of the Legacy Boot Event. The Framework moved from
238   a proprietary to UEFI 2.0 based mechanism.  This library abstracts the caller from how
239   this event is created to prevent to code form having to change with the version of the
240   specification supported.
241 
242 **/
243 VOID
244 EFIAPI
EfiSignalEventLegacyBoot(VOID)245 EfiSignalEventLegacyBoot (
246   VOID
247   )
248 {
249   EFI_STATUS    Status;
250   EFI_EVENT     LegacyBootEvent;
251 
252   Status = EfiCreateEventLegacyBoot (&LegacyBootEvent);
253   if (!EFI_ERROR (Status)) {
254     gBS->SignalEvent (LegacyBootEvent);
255     gBS->CloseEvent (LegacyBootEvent);
256   }
257 }
258 
259 
260 /**
261   Check to see if the Firmware Volume (FV) Media Device Path is valid
262 
263   The Framework FwVol Device Path changed to conform to the UEFI 2.0 specification.
264   This library function abstracts validating a device path node.
265   Check the MEDIA_FW_VOL_FILEPATH_DEVICE_PATH data structure to see if it's valid.
266   If it is valid, then return the GUID file name from the device path node.  Otherwise,
267   return NULL.  This device path changed in the DXE CIS version 0.92 in a non back ward
268   compatible way to not conflict with the UEFI 2.0 specification.  This function abstracts
269   the differences from the caller.
270   If FvDevicePathNode is NULL, then ASSERT().
271 
272   @param  FvDevicePathNode  The pointer to FV device path to check.
273 
274   @retval NULL              FvDevicePathNode is not valid.
275   @retval Other             FvDevicePathNode is valid and pointer to NameGuid was returned.
276 
277 **/
278 EFI_GUID *
279 EFIAPI
EfiGetNameGuidFromFwVolDevicePathNode(IN CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH * FvDevicePathNode)280 EfiGetNameGuidFromFwVolDevicePathNode (
281   IN CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  *FvDevicePathNode
282   )
283 {
284   ASSERT (FvDevicePathNode != NULL);
285 
286   if (DevicePathType (&FvDevicePathNode->Header) == MEDIA_DEVICE_PATH &&
287       DevicePathSubType (&FvDevicePathNode->Header) == MEDIA_PIWG_FW_FILE_DP) {
288     return (EFI_GUID *) &FvDevicePathNode->FvFileName;
289   }
290 
291   return NULL;
292 }
293 
294 
295 /**
296   Initialize a Firmware Volume (FV) Media Device Path node.
297 
298   The Framework FwVol Device Path changed to conform to the UEFI 2.0 specification.
299   This library function abstracts initializing a device path node.
300   Initialize the MEDIA_FW_VOL_FILEPATH_DEVICE_PATH data structure.  This device
301   path changed in the DXE CIS version 0.92 in a non back ward compatible way to
302   not conflict with the UEFI 2.0 specification.  This function abstracts the
303   differences from the caller.
304   If FvDevicePathNode is NULL, then ASSERT().
305   If NameGuid is NULL, then ASSERT().
306 
307   @param  FvDevicePathNode  The pointer to a FV device path node to initialize
308   @param  NameGuid          FV file name to use in FvDevicePathNode
309 
310 **/
311 VOID
312 EFIAPI
EfiInitializeFwVolDevicepathNode(IN OUT MEDIA_FW_VOL_FILEPATH_DEVICE_PATH * FvDevicePathNode,IN CONST EFI_GUID * NameGuid)313 EfiInitializeFwVolDevicepathNode (
314   IN OUT MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  *FvDevicePathNode,
315   IN CONST EFI_GUID                         *NameGuid
316   )
317 {
318   ASSERT (FvDevicePathNode != NULL);
319   ASSERT (NameGuid          != NULL);
320 
321   //
322   // Use the new Device path that does not conflict with the UEFI
323   //
324   FvDevicePathNode->Header.Type     = MEDIA_DEVICE_PATH;
325   FvDevicePathNode->Header.SubType  = MEDIA_PIWG_FW_FILE_DP;
326   SetDevicePathNodeLength (&FvDevicePathNode->Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH));
327 
328   CopyGuid (&FvDevicePathNode->FvFileName, NameGuid);
329 }
330 
331