1 /** @file 2 The realization of EFI_RAM_DISK_PROTOCOL. 3 4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> 5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "RamDiskImpl.h" 17 18 RAM_DISK_PRIVATE_DATA mRamDiskPrivateDataTemplate = { 19 RAM_DISK_PRIVATE_DATA_SIGNATURE, 20 NULL 21 }; 22 23 MEDIA_RAM_DISK_DEVICE_PATH mRamDiskDeviceNodeTemplate = { 24 { 25 MEDIA_DEVICE_PATH, 26 MEDIA_RAM_DISK_DP, 27 { 28 (UINT8) (sizeof (MEDIA_RAM_DISK_DEVICE_PATH)), 29 (UINT8) ((sizeof (MEDIA_RAM_DISK_DEVICE_PATH)) >> 8) 30 } 31 } 32 }; 33 34 BOOLEAN mRamDiskSsdtTableKeyValid = FALSE; 35 UINTN mRamDiskSsdtTableKey; 36 37 38 /** 39 Initialize the RAM disk device node. 40 41 @param[in] PrivateData Points to RAM disk private data. 42 @param[in, out] RamDiskDevNode Points to the RAM disk device node. 43 44 **/ 45 VOID 46 RamDiskInitDeviceNode ( 47 IN RAM_DISK_PRIVATE_DATA *PrivateData, 48 IN OUT MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode 49 ) 50 { 51 WriteUnaligned64 ( 52 (UINT64 *) &(RamDiskDevNode->StartingAddr[0]), 53 (UINT64) PrivateData->StartingAddr 54 ); 55 WriteUnaligned64 ( 56 (UINT64 *) &(RamDiskDevNode->EndingAddr[0]), 57 (UINT64) PrivateData->StartingAddr + PrivateData->Size - 1 58 ); 59 CopyGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid); 60 RamDiskDevNode->Instance = PrivateData->InstanceNumber; 61 } 62 63 64 /** 65 Initialize and publish NVDIMM root device SSDT in ACPI table. 66 67 @retval EFI_SUCCESS The NVDIMM root device SSDT is published. 68 @retval Others The NVDIMM root device SSDT is not published. 69 70 **/ 71 EFI_STATUS 72 RamDiskPublishSsdt ( 73 VOID 74 ) 75 { 76 EFI_STATUS Status; 77 EFI_ACPI_DESCRIPTION_HEADER *Table; 78 UINTN SectionInstance; 79 UINTN TableSize; 80 81 Status = EFI_SUCCESS; 82 SectionInstance = 0; 83 84 // 85 // Scan all the EFI raw section instances in FV to find the NVDIMM root 86 // device SSDT. 87 // 88 while (TRUE) { 89 Status = GetSectionFromFv ( 90 &gEfiCallerIdGuid, 91 EFI_SECTION_RAW, 92 SectionInstance, 93 (VOID **) &Table, 94 &TableSize 95 ); 96 if (EFI_ERROR (Status)) { 97 break; 98 } 99 100 if (Table->OemTableId == SIGNATURE_64 ('R', 'a', 'm', 'D', 'i', 's', 'k', ' ')) { 101 Status = mAcpiTableProtocol->InstallAcpiTable ( 102 mAcpiTableProtocol, 103 Table, 104 TableSize, 105 &mRamDiskSsdtTableKey 106 ); 107 ASSERT_EFI_ERROR (Status); 108 109 if (!EFI_ERROR (Status)) { 110 mRamDiskSsdtTableKeyValid = TRUE; 111 } 112 113 FreePool (Table); 114 return Status; 115 } else { 116 FreePool (Table); 117 SectionInstance++; 118 } 119 } 120 121 return Status; 122 } 123 124 125 /** 126 Publish the RAM disk NVDIMM Firmware Interface Table (NFIT) to the ACPI 127 table. 128 129 @param[in] PrivateData Points to RAM disk private data. 130 131 @retval EFI_SUCCESS The RAM disk NFIT has been published. 132 @retval others The RAM disk NFIT has not been published. 133 134 **/ 135 EFI_STATUS 136 RamDiskPublishNfit ( 137 IN RAM_DISK_PRIVATE_DATA *PrivateData 138 ) 139 { 140 EFI_STATUS Status; 141 EFI_MEMORY_DESCRIPTOR *MemoryMap; 142 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; 143 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; 144 UINTN TableIndex; 145 VOID *TableHeader; 146 EFI_ACPI_TABLE_VERSION TableVersion; 147 UINTN TableKey; 148 EFI_ACPI_DESCRIPTION_HEADER *NfitHeader; 149 EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE 150 *SpaRange; 151 VOID *Nfit; 152 UINT32 NfitLen; 153 UINTN MemoryMapSize; 154 UINTN MapKey; 155 UINTN DescriptorSize; 156 UINT32 DescriptorVersion; 157 UINT64 CurrentData; 158 UINT8 Checksum; 159 BOOLEAN MemoryFound; 160 161 // 162 // Get the EFI memory map. 163 // 164 MemoryMapSize = 0; 165 MemoryMap = NULL; 166 MemoryFound = FALSE; 167 168 Status = gBS->GetMemoryMap ( 169 &MemoryMapSize, 170 MemoryMap, 171 &MapKey, 172 &DescriptorSize, 173 &DescriptorVersion 174 ); 175 ASSERT (Status == EFI_BUFFER_TOO_SMALL); 176 do { 177 MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize); 178 ASSERT (MemoryMap != NULL); 179 Status = gBS->GetMemoryMap ( 180 &MemoryMapSize, 181 MemoryMap, 182 &MapKey, 183 &DescriptorSize, 184 &DescriptorVersion 185 ); 186 if (EFI_ERROR (Status)) { 187 FreePool (MemoryMap); 188 } 189 } while (Status == EFI_BUFFER_TOO_SMALL); 190 ASSERT_EFI_ERROR (Status); 191 192 MemoryMapEntry = MemoryMap; 193 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize); 194 while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) { 195 if ((MemoryMapEntry->Type == EfiReservedMemoryType) && 196 (MemoryMapEntry->PhysicalStart <= PrivateData->StartingAddr) && 197 (MemoryMapEntry->PhysicalStart + 198 MultU64x32 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SIZE) 199 >= PrivateData->StartingAddr + PrivateData->Size)) { 200 MemoryFound = TRUE; 201 DEBUG (( 202 EFI_D_INFO, 203 "RamDiskPublishNfit: RAM disk with reserved meomry type, will publish to NFIT.\n" 204 )); 205 break; 206 } 207 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); 208 } 209 FreePool (MemoryMap); 210 211 if (!MemoryFound) { 212 return EFI_NOT_FOUND; 213 } 214 215 // 216 // Determine whether there is a NFIT already in the ACPI table. 217 // 218 Status = EFI_SUCCESS; 219 TableIndex = 0; 220 TableKey = 0; 221 TableHeader = NULL; 222 223 while (!EFI_ERROR (Status)) { 224 Status = mAcpiSdtProtocol->GetAcpiTable ( 225 TableIndex, 226 (EFI_ACPI_SDT_HEADER **)&TableHeader, 227 &TableVersion, 228 &TableKey 229 ); 230 if (!EFI_ERROR (Status)) { 231 TableIndex++; 232 233 if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature == 234 EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) { 235 break; 236 } 237 } 238 } 239 240 if (!EFI_ERROR (Status)) { 241 // 242 // A NFIT is already in the ACPI table. 243 // 244 DEBUG (( 245 EFI_D_INFO, 246 "RamDiskPublishNfit: A NFIT is already exist in the ACPI Table.\n" 247 )); 248 249 NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)TableHeader; 250 NfitLen = NfitHeader->Length + sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE); 251 Nfit = AllocateZeroPool (NfitLen); 252 if (Nfit == NULL) { 253 return EFI_OUT_OF_RESOURCES; 254 } 255 CopyMem (Nfit, TableHeader, NfitHeader->Length); 256 257 // 258 // Update the NFIT head pointer. 259 // 260 NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit; 261 262 // 263 // Uninstall the origin NFIT from the ACPI table. 264 // 265 Status = mAcpiTableProtocol->UninstallAcpiTable ( 266 mAcpiTableProtocol, 267 TableKey 268 ); 269 ASSERT_EFI_ERROR (Status); 270 271 if (EFI_ERROR (Status)) { 272 FreePool (Nfit); 273 return Status; 274 } 275 276 // 277 // Append the System Physical Address (SPA) Range Structure at the end 278 // of the origin NFIT. 279 // 280 SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *) 281 ((UINT8 *)Nfit + NfitHeader->Length); 282 283 // 284 // Update the length field of the NFIT 285 // 286 NfitHeader->Length = NfitLen; 287 288 // 289 // The checksum will be updated after the new contents are appended. 290 // 291 NfitHeader->Checksum = 0; 292 } else { 293 // 294 // Assumption is made that if no NFIT is in the ACPI table, there is no 295 // NVDIMM root device in the \SB scope. 296 // Therefore, a NVDIMM root device will be reported via Secondary System 297 // Description Table (SSDT). 298 // 299 Status = RamDiskPublishSsdt (); 300 if (EFI_ERROR (Status)) { 301 return Status; 302 } 303 304 // 305 // No NFIT is in the ACPI table, we will create one here. 306 // 307 DEBUG (( 308 EFI_D_INFO, 309 "RamDiskPublishNfit: No NFIT is in the ACPI Table, will create one.\n" 310 )); 311 312 NfitLen = sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE) + 313 sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE); 314 Nfit = AllocateZeroPool (NfitLen); 315 if (Nfit == NULL) { 316 return EFI_OUT_OF_RESOURCES; 317 } 318 319 SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *) 320 ((UINT8 *)Nfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)); 321 322 NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit; 323 NfitHeader->Signature = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE; 324 NfitHeader->Length = NfitLen; 325 NfitHeader->Revision = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION; 326 NfitHeader->Checksum = 0; 327 NfitHeader->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); 328 NfitHeader->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); 329 NfitHeader->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); 330 CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId); 331 CopyMem (NfitHeader->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (NfitHeader->OemId)); 332 CopyMem (&NfitHeader->OemTableId, &CurrentData, sizeof (UINT64)); 333 } 334 335 // 336 // Fill in the content of the SPA Range Structure. 337 // 338 SpaRange->Type = EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE; 339 SpaRange->Length = sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE); 340 SpaRange->SystemPhysicalAddressRangeBase = PrivateData->StartingAddr; 341 SpaRange->SystemPhysicalAddressRangeLength = PrivateData->Size; 342 CopyGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid); 343 344 Checksum = CalculateCheckSum8((UINT8 *)Nfit, NfitHeader->Length); 345 NfitHeader->Checksum = Checksum; 346 347 // 348 // Publish the NFIT to the ACPI table. 349 // Note, since the NFIT might be modified by other driver, therefore, we 350 // do not track the returning TableKey from the InstallAcpiTable(). 351 // 352 Status = mAcpiTableProtocol->InstallAcpiTable ( 353 mAcpiTableProtocol, 354 Nfit, 355 NfitHeader->Length, 356 &TableKey 357 ); 358 ASSERT_EFI_ERROR (Status); 359 360 FreePool (Nfit); 361 362 if (EFI_ERROR (Status)) { 363 return Status; 364 } 365 366 PrivateData->InNfit = TRUE; 367 368 return EFI_SUCCESS; 369 } 370 371 372 /** 373 Unpublish the RAM disk NVDIMM Firmware Interface Table (NFIT) from the 374 ACPI table. 375 376 @param[in] PrivateData Points to RAM disk private data. 377 378 @retval EFI_SUCCESS The RAM disk NFIT has been unpublished. 379 @retval others The RAM disk NFIT has not been unpublished. 380 381 **/ 382 EFI_STATUS 383 RamDiskUnpublishNfit ( 384 IN RAM_DISK_PRIVATE_DATA *PrivateData 385 ) 386 { 387 EFI_STATUS Status; 388 UINTN TableIndex; 389 VOID *TableHeader; 390 EFI_ACPI_TABLE_VERSION TableVersion; 391 UINTN TableKey; 392 EFI_ACPI_DESCRIPTION_HEADER *NewNfitHeader; 393 EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE 394 *SpaRange; 395 VOID *NewNfit; 396 VOID *NewNfitPtr; 397 EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *NfitStructHeader; 398 UINT32 NewNfitLen; 399 UINT32 RemainLen; 400 UINT8 Checksum; 401 402 // 403 // Find the NFIT in the ACPI table. 404 // 405 Status = EFI_SUCCESS; 406 TableIndex = 0; 407 TableKey = 0; 408 TableHeader = NULL; 409 410 while (!EFI_ERROR (Status)) { 411 Status = mAcpiSdtProtocol->GetAcpiTable ( 412 TableIndex, 413 (EFI_ACPI_SDT_HEADER **)&TableHeader, 414 &TableVersion, 415 &TableKey 416 ); 417 if (!EFI_ERROR (Status)) { 418 TableIndex++; 419 420 if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature == 421 EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) { 422 break; 423 } 424 } 425 } 426 427 if (EFI_ERROR (Status)) { 428 // 429 // No NFIT is found in the ACPI table. 430 // 431 return EFI_NOT_FOUND; 432 } 433 434 NewNfitLen = ((EFI_ACPI_DESCRIPTION_HEADER *)TableHeader)->Length - 435 sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE); 436 437 // 438 // After removing this RAM disk from the NFIT, if no other structure is in 439 // the NFIT, we just remove the NFIT and the SSDT which is used to report 440 // the NVDIMM root device. 441 // 442 if (NewNfitLen == sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)) { 443 // 444 // Remove the NFIT. 445 // 446 Status = mAcpiTableProtocol->UninstallAcpiTable ( 447 mAcpiTableProtocol, 448 TableKey 449 ); 450 ASSERT_EFI_ERROR (Status); 451 if (EFI_ERROR (Status)) { 452 return Status; 453 } 454 455 // 456 // Remove the SSDT which is used by RamDiskDxe driver to report the NVDIMM 457 // root device. 458 // We do not care the return status since this SSDT might already be 459 // uninstalled by other drivers to update the information of the NVDIMM 460 // root device. 461 // 462 if (mRamDiskSsdtTableKeyValid) { 463 mRamDiskSsdtTableKeyValid = FALSE; 464 465 mAcpiTableProtocol->UninstallAcpiTable ( 466 mAcpiTableProtocol, 467 mRamDiskSsdtTableKey 468 ); 469 } 470 471 return EFI_SUCCESS; 472 } 473 474 NewNfit = AllocateZeroPool (NewNfitLen); 475 if (NewNfit == NULL) { 476 return EFI_OUT_OF_RESOURCES; 477 } 478 479 // 480 // Get a copy of the old NFIT header content. 481 // 482 CopyMem (NewNfit, TableHeader, sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)); 483 NewNfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)NewNfit; 484 NewNfitHeader->Length = NewNfitLen; 485 NewNfitHeader->Checksum = 0; 486 487 // 488 // Copy the content of required NFIT structures. 489 // 490 NewNfitPtr = (UINT8 *)NewNfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE); 491 RemainLen = NewNfitLen - sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE); 492 NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *) 493 ((UINT8 *)TableHeader + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)); 494 while (RemainLen > 0) { 495 if ((NfitStructHeader->Type == EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE) && 496 (NfitStructHeader->Length == sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE))) { 497 SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)NfitStructHeader; 498 499 if ((SpaRange->SystemPhysicalAddressRangeBase == PrivateData->StartingAddr) && 500 (SpaRange->SystemPhysicalAddressRangeLength == PrivateData->Size) && 501 (CompareGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid))) { 502 // 503 // Skip the SPA Range Structure for the RAM disk to be unpublished 504 // from NFIT. 505 // 506 NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *) 507 ((UINT8 *)NfitStructHeader + NfitStructHeader->Length); 508 continue; 509 } 510 } 511 512 // 513 // Copy the content of origin NFIT. 514 // 515 CopyMem (NewNfitPtr, NfitStructHeader, NfitStructHeader->Length); 516 NewNfitPtr = (UINT8 *)NewNfitPtr + NfitStructHeader->Length; 517 518 // 519 // Move to the header of next NFIT structure. 520 // 521 RemainLen -= NfitStructHeader->Length; 522 NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *) 523 ((UINT8 *)NfitStructHeader + NfitStructHeader->Length); 524 } 525 526 Checksum = CalculateCheckSum8((UINT8 *)NewNfit, NewNfitHeader->Length); 527 NewNfitHeader->Checksum = Checksum; 528 529 Status = mAcpiTableProtocol->UninstallAcpiTable ( 530 mAcpiTableProtocol, 531 TableKey 532 ); 533 ASSERT_EFI_ERROR (Status); 534 535 if (EFI_ERROR (Status)) { 536 FreePool (NewNfit); 537 return Status; 538 } 539 540 // 541 // Publish the NFIT to the ACPI table. 542 // Note, since the NFIT might be modified by other driver, therefore, we 543 // do not track the returning TableKey from the InstallAcpiTable(). 544 // 545 Status = mAcpiTableProtocol->InstallAcpiTable ( 546 mAcpiTableProtocol, 547 NewNfit, 548 NewNfitLen, 549 &TableKey 550 ); 551 ASSERT_EFI_ERROR (Status); 552 553 FreePool (NewNfit); 554 if (EFI_ERROR (Status)) { 555 return Status; 556 } 557 558 return EFI_SUCCESS; 559 } 560 561 562 /** 563 Register a RAM disk with specified address, size and type. 564 565 @param[in] RamDiskBase The base address of registered RAM disk. 566 @param[in] RamDiskSize The size of registered RAM disk. 567 @param[in] RamDiskType The type of registered RAM disk. The GUID can be 568 any of the values defined in section 9.3.6.9, or a 569 vendor defined GUID. 570 @param[in] ParentDevicePath 571 Pointer to the parent device path. If there is no 572 parent device path then ParentDevicePath is NULL. 573 @param[out] DevicePath On return, points to a pointer to the device path 574 of the RAM disk device. 575 If ParentDevicePath is not NULL, the returned 576 DevicePath is created by appending a RAM disk node 577 to the parent device path. If ParentDevicePath is 578 NULL, the returned DevicePath is a RAM disk device 579 path without appending. This function is 580 responsible for allocating the buffer DevicePath 581 with the boot service AllocatePool(). 582 583 @retval EFI_SUCCESS The RAM disk is registered successfully. 584 @retval EFI_INVALID_PARAMETER DevicePath or RamDiskType is NULL. 585 RamDiskSize is 0. 586 @retval EFI_ALREADY_STARTED A Device Path Protocol instance to be created 587 is already present in the handle database. 588 @retval EFI_OUT_OF_RESOURCES The RAM disk register operation fails due to 589 resource limitation. 590 591 **/ 592 EFI_STATUS 593 EFIAPI 594 RamDiskRegister ( 595 IN UINT64 RamDiskBase, 596 IN UINT64 RamDiskSize, 597 IN EFI_GUID *RamDiskType, 598 IN EFI_DEVICE_PATH *ParentDevicePath OPTIONAL, 599 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath 600 ) 601 { 602 EFI_STATUS Status; 603 RAM_DISK_PRIVATE_DATA *PrivateData; 604 RAM_DISK_PRIVATE_DATA *RegisteredPrivateData; 605 MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode; 606 UINTN DevicePathSize; 607 LIST_ENTRY *Entry; 608 609 if ((0 == RamDiskSize) || (NULL == RamDiskType) || (NULL == DevicePath)) { 610 return EFI_INVALID_PARAMETER; 611 } 612 613 // 614 // Add check to prevent data read across the memory boundary 615 // 616 if (RamDiskBase + RamDiskSize > ((UINTN) -1) - RAM_DISK_BLOCK_SIZE + 1) { 617 return EFI_INVALID_PARAMETER; 618 } 619 620 RamDiskDevNode = NULL; 621 622 // 623 // Create a new RAM disk instance and initialize its private data 624 // 625 PrivateData = AllocateCopyPool ( 626 sizeof (RAM_DISK_PRIVATE_DATA), 627 &mRamDiskPrivateDataTemplate 628 ); 629 if (NULL == PrivateData) { 630 return EFI_OUT_OF_RESOURCES; 631 } 632 633 PrivateData->StartingAddr = RamDiskBase; 634 PrivateData->Size = RamDiskSize; 635 CopyGuid (&PrivateData->TypeGuid, RamDiskType); 636 InitializeListHead (&PrivateData->ThisInstance); 637 638 // 639 // Generate device path information for the registered RAM disk 640 // 641 RamDiskDevNode = AllocateCopyPool ( 642 sizeof (MEDIA_RAM_DISK_DEVICE_PATH), 643 &mRamDiskDeviceNodeTemplate 644 ); 645 if (NULL == RamDiskDevNode) { 646 Status = EFI_OUT_OF_RESOURCES; 647 goto ErrorExit; 648 } 649 650 RamDiskInitDeviceNode (PrivateData, RamDiskDevNode); 651 652 *DevicePath = AppendDevicePathNode ( 653 ParentDevicePath, 654 (EFI_DEVICE_PATH_PROTOCOL *) RamDiskDevNode 655 ); 656 if (NULL == *DevicePath) { 657 Status = EFI_OUT_OF_RESOURCES; 658 goto ErrorExit; 659 } 660 661 PrivateData->DevicePath = *DevicePath; 662 663 // 664 // Check whether the created device path is already present in the handle 665 // database 666 // 667 if (!IsListEmpty(&RegisteredRamDisks)) { 668 DevicePathSize = GetDevicePathSize (PrivateData->DevicePath); 669 670 EFI_LIST_FOR_EACH (Entry, &RegisteredRamDisks) { 671 RegisteredPrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); 672 if (DevicePathSize == GetDevicePathSize (RegisteredPrivateData->DevicePath)) { 673 // 674 // Compare device path 675 // 676 if ((CompareMem ( 677 PrivateData->DevicePath, 678 RegisteredPrivateData->DevicePath, 679 DevicePathSize)) == 0) { 680 *DevicePath = NULL; 681 Status = EFI_ALREADY_STARTED; 682 goto ErrorExit; 683 } 684 } 685 } 686 } 687 688 // 689 // Fill Block IO protocol informations for the RAM disk 690 // 691 RamDiskInitBlockIo (PrivateData); 692 693 // 694 // Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL on a new 695 // handle 696 // 697 Status = gBS->InstallMultipleProtocolInterfaces ( 698 &PrivateData->Handle, 699 &gEfiBlockIoProtocolGuid, 700 &PrivateData->BlockIo, 701 &gEfiBlockIo2ProtocolGuid, 702 &PrivateData->BlockIo2, 703 &gEfiDevicePathProtocolGuid, 704 PrivateData->DevicePath, 705 NULL 706 ); 707 if (EFI_ERROR (Status)) { 708 goto ErrorExit; 709 } 710 711 // 712 // Insert the newly created one to the registered RAM disk list 713 // 714 InsertTailList (&RegisteredRamDisks, &PrivateData->ThisInstance); 715 716 gBS->ConnectController (PrivateData->Handle, NULL, NULL, TRUE); 717 718 FreePool (RamDiskDevNode); 719 720 if ((mAcpiTableProtocol != NULL) && (mAcpiSdtProtocol != NULL)) { 721 RamDiskPublishNfit (PrivateData); 722 } 723 724 return EFI_SUCCESS; 725 726 ErrorExit: 727 if (RamDiskDevNode != NULL) { 728 FreePool (RamDiskDevNode); 729 } 730 731 if (PrivateData != NULL) { 732 if (PrivateData->DevicePath) { 733 FreePool (PrivateData->DevicePath); 734 } 735 736 FreePool (PrivateData); 737 } 738 739 return Status; 740 } 741 742 743 /** 744 Unregister a RAM disk specified by DevicePath. 745 746 @param[in] DevicePath A pointer to the device path that describes a RAM 747 Disk device. 748 749 @retval EFI_SUCCESS The RAM disk is unregistered successfully. 750 @retval EFI_INVALID_PARAMETER DevicePath is NULL. 751 @retval EFI_UNSUPPORTED The device specified by DevicePath is not a 752 valid ramdisk device path and not supported 753 by the driver. 754 @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't 755 exist. 756 757 **/ 758 EFI_STATUS 759 EFIAPI 760 RamDiskUnregister ( 761 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath 762 ) 763 { 764 LIST_ENTRY *Entry; 765 LIST_ENTRY *NextEntry; 766 BOOLEAN Found; 767 UINT64 StartingAddr; 768 UINT64 EndingAddr; 769 EFI_DEVICE_PATH_PROTOCOL *Header; 770 MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode; 771 RAM_DISK_PRIVATE_DATA *PrivateData; 772 773 if (NULL == DevicePath) { 774 return EFI_INVALID_PARAMETER; 775 } 776 777 // 778 // Locate the RAM disk device node. 779 // 780 RamDiskDevNode = NULL; 781 Header = DevicePath; 782 do { 783 // 784 // Test if the current device node is a RAM disk. 785 // 786 if ((MEDIA_DEVICE_PATH == Header->Type) && 787 (MEDIA_RAM_DISK_DP == Header->SubType)) { 788 RamDiskDevNode = (MEDIA_RAM_DISK_DEVICE_PATH *) Header; 789 790 break; 791 } 792 793 Header = NextDevicePathNode (Header); 794 } while ((Header->Type != END_DEVICE_PATH_TYPE)); 795 796 if (NULL == RamDiskDevNode) { 797 return EFI_UNSUPPORTED; 798 } 799 800 Found = FALSE; 801 StartingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->StartingAddr[0])); 802 EndingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->EndingAddr[0])); 803 804 if (!IsListEmpty(&RegisteredRamDisks)) { 805 EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) { 806 PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry); 807 808 // 809 // Unregister the RAM disk given by its starting address, ending address 810 // and type guid. 811 // 812 if ((StartingAddr == PrivateData->StartingAddr) && 813 (EndingAddr == PrivateData->StartingAddr + PrivateData->Size - 1) && 814 (CompareGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid))) { 815 // 816 // Remove the content for this RAM disk in NFIT. 817 // 818 if (PrivateData->InNfit) { 819 RamDiskUnpublishNfit (PrivateData); 820 } 821 822 // 823 // Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL 824 // 825 gBS->UninstallMultipleProtocolInterfaces ( 826 PrivateData->Handle, 827 &gEfiBlockIoProtocolGuid, 828 &PrivateData->BlockIo, 829 &gEfiBlockIo2ProtocolGuid, 830 &PrivateData->BlockIo2, 831 &gEfiDevicePathProtocolGuid, 832 (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath, 833 NULL 834 ); 835 836 RemoveEntryList (&PrivateData->ThisInstance); 837 838 if (RamDiskCreateHii == PrivateData->CreateMethod) { 839 // 840 // If a RAM disk is created within HII, then the RamDiskDxe driver 841 // driver is responsible for freeing the allocated memory for the 842 // RAM disk. 843 // 844 FreePool ((VOID *)(UINTN) PrivateData->StartingAddr); 845 } 846 847 FreePool (PrivateData->DevicePath); 848 FreePool (PrivateData); 849 Found = TRUE; 850 851 break; 852 } 853 } 854 } 855 856 if (TRUE == Found) { 857 return EFI_SUCCESS; 858 } else { 859 return EFI_NOT_FOUND; 860 } 861 } 862