]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/EdkFvbServiceLib/Fvb.c
bf77d80d6f6d7ba4f5fd9c047d2f1c5b10c0feaa
[mirror_edk2.git] / MdeModulePkg / Library / EdkFvbServiceLib / Fvb.c
1 /**@file
2
3 Firmware Volume Block Protocol Runtime Abstraction
4
5 mFvbEntry is an array of Handle Fvb pairs. The Fvb Lib Instance matches the
6 index in the mFvbEntry array. This should be the same sequence as the FVB's
7 were described in the HOB. We have to remember the handle so we can tell if
8 the protocol has been reinstalled and it needs updateing.
9
10 If you are using any of these lib functions.you must first call FvbInitialize ().
11
12 Copyright (c) 2006, Intel Corporation
13 All rights reserved. This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
17
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20
21 **/
22
23
24 #include "Fvb.h"
25
26 //
27 // Event for Set Virtual Map Changed Event
28 //
29 STATIC EFI_EVENT mSetVirtualMapChangedEvent = NULL;
30
31 //
32 // Lib will ASSERT if more FVB devices than this are added to the system.
33 //
34 STATIC FVB_ENTRY *mFvbEntry;
35 STATIC EFI_EVENT mFvbRegistration;
36 STATIC UINTN mFvbCount;
37
38 /**
39 Check whether an address is runtime memory or not.
40
41 @param Address The Address being checked.
42
43 @retval TRUE The address is runtime memory.
44 @retval FALSE The address is not runtime memory.
45 **/
46 BOOLEAN
47 IsRuntimeMemory (
48 IN VOID *Address
49 )
50 {
51 EFI_STATUS Status;
52 UINT8 TmpMemoryMap[1];
53 UINTN MapKey;
54 UINTN DescriptorSize;
55 UINT32 DescriptorVersion;
56 UINTN MemoryMapSize;
57 EFI_MEMORY_DESCRIPTOR *MemoryMap;
58 EFI_MEMORY_DESCRIPTOR *MemoryMapPtr;
59 BOOLEAN IsRuntime;
60 UINTN Index;
61
62 IsRuntime = FALSE;
63
64 //
65 // Get System MemoryMapSize
66 //
67 MemoryMapSize = 1;
68 Status = gBS->GetMemoryMap (
69 &MemoryMapSize,
70 (EFI_MEMORY_DESCRIPTOR *)TmpMemoryMap,
71 &MapKey,
72 &DescriptorSize,
73 &DescriptorVersion
74 );
75 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
76 //
77 // Enlarge space here, because we will allocate pool now.
78 //
79 MemoryMapSize += EFI_PAGE_SIZE;
80 Status = gBS->AllocatePool (
81 EfiBootServicesData,
82 MemoryMapSize,
83 (VOID**)&MemoryMap
84 );
85 ASSERT_EFI_ERROR (Status);
86
87 //
88 // Get System MemoryMap
89 //
90 Status = gBS->GetMemoryMap (
91 &MemoryMapSize,
92 MemoryMap,
93 &MapKey,
94 &DescriptorSize,
95 &DescriptorVersion
96 );
97 ASSERT_EFI_ERROR (Status);
98
99 MemoryMapPtr = MemoryMap;
100 //
101 // Search the request Address
102 //
103 for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {
104 if (((EFI_PHYSICAL_ADDRESS)(UINTN)Address >= MemoryMap->PhysicalStart) &&
105 ((EFI_PHYSICAL_ADDRESS)(UINTN)Address < MemoryMap->PhysicalStart
106 + LShiftU64 (MemoryMap->NumberOfPages, EFI_PAGE_SHIFT))) {
107 //
108 // Found it
109 //
110 if (MemoryMap->Attribute & EFI_MEMORY_RUNTIME) {
111 IsRuntime = TRUE;
112 }
113 break;
114 }
115 //
116 // Get next item
117 //
118 MemoryMap = (EFI_MEMORY_DESCRIPTOR *)((UINTN)MemoryMap + DescriptorSize);
119 }
120
121 //
122 // Done
123 //
124 gBS->FreePool (MemoryMapPtr);
125
126 return IsRuntime;
127 }
128
129 /**
130 Update mFvbEntry. Add new entry, or update existing entry if Fvb protocol is
131 reinstalled.
132
133 @param Event The Event that is being processed
134 @param Context Event Context
135
136 **/
137 STATIC
138 VOID
139 EFIAPI
140 FvbNotificationEvent (
141 IN EFI_EVENT Event,
142 IN VOID *Context
143 )
144 {
145 EFI_STATUS Status;
146 UINTN BufferSize;
147 EFI_HANDLE Handle;
148 UINTN Index;
149 UINTN UpdateIndex;
150
151 while (TRUE) {
152 BufferSize = sizeof (Handle);
153 Status = gBS->LocateHandle (
154 ByRegisterNotify,
155 &gEfiFirmwareVolumeBlockProtocolGuid,
156 mFvbRegistration,
157 &BufferSize,
158 &Handle
159 );
160 if (EFI_ERROR (Status)) {
161 //
162 // Exit Path of While Loop....
163 //
164 break;
165 }
166
167 UpdateIndex = MAX_FVB_COUNT;
168 for (Index = 0; Index < mFvbCount; Index++) {
169 if (mFvbEntry[Index].Handle == Handle) {
170 //
171 // If the handle is already in the table just update the protocol
172 //
173 UpdateIndex = Index;
174 break;
175 }
176 }
177
178 if (UpdateIndex == MAX_FVB_COUNT) {
179 //
180 // Use the next free slot for a new entry
181 //
182 UpdateIndex = mFvbCount++;
183 //
184 // Check the UpdateIndex whether exceed the maximum value.
185 //
186 ASSERT (UpdateIndex < MAX_FVB_COUNT);
187 mFvbEntry[UpdateIndex].Handle = Handle;
188 }
189 //
190 // The array does not have enough entries
191 //
192 ASSERT (UpdateIndex < MAX_FVB_COUNT);
193
194 //
195 // Get the interface pointer and if it's ours, skip it
196 //
197 Status = gBS->HandleProtocol (
198 Handle,
199 &gEfiFirmwareVolumeBlockProtocolGuid,
200 (VOID **) &mFvbEntry[UpdateIndex].Fvb
201 );
202 ASSERT_EFI_ERROR (Status);
203
204 Status = gBS->HandleProtocol (
205 Handle,
206 &gEfiFvbExtensionProtocolGuid,
207 (VOID **) &mFvbEntry[UpdateIndex].FvbExtension
208 );
209 if (Status != EFI_SUCCESS) {
210 mFvbEntry[UpdateIndex].FvbExtension = NULL;
211 }
212
213 //
214 // Check the FVB can be accessed in RUNTIME, The FVBs in FVB handle list comes
215 // from two way:
216 // 1) Dxe Core. (FVB information is transferred from FV HOB).
217 // 2) FVB driver.
218 // The FVB produced Dxe core is used for discoverying DXE driver and dispatch. These
219 // FVBs can only be accessed in boot time.
220 // FVB driver will discovery all FV in FLASH and these FVBs can be accessed in runtime.
221 // The FVB itself produced by FVB driver is allocated in runtime memory. So we can
222 // determine the what FVB can be accessed in RUNTIME by judging whether FVB itself is allocated
223 // in RUNTIME memory.
224 //
225 mFvbEntry[UpdateIndex].IsRuntimeAccess = IsRuntimeMemory (mFvbEntry[UpdateIndex].Fvb);
226 }
227 }
228
229 /**
230 Convert all pointers in mFvbEntry after ExitBootServices.
231
232 @param Event The Event that is being processed
233 @param Context Event Context
234
235 **/
236 VOID
237 EFIAPI
238 FvbVirtualAddressChangeNotifyEvent (
239 IN EFI_EVENT Event,
240 IN VOID *Context
241 )
242 {
243 UINTN Index;
244 if (mFvbEntry != NULL) {
245 for (Index = 0; Index < MAX_FVB_COUNT; Index++) {
246 if (!mFvbEntry[Index].IsRuntimeAccess) {
247 continue;
248 }
249
250 if (NULL != mFvbEntry[Index].Fvb) {
251 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetBlockSize);
252 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetPhysicalAddress);
253 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->GetAttributes);
254 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->SetAttributes);
255 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->Read);
256 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->Write);
257 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb->EraseBlocks);
258 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].Fvb);
259 }
260
261 if (NULL != mFvbEntry[Index].FvbExtension) {
262 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].FvbExtension->EraseFvbCustomBlock);
263 EfiConvertPointer (0x0, (VOID **) &mFvbEntry[Index].FvbExtension);
264 }
265 }
266
267 EfiConvertPointer (0x0, (VOID **) &mFvbEntry);
268 }
269 }
270
271 /**
272 Library constructor function entry.
273
274 @param ImageHandle The handle of image who call this libary.
275 @param SystemTable The point of System Table.
276
277 @retval EFI_SUCESS Sucess construct this library.
278 @retval Others Fail to contruct this libary.
279 **/
280 EFI_STATUS
281 EFIAPI
282 FvbLibInitialize (
283 IN EFI_HANDLE ImageHandle,
284 IN EFI_SYSTEM_TABLE *SystemTable
285 )
286 {
287 UINTN Status;
288 mFvbCount = 0;
289
290 Status = gBS->AllocatePool (
291 EfiRuntimeServicesData,
292 (UINTN) sizeof (FVB_ENTRY) * MAX_FVB_COUNT,
293 (VOID *) &mFvbEntry
294 );
295
296 if (EFI_ERROR (Status)) {
297 return Status;
298 }
299
300 ZeroMem (mFvbEntry, sizeof (FVB_ENTRY) * MAX_FVB_COUNT);
301
302 EfiCreateProtocolNotifyEvent (
303 &gEfiFirmwareVolumeBlockProtocolGuid,
304 TPL_CALLBACK,
305 FvbNotificationEvent,
306 NULL,
307 &mFvbRegistration
308 );
309
310 //
311 // Register SetVirtualAddressMap () notify function
312 //
313 Status = gBS->CreateEvent (
314 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
315 TPL_NOTIFY,
316 FvbVirtualAddressChangeNotifyEvent,
317 NULL,
318 &mSetVirtualMapChangedEvent
319 );
320 ASSERT_EFI_ERROR (Status);
321
322 return EFI_SUCCESS;
323 }
324
325 //
326 // =============================================================================
327 // The following functions wrap Fvb protocol in the Runtime Lib functions.
328 // The Instance translates into Fvb instance. The Fvb order defined by HOBs and
329 // thus the sequence of FVB protocol addition define Instance.
330 //
331 // EfiFvbInitialize () must be called before any of the following functions
332 // must be called.
333 // =============================================================================
334 //
335
336 /**
337 Reads specified number of bytes into a buffer from the specified block
338
339 @param Instance The FV instance to be read from.
340 @param Lba The logical block address to be read from
341 @param Offset Offset into the block at which to begin reading
342 @param NumBytes Pointer that on input contains the total size of
343 the buffer. On output, it contains the total number
344 of bytes read
345 @param Buffer Pointer to a caller allocated buffer that will be
346 used to hold the data read
347
348 @retval EFI_INVALID_PARAMETER Invalid parameter
349 @retval EFI_SUCESS Sucess to Read block
350 @retval Others Fail to read block
351 **/
352 EFI_STATUS
353 EfiFvbReadBlock (
354 IN UINTN Instance,
355 IN EFI_LBA Lba,
356 IN UINTN Offset,
357 IN OUT UINTN *NumBytes,
358 OUT UINT8 *Buffer
359 )
360 {
361 ASSERT (NumBytes != NULL);
362 ASSERT (Buffer != NULL);
363
364 if (Instance >= mFvbCount) {
365 return EFI_INVALID_PARAMETER;
366 }
367
368 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {
369 return EFI_INVALID_PARAMETER;
370 }
371
372 return mFvbEntry[Instance].Fvb->Read (mFvbEntry[Instance].Fvb, Lba, Offset, NumBytes, Buffer);
373 }
374
375 /**
376 Writes specified number of bytes from the input buffer to the block
377
378 @param Instance The FV instance to be written to
379 @param Lba The starting logical block index to write to
380 @param Offset Offset into the block at which to begin writing
381 @param NumBytes Pointer that on input contains the total size of
382 the buffer. On output, it contains the total number
383 of bytes actually written
384 @param Buffer Pointer to a caller allocated buffer that contains
385 the source for the write
386
387 @retval EFI_INVALID_PARAMETER Invalid parameter
388 @retval EFI_SUCESS Sucess to write block
389 @retval Others Fail to write block
390 **/
391 EFI_STATUS
392 EfiFvbWriteBlock (
393 IN UINTN Instance,
394 IN EFI_LBA Lba,
395 IN UINTN Offset,
396 IN OUT UINTN *NumBytes,
397 IN UINT8 *Buffer
398 )
399 {
400 ASSERT (NumBytes != NULL);
401
402 if (Instance >= mFvbCount) {
403 return EFI_INVALID_PARAMETER;
404 }
405
406 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {
407 return EFI_INVALID_PARAMETER;
408 }
409
410 return mFvbEntry[Instance].Fvb->Write (mFvbEntry[Instance].Fvb, Lba, Offset, NumBytes, Buffer);
411 }
412
413 /**
414 Erases and initializes a firmware volume block
415
416 @param Instance The FV instance to be erased
417 @param Lba The logical block index to be erased
418
419 @retval EFI_INVALID_PARAMETER Invalid parameter
420 @retval EFI_SUCESS Sucess to erase block
421 @retval Others Fail to erase block
422 **/
423 EFI_STATUS
424 EfiFvbEraseBlock (
425 IN UINTN Instance,
426 IN EFI_LBA Lba
427 )
428 {
429 if (Instance >= mFvbCount) {
430 return EFI_INVALID_PARAMETER;
431 }
432
433 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {
434 return EFI_INVALID_PARAMETER;
435 }
436
437 return mFvbEntry[Instance].Fvb->EraseBlocks (mFvbEntry[Instance].Fvb, Lba, 1, EFI_LBA_LIST_TERMINATOR);
438 }
439
440 /**
441 Retrieves attributes, insures positive polarity of attribute bits, returns
442 resulting attributes in output parameter
443
444 @param Instance The FV instance whose attributes is going to be returned
445 @param Attributes Output buffer which contains attributes
446
447 @retval EFI_INVALID_PARAMETER Invalid parameter
448 @retval EFI_SUCESS Sucess to get Fv attribute
449 @retval Others Fail to get Fv attribute
450 **/
451 EFI_STATUS
452 EfiFvbGetVolumeAttributes (
453 IN UINTN Instance,
454 OUT EFI_FVB_ATTRIBUTES *Attributes
455 )
456 {
457 ASSERT (Attributes != NULL);
458
459 if (Instance >= mFvbCount) {
460 return EFI_INVALID_PARAMETER;
461 }
462
463 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {
464 return EFI_INVALID_PARAMETER;
465 }
466
467 return mFvbEntry[Instance].Fvb->GetAttributes (mFvbEntry[Instance].Fvb, Attributes);
468 }
469
470 /**
471 Modifies the current settings of the firmware volume according to the
472 input parameter, and returns the new setting of the volume
473
474 @param Instance The FV instance whose attributes is going to be
475 modified
476 @param Attributes On input, it is a pointer to EFI_FVB_ATTRIBUTES
477 containing the desired firmware volume settings.
478 On successful return, it contains the new settings
479 of the firmware volume
480
481 @retval EFI_INVALID_PARAMETER Invalid parameter
482 @retval EFI_SUCESS Sucess to set Fv attribute
483 @retval Others Fail to set Fv attribute
484 **/
485 EFI_STATUS
486 EfiFvbSetVolumeAttributes (
487 IN UINTN Instance,
488 IN OUT EFI_FVB_ATTRIBUTES *Attributes
489 )
490 {
491 ASSERT (Attributes != NULL);
492
493 if (Instance >= mFvbCount) {
494 return EFI_INVALID_PARAMETER;
495 }
496
497 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {
498 return EFI_INVALID_PARAMETER;
499 }
500
501 return mFvbEntry[Instance].Fvb->SetAttributes (mFvbEntry[Instance].Fvb, Attributes);
502 }
503
504 /**
505 Retrieves the physical address of a memory mapped FV
506
507 @param Instance The FV instance whose base address is going to be
508 returned
509 @param BaseAddress Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
510 that on successful return, contains the base address
511 of the firmware volume.
512
513 @retval EFI_INVALID_PARAMETER Invalid parameter
514 @retval EFI_SUCESS Sucess to get physical address
515 @retval Others Fail to get physical address
516 **/
517 EFI_STATUS
518 EfiFvbGetPhysicalAddress (
519 IN UINTN Instance,
520 OUT EFI_PHYSICAL_ADDRESS *BaseAddress
521 )
522 {
523 ASSERT (BaseAddress != NULL);
524
525 if (Instance >= mFvbCount) {
526 return EFI_INVALID_PARAMETER;
527 }
528
529 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {
530 return EFI_INVALID_PARAMETER;
531 }
532
533 return mFvbEntry[Instance].Fvb->GetPhysicalAddress (mFvbEntry[Instance].Fvb, BaseAddress);
534 }
535
536 /**
537 Retrieve the size of a logical block
538
539 @param Instance The FV instance whose block size is going to be
540 returned
541 @param Lba Indicates which block to return the size for.
542 @param BlockSize A pointer to a caller allocated UINTN in which
543 the size of the block is returned
544 @param NumOfBlocks a pointer to a caller allocated UINTN in which the
545 number of consecutive blocks starting with Lba is
546 returned. All blocks in this range have a size of
547 BlockSize
548
549 @retval EFI_INVALID_PARAMETER Invalid parameter
550 @retval EFI_SUCESS Sucess to get block size
551 @retval Others Fail to get block size
552 **/
553 EFI_STATUS
554 EfiFvbGetBlockSize (
555 IN UINTN Instance,
556 IN EFI_LBA Lba,
557 OUT UINTN *BlockSize,
558 OUT UINTN *NumOfBlocks
559 )
560 {
561 ASSERT (BlockSize != NULL);
562 ASSERT (NumOfBlocks != NULL);
563
564 if (Instance >= mFvbCount) {
565 return EFI_INVALID_PARAMETER;
566 }
567
568 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {
569 return EFI_INVALID_PARAMETER;
570 }
571
572 return mFvbEntry[Instance].Fvb->GetBlockSize (mFvbEntry[Instance].Fvb, Lba, BlockSize, NumOfBlocks);
573 }
574
575 /**
576 Erases and initializes a specified range of a firmware volume
577
578 @param Instance The FV instance to be erased
579 @param StartLba The starting logical block index to be erased
580 @param OffsetStartLba Offset into the starting block at which to
581 begin erasing
582 @param LastLba The last logical block index to be erased
583 @param OffsetLastLba Offset into the last block at which to end erasing
584
585 @retval EFI_INVALID_PARAMETER Invalid parameter
586 @retval EFI_SUCESS Sucess to erase custom block range
587 @retval Others Fail to erase custom block range
588 **/
589 EFI_STATUS
590 EfiFvbEraseCustomBlockRange (
591 IN UINTN Instance,
592 IN EFI_LBA StartLba,
593 IN UINTN OffsetStartLba,
594 IN EFI_LBA LastLba,
595 IN UINTN OffsetLastLba
596 )
597 {
598 if (Instance >= mFvbCount) {
599 return EFI_INVALID_PARAMETER;
600 }
601
602 if (EfiAtRuntime() && !mFvbEntry[Instance].IsRuntimeAccess) {
603 return EFI_INVALID_PARAMETER;
604 }
605
606 if (!(mFvbEntry[Instance].FvbExtension)) {
607 return EFI_UNSUPPORTED;
608 }
609
610 if (!(mFvbEntry[Instance].FvbExtension->EraseFvbCustomBlock)) {
611 return EFI_UNSUPPORTED;
612 }
613
614 return mFvbEntry[Instance].FvbExtension->EraseFvbCustomBlock (
615 mFvbEntry[Instance].FvbExtension,
616 StartLba,
617 OffsetStartLba,
618 LastLba,
619 OffsetLastLba
620 );
621 }