]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c
ArmPlatformPkg/BootMonFs: Fix the setting of information about a file
[mirror_edk2.git] / ArmPlatformPkg / FileSystem / BootMonFs / BootMonFsEntryPoint.c
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
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 UnicodeStrToAsciiStr (FileEntry->Info->FileName, OpenFileAsciiFileName);
102 AsciiFileNameToCompare = OpenFileAsciiFileName;
103 } else {
104 AsciiFileNameToCompare = FileEntry->HwDescription.Footer.Filename;
105 }
106
107 if (AsciiStrCmp (AsciiFileNameToCompare, AsciiFileName) == 0) {
108 *File = FileEntry;
109 return EFI_SUCCESS;
110 }
111 }
112 return EFI_NOT_FOUND;
113 }
114
115 EFI_STATUS
116 BootMonGetFileFromPosition (
117 IN BOOTMON_FS_INSTANCE *Instance,
118 IN UINTN Position,
119 OUT BOOTMON_FS_FILE **File
120 )
121 {
122 LIST_ENTRY *Entry;
123 BOOTMON_FS_FILE *FileEntry;
124
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)
129 )
130 {
131 if (Position == 0) {
132 FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);
133 *File = FileEntry;
134 return EFI_SUCCESS;
135 }
136 Position--;
137 }
138 return EFI_NOT_FOUND;
139 }
140
141 EFI_STATUS
142 BootMonFsCreateFile (
143 IN BOOTMON_FS_INSTANCE *Instance,
144 OUT BOOTMON_FS_FILE **File
145 )
146 {
147 BOOTMON_FS_FILE *NewFile;
148
149 NewFile = (BOOTMON_FS_FILE*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE));
150 if (NewFile == NULL) {
151 return EFI_OUT_OF_RESOURCES;
152 }
153
154 NewFile->Signature = BOOTMON_FS_FILE_SIGNATURE;
155 InitializeListHead (&NewFile->Link);
156 InitializeListHead (&NewFile->RegionToFlushLink);
157 NewFile->Instance = Instance;
158
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));
162 } else {
163 CopyMem (&NewFile->File, &mBootMonFsFileTemplate, sizeof (mBootMonFsFileTemplate));
164 }
165 *File = NewFile;
166 return EFI_SUCCESS;
167 }
168
169 STATIC
170 EFI_STATUS
171 SupportedDevicePathsInit (
172 VOID
173 )
174 {
175 EFI_STATUS Status;
176 CHAR16* DevicePathListStr;
177 CHAR16* DevicePathStr;
178 CHAR16* NextDevicePathStr;
179 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
180 EFI_DEVICE_PATH_PROTOCOL *Instance;
181
182 Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
183 ASSERT_EFI_ERROR (Status);
184
185 // Initialize Variable
186 DevicePathListStr = (CHAR16*)PcdGetPtr (PcdBootMonFsSupportedDevicePaths);
187 mBootMonFsSupportedDevicePaths = NULL;
188
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;
195 } else {
196 DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DevicePathListStr + 1) * sizeof (CHAR16), DevicePathListStr);
197 if (DevicePathStr == NULL) {
198 return EFI_OUT_OF_RESOURCES;
199 }
200 *(DevicePathStr + (NextDevicePathStr - DevicePathListStr)) = L'\0';
201 DevicePathListStr = NextDevicePathStr;
202 if (DevicePathListStr[0] == L';') {
203 DevicePathListStr++;
204 }
205 }
206
207 Instance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr);
208 ASSERT (Instance != NULL);
209 mBootMonFsSupportedDevicePaths = AppendDevicePathInstance (mBootMonFsSupportedDevicePaths, Instance);
210
211 if (NextDevicePathStr != NULL) {
212 FreePool (DevicePathStr);
213 }
214 FreePool (Instance);
215 }
216
217 if (mBootMonFsSupportedDevicePaths == NULL) {
218 return EFI_UNSUPPORTED;
219 } else {
220 return EFI_SUCCESS;
221 }
222 }
223
224 EFI_STATUS
225 EFIAPI
226 BootMonFsDriverSupported (
227 IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
228 IN EFI_HANDLE ControllerHandle,
229 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
230 )
231 {
232 EFI_DISK_IO_PROTOCOL *DiskIo;
233 EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol;
234 EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePath;
235 EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePaths;
236 EFI_STATUS Status;
237 UINTN Size1;
238 UINTN Size2;
239
240 //
241 // Open the IO Abstraction(s) needed to perform the supported test
242 //
243 Status = gBS->OpenProtocol (
244 ControllerHandle,
245 &gEfiDiskIoProtocolGuid,
246 (VOID **) &DiskIo,
247 gImageHandle,
248 ControllerHandle,
249 EFI_OPEN_PROTOCOL_BY_DRIVER
250 );
251
252 if (EFI_ERROR (Status)) {
253 return Status;
254 }
255 //
256 // Close the I/O Abstraction(s) used to perform the supported test
257 //
258 gBS->CloseProtocol (
259 ControllerHandle,
260 &gEfiDiskIoProtocolGuid,
261 gImageHandle,
262 ControllerHandle
263 );
264
265 // Check that BlockIo protocol instance exists
266 Status = gBS->OpenProtocol (
267 ControllerHandle,
268 &gEfiBlockIoProtocolGuid,
269 NULL,
270 gImageHandle,
271 ControllerHandle,
272 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
273 );
274 if (EFI_ERROR (Status)) {
275 return Status;
276 }
277
278 // Check if a DevicePath is attached to the handle
279 Status = gBS->OpenProtocol (
280 ControllerHandle,
281 &gEfiDevicePathProtocolGuid,
282 (VOID **)&DevicePathProtocol,
283 gImageHandle,
284 ControllerHandle,
285 EFI_OPEN_PROTOCOL_BY_DRIVER
286 );
287 if (EFI_ERROR (Status)) {
288 return Status;
289 }
290
291 // Check if the Device Path is the one which contains the Boot Monitor File System
292 Size1 = GetDevicePathSize (DevicePathProtocol);
293
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);
299
300 if ((Size1 == Size2) && (CompareMem (DevicePathProtocol, SupportedDevicePath, Size1) == 0)) {
301 // The Device Path is supported
302 Status = EFI_SUCCESS;
303 break;
304 }
305 }
306
307 gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, gImageHandle, ControllerHandle);
308 return Status;
309 }
310
311 EFI_STATUS
312 EFIAPI
313 BootMonFsDriverStart (
314 IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
315 IN EFI_HANDLE ControllerHandle,
316 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
317 )
318 {
319 BOOTMON_FS_INSTANCE *Instance;
320 EFI_STATUS Status;
321 UINTN VolumeNameSize;
322 EFI_FILE_INFO *Info;
323
324 Instance = AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE));
325 if (Instance == NULL) {
326 return EFI_OUT_OF_RESOURCES;
327 }
328
329 // Initialize the BlockIo of the Instance
330 Status = gBS->OpenProtocol (
331 ControllerHandle,
332 &gEfiBlockIoProtocolGuid,
333 (VOID **)&(Instance->BlockIo),
334 gImageHandle,
335 ControllerHandle,
336 EFI_OPEN_PROTOCOL_GET_PROTOCOL
337 );
338 if (EFI_ERROR (Status)) {
339 goto Error;
340 }
341
342 Status = gBS->OpenProtocol (
343 ControllerHandle,
344 &gEfiDiskIoProtocolGuid,
345 (VOID **)&(Instance->DiskIo),
346 gImageHandle,
347 ControllerHandle,
348 EFI_OPEN_PROTOCOL_BY_DRIVER
349 );
350 if (EFI_ERROR (Status)) {
351 goto Error;
352 }
353
354 //
355 // Initialize the attributes of the Instance
356 //
357 Instance->Signature = BOOTMON_FS_SIGNATURE;
358 Instance->ControllerHandle = ControllerHandle;
359 Instance->Media = Instance->BlockIo->Media;
360 Instance->Binding = DriverBinding;
361
362 // Initialize the Simple File System Protocol
363 Instance->Fs.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
364 Instance->Fs.OpenVolume = OpenBootMonFsOpenVolume;
365
366 // Volume name + L' ' + '2' digit number
367 VolumeNameSize = StrSize (BOOTMON_FS_VOLUME_LABEL) + (3 * sizeof (CHAR16));
368
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));
376
377 // Initialize the root file
378 Status = BootMonFsCreateFile (Instance, &Instance->RootFile);
379 if (EFI_ERROR (Status)) {
380 goto Error;
381 }
382
383 Info = AllocateZeroPool (sizeof (EFI_FILE_INFO));
384 if (Info == NULL) {
385 Status = EFI_OUT_OF_RESOURCES;
386 goto Error;
387 }
388 Instance->RootFile->Info = Info;
389
390 // Initialize the DevicePath of the Instance
391 Status = gBS->OpenProtocol (
392 ControllerHandle,
393 &gEfiDevicePathProtocolGuid,
394 (VOID **)&(Instance->DevicePath),
395 gImageHandle,
396 ControllerHandle,
397 EFI_OPEN_PROTOCOL_GET_PROTOCOL
398 );
399 if (EFI_ERROR (Status)) {
400 goto Error;
401 }
402
403 //
404 // Install the Simple File System Protocol
405 //
406 Status = gBS->InstallMultipleProtocolInterfaces (
407 &ControllerHandle,
408 &gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
409 NULL
410 );
411 if (EFI_ERROR (Status)) {
412 goto Error;
413 }
414
415 InsertTailList (&mInstances, &Instance->Link);
416
417 return EFI_SUCCESS;
418
419 Error:
420
421 if (Instance->RootFile != NULL) {
422 if (Instance->RootFile->Info != NULL) {
423 FreePool (Instance->RootFile->Info);
424 }
425 FreePool (Instance->RootFile);
426 }
427 FreePool (Instance);
428
429 return Status;
430 }
431
432
433 EFI_STATUS
434 EFIAPI
435 BootMonFsDriverStop (
436 IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
437 IN EFI_HANDLE ControllerHandle,
438 IN UINTN NumberOfChildren,
439 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
440 )
441 {
442 BOOTMON_FS_INSTANCE *Instance;
443 LIST_ENTRY *Link;
444 EFI_STATUS Status;
445 BOOLEAN InstanceFound;
446
447 // Find instance from ControllerHandle.
448 Instance = NULL;
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);
453
454 if (Instance->ControllerHandle == ControllerHandle) {
455 InstanceFound = TRUE;
456 break;
457 }
458 }
459 ASSERT (InstanceFound == TRUE);
460
461 gBS->CloseProtocol (
462 ControllerHandle,
463 &gEfiDevicePathProtocolGuid,
464 DriverBinding->ImageHandle,
465 ControllerHandle);
466
467 gBS->CloseProtocol (
468 ControllerHandle,
469 &gEfiDiskIoProtocolGuid,
470 DriverBinding->ImageHandle,
471 ControllerHandle);
472
473 gBS->CloseProtocol (
474 ControllerHandle,
475 &gEfiBlockIoProtocolGuid,
476 DriverBinding->ImageHandle,
477 ControllerHandle);
478
479 Status = gBS->UninstallMultipleProtocolInterfaces (
480 &ControllerHandle,
481 &gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
482 NULL);
483
484 FreePool (Instance->RootFile->Info);
485 FreePool (Instance->RootFile);
486 FreePool (Instance);
487
488 return Status;
489 }
490
491 //
492 // Simple Network Protocol Driver Global Variables
493 //
494 EFI_DRIVER_BINDING_PROTOCOL mBootMonFsDriverBinding = {
495 BootMonFsDriverSupported,
496 BootMonFsDriverStart,
497 BootMonFsDriverStop,
498 0xa,
499 NULL,
500 NULL
501 };
502
503 EFI_STATUS
504 EFIAPI
505 BootMonFsEntryPoint (
506 IN EFI_HANDLE ImageHandle,
507 IN EFI_SYSTEM_TABLE *SystemTable
508 )
509 {
510 EFI_STATUS Status;
511
512 InitializeListHead (&mInstances);
513
514 // Initialize the list of Device Paths that could support BootMonFs
515 Status = SupportedDevicePathsInit ();
516 if (!EFI_ERROR (Status)) {
517 Status = gBS->InstallMultipleProtocolInterfaces (
518 &ImageHandle,
519 &gEfiDriverBindingProtocolGuid, &mBootMonFsDriverBinding,
520 NULL
521 );
522 ASSERT_EFI_ERROR (Status);
523 } else {
524 DEBUG((EFI_D_ERROR,"Warning: No Device Paths supporting BootMonFs have been defined in the PCD.\n"));
525 }
526
527 return Status;
528 }