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 EFI_HANDLE mImageHandle
;
28 LIST_ENTRY mInstances
;
30 EFI_FILE_PROTOCOL mBootMonFsRootTemplate
= {
31 EFI_FILE_PROTOCOL_REVISION
,
35 BootMonFsReadDirectory
,
37 BootMonFsGetPositionUnsupported
, // UEFI Spec: GetPosition not valid on dirs
38 BootMonFsSetDirPosition
,
41 BootMonFsFlushDirectory
44 EFI_FILE_PROTOCOL mBootMonFsFileTemplate
= {
45 EFI_FILE_PROTOCOL_REVISION
,
59 BootMonGetFileFromAsciiFileName (
60 IN BOOTMON_FS_INSTANCE
*Instance
,
61 IN CHAR8
* AsciiFileName
,
62 OUT BOOTMON_FS_FILE
**File
66 BOOTMON_FS_FILE
*FileEntry
;
68 // Remove the leading '\\'
69 if (*AsciiFileName
== '\\') {
73 // Go through all the files in the list and return the file handle
74 for (Entry
= GetFirstNode (&Instance
->RootFile
->Link
);
75 !IsNull (&Instance
->RootFile
->Link
, Entry
);
76 Entry
= GetNextNode (&Instance
->RootFile
->Link
, Entry
)
79 FileEntry
= BOOTMON_FS_FILE_FROM_LINK_THIS (Entry
);
80 if (AsciiStrCmp (FileEntry
->HwDescription
.Footer
.Filename
, AsciiFileName
) == 0) {
89 BootMonGetFileFromPosition (
90 IN BOOTMON_FS_INSTANCE
*Instance
,
92 OUT BOOTMON_FS_FILE
**File
96 BOOTMON_FS_FILE
*FileEntry
;
98 // Go through all the files in the list and return the file handle
99 for (Entry
= GetFirstNode (&Instance
->RootFile
->Link
);
100 !IsNull (&Instance
->RootFile
->Link
, Entry
) && (&Instance
->RootFile
->Link
!= Entry
);
101 Entry
= GetNextNode (&Instance
->RootFile
->Link
, Entry
)
105 FileEntry
= BOOTMON_FS_FILE_FROM_LINK_THIS (Entry
);
111 return EFI_NOT_FOUND
;
115 BootMonFsCreateFile (
116 IN BOOTMON_FS_INSTANCE
*Instance
,
117 OUT BOOTMON_FS_FILE
**File
120 BOOTMON_FS_FILE
*NewFile
;
122 NewFile
= (BOOTMON_FS_FILE
*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE
));
123 if (NewFile
== NULL
) {
124 return EFI_OUT_OF_RESOURCES
;
127 NewFile
->Signature
= BOOTMON_FS_FILE_SIGNATURE
;
128 InitializeListHead (&NewFile
->Link
);
129 InitializeListHead (&NewFile
->RegionToFlushLink
);
130 NewFile
->Instance
= Instance
;
132 // If the created file is the root file then create a directory EFI_FILE_PROTOCOL
133 if (Instance
->RootFile
== *File
) {
134 CopyMem (&NewFile
->File
, &mBootMonFsRootTemplate
, sizeof (mBootMonFsRootTemplate
));
136 CopyMem (&NewFile
->File
, &mBootMonFsFileTemplate
, sizeof (mBootMonFsFileTemplate
));
144 SupportedDevicePathsInit (
149 CHAR16
* DevicePathListStr
;
150 CHAR16
* DevicePathStr
;
151 CHAR16
* NextDevicePathStr
;
152 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
*EfiDevicePathFromTextProtocol
;
153 EFI_DEVICE_PATH_PROTOCOL
*Instance
;
155 Status
= gBS
->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid
, NULL
, (VOID
**)&EfiDevicePathFromTextProtocol
);
156 ASSERT_EFI_ERROR (Status
);
158 // Initialize Variable
159 DevicePathListStr
= (CHAR16
*)PcdGetPtr (PcdBootMonFsSupportedDevicePaths
);
160 mBootMonFsSupportedDevicePaths
= NULL
;
162 // Extract the Device Path instances from the multi-device path string
163 while ((DevicePathListStr
!= NULL
) && (DevicePathListStr
[0] != L
'\0')) {
164 NextDevicePathStr
= StrStr (DevicePathListStr
, L
";");
165 if (NextDevicePathStr
== NULL
) {
166 DevicePathStr
= DevicePathListStr
;
167 DevicePathListStr
= NULL
;
169 DevicePathStr
= (CHAR16
*)AllocateCopyPool ((NextDevicePathStr
- DevicePathListStr
+ 1) * sizeof (CHAR16
), DevicePathListStr
);
170 if (DevicePathStr
== NULL
) {
171 return EFI_OUT_OF_RESOURCES
;
173 *(DevicePathStr
+ (NextDevicePathStr
- DevicePathListStr
)) = L
'\0';
174 DevicePathListStr
= NextDevicePathStr
;
175 if (DevicePathListStr
[0] == L
';') {
180 Instance
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath (DevicePathStr
);
181 ASSERT (Instance
!= NULL
);
182 mBootMonFsSupportedDevicePaths
= AppendDevicePathInstance (mBootMonFsSupportedDevicePaths
, Instance
);
184 if (NextDevicePathStr
!= NULL
) {
185 FreePool (DevicePathStr
);
190 if (mBootMonFsSupportedDevicePaths
== NULL
) {
191 return EFI_UNSUPPORTED
;
199 BootMonFsDriverSupported (
200 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
201 IN EFI_HANDLE ControllerHandle
,
202 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
205 EFI_DISK_IO_PROTOCOL
*DiskIo
;
206 EFI_DEVICE_PATH_PROTOCOL
*DevicePathProtocol
;
207 EFI_DEVICE_PATH_PROTOCOL
*SupportedDevicePath
;
208 EFI_DEVICE_PATH_PROTOCOL
*SupportedDevicePaths
;
214 // Open the IO Abstraction(s) needed to perform the supported test
216 Status
= gBS
->OpenProtocol (
218 &gEfiDiskIoProtocolGuid
,
222 EFI_OPEN_PROTOCOL_BY_DRIVER
225 if (EFI_ERROR (Status
)) {
229 // Close the I/O Abstraction(s) used to perform the supported test
233 &gEfiDiskIoProtocolGuid
,
238 // Check that BlockIo protocol instance exists
239 Status
= gBS
->OpenProtocol (
241 &gEfiBlockIoProtocolGuid
,
245 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
247 if (EFI_ERROR (Status
)) {
251 // Check if a DevicePath is attached to the handle
252 Status
= gBS
->OpenProtocol (
254 &gEfiDevicePathProtocolGuid
,
255 (VOID
**)&DevicePathProtocol
,
258 EFI_OPEN_PROTOCOL_BY_DRIVER
260 if (EFI_ERROR (Status
)) {
264 // Check if the Device Path is the one which contains the Boot Monitor File System
265 Size1
= GetDevicePathSize (DevicePathProtocol
);
267 // Go through the list of Device Path Instances
268 Status
= EFI_UNSUPPORTED
;
269 SupportedDevicePaths
= mBootMonFsSupportedDevicePaths
;
270 while (SupportedDevicePaths
!= NULL
) {
271 SupportedDevicePath
= GetNextDevicePathInstance (&SupportedDevicePaths
, &Size2
);
273 if ((Size1
== Size2
) && (CompareMem (DevicePathProtocol
, SupportedDevicePath
, Size1
) == 0)) {
274 // The Device Path is supported
275 Status
= EFI_SUCCESS
;
280 gBS
->CloseProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
, mImageHandle
, ControllerHandle
);
286 BootMonFsDriverStart (
287 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
288 IN EFI_HANDLE ControllerHandle
,
289 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
292 BOOTMON_FS_INSTANCE
*Instance
;
294 UINTN VolumeNameSize
;
296 Instance
= AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE
));
297 if (Instance
== NULL
) {
298 return EFI_OUT_OF_RESOURCES
;
301 // Initialize the BlockIo of the Instance
302 Status
= gBS
->OpenProtocol (
304 &gEfiBlockIoProtocolGuid
,
305 (VOID
**)&(Instance
->BlockIo
),
308 EFI_OPEN_PROTOCOL_GET_PROTOCOL
310 if (EFI_ERROR (Status
)) {
315 Status
= gBS
->OpenProtocol (
317 &gEfiDiskIoProtocolGuid
,
318 (VOID
**)&(Instance
->DiskIo
),
321 EFI_OPEN_PROTOCOL_BY_DRIVER
323 if (EFI_ERROR (Status
)) {
329 // Initialize the attributes of the Instance
331 Instance
->Signature
= BOOTMON_FS_SIGNATURE
;
332 Instance
->ControllerHandle
= ControllerHandle
;
333 Instance
->Media
= Instance
->BlockIo
->Media
;
334 Instance
->Binding
= DriverBinding
;
336 // Initialize the Simple File System Protocol
337 Instance
->Fs
.Revision
= EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
;
338 Instance
->Fs
.OpenVolume
= OpenBootMonFsOpenVolume
;
340 // Volume name + L' ' + '2' digit number
341 VolumeNameSize
= StrSize (BOOTMON_FS_VOLUME_LABEL
) + (3 * sizeof (CHAR16
));
343 // Initialize FileSystem Information
344 Instance
->FsInfo
.Size
= SIZE_OF_EFI_FILE_SYSTEM_INFO
+ VolumeNameSize
;
345 Instance
->FsInfo
.BlockSize
= Instance
->Media
->BlockSize
;
346 Instance
->FsInfo
.ReadOnly
= FALSE
;
347 Instance
->FsInfo
.VolumeSize
=
348 Instance
->Media
->BlockSize
* (Instance
->Media
->LastBlock
- Instance
->Media
->LowestAlignedLba
);
349 CopyMem (Instance
->FsInfo
.VolumeLabel
, BOOTMON_FS_VOLUME_LABEL
, StrSize (BOOTMON_FS_VOLUME_LABEL
));
351 // Initialize the root file
352 Status
= BootMonFsCreateFile (Instance
, &Instance
->RootFile
);
353 if (EFI_ERROR (Status
)) {
358 // Initialize the DevicePath of the Instance
359 Status
= gBS
->OpenProtocol (
361 &gEfiDevicePathProtocolGuid
,
362 (VOID
**)&(Instance
->DevicePath
),
365 EFI_OPEN_PROTOCOL_GET_PROTOCOL
367 if (EFI_ERROR (Status
)) {
373 // Install the Simple File System Protocol
375 Status
= gBS
->InstallMultipleProtocolInterfaces (
377 &gEfiSimpleFileSystemProtocolGuid
, &Instance
->Fs
,
381 InsertTailList (&mInstances
, &Instance
->Link
);
389 BootMonFsDriverStop (
390 IN EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
,
391 IN EFI_HANDLE ControllerHandle
,
392 IN UINTN NumberOfChildren
,
393 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
396 BOOTMON_FS_INSTANCE
*Instance
;
399 BOOLEAN InstanceFound
;
401 // Find instance from ControllerHandle.
403 InstanceFound
= FALSE
;
404 // For each instance in mInstances:
405 for (Link
= GetFirstNode (&mInstances
); !IsNull (&mInstances
, Link
); Link
= GetNextNode (&mInstances
, Link
)) {
406 Instance
= BOOTMON_FS_FROM_LINK (Link
);
408 if (Instance
->ControllerHandle
== ControllerHandle
) {
409 InstanceFound
= TRUE
;
413 ASSERT (InstanceFound
== TRUE
);
417 &gEfiDevicePathProtocolGuid
,
418 DriverBinding
->ImageHandle
,
423 &gEfiDiskIoProtocolGuid
,
424 DriverBinding
->ImageHandle
,
429 &gEfiBlockIoProtocolGuid
,
430 DriverBinding
->ImageHandle
,
433 Status
= gBS
->UninstallMultipleProtocolInterfaces (
435 &gEfiSimpleFileSystemProtocolGuid
, &Instance
->Fs
,
442 // Simple Network Protocol Driver Global Variables
444 EFI_DRIVER_BINDING_PROTOCOL mBootMonFsDriverBinding
= {
445 BootMonFsDriverSupported
,
446 BootMonFsDriverStart
,
455 BootMonFsEntryPoint (
456 IN EFI_HANDLE ImageHandle
,
457 IN EFI_SYSTEM_TABLE
*SystemTable
462 mImageHandle
= ImageHandle
;
463 InitializeListHead (&mInstances
);
465 // Initialize the list of Device Paths that could support BootMonFs
466 Status
= SupportedDevicePathsInit ();
467 if (!EFI_ERROR (Status
)) {
468 Status
= gBS
->InstallMultipleProtocolInterfaces (
470 &gEfiDriverBindingProtocolGuid
, &mBootMonFsDriverBinding
,
473 ASSERT_EFI_ERROR (Status
);
475 DEBUG((EFI_D_ERROR
,"Warning: No Device Paths supporting BootMonFs have been defined in the PCD.\n"));