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