3 * Copyright (c) 2012-2014, ARM Limited. All rights reserved.
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DevicePathLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/PrintLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
21 #include <Protocol/DevicePathFromText.h>
22 #include <Protocol/DriverBinding.h>
24 #include "BootMonFsInternal.h"
26 EFI_DEVICE_PATH
* mBootMonFsSupportedDevicePaths
;
27 LIST_ENTRY mInstances
;
29 EFI_FILE_PROTOCOL mBootMonFsRootTemplate
= {
30 EFI_FILE_PROTOCOL_REVISION
,
34 BootMonFsReadDirectory
,
36 BootMonFsGetPositionUnsupported
, // UEFI Spec: GetPosition not valid on dirs
37 BootMonFsSetDirPosition
,
40 BootMonFsFlushDirectory
43 EFI_FILE_PROTOCOL mBootMonFsFileTemplate
= {
44 EFI_FILE_PROTOCOL_REVISION
,
58 Search for a file given its name coded in Ascii.
60 When searching through the files of the volume, if a file is currently not
61 open, its name was written on the media and is kept in RAM in the
62 "HwDescription.Footer.Filename[]" field of the file's description.
64 If a file is currently open, its name might not have been written on the
65 media yet, and as the "HwDescription" is a mirror in RAM of what is on the
66 media the "HwDescription.Footer.Filename[]" might be outdated. In that case,
67 the up to date name of the file is stored in the "Info" field of the file's
70 @param[in] Instance Pointer to the description of the volume in which
71 the file has to be search for.
72 @param[in] AsciiFileName Name of the file.
74 @param[out] File Pointer to the description of the file if the
77 @retval EFI_SUCCESS The file was found.
78 @retval EFI_NOT_FOUND The file was not found.
82 BootMonGetFileFromAsciiFileName (
83 IN BOOTMON_FS_INSTANCE
*Instance
,
84 IN CHAR8
* AsciiFileName
,
85 OUT BOOTMON_FS_FILE
**File
89 BOOTMON_FS_FILE
*FileEntry
;
90 CHAR8 OpenFileAsciiFileName
[MAX_NAME_LENGTH
];
91 CHAR8
*AsciiFileNameToCompare
;
93 // Go through all the files in the list and return the file handle
94 for (Entry
= GetFirstNode (&Instance
->RootFile
->Link
);
95 !IsNull (&Instance
->RootFile
->Link
, Entry
);
96 Entry
= GetNextNode (&Instance
->RootFile
->Link
, Entry
)
99 FileEntry
= BOOTMON_FS_FILE_FROM_LINK_THIS (Entry
);
100 if (FileEntry
->Info
!= NULL
) {
101 UnicodeStrToAsciiStrS (FileEntry
->Info
->FileName
, OpenFileAsciiFileName
,
103 AsciiFileNameToCompare
= OpenFileAsciiFileName
;
105 AsciiFileNameToCompare
= FileEntry
->HwDescription
.Footer
.Filename
;
108 if (AsciiStrCmp (AsciiFileNameToCompare
, AsciiFileName
) == 0) {
113 return EFI_NOT_FOUND
;
117 BootMonGetFileFromPosition (
118 IN BOOTMON_FS_INSTANCE
*Instance
,
120 OUT BOOTMON_FS_FILE
**File
124 BOOTMON_FS_FILE
*FileEntry
;
126 // Go through all the files in the list and return the file handle
127 for (Entry
= GetFirstNode (&Instance
->RootFile
->Link
);
128 !IsNull (&Instance
->RootFile
->Link
, Entry
) && (&Instance
->RootFile
->Link
!= Entry
);
129 Entry
= GetNextNode (&Instance
->RootFile
->Link
, Entry
)
133 FileEntry
= BOOTMON_FS_FILE_FROM_LINK_THIS (Entry
);
139 return EFI_NOT_FOUND
;
143 BootMonFsCreateFile (
144 IN BOOTMON_FS_INSTANCE
*Instance
,
145 OUT BOOTMON_FS_FILE
**File
148 BOOTMON_FS_FILE
*NewFile
;
150 NewFile
= (BOOTMON_FS_FILE
*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE
));
151 if (NewFile
== NULL
) {
152 return EFI_OUT_OF_RESOURCES
;
155 NewFile
->Signature
= BOOTMON_FS_FILE_SIGNATURE
;
156 InitializeListHead (&NewFile
->Link
);
157 InitializeListHead (&NewFile
->RegionToFlushLink
);
158 NewFile
->Instance
= Instance
;
160 // If the created file is the root file then create a directory EFI_FILE_PROTOCOL
161 if (Instance
->RootFile
== *File
) {
162 CopyMem (&NewFile
->File
, &mBootMonFsRootTemplate
, sizeof (mBootMonFsRootTemplate
));
164 CopyMem (&NewFile
->File
, &mBootMonFsFileTemplate
, sizeof (mBootMonFsFileTemplate
));
172 SupportedDevicePathsInit (
177 CHAR16
* DevicePathListStr
;
178 CHAR16
* DevicePathStr
;
179 CHAR16
* NextDevicePathStr
;
180 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
*EfiDevicePathFromTextProtocol
;
181 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
183 Status
= gBS
->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid
, NULL
, (VOID
**)&EfiDevicePathFromTextProtocol
);
184 ASSERT_EFI_ERROR (Status
);
186 // Initialize Variable
187 DevicePathListStr
= (CHAR16
*)PcdGetPtr (PcdBootMonFsSupportedDevicePaths
);
188 mBootMonFsSupportedDevicePaths
= NULL
;
190 // Extract the Device Path instances from the multi-device path string
191 while ((DevicePathListStr
!= NULL
) && (DevicePathListStr
[0] != L
'\0')) {
192 NextDevicePathStr
= StrStr (DevicePathListStr
, L
";");
193 if (NextDevicePathStr
== NULL
) {
194 DevicePathStr
= DevicePathListStr
;
195 DevicePathListStr
= NULL
;
197 DevicePathStr
= (CHAR16
*)AllocateCopyPool ((NextDevicePathStr
- DevicePathListStr
+ 1) * sizeof (CHAR16
), DevicePathListStr
);
198 if (DevicePathStr
== NULL
) {
199 return EFI_OUT_OF_RESOURCES
;
201 *(DevicePathStr
+ (NextDevicePathStr
- DevicePathListStr
)) = L
'\0';
202 DevicePathListStr
= NextDevicePathStr
;
203 if (DevicePathListStr
[0] == L
';') {
208 Instance
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath (DevicePathStr
);
209 ASSERT (Instance
!= NULL
);
210 mBootMonFsSupportedDevicePaths
= AppendDevicePathInstance (mBootMonFsSupportedDevicePaths
, Instance
);
212 if (NextDevicePathStr
!= NULL
) {
213 FreePool (DevicePathStr
);
218 if (mBootMonFsSupportedDevicePaths
== NULL
) {
219 return EFI_UNSUPPORTED
;
227 BootMonFsDriverSupported (
228 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
229 IN EFI_HANDLE ControllerHandle
,
230 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
233 EFI_DISK_IO_PROTOCOL
*DiskIo
;
234 EFI_DEVICE_PATH_PROTOCOL
*DevicePathProtocol
;
235 EFI_DEVICE_PATH_PROTOCOL
*SupportedDevicePath
;
236 EFI_DEVICE_PATH_PROTOCOL
*SupportedDevicePaths
;
242 // Open the IO Abstraction(s) needed to perform the supported test
244 Status
= gBS
->OpenProtocol (
246 &gEfiDiskIoProtocolGuid
,
250 EFI_OPEN_PROTOCOL_BY_DRIVER
253 if (EFI_ERROR (Status
)) {
257 // Close the I/O Abstraction(s) used to perform the supported test
261 &gEfiDiskIoProtocolGuid
,
266 // Check that BlockIo protocol instance exists
267 Status
= gBS
->OpenProtocol (
269 &gEfiBlockIoProtocolGuid
,
273 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
275 if (EFI_ERROR (Status
)) {
279 // Check if a DevicePath is attached to the handle
280 Status
= gBS
->OpenProtocol (
282 &gEfiDevicePathProtocolGuid
,
283 (VOID
**)&DevicePathProtocol
,
286 EFI_OPEN_PROTOCOL_BY_DRIVER
288 if (EFI_ERROR (Status
)) {
292 // Check if the Device Path is the one which contains the Boot Monitor File System
293 Size1
= GetDevicePathSize (DevicePathProtocol
);
295 // Go through the list of Device Path Instances
296 Status
= EFI_UNSUPPORTED
;
297 SupportedDevicePaths
= mBootMonFsSupportedDevicePaths
;
298 while (SupportedDevicePaths
!= NULL
) {
299 SupportedDevicePath
= GetNextDevicePathInstance (&SupportedDevicePaths
, &Size2
);
301 if ((Size1
== Size2
) && (CompareMem (DevicePathProtocol
, SupportedDevicePath
, Size1
) == 0)) {
302 // The Device Path is supported
303 Status
= EFI_SUCCESS
;
308 gBS
->CloseProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
, gImageHandle
, ControllerHandle
);
314 BootMonFsDriverStart (
315 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
316 IN EFI_HANDLE ControllerHandle
,
317 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
320 BOOTMON_FS_INSTANCE
*Instance
;
322 UINTN VolumeNameSize
;
325 Instance
= AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE
));
326 if (Instance
== NULL
) {
327 return EFI_OUT_OF_RESOURCES
;
330 // Initialize the BlockIo of the Instance
331 Status
= gBS
->OpenProtocol (
333 &gEfiBlockIoProtocolGuid
,
334 (VOID
**)&(Instance
->BlockIo
),
337 EFI_OPEN_PROTOCOL_GET_PROTOCOL
339 if (EFI_ERROR (Status
)) {
343 Status
= gBS
->OpenProtocol (
345 &gEfiDiskIoProtocolGuid
,
346 (VOID
**)&(Instance
->DiskIo
),
349 EFI_OPEN_PROTOCOL_BY_DRIVER
351 if (EFI_ERROR (Status
)) {
356 // Initialize the attributes of the Instance
358 Instance
->Signature
= BOOTMON_FS_SIGNATURE
;
359 Instance
->ControllerHandle
= ControllerHandle
;
360 Instance
->Media
= Instance
->BlockIo
->Media
;
361 Instance
->Binding
= DriverBinding
;
363 // Initialize the Simple File System Protocol
364 Instance
->Fs
.Revision
= EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
;
365 Instance
->Fs
.OpenVolume
= OpenBootMonFsOpenVolume
;
367 // Volume name + L' ' + '2' digit number
368 VolumeNameSize
= StrSize (BOOTMON_FS_VOLUME_LABEL
) + (3 * sizeof (CHAR16
));
370 // Initialize FileSystem Information
371 Instance
->FsInfo
.Size
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ VolumeNameSize
;
372 Instance
->FsInfo
.BlockSize
= Instance
->Media
->BlockSize
;
373 Instance
->FsInfo
.ReadOnly
= FALSE
;
374 Instance
->FsInfo
.VolumeSize
=
375 Instance
->Media
->BlockSize
* (Instance
->Media
->LastBlock
- Instance
->Media
->LowestAlignedLba
);
376 CopyMem (Instance
->FsInfo
.VolumeLabel
, BOOTMON_FS_VOLUME_LABEL
, StrSize (BOOTMON_FS_VOLUME_LABEL
));
378 // Initialize the root file
379 Status
= BootMonFsCreateFile (Instance
, &Instance
->RootFile
);
380 if (EFI_ERROR (Status
)) {
384 Info
= AllocateZeroPool (sizeof (EFI_FILE_INFO
));
386 Status
= EFI_OUT_OF_RESOURCES
;
389 Instance
->RootFile
->Info
= Info
;
391 // Initialize the DevicePath of the Instance
392 Status
= gBS
->OpenProtocol (
394 &gEfiDevicePathProtocolGuid
,
395 (VOID
**)&(Instance
->DevicePath
),
398 EFI_OPEN_PROTOCOL_GET_PROTOCOL
400 if (EFI_ERROR (Status
)) {
405 // Install the Simple File System Protocol
407 Status
= gBS
->InstallMultipleProtocolInterfaces (
409 &gEfiSimpleFileSystemProtocolGuid
, &Instance
->Fs
,
412 if (EFI_ERROR (Status
)) {
416 InsertTailList (&mInstances
, &Instance
->Link
);
422 if (Instance
->RootFile
!= NULL
) {
423 if (Instance
->RootFile
->Info
!= NULL
) {
424 FreePool (Instance
->RootFile
->Info
);
426 FreePool (Instance
->RootFile
);
436 BootMonFsDriverStop (
437 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
438 IN EFI_HANDLE ControllerHandle
,
439 IN UINTN NumberOfChildren
,
440 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
443 BOOTMON_FS_INSTANCE
*Instance
;
446 BOOLEAN InstanceFound
;
448 // Find instance from ControllerHandle.
450 InstanceFound
= FALSE
;
451 // For each instance in mInstances:
452 for (Link
= GetFirstNode (&mInstances
); !IsNull (&mInstances
, Link
); Link
= GetNextNode (&mInstances
, Link
)) {
453 Instance
= BOOTMON_FS_FROM_LINK (Link
);
455 if (Instance
->ControllerHandle
== ControllerHandle
) {
456 InstanceFound
= TRUE
;
460 ASSERT (InstanceFound
== TRUE
);
464 &gEfiDevicePathProtocolGuid
,
465 DriverBinding
->ImageHandle
,
470 &gEfiDiskIoProtocolGuid
,
471 DriverBinding
->ImageHandle
,
476 &gEfiBlockIoProtocolGuid
,
477 DriverBinding
->ImageHandle
,
480 Status
= gBS
->UninstallMultipleProtocolInterfaces (
482 &gEfiSimpleFileSystemProtocolGuid
, &Instance
->Fs
,
485 FreePool (Instance
->RootFile
->Info
);
486 FreePool (Instance
->RootFile
);
493 // Simple Network Protocol Driver Global Variables
495 EFI_DRIVER_BINDING_PROTOCOL mBootMonFsDriverBinding
= {
496 BootMonFsDriverSupported
,
497 BootMonFsDriverStart
,
506 BootMonFsEntryPoint (
507 IN EFI_HANDLE ImageHandle
,
508 IN EFI_SYSTEM_TABLE
*SystemTable
513 InitializeListHead (&mInstances
);
515 // Initialize the list of Device Paths that could support BootMonFs
516 Status
= SupportedDevicePathsInit ();
517 if (!EFI_ERROR (Status
)) {
518 Status
= gBS
->InstallMultipleProtocolInterfaces (
520 &gEfiDriverBindingProtocolGuid
, &mBootMonFsDriverBinding
,
523 ASSERT_EFI_ERROR (Status
);
525 DEBUG((EFI_D_ERROR
,"Warning: No Device Paths supporting BootMonFs have been defined in the PCD.\n"));