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