]> git.proxmox.com Git - mirror_edk2.git/blob - FatPkg/FatPei/FatLiteApi.c
Only traverse recovery file's FAT table to fast the recovery performance.
[mirror_edk2.git] / FatPkg / FatPei / FatLiteApi.c
1 /** @file
2 FAT recovery PEIM entry point, Ppi Functions and FAT Api functions.
3
4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials are licensed and made available
7 under the terms and conditions of the BSD License which accompanies this
8 distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "FatLitePeim.h"
17
18 PEI_FAT_PRIVATE_DATA *mPrivateData = NULL;
19
20 /**
21 BlockIo installation nofication function. Find out all the current BlockIO
22 PPIs in the system and add them into private data. Assume there is
23
24 @param PeiServices General purpose services available to every
25 PEIM.
26 @param NotifyDescriptor The typedef structure of the notification
27 descriptor. Not used in this function.
28 @param Ppi The typedef structure of the PPI descriptor.
29 Not used in this function.
30
31 @retval EFI_SUCCESS The function completed successfully.
32
33 **/
34 EFI_STATUS
35 EFIAPI
36 BlockIoNotifyEntry (
37 IN EFI_PEI_SERVICES **PeiServices,
38 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
39 IN VOID *Ppi
40 );
41
42
43 /**
44 Discover all the block I/O devices to find the FAT volume.
45
46 @param PrivateData Global memory map for accessing global
47 variables.
48
49 @retval EFI_SUCCESS The function completed successfully.
50
51 **/
52 EFI_STATUS
53 UpdateBlocksAndVolumes (
54 IN OUT PEI_FAT_PRIVATE_DATA *PrivateData
55 )
56 {
57 EFI_STATUS Status;
58 EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor;
59 UINTN BlockIoPpiInstance;
60 EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
61 UINTN NumberBlockDevices;
62 UINTN Index;
63 EFI_PEI_BLOCK_IO_MEDIA Media;
64 PEI_FAT_VOLUME Volume;
65 EFI_PEI_SERVICES **PeiServices;
66
67 PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();
68
69 //
70 // Clean up caches
71 //
72 for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {
73 PrivateData->CacheBuffer[Index].Valid = FALSE;
74 }
75
76 PrivateData->BlockDeviceCount = 0;
77
78 //
79 // Find out all Block Io Ppi instances within the system
80 // Assuming all device Block Io Peims are dispatched already
81 //
82 for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_FAT_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {
83 Status = PeiServicesLocatePpi (
84 &gEfiPeiVirtualBlockIoPpiGuid,
85 BlockIoPpiInstance,
86 &TempPpiDescriptor,
87 (VOID **) &BlockIoPpi
88 );
89 if (EFI_ERROR (Status)) {
90 //
91 // Done with all Block Io Ppis
92 //
93 break;
94 }
95
96 Status = BlockIoPpi->GetNumberOfBlockDevices (
97 PeiServices,
98 BlockIoPpi,
99 &NumberBlockDevices
100 );
101 if (EFI_ERROR (Status)) {
102 continue;
103 }
104
105 for (Index = 1; Index <= NumberBlockDevices && PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE; Index++) {
106
107 Status = BlockIoPpi->GetBlockDeviceMediaInfo (
108 PeiServices,
109 BlockIoPpi,
110 Index,
111 &Media
112 );
113 if (EFI_ERROR (Status) || !Media.MediaPresent) {
114 continue;
115 }
116
117 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = (UINT32) Media.BlockSize;
118 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media.LastBlock;
119 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign = 0;
120 //
121 // Not used here
122 //
123 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].Logical = FALSE;
124 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PartitionChecked = FALSE;
125
126 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo = BlockIoPpi;
127 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PhysicalDevNo = (UINT8) Index;
128 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].DevType = Media.DeviceType;
129
130 PrivateData->BlockDeviceCount++;
131 }
132 }
133 //
134 // Find out all logical devices
135 //
136 FatFindPartitions (PrivateData);
137
138 //
139 // Build up file system volume array
140 //
141 PrivateData->VolumeCount = 0;
142 for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {
143 Volume.BlockDeviceNo = Index;
144 Status = FatGetBpbInfo (PrivateData, &Volume);
145 if (Status == EFI_SUCCESS) {
146 //
147 // Add the detected volume to the volume array
148 //
149 CopyMem (
150 (UINT8 *) &(PrivateData->Volume[PrivateData->VolumeCount]),
151 (UINT8 *) &Volume,
152 sizeof (PEI_FAT_VOLUME)
153 );
154 PrivateData->VolumeCount += 1;
155 if (PrivateData->VolumeCount >= PEI_FAT_MAX_VOLUME) {
156 break;
157 }
158 }
159 }
160
161 return EFI_SUCCESS;
162 }
163
164
165 /**
166 BlockIo installation notification function. Find out all the current BlockIO
167 PPIs in the system and add them into private data. Assume there is
168
169 @param PeiServices General purpose services available to every
170 PEIM.
171 @param NotifyDescriptor The typedef structure of the notification
172 descriptor. Not used in this function.
173 @param Ppi The typedef structure of the PPI descriptor.
174 Not used in this function.
175
176 @retval EFI_SUCCESS The function completed successfully.
177
178 **/
179 EFI_STATUS
180 EFIAPI
181 BlockIoNotifyEntry (
182 IN EFI_PEI_SERVICES **PeiServices,
183 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
184 IN VOID *Ppi
185 )
186 {
187 UpdateBlocksAndVolumes (mPrivateData);
188
189 return EFI_SUCCESS;
190 }
191
192
193 /**
194 Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
195 installation notification
196
197 @param FileHandle Handle of the file being invoked. Type
198 EFI_PEI_FILE_HANDLE is defined in
199 FfsFindNextFile().
200 @param PeiServices Describes the list of possible PEI Services.
201
202 @retval EFI_SUCCESS The entry point was executed successfully.
203 @retval EFI_OUT_OF_RESOURCES There is no enough memory to complete the
204 operations.
205
206 **/
207 EFI_STATUS
208 EFIAPI
209 FatPeimEntry (
210 IN EFI_PEI_FILE_HANDLE FileHandle,
211 IN CONST EFI_PEI_SERVICES **PeiServices
212 )
213 {
214 EFI_STATUS Status;
215 EFI_PHYSICAL_ADDRESS Address;
216 PEI_FAT_PRIVATE_DATA *PrivateData;
217
218 Status = PeiServicesRegisterForShadow (FileHandle);
219 if (!EFI_ERROR (Status)) {
220 return Status;
221 }
222
223 Status = PeiServicesAllocatePages (
224 EfiBootServicesCode,
225 (sizeof (PEI_FAT_PRIVATE_DATA) - 1) / PEI_FAT_MEMMORY_PAGE_SIZE + 1,
226 &Address
227 );
228 if (EFI_ERROR (Status)) {
229 return EFI_OUT_OF_RESOURCES;
230 }
231
232 PrivateData = (PEI_FAT_PRIVATE_DATA *) (UINTN) Address;
233
234 //
235 // Initialize Private Data (to zero, as is required by subsequent operations)
236 //
237 ZeroMem ((UINT8 *) PrivateData, sizeof (PEI_FAT_PRIVATE_DATA));
238
239 PrivateData->Signature = PEI_FAT_PRIVATE_DATA_SIGNATURE;
240
241 //
242 // Installs Ppi
243 //
244 PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules;
245 PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo;
246 PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule;
247
248 PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
249 PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid;
250 PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi;
251
252 Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor);
253 if (EFI_ERROR (Status)) {
254 return EFI_OUT_OF_RESOURCES;
255 }
256 //
257 // Other initializations
258 //
259 PrivateData->BlockDeviceCount = 0;
260
261 UpdateBlocksAndVolumes (PrivateData);
262
263 //
264 // PrivateData is allocated now, set it to the module variable
265 //
266 mPrivateData = PrivateData;
267
268 //
269 // Installs Block Io Ppi notification function
270 //
271 PrivateData->NotifyDescriptor.Flags =
272 (
273 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
274 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
275 );
276 PrivateData->NotifyDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid;
277 PrivateData->NotifyDescriptor.Notify = BlockIoNotifyEntry;
278 return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor);
279 }
280
281
282 /**
283 Returns the number of DXE capsules residing on the device.
284
285 This function searches for DXE capsules from the associated device and returns
286 the number and maximum size in bytes of the capsules discovered. Entry 1 is
287 assumed to be the highest load priority and entry N is assumed to be the lowest
288 priority.
289
290 @param[in] PeiServices General-purpose services that are available
291 to every PEIM
292 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
293 instance.
294 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
295 output, *NumberRecoveryCapsules contains
296 the number of recovery capsule images
297 available for retrieval from this PEIM
298 instance.
299
300 @retval EFI_SUCCESS One or more capsules were discovered.
301 @retval EFI_DEVICE_ERROR A device error occurred.
302 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
303
304 **/
305 EFI_STATUS
306 EFIAPI
307 GetNumberRecoveryCapsules (
308 IN EFI_PEI_SERVICES **PeiServices,
309 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
310 OUT UINTN *NumberRecoveryCapsules
311 )
312 {
313 EFI_STATUS Status;
314 PEI_FAT_PRIVATE_DATA *PrivateData;
315 UINTN Index;
316 UINTN RecoveryCapsuleCount;
317 PEI_FILE_HANDLE Handle;
318
319 PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);
320
321 //
322 // Search each volume in the root directory for the Recovery capsule
323 //
324 RecoveryCapsuleCount = 0;
325 for (Index = 0; Index < PrivateData->VolumeCount; Index++) {
326 Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);
327 if (EFI_ERROR (Status)) {
328 continue;
329 }
330
331 RecoveryCapsuleCount++;
332 }
333
334 *NumberRecoveryCapsules = RecoveryCapsuleCount;
335
336 if (*NumberRecoveryCapsules == 0) {
337 return EFI_NOT_FOUND;
338 }
339
340 return EFI_SUCCESS;
341 }
342
343
344 /**
345 Returns the size and type of the requested recovery capsule.
346
347 This function gets the size and type of the capsule specified by CapsuleInstance.
348
349 @param[in] PeiServices General-purpose services that are available to every PEIM
350 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
351 instance.
352 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
353 the information. This parameter must be between
354 one and the value returned by GetNumberRecoveryCapsules()
355 in NumberRecoveryCapsules.
356 @param[out] Size A pointer to a caller-allocated UINTN in which
357 the size of the requested recovery module is
358 returned.
359 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
360 the type of the requested recovery capsule is
361 returned. The semantic meaning of the value
362 returned is defined by the implementation.
363
364 @retval EFI_SUCCESS One or more capsules were discovered.
365 @retval EFI_DEVICE_ERROR A device error occurred.
366 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
367
368 **/
369 EFI_STATUS
370 EFIAPI
371 GetRecoveryCapsuleInfo (
372 IN EFI_PEI_SERVICES **PeiServices,
373 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
374 IN UINTN CapsuleInstance,
375 OUT UINTN *Size,
376 OUT EFI_GUID *CapsuleType
377 )
378 {
379 EFI_STATUS Status;
380 PEI_FAT_PRIVATE_DATA *PrivateData;
381 UINTN Index;
382 UINTN BlockDeviceNo;
383 UINTN RecoveryCapsuleCount;
384 PEI_FILE_HANDLE Handle;
385 UINTN NumberRecoveryCapsules;
386
387 Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
388
389 if (EFI_ERROR (Status)) {
390 return Status;
391 }
392
393 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
394 CapsuleInstance = CapsuleInstance + 1;
395 }
396
397 if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
398 return EFI_NOT_FOUND;
399 }
400
401 PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);
402
403 //
404 // Search each volume in the root directory for the Recovery capsule
405 //
406 RecoveryCapsuleCount = 0;
407 for (Index = 0; Index < PrivateData->VolumeCount; Index++) {
408 Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);
409
410 if (EFI_ERROR (Status)) {
411 continue;
412 }
413
414 if (CapsuleInstance - 1 == RecoveryCapsuleCount) {
415 //
416 // Get file size
417 //
418 *Size = (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize);
419
420 //
421 // Find corresponding physical block device
422 //
423 BlockDeviceNo = PrivateData->Volume[Index].BlockDeviceNo;
424 while (PrivateData->BlockDevice[BlockDeviceNo].Logical && BlockDeviceNo < PrivateData->BlockDeviceCount) {
425 BlockDeviceNo = PrivateData->BlockDevice[BlockDeviceNo].ParentDevNo;
426 }
427 //
428 // Fill in the Capsule Type GUID according to the block device type
429 //
430 if (BlockDeviceNo < PrivateData->BlockDeviceCount) {
431 switch (PrivateData->BlockDevice[BlockDeviceNo].DevType) {
432 case LegacyFloppy:
433 CopyGuid (CapsuleType, &gRecoveryOnFatFloppyDiskGuid);
434 break;
435
436 case IdeCDROM:
437 case IdeLS120:
438 CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid);
439 break;
440
441 case UsbMassStorage:
442 CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid);
443 break;
444
445 default:
446 break;
447 }
448 }
449
450 return EFI_SUCCESS;
451 }
452
453 RecoveryCapsuleCount++;
454 }
455
456 return EFI_NOT_FOUND;
457 }
458
459
460 /**
461 Loads a DXE capsule from some media into memory.
462
463 This function, by whatever mechanism, retrieves a DXE capsule from some device
464 and loads it into memory. Note that the published interface is device neutral.
465
466 @param[in] PeiServices General-purpose services that are available
467 to every PEIM
468 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
469 instance.
470 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
471 @param[out] Buffer Specifies a caller-allocated buffer in which
472 the requested recovery capsule will be returned.
473
474 @retval EFI_SUCCESS The capsule was loaded correctly.
475 @retval EFI_DEVICE_ERROR A device error occurred.
476 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
477
478 **/
479 EFI_STATUS
480 EFIAPI
481 LoadRecoveryCapsule (
482 IN EFI_PEI_SERVICES **PeiServices,
483 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
484 IN UINTN CapsuleInstance,
485 OUT VOID *Buffer
486 )
487 {
488 EFI_STATUS Status;
489 PEI_FAT_PRIVATE_DATA *PrivateData;
490 UINTN Index;
491 UINTN RecoveryCapsuleCount;
492 PEI_FILE_HANDLE Handle;
493 UINTN NumberRecoveryCapsules;
494
495 Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
496
497 if (EFI_ERROR (Status)) {
498 return Status;
499 }
500
501 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
502 CapsuleInstance = CapsuleInstance + 1;
503 }
504
505 if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
506 return EFI_NOT_FOUND;
507 }
508
509 PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);
510
511 //
512 // Search each volume in the root directory for the Recovery capsule
513 //
514 RecoveryCapsuleCount = 0;
515 for (Index = 0; Index < PrivateData->VolumeCount; Index++) {
516 Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);
517 if (EFI_ERROR (Status)) {
518 continue;
519 }
520
521 if (CapsuleInstance - 1 == RecoveryCapsuleCount) {
522
523 Status = FatReadFile (
524 PrivateData,
525 Handle,
526 (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize),
527 Buffer
528 );
529 return Status;
530 }
531
532 RecoveryCapsuleCount++;
533 }
534
535 return EFI_NOT_FOUND;
536 }
537
538
539 /**
540 Finds the recovery file on a FAT volume.
541 This function finds the the recovery file named FileName on a specified FAT volume and returns
542 its FileHandle pointer.
543
544 @param PrivateData Global memory map for accessing global
545 variables.
546 @param VolumeIndex The index of the volume.
547 @param FileName The recovery file name to find.
548 @param Handle The output file handle.
549
550 @retval EFI_DEVICE_ERROR Some error occured when operating the FAT
551 volume.
552 @retval EFI_NOT_FOUND The recovery file was not found.
553 @retval EFI_SUCCESS The recovery file was successfully found on the
554 FAT volume.
555
556 **/
557 EFI_STATUS
558 FindRecoveryFile (
559 IN PEI_FAT_PRIVATE_DATA *PrivateData,
560 IN UINTN VolumeIndex,
561 IN CHAR16 *FileName,
562 OUT PEI_FILE_HANDLE *Handle
563 )
564 {
565 EFI_STATUS Status;
566 PEI_FAT_FILE Parent;
567 PEI_FAT_FILE *File;
568
569 File = &PrivateData->File;
570
571 //
572 // VolumeIndex must be less than PEI_FAT_MAX_VOLUME because PrivateData->VolumeCount
573 // cannot be larger than PEI_FAT_MAX_VOLUME when detecting recovery volume.
574 //
575 ASSERT (VolumeIndex < PEI_FAT_MAX_VOLUME);
576
577 //
578 // Construct root directory file
579 //
580 ZeroMem (&Parent, sizeof (PEI_FAT_FILE));
581 Parent.IsFixedRootDir = (BOOLEAN) ((PrivateData->Volume[VolumeIndex].FatType == Fat32) ? FALSE : TRUE);
582 Parent.Attributes = FAT_ATTR_DIRECTORY;
583 Parent.CurrentPos = 0;
584 Parent.CurrentCluster = Parent.IsFixedRootDir ? 0 : PrivateData->Volume[VolumeIndex].RootDirCluster;
585 Parent.StartingCluster = Parent.CurrentCluster;
586 Parent.Volume = &PrivateData->Volume[VolumeIndex];
587
588 Status = FatSetFilePos (PrivateData, &Parent, 0);
589 if (EFI_ERROR (Status)) {
590 return EFI_DEVICE_ERROR;
591 }
592 //
593 // Search for recovery capsule in root directory
594 //
595 Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);
596 while (Status == EFI_SUCCESS) {
597 //
598 // Compare whether the file name is recovery file name.
599 //
600 if (EngStriColl (PrivateData, FileName, File->FileName)) {
601 break;
602 }
603
604 Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);
605 }
606
607 if (EFI_ERROR (Status)) {
608 return EFI_NOT_FOUND;
609 }
610
611 //
612 // Get the recovery file, set its file position to 0.
613 //
614 if (File->StartingCluster != 0) {
615 Status = FatSetFilePos (PrivateData, File, 0);
616 }
617
618 *Handle = File;
619
620 return EFI_SUCCESS;
621
622 }