]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/FwVol/FwVol.c
Add doxygen style comments for functions in DxeMain.
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / FwVol / FwVol.c
1 /** @file
2 Firmware File System driver that produce Firmware Volume protocol.
3 Layers on top of Firmware Block protocol to produce a file abstraction
4 of FV based files.
5
6 Copyright (c) 2006 - 2008 Intel Corporation. <BR>
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include <DxeMain.h>
18
19 #define KEYSIZE sizeof (UINTN)
20
21 //
22 // Protocol notify related globals
23 //
24 VOID *gEfiFwVolBlockNotifyReg;
25 EFI_EVENT gEfiFwVolBlockEvent;
26
27 FV_DEVICE mFvDevice = {
28 FV2_DEVICE_SIGNATURE,
29 NULL,
30 NULL,
31 {
32 FvGetVolumeAttributes,
33 FvSetVolumeAttributes,
34 FvReadFile,
35 FvReadFileSection,
36 FvWriteFile,
37 FvGetNextFile,
38 KEYSIZE,
39 NULL,
40 FvGetVolumeInfo,
41 FvSetVolumeInfo
42 },
43 NULL,
44 NULL,
45 NULL,
46 NULL,
47 { NULL, NULL },
48 0
49 };
50
51
52 //
53 // FFS helper functions
54 //
55
56
57 /**
58 given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
59 copy the volume header into it.
60
61 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
62 read the volume header
63 @param FwVolHeader Pointer to pointer to allocated buffer in which
64 the volume header is returned.
65
66 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
67 @retval EFI_SUCCESS Successfully read volume header to the allocated
68 buffer.
69
70 **/
71 EFI_STATUS
72 GetFwVolHeader (
73 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
74 OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
75 )
76 {
77 EFI_STATUS Status;
78 EFI_FIRMWARE_VOLUME_HEADER TempFvh;
79 UINTN FvhLength;
80 UINT8 *Buffer;
81
82
83 //
84 //Determine the real length of FV header
85 //
86 FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
87 Status = Fvb->Read (Fvb, 0, 0, &FvhLength, (UINT8 *)&TempFvh);
88
89 //
90 // Allocate a buffer for the caller
91 //
92 *FwVolHeader = CoreAllocateBootServicesPool (TempFvh.HeaderLength);
93 if (*FwVolHeader == NULL) {
94 return EFI_OUT_OF_RESOURCES;
95 }
96
97 //
98 // Copy the standard header into the buffer
99 //
100 CopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
101
102 //
103 // Read the rest of the header
104 //
105 FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);
106 Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);
107 Status = Fvb->Read (Fvb, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER), &FvhLength, Buffer);
108 if (EFI_ERROR (Status)) {
109 //
110 // Read failed so free buffer
111 //
112 CoreFreePool (*FwVolHeader);
113 }
114
115 return Status;
116 }
117
118
119
120 /**
121 Free FvDevice resource when error happens
122
123 @param FvDevice pointer to the FvDevice to be freed.
124
125 @return None.
126
127 **/
128 STATIC
129 VOID
130 FreeFvDeviceResource (
131 IN FV_DEVICE *FvDevice
132 )
133 {
134 FFS_FILE_LIST_ENTRY *FfsFileEntry;
135 LIST_ENTRY *NextEntry;
136
137 //
138 // Free File List Entry
139 //
140 FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;
141 while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
142 NextEntry = (&FfsFileEntry->Link)->ForwardLink;
143
144 if (FfsFileEntry->StreamHandle != 0) {
145 //
146 // Close stream and free resources from SEP
147 //
148 CloseSectionStream (FfsFileEntry->StreamHandle);
149 }
150
151 CoreFreePool (FfsFileEntry);
152
153 FfsFileEntry = (FFS_FILE_LIST_ENTRY *)NextEntry;
154 }
155
156
157 //
158 // Free the cache
159 //
160 CoreFreePool (FvDevice->CachedFv);
161
162 //
163 // Free Volume Header
164 //
165 CoreFreePool (FvDevice->FwVolHeader);
166
167 return;
168 }
169
170
171
172 /**
173 Check if a FV is consistent and allocate cache
174
175 @param FvDevice pointer to the FvDevice to be checked.
176
177 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
178 @retval EFI_SUCCESS FV is consistent and cache is allocated.
179 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
180
181 **/
182 EFI_STATUS
183 FvCheck (
184 IN OUT FV_DEVICE *FvDevice
185 )
186 {
187 EFI_STATUS Status;
188 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
189 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
190 EFI_FVB_ATTRIBUTES FvbAttributes;
191 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
192 FFS_FILE_LIST_ENTRY *FfsFileEntry;
193 EFI_FFS_FILE_HEADER *FfsHeader;
194 UINT8 *CacheLocation;
195 UINTN LbaOffset;
196 UINTN Index;
197 EFI_LBA LbaIndex;
198 UINTN Size;
199 UINTN FileLength;
200 EFI_FFS_FILE_STATE FileState;
201 UINT8 *TopFvAddress;
202 UINTN TestLength;
203
204
205 Fvb = FvDevice->Fvb;
206 FwVolHeader = FvDevice->FwVolHeader;
207
208 Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
209 if (EFI_ERROR (Status)) {
210 return Status;
211 }
212
213 //
214 // Size is the size of the FV minus the head. We have already allocated
215 // the header to check to make sure the volume is valid
216 //
217 Size = (UINTN)(FwVolHeader->FvLength - FwVolHeader->HeaderLength);
218 FvDevice->CachedFv = CoreAllocateBootServicesPool (Size);
219
220 if (FvDevice->CachedFv == NULL) {
221 return EFI_OUT_OF_RESOURCES;
222 }
223
224 //
225 // Remember a pointer to the end fo the CachedFv
226 //
227 FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;
228
229 //
230 // Copy FV minus header into memory using the block map we have all ready
231 // read into memory.
232 //
233 BlockMap = FwVolHeader->BlockMap;
234 CacheLocation = FvDevice->CachedFv;
235 LbaIndex = 0;
236 LbaOffset = FwVolHeader->HeaderLength;
237 while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
238
239 for (Index = 0; Index < BlockMap->NumBlocks; Index ++) {
240
241 Size = BlockMap->Length;
242 if (Index == 0) {
243 //
244 // Cache does not include FV Header
245 //
246 Size -= LbaOffset;
247 }
248 Status = Fvb->Read (Fvb,
249 LbaIndex,
250 LbaOffset,
251 &Size,
252 CacheLocation
253 );
254 //
255 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
256 //
257 if (EFI_ERROR (Status)) {
258 goto Done;
259 }
260
261 //
262 // After we skip Fv Header always read from start of block
263 //
264 LbaOffset = 0;
265
266 LbaIndex++;
267 CacheLocation += Size;
268 }
269 BlockMap++;
270 }
271
272 //
273 // Scan to check the free space & File list
274 //
275 if (FvbAttributes & EFI_FVB2_ERASE_POLARITY) {
276 FvDevice->ErasePolarity = 1;
277 } else {
278 FvDevice->ErasePolarity = 0;
279 }
280
281
282 //
283 // go through the whole FV cache, check the consistence of the FV.
284 // Make a linked list off all the Ffs file headers
285 //
286 Status = EFI_SUCCESS;
287 InitializeListHead (&FvDevice->FfsFileListHeader);
288
289 //
290 // Build FFS list
291 //
292 FfsHeader = (EFI_FFS_FILE_HEADER *)FvDevice->CachedFv;
293 TopFvAddress = FvDevice->EndOfCachedFv;
294 while ((UINT8 *)FfsHeader < TopFvAddress) {
295
296 TestLength = TopFvAddress - ((UINT8 *)FfsHeader);
297 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
298 TestLength = sizeof (EFI_FFS_FILE_HEADER);
299 }
300
301 if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {
302 //
303 // We have found the free space so we are done!
304 //
305 goto Done;
306 }
307
308 if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {
309 if ((FileState == EFI_FILE_HEADER_INVALID) ||
310 (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
311 FfsHeader++;
312
313 continue;
314
315 } else {
316 //
317 // File system is corrputed
318 //
319 Status = EFI_VOLUME_CORRUPTED;
320 goto Done;
321 }
322 }
323
324 if (!IsValidFfsFile (FvDevice->ErasePolarity, FfsHeader)) {
325 //
326 // File system is corrupted
327 //
328 Status = EFI_VOLUME_CORRUPTED;
329 goto Done;
330 }
331
332 //
333 // Size[3] is a three byte array, read 4 bytes and throw one away
334 //
335 FileLength = *(UINT32 *)&FfsHeader->Size[0] & 0x00FFFFFF;
336
337 FileState = GetFileState (FvDevice->ErasePolarity, FfsHeader);
338
339 //
340 // check for non-deleted file
341 //
342 if (FileState != EFI_FILE_DELETED) {
343 //
344 // Create a FFS list entry for each non-deleted file
345 //
346 FfsFileEntry = CoreAllocateZeroBootServicesPool (sizeof (FFS_FILE_LIST_ENTRY));
347 if (FfsFileEntry == NULL) {
348 Status = EFI_OUT_OF_RESOURCES;
349 goto Done;
350 }
351
352 FfsFileEntry->FfsHeader = FfsHeader;
353 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
354 }
355
356 FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FfsHeader) + FileLength);
357
358 //
359 // Adjust pointer to the next 8-byte aligned boundry.
360 //
361 FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);
362
363 }
364
365 Done:
366 if (EFI_ERROR (Status)) {
367 FreeFvDeviceResource (FvDevice);
368 }
369
370 return Status;
371 }
372
373
374
375 /**
376 This notification function is invoked when an instance of the
377 EFI_FW_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
378 EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
379 the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
380
381 @param Event The event that occured
382 @param Context For EFI compatiblity. Not used.
383
384 **/
385 STATIC
386 VOID
387 EFIAPI
388 NotifyFwVolBlock (
389 IN EFI_EVENT Event,
390 IN VOID *Context
391 )
392 {
393 EFI_HANDLE Handle;
394 EFI_STATUS Status;
395 UINTN BufferSize;
396 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
397 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
398 FV_DEVICE *FvDevice;
399 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
400 //
401 // Examine all new handles
402 //
403 for (;;) {
404 //
405 // Get the next handle
406 //
407 BufferSize = sizeof (Handle);
408 Status = CoreLocateHandle (
409 ByRegisterNotify,
410 NULL,
411 gEfiFwVolBlockNotifyReg,
412 &BufferSize,
413 &Handle
414 );
415
416 //
417 // If not found, we're done
418 //
419 if (EFI_NOT_FOUND == Status) {
420 break;
421 }
422
423 if (EFI_ERROR (Status)) {
424 continue;
425 }
426
427 //
428 // Get the FirmwareVolumeBlock protocol on that handle
429 //
430 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
431 ASSERT_EFI_ERROR (Status);
432
433
434 //
435 // Make sure the Fv Header is O.K.
436 //
437 Status = GetFwVolHeader (Fvb, &FwVolHeader);
438 if (EFI_ERROR (Status)) {
439 return;
440 }
441
442 if (!VerifyFvHeaderChecksum (FwVolHeader)) {
443 CoreFreePool (FwVolHeader);
444 continue;
445 }
446
447
448 //
449 // Check to see that the file system is indeed formatted in a way we can
450 // understand it...
451 //
452 if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) {
453 continue;
454 }
455
456 //
457 // Check if there is an FV protocol already installed in that handle
458 //
459 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
460 if (!EFI_ERROR (Status)) {
461 //
462 // Update Fv to use a new Fvb
463 //
464 FvDevice = _CR (Fv, FV_DEVICE, Fv);
465 if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {
466 //
467 // Only write into our device structure if it's our device structure
468 //
469 FvDevice->Fvb = Fvb;
470 }
471
472 } else {
473 //
474 // No FwVol protocol on the handle so create a new one
475 //
476 FvDevice = CoreAllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);
477 if (FvDevice == NULL) {
478 return;
479 }
480
481 FvDevice->Fvb = Fvb;
482 FvDevice->Handle = Handle;
483 FvDevice->FwVolHeader = FwVolHeader;
484 FvDevice->Fv.ParentHandle = Fvb->ParentHandle;
485
486 //
487 // Install an New FV protocol on the existing handle
488 //
489 Status = CoreInstallProtocolInterface (
490 &Handle,
491 &gEfiFirmwareVolume2ProtocolGuid,
492 EFI_NATIVE_INTERFACE,
493 &FvDevice->Fv
494 );
495 ASSERT_EFI_ERROR (Status);
496 }
497 }
498
499 return;
500 }
501
502
503
504 /**
505 This routine is the driver initialization entry point. It initializes the
506 libraries, and registers two notification functions. These notification
507 functions are responsible for building the FV stack dynamically.
508
509 @param ImageHandle The image handle.
510 @param SystemTable The system table.
511
512 @retval EFI_SUCCESS Function successfully returned.
513
514 **/
515 EFI_STATUS
516 EFIAPI
517 FwVolDriverInit (
518 IN EFI_HANDLE ImageHandle,
519 IN EFI_SYSTEM_TABLE *SystemTable
520 )
521 {
522 gEfiFwVolBlockEvent = CoreCreateProtocolNotifyEvent (
523 &gEfiFirmwareVolumeBlockProtocolGuid,
524 TPL_CALLBACK,
525 NotifyFwVolBlock,
526 NULL,
527 &gEfiFwVolBlockNotifyReg,
528 TRUE
529 );
530 return EFI_SUCCESS;
531 }
532
533