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
;
118 Root
->FvFileInfo
->FileInfo
.Size
= sizeof (EFI_FILE_INFO
);
119 Root
->FvFileInfo
->FileInfo
.Attribute
= EFI_FILE_DIRECTORY
| EFI_FILE_READ_ONLY
;
122 // Populate the instance's list of files. We consider anything a file that
123 // has a UI_SECTION, which we consider to be its filename.
125 FvProtocol
= Instance
->FvProtocol
;
132 FileType
= EFI_FV_FILETYPE_ALL
;
134 Status
= FvProtocol
->GetNextFile (
142 if (EFI_ERROR (Status
)) {
143 ASSERT (Status
== EFI_NOT_FOUND
);
148 // Get a file's name: If it has a UI section, use that, otherwise use
152 Status
= FvProtocol
->ReadSection (
155 EFI_SECTION_USER_INTERFACE
,
161 if (!EFI_ERROR (Status
)) {
164 Name
= AllocateZeroPool (GUID_STRING_SIZE
);
166 return EFI_OUT_OF_RESOURCES
;
168 NumChars
= UnicodeSPrint (Name
, GUID_STRING_SIZE
, L
"%g", &NameGuid
);
169 ASSERT ((NumChars
+ 1) * sizeof (CHAR16
) == GUID_STRING_SIZE
);
174 // Allocate a file structure and populate it.
176 NameLen
= StrSize (Name
);
177 if (FV_FILETYPE_IS_EXECUTABLE (FileType
)) {
178 NameLen
+= StrSize (L
".efi") - sizeof (CHAR16
);
181 FvFileInfo
= AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO
) + NameLen
- sizeof (CHAR16
));
182 if (FvFileInfo
== NULL
) {
183 return EFI_OUT_OF_RESOURCES
;
186 FvFileInfo
->Signature
= FVFS_FILE_INFO_SIGNATURE
;
187 InitializeListHead (&FvFileInfo
->Link
);
188 CopyMem (&FvFileInfo
->NameGuid
, &NameGuid
, sizeof (EFI_GUID
));
189 FvFileInfo
->Type
= FileType
;
192 // Add ".efi" to filenames of drivers and applications.
194 DestMax
= NameLen
/ sizeof (CHAR16
);
195 Status
= StrnCpyS (&FvFileInfo
->FileInfo
.FileName
[0], DestMax
, Name
, StrLen (Name
));
196 ASSERT_EFI_ERROR (Status
);
198 if (FV_FILETYPE_IS_EXECUTABLE (FileType
)) {
199 Status
= StrnCatS (&FvFileInfo
->FileInfo
.FileName
[0], DestMax
, L
".efi", StrLen (L
".efi"));
200 ASSERT_EFI_ERROR (Status
);
203 FvFileInfo
->FileInfo
.Size
= sizeof (EFI_FILE_INFO
) + NameLen
- sizeof (CHAR16
);
204 Status
= FvFsGetFileSize (FvProtocol
, FvFileInfo
);
205 ASSERT_EFI_ERROR (Status
);
206 FvFileInfo
->FileInfo
.PhysicalSize
= FvFileInfo
->FileInfo
.FileSize
;
207 FvFileInfo
->FileInfo
.Attribute
= EFI_FILE_READ_ONLY
;
209 InsertHeadList (&Instance
->FileInfoHead
, &FvFileInfo
->Link
);
215 if (Status
== EFI_NOT_FOUND
) {
216 Status
= EFI_SUCCESS
;
220 Instance
->Root
->DirReadNext
= NULL
;
221 if (!IsListEmpty (&Instance
->FileInfoHead
)) {
222 Instance
->Root
->DirReadNext
= FVFS_GET_FIRST_FILE_INFO (Instance
);
225 *RootFile
= &Instance
->Root
->FileProtocol
;
230 Worker function to initialize Unicode Collation support.
232 It tries to locate Unicode Collation (2) protocol and matches it with current
233 platform language code.
235 @param AgentHandle The handle used to open Unicode Collation (2) protocol.
236 @param ProtocolGuid The pointer to Unicode Collation (2) protocol GUID.
237 @param VariableName The name of the RFC 4646 or ISO 639-2 language variable.
238 @param DefaultLanguage The default language in case the RFC 4646 or ISO 639-2 language is absent.
240 @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located.
241 @retval Others The Unicode Collation (2) protocol has not been located.
245 InitializeUnicodeCollationSupportWorker (
246 IN EFI_HANDLE AgentHandle
,
247 IN EFI_GUID
*ProtocolGuid
,
248 IN CONST CHAR16
*VariableName
,
249 IN CONST CHAR8
*DefaultLanguage
252 EFI_STATUS ReturnStatus
;
257 EFI_UNICODE_COLLATION_PROTOCOL
*Uci
;
258 BOOLEAN Iso639Language
;
262 Status
= gBS
->LocateHandleBuffer (
269 if (EFI_ERROR (Status
)) {
273 Iso639Language
= (BOOLEAN
) (ProtocolGuid
== &gEfiUnicodeCollationProtocolGuid
);
274 GetEfiGlobalVariable2 (VariableName
, (VOID
**) &Language
, NULL
);
276 ReturnStatus
= EFI_UNSUPPORTED
;
277 for (Index
= 0; Index
< NumHandles
; Index
++) {
279 // Open Unicode Collation Protocol
281 Status
= gBS
->OpenProtocol (
287 EFI_OPEN_PROTOCOL_GET_PROTOCOL
289 if (EFI_ERROR (Status
)) {
294 // Find the best matching matching language from the supported languages
295 // of Unicode Collation (2) protocol.
297 BestLanguage
= GetBestLanguage (
298 Uci
->SupportedLanguages
,
300 (Language
== NULL
) ? "" : Language
,
304 if (BestLanguage
!= NULL
) {
305 FreePool (BestLanguage
);
306 mUnicodeCollation
= Uci
;
307 ReturnStatus
= EFI_SUCCESS
;
312 if (Language
!= NULL
) {
322 Initialize Unicode Collation support.
324 It tries to locate Unicode Collation 2 protocol and matches it with current
325 platform language code. If for any reason the first attempt fails, it then tries to
326 use Unicode Collation Protocol.
328 @param AgentHandle The handle used to open Unicode Collation (2) protocol.
330 @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located.
331 @retval Others The Unicode Collation (2) protocol has not been located.
335 InitializeUnicodeCollationSupport (
336 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
) {
491 // Allocate the volume label
493 Instance
->VolumeLabel
= AllocateZeroPool (FVFS_VOLUME_LABEL_SIZE
);
495 // Check the allocation was successful
497 if (Instance
->VolumeLabel
!= NULL
) {
499 // Extract the FV's guid
501 FvGuid
= &((MEDIA_FW_VOL_DEVICE_PATH
*) FvDevicePath
)->FvName
;
503 // Build the volume label string
505 NumChars
= UnicodeSPrint (
506 Instance
->VolumeLabel
,
507 FVFS_VOLUME_LABEL_SIZE
,
508 FVFS_VOLUME_LABEL_PREFIX L
"%g",
511 ASSERT ((NumChars
+ 1) * sizeof (CHAR16
) == FVFS_VOLUME_LABEL_SIZE
);
515 FvDevicePath
= NextDevicePathNode (FvDevicePath
);
519 // If we didn't decide on a volume label, set a fallback one
521 if (Instance
->VolumeLabel
== NULL
) {
522 Instance
->VolumeLabel
= AllocateCopyPool (
523 sizeof (FVFS_FALLBACK_VOLUME_LABEL
),
524 FVFS_FALLBACK_VOLUME_LABEL
532 Stop this driver on ControllerHandle by removing SimpleFileSystem protocol and closing
533 the FV protocol on ControllerHandle.
535 @param DriverBinding Protocol instance pointer.
536 @param ControllerHandle Handle of device to stop driver on
537 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
538 children is zero stop the entire bus driver.
539 @param ChildHandleBuffer List of Child Handles to Stop.
541 @retval EFI_SUCCESS This driver is removed ControllerHandle
542 @retval other This driver was not removed from this device
547 FvSimpleFileSystemDriverStop (
548 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
549 IN EFI_HANDLE ControllerHandle
,
550 IN UINTN NumberOfChildren
,
551 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
555 FV_FILESYSTEM_INSTANCE
*Instance
;
556 FV_FILESYSTEM_FILE_INFO
*FvFileInfo
;
558 LIST_ENTRY
*DelEntry
;
559 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SimpleFile
;
561 Status
= gBS
->OpenProtocol (
563 &gEfiSimpleFileSystemProtocolGuid
,
564 (VOID
**) &SimpleFile
,
565 DriverBinding
->DriverBindingHandle
,
567 EFI_OPEN_PROTOCOL_GET_PROTOCOL
569 if (EFI_ERROR (Status
)) {
573 Instance
= FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (SimpleFile
);
575 if (IsListEmpty (&Instance
->FileHead
) == FALSE
) {
577 // Not all opened files are closed
579 return EFI_DEVICE_ERROR
;
583 // Close and uninstall protocols.
585 Status
= gBS
->CloseProtocol (
587 &gEfiFirmwareVolume2ProtocolGuid
,
591 ASSERT_EFI_ERROR (Status
);
593 Status
= gBS
->UninstallProtocolInterface (
595 &gEfiSimpleFileSystemProtocolGuid
,
598 ASSERT_EFI_ERROR (Status
);
601 // Free file structures
603 if (!IsListEmpty (&Instance
->FileInfoHead
)) {
605 // Free the Subtask list.
607 for(Entry
= Instance
->FileInfoHead
.ForwardLink
;
608 Entry
!= (&Instance
->FileInfoHead
);
611 Entry
= Entry
->ForwardLink
;
612 FvFileInfo
= FVFS_FILE_INFO_FROM_LINK (DelEntry
);
614 RemoveEntryList (DelEntry
);
615 FreePool (FvFileInfo
);
619 if (Instance
->Root
!= NULL
) {
621 // Root->Name is statically allocated, no need to free.
623 if (Instance
->Root
->FvFileInfo
!= NULL
) {
624 FreePool (Instance
->Root
->FvFileInfo
);
626 FreePool (Instance
->Root
);
632 if (Instance
->VolumeLabel
!= NULL
) {
633 FreePool (Instance
->VolumeLabel
);
641 The user Entry Point for module FvSimpleFileSystem. The user code starts with this function.
643 @param[in] ImageHandle The firmware allocated handle for the EFI image.
644 @param[in] SystemTable A pointer to the EFI System Table.
646 @retval EFI_SUCCESS The entry point is executed successfully.
647 @retval other Some error occurs when executing this entry point.
652 FvSimpleFileSystemEntryPoint (
653 IN EFI_HANDLE ImageHandle
,
654 IN EFI_SYSTEM_TABLE
*SystemTable
660 // Install driver model protocol(s).
662 Status
= EfiLibInstallDriverBindingComponentName2 (
667 &gFvSimpleFileSystemComponentName
,
668 &gFvSimpleFileSystemComponentName2
670 ASSERT_EFI_ERROR (Status
);