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