| /** @file | |
| Copyright (c) 2014-2018, Linaro Ltd. All rights reserved.<BR> | |
| Copyright (c) 2023, Ventana Micro Systems Inc. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Library/BaseLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Library/VirtNorFlashPlatformLib.h> | |
| #include <Protocol/FdtClient.h> | |
| #define QEMU_NOR_BLOCK_SIZE SIZE_256KB | |
| #define MAX_FLASH_BANKS 4 | |
| EFI_STATUS | |
| VirtNorFlashPlatformInitialization ( | |
| VOID | |
| ) | |
| { | |
| return EFI_SUCCESS; | |
| } | |
| STATIC VIRT_NOR_FLASH_DESCRIPTION mNorFlashDevices[MAX_FLASH_BANKS]; | |
| EFI_STATUS | |
| VirtNorFlashPlatformGetDevices ( | |
| OUT VIRT_NOR_FLASH_DESCRIPTION **NorFlashDescriptions, | |
| OUT UINT32 *Count | |
| ) | |
| { | |
| FDT_CLIENT_PROTOCOL *FdtClient; | |
| INT32 Node; | |
| EFI_STATUS Status; | |
| EFI_STATUS FindNodeStatus; | |
| CONST UINT32 *Reg; | |
| UINT32 PropSize; | |
| UINT32 Num; | |
| UINT64 Base; | |
| UINT64 Size; | |
| Status = gBS->LocateProtocol ( | |
| &gFdtClientProtocolGuid, | |
| NULL, | |
| (VOID **)&FdtClient | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Num = 0; | |
| for (FindNodeStatus = FdtClient->FindCompatibleNode ( | |
| FdtClient, | |
| "cfi-flash", | |
| &Node | |
| ); | |
| !EFI_ERROR (FindNodeStatus) && Num < MAX_FLASH_BANKS; | |
| FindNodeStatus = FdtClient->FindNextCompatibleNode ( | |
| FdtClient, | |
| "cfi-flash", | |
| Node, | |
| &Node | |
| )) | |
| { | |
| Status = FdtClient->GetNodeProperty ( | |
| FdtClient, | |
| Node, | |
| "reg", | |
| (CONST VOID **)&Reg, | |
| &PropSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "%a: GetNodeProperty () failed (Status == %r)\n", | |
| __func__, | |
| Status | |
| )); | |
| continue; | |
| } | |
| ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0); | |
| while (PropSize >= (4 * sizeof (UINT32)) && Num < MAX_FLASH_BANKS) { | |
| Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0])); | |
| Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2])); | |
| Reg += 4; | |
| PropSize -= 4 * sizeof (UINT32); | |
| // | |
| // Disregard any flash devices that overlap with the primary FV. | |
| // The firmware is not updatable from inside the guest anyway. | |
| // | |
| if ((PcdGet32 (PcdOvmfFdBaseAddress) + PcdGet32 (PcdOvmfFirmwareFdSize) > Base) && | |
| ((Base + Size) > PcdGet32 (PcdOvmfFdBaseAddress))) | |
| { | |
| continue; | |
| } | |
| mNorFlashDevices[Num].DeviceBaseAddress = (UINTN)Base; | |
| mNorFlashDevices[Num].RegionBaseAddress = (UINTN)Base; | |
| mNorFlashDevices[Num].Size = (UINTN)Size; | |
| mNorFlashDevices[Num].BlockSize = QEMU_NOR_BLOCK_SIZE; | |
| Num++; | |
| } | |
| // | |
| // UEFI takes ownership of the NOR flash, and exposes its functionality | |
| // through the UEFI Runtime Services GetVariable, SetVariable, etc. This | |
| // means we need to disable it in the device tree to prevent the OS from | |
| // attaching its device driver as well. | |
| // Note that this also hides other flash banks, but the only other flash | |
| // bank we expect to encounter is the one that carries the UEFI executable | |
| // code, which is not intended to be guest updatable, and is usually backed | |
| // in a readonly manner by QEMU anyway. | |
| // | |
| Status = FdtClient->SetNodeProperty ( | |
| FdtClient, | |
| Node, | |
| "status", | |
| "disabled", | |
| sizeof ("disabled") | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_WARN, "Failed to set NOR flash status to 'disabled'\n")); | |
| } | |
| } | |
| *NorFlashDescriptions = mNorFlashDevices; | |
| *Count = Num; | |
| return EFI_SUCCESS; | |
| } |