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