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   Create a Legacy Boot Event.
20 
21   Tiano extended the CreateEvent Type enum to add a legacy boot event type.
22   This was bad as Tiano did not own the enum. In UEFI 2.0 CreateEventEx was
23   added and now it's possible to not voilate the UEFI specification by
24   declaring a GUID for the legacy boot event class. This library supports
25   the EDK/EFI 1.10 form and EDK II/UEFI 2.0 form and allows common code to
26   work both ways.
27 
28   @param  LegacyBootEvent   Returns the EFI event returned from gBS->CreateEvent(Ex).
29 
30   @retval EFI_SUCCESS       Event was created.
31   @retval Other             Event was not created.
32 
33 **/
34 EFI_STATUS
35 EFIAPI
EfiCreateEventLegacyBoot(OUT EFI_EVENT * LegacyBootEvent)36 EfiCreateEventLegacyBoot (
37   OUT EFI_EVENT  *LegacyBootEvent
38   )
39 {
40   return EfiCreateEventLegacyBootEx (
41            TPL_CALLBACK,
42            EfiEventEmptyFunction,
43            NULL,
44            LegacyBootEvent
45            );
46 }
47 
48 /**
49   Create an EFI event in the Legacy Boot Event Group and allows
50   the caller to specify a notification function.
51 
52   This function abstracts the creation of the Legacy Boot Event.
53   The Framework moved from a proprietary to UEFI 2.0 based mechanism.
54   This library abstracts the caller from how this event is created to prevent
55   to code form having to change with the version of the specification supported.
56   If LegacyBootEvent is NULL, then ASSERT().
57 
58   @param  NotifyTpl         The task priority level of the event.
59   @param  NotifyFunction    The notification function to call when the event is signaled.
60   @param  NotifyContext     The content to pass to NotifyFunction when the event is signaled.
61   @param  LegacyBootEvent   Returns the EFI event returned from gBS->CreateEvent(Ex).
62 
63   @retval EFI_SUCCESS       Event was created.
64   @retval Other             Event was not created.
65 
66 **/
67 EFI_STATUS
68 EFIAPI
EfiCreateEventLegacyBootEx(IN EFI_TPL NotifyTpl,IN EFI_EVENT_NOTIFY NotifyFunction,OPTIONAL IN VOID * NotifyContext,OPTIONAL OUT EFI_EVENT * LegacyBootEvent)69 EfiCreateEventLegacyBootEx (
70   IN  EFI_TPL           NotifyTpl,
71   IN  EFI_EVENT_NOTIFY  NotifyFunction,  OPTIONAL
72   IN  VOID              *NotifyContext,  OPTIONAL
73   OUT EFI_EVENT         *LegacyBootEvent
74   )
75 {
76   EFI_STATUS    Status;
77 
78   ASSERT (LegacyBootEvent != NULL);
79 
80   if (gST->Hdr.Revision < 0x00020000) {
81     //
82     // prior to UEFI 2.0 use Tiano extension to EFI
83     //
84     Status = gBS->CreateEvent (
85                     EFI_EVENT_SIGNAL_LEGACY_BOOT | EVT_NOTIFY_SIGNAL,
86                     NotifyTpl,
87                     NotifyFunction,
88                     NotifyContext,
89                     LegacyBootEvent
90                     );
91   } else {
92     //
93     // For UEFI 2.0 and the future use an Event Group
94     //
95     Status = gBS->CreateEventEx (
96                     EVT_NOTIFY_SIGNAL,
97                     NotifyTpl,
98                     NotifyFunction,
99                     NotifyContext,
100                     &gEfiEventLegacyBootGuid,
101                     LegacyBootEvent
102                     );
103   }
104 
105   return Status;
106 }
107 
108 /**
109   Create a Read to Boot Event.
110 
111   Tiano extended the CreateEvent Type enum to add a ready to boot event type.
112   This was bad as Tiano did not own the enum. In UEFI 2.0 CreateEventEx was
113   added and now it's possible to not voilate the UEFI specification and use
114   the ready to boot event class defined in UEFI 2.0. This library supports
115   the EDK/EFI 1.10 form and EDK II/UEFI 2.0 form and allows common code to
116   work both ways.
117 
118   @param  ReadyToBootEvent   Returns the EFI event returned from gBS->CreateEvent(Ex).
119 
120   @retval EFI_SUCCESS       Event was created.
121   @retval Other             Event was not created.
122 
123 **/
124 EFI_STATUS
125 EFIAPI
EfiCreateEventReadyToBoot(OUT EFI_EVENT * ReadyToBootEvent)126 EfiCreateEventReadyToBoot (
127   OUT EFI_EVENT  *ReadyToBootEvent
128   )
129 {
130   return EfiCreateEventReadyToBootEx (
131            TPL_CALLBACK,
132            EfiEventEmptyFunction,
133            NULL,
134            ReadyToBootEvent
135            );
136 }
137 
138 /**
139   Create an EFI event in the Ready To Boot Event Group and allows
140   the caller to specify a notification function.
141 
142   This function abstracts the creation of the Ready to Boot Event.
143   The Framework moved from a proprietary to UEFI 2.0 based mechanism.
144   This library abstracts the caller from how this event is created to prevent
145   to code form having to change with the version of the specification supported.
146   If ReadyToBootEvent is NULL, then ASSERT().
147 
148   @param  NotifyTpl         The task priority level of the event.
149   @param  NotifyFunction    The notification function to call when the event is signaled.
150   @param  NotifyContext     The content to pass to NotifyFunction when the event is signaled.
151   @param  ReadyToBootEvent  Returns the EFI event returned from gBS->CreateEvent(Ex).
152 
153   @retval EFI_SUCCESS       Event was created.
154   @retval Other             Event was not created.
155 
156 **/
157 EFI_STATUS
158 EFIAPI
EfiCreateEventReadyToBootEx(IN EFI_TPL NotifyTpl,IN EFI_EVENT_NOTIFY NotifyFunction,OPTIONAL IN VOID * NotifyContext,OPTIONAL OUT EFI_EVENT * ReadyToBootEvent)159 EfiCreateEventReadyToBootEx (
160   IN  EFI_TPL           NotifyTpl,
161   IN  EFI_EVENT_NOTIFY  NotifyFunction,  OPTIONAL
162   IN  VOID              *NotifyContext,  OPTIONAL
163   OUT EFI_EVENT         *ReadyToBootEvent
164   )
165 {
166   EFI_STATUS    Status;
167 
168   ASSERT (ReadyToBootEvent != NULL);
169 
170   if (gST->Hdr.Revision < 0x00020000) {
171     //
172     // prior to UEFI 2.0 use Tiano extension to EFI
173     //
174     Status = gBS->CreateEvent (
175                     EFI_EVENT_SIGNAL_READY_TO_BOOT | EFI_EVENT_NOTIFY_SIGNAL_ALL,
176                     NotifyTpl,
177                     NotifyFunction,
178                     NotifyContext,
179                     ReadyToBootEvent
180                     );
181   } else {
182     //
183     // For UEFI 2.0 and the future use an Event Group
184     //
185     Status = gBS->CreateEventEx (
186                     EVT_NOTIFY_SIGNAL,
187                     NotifyTpl,
188                     NotifyFunction,
189                     NotifyContext,
190                     &gEfiEventReadyToBootGuid,
191                     ReadyToBootEvent
192                     );
193   }
194 
195   return Status;
196 }
197 
198 
199 /**
200   Signal a Ready to Boot Event.
201 
202   Create a Ready to Boot Event. Signal it and close it. This causes other
203   events of the same event group to be signaled in other modules.
204 
205 **/
206 VOID
207 EFIAPI
EfiSignalEventReadyToBoot(VOID)208 EfiSignalEventReadyToBoot (
209   VOID
210   )
211 {
212   EFI_STATUS    Status;
213   EFI_EVENT     ReadyToBootEvent;
214 
215   Status = EfiCreateEventReadyToBoot (&ReadyToBootEvent);
216   if (!EFI_ERROR (Status)) {
217     gBS->SignalEvent (ReadyToBootEvent);
218     gBS->CloseEvent (ReadyToBootEvent);
219   }
220 }
221 
222 /**
223   Signal a Legacy Boot Event.
224 
225   Create a legacy Boot Event. Signal it and close it. This causes other
226   events of the same event group to be signaled in other modules.
227 
228 **/
229 VOID
230 EFIAPI
EfiSignalEventLegacyBoot(VOID)231 EfiSignalEventLegacyBoot (
232   VOID
233   )
234 {
235   EFI_STATUS    Status;
236   EFI_EVENT     LegacyBootEvent;
237 
238   Status = EfiCreateEventLegacyBoot (&LegacyBootEvent);
239   if (!EFI_ERROR (Status)) {
240     gBS->SignalEvent (LegacyBootEvent);
241     gBS->CloseEvent (LegacyBootEvent);
242   }
243 }
244 
245 
246 /**
247   Check to see if the Firmware Volume (FV) Media Device Path is valid
248 
249   Tiano extended the EFI 1.10 device path nodes. Tiano does not own this enum
250   so as we move to UEFI 2.0 support we must use a mechanism that conforms with
251   the UEFI 2.0 specification to define the FV device path. An UEFI GUIDed
252   device path is defined for Tiano extensions of device path. If the code
253   is compiled to conform with the UEFI 2.0 specification use the new device path
254   else use the old form for backwards compatability. The return value to this
255   function points to a location in FvDevicePathNode and it does not allocate
256   new memory for the GUID pointer that is returned.
257 
258   @param  FvDevicePathNode  Pointer to FV device path to check.
259 
260   @retval NULL              FvDevicePathNode is not valid.
261   @retval Other             FvDevicePathNode is valid and pointer to NameGuid was returned.
262 
263 **/
264 EFI_GUID *
265 EFIAPI
EfiGetNameGuidFromFwVolDevicePathNode(IN CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH * FvDevicePathNode)266 EfiGetNameGuidFromFwVolDevicePathNode (
267   IN CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  *FvDevicePathNode
268   )
269 {
270   ASSERT (FvDevicePathNode != NULL);
271 
272   //
273   // EFI Specification extension on Media Device Path. MEDIA_FW_VOL_FILEPATH_DEVICE_PATH is adopted by UEFI later and added in UEFI2.10.
274   // In EdkCompatibility Package, we only support MEDIA_FW_VOL_FILEPATH_DEVICE_PATH that complies with
275   // EFI 1.10 and UEFI 2.10.
276   //
277   if (DevicePathType (&FvDevicePathNode->Header) == MEDIA_DEVICE_PATH &&
278       DevicePathSubType (&FvDevicePathNode->Header) == MEDIA_PIWG_FW_FILE_DP) {
279     return (EFI_GUID *) &FvDevicePathNode->FvFileName;
280   }
281 
282   return NULL;
283 }
284 
285 
286 /**
287   Initialize a Firmware Volume (FV) Media Device Path node.
288 
289   Tiano extended the EFI 1.10 device path nodes. Tiano does not own this enum
290   so as we move to UEFI 2.0 support we must use a mechanism that conforms with
291   the UEFI 2.0 specification to define the FV device path. An UEFI GUIDed
292   device path is defined for Tiano extensions of device path. If the code
293   is compiled to conform with the UEFI 2.0 specification use the new device path
294   else use the old form for backwards compatability.
295 
296   @param  FvDevicePathNode  Pointer to a FV device path node to initialize
297   @param  NameGuid          FV file name to use in FvDevicePathNode
298 
299 **/
300 VOID
301 EFIAPI
EfiInitializeFwVolDevicepathNode(IN OUT MEDIA_FW_VOL_FILEPATH_DEVICE_PATH * FvDevicePathNode,IN CONST EFI_GUID * NameGuid)302 EfiInitializeFwVolDevicepathNode (
303   IN OUT MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  *FvDevicePathNode,
304   IN CONST EFI_GUID                         *NameGuid
305   )
306 {
307   ASSERT (FvDevicePathNode  != NULL);
308   ASSERT (NameGuid          != NULL);
309 
310   //
311   // EFI Specification extension on Media Device Path. MEDIA_FW_VOL_FILEPATH_DEVICE_PATH is adopted by UEFI later and added in UEFI2.10.
312   // In EdkCompatibility Package, we only support MEDIA_FW_VOL_FILEPATH_DEVICE_PATH that complies with
313   // EFI 1.10 and UEFI 2.10.
314   //
315   FvDevicePathNode->Header.Type     = MEDIA_DEVICE_PATH;
316   FvDevicePathNode->Header.SubType  = MEDIA_PIWG_FW_FILE_DP;
317   SetDevicePathNodeLength (&FvDevicePathNode->Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH));
318 
319   CopyGuid (&FvDevicePathNode->FvFileName, NameGuid);
320 }
321 
322