2 This driver uses the EFI_FIRMWARE_VOLUME2_PROTOCOL to expose files in firmware
3 volumes via the the EFI_SIMPLE_FILESYSTEM_PROTOCOL and EFI_FILE_PROTOCOL.
5 It will expose a single directory, containing one file for each file in the firmware
6 volume. If a file has a UI section, its contents will be used as a filename.
7 Otherwise, a string representation of the GUID will be used.
8 Files of an executable type (That is PEIM, DRIVER, COMBINED_PEIM_DRIVER and APPLICATION)
9 will have ".efi" added to their filename.
11 Its primary intended use is to be able to start EFI applications embedded in FVs
12 from the UEFI shell. It is entirely read-only.
14 Copyright (c) 2014, ARM Limited. All rights reserved.
15 Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
17 SPDX-License-Identifier: BSD-2-Clause-Patent
21 #include "FvSimpleFileSystemInternal.h"
23 EFI_UNICODE_COLLATION_PROTOCOL
*mUnicodeCollation
= NULL
;
26 // A Guid string is 32 hex characters with 4 hyphens and a NULL-terminated char: 37 characters total
28 #define GUID_STRING_SIZE (37 * sizeof (CHAR16))
30 #define FVFS_VOLUME_LABEL_PREFIX L"Firmware Volume: "
31 #define FVFS_VOLUME_LABEL_SIZE (sizeof (FVFS_VOLUME_LABEL_PREFIX) + GUID_STRING_SIZE - sizeof (CHAR16))
32 #define FVFS_FALLBACK_VOLUME_LABEL L"Firmware Volume"
35 // Template for EFI_SIMPLE_FILE_SYSTEM_PROTOCOL data structure.
37 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mSimpleFsTemplate
= {
38 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
,
39 FvSimpleFileSystemOpenVolume
43 // Template for EFI_DRIVER_BINDING_PROTOCOL data structure.
45 EFI_DRIVER_BINDING_PROTOCOL mDriverBinding
= {
46 FvSimpleFileSystemDriverSupported
,
47 FvSimpleFileSystemDriverStart
,
48 FvSimpleFileSystemDriverStop
,
55 Open the root directory on a volume.
57 @param This A pointer to the volume to open the root directory.
58 @param RootFile A pointer to the location to return the opened file handle for the
61 @retval EFI_SUCCESS The device was opened.
62 @retval EFI_UNSUPPORTED This volume does not support the requested file system type.
63 @retval EFI_NO_MEDIA The device has no medium.
64 @retval EFI_DEVICE_ERROR The device reported an error.
65 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
66 @retval EFI_ACCESS_DENIED The service denied access to the file.
67 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
68 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no
69 longer supported. Any existing file handles for this volume are
70 no longer valid. To access the files on the new medium, the
71 volume must be reopened with OpenVolume().
76 FvSimpleFileSystemOpenVolume (
77 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
78 OUT EFI_FILE_PROTOCOL
**RootFile
82 FV_FILESYSTEM_FILE
*Root
;
85 EFI_FV_FILE_ATTRIBUTES Attributes
;
86 UINT32 Authentication
;
88 EFI_FV_FILETYPE FileType
;
90 FV_FILESYSTEM_INSTANCE
*Instance
;
91 FV_FILESYSTEM_FILE_INFO
*FvFileInfo
;
92 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvProtocol
;
98 Instance
= FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (This
);
101 if (Instance
->Root
== NULL
) {
103 // Allocate file structure for root file
105 Root
= AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE
));
107 return EFI_OUT_OF_RESOURCES
;
110 Instance
->Root
= Root
;
111 Root
->Instance
= Instance
;
112 Root
->Signature
= FVFS_FILE_SIGNATURE
;
113 CopyMem (&Root
->FileProtocol
, &mFileSystemTemplate
, sizeof (mFileSystemTemplate
));
114 Root
->FvFileInfo
= AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO
));
115 if (Root
->FvFileInfo
== NULL
) {
116 return EFI_OUT_OF_RESOURCES
;
119 Root
->FvFileInfo
->FileInfo
.Size
= sizeof (EFI_FILE_INFO
);
120 Root
->FvFileInfo
->FileInfo
.Attribute
= EFI_FILE_DIRECTORY
| EFI_FILE_READ_ONLY
;
123 // Populate the instance's list of files. We consider anything a file that
124 // has a UI_SECTION, which we consider to be its filename.
126 FvProtocol
= Instance
->FvProtocol
;
133 FileType
= EFI_FV_FILETYPE_ALL
;
135 Status
= FvProtocol
->GetNextFile (
143 if (EFI_ERROR (Status
)) {
144 ASSERT (Status
== EFI_NOT_FOUND
);
149 // Get a file's name: If it has a UI section, use that, otherwise use
153 Status
= FvProtocol
->ReadSection (
156 EFI_SECTION_USER_INTERFACE
,
162 if (!EFI_ERROR (Status
)) {
165 Name
= AllocateZeroPool (GUID_STRING_SIZE
);
167 return EFI_OUT_OF_RESOURCES
;
170 NumChars
= UnicodeSPrint (Name
, GUID_STRING_SIZE
, L
"%g", &NameGuid
);
171 ASSERT ((NumChars
+ 1) * sizeof (CHAR16
) == GUID_STRING_SIZE
);
176 // Allocate a file structure and populate it.
178 NameLen
= StrSize (Name
);
179 if (FV_FILETYPE_IS_EXECUTABLE (FileType
)) {
180 NameLen
+= StrSize (L
".efi") - sizeof (CHAR16
);
183 FvFileInfo
= AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO
) + NameLen
- sizeof (CHAR16
));
184 if (FvFileInfo
== NULL
) {
185 return EFI_OUT_OF_RESOURCES
;
188 FvFileInfo
->Signature
= FVFS_FILE_INFO_SIGNATURE
;
189 InitializeListHead (&FvFileInfo
->Link
);
190 CopyMem (&FvFileInfo
->NameGuid
, &NameGuid
, sizeof (EFI_GUID
));
191 FvFileInfo
->Type
= FileType
;
194 // Add ".efi" to filenames of drivers and applications.
196 DestMax
= NameLen
/ sizeof (CHAR16
);
197 Status
= StrnCpyS (&FvFileInfo
->FileInfo
.FileName
[0], DestMax
, Name
, StrLen (Name
));
198 ASSERT_EFI_ERROR (Status
);
200 if (FV_FILETYPE_IS_EXECUTABLE (FileType
)) {
201 Status
= StrnCatS (&FvFileInfo
->FileInfo
.FileName
[0], DestMax
, L
".efi", StrLen (L
".efi"));
202 ASSERT_EFI_ERROR (Status
);
205 FvFileInfo
->FileInfo
.Size
= sizeof (EFI_FILE_INFO
) + NameLen
- sizeof (CHAR16
);
206 Status
= FvFsGetFileSize (FvProtocol
, FvFileInfo
);
207 ASSERT_EFI_ERROR (Status
);
208 FvFileInfo
->FileInfo
.PhysicalSize
= FvFileInfo
->FileInfo
.FileSize
;
209 FvFileInfo
->FileInfo
.Attribute
= EFI_FILE_READ_ONLY
;
211 InsertHeadList (&Instance
->FileInfoHead
, &FvFileInfo
->Link
);
216 if (Status
== EFI_NOT_FOUND
) {
217 Status
= EFI_SUCCESS
;
221 Instance
->Root
->DirReadNext
= NULL
;
222 if (!IsListEmpty (&Instance
->FileInfoHead
)) {
223 Instance
->Root
->DirReadNext
= FVFS_GET_FIRST_FILE_INFO (Instance
);
226 *RootFile
= &Instance
->Root
->FileProtocol
;
231 Worker function to initialize Unicode Collation support.
233 It tries to locate Unicode Collation (2) protocol and matches it with current
234 platform language code.
236 @param AgentHandle The handle used to open Unicode Collation (2) protocol.
237 @param ProtocolGuid The pointer to Unicode Collation (2) protocol GUID.
238 @param VariableName The name of the RFC 4646 or ISO 639-2 language variable.
239 @param DefaultLanguage The default language in case the RFC 4646 or ISO 639-2 language is absent.
241 @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located.
242 @retval Others The Unicode Collation (2) protocol has not been located.
246 InitializeUnicodeCollationSupportWorker (
247 IN EFI_HANDLE AgentHandle
,
248 IN EFI_GUID
*ProtocolGuid
,
249 IN CONST CHAR16
*VariableName
,
250 IN CONST CHAR8
*DefaultLanguage
253 EFI_STATUS ReturnStatus
;
258 EFI_UNICODE_COLLATION_PROTOCOL
*Uci
;
259 BOOLEAN Iso639Language
;
263 Status
= gBS
->LocateHandleBuffer (
270 if (EFI_ERROR (Status
)) {
274 Iso639Language
= (BOOLEAN
)(ProtocolGuid
== &gEfiUnicodeCollationProtocolGuid
);
275 GetEfiGlobalVariable2 (VariableName
, (VOID
**)&Language
, NULL
);
277 ReturnStatus
= EFI_UNSUPPORTED
;
278 for (Index
= 0; Index
< NumHandles
; Index
++) {
280 // Open Unicode Collation Protocol
282 Status
= gBS
->OpenProtocol (
288 EFI_OPEN_PROTOCOL_GET_PROTOCOL
290 if (EFI_ERROR (Status
)) {
295 // Find the best matching matching language from the supported languages
296 // of Unicode Collation (2) protocol.
298 BestLanguage
= GetBestLanguage (
299 Uci
->SupportedLanguages
,
301 (Language
== NULL
) ? "" : Language
,
305 if (BestLanguage
!= NULL
) {
306 FreePool (BestLanguage
);
307 mUnicodeCollation
= Uci
;
308 ReturnStatus
= EFI_SUCCESS
;
313 if (Language
!= NULL
) {
323 Initialize Unicode Collation support.
325 It tries to locate Unicode Collation 2 protocol and matches it with current
326 platform language code. If for any reason the first attempt fails, it then tries to
327 use Unicode Collation Protocol.
329 @param AgentHandle The handle used to open Unicode Collation (2) protocol.
331 @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located.
332 @retval Others The Unicode Collation (2) protocol has not been located.
336 InitializeUnicodeCollationSupport (
337 IN EFI_HANDLE AgentHandle
342 Status
= EFI_UNSUPPORTED
;
345 // First try to use RFC 4646 Unicode Collation 2 Protocol.
347 Status
= InitializeUnicodeCollationSupportWorker (
349 &gEfiUnicodeCollation2ProtocolGuid
,
351 (CONST CHAR8
*)PcdGetPtr (PcdUefiVariableDefaultPlatformLang
)
354 // If the attempt to use Unicode Collation 2 Protocol fails, then we fall back
355 // on the ISO 639-2 Unicode Collation Protocol.
357 if (EFI_ERROR (Status
)) {
358 Status
= InitializeUnicodeCollationSupportWorker (
360 &gEfiUnicodeCollationProtocolGuid
,
362 (CONST CHAR8
*)PcdGetPtr (PcdUefiVariableDefaultLang
)
370 Test to see if this driver supports ControllerHandle.
372 @param DriverBinding Protocol instance pointer.
373 @param ControllerHandle Handle of device to test
374 @param RemainingDevicePath Optional parameter use to pick a specific child
377 @retval EFI_SUCCESS This driver supports this device
378 @retval EFI_ALREADY_STARTED This driver is already running on this device
379 @retval other This driver does not support this device
384 FvSimpleFileSystemDriverSupported (
385 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
386 IN EFI_HANDLE ControllerHandle
,
387 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
390 return gBS
->OpenProtocol (
392 &gEfiFirmwareVolume2ProtocolGuid
,
396 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
401 Start this driver on ControllerHandle by opening a FV protocol and
402 installing a SimpleFileSystem protocol on ControllerHandle.
404 @param DriverBinding Protocol instance pointer.
405 @param ControllerHandle Handle of device to bind driver to
406 @param RemainingDevicePath Optional parameter use to pick a specific child
409 @retval EFI_SUCCESS This driver is added to ControllerHandle
410 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
411 @retval other This driver does not support this device
416 FvSimpleFileSystemDriverStart (
417 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
418 IN EFI_HANDLE ControllerHandle
,
419 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
423 EFI_FIRMWARE_VOLUME2_PROTOCOL
*FvProtocol
;
424 FV_FILESYSTEM_INSTANCE
*Instance
;
425 EFI_DEVICE_PATH_PROTOCOL
*FvDevicePath
;
429 Status
= InitializeUnicodeCollationSupport (DriverBinding
->DriverBindingHandle
);
430 if (EFI_ERROR (Status
)) {
437 Status
= gBS
->OpenProtocol (
439 &gEfiFirmwareVolume2ProtocolGuid
,
440 (VOID
**)&FvProtocol
,
443 EFI_OPEN_PROTOCOL_BY_DRIVER
445 if (EFI_ERROR (Status
)) {
450 // Create an instance
452 Instance
= AllocateZeroPool (sizeof (FV_FILESYSTEM_INSTANCE
));
453 ASSERT (Instance
!= NULL
);
455 Instance
->Root
= NULL
;
456 Instance
->FvProtocol
= FvProtocol
;
457 Instance
->Signature
= FVFS_INSTANCE_SIGNATURE
;
458 InitializeListHead (&Instance
->FileInfoHead
);
459 InitializeListHead (&Instance
->FileHead
);
460 CopyMem (&Instance
->SimpleFs
, &mSimpleFsTemplate
, sizeof (mSimpleFsTemplate
));
462 Status
= gBS
->InstallProtocolInterface (
464 &gEfiSimpleFileSystemProtocolGuid
,
465 EFI_NATIVE_INTERFACE
,
468 ASSERT_EFI_ERROR (Status
);
471 // Decide on a filesystem volume label, which will include the FV's guid.
472 // Get the device path to find the FV's GUID
474 Instance
->VolumeLabel
= NULL
;
475 Status
= gBS
->OpenProtocol (
477 &gEfiDevicePathProtocolGuid
,
478 (VOID
**)&FvDevicePath
,
481 EFI_OPEN_PROTOCOL_GET_PROTOCOL
483 if (!EFI_ERROR (Status
)) {
485 // Iterate over device path until we find a firmware volume node
487 while (!IsDevicePathEndType (FvDevicePath
)) {
488 if ((DevicePathType (FvDevicePath
) == MEDIA_DEVICE_PATH
) &&
489 (DevicePathSubType (FvDevicePath
) == MEDIA_PIWG_FW_VOL_DP
))
492 // Allocate the volume label
494 Instance
->VolumeLabel
= AllocateZeroPool (FVFS_VOLUME_LABEL_SIZE
);
496 // Check the allocation was successful
498 if (Instance
->VolumeLabel
!= NULL
) {
500 // Extract the FV's guid
502 FvGuid
= &((MEDIA_FW_VOL_DEVICE_PATH
*)FvDevicePath
)->FvName
;
504 // Build the volume label string
506 NumChars
= UnicodeSPrint (
507 Instance
->VolumeLabel
,
508 FVFS_VOLUME_LABEL_SIZE
,
509 FVFS_VOLUME_LABEL_PREFIX L
"%g",
512 ASSERT ((NumChars
+ 1) * sizeof (CHAR16
) == FVFS_VOLUME_LABEL_SIZE
);
518 FvDevicePath
= NextDevicePathNode (FvDevicePath
);
523 // If we didn't decide on a volume label, set a fallback one
525 if (Instance
->VolumeLabel
== NULL
) {
526 Instance
->VolumeLabel
= AllocateCopyPool (
527 sizeof (FVFS_FALLBACK_VOLUME_LABEL
),
528 FVFS_FALLBACK_VOLUME_LABEL
536 Stop this driver on ControllerHandle by removing SimpleFileSystem protocol and closing
537 the FV protocol on ControllerHandle.
539 @param DriverBinding Protocol instance pointer.
540 @param ControllerHandle Handle of device to stop driver on
541 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
542 children is zero stop the entire bus driver.
543 @param ChildHandleBuffer List of Child Handles to Stop.
545 @retval EFI_SUCCESS This driver is removed ControllerHandle
546 @retval other This driver was not removed from this device
551 FvSimpleFileSystemDriverStop (
552 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
553 IN EFI_HANDLE ControllerHandle
,
554 IN UINTN NumberOfChildren
,
555 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
559 FV_FILESYSTEM_INSTANCE
*Instance
;
560 FV_FILESYSTEM_FILE_INFO
*FvFileInfo
;
562 LIST_ENTRY
*DelEntry
;
563 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SimpleFile
;
565 Status
= gBS
->OpenProtocol (
567 &gEfiSimpleFileSystemProtocolGuid
,
568 (VOID
**)&SimpleFile
,
569 DriverBinding
->DriverBindingHandle
,
571 EFI_OPEN_PROTOCOL_GET_PROTOCOL
573 if (EFI_ERROR (Status
)) {
577 Instance
= FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (SimpleFile
);
579 if (IsListEmpty (&Instance
->FileHead
) == FALSE
) {
581 // Not all opened files are closed
583 return EFI_DEVICE_ERROR
;
587 // Close and uninstall protocols.
589 Status
= gBS
->CloseProtocol (
591 &gEfiFirmwareVolume2ProtocolGuid
,
595 ASSERT_EFI_ERROR (Status
);
597 Status
= gBS
->UninstallProtocolInterface (
599 &gEfiSimpleFileSystemProtocolGuid
,
602 ASSERT_EFI_ERROR (Status
);
605 // Free file structures
607 if (!IsListEmpty (&Instance
->FileInfoHead
)) {
609 // Free the Subtask list.
611 for (Entry
= Instance
->FileInfoHead
.ForwardLink
;
612 Entry
!= (&Instance
->FileInfoHead
);
616 Entry
= Entry
->ForwardLink
;
617 FvFileInfo
= FVFS_FILE_INFO_FROM_LINK (DelEntry
);
619 RemoveEntryList (DelEntry
);
620 FreePool (FvFileInfo
);
624 if (Instance
->Root
!= NULL
) {
626 // Root->Name is statically allocated, no need to free.
628 if (Instance
->Root
->FvFileInfo
!= NULL
) {
629 FreePool (Instance
->Root
->FvFileInfo
);
632 FreePool (Instance
->Root
);
638 if (Instance
->VolumeLabel
!= NULL
) {
639 FreePool (Instance
->VolumeLabel
);
648 The user Entry Point for module FvSimpleFileSystem. The user code starts with this function.
650 @param[in] ImageHandle The firmware allocated handle for the EFI image.
651 @param[in] SystemTable A pointer to the EFI System Table.
653 @retval EFI_SUCCESS The entry point is executed successfully.
654 @retval other Some error occurs when executing this entry point.
659 FvSimpleFileSystemEntryPoint (
660 IN EFI_HANDLE ImageHandle
,
661 IN EFI_SYSTEM_TABLE
*SystemTable
667 // Install driver model protocol(s).
669 Status
= EfiLibInstallDriverBindingComponentName2 (
674 &gFvSimpleFileSystemComponentName
,
675 &gFvSimpleFileSystemComponentName2
677 ASSERT_EFI_ERROR (Status
);