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 UnicodeStrToAsciiStr (FileEntry
->Info
->FileName
, OpenFileAsciiFileName
);
102 AsciiFileNameToCompare
= OpenFileAsciiFileName
;
104 AsciiFileNameToCompare
= FileEntry
->HwDescription
.Footer
.Filename
;
107 if (AsciiStrCmp (AsciiFileNameToCompare
, AsciiFileName
) == 0) {
112 return EFI_NOT_FOUND
;
116 BootMonGetFileFromPosition (
117 IN BOOTMON_FS_INSTANCE
*Instance
,
119 OUT BOOTMON_FS_FILE
**File
123 BOOTMON_FS_FILE
*FileEntry
;
125 // Go through all the files in the list and return the file handle
126 for (Entry
= GetFirstNode (&Instance
->RootFile
->Link
);
127 !IsNull (&Instance
->RootFile
->Link
, Entry
) && (&Instance
->RootFile
->Link
!= Entry
);
128 Entry
= GetNextNode (&Instance
->RootFile
->Link
, Entry
)
132 FileEntry
= BOOTMON_FS_FILE_FROM_LINK_THIS (Entry
);
138 return EFI_NOT_FOUND
;
142 BootMonFsCreateFile (
143 IN BOOTMON_FS_INSTANCE
*Instance
,
144 OUT BOOTMON_FS_FILE
**File
147 BOOTMON_FS_FILE
*NewFile
;
149 NewFile
= (BOOTMON_FS_FILE
*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE
));
150 if (NewFile
== NULL
) {
151 return EFI_OUT_OF_RESOURCES
;
154 NewFile
->Signature
= BOOTMON_FS_FILE_SIGNATURE
;
155 InitializeListHead (&NewFile
->Link
);
156 InitializeListHead (&NewFile
->RegionToFlushLink
);
157 NewFile
->Instance
= Instance
;
159 // If the created file is the root file then create a directory EFI_FILE_PROTOCOL
160 if (Instance
->RootFile
== *File
) {
161 CopyMem (&NewFile
->File
, &mBootMonFsRootTemplate
, sizeof (mBootMonFsRootTemplate
));
163 CopyMem (&NewFile
->File
, &mBootMonFsFileTemplate
, sizeof (mBootMonFsFileTemplate
));
171 SupportedDevicePathsInit (
176 CHAR16
* DevicePathListStr
;
177 CHAR16
* DevicePathStr
;
178 CHAR16
* NextDevicePathStr
;
179 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
*EfiDevicePathFromTextProtocol
;
180 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
182 Status
= gBS
->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid
, NULL
, (VOID
**)&EfiDevicePathFromTextProtocol
);
183 ASSERT_EFI_ERROR (Status
);
185 // Initialize Variable
186 DevicePathListStr
= (CHAR16
*)PcdGetPtr (PcdBootMonFsSupportedDevicePaths
);
187 mBootMonFsSupportedDevicePaths
= NULL
;
189 // Extract the Device Path instances from the multi-device path string
190 while ((DevicePathListStr
!= NULL
) && (DevicePathListStr
[0] != L
'\0')) {
191 NextDevicePathStr
= StrStr (DevicePathListStr
, L
";");
192 if (NextDevicePathStr
== NULL
) {
193 DevicePathStr
= DevicePathListStr
;
194 DevicePathListStr
= NULL
;
196 DevicePathStr
= (CHAR16
*)AllocateCopyPool ((NextDevicePathStr
- DevicePathListStr
+ 1) * sizeof (CHAR16
), DevicePathListStr
);
197 if (DevicePathStr
== NULL
) {
198 return EFI_OUT_OF_RESOURCES
;
200 *(DevicePathStr
+ (NextDevicePathStr
- DevicePathListStr
)) = L
'\0';
201 DevicePathListStr
= NextDevicePathStr
;
202 if (DevicePathListStr
[0] == L
';') {
207 Instance
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath (DevicePathStr
);
208 ASSERT (Instance
!= NULL
);
209 mBootMonFsSupportedDevicePaths
= AppendDevicePathInstance (mBootMonFsSupportedDevicePaths
, Instance
);
211 if (NextDevicePathStr
!= NULL
) {
212 FreePool (DevicePathStr
);
217 if (mBootMonFsSupportedDevicePaths
== NULL
) {
218 return EFI_UNSUPPORTED
;
226 BootMonFsDriverSupported (
227 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
228 IN EFI_HANDLE ControllerHandle
,
229 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
232 EFI_DISK_IO_PROTOCOL
*DiskIo
;
233 EFI_DEVICE_PATH_PROTOCOL
*DevicePathProtocol
;
234 EFI_DEVICE_PATH_PROTOCOL
*SupportedDevicePath
;
235 EFI_DEVICE_PATH_PROTOCOL
*SupportedDevicePaths
;
241 // Open the IO Abstraction(s) needed to perform the supported test
243 Status
= gBS
->OpenProtocol (
245 &gEfiDiskIoProtocolGuid
,
249 EFI_OPEN_PROTOCOL_BY_DRIVER
252 if (EFI_ERROR (Status
)) {
256 // Close the I/O Abstraction(s) used to perform the supported test
260 &gEfiDiskIoProtocolGuid
,
265 // Check that BlockIo protocol instance exists
266 Status
= gBS
->OpenProtocol (
268 &gEfiBlockIoProtocolGuid
,
272 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
274 if (EFI_ERROR (Status
)) {
278 // Check if a DevicePath is attached to the handle
279 Status
= gBS
->OpenProtocol (
281 &gEfiDevicePathProtocolGuid
,
282 (VOID
**)&DevicePathProtocol
,
285 EFI_OPEN_PROTOCOL_BY_DRIVER
287 if (EFI_ERROR (Status
)) {
291 // Check if the Device Path is the one which contains the Boot Monitor File System
292 Size1
= GetDevicePathSize (DevicePathProtocol
);
294 // Go through the list of Device Path Instances
295 Status
= EFI_UNSUPPORTED
;
296 SupportedDevicePaths
= mBootMonFsSupportedDevicePaths
;
297 while (SupportedDevicePaths
!= NULL
) {
298 SupportedDevicePath
= GetNextDevicePathInstance (&SupportedDevicePaths
, &Size2
);
300 if ((Size1
== Size2
) && (CompareMem (DevicePathProtocol
, SupportedDevicePath
, Size1
) == 0)) {
301 // The Device Path is supported
302 Status
= EFI_SUCCESS
;
307 gBS
->CloseProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
, gImageHandle
, ControllerHandle
);
313 BootMonFsDriverStart (
314 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
315 IN EFI_HANDLE ControllerHandle
,
316 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
319 BOOTMON_FS_INSTANCE
*Instance
;
321 UINTN VolumeNameSize
;
324 Instance
= AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE
));
325 if (Instance
== NULL
) {
326 return EFI_OUT_OF_RESOURCES
;
329 // Initialize the BlockIo of the Instance
330 Status
= gBS
->OpenProtocol (
332 &gEfiBlockIoProtocolGuid
,
333 (VOID
**)&(Instance
->BlockIo
),
336 EFI_OPEN_PROTOCOL_GET_PROTOCOL
338 if (EFI_ERROR (Status
)) {
342 Status
= gBS
->OpenProtocol (
344 &gEfiDiskIoProtocolGuid
,
345 (VOID
**)&(Instance
->DiskIo
),
348 EFI_OPEN_PROTOCOL_BY_DRIVER
350 if (EFI_ERROR (Status
)) {
355 // Initialize the attributes of the Instance
357 Instance
->Signature
= BOOTMON_FS_SIGNATURE
;
358 Instance
->ControllerHandle
= ControllerHandle
;
359 Instance
->Media
= Instance
->BlockIo
->Media
;
360 Instance
->Binding
= DriverBinding
;
362 // Initialize the Simple File System Protocol
363 Instance
->Fs
.Revision
= EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
;
364 Instance
->Fs
.OpenVolume
= OpenBootMonFsOpenVolume
;
366 // Volume name + L' ' + '2' digit number
367 VolumeNameSize
= StrSize (BOOTMON_FS_VOLUME_LABEL
) + (3 * sizeof (CHAR16
));
369 // Initialize FileSystem Information
370 Instance
->FsInfo
.Size
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ VolumeNameSize
;
371 Instance
->FsInfo
.BlockSize
= Instance
->Media
->BlockSize
;
372 Instance
->FsInfo
.ReadOnly
= FALSE
;
373 Instance
->FsInfo
.VolumeSize
=
374 Instance
->Media
->BlockSize
* (Instance
->Media
->LastBlock
- Instance
->Media
->LowestAlignedLba
);
375 CopyMem (Instance
->FsInfo
.VolumeLabel
, BOOTMON_FS_VOLUME_LABEL
, StrSize (BOOTMON_FS_VOLUME_LABEL
));
377 // Initialize the root file
378 Status
= BootMonFsCreateFile (Instance
, &Instance
->RootFile
);
379 if (EFI_ERROR (Status
)) {
383 Info
= AllocateZeroPool (sizeof (EFI_FILE_INFO
));
385 Status
= EFI_OUT_OF_RESOURCES
;
388 Instance
->RootFile
->Info
= Info
;
390 // Initialize the DevicePath of the Instance
391 Status
= gBS
->OpenProtocol (
393 &gEfiDevicePathProtocolGuid
,
394 (VOID
**)&(Instance
->DevicePath
),
397 EFI_OPEN_PROTOCOL_GET_PROTOCOL
399 if (EFI_ERROR (Status
)) {
404 // Install the Simple File System Protocol
406 Status
= gBS
->InstallMultipleProtocolInterfaces (
408 &gEfiSimpleFileSystemProtocolGuid
, &Instance
->Fs
,
411 if (EFI_ERROR (Status
)) {
415 InsertTailList (&mInstances
, &Instance
->Link
);
421 if (Instance
->RootFile
!= NULL
) {
422 if (Instance
->RootFile
->Info
!= NULL
) {
423 FreePool (Instance
->RootFile
->Info
);
425 FreePool (Instance
->RootFile
);
435 BootMonFsDriverStop (
436 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
437 IN EFI_HANDLE ControllerHandle
,
438 IN UINTN NumberOfChildren
,
439 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
442 BOOTMON_FS_INSTANCE
*Instance
;
445 BOOLEAN InstanceFound
;
447 // Find instance from ControllerHandle.
449 InstanceFound
= FALSE
;
450 // For each instance in mInstances:
451 for (Link
= GetFirstNode (&mInstances
); !IsNull (&mInstances
, Link
); Link
= GetNextNode (&mInstances
, Link
)) {
452 Instance
= BOOTMON_FS_FROM_LINK (Link
);
454 if (Instance
->ControllerHandle
== ControllerHandle
) {
455 InstanceFound
= TRUE
;
459 ASSERT (InstanceFound
== TRUE
);
463 &gEfiDevicePathProtocolGuid
,
464 DriverBinding
->ImageHandle
,
469 &gEfiDiskIoProtocolGuid
,
470 DriverBinding
->ImageHandle
,
475 &gEfiBlockIoProtocolGuid
,
476 DriverBinding
->ImageHandle
,
479 Status
= gBS
->UninstallMultipleProtocolInterfaces (
481 &gEfiSimpleFileSystemProtocolGuid
, &Instance
->Fs
,
484 FreePool (Instance
->RootFile
->Info
);
485 FreePool (Instance
->RootFile
);
492 // Simple Network Protocol Driver Global Variables
494 EFI_DRIVER_BINDING_PROTOCOL mBootMonFsDriverBinding
= {
495 BootMonFsDriverSupported
,
496 BootMonFsDriverStart
,
505 BootMonFsEntryPoint (
506 IN EFI_HANDLE ImageHandle
,
507 IN EFI_SYSTEM_TABLE
*SystemTable
512 InitializeListHead (&mInstances
);
514 // Initialize the list of Device Paths that could support BootMonFs
515 Status
= SupportedDevicePathsInit ();
516 if (!EFI_ERROR (Status
)) {
517 Status
= gBS
->InstallMultipleProtocolInterfaces (
519 &gEfiDriverBindingProtocolGuid
, &mBootMonFsDriverBinding
,
522 ASSERT_EFI_ERROR (Status
);
524 DEBUG((EFI_D_ERROR
,"Warning: No Device Paths supporting BootMonFs have been defined in the PCD.\n"));