• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 *
3 *  Copyright (c) 2012-2014, ARM Limited. All rights reserved.
4 *
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
9 *
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.
12 *
13 **/
14 
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>
20 
21 #include <Protocol/DevicePathFromText.h>
22 #include <Protocol/DriverBinding.h>
23 
24 #include "BootMonFsInternal.h"
25 
26 EFI_DEVICE_PATH* mBootMonFsSupportedDevicePaths;
27 LIST_ENTRY       mInstances;
28 
29 EFI_FILE_PROTOCOL mBootMonFsRootTemplate = {
30   EFI_FILE_PROTOCOL_REVISION,
31   BootMonFsOpenFile,
32   BootMonFsCloseFile,
33   BootMonFsDeleteFail,
34   BootMonFsReadDirectory,
35   BootMonFsWriteFile,
36   BootMonFsGetPositionUnsupported,  // UEFI Spec: GetPosition not valid on dirs
37   BootMonFsSetDirPosition,
38   BootMonFsGetInfo,
39   BootMonFsSetInfo,
40   BootMonFsFlushDirectory
41 };
42 
43 EFI_FILE_PROTOCOL mBootMonFsFileTemplate = {
44   EFI_FILE_PROTOCOL_REVISION,
45   BootMonFsOpenFile,
46   BootMonFsCloseFile,
47   BootMonFsDelete,
48   BootMonFsReadFile,
49   BootMonFsWriteFile,
50   BootMonFsGetPosition,
51   BootMonFsSetPosition,
52   BootMonFsGetInfo,
53   BootMonFsSetInfo,
54   BootMonFsFlushFile
55 };
56 
57 /**
58   Search for a file given its name coded in Ascii.
59 
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.
63 
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
68   description.
69 
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.
73 
74   @param[out]  File           Pointer to the description of the file if the
75                               file was found.
76 
77   @retval  EFI_SUCCESS    The file was found.
78   @retval  EFI_NOT_FOUND  The file was not found.
79 
80 **/
81 EFI_STATUS
BootMonGetFileFromAsciiFileName(IN BOOTMON_FS_INSTANCE * Instance,IN CHAR8 * AsciiFileName,OUT BOOTMON_FS_FILE ** File)82 BootMonGetFileFromAsciiFileName (
83   IN  BOOTMON_FS_INSTANCE   *Instance,
84   IN  CHAR8*                AsciiFileName,
85   OUT BOOTMON_FS_FILE       **File
86   )
87 {
88   LIST_ENTRY       *Entry;
89   BOOTMON_FS_FILE  *FileEntry;
90   CHAR8            OpenFileAsciiFileName[MAX_NAME_LENGTH];
91   CHAR8            *AsciiFileNameToCompare;
92 
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)
97        )
98   {
99     FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);
100     if (FileEntry->Info != NULL) {
101       UnicodeStrToAsciiStrS (FileEntry->Info->FileName, OpenFileAsciiFileName,
102         MAX_NAME_LENGTH);
103       AsciiFileNameToCompare = OpenFileAsciiFileName;
104     } else {
105       AsciiFileNameToCompare = FileEntry->HwDescription.Footer.Filename;
106     }
107 
108     if (AsciiStrCmp (AsciiFileNameToCompare, AsciiFileName) == 0) {
109       *File = FileEntry;
110       return EFI_SUCCESS;
111     }
112   }
113   return EFI_NOT_FOUND;
114 }
115 
116 EFI_STATUS
BootMonGetFileFromPosition(IN BOOTMON_FS_INSTANCE * Instance,IN UINTN Position,OUT BOOTMON_FS_FILE ** File)117 BootMonGetFileFromPosition (
118   IN  BOOTMON_FS_INSTANCE   *Instance,
119   IN  UINTN                 Position,
120   OUT BOOTMON_FS_FILE       **File
121   )
122 {
123   LIST_ENTRY        *Entry;
124   BOOTMON_FS_FILE   *FileEntry;
125 
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)
130        )
131   {
132     if (Position == 0) {
133       FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);
134       *File = FileEntry;
135       return EFI_SUCCESS;
136     }
137     Position--;
138   }
139   return EFI_NOT_FOUND;
140 }
141 
142 EFI_STATUS
BootMonFsCreateFile(IN BOOTMON_FS_INSTANCE * Instance,OUT BOOTMON_FS_FILE ** File)143 BootMonFsCreateFile (
144   IN  BOOTMON_FS_INSTANCE *Instance,
145   OUT BOOTMON_FS_FILE     **File
146   )
147 {
148   BOOTMON_FS_FILE *NewFile;
149 
150   NewFile = (BOOTMON_FS_FILE*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE));
151   if (NewFile == NULL) {
152     return EFI_OUT_OF_RESOURCES;
153   }
154 
155   NewFile->Signature = BOOTMON_FS_FILE_SIGNATURE;
156   InitializeListHead (&NewFile->Link);
157   InitializeListHead (&NewFile->RegionToFlushLink);
158   NewFile->Instance = Instance;
159 
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));
163   } else {
164     CopyMem (&NewFile->File, &mBootMonFsFileTemplate, sizeof (mBootMonFsFileTemplate));
165   }
166   *File = NewFile;
167   return EFI_SUCCESS;
168 }
169 
170 STATIC
171 EFI_STATUS
SupportedDevicePathsInit(VOID)172 SupportedDevicePathsInit (
173   VOID
174   )
175 {
176   EFI_STATUS                          Status;
177   CHAR16*                             DevicePathListStr;
178   CHAR16*                             DevicePathStr;
179   CHAR16*                             NextDevicePathStr;
180   EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
181   EFI_DEVICE_PATH_PROTOCOL           *Instance;
182 
183   Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
184   ASSERT_EFI_ERROR (Status);
185 
186   // Initialize Variable
187   DevicePathListStr = (CHAR16*)PcdGetPtr (PcdBootMonFsSupportedDevicePaths);
188   mBootMonFsSupportedDevicePaths = NULL;
189 
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;
196     } else {
197       DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DevicePathListStr + 1) * sizeof (CHAR16), DevicePathListStr);
198       if (DevicePathStr == NULL) {
199         return EFI_OUT_OF_RESOURCES;
200       }
201       *(DevicePathStr + (NextDevicePathStr - DevicePathListStr)) = L'\0';
202       DevicePathListStr = NextDevicePathStr;
203       if (DevicePathListStr[0] == L';') {
204         DevicePathListStr++;
205       }
206     }
207 
208     Instance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr);
209     ASSERT (Instance != NULL);
210     mBootMonFsSupportedDevicePaths = AppendDevicePathInstance (mBootMonFsSupportedDevicePaths, Instance);
211 
212     if (NextDevicePathStr != NULL) {
213       FreePool (DevicePathStr);
214     }
215     FreePool (Instance);
216   }
217 
218   if (mBootMonFsSupportedDevicePaths == NULL) {
219     return EFI_UNSUPPORTED;
220   } else {
221     return EFI_SUCCESS;
222   }
223 }
224 
225 EFI_STATUS
226 EFIAPI
BootMonFsDriverSupported(IN EFI_DRIVER_BINDING_PROTOCOL * DriverBinding,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath OPTIONAL)227 BootMonFsDriverSupported (
228   IN        EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
229   IN        EFI_HANDLE                   ControllerHandle,
230   IN        EFI_DEVICE_PATH_PROTOCOL    *DevicePath OPTIONAL
231   )
232 {
233   EFI_DISK_IO_PROTOCOL  *DiskIo;
234   EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol;
235   EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePath;
236   EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePaths;
237   EFI_STATUS Status;
238   UINTN Size1;
239   UINTN Size2;
240 
241   //
242   // Open the IO Abstraction(s) needed to perform the supported test
243   //
244   Status = gBS->OpenProtocol (
245                   ControllerHandle,
246                   &gEfiDiskIoProtocolGuid,
247                   (VOID **) &DiskIo,
248                   gImageHandle,
249                   ControllerHandle,
250                   EFI_OPEN_PROTOCOL_BY_DRIVER
251                   );
252 
253   if (EFI_ERROR (Status)) {
254     return Status;
255   }
256   //
257   // Close the I/O Abstraction(s) used to perform the supported test
258   //
259   gBS->CloseProtocol (
260          ControllerHandle,
261          &gEfiDiskIoProtocolGuid,
262          gImageHandle,
263          ControllerHandle
264          );
265 
266   // Check that BlockIo protocol instance exists
267   Status = gBS->OpenProtocol (
268                   ControllerHandle,
269                   &gEfiBlockIoProtocolGuid,
270                   NULL,
271                   gImageHandle,
272                   ControllerHandle,
273                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
274                   );
275   if (EFI_ERROR (Status)) {
276     return Status;
277   }
278 
279   // Check if a DevicePath is attached to the handle
280   Status = gBS->OpenProtocol (
281                   ControllerHandle,
282                   &gEfiDevicePathProtocolGuid,
283                   (VOID **)&DevicePathProtocol,
284                   gImageHandle,
285                   ControllerHandle,
286                   EFI_OPEN_PROTOCOL_BY_DRIVER
287                   );
288   if (EFI_ERROR (Status)) {
289     return Status;
290   }
291 
292   // Check if the Device Path is the one which contains the Boot Monitor File System
293   Size1 = GetDevicePathSize (DevicePathProtocol);
294 
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);
300 
301     if ((Size1 == Size2) && (CompareMem (DevicePathProtocol, SupportedDevicePath, Size1) == 0)) {
302       // The Device Path is supported
303       Status = EFI_SUCCESS;
304       break;
305     }
306   }
307 
308   gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, gImageHandle, ControllerHandle);
309   return Status;
310 }
311 
312 EFI_STATUS
313 EFIAPI
BootMonFsDriverStart(IN EFI_DRIVER_BINDING_PROTOCOL * DriverBinding,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath OPTIONAL)314 BootMonFsDriverStart (
315   IN        EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
316   IN        EFI_HANDLE                   ControllerHandle,
317   IN        EFI_DEVICE_PATH_PROTOCOL    *DevicePath OPTIONAL
318   )
319 {
320   BOOTMON_FS_INSTANCE *Instance;
321   EFI_STATUS           Status;
322   UINTN                VolumeNameSize;
323   EFI_FILE_INFO       *Info;
324 
325   Instance = AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE));
326   if (Instance == NULL) {
327     return EFI_OUT_OF_RESOURCES;
328   }
329 
330   // Initialize the BlockIo of the Instance
331   Status = gBS->OpenProtocol (
332                   ControllerHandle,
333                   &gEfiBlockIoProtocolGuid,
334                   (VOID **)&(Instance->BlockIo),
335                   gImageHandle,
336                   ControllerHandle,
337                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
338                   );
339   if (EFI_ERROR (Status)) {
340     goto Error;
341   }
342 
343   Status = gBS->OpenProtocol (
344                   ControllerHandle,
345                   &gEfiDiskIoProtocolGuid,
346                   (VOID **)&(Instance->DiskIo),
347                   gImageHandle,
348                   ControllerHandle,
349                   EFI_OPEN_PROTOCOL_BY_DRIVER
350                   );
351   if (EFI_ERROR (Status)) {
352     goto Error;
353   }
354 
355   //
356   // Initialize the attributes of the Instance
357   //
358   Instance->Signature = BOOTMON_FS_SIGNATURE;
359   Instance->ControllerHandle = ControllerHandle;
360   Instance->Media = Instance->BlockIo->Media;
361   Instance->Binding = DriverBinding;
362 
363     // Initialize the Simple File System Protocol
364   Instance->Fs.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
365   Instance->Fs.OpenVolume = OpenBootMonFsOpenVolume;
366 
367   // Volume name + L' ' + '2' digit number
368   VolumeNameSize = StrSize (BOOTMON_FS_VOLUME_LABEL) + (3 * sizeof (CHAR16));
369 
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));
377 
378   // Initialize the root file
379   Status = BootMonFsCreateFile (Instance, &Instance->RootFile);
380   if (EFI_ERROR (Status)) {
381     goto Error;
382   }
383 
384   Info = AllocateZeroPool (sizeof (EFI_FILE_INFO));
385   if (Info == NULL) {
386     Status = EFI_OUT_OF_RESOURCES;
387     goto Error;
388   }
389   Instance->RootFile->Info = Info;
390 
391   // Initialize the DevicePath of the Instance
392   Status = gBS->OpenProtocol (
393                   ControllerHandle,
394                   &gEfiDevicePathProtocolGuid,
395                   (VOID **)&(Instance->DevicePath),
396                   gImageHandle,
397                   ControllerHandle,
398                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
399                   );
400   if (EFI_ERROR (Status)) {
401     goto Error;
402   }
403 
404   //
405   // Install the Simple File System Protocol
406   //
407   Status = gBS->InstallMultipleProtocolInterfaces (
408                       &ControllerHandle,
409                       &gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
410                       NULL
411                       );
412   if (EFI_ERROR (Status)) {
413     goto Error;
414   }
415 
416   InsertTailList (&mInstances, &Instance->Link);
417 
418   return EFI_SUCCESS;
419 
420 Error:
421 
422     if (Instance->RootFile != NULL) {
423       if (Instance->RootFile->Info != NULL) {
424         FreePool (Instance->RootFile->Info);
425       }
426       FreePool (Instance->RootFile);
427     }
428     FreePool (Instance);
429 
430   return Status;
431 }
432 
433 
434 EFI_STATUS
435 EFIAPI
BootMonFsDriverStop(IN EFI_DRIVER_BINDING_PROTOCOL * DriverBinding,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)436 BootMonFsDriverStop (
437   IN        EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
438   IN        EFI_HANDLE                   ControllerHandle,
439   IN        UINTN                        NumberOfChildren,
440   IN        EFI_HANDLE                  *ChildHandleBuffer OPTIONAL
441   )
442 {
443   BOOTMON_FS_INSTANCE *Instance;
444   LIST_ENTRY          *Link;
445   EFI_STATUS           Status;
446   BOOLEAN              InstanceFound;
447 
448   // Find instance from ControllerHandle.
449   Instance = NULL;
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);
454 
455     if (Instance->ControllerHandle == ControllerHandle) {
456       InstanceFound = TRUE;
457       break;
458     }
459   }
460   ASSERT (InstanceFound == TRUE);
461 
462   gBS->CloseProtocol (
463       ControllerHandle,
464       &gEfiDevicePathProtocolGuid,
465       DriverBinding->ImageHandle,
466       ControllerHandle);
467 
468   gBS->CloseProtocol (
469       ControllerHandle,
470       &gEfiDiskIoProtocolGuid,
471       DriverBinding->ImageHandle,
472       ControllerHandle);
473 
474   gBS->CloseProtocol (
475       ControllerHandle,
476       &gEfiBlockIoProtocolGuid,
477       DriverBinding->ImageHandle,
478       ControllerHandle);
479 
480   Status = gBS->UninstallMultipleProtocolInterfaces (
481       &ControllerHandle,
482       &gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
483       NULL);
484 
485   FreePool (Instance->RootFile->Info);
486   FreePool (Instance->RootFile);
487   FreePool (Instance);
488 
489   return Status;
490 }
491 
492 //
493 // Simple Network Protocol Driver Global Variables
494 //
495 EFI_DRIVER_BINDING_PROTOCOL mBootMonFsDriverBinding = {
496   BootMonFsDriverSupported,
497   BootMonFsDriverStart,
498   BootMonFsDriverStop,
499   0xa,
500   NULL,
501   NULL
502 };
503 
504 EFI_STATUS
505 EFIAPI
BootMonFsEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)506 BootMonFsEntryPoint (
507   IN EFI_HANDLE                            ImageHandle,
508   IN EFI_SYSTEM_TABLE                      *SystemTable
509   )
510 {
511   EFI_STATUS  Status;
512 
513   InitializeListHead (&mInstances);
514 
515   // Initialize the list of Device Paths that could support BootMonFs
516   Status = SupportedDevicePathsInit ();
517   if (!EFI_ERROR (Status)) {
518     Status = gBS->InstallMultipleProtocolInterfaces (
519                     &ImageHandle,
520                     &gEfiDriverBindingProtocolGuid, &mBootMonFsDriverBinding,
521                     NULL
522                     );
523     ASSERT_EFI_ERROR (Status);
524   } else {
525     DEBUG((EFI_D_ERROR,"Warning: No Device Paths supporting BootMonFs have been defined in the PCD.\n"));
526   }
527 
528   return Status;
529 }
530