]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c
ArmPlatformPkg/BootMonFs: Added support for the NorFlash File System of the ARM Devel...
[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 EFI_HANDLE mImageHandle;
28 LIST_ENTRY mInstances;
29
30 EFI_FILE_PROTOCOL mBootMonFsRootTemplate = {
31 EFI_FILE_PROTOCOL_REVISION,
32 BootMonFsOpenFile,
33 BootMonFsCloseFile,
34 BootMonFsDeleteFail,
35 BootMonFsReadDirectory,
36 BootMonFsWriteFile,
37 BootMonFsGetPositionUnsupported, // UEFI Spec: GetPosition not valid on dirs
38 BootMonFsSetDirPosition,
39 BootMonFsGetInfo,
40 BootMonFsSetInfo,
41 BootMonFsFlushDirectory
42 };
43
44 EFI_FILE_PROTOCOL mBootMonFsFileTemplate = {
45 EFI_FILE_PROTOCOL_REVISION,
46 BootMonFsOpenFile,
47 BootMonFsCloseFile,
48 BootMonFsDelete,
49 BootMonFsReadFile,
50 BootMonFsWriteFile,
51 BootMonFsGetPosition,
52 BootMonFsSetPosition,
53 BootMonFsGetInfo,
54 BootMonFsSetInfo,
55 BootMonFsFlushFile
56 };
57
58 EFI_STATUS
59 BootMonGetFileFromAsciiFileName (
60 IN BOOTMON_FS_INSTANCE *Instance,
61 IN CHAR8* AsciiFileName,
62 OUT BOOTMON_FS_FILE **File
63 )
64 {
65 LIST_ENTRY *Entry;
66 BOOTMON_FS_FILE *FileEntry;
67
68 // Remove the leading '\\'
69 if (*AsciiFileName == '\\') {
70 AsciiFileName++;
71 }
72
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)
77 )
78 {
79 FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);
80 if (AsciiStrCmp (FileEntry->HwDescription.Footer.Filename, AsciiFileName) == 0) {
81 *File = FileEntry;
82 return EFI_SUCCESS;
83 }
84 }
85 return EFI_NOT_FOUND;
86 }
87
88 EFI_STATUS
89 BootMonGetFileFromPosition (
90 IN BOOTMON_FS_INSTANCE *Instance,
91 IN UINTN Position,
92 OUT BOOTMON_FS_FILE **File
93 )
94 {
95 LIST_ENTRY *Entry;
96 BOOTMON_FS_FILE *FileEntry;
97
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)
102 )
103 {
104 if (Position == 0) {
105 FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);
106 *File = FileEntry;
107 return EFI_SUCCESS;
108 }
109 Position--;
110 }
111 return EFI_NOT_FOUND;
112 }
113
114 EFI_STATUS
115 BootMonFsCreateFile (
116 IN BOOTMON_FS_INSTANCE *Instance,
117 OUT BOOTMON_FS_FILE **File
118 )
119 {
120 BOOTMON_FS_FILE *NewFile;
121
122 NewFile = (BOOTMON_FS_FILE*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE));
123 if (NewFile == NULL) {
124 return EFI_OUT_OF_RESOURCES;
125 }
126
127 NewFile->Signature = BOOTMON_FS_FILE_SIGNATURE;
128 InitializeListHead (&NewFile->Link);
129 InitializeListHead (&NewFile->RegionToFlushLink);
130 NewFile->Instance = Instance;
131
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));
135 } else {
136 CopyMem (&NewFile->File, &mBootMonFsFileTemplate, sizeof (mBootMonFsFileTemplate));
137 }
138 *File = NewFile;
139 return EFI_SUCCESS;
140 }
141
142 STATIC
143 EFI_STATUS
144 SupportedDevicePathsInit (
145 VOID
146 )
147 {
148 EFI_STATUS Status;
149 CHAR16* DevicePathListStr;
150 CHAR16* DevicePathStr;
151 CHAR16* NextDevicePathStr;
152 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
153 EFI_DEVICE_PATH_PROTOCOL *Instance;
154
155 Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
156 ASSERT_EFI_ERROR (Status);
157
158 // Initialize Variable
159 DevicePathListStr = (CHAR16*)PcdGetPtr (PcdBootMonFsSupportedDevicePaths);
160 mBootMonFsSupportedDevicePaths = NULL;
161
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;
168 } else {
169 DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DevicePathListStr + 1) * sizeof (CHAR16), DevicePathListStr);
170 if (DevicePathStr == NULL) {
171 return EFI_OUT_OF_RESOURCES;
172 }
173 *(DevicePathStr + (NextDevicePathStr - DevicePathListStr)) = L'\0';
174 DevicePathListStr = NextDevicePathStr;
175 if (DevicePathListStr[0] == L';') {
176 DevicePathListStr++;
177 }
178 }
179
180 Instance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr);
181 ASSERT (Instance != NULL);
182 mBootMonFsSupportedDevicePaths = AppendDevicePathInstance (mBootMonFsSupportedDevicePaths, Instance);
183
184 if (NextDevicePathStr != NULL) {
185 FreePool (DevicePathStr);
186 }
187 FreePool (Instance);
188 }
189
190 if (mBootMonFsSupportedDevicePaths == NULL) {
191 return EFI_UNSUPPORTED;
192 } else {
193 return EFI_SUCCESS;
194 }
195 }
196
197 EFI_STATUS
198 EFIAPI
199 BootMonFsDriverSupported (
200 IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
201 IN EFI_HANDLE ControllerHandle,
202 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
203 )
204 {
205 EFI_DISK_IO_PROTOCOL *DiskIo;
206 EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol;
207 EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePath;
208 EFI_DEVICE_PATH_PROTOCOL *SupportedDevicePaths;
209 EFI_STATUS Status;
210 UINTN Size1;
211 UINTN Size2;
212
213 //
214 // Open the IO Abstraction(s) needed to perform the supported test
215 //
216 Status = gBS->OpenProtocol (
217 ControllerHandle,
218 &gEfiDiskIoProtocolGuid,
219 (VOID **) &DiskIo,
220 mImageHandle,
221 ControllerHandle,
222 EFI_OPEN_PROTOCOL_BY_DRIVER
223 );
224
225 if (EFI_ERROR (Status)) {
226 return Status;
227 }
228 //
229 // Close the I/O Abstraction(s) used to perform the supported test
230 //
231 gBS->CloseProtocol (
232 ControllerHandle,
233 &gEfiDiskIoProtocolGuid,
234 mImageHandle,
235 ControllerHandle
236 );
237
238 // Check that BlockIo protocol instance exists
239 Status = gBS->OpenProtocol (
240 ControllerHandle,
241 &gEfiBlockIoProtocolGuid,
242 NULL,
243 mImageHandle,
244 ControllerHandle,
245 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
246 );
247 if (EFI_ERROR (Status)) {
248 return Status;
249 }
250
251 // Check if a DevicePath is attached to the handle
252 Status = gBS->OpenProtocol (
253 ControllerHandle,
254 &gEfiDevicePathProtocolGuid,
255 (VOID **)&DevicePathProtocol,
256 mImageHandle,
257 ControllerHandle,
258 EFI_OPEN_PROTOCOL_BY_DRIVER
259 );
260 if (EFI_ERROR (Status)) {
261 return Status;
262 }
263
264 // Check if the Device Path is the one which contains the Boot Monitor File System
265 Size1 = GetDevicePathSize (DevicePathProtocol);
266
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);
272
273 if ((Size1 == Size2) && (CompareMem (DevicePathProtocol, SupportedDevicePath, Size1) == 0)) {
274 // The Device Path is supported
275 Status = EFI_SUCCESS;
276 break;
277 }
278 }
279
280 gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, mImageHandle, ControllerHandle);
281 return Status;
282 }
283
284 EFI_STATUS
285 EFIAPI
286 BootMonFsDriverStart (
287 IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
288 IN EFI_HANDLE ControllerHandle,
289 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
290 )
291 {
292 BOOTMON_FS_INSTANCE *Instance;
293 EFI_STATUS Status;
294 UINTN VolumeNameSize;
295
296 Instance = AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE));
297 if (Instance == NULL) {
298 return EFI_OUT_OF_RESOURCES;
299 }
300
301 // Initialize the BlockIo of the Instance
302 Status = gBS->OpenProtocol (
303 ControllerHandle,
304 &gEfiBlockIoProtocolGuid,
305 (VOID **)&(Instance->BlockIo),
306 mImageHandle,
307 ControllerHandle,
308 EFI_OPEN_PROTOCOL_GET_PROTOCOL
309 );
310 if (EFI_ERROR (Status)) {
311 FreePool (Instance);
312 return Status;
313 }
314
315 Status = gBS->OpenProtocol (
316 ControllerHandle,
317 &gEfiDiskIoProtocolGuid,
318 (VOID **)&(Instance->DiskIo),
319 mImageHandle,
320 ControllerHandle,
321 EFI_OPEN_PROTOCOL_BY_DRIVER
322 );
323 if (EFI_ERROR (Status)) {
324 FreePool (Instance);
325 return Status;
326 }
327
328 //
329 // Initialize the attributes of the Instance
330 //
331 Instance->Signature = BOOTMON_FS_SIGNATURE;
332 Instance->ControllerHandle = ControllerHandle;
333 Instance->Media = Instance->BlockIo->Media;
334 Instance->Binding = DriverBinding;
335
336 // Initialize the Simple File System Protocol
337 Instance->Fs.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
338 Instance->Fs.OpenVolume = OpenBootMonFsOpenVolume;
339
340 // Volume name + L' ' + '2' digit number
341 VolumeNameSize = StrSize (BOOTMON_FS_VOLUME_LABEL) + (3 * sizeof (CHAR16));
342
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));
350
351 // Initialize the root file
352 Status = BootMonFsCreateFile (Instance, &Instance->RootFile);
353 if (EFI_ERROR (Status)) {
354 FreePool (Instance);
355 return Status;
356 }
357
358 // Initialize the DevicePath of the Instance
359 Status = gBS->OpenProtocol (
360 ControllerHandle,
361 &gEfiDevicePathProtocolGuid,
362 (VOID **)&(Instance->DevicePath),
363 mImageHandle,
364 ControllerHandle,
365 EFI_OPEN_PROTOCOL_GET_PROTOCOL
366 );
367 if (EFI_ERROR (Status)) {
368 FreePool (Instance);
369 return Status;
370 }
371
372 //
373 // Install the Simple File System Protocol
374 //
375 Status = gBS->InstallMultipleProtocolInterfaces (
376 &ControllerHandle,
377 &gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
378 NULL
379 );
380
381 InsertTailList (&mInstances, &Instance->Link);
382
383 return Status;
384 }
385
386
387 EFI_STATUS
388 EFIAPI
389 BootMonFsDriverStop (
390 IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding,
391 IN EFI_HANDLE ControllerHandle,
392 IN UINTN NumberOfChildren,
393 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
394 )
395 {
396 BOOTMON_FS_INSTANCE *Instance;
397 LIST_ENTRY *Link;
398 EFI_STATUS Status;
399 BOOLEAN InstanceFound;
400
401 // Find instance from ControllerHandle.
402 Instance = NULL;
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);
407
408 if (Instance->ControllerHandle == ControllerHandle) {
409 InstanceFound = TRUE;
410 break;
411 }
412 }
413 ASSERT (InstanceFound == TRUE);
414
415 gBS->CloseProtocol (
416 ControllerHandle,
417 &gEfiDevicePathProtocolGuid,
418 DriverBinding->ImageHandle,
419 ControllerHandle);
420
421 gBS->CloseProtocol (
422 ControllerHandle,
423 &gEfiDiskIoProtocolGuid,
424 DriverBinding->ImageHandle,
425 ControllerHandle);
426
427 gBS->CloseProtocol (
428 ControllerHandle,
429 &gEfiBlockIoProtocolGuid,
430 DriverBinding->ImageHandle,
431 ControllerHandle);
432
433 Status = gBS->UninstallMultipleProtocolInterfaces (
434 &ControllerHandle,
435 &gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
436 NULL);
437
438 return Status;
439 }
440
441 //
442 // Simple Network Protocol Driver Global Variables
443 //
444 EFI_DRIVER_BINDING_PROTOCOL mBootMonFsDriverBinding = {
445 BootMonFsDriverSupported,
446 BootMonFsDriverStart,
447 BootMonFsDriverStop,
448 0xa,
449 NULL,
450 NULL
451 };
452
453 EFI_STATUS
454 EFIAPI
455 BootMonFsEntryPoint (
456 IN EFI_HANDLE ImageHandle,
457 IN EFI_SYSTEM_TABLE *SystemTable
458 )
459 {
460 EFI_STATUS Status;
461
462 mImageHandle = ImageHandle;
463 InitializeListHead (&mInstances);
464
465 // Initialize the list of Device Paths that could support BootMonFs
466 Status = SupportedDevicePathsInit ();
467 if (!EFI_ERROR (Status)) {
468 Status = gBS->InstallMultipleProtocolInterfaces (
469 &ImageHandle,
470 &gEfiDriverBindingProtocolGuid, &mBootMonFsDriverBinding,
471 NULL
472 );
473 ASSERT_EFI_ERROR (Status);
474 } else {
475 DEBUG((EFI_D_ERROR,"Warning: No Device Paths supporting BootMonFs have been defined in the PCD.\n"));
476 }
477
478 return Status;
479 }