|
25 | 25 | #include <IndustryStandard/Pci22.h>
|
26 | 26 | #include <IndustryStandard/Q35MchIch9.h>
|
27 | 27 | #include <IndustryStandard/QemuCpuHotplug.h>
|
| 28 | +#include <Library/MemoryAllocationLib.h> |
28 | 29 | #include <Library/QemuFwCfgLib.h>
|
29 | 30 | #include <Library/QemuFwCfgS3Lib.h>
|
30 | 31 | #include <Library/QemuFwCfgSimpleParserLib.h>
|
31 | 32 | #include <Library/PciLib.h>
|
| 33 | +#include <Guid/SystemNvDataGuid.h> |
| 34 | +#include <Guid/VariableFormat.h> |
32 | 35 | #include <OvmfPlatforms.h>
|
33 | 36 |
|
34 | 37 | #include <Library/PlatformInitLib.h>
|
@@ -576,3 +579,238 @@ PlatformMaxCpuCountInitialization (
|
576 | 579 | PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber = MaxCpuCount;
|
577 | 580 | PlatformInfoHob->PcdCpuBootLogicalProcessorNumber = BootCpuCount;
|
578 | 581 | }
|
| 582 | + |
| 583 | +/** |
| 584 | + Check padding data all bit should be 1. |
| 585 | +
|
| 586 | + @param[in] Buffer - A pointer to buffer header |
| 587 | + @param[in] BufferSize - Buffer size |
| 588 | +
|
| 589 | + @retval TRUE - The padding data is valid. |
| 590 | + @retval TRUE - The padding data is invalid. |
| 591 | +
|
| 592 | +**/ |
| 593 | +BOOLEAN |
| 594 | +CheckPaddingData ( |
| 595 | + IN UINT8 *Buffer, |
| 596 | + IN UINT32 BufferSize |
| 597 | + ) |
| 598 | +{ |
| 599 | + UINT32 index; |
| 600 | + |
| 601 | + for (index = 0; index < BufferSize; index++) { |
| 602 | + if (Buffer[index] != 0xFF) { |
| 603 | + return FALSE; |
| 604 | + } |
| 605 | + } |
| 606 | + |
| 607 | + return TRUE; |
| 608 | +} |
| 609 | + |
| 610 | +/** |
| 611 | + Check the integrity of NvVarStore. |
| 612 | +
|
| 613 | + @param[in] NvVarStoreBase - A pointer to NvVarStore header |
| 614 | + @param[in] NvVarStoreSize - NvVarStore size |
| 615 | +
|
| 616 | + @retval TRUE - The NvVarStore is valid. |
| 617 | + @retval FALSE - The NvVarStore is invalid. |
| 618 | +
|
| 619 | +**/ |
| 620 | +BOOLEAN |
| 621 | +EFIAPI |
| 622 | +PlatformValidateNvVarStore ( |
| 623 | + IN UINT8 *NvVarStoreBase, |
| 624 | + IN UINT32 NvVarStoreSize |
| 625 | + ) |
| 626 | +{ |
| 627 | + UINT16 Checksum; |
| 628 | + UINTN VariableBase; |
| 629 | + UINT32 VariableOffset; |
| 630 | + UINT32 VariableOffsetBeforeAlign; |
| 631 | + EFI_FIRMWARE_VOLUME_HEADER *NvVarStoreFvHeader; |
| 632 | + VARIABLE_STORE_HEADER *NvVarStoreHeader; |
| 633 | + AUTHENTICATED_VARIABLE_HEADER *VariableHeader; |
| 634 | + |
| 635 | + static EFI_GUID FvHdrGUID = EFI_SYSTEM_NV_DATA_FV_GUID; |
| 636 | + static EFI_GUID VarStoreHdrGUID = EFI_AUTHENTICATED_VARIABLE_GUID; |
| 637 | + |
| 638 | + VariableOffset = 0; |
| 639 | + |
| 640 | + if (NvVarStoreBase == NULL) { |
| 641 | + DEBUG ((DEBUG_ERROR, "NvVarStore pointer is NULL.\n")); |
| 642 | + return FALSE; |
| 643 | + } |
| 644 | + |
| 645 | + // |
| 646 | + // Verify the header zerovetor, filesystemguid, |
| 647 | + // revision, signature, attributes, fvlength, checksum |
| 648 | + // HeaderLength cannot be an odd number |
| 649 | + // |
| 650 | + NvVarStoreFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NvVarStoreBase; |
| 651 | + |
| 652 | + if ((!IsZeroBuffer (NvVarStoreFvHeader->ZeroVector, 16)) || |
| 653 | + (!CompareGuid (&FvHdrGUID, &NvVarStoreFvHeader->FileSystemGuid)) || |
| 654 | + (NvVarStoreFvHeader->Signature != EFI_FVH_SIGNATURE) || |
| 655 | + (NvVarStoreFvHeader->Attributes != 0x4feff) || |
| 656 | + (NvVarStoreFvHeader->Revision != EFI_FVH_REVISION) || |
| 657 | + (NvVarStoreFvHeader->FvLength != NvVarStoreSize) |
| 658 | + ) |
| 659 | + { |
| 660 | + DEBUG ((DEBUG_ERROR, "NvVarStore FV headers were invalid.\n")); |
| 661 | + return FALSE; |
| 662 | + } |
| 663 | + |
| 664 | + // |
| 665 | + // Verify the header checksum |
| 666 | + // |
| 667 | + Checksum = CalculateSum16 ((VOID *)NvVarStoreFvHeader, NvVarStoreFvHeader->HeaderLength); |
| 668 | + |
| 669 | + if (Checksum != 0) { |
| 670 | + DEBUG ((DEBUG_ERROR, "NvVarStore FV checksum was invalid.\n")); |
| 671 | + return FALSE; |
| 672 | + } |
| 673 | + |
| 674 | + // |
| 675 | + // Verify the header signature, size, format, state |
| 676 | + // |
| 677 | + NvVarStoreHeader = (VARIABLE_STORE_HEADER *)(NvVarStoreBase + NvVarStoreFvHeader->HeaderLength); |
| 678 | + if ((!CompareGuid (&VarStoreHdrGUID, &NvVarStoreHeader->Signature)) || |
| 679 | + (NvVarStoreHeader->Format != VARIABLE_STORE_FORMATTED) || |
| 680 | + (NvVarStoreHeader->State != VARIABLE_STORE_HEALTHY) || |
| 681 | + (NvVarStoreHeader->Size > (NvVarStoreFvHeader->FvLength - NvVarStoreFvHeader->HeaderLength)) || |
| 682 | + (NvVarStoreHeader->Size < sizeof (VARIABLE_STORE_HEADER)) |
| 683 | + ) |
| 684 | + { |
| 685 | + DEBUG ((DEBUG_ERROR, "NvVarStore header signature/size/format/state were invalid.\n")); |
| 686 | + return FALSE; |
| 687 | + } |
| 688 | + |
| 689 | + // |
| 690 | + // Verify the header startId, state |
| 691 | + // Verify data to the end |
| 692 | + // |
| 693 | + VariableBase = (UINTN)NvVarStoreBase + NvVarStoreFvHeader->HeaderLength + sizeof (VARIABLE_STORE_HEADER); |
| 694 | + while (VariableOffset < (NvVarStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER))) { |
| 695 | + VariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)(VariableBase + VariableOffset); |
| 696 | + if (VariableHeader->StartId != VARIABLE_DATA) { |
| 697 | + if (!CheckPaddingData ((UINT8 *)VariableHeader, NvVarStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - VariableOffset)) { |
| 698 | + DEBUG ((DEBUG_ERROR, "NvVarStore variable header StartId was invalid.\n")); |
| 699 | + return FALSE; |
| 700 | + } |
| 701 | + |
| 702 | + VariableOffset = NvVarStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER); |
| 703 | + } else { |
| 704 | + if (!((VariableHeader->State == VAR_IN_DELETED_TRANSITION) || |
| 705 | + (VariableHeader->State == VAR_DELETED) || |
| 706 | + (VariableHeader->State == VAR_HEADER_VALID_ONLY) || |
| 707 | + (VariableHeader->State == VAR_ADDED))) |
| 708 | + { |
| 709 | + DEBUG ((DEBUG_ERROR, "NvVarStore Variable header State was invalid.\n")); |
| 710 | + return FALSE; |
| 711 | + } |
| 712 | + |
| 713 | + VariableOffset += sizeof (AUTHENTICATED_VARIABLE_HEADER) + VariableHeader->NameSize + VariableHeader->DataSize; |
| 714 | + // Verify VariableOffset should be less than or equal NvVarStoreHeader->Size - sizeof(VARIABLE_STORE_HEADER) |
| 715 | + if (VariableOffset > (NvVarStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER))) { |
| 716 | + DEBUG ((DEBUG_ERROR, "NvVarStore Variable header VariableOffset was invalid.\n")); |
| 717 | + return FALSE; |
| 718 | + } |
| 719 | + |
| 720 | + VariableOffsetBeforeAlign = VariableOffset; |
| 721 | + // 4 byte align |
| 722 | + VariableOffset = (VariableOffset + 3) & (UINTN)(~3); |
| 723 | + |
| 724 | + if (!CheckPaddingData ((UINT8 *)(VariableBase + VariableOffsetBeforeAlign), VariableOffset - VariableOffsetBeforeAlign)) { |
| 725 | + DEBUG ((DEBUG_ERROR, "NvVarStore Variable header PaddingData was invalid.\n")); |
| 726 | + return FALSE; |
| 727 | + } |
| 728 | + } |
| 729 | + } |
| 730 | + |
| 731 | + return TRUE; |
| 732 | +} |
| 733 | + |
| 734 | +/** |
| 735 | + Allocate storage for NV variables early on so it will be |
| 736 | + at a consistent address. Since VM memory is preserved |
| 737 | + across reboots, this allows the NV variable storage to survive |
| 738 | + a VM reboot. |
| 739 | +
|
| 740 | + * |
| 741 | + * @retval VOID* The pointer to the storage for NV Variables |
| 742 | + */ |
| 743 | +VOID * |
| 744 | +EFIAPI |
| 745 | +PlatformReserveEmuVariableNvStore ( |
| 746 | + VOID |
| 747 | + ) |
| 748 | +{ |
| 749 | + VOID *VariableStore; |
| 750 | + UINT32 VarStoreSize; |
| 751 | + |
| 752 | + VarStoreSize = 2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize); |
| 753 | + // |
| 754 | + // Allocate storage for NV variables early on so it will be |
| 755 | + // at a consistent address. Since VM memory is preserved |
| 756 | + // across reboots, this allows the NV variable storage to survive |
| 757 | + // a VM reboot. |
| 758 | + // |
| 759 | + VariableStore = |
| 760 | + AllocateRuntimePages ( |
| 761 | + EFI_SIZE_TO_PAGES (VarStoreSize) |
| 762 | + ); |
| 763 | + DEBUG (( |
| 764 | + DEBUG_INFO, |
| 765 | + "Reserved variable store memory: 0x%p; size: %dkb\n", |
| 766 | + VariableStore, |
| 767 | + VarStoreSize / 1024 |
| 768 | + )); |
| 769 | + |
| 770 | + return VariableStore; |
| 771 | +} |
| 772 | + |
| 773 | +/** |
| 774 | + When OVMF is lauched with -bios parameter, UEFI variables will be |
| 775 | + partially emulated, and non-volatile variables may lose their contents |
| 776 | + after a reboot. This makes the secure boot feature not working. |
| 777 | +
|
| 778 | + This function is used to initialize the EmuVariableNvStore |
| 779 | + with the conent in PcdOvmfFlashNvStorageVariableBase. |
| 780 | +
|
| 781 | + @param[in] EmuVariableNvStore - A pointer to EmuVariableNvStore |
| 782 | +
|
| 783 | + @retval EFI_SUCCESS - Successfully init the EmuVariableNvStore |
| 784 | + @retval Others - As the error code indicates |
| 785 | + */ |
| 786 | +EFI_STATUS |
| 787 | +EFIAPI |
| 788 | +PlatformInitEmuVariableNvStore ( |
| 789 | + IN VOID *EmuVariableNvStore |
| 790 | + ) |
| 791 | +{ |
| 792 | + UINT8 *Base; |
| 793 | + UINT32 Size; |
| 794 | + UINT32 EmuVariableNvStoreSize; |
| 795 | + |
| 796 | + EmuVariableNvStoreSize = 2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize); |
| 797 | + if ((EmuVariableNvStore == NULL) || (EmuVariableNvStoreSize == 0)) { |
| 798 | + DEBUG ((DEBUG_ERROR, "Invalid EmuVariableNvStore parameter.\n")); |
| 799 | + return EFI_INVALID_PARAMETER; |
| 800 | + } |
| 801 | + |
| 802 | + Base = (UINT8 *)(UINTN)PcdGet32 (PcdOvmfFlashNvStorageVariableBase); |
| 803 | + Size = (UINT32)PcdGet32 (PcdFlashNvStorageVariableSize); |
| 804 | + ASSERT (Size < EmuVariableNvStoreSize); |
| 805 | + |
| 806 | + if (!PlatformValidateNvVarStore (Base, PcdGet32 (PcdCfvRawDataSize))) { |
| 807 | + ASSERT (FALSE); |
| 808 | + return EFI_INVALID_PARAMETER; |
| 809 | + } |
| 810 | + |
| 811 | + DEBUG ((DEBUG_INFO, "Init EmuVariableNvStore with the content in FlashNvStorage\n")); |
| 812 | + |
| 813 | + CopyMem (EmuVariableNvStore, Base, Size); |
| 814 | + |
| 815 | + return EFI_SUCCESS; |
| 816 | +} |
0 commit comments