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 BootMonGetFileFromAsciiFileName (
59 IN BOOTMON_FS_INSTANCE
*Instance
,
60 IN CHAR8
* AsciiFileName
,
61 OUT BOOTMON_FS_FILE
**File
65 BOOTMON_FS_FILE
*FileEntry
;
67 // Remove the leading '\\'
68 if (*AsciiFileName
== '\\') {
72 // Go through all the files in the list and return the file handle
73 for (Entry
= GetFirstNode (&Instance
->RootFile
->Link
);
74 !IsNull (&Instance
->RootFile
->Link
, Entry
);
75 Entry
= GetNextNode (&Instance
->RootFile
->Link
, Entry
)
78 FileEntry
= BOOTMON_FS_FILE_FROM_LINK_THIS (Entry
);
79 if (AsciiStrCmp (FileEntry
->HwDescription
.Footer
.Filename
, AsciiFileName
) == 0) {
88 BootMonGetFileFromPosition (
89 IN BOOTMON_FS_INSTANCE
*Instance
,
91 OUT BOOTMON_FS_FILE
**File
95 BOOTMON_FS_FILE
*FileEntry
;
97 // Go through all the files in the list and return the file handle
98 for (Entry
= GetFirstNode (&Instance
->RootFile
->Link
);
99 !IsNull (&Instance
->RootFile
->Link
, Entry
) && (&Instance
->RootFile
->Link
!= Entry
);
100 Entry
= GetNextNode (&Instance
->RootFile
->Link
, Entry
)
104 FileEntry
= BOOTMON_FS_FILE_FROM_LINK_THIS (Entry
);
110 return EFI_NOT_FOUND
;
114 BootMonFsCreateFile (
115 IN BOOTMON_FS_INSTANCE
*Instance
,
116 OUT BOOTMON_FS_FILE
**File
119 BOOTMON_FS_FILE
*NewFile
;
121 NewFile
= (BOOTMON_FS_FILE
*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE
));
122 if (NewFile
== NULL
) {
123 return EFI_OUT_OF_RESOURCES
;
126 NewFile
->Signature
= BOOTMON_FS_FILE_SIGNATURE
;
127 InitializeListHead (&NewFile
->Link
);
128 InitializeListHead (&NewFile
->RegionToFlushLink
);
129 NewFile
->Instance
= Instance
;
131 // If the created file is the root file then create a directory EFI_FILE_PROTOCOL
132 if (Instance
->RootFile
== *File
) {
133 CopyMem (&NewFile
->File
, &mBootMonFsRootTemplate
, sizeof (mBootMonFsRootTemplate
));
135 CopyMem (&NewFile
->File
, &mBootMonFsFileTemplate
, sizeof (mBootMonFsFileTemplate
));
143 SupportedDevicePathsInit (
148 CHAR16
* DevicePathListStr
;
149 CHAR16
* DevicePathStr
;
150 CHAR16
* NextDevicePathStr
;
151 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
*EfiDevicePathFromTextProtocol
;
152 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
154 Status
= gBS
->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid
, NULL
, (VOID
**)&EfiDevicePathFromTextProtocol
);
155 ASSERT_EFI_ERROR (Status
);
157 // Initialize Variable
158 DevicePathListStr
= (CHAR16
*)PcdGetPtr (PcdBootMonFsSupportedDevicePaths
);
159 mBootMonFsSupportedDevicePaths
= NULL
;
161 // Extract the Device Path instances from the multi-device path string
162 while ((DevicePathListStr
!= NULL
) && (DevicePathListStr
[0] != L
'\0')) {
163 NextDevicePathStr
= StrStr (DevicePathListStr
, L
";");
164 if (NextDevicePathStr
== NULL
) {
165 DevicePathStr
= DevicePathListStr
;
166 DevicePathListStr
= NULL
;
168 DevicePathStr
= (CHAR16
*)AllocateCopyPool ((NextDevicePathStr
- DevicePathListStr
+ 1) * sizeof (CHAR16
), DevicePathListStr
);
169 if (DevicePathStr
== NULL
) {
170 return EFI_OUT_OF_RESOURCES
;
172 *(DevicePathStr
+ (NextDevicePathStr
- DevicePathListStr
)) = L
'\0';
173 DevicePathListStr
= NextDevicePathStr
;
174 if (DevicePathListStr
[0] == L
';') {
179 Instance
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath (DevicePathStr
);
180 ASSERT (Instance
!= NULL
);
181 mBootMonFsSupportedDevicePaths
= AppendDevicePathInstance (mBootMonFsSupportedDevicePaths
, Instance
);
183 if (NextDevicePathStr
!= NULL
) {
184 FreePool (DevicePathStr
);
189 if (mBootMonFsSupportedDevicePaths
== NULL
) {
190 return EFI_UNSUPPORTED
;
198 BootMonFsDriverSupported (
199 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
200 IN EFI_HANDLE ControllerHandle
,
201 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
204 EFI_DISK_IO_PROTOCOL
*DiskIo
;
205 EFI_DEVICE_PATH_PROTOCOL
*DevicePathProtocol
;
206 EFI_DEVICE_PATH_PROTOCOL
*SupportedDevicePath
;
207 EFI_DEVICE_PATH_PROTOCOL
*SupportedDevicePaths
;
213 // Open the IO Abstraction(s) needed to perform the supported test
215 Status
= gBS
->OpenProtocol (
217 &gEfiDiskIoProtocolGuid
,
221 EFI_OPEN_PROTOCOL_BY_DRIVER
224 if (EFI_ERROR (Status
)) {
228 // Close the I/O Abstraction(s) used to perform the supported test
232 &gEfiDiskIoProtocolGuid
,
237 // Check that BlockIo protocol instance exists
238 Status
= gBS
->OpenProtocol (
240 &gEfiBlockIoProtocolGuid
,
244 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
246 if (EFI_ERROR (Status
)) {
250 // Check if a DevicePath is attached to the handle
251 Status
= gBS
->OpenProtocol (
253 &gEfiDevicePathProtocolGuid
,
254 (VOID
**)&DevicePathProtocol
,
257 EFI_OPEN_PROTOCOL_BY_DRIVER
259 if (EFI_ERROR (Status
)) {
263 // Check if the Device Path is the one which contains the Boot Monitor File System
264 Size1
= GetDevicePathSize (DevicePathProtocol
);
266 // Go through the list of Device Path Instances
267 Status
= EFI_UNSUPPORTED
;
268 SupportedDevicePaths
= mBootMonFsSupportedDevicePaths
;
269 while (SupportedDevicePaths
!= NULL
) {
270 SupportedDevicePath
= GetNextDevicePathInstance (&SupportedDevicePaths
, &Size2
);
272 if ((Size1
== Size2
) && (CompareMem (DevicePathProtocol
, SupportedDevicePath
, Size1
) == 0)) {
273 // The Device Path is supported
274 Status
= EFI_SUCCESS
;
279 gBS
->CloseProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
, gImageHandle
, ControllerHandle
);
285 BootMonFsDriverStart (
286 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
287 IN EFI_HANDLE ControllerHandle
,
288 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
291 BOOTMON_FS_INSTANCE
*Instance
;
293 UINTN VolumeNameSize
;
295 Instance
= AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE
));
296 if (Instance
== NULL
) {
297 return EFI_OUT_OF_RESOURCES
;
300 // Initialize the BlockIo of the Instance
301 Status
= gBS
->OpenProtocol (
303 &gEfiBlockIoProtocolGuid
,
304 (VOID
**)&(Instance
->BlockIo
),
307 EFI_OPEN_PROTOCOL_GET_PROTOCOL
309 if (EFI_ERROR (Status
)) {
314 Status
= gBS
->OpenProtocol (
316 &gEfiDiskIoProtocolGuid
,
317 (VOID
**)&(Instance
->DiskIo
),
320 EFI_OPEN_PROTOCOL_BY_DRIVER
322 if (EFI_ERROR (Status
)) {
328 // Initialize the attributes of the Instance
330 Instance
->Signature
= BOOTMON_FS_SIGNATURE
;
331 Instance
->ControllerHandle
= ControllerHandle
;
332 Instance
->Media
= Instance
->BlockIo
->Media
;
333 Instance
->Binding
= DriverBinding
;
335 // Initialize the Simple File System Protocol
336 Instance
->Fs
.Revision
= EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
;
337 Instance
->Fs
.OpenVolume
= OpenBootMonFsOpenVolume
;
339 // Volume name + L' ' + '2' digit number
340 VolumeNameSize
= StrSize (BOOTMON_FS_VOLUME_LABEL
) + (3 * sizeof (CHAR16
));
342 // Initialize FileSystem Information
343 Instance
->FsInfo
.Size
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ VolumeNameSize
;
344 Instance
->FsInfo
.BlockSize
= Instance
->Media
->BlockSize
;
345 Instance
->FsInfo
.ReadOnly
= FALSE
;
346 Instance
->FsInfo
.VolumeSize
=
347 Instance
->Media
->BlockSize
* (Instance
->Media
->LastBlock
- Instance
->Media
->LowestAlignedLba
);
348 CopyMem (Instance
->FsInfo
.VolumeLabel
, BOOTMON_FS_VOLUME_LABEL
, StrSize (BOOTMON_FS_VOLUME_LABEL
));
350 // Initialize the root file
351 Status
= BootMonFsCreateFile (Instance
, &Instance
->RootFile
);
352 if (EFI_ERROR (Status
)) {
357 // Initialize the DevicePath of the Instance
358 Status
= gBS
->OpenProtocol (
360 &gEfiDevicePathProtocolGuid
,
361 (VOID
**)&(Instance
->DevicePath
),
364 EFI_OPEN_PROTOCOL_GET_PROTOCOL
366 if (EFI_ERROR (Status
)) {
372 // Install the Simple File System Protocol
374 Status
= gBS
->InstallMultipleProtocolInterfaces (
376 &gEfiSimpleFileSystemProtocolGuid
, &Instance
->Fs
,
380 InsertTailList (&mInstances
, &Instance
->Link
);
388 BootMonFsDriverStop (
389 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
390 IN EFI_HANDLE ControllerHandle
,
391 IN UINTN NumberOfChildren
,
392 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
395 BOOTMON_FS_INSTANCE
*Instance
;
398 BOOLEAN InstanceFound
;
400 // Find instance from ControllerHandle.
402 InstanceFound
= FALSE
;
403 // For each instance in mInstances:
404 for (Link
= GetFirstNode (&mInstances
); !IsNull (&mInstances
, Link
); Link
= GetNextNode (&mInstances
, Link
)) {
405 Instance
= BOOTMON_FS_FROM_LINK (Link
);
407 if (Instance
->ControllerHandle
== ControllerHandle
) {
408 InstanceFound
= TRUE
;
412 ASSERT (InstanceFound
== TRUE
);
416 &gEfiDevicePathProtocolGuid
,
417 DriverBinding
->ImageHandle
,
422 &gEfiDiskIoProtocolGuid
,
423 DriverBinding
->ImageHandle
,
428 &gEfiBlockIoProtocolGuid
,
429 DriverBinding
->ImageHandle
,
432 Status
= gBS
->UninstallMultipleProtocolInterfaces (
434 &gEfiSimpleFileSystemProtocolGuid
, &Instance
->Fs
,
441 // Simple Network Protocol Driver Global Variables
443 EFI_DRIVER_BINDING_PROTOCOL mBootMonFsDriverBinding
= {
444 BootMonFsDriverSupported
,
445 BootMonFsDriverStart
,
454 BootMonFsEntryPoint (
455 IN EFI_HANDLE ImageHandle
,
456 IN EFI_SYSTEM_TABLE
*SystemTable
461 InitializeListHead (&mInstances
);
463 // Initialize the list of Device Paths that could support BootMonFs
464 Status
= SupportedDevicePathsInit ();
465 if (!EFI_ERROR (Status
)) {
466 Status
= gBS
->InstallMultipleProtocolInterfaces (
468 &gEfiDriverBindingProtocolGuid
, &mBootMonFsDriverBinding
,
471 ASSERT_EFI_ERROR (Status
);
473 DEBUG((EFI_D_ERROR
,"Warning: No Device Paths supporting BootMonFs have been defined in the PCD.\n"));