From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../Application/AndroidBoot/AndroidBootApp.c | 134 ++ .../Application/AndroidBoot/AndroidBootApp.inf | 58 + .../Application/AndroidFastboot/AndroidBootImg.c | 60 + .../AndroidFastboot/AndroidFastbootApp.c | 529 ++++++ .../AndroidFastboot/AndroidFastbootApp.h | 37 + .../AndroidFastboot/AndroidFastbootApp.inf | 53 + .../AndroidFastboot/Arm/BootAndroidBootImg.c | 178 ++ .../FastbootTransportTcp.c | 660 +++++++ .../FastbootTransportTcpDxe.inf | 46 + .../FastbootTransportUsb.c | 272 +++ .../FastbootTransportUsbDxe.inf | 41 + .../Drivers/ConsolePrefDxe/ConsolePrefDxe.c | 288 +++ .../Drivers/ConsolePrefDxe/ConsolePrefDxe.h | 25 + .../Drivers/ConsolePrefDxe/ConsolePrefDxe.inf | 55 + .../Drivers/ConsolePrefDxe/ConsolePrefHii.uni | 21 + .../Drivers/ConsolePrefDxe/ConsolePrefHii.vfr | 38 + .../Drivers/DtPlatformDxe/DtPlatformDxe.c | 208 +++ .../Drivers/DtPlatformDxe/DtPlatformDxe.h | 25 + .../Drivers/DtPlatformDxe/DtPlatformDxe.inf | 54 + .../Drivers/DtPlatformDxe/DtPlatformHii.uni | 21 + .../Drivers/DtPlatformDxe/DtPlatformHii.vfr | 38 + .../NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.c | 250 +++ .../NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf | 35 + .../Drivers/VirtualKeyboardDxe/ComponentName.c | 181 ++ .../Drivers/VirtualKeyboardDxe/ComponentName.h | 147 ++ .../Drivers/VirtualKeyboardDxe/VirtualKeyboard.c | 1143 ++++++++++++ .../Drivers/VirtualKeyboardDxe/VirtualKeyboard.h | 537 ++++++ .../VirtualKeyboardDxe/VirtualKeyboardDxe.inf | 54 + .../EmbeddedMonotonicCounter.c | 76 + .../EmbeddedMonotonicCounter.inf | 35 + .../EFI/Firmware/EmbeddedPkg/EmbeddedPkg.dec | 175 ++ .../EFI/Firmware/EmbeddedPkg/EmbeddedPkg.dsc | 254 +++ .../Firmware/EmbeddedPkg/GdbStub/Arm/Processor.c | 697 +++++++ .../EFI/Firmware/EmbeddedPkg/GdbStub/GdbStub.c | 1251 +++++++++++++ .../EFI/Firmware/EmbeddedPkg/GdbStub/GdbStub.inf | 72 + .../Firmware/EmbeddedPkg/GdbStub/GdbStubInternal.h | 749 ++++++++ .../Firmware/EmbeddedPkg/GdbStub/Ia32/Processor.c | 987 ++++++++++ .../EFI/Firmware/EmbeddedPkg/GdbStub/SerialIo.c | 547 ++++++ .../Firmware/EmbeddedPkg/GdbStub/X64/Processor.c | 957 ++++++++++ .../EmbeddedPkg/Include/Guid/ConsolePrefFormSet.h | 17 + .../Include/Guid/DtPlatformDefaultDtbFile.h | 17 + .../EmbeddedPkg/Include/Guid/DtPlatformFormSet.h | 17 + .../EmbeddedPkg/Include/Guid/ExtractSection.h | 30 + .../EFI/Firmware/EmbeddedPkg/Include/Guid/Fdt.h | 22 + .../EFI/Firmware/EmbeddedPkg/Include/Guid/FdtHob.h | 20 + .../EmbeddedPkg/Include/Guid/NvVarStoreFormatted.h | 33 + .../Include/Guid/PlatformHasDeviceTree.h | 29 + .../Firmware/EmbeddedPkg/Include/Library/AcpiLib.h | 131 ++ .../Include/Library/AndroidBootImgLib.h | 65 + .../Include/Library/DebugAgentTimerLib.h | 56 + .../Firmware/EmbeddedPkg/Include/Library/DmaLib.h | 181 ++ .../Include/Library/DtPlatformDtbLoaderLib.h | 33 + .../EmbeddedPkg/Include/Library/EfiFileLib.h | 344 ++++ .../Include/Library/EfiResetSystemLib.h | 52 + .../EmbeddedPkg/Include/Library/FdtLoadLib.h | 42 + .../EmbeddedPkg/Include/Library/GdbSerialLib.h | 101 ++ .../Include/Library/HalRuntimeServicesLib.h | 159 ++ .../EmbeddedPkg/Include/Library/NorFlashInfoLib.h | 90 + .../Include/Library/PrePiHobListPointerLib.h | 38 + .../EmbeddedPkg/Include/Library/PrePiLib.h | 758 ++++++++ .../EmbeddedPkg/Include/Library/RealTimeClockLib.h | 132 ++ .../EmbeddedPkg/Include/Library/TimeBaseLib.h | 178 ++ .../EmbeddedPkg/Include/Ppi/EmbeddedGpio.h | 145 ++ .../EmbeddedPkg/Include/Protocol/AndroidBootImg.h | 41 + .../Include/Protocol/AndroidFastbootPlatform.h | 139 ++ .../Include/Protocol/AndroidFastbootTransport.h | 125 ++ .../EmbeddedPkg/Include/Protocol/EmbeddedDevice.h | 52 + .../Include/Protocol/EmbeddedExternalDevice.h | 88 + .../EmbeddedPkg/Include/Protocol/EmbeddedGpio.h | 178 ++ .../Include/Protocol/HardwareInterrupt.h | 164 ++ .../Include/Protocol/HardwareInterrupt2.h | 176 ++ .../EmbeddedPkg/Include/Protocol/MmcHost.h | 184 ++ .../EmbeddedPkg/Include/Protocol/PeCoffLoader.h | 235 +++ .../Include/Protocol/PlatformBootManager.h | 80 + .../Include/Protocol/PlatformVirtualKeyboard.h | 59 + .../EmbeddedPkg/Include/Protocol/UsbDevice.h | 112 ++ .../Devices/EFI/Firmware/EmbeddedPkg/Include/fdt.h | 111 ++ .../EFI/Firmware/EmbeddedPkg/Include/libfdt.h | 1899 ++++++++++++++++++++ .../EFI/Firmware/EmbeddedPkg/Include/libfdt_env.h | 83 + .../Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.c | 172 ++ .../EmbeddedPkg/Library/AcpiLib/AcpiLib.inf | 31 + .../Library/AndroidBootImgLib/AndroidBootImgLib.c | 470 +++++ .../AndroidBootImgLib/AndroidBootImgLib.inf | 44 + .../Library/CoherentDmaLib/CoherentDmaLib.c | 195 ++ .../Library/CoherentDmaLib/CoherentDmaLib.inf | 30 + .../DebugAgentTimerLibNull/DebugAgentTimerLib.c | 57 + .../DebugAgentTimerLibNull.inf | 32 + .../DxeDtPlatformDtbLoaderLibDefault.c | 54 + .../DxeDtPlatformDtbLoaderLibDefault.inf | 30 + .../Firmware/EmbeddedPkg/Library/FdtLib/FdtLib.inf | 41 + .../EmbeddedPkg/Library/FdtLib/Makefile.libfdt | 11 + .../EFI/Firmware/EmbeddedPkg/Library/FdtLib/TODO | 3 + .../EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt.c | 251 +++ .../EmbeddedPkg/Library/FdtLib/fdt_addresses.c | 96 + .../EmbeddedPkg/Library/FdtLib/fdt_empty_tree.c | 83 + .../EmbeddedPkg/Library/FdtLib/fdt_overlay.c | 914 ++++++++++ .../Firmware/EmbeddedPkg/Library/FdtLib/fdt_ro.c | 703 ++++++++ .../Firmware/EmbeddedPkg/Library/FdtLib/fdt_rw.c | 505 ++++++ .../EmbeddedPkg/Library/FdtLib/fdt_strerror.c | 102 ++ .../EmbeddedPkg/Library/FdtLib/fdt_strtoul.c | 32 + .../Firmware/EmbeddedPkg/Library/FdtLib/fdt_sw.c | 300 ++++ .../Firmware/EmbeddedPkg/Library/FdtLib/fdt_wip.c | 139 ++ .../EmbeddedPkg/Library/FdtLib/libfdt_internal.h | 95 + .../EmbeddedPkg/Library/FdtLib/version.lds | 67 + .../GdbSerialDebugPortLib/GdbSerialDebugPortLib.c | 181 ++ .../GdbSerialDebugPortLib.inf | 44 + .../Library/GdbSerialLib/GdbSerialLib.c | 256 +++ .../Library/GdbSerialLib/GdbSerialLib.inf | 41 + .../Library/NonCoherentDmaLib/NonCoherentDmaLib.c | 624 +++++++ .../NonCoherentDmaLib/NonCoherentDmaLib.inf | 44 + .../Library/NorFlashInfoLib/NorFlashInfoLib.c | 220 +++ .../Library/NorFlashInfoLib/NorFlashInfoLib.inf | 27 + .../NvVarStoreFormattedLib.c | 35 + .../NvVarStoreFormattedLib.inf | 46 + .../PlatformHasAcpiLib/PlatformHasAcpiLib.c | 30 + .../PlatformHasAcpiLib/PlatformHasAcpiLib.inf | 34 + .../PrePiExtractGuidedSectionLib.c | 255 +++ .../PrePiExtractGuidedSectionLib.inf | 30 + .../Firmware/EmbeddedPkg/Library/PrePiHobLib/Hob.c | 849 +++++++++ .../Library/PrePiHobLib/PrePiHobLib.inf | 57 + .../Firmware/EmbeddedPkg/Library/PrePiLib/FwVol.c | 878 +++++++++ .../Firmware/EmbeddedPkg/Library/PrePiLib/PrePi.h | 41 + .../EmbeddedPkg/Library/PrePiLib/PrePiLib.c | 251 +++ .../EmbeddedPkg/Library/PrePiLib/PrePiLib.inf | 74 + .../PrePiMemoryAllocationLib/MemoryAllocationLib.c | 246 +++ .../PrePiMemoryAllocationLib.inf | 33 + .../TemplateRealTimeClockLib/RealTimeClockLib.c | 169 ++ .../TemplateRealTimeClockLib.inf | 31 + .../TemplateResetSystemLib/ResetSystemLib.c | 97 + .../TemplateResetSystemLib.inf | 30 + .../EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c | 289 +++ .../Library/TimeBaseLib/TimeBaseLib.inf | 28 + .../VirtualRealTimeClockLib.c | 418 +++++ .../VirtualRealTimeClockLib.inf | 37 + .../Firmware/EmbeddedPkg/MetronomeDxe/Metronome.c | 134 ++ .../EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf | 44 + .../RealTimeClockRuntimeDxe/RealTimeClock.c | 227 +++ .../RealTimeClockRuntimeDxe.inf | 42 + .../ResetRuntimeDxe/ResetRuntimeDxe.inf | 45 + .../Firmware/EmbeddedPkg/ResetRuntimeDxe/reset.c | 68 + .../EmbeddedPkg/Scripts/LauterbachT32/EFI.CMM | 34 + .../Scripts/LauterbachT32/EfiLoadDxe.cmm | 129 ++ .../Scripts/LauterbachT32/EfiLoadFv.cmm | 125 ++ .../Scripts/LauterbachT32/EfiProcessPeImage.cmm | 71 + .../Scripts/LauterbachT32/EfiProcessTeImage.cmm | 64 + .../EmbeddedPkg/Scripts/LauterbachT32/Readme.md | 16 + .../EmbeddedPkg/Scripts/LauterbachT32/T32.CMM | 59 + .../SimpleTextInOutSerial/SimpleTextInOut.c | 753 ++++++++ .../SimpleTextInOutSerial.inf | 56 + .../EmbeddedPkg/Universal/MmcDxe/ComponentName.c | 156 ++ .../EmbeddedPkg/Universal/MmcDxe/Diagnostics.c | 253 +++ .../Firmware/EmbeddedPkg/Universal/MmcDxe/Mmc.c | 452 +++++ .../Firmware/EmbeddedPkg/Universal/MmcDxe/Mmc.h | 523 ++++++ .../EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c | 396 ++++ .../EmbeddedPkg/Universal/MmcDxe/MmcDebug.c | 162 ++ .../EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf | 45 + .../Universal/MmcDxe/MmcIdentification.c | 799 ++++++++ 157 files changed, 31909 insertions(+) create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidBootImg.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/Arm/BootAndroidBootImg.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcp.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcpDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.uni create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.vfr create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboardDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedPkg.dec create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedPkg.dsc create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/Arm/Processor.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/GdbStub.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/GdbStub.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/GdbStubInternal.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/Ia32/Processor.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/SerialIo.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/X64/Processor.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/ConsolePrefFormSet.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/DtPlatformDefaultDtbFile.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/DtPlatformFormSet.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/ExtractSection.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/Fdt.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/FdtHob.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/NvVarStoreFormatted.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/PlatformHasDeviceTree.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/AcpiLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/AndroidBootImgLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/DebugAgentTimerLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/DmaLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/DtPlatformDtbLoaderLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/EfiFileLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/EfiResetSystemLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/FdtLoadLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/GdbSerialLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/HalRuntimeServicesLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/NorFlashInfoLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/PrePiHobListPointerLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/PrePiLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/RealTimeClockLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/TimeBaseLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Ppi/EmbeddedGpio.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/AndroidBootImg.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/AndroidFastbootPlatform.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/AndroidFastbootTransport.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/EmbeddedDevice.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/EmbeddedExternalDevice.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/EmbeddedGpio.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/HardwareInterrupt.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/HardwareInterrupt2.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/MmcHost.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/PeCoffLoader.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/PlatformBootManager.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/PlatformVirtualKeyboard.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/UsbDevice.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/fdt.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/libfdt.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/libfdt_env.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/FdtLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/Makefile.libfdt create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/TODO create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_addresses.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_empty_tree.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_overlay.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_ro.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_rw.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strerror.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strtoul.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_sw.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_wip.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/libfdt_internal.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/version.lds create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/Hob.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/FwVol.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePi.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/MemoryAllocationLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/MetronomeDxe/Metronome.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClock.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/ResetRuntimeDxe/reset.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EFI.CMM create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiLoadDxe.cmm create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiLoadFv.cmm create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiProcessPeImage.cmm create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiProcessTeImage.cmm create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/Readme.md create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/T32.CMM create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOut.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOutSerial.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/ComponentName.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/Diagnostics.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/Mmc.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/Mmc.h create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcDebug.c create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c (limited to 'src/VBox/Devices/EFI/Firmware/EmbeddedPkg') diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c new file mode 100644 index 00000000..4633e8d3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.c @@ -0,0 +1,134 @@ +/** @file + + Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
+ Copyright (c) 2017, Linaro. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Validate the node is media hard drive type */ +EFI_STATUS +ValidateAndroidMediaDevicePath ( + IN EFI_DEVICE_PATH *DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *Node, *NextNode; + + NextNode = DevicePath; + while (NextNode != NULL) { + Node = NextNode; + if (Node->Type == MEDIA_DEVICE_PATH && + Node->SubType == MEDIA_HARDDRIVE_DP) { + return EFI_SUCCESS; + } + NextNode = NextDevicePathNode (Node); + } + return EFI_INVALID_PARAMETER; +} + +EFI_STATUS +EFIAPI +AndroidBootAppEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + CHAR16 *BootPathStr; + EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol; + EFI_DEVICE_PATH *DevicePath; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + UINT32 MediaId, BlockSize; + VOID *Buffer; + EFI_HANDLE Handle; + UINTN BootImgSize; + + BootPathStr = (CHAR16 *)PcdGetPtr (PcdAndroidBootDevicePath); + ASSERT (BootPathStr != NULL); + Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, + (VOID **)&EfiDevicePathFromTextProtocol); + ASSERT_EFI_ERROR(Status); + DevicePath = (EFI_DEVICE_PATH *)EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (BootPathStr); + ASSERT (DevicePath != NULL); + + Status = ValidateAndroidMediaDevicePath (DevicePath); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, + &DevicePath, &Handle); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + Handle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to get BlockIo: %r\n", Status)); + return Status; + } + + MediaId = BlockIo->Media->MediaId; + BlockSize = BlockIo->Media->BlockSize; + Buffer = AllocatePages (EFI_SIZE_TO_PAGES (sizeof(ANDROID_BOOTIMG_HEADER))); + if (Buffer == NULL) { + return EFI_BUFFER_TOO_SMALL; + } + /* Load header of boot.img */ + Status = BlockIo->ReadBlocks ( + BlockIo, + MediaId, + 0, + BlockSize, + Buffer + ); + Status = AndroidBootImgGetImgSize (Buffer, &BootImgSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to get AndroidBootImg Size: %r\n", Status)); + return Status; + } + BootImgSize = ALIGN_VALUE (BootImgSize, BlockSize); + FreePages (Buffer, EFI_SIZE_TO_PAGES (sizeof(ANDROID_BOOTIMG_HEADER))); + + /* Both PartitionStart and PartitionSize are counted as block size. */ + Buffer = AllocatePages (EFI_SIZE_TO_PAGES (BootImgSize)); + if (Buffer == NULL) { + return EFI_BUFFER_TOO_SMALL; + } + + /* Load header of boot.img */ + Status = BlockIo->ReadBlocks ( + BlockIo, + MediaId, + 0, + BootImgSize, + Buffer + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to read blocks: %r\n", Status)); + goto EXIT; + } + + Status = AndroidBootImgBoot (Buffer, BootImgSize); + +EXIT: + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf new file mode 100644 index 00000000..149a524a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf @@ -0,0 +1,58 @@ +#/** @file +# +# Copyright (c) 2013-2015, ARM Ltd. All rights reserved.
+# Copyright (c) 2017, Linaro. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = AndroidBootApp + FILE_GUID = 3a738b36-b9c5-4763-abbd-6cbd4b25f9ff + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = AndroidBootAppEntryPoint + +[Sources.common] + AndroidBootApp.c + +[LibraryClasses] + AndroidBootImgLib + BaseLib + BaseMemoryLib + DebugLib + DevicePathLib + DxeServicesTableLib + FdtLib + MemoryAllocationLib + PcdLib + PrintLib + UefiApplicationEntryPoint + UefiBootServicesTableLib + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + gAndroidFastbootPlatformProtocolGuid + gEfiBlockIoProtocolGuid + gEfiDevicePathFromTextProtocolGuid + gEfiSimpleTextOutProtocolGuid + gEfiSimpleTextInProtocolGuid + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[Packages.ARM, Packages.AARCH64] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + +[Guids] + gFdtTableGuid + +[Pcd] + gEmbeddedTokenSpaceGuid.PcdAndroidBootDevicePath diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidBootImg.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidBootImg.c new file mode 100644 index 00000000..63bda4c2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidBootImg.c @@ -0,0 +1,60 @@ +/** @file + + Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "AndroidFastbootApp.h" + +// Find the kernel and ramdisk in an Android boot.img. +// return EFI_INVALID_PARAMETER if the boot.img is invalid (i.e. doesn't have the +// right magic value), +// return EFI_NOT_FOUND if there was no kernel in the boot.img. +// Note that the Ramdisk is optional - *Ramdisk won't be touched if it isn't +// present, but RamdiskSize will be set to 0. +EFI_STATUS +ParseAndroidBootImg ( + IN VOID *BootImg, + OUT VOID **Kernel, + OUT UINTN *KernelSize, + OUT VOID **Ramdisk, + OUT UINTN *RamdiskSize, + OUT CHAR8 *KernelArgs + ) +{ + ANDROID_BOOTIMG_HEADER *Header; + UINT8 *BootImgBytePtr; + + // Cast to UINT8 so we can do pointer arithmetic + BootImgBytePtr = (UINT8 *) BootImg; + + Header = (ANDROID_BOOTIMG_HEADER *) BootImg; + + if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC, + ANDROID_BOOT_MAGIC_LENGTH) != 0) { + return EFI_INVALID_PARAMETER; + } + + if (Header->KernelSize == 0) { + return EFI_NOT_FOUND; + } + + ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); + + *KernelSize = Header->KernelSize; + *Kernel = BootImgBytePtr + Header->PageSize; + *RamdiskSize = Header->RamdiskSize; + + if (Header->RamdiskSize != 0) { + *Ramdisk = (VOID *) (BootImgBytePtr + + Header->PageSize + + ALIGN_VALUE (Header->KernelSize, Header->PageSize)); + } + + AsciiStrnCpyS (KernelArgs, ANDROID_BOOTIMG_KERNEL_ARGS_SIZE, Header->KernelArgs, + ANDROID_BOOTIMG_KERNEL_ARGS_SIZE); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.c new file mode 100644 index 00000000..112ed479 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.c @@ -0,0 +1,529 @@ +/** @file + + Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "AndroidFastbootApp.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * UEFI Application using the FASTBOOT_TRANSPORT_PROTOCOL and + * FASTBOOT_PLATFORM_PROTOCOL to implement the Android Fastboot protocol. + */ + +STATIC FASTBOOT_TRANSPORT_PROTOCOL *mTransport; +STATIC FASTBOOT_PLATFORM_PROTOCOL *mPlatform; + +STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut; + +typedef enum { + ExpectCmdState, + ExpectDataState, + FastbootStateMax +} ANDROID_FASTBOOT_STATE; + +STATIC ANDROID_FASTBOOT_STATE mState = ExpectCmdState; + +// When in ExpectDataState, the number of bytes of data to expect: +STATIC UINT64 mNumDataBytes; +// .. and the number of bytes so far received this data phase +STATIC UINT64 mBytesReceivedSoFar; +// .. and the buffer to save data into +STATIC UINT8 *mDataBuffer = NULL; + +// Event notify functions, from which gBS->Exit shouldn't be called, can signal +// this event when the application should exit +STATIC EFI_EVENT mFinishedEvent; + +STATIC EFI_EVENT mFatalSendErrorEvent; + +// This macro uses sizeof - only use it on arrays (i.e. string literals) +#define SEND_LITERAL(Str) mTransport->Send ( \ + sizeof (Str) - 1, \ + Str, \ + &mFatalSendErrorEvent \ + ) +#define MATCH_CMD_LITERAL(Cmd, Buf) !AsciiStrnCmp (Cmd, Buf, sizeof (Cmd) - 1) + +#define IS_LOWERCASE_ASCII(Char) (Char >= 'a' && Char <= 'z') + +#define FASTBOOT_STRING_MAX_LENGTH 256 +#define FASTBOOT_COMMAND_MAX_LENGTH 64 + +STATIC +VOID +HandleGetVar ( + IN CHAR8 *CmdArg + ) +{ + CHAR8 Response[FASTBOOT_COMMAND_MAX_LENGTH + 1] = "OKAY"; + EFI_STATUS Status; + + // Respond to getvar:version with 0.4 (version of Fastboot protocol) + if (!AsciiStrnCmp ("version", CmdArg, sizeof ("version") - 1 )) { + SEND_LITERAL ("OKAY" ANDROID_FASTBOOT_VERSION); + } else { + // All other variables are assumed to be platform specific + Status = mPlatform->GetVar (CmdArg, Response + 4); + if (EFI_ERROR (Status)) { + SEND_LITERAL ("FAILSomething went wrong when looking up the variable"); + } else { + mTransport->Send (AsciiStrLen (Response), Response, &mFatalSendErrorEvent); + } + } +} + +STATIC +VOID +HandleDownload ( + IN CHAR8 *NumBytesString + ) +{ + CHAR8 Response[13]; + CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH]; + + // Argument is 8-character ASCII string hex representation of number of bytes + // that will be sent in the data phase. + // Response is "DATA" + that same 8-character string. + + // Replace any previously downloaded data + if (mDataBuffer != NULL) { + FreePool (mDataBuffer); + mDataBuffer = NULL; + } + + // Parse out number of data bytes to expect + mNumDataBytes = AsciiStrHexToUint64 (NumBytesString); + if (mNumDataBytes == 0) { + mTextOut->OutputString (mTextOut, L"ERROR: Fail to get the number of bytes to download.\r\n"); + SEND_LITERAL ("FAILFailed to get the number of bytes to download"); + return; + } + + UnicodeSPrint (OutputString, sizeof (OutputString), L"Downloading %d bytes\r\n", mNumDataBytes); + mTextOut->OutputString (mTextOut, OutputString); + + mDataBuffer = AllocatePool (mNumDataBytes); + if (mDataBuffer == NULL) { + SEND_LITERAL ("FAILNot enough memory"); + } else { + ZeroMem (Response, sizeof Response); + AsciiSPrint (Response, sizeof Response, "DATA%x", + (UINT32)mNumDataBytes); + mTransport->Send (sizeof Response - 1, Response, &mFatalSendErrorEvent); + + mState = ExpectDataState; + mBytesReceivedSoFar = 0; + } +} + +STATIC +VOID +HandleFlash ( + IN CHAR8 *PartitionName + ) +{ + EFI_STATUS Status; + CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH]; + + // Build output string + UnicodeSPrint (OutputString, sizeof (OutputString), L"Flashing partition %a\r\n", PartitionName); + mTextOut->OutputString (mTextOut, OutputString); + + if (mDataBuffer == NULL) { + // Doesn't look like we were sent any data + SEND_LITERAL ("FAILNo data to flash"); + return; + } + + Status = mPlatform->FlashPartition ( + PartitionName, + mNumDataBytes, + mDataBuffer + ); + if (Status == EFI_NOT_FOUND) { + SEND_LITERAL ("FAILNo such partition."); + mTextOut->OutputString (mTextOut, L"No such partition.\r\n"); + } else if (EFI_ERROR (Status)) { + SEND_LITERAL ("FAILError flashing partition."); + mTextOut->OutputString (mTextOut, L"Error flashing partition.\r\n"); + DEBUG ((EFI_D_ERROR, "Couldn't flash image: %r\n", Status)); + } else { + mTextOut->OutputString (mTextOut, L"Done.\r\n"); + SEND_LITERAL ("OKAY"); + } +} + +STATIC +VOID +HandleErase ( + IN CHAR8 *PartitionName + ) +{ + EFI_STATUS Status; + CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH]; + + // Build output string + UnicodeSPrint (OutputString, sizeof (OutputString), L"Erasing partition %a\r\n", PartitionName); + mTextOut->OutputString (mTextOut, OutputString); + + Status = mPlatform->ErasePartition (PartitionName); + if (EFI_ERROR (Status)) { + SEND_LITERAL ("FAILCheck device console."); + DEBUG ((EFI_D_ERROR, "Couldn't erase image: %r\n", Status)); + } else { + SEND_LITERAL ("OKAY"); + } +} + +STATIC +VOID +HandleBoot ( + VOID + ) +{ + EFI_STATUS Status; + + mTextOut->OutputString (mTextOut, L"Booting downloaded image\r\n"); + + if (mDataBuffer == NULL) { + // Doesn't look like we were sent any data + SEND_LITERAL ("FAILNo image in memory"); + return; + } + + // We don't really have any choice but to report success, because once we + // boot we lose control of the system. + SEND_LITERAL ("OKAY"); + + Status = BootAndroidBootImg (mNumDataBytes, mDataBuffer); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Failed to boot downloaded image: %r\n", Status)); + } + // We shouldn't get here +} + +STATIC +VOID +HandleOemCommand ( + IN CHAR8 *Command + ) +{ + EFI_STATUS Status; + + Status = mPlatform->DoOemCommand (Command); + if (Status == EFI_NOT_FOUND) { + SEND_LITERAL ("FAILOEM Command not recognised."); + } else if (Status == EFI_DEVICE_ERROR) { + SEND_LITERAL ("FAILError while executing command"); + } else if (EFI_ERROR (Status)) { + SEND_LITERAL ("FAIL"); + } else { + SEND_LITERAL ("OKAY"); + } +} + +STATIC +VOID +AcceptCmd ( + IN UINTN Size, + IN CONST CHAR8 *Data + ) +{ + CHAR8 Command[FASTBOOT_COMMAND_MAX_LENGTH + 1]; + + // Max command size is 64 bytes + if (Size > FASTBOOT_COMMAND_MAX_LENGTH) { + SEND_LITERAL ("FAILCommand too large"); + return; + } + + // Commands aren't null-terminated. Let's get a null-terminated version. + AsciiStrnCpyS (Command, sizeof Command, Data, Size); + + // Parse command + if (MATCH_CMD_LITERAL ("getvar", Command)) { + HandleGetVar (Command + sizeof ("getvar")); + } else if (MATCH_CMD_LITERAL ("download", Command)) { + HandleDownload (Command + sizeof ("download")); + } else if (MATCH_CMD_LITERAL ("verify", Command)) { + SEND_LITERAL ("FAILNot supported"); + } else if (MATCH_CMD_LITERAL ("flash", Command)) { + HandleFlash (Command + sizeof ("flash")); + } else if (MATCH_CMD_LITERAL ("erase", Command)) { + HandleErase (Command + sizeof ("erase")); + } else if (MATCH_CMD_LITERAL ("boot", Command)) { + HandleBoot (); + } else if (MATCH_CMD_LITERAL ("continue", Command)) { + SEND_LITERAL ("OKAY"); + mTextOut->OutputString (mTextOut, L"Received 'continue' command. Exiting Fastboot mode\r\n"); + + gBS->SignalEvent (mFinishedEvent); + } else if (MATCH_CMD_LITERAL ("reboot", Command)) { + if (MATCH_CMD_LITERAL ("reboot-booloader", Command)) { + // fastboot_protocol.txt: + // "reboot-bootloader Reboot back into the bootloader." + // I guess this means reboot back into fastboot mode to save the user + // having to do whatever they did to get here again. + // Here we just reboot normally. + SEND_LITERAL ("INFOreboot-bootloader not supported, rebooting normally."); + } + SEND_LITERAL ("OKAY"); + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + + // Shouldn't get here + DEBUG ((EFI_D_ERROR, "Fastboot: gRT->ResetSystem didn't work\n")); + } else if (MATCH_CMD_LITERAL ("powerdown", Command)) { + SEND_LITERAL ("OKAY"); + gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); + + // Shouldn't get here + DEBUG ((EFI_D_ERROR, "Fastboot: gRT->ResetSystem didn't work\n")); + } else if (MATCH_CMD_LITERAL ("oem", Command)) { + // The "oem" command isn't in the specification, but it was observed in the + // wild, followed by a space, followed by the actual command. + HandleOemCommand (Command + sizeof ("oem")); + } else if (IS_LOWERCASE_ASCII (Command[0])) { + // Commands starting with lowercase ASCII characters are reserved for the + // Fastboot protocol. If we don't recognise it, it's probably the future + // and there are new commands in the protocol. + // (By the way, the "oem" command mentioned above makes this reservation + // redundant, but we handle it here to be spec-compliant) + SEND_LITERAL ("FAILCommand not recognised. Check Fastboot version."); + } else { + HandleOemCommand (Command); + } +} + +STATIC +VOID +AcceptData ( + IN UINTN Size, + IN VOID *Data + ) +{ + UINT32 RemainingBytes = mNumDataBytes - mBytesReceivedSoFar; + CHAR16 OutputString[FASTBOOT_STRING_MAX_LENGTH]; + STATIC UINTN Count = 0; + + // Protocol doesn't say anything about sending extra data so just ignore it. + if (Size > RemainingBytes) { + Size = RemainingBytes; + } + + CopyMem (&mDataBuffer[mBytesReceivedSoFar], Data, Size); + + mBytesReceivedSoFar += Size; + + // Show download progress. Don't do it for every packet as outputting text + // might be time consuming - do it on the last packet and on every 32nd packet + if ((Count++ % 32) == 0 || Size == RemainingBytes) { + // (Note no newline in format string - it will overwrite the line each time) + UnicodeSPrint ( + OutputString, + sizeof (OutputString), + L"\r%8d / %8d bytes downloaded (%d%%)", + mBytesReceivedSoFar, + mNumDataBytes, + (mBytesReceivedSoFar * 100) / mNumDataBytes // percentage + ); + mTextOut->OutputString (mTextOut, OutputString); + } + + if (mBytesReceivedSoFar == mNumDataBytes) { + // Download finished. + + mTextOut->OutputString (mTextOut, L"\r\n"); + SEND_LITERAL ("OKAY"); + mState = ExpectCmdState; + } +} + +/* + This is the NotifyFunction passed to CreateEvent in the FastbootAppEntryPoint + It will be called by the UEFI event framework when the transport protocol + implementation signals that data has been received from the Fastboot host. + The parameters are ignored. +*/ +STATIC +VOID +DataReady ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Size; + VOID *Data; + EFI_STATUS Status; + + do { + Status = mTransport->Receive (&Size, &Data); + if (!EFI_ERROR (Status)) { + if (mState == ExpectCmdState) { + AcceptCmd (Size, (CHAR8 *) Data); + } else if (mState == ExpectDataState) { + AcceptData (Size, Data); + } else { + ASSERT (FALSE); + } + FreePool (Data); + } + } while (!EFI_ERROR (Status)); + + // Quit if there was a fatal error + if (Status != EFI_NOT_READY) { + ASSERT (Status == EFI_DEVICE_ERROR); + // (Put a newline at the beginning as we are probably in the data phase, + // so the download progress line, with no '\n' is probably on the console) + mTextOut->OutputString (mTextOut, L"\r\nFatal error receiving data. Exiting.\r\n"); + gBS->SignalEvent (mFinishedEvent); + } +} + +/* + Event notify for a fatal error in transmission. +*/ +STATIC +VOID +FatalErrorNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + mTextOut->OutputString (mTextOut, L"Fatal error sending command response. Exiting.\r\n"); + gBS->SignalEvent (mFinishedEvent); +} + +EFI_STATUS +EFIAPI +FastbootAppEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT ReceiveEvent; + EFI_EVENT WaitEventArray[2]; + UINTN EventIndex; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *TextIn; + EFI_INPUT_KEY Key; + + mDataBuffer = NULL; + + Status = gBS->LocateProtocol ( + &gAndroidFastbootTransportProtocolGuid, + NULL, + (VOID **) &mTransport + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't open Fastboot Transport Protocol: %r\n", Status)); + return Status; + } + + Status = gBS->LocateProtocol (&gAndroidFastbootPlatformProtocolGuid, NULL, (VOID **) &mPlatform); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't open Fastboot Platform Protocol: %r\n", Status)); + return Status; + } + + Status = mPlatform->Init (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't initialise Fastboot Platform Protocol: %r\n", Status)); + return Status; + } + + Status = gBS->LocateProtocol (&gEfiSimpleTextOutProtocolGuid, NULL, (VOID **) &mTextOut); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, + "Fastboot: Couldn't open Text Output Protocol: %r\n", Status + )); + return Status; + } + + Status = gBS->LocateProtocol (&gEfiSimpleTextInProtocolGuid, NULL, (VOID **) &TextIn); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't open Text Input Protocol: %r\n", Status)); + return Status; + } + + // Disable watchdog + Status = gBS->SetWatchdogTimer (0, 0x10000, 0, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't disable watchdog timer: %r\n", Status)); + } + + // Create event for receipt of data from the host + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + DataReady, + NULL, + &ReceiveEvent + ); + ASSERT_EFI_ERROR (Status); + + // Create event for exiting application when "continue" command is received + Status = gBS->CreateEvent (0, TPL_CALLBACK, NULL, NULL, &mFinishedEvent); + ASSERT_EFI_ERROR (Status); + + // Create event to pass to FASTBOOT_TRANSPORT_PROTOCOL.Send, signalling a + // fatal error + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + FatalErrorNotify, + NULL, + &mFatalSendErrorEvent + ); + ASSERT_EFI_ERROR (Status); + + + // Start listening for data + Status = mTransport->Start ( + ReceiveEvent + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fastboot: Couldn't start transport: %r\n", Status)); + return Status; + } + + // Talk to the user + mTextOut->OutputString (mTextOut, + L"Android Fastboot mode - version " ANDROID_FASTBOOT_VERSION ". Press RETURN or SPACE key to quit.\r\n"); + + // Quit when the user presses any key, or mFinishedEvent is signalled + WaitEventArray[0] = mFinishedEvent; + WaitEventArray[1] = TextIn->WaitForKey; + while (1) { + gBS->WaitForEvent (2, WaitEventArray, &EventIndex); + Status = TextIn->ReadKeyStroke (gST->ConIn, &Key); + if (Key.ScanCode == SCAN_NULL) { + if ((Key.UnicodeChar == CHAR_CARRIAGE_RETURN) || + (Key.UnicodeChar == L' ')) { + break; + } + } + } + + mTransport->Stop (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Warning: Fastboot Transport Stop: %r\n", Status)); + } + mPlatform->UnInit (); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.h new file mode 100644 index 00000000..196028e1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.h @@ -0,0 +1,37 @@ +/** @file + + Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __ANDROID_FASTBOOT_APP_H__ +#define __ANDROID_FASTBOOT_APP_H__ + +#include +#include +#include +#include + +#define BOOTIMG_KERNEL_ARGS_SIZE 512 + +#define ANDROID_FASTBOOT_VERSION "0.4" + +EFI_STATUS +BootAndroidBootImg ( + IN UINTN BufferSize, + IN VOID *Buffer + ); + +EFI_STATUS +ParseAndroidBootImg ( + IN VOID *BootImg, + OUT VOID **Kernel, + OUT UINTN *KernelSize, + OUT VOID **Ramdisk, + OUT UINTN *RamdiskSize, + OUT CHAR8 *KernelArgs + ); + +#endif //ifdef __ANDROID_FASTBOOT_APP_H__ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf new file mode 100644 index 00000000..66007012 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf @@ -0,0 +1,53 @@ +#/** @file +# +# Copyright (c) 2013-2015, ARM Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AndroidFastbootApp + FILE_GUID = 9588502a-5370-11e3-8631-d7c5951364c8 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = FastbootAppEntryPoint + +[Sources.common] + AndroidFastbootApp.c + AndroidBootImg.c + +[Sources.ARM, Sources.AARCH64] + Arm/BootAndroidBootImg.c + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DevicePathLib + DxeServicesTableLib + MemoryAllocationLib + PcdLib + PrintLib + UefiApplicationEntryPoint + UefiBootServicesTableLib + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + gAndroidFastbootTransportProtocolGuid + gAndroidFastbootPlatformProtocolGuid + gEfiLoadedImageProtocolGuid + gEfiSimpleTextOutProtocolGuid + gEfiSimpleTextInProtocolGuid + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[Packages.ARM, Packages.AARCH64] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/Arm/BootAndroidBootImg.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/Arm/BootAndroidBootImg.c new file mode 100644 index 00000000..c61e5290 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Application/AndroidFastboot/Arm/BootAndroidBootImg.c @@ -0,0 +1,178 @@ +/** @file + + Copyright (c) 2013-2015, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "AndroidFastbootApp.h" + +#include +#include + +#include +#include +#include + +// Device Path representing an image in memory +#pragma pack(1) +typedef struct { + MEMMAP_DEVICE_PATH Node1; + EFI_DEVICE_PATH_PROTOCOL End; +} MEMORY_DEVICE_PATH; +#pragma pack() + +STATIC CONST MEMORY_DEVICE_PATH MemoryDevicePathTemplate = +{ + { + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + { + (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), + (UINT8)((sizeof (MEMMAP_DEVICE_PATH)) >> 8), + }, + }, // Header + 0, // StartingAddress (set at runtime) + 0 // EndingAddress (set at runtime) + }, // Node1 + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } + } // End +}; + + +/** + Start an EFI Application from a Device Path + + @param ParentImageHandle Handle of the calling image + @param DevicePath Location of the EFI Application + + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found + @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. + +**/ +STATIC +EFI_STATUS +StartEfiApplication ( + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN UINTN LoadOptionsSize, + IN VOID* LoadOptions + ) +{ + EFI_STATUS Status; + EFI_HANDLE ImageHandle; + EFI_LOADED_IMAGE_PROTOCOL* LoadedImage; + + // Load the image from the device path with Boot Services function + Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, NULL, 0, + &ImageHandle); + if (EFI_ERROR (Status)) { + // + // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created + // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now. + // If the caller doesn't have the option to defer the execution of an image, we should + // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak. + // + if (Status == EFI_SECURITY_VIOLATION) { + gBS->UnloadImage (ImageHandle); + } + return Status; + } + + // Passed LoadOptions to the EFI Application + if (LoadOptionsSize != 0) { + Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, + (VOID **) &LoadedImage); + if (EFI_ERROR (Status)) { + return Status; + } + + LoadedImage->LoadOptionsSize = LoadOptionsSize; + LoadedImage->LoadOptions = LoadOptions; + } + + // Before calling the image, enable the Watchdog Timer for the 5 Minute period + gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); + // Start the image + Status = gBS->StartImage (ImageHandle, NULL, NULL); + // Clear the Watchdog Timer after the image returns + gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); + + return Status; +} + +EFI_STATUS +BootAndroidBootImg ( + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + CHAR8 KernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE]; + VOID *Kernel; + UINTN KernelSize; + VOID *Ramdisk; + UINTN RamdiskSize; + MEMORY_DEVICE_PATH KernelDevicePath; + CHAR16 *LoadOptions, *NewLoadOptions; + + Status = ParseAndroidBootImg ( + Buffer, + &Kernel, + &KernelSize, + &Ramdisk, + &RamdiskSize, + KernelArgs + ); + if (EFI_ERROR (Status)) { + return Status; + } + + KernelDevicePath = MemoryDevicePathTemplate; + + // Have to cast to UINTN before casting to EFI_PHYSICAL_ADDRESS in order to + // appease GCC. + KernelDevicePath.Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel; + KernelDevicePath.Node1.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel + KernelSize; + + // Initialize Linux command line + LoadOptions = CatSPrint (NULL, L"%a", KernelArgs); + if (LoadOptions == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (RamdiskSize != 0) { + NewLoadOptions = CatSPrint (LoadOptions, L" initrd=0x%x,0x%x", + (UINTN)Ramdisk, RamdiskSize); + FreePool (LoadOptions); + if (NewLoadOptions == NULL) { + return EFI_OUT_OF_RESOURCES; + } + LoadOptions = NewLoadOptions; + } + + Status = StartEfiApplication (gImageHandle, + (EFI_DEVICE_PATH_PROTOCOL *) &KernelDevicePath, + StrSize (LoadOptions), + LoadOptions); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Couldn't Boot Linux: %d\n", Status)); + Status = EFI_DEVICE_ERROR; + goto FreeLoadOptions; + } + + // If we got here we do a confused face because BootLinuxFdt returned, + // reporting success. + DEBUG ((EFI_D_ERROR, "WARNING: BdsBootLinuxFdt returned EFI_SUCCESS.\n")); + return EFI_SUCCESS; + +FreeLoadOptions: + FreePool (LoadOptions); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcp.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcp.c new file mode 100644 index 00000000..c4e20ea5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcp.c @@ -0,0 +1,660 @@ +/** @file +# +# Copyright (c) 2014, ARM Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define IP4_ADDR_TO_STRING(IpAddr, IpAddrString) UnicodeSPrint ( \ + IpAddrString, \ + 16 * 2, \ + L"%d.%d.%d.%d", \ + IpAddr.Addr[0], \ + IpAddr.Addr[1], \ + IpAddr.Addr[2], \ + IpAddr.Addr[3] \ + ); + +// Fastboot says max packet size is 512, but FASTBOOT_TRANSPORT_PROTOCOL +// doesn't place a limit on the size of buffers returned by Receive. +// (This isn't actually a packet size - it's just the size of the buffers we +// pass to the TCP driver to fill with received data.) +// We can achieve much better performance by doing this in larger chunks. +#define RX_FRAGMENT_SIZE 2048 + +STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut; + +STATIC EFI_TCP4_PROTOCOL *mTcpConnection; +STATIC EFI_TCP4_PROTOCOL *mTcpListener; + +STATIC EFI_EVENT mReceiveEvent; + +STATIC EFI_SERVICE_BINDING_PROTOCOL *mTcpServiceBinding; +STATIC EFI_HANDLE mTcpHandle = NULL; + +// We only ever use one IO token for receive and one for transmit. To save +// repeatedly allocating and freeing, just allocate statically and re-use. +#define NUM_RX_TOKENS 16 +#define TOKEN_NEXT(Index) (((Index) + 1) % NUM_RX_TOKENS) + +STATIC UINTN mNextSubmitIndex; +STATIC UINTN mNextReceiveIndex; +STATIC EFI_TCP4_IO_TOKEN mReceiveToken[NUM_RX_TOKENS]; +STATIC EFI_TCP4_RECEIVE_DATA mRxData[NUM_RX_TOKENS]; +STATIC EFI_TCP4_IO_TOKEN mTransmitToken; +STATIC EFI_TCP4_TRANSMIT_DATA mTxData; +// We also reuse the accept token +STATIC EFI_TCP4_LISTEN_TOKEN mAcceptToken; +// .. and the close token +STATIC EFI_TCP4_CLOSE_TOKEN mCloseToken; + +// List type for queued received packets +typedef struct _FASTBOOT_TCP_PACKET_LIST { + LIST_ENTRY Link; + VOID *Buffer; + UINTN BufferSize; +} FASTBOOT_TCP_PACKET_LIST; + +STATIC LIST_ENTRY mPacketListHead; + +STATIC +VOID +EFIAPI +DataReceived ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/* + Helper function to set up a receive IO token and call Tcp->Receive +*/ +STATIC +EFI_STATUS +SubmitRecieveToken ( + VOID + ) +{ + EFI_STATUS Status; + VOID *FragmentBuffer; + + Status = EFI_SUCCESS; + + FragmentBuffer = AllocatePool (RX_FRAGMENT_SIZE); + ASSERT (FragmentBuffer != NULL); + if (FragmentBuffer == NULL) { + DEBUG ((EFI_D_ERROR, "TCP Fastboot out of resources")); + return EFI_OUT_OF_RESOURCES; + } + + mRxData[mNextSubmitIndex].DataLength = RX_FRAGMENT_SIZE; + mRxData[mNextSubmitIndex].FragmentTable[0].FragmentLength = RX_FRAGMENT_SIZE; + mRxData[mNextSubmitIndex].FragmentTable[0].FragmentBuffer = FragmentBuffer; + + Status = mTcpConnection->Receive (mTcpConnection, &mReceiveToken[mNextSubmitIndex]); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TCP Receive: %r\n", Status)); + FreePool (FragmentBuffer); + } + + mNextSubmitIndex = TOKEN_NEXT (mNextSubmitIndex); + return Status; +} + +/* + Event notify function for when we have closed our TCP connection. + We can now start listening for another connection. +*/ +STATIC +VOID +ConnectionClosed ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // Possible bug in EDK2 TCP4 driver: closing a connection doesn't remove its + // PCB from the list of live connections. Subsequent attempts to Configure() + // a TCP instance with the same local port will fail with INVALID_PARAMETER. + // Calling Configure with NULL is a workaround for this issue. + Status = mTcpConnection->Configure (mTcpConnection, NULL); + + mTcpConnection = NULL; + + Status = mTcpListener->Accept (mTcpListener, &mAcceptToken); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TCP Accept: %r\n", Status)); + } +} + +STATIC +VOID +CloseReceiveEvents ( + VOID + ) +{ + UINTN Index; + + for (Index = 0; Index < NUM_RX_TOKENS; Index++) { + gBS->CloseEvent (mReceiveToken[Index].CompletionToken.Event); + } +} + +/* + Event notify function to be called when we receive TCP data. +*/ +STATIC +VOID +EFIAPI +DataReceived ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + FASTBOOT_TCP_PACKET_LIST *NewEntry; + EFI_TCP4_IO_TOKEN *ReceiveToken; + + ReceiveToken = &mReceiveToken[mNextReceiveIndex]; + + Status = ReceiveToken->CompletionToken.Status; + + if (Status == EFI_CONNECTION_FIN) { + // + // Remote host closed connection. Close our end. + // + + CloseReceiveEvents (); + + Status = mTcpConnection->Close (mTcpConnection, &mCloseToken); + ASSERT_EFI_ERROR (Status); + + return; + } + + // + // Add an element to the receive queue + // + + NewEntry = AllocatePool (sizeof (FASTBOOT_TCP_PACKET_LIST)); + if (NewEntry == NULL) { + DEBUG ((EFI_D_ERROR, "TCP Fastboot: Out of resources\n")); + return; + } + + mNextReceiveIndex = TOKEN_NEXT (mNextReceiveIndex); + + if (!EFI_ERROR (Status)) { + NewEntry->Buffer + = ReceiveToken->Packet.RxData->FragmentTable[0].FragmentBuffer; + NewEntry->BufferSize + = ReceiveToken->Packet.RxData->FragmentTable[0].FragmentLength; + + // Prepare to receive more data + SubmitRecieveToken(); + } else { + // Fatal receive error. Put an entry with NULL in the queue, signifying + // to return EFI_DEVICE_ERROR from TcpFastbootTransportReceive. + NewEntry->Buffer = NULL; + NewEntry->BufferSize = 0; + + DEBUG ((EFI_D_ERROR, "\nTCP Fastboot Receive error: %r\n", Status)); + } + + InsertTailList (&mPacketListHead, &NewEntry->Link); + + Status = gBS->SignalEvent (mReceiveEvent); + ASSERT_EFI_ERROR (Status); +} + + +/* + Event notify function to be called when we accept an incoming TCP connection. +*/ +STATIC +VOID +EFIAPI +ConnectionAccepted ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_TCP4_LISTEN_TOKEN *AcceptToken; + EFI_STATUS Status; + UINTN Index; + + AcceptToken = (EFI_TCP4_LISTEN_TOKEN *) Context; + Status = AcceptToken->CompletionToken.Status; + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TCP Fastboot: Connection Error: %r\n", Status)); + return; + } + DEBUG ((EFI_D_ERROR, "TCP Fastboot: Connection Received.\n")); + + // + // Accepting a new TCP connection creates a new instance of the TCP protocol. + // Open it and prepare to receive on it. + // + + Status = gBS->OpenProtocol ( + AcceptToken->NewChildHandle, + &gEfiTcp4ProtocolGuid, + (VOID **) &mTcpConnection, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Open TCP Connection: %r\n", Status)); + return; + } + + mNextSubmitIndex = 0; + mNextReceiveIndex = 0; + + for (Index = 0; Index < NUM_RX_TOKENS; Index++) { + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + DataReceived, + NULL, + &(mReceiveToken[Index].CompletionToken.Event) + ); + ASSERT_EFI_ERROR (Status); + } + + for (Index = 0; Index < NUM_RX_TOKENS; Index++) { + SubmitRecieveToken(); + } +} + +/* + Set up TCP Fastboot transport: Configure the network device via DHCP then + start waiting for a TCP connection on the Fastboot port. +*/ +EFI_STATUS +TcpFastbootTransportStart ( + EFI_EVENT ReceiveEvent + ) +{ + EFI_STATUS Status; + EFI_HANDLE NetDeviceHandle; + EFI_HANDLE *HandleBuffer; + EFI_IP4_MODE_DATA Ip4ModeData; + UINTN NumHandles; + CHAR16 IpAddrString[16]; + UINTN Index; + + EFI_TCP4_CONFIG_DATA TcpConfigData = { + 0x00, // IPv4 Type of Service + 255, // IPv4 Time to Live + { // AccessPoint: + TRUE, // Use default address + { {0, 0, 0, 0} }, // IP Address (ignored - use default) + { {0, 0, 0, 0} }, // Subnet mask (ignored - use default) + FixedPcdGet32 (PcdAndroidFastbootTcpPort), // Station port + { {0, 0, 0, 0} }, // Remote address: accept any + 0, // Remote Port: accept any + FALSE // ActiveFlag: be a "server" + }, + NULL // Default advanced TCP options + }; + + mReceiveEvent = ReceiveEvent; + InitializeListHead (&mPacketListHead); + + mTextOut->OutputString (mTextOut, L"Initialising TCP Fastboot transport...\r\n"); + + // + // Open a passive TCP instance + // + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiTcp4ServiceBindingProtocolGuid, + NULL, + &NumHandles, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Find TCP Service Binding: %r\n", Status)); + return Status; + } + + // We just use the first network device + NetDeviceHandle = HandleBuffer[0]; + + Status = gBS->OpenProtocol ( + NetDeviceHandle, + &gEfiTcp4ServiceBindingProtocolGuid, + (VOID **) &mTcpServiceBinding, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Open TCP Service Binding: %r\n", Status)); + return Status; + } + + Status = mTcpServiceBinding->CreateChild (mTcpServiceBinding, &mTcpHandle); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TCP ServiceBinding Create: %r\n", Status)); + return Status; + } + + Status = gBS->OpenProtocol ( + mTcpHandle, + &gEfiTcp4ProtocolGuid, + (VOID **) &mTcpListener, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Open TCP Protocol: %r\n", Status)); + } + + // + // Set up re-usable tokens + // + + for (Index = 0; Index < NUM_RX_TOKENS; Index++) { + mRxData[Index].UrgentFlag = FALSE; + mRxData[Index].FragmentCount = 1; + mReceiveToken[Index].Packet.RxData = &mRxData[Index]; + } + + mTxData.Push = TRUE; + mTxData.Urgent = FALSE; + mTxData.FragmentCount = 1; + mTransmitToken.Packet.TxData = &mTxData; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ConnectionAccepted, + &mAcceptToken, + &mAcceptToken.CompletionToken.Event + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ConnectionClosed, + &mCloseToken, + &mCloseToken.CompletionToken.Event + ); + ASSERT_EFI_ERROR (Status); + + // + // Configure the TCP instance + // + + Status = mTcpListener->Configure (mTcpListener, &TcpConfigData); + if (Status == EFI_NO_MAPPING) { + // Wait until the IP configuration process (probably DHCP) has finished + do { + Status = mTcpListener->GetModeData (mTcpListener, + NULL, NULL, + &Ip4ModeData, + NULL, NULL + ); + ASSERT_EFI_ERROR (Status); + } while (!Ip4ModeData.IsConfigured); + Status = mTcpListener->Configure (mTcpListener, &TcpConfigData); + } else if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TCP Configure: %r\n", Status)); + return Status; + } + + // + // Tell the user our address and hostname + // + IP4_ADDR_TO_STRING (Ip4ModeData.ConfigData.StationAddress, IpAddrString); + + mTextOut->OutputString (mTextOut, L"TCP Fastboot transport configured."); + mTextOut->OutputString (mTextOut, L"\r\nIP address: "); + mTextOut->OutputString (mTextOut ,IpAddrString); + mTextOut->OutputString (mTextOut, L"\r\n"); + + // + // Start listening for a connection + // + + Status = mTcpListener->Accept (mTcpListener, &mAcceptToken); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TCP Accept: %r\n", Status)); + return Status; + } + + mTextOut->OutputString (mTextOut, L"TCP Fastboot transport initialised.\r\n"); + + FreePool (HandleBuffer); + + return EFI_SUCCESS; +} + +EFI_STATUS +TcpFastbootTransportStop ( + VOID + ) +{ + EFI_TCP4_CLOSE_TOKEN CloseToken; + EFI_STATUS Status; + UINTN EventIndex; + FASTBOOT_TCP_PACKET_LIST *Entry; + FASTBOOT_TCP_PACKET_LIST *NextEntry; + + // Close any existing TCP connection, blocking until it's done. + if (mTcpConnection != NULL) { + CloseReceiveEvents (); + + CloseToken.AbortOnClose = FALSE; + + Status = gBS->CreateEvent (0, 0, NULL, NULL, &CloseToken.CompletionToken.Event); + ASSERT_EFI_ERROR (Status); + + Status = mTcpConnection->Close (mTcpConnection, &CloseToken); + ASSERT_EFI_ERROR (Status); + + Status = gBS->WaitForEvent ( + 1, + &CloseToken.CompletionToken.Event, + &EventIndex + ); + ASSERT_EFI_ERROR (Status); + + ASSERT_EFI_ERROR (CloseToken.CompletionToken.Status); + + // Possible bug in EDK2 TCP4 driver: closing a connection doesn't remove its + // PCB from the list of live connections. Subsequent attempts to Configure() + // a TCP instance with the same local port will fail with INVALID_PARAMETER. + // Calling Configure with NULL is a workaround for this issue. + Status = mTcpConnection->Configure (mTcpConnection, NULL); + ASSERT_EFI_ERROR (Status); + } + + + gBS->CloseEvent (mAcceptToken.CompletionToken.Event); + + // Stop listening for connections. + // Ideally we would do this with Cancel, but it isn't implemented by EDK2. + // So we just "reset this TCPv4 instance brutally". + Status = mTcpListener->Configure (mTcpListener, NULL); + ASSERT_EFI_ERROR (Status); + + Status = mTcpServiceBinding->DestroyChild (mTcpServiceBinding, mTcpHandle); + + // Free any data the user didn't pick up + Entry = (FASTBOOT_TCP_PACKET_LIST *) GetFirstNode (&mPacketListHead); + while (!IsNull (&mPacketListHead, &Entry->Link)) { + NextEntry = (FASTBOOT_TCP_PACKET_LIST *) GetNextNode (&mPacketListHead, &Entry->Link); + + RemoveEntryList (&Entry->Link); + if (Entry->Buffer) { + FreePool (Entry->Buffer); + } + FreePool (Entry); + + Entry = NextEntry; + } + + return EFI_SUCCESS; +} + +/* + Event notify function for when data has been sent. Free resources and report + errors. + Context should point to the transmit IO token passed to + TcpConnection->Transmit. +*/ +STATIC +VOID +DataSent ( + EFI_EVENT Event, + VOID *Context + ) +{ + EFI_STATUS Status; + + Status = mTransmitToken.CompletionToken.Status; + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TCP Fastboot transmit result: %r\n", Status)); + gBS->SignalEvent (*(EFI_EVENT *) Context); + } + + FreePool (mTransmitToken.Packet.TxData->FragmentTable[0].FragmentBuffer); +} + +EFI_STATUS +TcpFastbootTransportSend ( + IN UINTN BufferSize, + IN CONST VOID *Buffer, + IN EFI_EVENT *FatalErrorEvent + ) +{ + EFI_STATUS Status; + + if (BufferSize > 512) { + return EFI_INVALID_PARAMETER; + } + + // + // Build transmit IO token + // + + // Create an event so we are notified when a transmission is complete. + // We use this to free resources and report errors. + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + DataSent, + FatalErrorEvent, + &mTransmitToken.CompletionToken.Event + ); + ASSERT_EFI_ERROR (Status); + + mTxData.DataLength = BufferSize; + + mTxData.FragmentTable[0].FragmentLength = BufferSize; + mTxData.FragmentTable[0].FragmentBuffer = AllocateCopyPool ( + BufferSize, + Buffer + ); + + Status = mTcpConnection->Transmit (mTcpConnection, &mTransmitToken); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TCP Transmit: %r\n", Status)); + return Status; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +TcpFastbootTransportReceive ( + OUT UINTN *BufferSize, + OUT VOID **Buffer + ) +{ + FASTBOOT_TCP_PACKET_LIST *Entry; + + if (IsListEmpty (&mPacketListHead)) { + return EFI_NOT_READY; + } + + Entry = (FASTBOOT_TCP_PACKET_LIST *) GetFirstNode (&mPacketListHead); + + if (Entry->Buffer == NULL) { + // There was an error receiving this packet. + return EFI_DEVICE_ERROR; + } + + *Buffer = Entry->Buffer; + *BufferSize = Entry->BufferSize; + + RemoveEntryList (&Entry->Link); + FreePool (Entry); + + return EFI_SUCCESS; +} + +FASTBOOT_TRANSPORT_PROTOCOL mTransportProtocol = { + TcpFastbootTransportStart, + TcpFastbootTransportStop, + TcpFastbootTransportSend, + TcpFastbootTransportReceive +}; + +EFI_STATUS +TcpFastbootTransportEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + + Status = gBS->LocateProtocol( + &gEfiSimpleTextOutProtocolGuid, + NULL, + (VOID **) &mTextOut + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fastboot: Open Text Output Protocol: %r\n", Status)); + return Status; + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gAndroidFastbootTransportProtocolGuid, + EFI_NATIVE_INTERFACE, + &mTransportProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fastboot: Install transport Protocol: %r\n", Status)); + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcpDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcpDxe.inf new file mode 100644 index 00000000..7f1693a9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcpDxe.inf @@ -0,0 +1,46 @@ +#/** @file +# +# Copyright (c) 2014, ARM Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcpFastbootTransportDxe + FILE_GUID = 86787704-8fed-11e3-b3ff-f33b73acfec2 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = TcpFastbootTransportEntryPoint + +[Sources.common] + FastbootTransportTcp.c + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + PrintLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + +[Protocols] + gAndroidFastbootTransportProtocolGuid + gEfiDhcp4ProtocolGuid + gEfiDhcp4ServiceBindingProtocolGuid + gEfiTcp4ServiceBindingProtocolGuid + gEfiSimpleTextOutProtocolGuid + gEfiTcp4ProtocolGuid + gEfiSimpleTextOutProtocolGuid + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[FixedPcd] + gEmbeddedTokenSpaceGuid.PcdAndroidFastbootTcpPort diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c new file mode 100644 index 00000000..130b00ad --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c @@ -0,0 +1,272 @@ +/** @file + + Copyright (c) 2014, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +/* + * Implementation of the FASTBOOT_TRANSPORT_PROTOCOL using the USB_DEVICE_PROTOCOL + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +STATIC USB_DEVICE_PROTOCOL *mUsbDevice; + +// Configuration attributes: +// bit 7 reserved and must be 1, bit 6 means self-powered. +#define CONFIG_DESC_ATTRIBUTES (BIT7 | BIT6) + +#define MAX_PACKET_SIZE_BULK 512 + +STATIC USB_DEVICE_PROTOCOL *mUsbDevice; +STATIC EFI_EVENT mReceiveEvent = NULL; +STATIC LIST_ENTRY mPacketList; + +// List type for queued received packets +typedef struct _FASTBOOT_USB_PACKET_LIST { + LIST_ENTRY Link; + VOID *Buffer; + UINTN BufferSize; +} FASTBOOT_USB_PACKET_LIST; + + +/* + No string descriptors - all string descriptor members are set to 0 +*/ + +STATIC USB_DEVICE_DESCRIPTOR mDeviceDescriptor = { + sizeof (USB_DEVICE_DESCRIPTOR), //Length + USB_DESC_TYPE_DEVICE, //DescriptorType + 0x0200, //BcdUSB + 0xFF, //DeviceClass + 0, //DeviceSubClass + 0, //DeviceProtocol + 64, //MaxPacketSize0 + FixedPcdGet32 (PcdAndroidFastbootUsbVendorId), //IdVendor + FixedPcdGet32 (PcdAndroidFastbootUsbProductId), //IdProduct + 0, //BcdDevice + 0, //StrManufacturer + 0, //StrProduct + 0, //StrSerialNumber + 1 //NumConfigurations +}; + +/* + We have one configuration, one interface, and two endpoints (one IN, one OUT) +*/ + +// Lazy (compile-time) way to concatenate descriptors to pass to the USB device +// protocol + +#pragma pack(1) +typedef struct { + USB_CONFIG_DESCRIPTOR ConfigDescriptor; + USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + USB_ENDPOINT_DESCRIPTOR EndpointDescriptor1; + USB_ENDPOINT_DESCRIPTOR EndpointDescriptor2; +} GET_CONFIG_DESCRIPTOR_RESPONSE; +#pragma pack() + +STATIC GET_CONFIG_DESCRIPTOR_RESPONSE mGetConfigDescriptorResponse = { + { // USB_CONFIG_DESCRIPTOR + sizeof (USB_CONFIG_DESCRIPTOR), //Length; + USB_DESC_TYPE_CONFIG, //DescriptorType; + sizeof (GET_CONFIG_DESCRIPTOR_RESPONSE), //TotalLength; + 1, //NumInterfaces; + 1, //ConfigurationValue; + 0, //Configuration; + CONFIG_DESC_ATTRIBUTES, //Attributes; + 0 //MaxPower; + }, + { // USB_INTERFACE_DESCRIPTOR + sizeof (USB_INTERFACE_DESCRIPTOR), //Length; + USB_DESC_TYPE_INTERFACE, //DescriptorType; + 0, //InterfaceNumber; + 0, //AlternateSetting; + 2, //NumEndpoints; + 0xFF, //InterfaceClass; + // Vendor specific interface subclass and protocol codes. + // I found these values in the Fastboot code + // (in match_fastboot_with_serial in fastboot.c). + 0x42, //InterfaceSubClass; + 0x03, //InterfaceProtocol; + 0 //Interface; + }, + { // USB_ENDPOINT_DESCRIPTOR (In Endpoint) + sizeof (USB_ENDPOINT_DESCRIPTOR), //Length; + USB_DESC_TYPE_ENDPOINT, //DescriptorType; + 1 | BIT7, //EndpointAddress; + 0x2, //Attributes; + MAX_PACKET_SIZE_BULK, //MaxPacketSize; + 16 //Interval; + }, + { // STATIC USB_ENDPOINT_DESCRIPTOR (Out Endpoint) + sizeof (USB_ENDPOINT_DESCRIPTOR), //Length; + USB_DESC_TYPE_ENDPOINT, //DescriptorType; + 1, //EndpointAddress; + 0x2, //Attributes; + MAX_PACKET_SIZE_BULK, //MaxPacketSize; + 16 //Interval; + } +}; + +STATIC +VOID +DataReceived ( + IN UINTN Size, + IN VOID *Buffer + ) +{ + FASTBOOT_USB_PACKET_LIST *NewEntry; + + NewEntry = AllocatePool (sizeof (*NewEntry)); + ASSERT (NewEntry != NULL); + + NewEntry->Buffer = Buffer; + NewEntry->BufferSize = Size; + + InsertTailList (&mPacketList, &NewEntry->Link); + + if (mReceiveEvent) { + gBS->SignalEvent (mReceiveEvent); + } +} + +STATIC +VOID +DataSent ( + IN UINT8 EndpointIndex + ) +{ + // Don't care. +} + +/* + Set up the transport system for use by Fastboot. + e.g. For USB this probably means making the device enumerable. +*/ +EFI_STATUS +FastbootTransportUsbStart ( + EFI_EVENT ReceiveEvent + ) +{ + GET_CONFIG_DESCRIPTOR_RESPONSE *Responses; + + mReceiveEvent = ReceiveEvent; + + mGetConfigDescriptorResponse.ConfigDescriptor.TotalLength = sizeof (GET_CONFIG_DESCRIPTOR_RESPONSE); + Responses = &mGetConfigDescriptorResponse; + + InitializeListHead (&mPacketList); + + return mUsbDevice->Start (&mDeviceDescriptor, (VOID **) &Responses, DataReceived, DataSent); +} + +/* + Function to be called when all Fastboot transactions are finished, to + de-initialise the transport system. + e.g. A USB OTG system might want to get out of peripheral mode so it can be + a USB host. +*/ +EFI_STATUS +FastbootTransportUsbStop ( + VOID + ) +{ + // not yet implemented in USB + return EFI_SUCCESS; +} + +/* + Send data. This function can be used both for command responses like "OKAY" + and for the data phase (the protocol doesn't describe any situation when the + latter might be necessary, but does allow it) + */ +EFI_STATUS +FastbootTransportUsbSend ( + IN UINTN BufferSize, + IN CONST VOID *Buffer, + IN EFI_EVENT *FatalErrorEvent + ) +{ + // Current USB protocol is blocking, so ignore FatalErrorEvent + return mUsbDevice->Send(1, BufferSize, Buffer); +} + +/* + When the event has been Signalled to say data is available from the host, + this function is used to get data. In order to handle the case where several + packets are received before ReceiveEvent's notify function is called, packets + received are queued, and each call to this function returns the next packet in + the queue. It should therefore be called in a loop, the exit condition being a + return of EFI_NOT_READY. + + Parameters: + Buffer - The buffer in which to place data + BufferSize - The size of Buffer in bytes + + Return EFI_NOT_READY if there is no data available +*/ +EFI_STATUS +FastbootTransportUsbReceive ( + OUT UINTN *BufferSize, + OUT VOID **Buffer + ) +{ + FASTBOOT_USB_PACKET_LIST *Entry; + + if (IsListEmpty (&mPacketList)) { + return EFI_NOT_READY; + } + + Entry = (FASTBOOT_USB_PACKET_LIST *) GetFirstNode (&mPacketList); + + *BufferSize = Entry->BufferSize; + *Buffer = Entry->Buffer; + + RemoveEntryList (&Entry->Link); + FreePool (Entry); + + return EFI_SUCCESS; +} + +STATIC FASTBOOT_TRANSPORT_PROTOCOL mTransportProtocol = { + FastbootTransportUsbStart, + FastbootTransportUsbStop, + FastbootTransportUsbSend, + FastbootTransportUsbReceive +}; + +EFI_STATUS +FastbootTransportUsbEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // Assume there's only one USB peripheral controller. + Status = gBS->LocateProtocol (&gUsbDeviceProtocolGuid, NULL, (VOID **) &mUsbDevice); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gAndroidFastbootTransportProtocolGuid, + EFI_NATIVE_INTERFACE, + &mTransportProtocol + ); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf new file mode 100644 index 00000000..94c804ff --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf @@ -0,0 +1,41 @@ +#/** @file +# +# Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FastbootTransportUsbDxe + FILE_GUID = f6bec3fe-88fb-11e3-ae84-e73b77561c35 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = FastbootTransportUsbEntryPoint + +[Sources.common] + FastbootTransportUsb.c + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Protocols] + gEfiDriverBindingProtocolGuid + gUsbDeviceProtocolGuid + gAndroidFastbootTransportProtocolGuid + gEfiSimpleTextOutProtocolGuid + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[FixedPcd] + gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbVendorId + gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbProductId diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c new file mode 100644 index 00000000..e92d0fd7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c @@ -0,0 +1,288 @@ +/** @file +* +* Copyright (c) 2017, Linaro, Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ConsolePrefDxe.h" + +#define SPCR_SIG EFI_ACPI_2_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE + +extern UINT8 ConsolePrefHiiBin[]; +extern UINT8 ConsolePrefDxeStrings[]; + +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +STATIC HII_VENDOR_DEVICE_PATH mConsolePrefDxeVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + CONSOLE_PREF_FORMSET_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +STATIC EFI_EVENT mReadyToBootEvent; + +STATIC +EFI_STATUS +InstallHiiPages ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + + DriverHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle, + &gEfiDevicePathProtocolGuid, + &mConsolePrefDxeVendorDevicePath, + NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + HiiHandle = HiiAddPackages (&gConsolePrefFormSetGuid, + DriverHandle, + ConsolePrefDxeStrings, + ConsolePrefHiiBin, + NULL); + + if (HiiHandle == NULL) { + gBS->UninstallMultipleProtocolInterfaces (DriverHandle, + &gEfiDevicePathProtocolGuid, + &mConsolePrefDxeVendorDevicePath, + NULL); + return EFI_OUT_OF_RESOURCES; + } + return EFI_SUCCESS; +} + +STATIC +VOID +RemoveDtStdoutPath ( + VOID +) +{ + VOID *Dtb; + INT32 Node; + INT32 Error; + EFI_STATUS Status; + + Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &Dtb); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: could not retrieve DT blob - %r\n", __FUNCTION__, + Status)); + return; + } + + Node = fdt_path_offset (Dtb, "/chosen"); + if (Node < 0) { + return; + } + + Error = fdt_delprop (Dtb, Node, "stdout-path"); + if (Error) { + DEBUG ((DEBUG_INFO, "%a: Failed to delete 'stdout-path' property: %a\n", + __FUNCTION__, fdt_strerror (Error))); + } +} + +STATIC +VOID +RemoveSpcrTable ( + VOID + ) +{ + EFI_ACPI_SDT_PROTOCOL *Sdt; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + EFI_STATUS Status; + UINTN TableIndex; + EFI_ACPI_SDT_HEADER *TableHeader; + EFI_ACPI_TABLE_VERSION TableVersion; + UINTN TableKey; + + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, + (VOID **)&AcpiTable); + if (EFI_ERROR (Status)) { + return; + } + + Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&Sdt); + if (EFI_ERROR (Status)) { + return; + } + + TableIndex = 0; + TableKey = 0; + TableHeader = NULL; + + do { + Status = Sdt->GetAcpiTable (TableIndex++, &TableHeader, &TableVersion, + &TableKey); + if (EFI_ERROR (Status)) { + break; + } + + if (TableHeader->Signature != SPCR_SIG) { + continue; + } + + Status = AcpiTable->UninstallAcpiTable (AcpiTable, TableKey); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a: failed to uninstall SPCR table - %r\n", + __FUNCTION__, Status)); + } + break; + } while (TRUE); +} + +STATIC +VOID +EFIAPI +OnReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + CONSOLE_PREF_VARSTORE_DATA ConsolePref; + UINTN BufferSize; + EFI_STATUS Status; + VOID *Gop; + + BufferSize = sizeof (ConsolePref); + Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME, + &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: variable '%s' could not be read - bailing!\n", __FUNCTION__, + CONSOLE_PREF_VARIABLE_NAME)); + return; + } + + if (ConsolePref.Console == CONSOLE_PREF_SERIAL) { + DEBUG ((DEBUG_INFO, + "%a: serial console preferred - doing nothing\n", __FUNCTION__)); + return; + } + + // + // Check if any GOP instances exist: if so, disable stdout-path and SPCR + // + Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, &Gop); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, + "%a: no GOP instances found - doing nothing (%r)\n", __FUNCTION__, + Status)); + return; + } + + RemoveDtStdoutPath (); + RemoveSpcrTable (); +} + +/** + The entry point for ConsolePrefDxe driver. + + @param[in] ImageHandle The image handle of the driver. + @param[in] SystemTable The system table. + + @retval EFI_ALREADY_STARTED The driver already exists in system. + @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of + resources. + @retval EFI_SUCCESS All the related protocols are installed on + the driver. + +**/ +EFI_STATUS +EFIAPI +ConsolePrefDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + CONSOLE_PREF_VARSTORE_DATA ConsolePref; + UINTN BufferSize; + + // + // Get the current console preference from the ConsolePref variable. + // + BufferSize = sizeof (ConsolePref); + Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME, + &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, + "%a: no console preference found, defaulting to graphical\n", + __FUNCTION__)); + ConsolePref.Console = CONSOLE_PREF_GRAPHICAL; + } + + if (!EFI_ERROR (Status) && + ConsolePref.Console != CONSOLE_PREF_GRAPHICAL && + ConsolePref.Console != CONSOLE_PREF_SERIAL) { + DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to graphical\n", + __FUNCTION__, CONSOLE_PREF_VARIABLE_NAME)); + ConsolePref.Console = CONSOLE_PREF_GRAPHICAL; + Status = EFI_INVALID_PARAMETER; // trigger setvar below + } + + // + // Write the newly selected value back to the variable store. + // + if (EFI_ERROR (Status)) { + ZeroMem (&ConsolePref.Reserved, sizeof (ConsolePref.Reserved)); + Status = gRT->SetVariable (CONSOLE_PREF_VARIABLE_NAME, + &gConsolePrefFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (ConsolePref), &ConsolePref); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: gRT->SetVariable () failed - %r\n", + __FUNCTION__, Status)); + return Status; + } + } + + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK, + OnReadyToBoot, NULL, &gEfiEventReadyToBootGuid, + &mReadyToBootEvent); + ASSERT_EFI_ERROR (Status); + + return InstallHiiPages (); +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h new file mode 100644 index 00000000..8d87ca90 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h @@ -0,0 +1,25 @@ +/** @file +* +* Copyright (c) 2017, Linaro Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __CONSOLE_PREF_DXE_H__ +#define __CONSOLE_PREF_DXE_H__ + +#include +#include + +#define CONSOLE_PREF_GRAPHICAL 0x0 +#define CONSOLE_PREF_SERIAL 0x1 + +#define CONSOLE_PREF_VARIABLE_NAME L"ConsolePref" + +typedef struct { + UINT8 Console; + UINT8 Reserved[3]; +} CONSOLE_PREF_VARSTORE_DATA; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf new file mode 100644 index 00000000..aa58142a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf @@ -0,0 +1,55 @@ +## @file +# +# Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = ConsolePrefDxe + FILE_GUID = bbe2668c-0efc-46fb-9137-4f2da8f419f3 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = ConsolePrefDxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 +# + +[Sources] + ConsolePrefDxe.c + ConsolePrefHii.vfr + ConsolePrefHii.uni + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + FdtLib + HiiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + UefiRuntimeServicesTableLib + +[Guids] + gConsolePrefFormSetGuid + gFdtTableGuid + gEfiEventReadyToBootGuid + +[Protocols] + gEfiAcpiTableProtocolGuid + gEfiAcpiSdtProtocolGuid + gEfiGraphicsOutputProtocolGuid + +[Depex] + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni new file mode 100644 index 00000000..d1c532b1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni @@ -0,0 +1,21 @@ +/** @file +* +* Copyright (c) 2017, Linaro, Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#langdef en-US "English" + +#string STR_FORM_SET_TITLE #language en-US "Console Preference Selection" +#string STR_FORM_SET_TITLE_HELP #language en-US "Press to choose between graphical and serial console." + +#string STR_MAIN_FORM_TITLE #language en-US "Console Preference Selection" +#string STR_NULL_STRING #language en-US "" + +#string STR_CONSOLE_PREF_SELECT_PROMPT #language en-US "Preferred console" +#string STR_CONSOLE_PREF_SELECT_HELP #language en-US "Select the preferred console if both graphical and serial are available." + +#string STR_CONSOLE_PREF_GRAPHICAL #language en-US "Graphical" +#string STR_CONSOLE_PREF_SERIAL #language en-US "Serial" diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr new file mode 100644 index 00000000..719f99e3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr @@ -0,0 +1,38 @@ +/** @file +* +* Copyright (c) 2017, Linaro, Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include "ConsolePrefDxe.h" + +formset + guid = CONSOLE_PREF_FORMSET_GUID, + title = STRING_TOKEN(STR_FORM_SET_TITLE), + help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP), + classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID, + + efivarstore CONSOLE_PREF_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, // EFI variable attributes + name = ConsolePref, + guid = CONSOLE_PREF_FORMSET_GUID; + + form formid = 0x1000, + title = STRING_TOKEN(STR_MAIN_FORM_TITLE); + + oneof varid = ConsolePref.Console, + prompt = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_PROMPT), + help = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_HELP), + flags = NUMERIC_SIZE_1 | INTERACTIVE, + option text = STRING_TOKEN(STR_CONSOLE_PREF_GRAPHICAL), value = CONSOLE_PREF_GRAPHICAL, flags = DEFAULT; + option text = STRING_TOKEN(STR_CONSOLE_PREF_SERIAL), value = CONSOLE_PREF_SERIAL, flags = 0; + endoneof; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + + endform; + +endformset; diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.c new file mode 100644 index 00000000..ef092a60 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.c @@ -0,0 +1,208 @@ +/** @file +* +* Copyright (c) 2017, Linaro, Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DtPlatformDxe.h" + +extern UINT8 DtPlatformHiiBin[]; +extern UINT8 DtPlatformDxeStrings[]; + +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +STATIC HII_VENDOR_DEVICE_PATH mDtPlatformDxeVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + DT_PLATFORM_FORMSET_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +STATIC +EFI_STATUS +InstallHiiPages ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + + DriverHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle, + &gEfiDevicePathProtocolGuid, + &mDtPlatformDxeVendorDevicePath, + NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + HiiHandle = HiiAddPackages (&gDtPlatformFormSetGuid, + DriverHandle, + DtPlatformDxeStrings, + DtPlatformHiiBin, + NULL); + + if (HiiHandle == NULL) { + gBS->UninstallMultipleProtocolInterfaces (DriverHandle, + &gEfiDevicePathProtocolGuid, + &mDtPlatformDxeVendorDevicePath, + NULL); + return EFI_OUT_OF_RESOURCES; + } + return EFI_SUCCESS; +} + +/** + The entry point for DtPlatformDxe driver. + + @param[in] ImageHandle The image handle of the driver. + @param[in] SystemTable The system table. + + @retval EFI_ALREADY_STARTED The driver already exists in system. + @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of + resources. + @retval EFI_SUCCESS All the related protocols are installed on + the driver. + +**/ +EFI_STATUS +EFIAPI +DtPlatformDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + DT_ACPI_VARSTORE_DATA DtAcpiPref; + UINTN BufferSize; + VOID *Dtb; + UINTN DtbSize; + + Dtb = NULL; + Status = DtPlatformLoadDtb (&Dtb, &DtbSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, + "%a: no DTB blob could be loaded, defaulting to ACPI (Status == %r)\n", + __FUNCTION__, Status)); + DtAcpiPref.Pref = DT_ACPI_SELECT_ACPI; + } else { + // + // Get the current DT/ACPI preference from the DtAcpiPref variable. + // + BufferSize = sizeof (DtAcpiPref); + Status = gRT->GetVariable(DT_ACPI_VARIABLE_NAME, &gDtPlatformFormSetGuid, + NULL, &BufferSize, &DtAcpiPref); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a: no DT/ACPI preference found, defaulting to %a\n", + __FUNCTION__, PcdGetBool (PcdDefaultDtPref) ? "DT" : "ACPI")); + DtAcpiPref.Pref = PcdGetBool (PcdDefaultDtPref) ? DT_ACPI_SELECT_DT + : DT_ACPI_SELECT_ACPI; + } + } + + if (!EFI_ERROR (Status) && + DtAcpiPref.Pref != DT_ACPI_SELECT_ACPI && + DtAcpiPref.Pref != DT_ACPI_SELECT_DT) { + DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to %a\n", + __FUNCTION__, DT_ACPI_VARIABLE_NAME, + PcdGetBool (PcdDefaultDtPref) ? "DT" : "ACPI")); + DtAcpiPref.Pref = PcdGetBool (PcdDefaultDtPref) ? DT_ACPI_SELECT_DT + : DT_ACPI_SELECT_ACPI; + Status = EFI_INVALID_PARAMETER; // trigger setvar below + } + + // + // Write the newly selected default value back to the variable store. + // + if (EFI_ERROR (Status)) { + Status = gRT->SetVariable(DT_ACPI_VARIABLE_NAME, &gDtPlatformFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (DtAcpiPref), &DtAcpiPref); + if (EFI_ERROR (Status)) { + goto FreeDtb; + } + } + + if (DtAcpiPref.Pref == DT_ACPI_SELECT_ACPI) { + // + // ACPI was selected: install the gEdkiiPlatformHasAcpiGuid GUID as a + // NULL protocol to unlock dispatch of ACPI related drivers. + // + Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle, + &gEdkiiPlatformHasAcpiGuid, NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: failed to install gEdkiiPlatformHasAcpiGuid as a protocol\n", + __FUNCTION__)); + goto FreeDtb; + } + } else if (DtAcpiPref.Pref == DT_ACPI_SELECT_DT) { + // + // DT was selected: copy the blob into newly allocated memory and install + // a reference to it as the FDT configuration table. + // + Status = gBS->InstallConfigurationTable (&gFdtTableGuid, Dtb); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: failed to install FDT configuration table\n", + __FUNCTION__)); + goto FreeDtb; + } + } else { + ASSERT (FALSE); + } + + // + // No point in installing the HII pages if ACPI is the only description + // we have + // + if (Dtb == NULL) { + return EFI_SUCCESS; + } + + // + // Note that we don't uninstall the gEdkiiPlatformHasAcpiGuid protocol nor + // the FDT configuration table if the following call fails. While that will + // cause loading of this driver to fail, proceeding with ACPI and DT both + // disabled will guarantee a failed boot, and so it is better to leave them + // installed in that case. + // + return InstallHiiPages (); + +FreeDtb: + if (Dtb != NULL) { + FreePool (Dtb); + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.h new file mode 100644 index 00000000..6a9d3962 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.h @@ -0,0 +1,25 @@ +/** @file +* +* Copyright (c) 2017, Linaro Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __DT_PLATFORM_DXE_H__ +#define __DT_PLATFORM_DXE_H__ + +#include +#include + +#define DT_ACPI_SELECT_DT 0x0 +#define DT_ACPI_SELECT_ACPI 0x1 + +#define DT_ACPI_VARIABLE_NAME L"DtAcpiPref" + +typedef struct { + UINT8 Pref; + UINT8 Reserved[3]; +} DT_ACPI_VARSTORE_DATA; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf new file mode 100644 index 00000000..7beccd34 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf @@ -0,0 +1,54 @@ +## @file +# +# Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = DtPlatformDxe + FILE_GUID = FC097B3C-2EBD-4A75-A3DA-121DCAB365CC + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DtPlatformDxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 +# + +[Sources] + DtPlatformDxe.c + DtPlatformHii.vfr + DtPlatformHii.uni + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + DtPlatformDtbLoaderLib + HiiLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + +[Guids] + gDtPlatformFormSetGuid + gDtPlatformDefaultDtbFileGuid + gEdkiiPlatformHasAcpiGuid + gFdtTableGuid + +[Pcd] + gEmbeddedTokenSpaceGuid.PcdDefaultDtPref + +[Depex] + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.uni b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.uni new file mode 100644 index 00000000..5f24061a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.uni @@ -0,0 +1,21 @@ +/** @file +* +* Copyright (c) 2017, Linaro, Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#langdef en-US "English" + +#string STR_FORM_SET_TITLE #language en-US "O/S Hardware Description Selection" +#string STR_FORM_SET_TITLE_HELP #language en-US "Press to choose between ACPI and DT hardware descriptions." + +#string STR_MAIN_FORM_TITLE #language en-US "O/S Hardware Description Selection" +#string STR_NULL_STRING #language en-US "" + +#string STR_DT_ACPI_SELECT_PROMPT #language en-US "O/S Hardware Description" +#string STR_DT_ACPI_SELECT_HELP #language en-US "Select the hardware description that will be exposed to the O/S." + +#string STR_DT_ACPI_SELECT_DT #language en-US "Device Tree" +#string STR_DT_ACPI_SELECT_ACPI #language en-US "ACPI" diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.vfr b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.vfr new file mode 100644 index 00000000..99d03bad --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.vfr @@ -0,0 +1,38 @@ +/** @file +* +* Copyright (c) 2017, Linaro, Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include "DtPlatformDxe.h" + +formset + guid = DT_PLATFORM_FORMSET_GUID, + title = STRING_TOKEN(STR_FORM_SET_TITLE), + help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP), + classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID, + + efivarstore DT_ACPI_VARSTORE_DATA, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, // EFI variable attributes + name = DtAcpiPref, + guid = DT_PLATFORM_FORMSET_GUID; + + form formid = 0x1000, + title = STRING_TOKEN(STR_MAIN_FORM_TITLE); + + oneof varid = DtAcpiPref.Pref, + prompt = STRING_TOKEN(STR_DT_ACPI_SELECT_PROMPT), + help = STRING_TOKEN(STR_DT_ACPI_SELECT_HELP), + flags = NUMERIC_SIZE_1 | INTERACTIVE | RESET_REQUIRED, + option text = STRING_TOKEN(STR_DT_ACPI_SELECT_DT), value = DT_ACPI_SELECT_DT, flags = DEFAULT; + option text = STRING_TOKEN(STR_DT_ACPI_SELECT_ACPI), value = DT_ACPI_SELECT_ACPI, flags = 0; + endoneof; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + + endform; + +endformset; diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.c new file mode 100644 index 00000000..48605463 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.c @@ -0,0 +1,250 @@ +/** @file + + Copyright (c) 2019, Linaro, Ltd. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +/** + Set IOMMU attribute for a system memory. + + If the IOMMU protocol exists, the system memory cannot be used + for DMA by default. + + When a device requests a DMA access for a system memory, + the device driver need use SetAttribute() to update the IOMMU + attribute to request DMA access (read and/or write). + + The DeviceHandle is used to identify which device submits the request. + The IOMMU implementation need translate the device path to an IOMMU device + ID, and set IOMMU hardware register accordingly. + 1) DeviceHandle can be a standard PCI device. + The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ. + The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE. + The memory for BusMasterCommonBuffer need set + EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE. + After the memory is used, the memory need set 0 to keep it being + protected. + 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc). + The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or + EDKII_IOMMU_ACCESS_WRITE. + + @param[in] This The protocol instance pointer. + @param[in] DeviceHandle The device who initiates the DMA access + request. + @param[in] Mapping The mapping value returned from Map(). + @param[in] IoMmuAccess The IOMMU access. + + @retval EFI_SUCCESS The IoMmuAccess is set for the memory range + specified by DeviceAddress and Length. + @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by + Map(). + @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination + of access. + @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU. + @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported + by the IOMMU. + @retval EFI_UNSUPPORTED The IOMMU does not support the memory range + specified by Mapping. + @retval EFI_OUT_OF_RESOURCES There are not enough resources available to + modify the IOMMU access. + @retval EFI_DEVICE_ERROR The IOMMU device reported an error while + attempting the operation. + +**/ +STATIC +EFI_STATUS +EFIAPI +NonCoherentIoMmuSetAttribute ( + IN EDKII_IOMMU_PROTOCOL *This, + IN EFI_HANDLE DeviceHandle, + IN VOID *Mapping, + IN UINT64 IoMmuAccess + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Provides the controller-specific addresses required to access system memory + from a DMA bus master. On SEV guest, the DMA operations must be performed on + shared buffer hence we allocate a bounce buffer to map the HostAddress to a + DeviceAddress. The Encryption attribute is removed from the DeviceAddress + buffer. + + @param This The protocol instance pointer. + @param Operation Indicates if the bus master is going to read or + write to system memory. + @param HostAddress The system memory address to map to the PCI + controller. + @param NumberOfBytes On input the number of bytes to map. On output + the number of bytes that were mapped. + @param DeviceAddress The resulting map address for the bus master + PCI controller to use to access the hosts + HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned + NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common + buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a + lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested + address. + +**/ +STATIC +EFI_STATUS +EFIAPI +NonCoherentIoMmuMap ( + IN EDKII_IOMMU_PROTOCOL *This, + IN EDKII_IOMMU_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + DMA_MAP_OPERATION DmaOperation; + + switch (Operation) { + case EdkiiIoMmuOperationBusMasterRead: + case EdkiiIoMmuOperationBusMasterRead64: + DmaOperation = MapOperationBusMasterRead; + break; + + case EdkiiIoMmuOperationBusMasterWrite: + case EdkiiIoMmuOperationBusMasterWrite64: + DmaOperation = MapOperationBusMasterWrite; + break; + + case EdkiiIoMmuOperationBusMasterCommonBuffer: + case EdkiiIoMmuOperationBusMasterCommonBuffer64: + DmaOperation = MapOperationBusMasterCommonBuffer; + break; + + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + return DmaMap (DmaOperation, HostAddress, NumberOfBytes, + DeviceAddress, Mapping); +} + +/** + Completes the Map() operation and releases any corresponding resources. + + @param This The protocol instance pointer. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by + Map(). + @retval EFI_DEVICE_ERROR The data was not committed to the target system + memory. +**/ +STATIC +EFI_STATUS +EFIAPI +NonCoherentIoMmuUnmap ( + IN EDKII_IOMMU_PROTOCOL *This, + IN VOID *Mapping + ) +{ + return DmaUnmap (Mapping); +} + +/** + Allocates pages that are suitable for an OperationBusMasterCommonBuffer or + OperationBusMasterCommonBuffer64 mapping. + + @param This The protocol instance pointer. + @param Type This parameter is not used and must be ignored. + @param MemoryType The type of memory to allocate, + EfiBootServicesData or EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory + address of the allocated range. + @param Attributes The requested bit mask of attributes for the + allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal + attribute bits are MEMORY_WRITE_COMBINE and + MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +STATIC +EFI_STATUS +EFIAPI +NonCoherentIoMmuAllocateBuffer ( + IN EDKII_IOMMU_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT VOID **HostAddress, + IN UINT64 Attributes + ) +{ + return DmaAllocateBuffer (MemoryType, Pages, HostAddress); +} + +/** + Frees memory that was allocated with AllocateBuffer(). + + @param This The protocol instance pointer. + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated + range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and + Pages was not allocated with AllocateBuffer(). + +**/ +STATIC +EFI_STATUS +EFIAPI +NonCoherentIoMmuFreeBuffer ( + IN EDKII_IOMMU_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ) +{ + return DmaFreeBuffer (Pages, HostAddress); +} + +STATIC EDKII_IOMMU_PROTOCOL mNonCoherentIoMmuOps = { + EDKII_IOMMU_PROTOCOL_REVISION, + NonCoherentIoMmuSetAttribute, + NonCoherentIoMmuMap, + NonCoherentIoMmuUnmap, + NonCoherentIoMmuAllocateBuffer, + NonCoherentIoMmuFreeBuffer, +}; + + +EFI_STATUS +EFIAPI +NonCoherentIoMmuDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return gBS->InstallMultipleProtocolInterfaces (&ImageHandle, + &gEdkiiIoMmuProtocolGuid, &mNonCoherentIoMmuOps, + NULL); +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf new file mode 100644 index 00000000..12ab8a80 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf @@ -0,0 +1,35 @@ +#/** @file +# +# Copyright (c) 2019, Linaro, Ltd. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 1.27 + BASE_NAME = NonCoherentIoMmuDxe + FILE_GUID = 7ed510aa-9cdc-49d2-a306-6e11e359f9b3 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = NonCoherentIoMmuDxeEntryPoint + +[Sources] + NonCoherentIoMmuDxe.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + DmaLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Protocols] + gEdkiiIoMmuProtocolGuid ## PRODUCES + +[Depex] + TRUE diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.c new file mode 100644 index 00000000..d12f1c63 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.c @@ -0,0 +1,181 @@ +/** @file + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+Copyright (c) 2018, Linaro Ltd. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "VirtualKeyboard.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gVirtualKeyboardComponentName = { + VirtualKeyboardComponentNameGetDriverName, + VirtualKeyboardComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gVirtualKeyboardComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) VirtualKeyboardComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) VirtualKeyboardComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mVirtualKeyboardDriverNameTable[] = { + { + "eng;en", + L"Virtual Keyboard Driver" + }, + { + "zh-CHS", + L"虚拟键盘驱动程序" + }, + { + NULL, + NULL + } +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mVirtualKeyboardDriverNameTable, + DriverName, + (BOOLEAN)(This == &gVirtualKeyboardComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.h new file mode 100644 index 00000000..45c20332 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.h @@ -0,0 +1,147 @@ +/** @file + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+Copyright (c) 2018, Linaro Ltd. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _VIRTUAL_KEYBOARD_COMPONENT_NAME_H_ +#define _VIRTUAL_KEYBOARD_COMPONENT_NAME_H_ + + +extern EFI_COMPONENT_NAME_PROTOCOL gVirtualKeyboardComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gVirtualKeyboardComponentName2; + +// +// EFI Component Name Functions +// +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.c new file mode 100644 index 00000000..c0193aed --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.c @@ -0,0 +1,1143 @@ +/** @file + VirtualKeyboard driver + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) 2018, Linaro Ltd. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "VirtualKeyboard.h" + +// +// RAM Keyboard Driver Binding Protocol Instance +// +EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding = { + VirtualKeyboardDriverBindingSupported, + VirtualKeyboardDriverBindingStart, + VirtualKeyboardDriverBindingStop, + 0x10, + NULL, + NULL +}; + +// +// EFI Driver Binding Protocol Functions +// + +/** + Check whether the driver supports this device. + + @param This The Udriver binding protocol. + @param Controller The controller handle to check. + @param RemainingDevicePath The remaining device path. + + @retval EFI_SUCCESS The driver supports this controller. + @retval other This device isn't supported. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + PLATFORM_VIRTUAL_KBD_PROTOCOL *PlatformVirtual; + + Status = gBS->OpenProtocol ( + Controller, + &gPlatformVirtualKeyboardProtocolGuid, + (VOID **) &PlatformVirtual, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + gBS->CloseProtocol ( + Controller, + &gPlatformVirtualKeyboardProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; +} + +/** + Starts the device with this driver. + + @param This The driver binding instance. + @param Controller Handle of device to bind driver to. + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS The controller is controlled by the driver. + @retval Other This controller cannot be started. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; + PLATFORM_VIRTUAL_KBD_PROTOCOL *PlatformVirtual; + + Status = gBS->OpenProtocol ( + Controller, + &gPlatformVirtualKeyboardProtocolGuid, + (VOID **) &PlatformVirtual, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Allocate the private device structure + // + VirtualKeyboardPrivate = (VIRTUAL_KEYBOARD_DEV *) AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_DEV)); + if (VirtualKeyboardPrivate == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Initialize the private device structure + // + VirtualKeyboardPrivate->Signature = VIRTUAL_KEYBOARD_DEV_SIGNATURE; + VirtualKeyboardPrivate->Handle = Controller; + VirtualKeyboardPrivate->PlatformVirtual = PlatformVirtual; + VirtualKeyboardPrivate->Queue.Front = 0; + VirtualKeyboardPrivate->Queue.Rear = 0; + VirtualKeyboardPrivate->QueueForNotify.Front = 0; + VirtualKeyboardPrivate->QueueForNotify.Rear = 0; + + VirtualKeyboardPrivate->SimpleTextIn.Reset = VirtualKeyboardReset; + VirtualKeyboardPrivate->SimpleTextIn.ReadKeyStroke = VirtualKeyboardReadKeyStroke; + + VirtualKeyboardPrivate->SimpleTextInputEx.Reset = VirtualKeyboardResetEx; + VirtualKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx = VirtualKeyboardReadKeyStrokeEx; + VirtualKeyboardPrivate->SimpleTextInputEx.SetState = VirtualKeyboardSetState; + + VirtualKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify = VirtualKeyboardRegisterKeyNotify; + VirtualKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = VirtualKeyboardUnregisterKeyNotify; + InitializeListHead (&VirtualKeyboardPrivate->NotifyList); + + Status = PlatformVirtual->Register (); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Report that the keyboard is being enabled + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE + ); + + // + // Setup the WaitForKey event + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + VirtualKeyboardWaitForKey, + &(VirtualKeyboardPrivate->SimpleTextIn), + &((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey) + ); + if (EFI_ERROR (Status)) { + (VirtualKeyboardPrivate->SimpleTextIn).WaitForKey = NULL; + goto Done; + } + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + VirtualKeyboardWaitForKeyEx, + &(VirtualKeyboardPrivate->SimpleTextInputEx), + &(VirtualKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx) + ); + if (EFI_ERROR (Status)) { + VirtualKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL; + goto Done; + } + + // + // Setup a periodic timer, used for reading keystrokes at a fixed interval + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + VirtualKeyboardTimerHandler, + VirtualKeyboardPrivate, + &VirtualKeyboardPrivate->TimerEvent + ); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = gBS->SetTimer ( + VirtualKeyboardPrivate->TimerEvent, + TimerPeriodic, + KEYBOARD_TIMER_INTERVAL + ); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + KeyNotifyProcessHandler, + VirtualKeyboardPrivate, + &VirtualKeyboardPrivate->KeyNotifyProcessEvent + ); + if (EFI_ERROR (Status)) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Reset the keyboard device + // + Status = VirtualKeyboardPrivate->SimpleTextInputEx.Reset ( + &VirtualKeyboardPrivate->SimpleTextInputEx, + FALSE + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[KBD]Reset Failed. Status - %r\n", Status)); + goto Done; + } + // + // Install protocol interfaces for the keyboard device. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiSimpleTextInProtocolGuid, + &VirtualKeyboardPrivate->SimpleTextIn, + &gEfiSimpleTextInputExProtocolGuid, + &VirtualKeyboardPrivate->SimpleTextInputEx, + NULL + ); + +Done: + if (EFI_ERROR (Status)) { + if (VirtualKeyboardPrivate != NULL) { + if ((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) { + gBS->CloseEvent ((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey); + } + + if ((VirtualKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) { + gBS->CloseEvent ( + (VirtualKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx + ); + } + + if (VirtualKeyboardPrivate->KeyNotifyProcessEvent != NULL) { + gBS->CloseEvent (VirtualKeyboardPrivate->KeyNotifyProcessEvent); + } + + VirtualKeyboardFreeNotifyList (&VirtualKeyboardPrivate->NotifyList); + + if (VirtualKeyboardPrivate->TimerEvent != NULL) { + gBS->CloseEvent (VirtualKeyboardPrivate->TimerEvent); + } + FreePool (VirtualKeyboardPrivate); + } + } + + gBS->CloseProtocol ( + Controller, + &gPlatformVirtualKeyboardProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +/** + Stop the device handled by this driver. + + @param This The driver binding protocol. + @param Controller The controller to release. + @param NumberOfChildren The number of handles in ChildHandleBuffer. + @param ChildHandleBuffer The array of child handle. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a + device error. + @retval Others Fail to uninstall protocols attached on the + device. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + return EFI_SUCCESS; +} + + +/** + Enqueue the key. + + @param Queue The queue to be enqueued. + @param KeyData The key data to be enqueued. + + @retval EFI_NOT_READY The queue is full. + @retval EFI_SUCCESS Successfully enqueued the key data. + +**/ +EFI_STATUS +Enqueue ( + IN SIMPLE_QUEUE *Queue, + IN EFI_KEY_DATA *KeyData + ) +{ + if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) { + return EFI_NOT_READY; + } + + CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA)); + Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT; + + return EFI_SUCCESS; +} + +/** + Dequeue the key. + + @param Queue The queue to be dequeued. + @param KeyData The key data to be dequeued. + + @retval EFI_NOT_READY The queue is empty. + @retval EFI_SUCCESS Successfully dequeued the key data. + +**/ +EFI_STATUS +Dequeue ( + IN SIMPLE_QUEUE *Queue, + IN EFI_KEY_DATA *KeyData + ) +{ + if (Queue->Front == Queue->Rear) { + return EFI_NOT_READY; + } + + CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA)); + Queue->Front = (Queue->Front + 1) % QUEUE_MAX_COUNT; + + return EFI_SUCCESS; +} + +/** + Check whether the queue is empty. + + @param Queue The queue to be checked. + + @retval EFI_NOT_READY The queue is empty. + @retval EFI_SUCCESS The queue is not empty. + +**/ +EFI_STATUS +CheckQueue ( + IN SIMPLE_QUEUE *Queue + ) +{ + if (Queue->Front == Queue->Rear) { + return EFI_NOT_READY; + } + + return EFI_SUCCESS; +} + +/** + Check key buffer to get the key stroke status. + + @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL. + + @retval EFI_SUCCESS A key is being pressed now. + @retval Other No key is now pressed. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardCheckForKey ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This + ) +{ + VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; + + VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); + + return CheckQueue (&VirtualKeyboardPrivate->Queue); +} + +/** + Free keyboard notify list. + + @param ListHead The list head + + @retval EFI_SUCCESS Free the notify list successfully + @retval EFI_INVALID_PARAMETER ListHead is invalid. + +**/ +EFI_STATUS +VirtualKeyboardFreeNotifyList ( + IN OUT LIST_ENTRY *ListHead + ) +{ + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode; + + if (ListHead == NULL) { + return EFI_INVALID_PARAMETER; + } + while (!IsListEmpty (ListHead)) { + NotifyNode = CR ( + ListHead->ForwardLink, + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + RemoveEntryList (ListHead->ForwardLink); + gBS->FreePool (NotifyNode); + } + + return EFI_SUCCESS; +} + +/** + Judge whether is a registed key + + @param RegsiteredData A pointer to a buffer that is filled in with + the keystroke state data for the key that was + registered. + @param InputData A pointer to a buffer that is filled in with + the keystroke state data for the key that was + pressed. + + @retval TRUE Key be pressed matches a registered key. + @retval FALSE Match failed. + +**/ +BOOLEAN +IsKeyRegistered ( + IN EFI_KEY_DATA *RegsiteredData, + IN EFI_KEY_DATA *InputData + ) + +{ + ASSERT (RegsiteredData != NULL && InputData != NULL); + + if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) || + (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) { + return FALSE; + } + + // + // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means + // these state could be ignored. + // + if ((RegsiteredData->KeyState.KeyShiftState != 0) && + (RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState)) { + return FALSE; + } + if ((RegsiteredData->KeyState.KeyToggleState != 0) && + (RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState)) { + return FALSE; + } + + return TRUE; + +} + +/** + Event notification function for SIMPLE_TEXT_IN.WaitForKey event + Signal the event if there is key available + + @param Event the event object + @param Context waiting context + +**/ +VOID +EFIAPI +VirtualKeyboardWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Stall 1ms to give a chance to let other driver interrupt this routine + // for their timer event. + // e.g. UI setup or Shell, other drivers which are driven by timer event + // will have a bad performance during this period, + // e.g. usb keyboard driver. + // Add a stall period can greatly increate other driver performance during + // the WaitForKey is recursivly invoked. 1ms delay will make little impact + // to the thunk keyboard driver, and user can not feel the delay at all when + // input. + // + gBS->Stall (1000); + // + // Use TimerEvent callback function to check whether there's any key pressed + // + VirtualKeyboardTimerHandler (NULL, VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context)); + + if (!EFI_ERROR (VirtualKeyboardCheckForKey (Context))) { + gBS->SignalEvent (Event); + } +} + +/** + Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx + event. Signal the event if there is key available + + @param Event event object + @param Context waiting context + +**/ +VOID +EFIAPI +VirtualKeyboardWaitForKeyEx ( + IN EFI_EVENT Event, + IN VOID *Context + ) + +{ + VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; + + VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context); + VirtualKeyboardWaitForKey (Event, &VirtualKeyboardPrivate->SimpleTextIn); + +} + +// +// EFI Simple Text In Protocol Functions +// +/** + Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) + then do some extra keyboard validations. + + @param This Pointer of simple text Protocol. + @param ExtendedVerification Whether perform the extra validation of + keyboard. True: perform; FALSE: skip. + + @retval EFI_SUCCESS The command byte is written successfully. + @retval EFI_DEVICE_ERROR Errors occurred during resetting keyboard. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardReset ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; + EFI_STATUS Status; + EFI_TPL OldTpl; + + VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); + + // + // Raise TPL to avoid mouse operation impact + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + if (VirtualKeyboardPrivate->PlatformVirtual && + VirtualKeyboardPrivate->PlatformVirtual->Reset) { + Status = VirtualKeyboardPrivate->PlatformVirtual->Reset (); + } else { + Status = EFI_INVALID_PARAMETER; + } + + // + // resume priority of task level + // + gBS->RestoreTPL (OldTpl); + + return Status; +} + +/** + Reset the input device and optionally run diagnostics + + @param This Protocol instance pointer. + @param ExtendedVerification Driver may perform diagnostics on reset. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning properly and + could not be reset. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardResetEx ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; + EFI_STATUS Status; + EFI_TPL OldTpl; + + VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); + + Status = VirtualKeyboardPrivate->SimpleTextIn.Reset ( + &VirtualKeyboardPrivate->SimpleTextIn, + ExtendedVerification + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; + +} + +/** + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existence of a keystroke via WaitForEvent () call. + + @param VirtualKeyboardPrivate Virtualkeyboard driver private structure. + @param KeyData A pointer to a buffer that is filled in + with the keystroke state data for the key + that was pressed. + + @retval EFI_SUCCESS The keystroke information was returned. + @retval EFI_NOT_READY There was no keystroke data available. + @retval EFI_DEVICE_ERROR The keystroke information was not returned + due to hardware errors. + @retval EFI_INVALID_PARAMETER KeyData is NULL. + +**/ +EFI_STATUS +KeyboardReadKeyStrokeWorker ( + IN VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate, + OUT EFI_KEY_DATA *KeyData + ) +{ + EFI_STATUS Status; + EFI_TPL OldTpl; + if (KeyData == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Use TimerEvent callback function to check whether there's any key pressed + // + + // + // Stall 1ms to give a chance to let other driver interrupt this routine for + // their timer event. + // e.g. OS loader, other drivers which are driven by timer event will have a + // bad performance during this period, + // e.g. usb keyboard driver. + // Add a stall period can greatly increate other driver performance during + // the WaitForKey is recursivly invoked. 1ms delay will make little impact + // to the thunk keyboard driver, and user can not feel the delay at all when + // input. + // + gBS->Stall (1000); + + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + VirtualKeyboardTimerHandler (NULL, VirtualKeyboardPrivate); + // + // If there's no key, just return + // + Status = CheckQueue (&VirtualKeyboardPrivate->Queue); + if (EFI_ERROR (Status)) { + gBS->RestoreTPL (OldTpl); + return EFI_NOT_READY; + } + + Status = Dequeue (&VirtualKeyboardPrivate->Queue, KeyData); + + gBS->RestoreTPL (OldTpl); + + return EFI_SUCCESS; +} + +/** + Read out the scan code of the key that has just been stroked. + + @param This Pointer of simple text Protocol. + @param Key Pointer for store the key that read out. + + @retval EFI_SUCCESS The key is read out successfully. + @retval other The key reading failed. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardReadKeyStroke ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +{ + VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; + EFI_STATUS Status; + EFI_KEY_DATA KeyData; + + VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); + + Status = KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate, &KeyData); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Convert the Ctrl+[a-z] to Ctrl+[1-26] + // + if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) { + if (KeyData.Key.UnicodeChar >= L'a' && + KeyData.Key.UnicodeChar <= L'z') { + KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1); + } else if (KeyData.Key.UnicodeChar >= L'A' && + KeyData.Key.UnicodeChar <= L'Z') { + KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1); + } + } + + CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); + + return EFI_SUCCESS; +} + +/** + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existence of a keystroke via WaitForEvent () call. + + @param This Protocol instance pointer. + @param KeyData A pointer to a buffer that is filled in with the + keystroke state data for the key that was pressed. + + @retval EFI_SUCCESS The keystroke information was returned. + @retval EFI_NOT_READY There was no keystroke data available. + @retval EFI_DEVICE_ERROR The keystroke information was not returned + due to hardware errors. + @retval EFI_INVALID_PARAMETER KeyData is NULL. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardReadKeyStrokeEx ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + OUT EFI_KEY_DATA *KeyData + ) +{ + VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; + + if (KeyData == NULL) { + return EFI_INVALID_PARAMETER; + } + + VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); + + return KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate, KeyData); + +} + +/** + Set certain state for the input device. + + @param This Protocol instance pointer. + @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the + state for the input device. + + @retval EFI_SUCCESS The device state was set successfully. + @retval EFI_DEVICE_ERROR The device is not functioning correctly and + could not have the setting adjusted. + @retval EFI_UNSUPPORTED The device does not have the ability to set + its state. + @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardSetState ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_TOGGLE_STATE *KeyToggleState + ) +{ + if (KeyToggleState == NULL) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + Register a notification function for a particular keystroke for the + input device. + + @param This Protocol instance pointer. + @param KeyData A pointer to a buffer that is filled in with + the keystroke information data for the key + that was pressed. + @param KeyNotificationFunction Points to the function to be called when the + key sequence is typed specified by KeyData. + @param NotifyHandle Points to the unique handle assigned to the + registered notification. + + + @retval EFI_SUCCESS The notification function was registered + successfully. + @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary + data structures. + @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardRegisterKeyNotify ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_DATA *KeyData, + IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, + OUT VOID **NotifyHandle + ) +{ + EFI_STATUS Status; + VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; + EFI_TPL OldTpl; + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify; + LIST_ENTRY *Link; + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + + if (KeyData == NULL || + NotifyHandle == NULL || + KeyNotificationFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + + VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); + + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + // + // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already + // registered. + // + for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink; + Link != &VirtualKeyboardPrivate->NotifyList; + Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { + if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) { + *NotifyHandle = CurrentNotify; + Status = EFI_SUCCESS; + goto Exit; + } + } + } + + // + // Allocate resource to save the notification function + // + + NewNotify = (VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY)); + if (NewNotify == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + NewNotify->Signature = VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE; + NewNotify->KeyNotificationFn = KeyNotificationFunction; + CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA)); + InsertTailList (&VirtualKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry); + + *NotifyHandle = NewNotify; + Status = EFI_SUCCESS; + +Exit: + // + // Leave critical section and return + // + gBS->RestoreTPL (OldTpl); + return Status; + +} + +/** + Remove a registered notification function from a particular keystroke. + + @param This Protocol instance pointer. + @param NotificationHandle The handle of the notification function + being unregistered. + + @retval EFI_SUCCESS The notification function was unregistered + successfully. + @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardUnregisterKeyNotify ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN VOID *NotificationHandle + ) +{ + EFI_STATUS Status; + VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; + EFI_TPL OldTpl; + LIST_ENTRY *Link; + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + + // + // Check incoming notification handle + // + if (NotificationHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (((VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + + VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This); + + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink; + Link != &VirtualKeyboardPrivate->NotifyList; + Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (CurrentNotify == NotificationHandle) { + // + // Remove the notification function from NotifyList and free resources + // + RemoveEntryList (&CurrentNotify->NotifyEntry); + + Status = EFI_SUCCESS; + goto Exit; + } + } + + // + // Can not find the specified Notification Handle + // + Status = EFI_INVALID_PARAMETER; + +Exit: + // + // Leave critical section and return + // + gBS->RestoreTPL (OldTpl); + return Status; +} + +/** + Timer event handler: read a series of scancodes from 8042 + and put them into memory scancode buffer. + it read as much scancodes to either fill + the memory buffer or empty the keyboard buffer. + It is registered as running under TPL_NOTIFY + + @param Event The timer event + @param Context A KEYBOARD_CONSOLE_IN_DEV pointer + +**/ +VOID +EFIAPI +VirtualKeyboardTimerHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_TPL OldTpl; + LIST_ENTRY *Link; + EFI_KEY_DATA KeyData; + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; + VIRTUAL_KBD_KEY VirtualKey; + + VirtualKeyboardPrivate = Context; + + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + if (VirtualKeyboardPrivate->PlatformVirtual && + VirtualKeyboardPrivate->PlatformVirtual->Query) { + if (VirtualKeyboardPrivate->PlatformVirtual->Query (&VirtualKey) == + FALSE) { + goto Exit; + } + // Found key + KeyData.Key.ScanCode = VirtualKey.Key.ScanCode; + KeyData.Key.UnicodeChar = VirtualKey.Key.UnicodeChar; + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; + KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; + if (VirtualKeyboardPrivate->PlatformVirtual->Clear) { + VirtualKeyboardPrivate->PlatformVirtual->Clear (&VirtualKey); + } + } else { + goto Exit; + } + + // + // Signal KeyNotify process event if this key pressed matches any key registered. + // + for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink; + Link != &VirtualKeyboardPrivate->NotifyList; + Link = Link->ForwardLink) { + CurrentNotify = CR ( + Link, + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { + // + // The key notification function needs to run at TPL_CALLBACK + // while current TPL is TPL_NOTIFY. It will be invoked in + // KeyNotifyProcessHandler() which runs at TPL_CALLBACK. + // + Enqueue (&VirtualKeyboardPrivate->QueueForNotify, &KeyData); + gBS->SignalEvent (VirtualKeyboardPrivate->KeyNotifyProcessEvent); + break; + } + } + + Enqueue (&VirtualKeyboardPrivate->Queue, &KeyData); + +Exit: + // + // Leave critical section and return + // + gBS->RestoreTPL (OldTpl); +} + +/** + Process key notify. + + @param Event Indicates the event that invoke this function. + @param Context Indicates the calling context. +**/ +VOID +EFIAPI +KeyNotifyProcessHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate; + EFI_KEY_DATA KeyData; + LIST_ENTRY *Link; + LIST_ENTRY *NotifyList; + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; + EFI_TPL OldTpl; + + VirtualKeyboardPrivate = (VIRTUAL_KEYBOARD_DEV *) Context; + + // + // Invoke notification functions. + // + NotifyList = &VirtualKeyboardPrivate->NotifyList; + while (TRUE) { + // + // Enter critical section + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + Status = Dequeue (&VirtualKeyboardPrivate->QueueForNotify, &KeyData); + // + // Leave critical section + // + gBS->RestoreTPL (OldTpl); + if (EFI_ERROR (Status)) { + break; + } + for (Link = GetFirstNode (NotifyList); + !IsNull (NotifyList, Link); + Link = GetNextNode (NotifyList, Link)) { + CurrentNotify = CR (Link, + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY, + NotifyEntry, + VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE + ); + if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { + CurrentNotify->KeyNotificationFn (&KeyData); + } + } + } +} + +/** + The user Entry Point for module VirtualKeyboard. The user code starts with + this function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeVirtualKeyboard( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gVirtualKeyboardDriverBinding, + ImageHandle, + &gVirtualKeyboardComponentName, + &gVirtualKeyboardComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.h new file mode 100644 index 00000000..75b77c34 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.h @@ -0,0 +1,537 @@ +/** @file + +Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+Copyright (c) 2018, Linaro Ltd. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _VIRTUAL_KEYBOARD_H_ +#define _VIRTUAL_KEYBOARD_H_ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Driver Binding Externs +// +extern EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gVirtualKeyboardComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gVirtualKeyboardComponentName2; + + +// +// VIRTUAL Keyboard Defines +// +#define CHAR_SCANCODE 0xe0 +#define CHAR_ESC 0x1b + +#define KEYBOARD_TIMEOUT 65536 // 0.07s +#define KEYBOARD_WAITFORVALUE_TIMEOUT 1000000 // 1s +#define KEYBOARD_BAT_TIMEOUT 4000000 // 4s +#define KEYBOARD_TIMER_INTERVAL 500000 // 0.5s + +#define QUEUE_MAX_COUNT 32 + +#define KEYBOARD_SCAN_CODE_MAX_COUNT 32 + +// +// VIRTUAL Keyboard Device Structure +// +#define VIRTUAL_KEYBOARD_DEV_SIGNATURE SIGNATURE_32 ('V', 'K', 'B', 'D') +#define VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE SIGNATURE_32 ('v', 'k', 'c', 'n') + +typedef struct _VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY { + UINTN Signature; + EFI_KEY_DATA KeyData; + EFI_KEY_NOTIFY_FUNCTION KeyNotificationFn; + LIST_ENTRY NotifyEntry; +} VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY; + +typedef struct { + UINTN Front; + UINTN Rear; + EFI_KEY_DATA Buffer[QUEUE_MAX_COUNT]; +} SIMPLE_QUEUE; + +typedef struct { + UINT8 Buffer[KEYBOARD_SCAN_CODE_MAX_COUNT]; + UINTN Head; + UINTN Tail; +} SCAN_CODE_QUEUE; + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + PLATFORM_VIRTUAL_KBD_PROTOCOL *PlatformVirtual; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL SimpleTextIn; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL SimpleTextInputEx; + + // + // Buffer storing EFI_KEY_DATA + // + SIMPLE_QUEUE Queue; + SIMPLE_QUEUE QueueForNotify; + + // + // Notification Function List + // + LIST_ENTRY NotifyList; + EFI_EVENT KeyNotifyProcessEvent; + EFI_EVENT TimerEvent; +} VIRTUAL_KEYBOARD_DEV; + +#define VIRTUAL_KEYBOARD_DEV_FROM_THIS(a) CR (a, VIRTUAL_KEYBOARD_DEV, SimpleTextIn, VIRTUAL_KEYBOARD_DEV_SIGNATURE) +#define TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS(a) \ + CR (a, \ + VIRTUAL_KEYBOARD_DEV, \ + SimpleTextInputEx, \ + VIRTUAL_KEYBOARD_DEV_SIGNATURE \ + ) + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding; + +// +// Driver Binding Protocol functions +// + +/** + Check whether the driver supports this device. + + @param This The Udriver binding protocol. + @param Controller The controller handle to check. + @param RemainingDevicePath The remaining device path. + + @retval EFI_SUCCESS The driver supports this controller. + @retval other This device isn't supported. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Starts the device with this driver. + + @param This The driver binding instance. + @param Controller Handle of device to bind driver to. + @param RemainingDevicePath Optional parameter use to pick a specific child + device to start. + + @retval EFI_SUCCESS The controller is controlled by the driver. + @retval Other This controller cannot be started. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Stop the device handled by this driver. + + @param This The driver binding protocol. + @param Controller The controller to release. + @param NumberOfChildren The number of handles in ChildHandleBuffer. + @param ChildHandleBuffer The array of child handle. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + @retval Others Fail to uninstall protocols attached on the device. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + + +// +// Simple Text Input Protocol functions +// +/** + Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations. + + @param This Pointer of simple text Protocol. + @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip. + + @retval EFI_SUCCESS The command byte is written successfully. + @retval EFI_DEVICE_ERROR Errors occurred during resetting keyboard. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardReset ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Reset the input device and optionally run diagnostics + + @param This Protocol instance pointer. + @param ExtendedVerification Driver may perform diagnostics on reset. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The device is not functioning properly and could + not be reset. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardResetEx ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Set certain state for the input device. + + @param This Protocol instance pointer. + @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the + state for the input device. + + @retval EFI_SUCCESS The device state was set successfully. + @retval EFI_DEVICE_ERROR The device is not functioning correctly and could + not have the setting adjusted. + @retval EFI_UNSUPPORTED The device does not have the ability to set its state. + @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardSetState ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_TOGGLE_STATE *KeyToggleState + ); + +/** + Register a notification function for a particular keystroke for the input device. + + @param This Protocol instance pointer. + @param KeyData A pointer to a buffer that is filled in with the keystroke + information data for the key that was pressed. + @param KeyNotificationFunction Points to the function to be called when the key + sequence is typed specified by KeyData. + @param NotifyHandle Points to the unique handle assigned to the registered notification. + + + @retval EFI_SUCCESS The notification function was registered successfully. + @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data structures. + @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardRegisterKeyNotify ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN EFI_KEY_DATA *KeyData, + IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, + OUT VOID **NotifyHandle + ); + +/** + Remove a registered notification function from a particular keystroke. + + @param This Protocol instance pointer. + @param NotificationHandle The handle of the notification function being unregistered. + + @retval EFI_SUCCESS The notification function was unregistered successfully. + @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardUnregisterKeyNotify ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + IN VOID *NotificationHandle + ); + +// +// Private worker functions +// +/** + Free keyboard notify list. + + @param ListHead The list head + + @retval EFI_SUCCESS Free the notify list successfully + @retval EFI_INVALID_PARAMETER ListHead is invalid. + +**/ +EFI_STATUS +VirtualKeyboardFreeNotifyList ( + IN OUT LIST_ENTRY *ListHead + ); + +/** + Check if key is registered. + + @param RegsiteredData A pointer to a buffer that is filled in with the keystroke + state data for the key that was registered. + @param InputData A pointer to a buffer that is filled in with the keystroke + state data for the key that was pressed. + + @retval TRUE Key be pressed matches a registered key. + @retval FALSE Match failed. + +**/ +BOOLEAN +IsKeyRegistered ( + IN EFI_KEY_DATA *RegsiteredData, + IN EFI_KEY_DATA *InputData + ); + +/** + Waiting on the keyboard event, if there's any key pressed by the user, signal the event + + @param Event The event that be signalled when any key has been struck. + @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL. + +**/ +VOID +EFIAPI +VirtualKeyboardWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Waiting on the keyboard event, if there's any key pressed by the user, signal the event + + @param Event The event that be signalled when any key has been struck. + @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. + +**/ +VOID +EFIAPI +VirtualKeyboardWaitForKeyEx ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Timer event handler: read a series of key stroke from 8042 + and put them into memory key buffer. + It is registered as running under TPL_NOTIFY + + @param Event The timer event + @param Context A VIRTUAL_KEYBOARD_DEV pointer + +**/ +VOID +EFIAPI +VirtualKeyboardTimerHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Process key notify. + + @param Event Indicates the event that invoke this function. + @param Context Indicates the calling context. +**/ +VOID +EFIAPI +KeyNotifyProcessHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Read out the scan code of the key that has just been stroked. + + @param This Pointer of simple text Protocol. + @param Key Pointer for store the key that read out. + + @retval EFI_SUCCESS The key is read out successfully. + @retval other The key reading failed. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardReadKeyStroke ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ); + +/** + Reads the next keystroke from the input device. The WaitForKey Event can + be used to test for existence of a keystroke via WaitForEvent () call. + + @param This Protocol instance pointer. + @param KeyData A pointer to a buffer that is filled in with the keystroke + state data for the key that was pressed. + + @retval EFI_SUCCESS The keystroke information was returned. + @retval EFI_NOT_READY There was no keystroke data available. + @retval EFI_DEVICE_ERROR The keystroke information was not returned due to + hardware errors. + @retval EFI_INVALID_PARAMETER KeyData is NULL. + +**/ +EFI_STATUS +EFIAPI +VirtualKeyboardReadKeyStrokeEx ( + IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + OUT EFI_KEY_DATA *KeyData + ); + +#endif /* _VIRTUAL_KEYBOARD_H_ */ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboardDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboardDxe.inf new file mode 100644 index 00000000..e74b3069 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboardDxe.inf @@ -0,0 +1,54 @@ +## @file +# Virtual Keyboard driver. +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2018, Linaro Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = VirtualKeyboardDxe + FILE_GUID = 88079b18-b42b-44aa-a6f2-b83911075e89 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeVirtualKeyboard + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 +# +# DRIVER_BINDING = gVirtualKeyboardDriverBinding +# COMPONENT_NAME = gVirtualKeyboardComponentName +# + +[Sources.common] + ComponentName.c + VirtualKeyboard.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + IoLib + ReportStatusCodeLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gEfiDriverBindingProtocolGuid + gEfiSimpleTextInProtocolGuid + gEfiSimpleTextInputExProtocolGuid + gPlatformVirtualKeyboardProtocolGuid + +[Depex] + TRUE diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.c new file mode 100644 index 00000000..cf87f2df --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.c @@ -0,0 +1,76 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include + +#include + +UINT64 gCurrentMonotonicCount = 0; + +EFI_STATUS +EFIAPI +GetNextMonotonicCount ( + OUT UINT64 *Count + ) +{ + if (Count == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Count = gCurrentMonotonicCount++; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GetNextHighMonotonicCount ( + OUT UINT32 *HighCount + ) +{ + if (HighCount == NULL) { + return EFI_INVALID_PARAMETER; + } + + gCurrentMonotonicCount += 0x0000000100000000ULL; + + *HighCount = (UINT32)RShiftU64 (gCurrentMonotonicCount, 32) & 0xFFFFFFFF; + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +MonotonicCounterDriverInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle = NULL; + + // Make sure the Monotonic Counter Architectural Protocol is not already installed in the system + ASSERT_PROTOCOL_ALREADY_INSTALLED(NULL, &gEfiMonotonicCounterArchProtocolGuid); + + // Fill in the EFI Boot Services and EFI Runtime Services Monotonic Counter Fields + gBS->GetNextMonotonicCount = GetNextMonotonicCount; + gRT->GetNextHighMonotonicCount = GetNextHighMonotonicCount; + + // Install the Monotonic Counter Architectural Protocol onto a new handle + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiMonotonicCounterArchProtocolGuid, NULL, + NULL + ); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf new file mode 100644 index 00000000..0ca9a8cb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf @@ -0,0 +1,35 @@ +#/** @file +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = EmbeddedMonotonicCounter + FILE_GUID = FCABE6A7-7953-4A84-B7EC-D29E89B62E87 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = MonotonicCounterDriverInitialize + +[Sources.common] + EmbeddedMonotonicCounter.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + +[Protocols] + gEfiMonotonicCounterArchProtocolGuid + +[Depex] + TRUE + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedPkg.dec b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedPkg.dec new file mode 100644 index 00000000..2a29f020 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedPkg.dec @@ -0,0 +1,175 @@ +#/** @file +# Framework Module Development Environment Industry Standards +# +# This Package provides headers and libraries that conform to EFI/PI Industry standards. +# Copyright (c) 2007, Intel Corporation. All rights reserved.
+# Copyright (c) 2012-2015, ARM Ltd. All rights reserved.
+# Copyright (c) 2017, Linaro Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = EmbeddedPkg + PACKAGE_GUID = dea8e498-7e1b-47c1-b6fa-4bc04092587e + PACKAGE_VERSION = 0.1 + + +################################################################################ +# +# Include Section - list of Include Paths that are provided by this package. +# Comments are used for Keywords and Module Types. +# +# Supported Module Types: +# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION +# +################################################################################ +[Includes.common] + Include # Root include for the package + +[LibraryClasses.common] + PrePiLib|Include/Library/PrePiLib.h + RealTimeClockLib|Include/Library/RealTimeClockLib.h + EfiResetSystemLib|Include/Library/EfiResetSystemLib.h + GdbSerialLib|Include/Library/GdbSerialLib.h + DebugAgentTimerLib|Include/Library/DebugAgentTimerLib.h + NorFlashInfoLib|Include/Library/NorFlashInfoLib.h + + DtPlatformDtbLoaderLib|Include/Library/DtPlatformDtbLoaderLib.h + +[Guids.common] + gEmbeddedTokenSpaceGuid = { 0xe0d8ca17, 0x4276, 0x4386, { 0xbb, 0x79, 0x48, 0xcb, 0x81, 0x3d, 0x3c, 0x4f }} + + ## FDT Configuration Table + # Include/Guid/Fdt.h + gFdtTableGuid = { 0xb1b621d5, 0xf19c, 0x41a5, { 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } } + # Include/Guid/FdtHob.h + gFdtHobGuid = { 0x16958446, 0x19B7, 0x480B, { 0xB0, 0x47, 0x74, 0x85, 0xAD, 0x3F, 0x71, 0x6D } } + gFdtVariableGuid = { 0x25a4fd4a, 0x9703, 0x4ba9, { 0xa1, 0x90, 0xb7, 0xc8, 0x4e, 0xfb, 0x3e, 0x57 } } + + ## Include/Guid/PlatformHasDeviceTree.h + gEdkiiPlatformHasDeviceTreeGuid = { 0x7ebb920d, 0x1aaf, 0x46d9, { 0xb2, 0xaf, 0x54, 0x1e, 0x1d, 0xce, 0x14, 0x8b } } + + # HII form set GUID for DtPlatformDxe driver + gDtPlatformFormSetGuid = { 0x2b7a240d, 0xd5ad, 0x4fd6, { 0xbe, 0x1c, 0xdf, 0xa4, 0x41, 0x5f, 0x55, 0x26 } } + + # File GUID for default DTB image embedded in the firmware volume + gDtPlatformDefaultDtbFileGuid = { 0x25462cda, 0x221f, 0x47df, { 0xac, 0x1d, 0x25, 0x9c, 0xfa, 0xa4, 0xe3, 0x26 } } + + # HII form set GUID for ConsolePrefDxe driver + gConsolePrefFormSetGuid = { 0x2d2358b4, 0xe96c, 0x484d, { 0xb2, 0xdd, 0x7c, 0x2e, 0xdf, 0xc7, 0xd5, 0x6f } } + + ## Include/Guid/NvVarStoreFormatted.h + gEdkiiNvVarStoreFormattedGuid = { 0xd1a86e3f, 0x0707, 0x4c35, { 0x83, 0xcd, 0xdc, 0x2c, 0x29, 0xc8, 0x91, 0xa3 } } + +[Protocols.common] + gHardwareInterruptProtocolGuid = { 0x2890B3EA, 0x053D, 0x1643, { 0xAD, 0x0C, 0xD6, 0x48, 0x08, 0xDA, 0x3F, 0xF1 } } + gHardwareInterrupt2ProtocolGuid = { 0x32898322, 0x2da1, 0x474a, { 0xba, 0xaa, 0xf3, 0xf7, 0xcf, 0x56, 0x94, 0x70 } } + gEmbeddedDeviceGuid = { 0xbf4b9d10, 0x13ec, 0x43dd, { 0x88, 0x80, 0xe9, 0xb, 0x71, 0x8f, 0x27, 0xde } } + gEmbeddedExternalDeviceProtocolGuid = { 0x735F8C64, 0xD696, 0x44D0, { 0xBD, 0xF2, 0x44, 0x7F, 0xD0, 0x5A, 0x54, 0x06 }} + gEmbeddedGpioProtocolGuid = { 0x17a0a3d7, 0xc0a5, 0x4635, { 0xbb, 0xd5, 0x07, 0x21, 0x87, 0xdf, 0xe2, 0xee }} + gPeCoffLoaderProtocolGuid = { 0xB323179B, 0x97FB, 0x477E, { 0xB0, 0xFE, 0xD8, 0x85, 0x91, 0xFA, 0x11, 0xAB } } + gEmbeddedMmcHostProtocolGuid = { 0x3e591c00, 0x9e4a, 0x11df, {0x92, 0x44, 0x00, 0x02, 0xA5, 0xD5, 0xC5, 0x1B }} + gAndroidFastbootTransportProtocolGuid = { 0x74bd9fe0, 0x8902, 0x11e3, {0xb9, 0xd3, 0xf7, 0x22, 0x38, 0xfc, 0x9a, 0x31}} + gAndroidFastbootPlatformProtocolGuid = { 0x524685a0, 0x89a0, 0x11e3, {0x9d, 0x4d, 0xbf, 0xa9, 0xf6, 0xa4, 0x03, 0x08}} + gUsbDeviceProtocolGuid = { 0x021bd2ca, 0x51d2, 0x11e3, {0x8e, 0x56, 0xb7, 0x54, 0x17, 0xc7, 0x0b, 0x44 }} + gPlatformBootManagerProtocolGuid = { 0x7197c8a7, 0x6559, 0x4c93, { 0x93, 0xd5, 0x8a, 0x84, 0xf9, 0x88, 0x79, 0x8b }} + gPlatformGpioProtocolGuid = { 0x52ce9845, 0x5af4, 0x43e2, {0xba, 0xfd, 0x23, 0x08, 0x12, 0x54, 0x7a, 0xc2 }} + gPlatformVirtualKeyboardProtocolGuid = { 0x0e3606d2, 0x1dc3, 0x4e6f, { 0xbe, 0x65, 0x39, 0x49, 0x82, 0xa2, 0x65, 0x47 }} + gAndroidBootImgProtocolGuid = { 0x9859bb19, 0x407c, 0x4f8b, {0xbc, 0xe1, 0xf8, 0xda, 0x65, 0x65, 0xf4, 0xa5 }} + +[Ppis] + gEdkiiEmbeddedGpioPpiGuid = { 0x21c3b115, 0x4e0b, 0x470c, { 0x85, 0xc7, 0xe1, 0x05, 0xa5, 0x75, 0xc9, 0x7b }} + +[PcdsFeatureFlag.common] + gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob|FALSE|BOOLEAN|0x0000001b + gEmbeddedTokenSpaceGuid.PcdGdbSerial|FALSE|BOOLEAN|0x00000053 + +[PcdsFixedAtBuild.common] + gEmbeddedTokenSpaceGuid.PcdPrePiStackBase|0|UINT32|0x0000000b + gEmbeddedTokenSpaceGuid.PcdPrePiStackSize|131072|UINT32|0x0000000c + + gEmbeddedTokenSpaceGuid.PcdMemoryBase|0x0|UINT32|0x0000004e + gEmbeddedTokenSpaceGuid.PcdMemorySize|0x0|UINT32|0x0000004f + + gEmbeddedTokenSpaceGuid.PcdFlashFvMainBase|0x0|UINT32|0x00000043 + gEmbeddedTokenSpaceGuid.PcdFlashFvMainOffset|0x0|UINT32|0x00000044 + gEmbeddedTokenSpaceGuid.PcdFlashFvMainSize|0x0|UINT32|0x00000045 + +# Used to help reduce fragmentation in the EFI memory map +# EFI Pages (4K) are the units used + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory|0|UINT32|0x00000012 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS|0|UINT32|0x00000013 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType|0|UINT32|0x00000014 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData|0|UINT32|0x00000015 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|0|UINT32|0x00000016 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode|0|UINT32|0x00000017 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData|0|UINT32|0x00000018 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode|0|UINT32|0x00000019 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData|0|UINT32|0x0000001a + + gEmbeddedTokenSpaceGuid.PcdTimerBaseAddress|0x3c700000|UINT32|0x0000001c + gEmbeddedTokenSpaceGuid.PcdTimerVector|7|UINT32|0x0000001d + gEmbeddedTokenSpaceGuid.PcdTimerPeriod|100000|UINT32|0x0000001e + gEmbeddedTokenSpaceGuid.PcdInterruptBaseAddress|0x38e00000|UINT32|0x0000001f + + gEmbeddedTokenSpaceGuid.PcdMetronomeTickPeriod|100|UINT32|0x00000020 + + gEmbeddedTokenSpaceGuid.PcdEmbeddedFdBaseAddress|0xffff0000|UINT32|0x00000030 + gEmbeddedTokenSpaceGuid.PcdEmbeddedFdSize|0x0000000|UINT32|0x00000031 + gEmbeddedTokenSpaceGuid.PcdEmbeddedPerformanceCounterFrequencyInHz|0x0000000|UINT64|0x00000032 + gEmbeddedTokenSpaceGuid.PcdEmbeddedPerformanceCounterPeriodInNanoseconds|0x0000000|UINT32|0x00000033 + + gEmbeddedTokenSpaceGuid.PcdGdbBaudRate|115200|UINT64|0x00000047 + gEmbeddedTokenSpaceGuid.PcdGdbDataBits|8|UINT8|0x00000048 + gEmbeddedTokenSpaceGuid.PcdGdbParity|1|UINT8|0x00000049 + gEmbeddedTokenSpaceGuid.PcdGdbStopBits|1|UINT8|0x0000004a + gEmbeddedTokenSpaceGuid.PcdGdbUartPort|0x3f8|UINT32|0x0000004b + gEmbeddedTokenSpaceGuid.PcdGdbMaxPacketRetryCount|10000000|UINT32|0x0000004c + gEmbeddedTokenSpaceGuid.PcdGdbTimerPeriodMilliseconds|250|UINT32|0x0000004d + + # + # Android FastBoot + # + + # The Android FastBoot utility has hard-coded USB Vendor IDs that it recognises + # (and 0xf00d isn't one of them!). + # You'll need to pass it "-i 0xf00d" to get it to recognise this device. + gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbVendorId|0xf00d|UINT32|0x00000022 + gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbProductId|0xbeef|UINT32|0x00000023 + gEmbeddedTokenSpaceGuid.PcdAndroidFastbootTcpPort|1234|UINT32|0x00000024 + + gEmbeddedTokenSpaceGuid.PcdAndroidBootDevicePath|L""|VOID*|0x00000057 + +[PcdsFixedAtBuild.ARM] + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0|UINT8|0x00000011 + +[PcdsFixedAtBuild.AARCH64] + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0|UINT8|0x00000011 + +[PcdsFixedAtBuild.IA32] + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|16|UINT8|0x00000011 + +[PcdsFixedAtBuild.X64] + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|16|UINT8|0x00000011 + +[PcdsFixedAtBuild.common, PcdsDynamic.common] + # + # Value to add to a host address to obtain a device address, using + # unsigned 64-bit integer arithmetic. This means we can rely on + # truncation on overflow to specify negative offsets. + # + gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset|0x0|UINT64|0x0000058 + + # + # Highest address value supported by the device for DMA addressing. Note + # that this value should be strictly greater than PcdDmaDeviceOffset. + # + gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit|0xFFFFFFFFFFFFFFFF|UINT64|0x000005A + + # + # Selection between DT and ACPI as a default + # + gEmbeddedTokenSpaceGuid.PcdDefaultDtPref|TRUE|BOOLEAN|0x0000059 diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedPkg.dsc b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedPkg.dsc new file mode 100644 index 00000000..0a095028 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/EmbeddedPkg.dsc @@ -0,0 +1,254 @@ +#/** @file +# Embedded Package +# +# +# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.
+# Copyright (c) 2012-2015, ARM Ltd. All rights reserved.
+# Copyright (c) 2016, Linaro Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + PLATFORM_NAME = Embedded + PLATFORM_GUID = 8DBB580B-CF89-4D57-95C6-DFE96C44686E + PLATFORM_VERSION = 0.1 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/Embedded + SUPPORTED_ARCHITECTURES = IA32|X64|ARM|AARCH64 + BUILD_TARGETS = DEBUG|RELEASE|NOOPT + SKUID_IDENTIFIER = DEFAULT + + +################################################################################ +# +# SKU Identification section - list of all SKU IDs supported by this +# Platform. +# +################################################################################ +[SkuIds] + 0|DEFAULT # The entry: 0|DEFAULT is reserved and always required. + +################################################################################ +# +# Library Class section - list of all Library Classes needed by this Platform. +# +################################################################################ + +!include MdePkg/MdeLibs.dsc.inc + +[LibraryClasses.common] +# DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + + + AndroidBootImgLib|EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf + PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf + + ReportStatusCodeLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf + + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf + PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf + PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf + CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf + PrePiLib|EmbeddedPkg/Library/PrePiLib/PrePiLib.inf + + SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf + RealTimeClockLib|EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf + EfiResetSystemLib|EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf + GdbSerialLib|EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf + + + # + # Need to change this for IPF + # + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf + + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + ExtractGuidedSectionLib|MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf + + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + + AcpiLib|EmbeddedPkg/Library/AcpiLib/AcpiLib.inf + FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf + + # Shell libraries + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf + FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf + + # Networking Requirements + !include NetworkPkg/NetworkLibs.dsc.inc + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf + + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + DtPlatformDtbLoaderLib|EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.inf + + TimeBaseLib|EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf + +[LibraryClasses.common.DXE_DRIVER] + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + + +[LibraryClasses.common.UEFI_APPLICATION] + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + +[LibraryClasses.common.UEFI_DRIVER] + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + +[LibraryClasses.common.SEC] + ExtractGuidedSectionLib|EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf + +[LibraryClasses.ARM, LibraryClasses.AARCH64] + ArmGicLib|ArmPkg/Drivers/ArmGic/ArmGicLib.inf + ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf + SemihostLib|ArmPkg/Library/SemihostLib/SemihostLib.inf + NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf + + # Add support for GCC stack protector + NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf + + ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf + +################################################################################ +# +# Pcd Section - list of all PCD Entries defined by this Platform +# +################################################################################ + +[PcdsFeatureFlag.common] + gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable|FALSE + gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable|FALSE + gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable|FALSE + gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable|FALSE + + gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob|FALSE + + +[PcdsFixedAtBuild.common] + gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength|1000000 + gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength|1000000 + gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength|1000000 + gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout|10000000 + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x0f + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000000 + gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x06 + gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue|0xAF + gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask|0 + gEfiMdePkgTokenSpaceGuid.PcdPostCodePropertyMask|0 + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0xE0000000 + gEfiMdePkgTokenSpaceGuid.PcdFSBClock|200000000 + gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|320 + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000000 + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0xE0000000 + gEfiMdePkgTokenSpaceGuid.PcdFSBClock|200000000 + + gEmbeddedTokenSpaceGuid.PcdPrePiStackBase|0 + gEmbeddedTokenSpaceGuid.PcdPrePiStackSize|0 + +# +# Optinal feature to help prevent EFI memory map fragments +# Turned on and off via: PcdPrePiProduceMemoryTypeInformationHob +# Values are in EFI Pages (4K). DXE Core will make sure that +# at least this much of each type of memory can be allocated +# from a single memory range. This way you only end up with +# maximum of two fragments for each type in the memory map +# (the memory used, and the free memory that was prereserved +# but not used). +# + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode|0 + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData|0 + +# +# Timer config for this platform +# + gEmbeddedTokenSpaceGuid.PcdTimerBaseAddress|0x3c700000 + gEmbeddedTokenSpaceGuid.PcdTimerVector|7 + gEmbeddedTokenSpaceGuid.PcdTimerPeriod|100000 + +[BuildOptions] + RVCT:*_*_ARM_PLATFORM_FLAGS == --cpu=7-A.security + *_*_*_CC_FLAGS = -DDISABLE_NEW_DEPRECATED_INTERFACES + +################################################################################ +# +# Components Section - list of all Modules needed by this Platform +# +################################################################################ +[Components.common] + EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf + EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf + EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf + EmbeddedPkg/Library/PrePiLib/PrePiLib.inf + EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf + EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf + EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.inf + EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf + EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.inf + EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf + + EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf + EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf + EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf + EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOutSerial.inf + EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf { + + TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf + } + + EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf + + EmbeddedPkg/Library/AcpiLib/AcpiLib.inf + EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf + EmbeddedPkg/Library/FdtLib/FdtLib.inf + EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf + EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf + + EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf + EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf + + EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf { + + DmaLib|EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf + } + +[Components.ARM, Components.AARCH64] + EmbeddedPkg/Application/AndroidBoot/AndroidBootApp.inf + EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf + EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf + EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcpDxe.inf + +[Components.IA32, Components.X64, Components.ARM] + EmbeddedPkg/GdbStub/GdbStub.inf diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/Arm/Processor.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/Arm/Processor.c new file mode 100644 index 00000000..dc0b1f5f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/Arm/Processor.c @@ -0,0 +1,697 @@ +/** @file + Processor specific parts of the GDB stub + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include + +// +// Array of exception types that need to be hooked by the debugger +// (efi, gdb) //efi number +// +EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = { + { EXCEPT_ARM_SOFTWARE_INTERRUPT, GDB_SIGTRAP } +// { EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP }, +// { EXCEPT_ARM_PREFETCH_ABORT, GDB_SIGTRAP }, +// { EXCEPT_ARM_DATA_ABORT, GDB_SIGEMT }, +// { EXCEPT_ARM_RESERVED, GDB_SIGILL } +}; + +// Shut up some annoying RVCT warnings +#ifdef __CC_ARM +#pragma diag_suppress 1296 +#endif + +UINTN gRegisterOffsets[] = { + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R0), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R1), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R2), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R3), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R4), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R5), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R6), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R7), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R8), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R9), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R10), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R11), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R12), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, SP), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, LR), + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, PC), + 0x00000F01, // f0 + 0x00000F02, + 0x00000F03, + 0x00000F11, // f1 + 0x00000F12, + 0x00000F13, + 0x00000F21, // f2 + 0x00000F22, + 0x00000F23, + 0x00000F31, // f3 + 0x00000F32, + 0x00000F33, + 0x00000F41, // f4 + 0x00000F42, + 0x00000F43, + 0x00000F51, // f5 + 0x00000F52, + 0x00000F53, + 0x00000F61, // f6 + 0x00000F62, + 0x00000F63, + 0x00000F71, // f7 + 0x00000F72, + 0x00000F73, + 0x00000FFF, // fps + OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, CPSR) +}; + +// restore warnings for RVCT +#ifdef __CC_ARM +#pragma diag_default 1296 +#endif + +/** + Return the number of entries in the gExceptionType[] + + @retval UINTN, the number of entries in the gExceptionType[] array. + **/ +UINTN +MaxEfiException ( + VOID + ) +{ + return sizeof (gExceptionType) / sizeof (EFI_EXCEPTION_TYPE_ENTRY); +} + + +/** + Return the number of entries in the gRegisters[] + + @retval UINTN, the number of entries (registers) in the gRegisters[] array. + **/ +UINTN +MaxRegisterCount ( + VOID + ) +{ + return sizeof (gRegisterOffsets) / sizeof (UINTN); +} + + +/** + Check to see if the ISA is supported. + ISA = Instruction Set Architecture + + @retval TRUE if Isa is supported + +**/ +BOOLEAN +CheckIsa ( + IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa + ) +{ + if (Isa == IsaArm) { + return TRUE; + } else { + return FALSE; + } +} + + +/** + This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering + It is, by default, set to find the register pointer of the ARM member + @param SystemContext Register content at time of the exception + @param RegNumber The register to which we want to find a pointer + @retval the pointer to the RegNumber-th pointer + **/ +UINTN * +FindPointerToRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN RegNumber + ) +{ + UINT8 *TempPtr; + ASSERT(gRegisterOffsets[RegNumber] < 0xF00); + TempPtr = ((UINT8 *)SystemContext.SystemContextArm) + gRegisterOffsets[RegNumber]; + return (UINT32 *)TempPtr; +} + + +/** + Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr + @param SystemContext Register content at time of the exception + @param RegNumber the number of the register that we want to read + @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on. + @retval the pointer to the next character of the output buffer that is available to be written on. + **/ +CHAR8 * +BasicReadRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN RegNumber, + IN CHAR8 *OutBufPtr + ) +{ + UINTN RegSize; + CHAR8 Char; + + if (gRegisterOffsets[RegNumber] > 0xF00) { + AsciiSPrint (OutBufPtr, 9, "00000000"); + OutBufPtr += 8; + return OutBufPtr; + } + + RegSize = 0; + while (RegSize < 32) { + Char = mHexToStr[(UINT8)((*FindPointerToRegister (SystemContext, RegNumber) >> (RegSize+4)) & 0xf)]; + if ((Char >= 'A') && (Char <= 'F')) { + Char = Char - 'A' + 'a'; + } + *OutBufPtr++ = Char; + + Char = mHexToStr[(UINT8)((*FindPointerToRegister (SystemContext, RegNumber) >> RegSize) & 0xf)]; + if ((Char >= 'A') && (Char <= 'F')) { + Char = Char - 'A' + 'a'; + } + *OutBufPtr++ = Char; + + RegSize = RegSize + 8; + } + return OutBufPtr; +} + + +/** + Reads the n-th register's value into an output buffer and sends it as a packet + @param SystemContext Register content at time of the exception + @param InBuffer Pointer to the input buffer received from gdb server + **/ +VOID +ReadNthRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ) +{ + UINTN RegNumber; + CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq) + CHAR8 *OutBufPtr; // pointer to the output buffer + + RegNumber = AsciiStrHexToUintn (&InBuffer[1]); + + if (RegNumber >= MaxRegisterCount ()) { + SendError (GDB_EINVALIDREGNUM); + return; + } + + OutBufPtr = OutBuffer; + OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr); + + *OutBufPtr = '\0'; // the end of the buffer + SendPacket (OutBuffer); +} + + +/** + Reads the general registers into an output buffer and sends it as a packet + @param SystemContext Register content at time of the exception + **/ +VOID +EFIAPI +ReadGeneralRegisters ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINTN Index; + CHAR8 *OutBuffer; + CHAR8 *OutBufPtr; + UINTN RegisterCount = MaxRegisterCount (); + + // It is not safe to allocate pool here.... + OutBuffer = AllocatePool ((RegisterCount * 8) + 1); // 8 bytes per register in string format plus a null to terminate + OutBufPtr = OutBuffer; + for (Index = 0; Index < RegisterCount; Index++) { + OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr); + } + + *OutBufPtr = '\0'; + SendPacket (OutBuffer); + FreePool (OutBuffer); +} + + +/** + Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr + @param SystemContext Register content at time of the exception + @param RegNumber the number of the register that we want to write + @param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on. + @retval the pointer to the next character of the input buffer that can be used + **/ +CHAR8 +*BasicWriteRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN RegNumber, + IN CHAR8 *InBufPtr + ) +{ + UINTN RegSize; + UINTN TempValue; // the value transferred from a hex char + UINT32 NewValue; // the new value of the RegNumber-th Register + + if (gRegisterOffsets[RegNumber] > 0xF00) { + return InBufPtr + 8; + } + + NewValue = 0; + RegSize = 0; + while (RegSize < 32) { + TempValue = HexCharToInt (*InBufPtr++); + + if ((INTN)TempValue < 0) { + SendError (GDB_EBADMEMDATA); + return NULL; + } + + NewValue += (TempValue << (RegSize+4)); + TempValue = HexCharToInt (*InBufPtr++); + + if ((INTN)TempValue < 0) { + SendError (GDB_EBADMEMDATA); + return NULL; + } + + NewValue += (TempValue << RegSize); + RegSize = RegSize + 8; + } + *(FindPointerToRegister (SystemContext, RegNumber)) = NewValue; + return InBufPtr; +} + + +/** ‘P n...=r...’ + Writes the new value of n-th register received into the input buffer to the n-th register + @param SystemContext Register content at time of the exception + @param InBuffer Pointer to the input buffer received from gdb server + **/ +VOID +WriteNthRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ) +{ + UINTN RegNumber; + CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array + CHAR8 *RegNumBufPtr; + CHAR8 *InBufPtr; // pointer to the input buffer + + // find the register number to write + InBufPtr = &InBuffer[1]; + RegNumBufPtr = RegNumBuffer; + while (*InBufPtr != '=') { + *RegNumBufPtr++ = *InBufPtr++; + } + *RegNumBufPtr = '\0'; + RegNumber = AsciiStrHexToUintn (RegNumBuffer); + + // check if this is a valid Register Number + if (RegNumber >= MaxRegisterCount ()) { + SendError (GDB_EINVALIDREGNUM); + return; + } + InBufPtr++; // skips the '=' character + BasicWriteRegister (SystemContext, RegNumber, InBufPtr); + SendSuccess(); +} + + +/** ‘G XX...’ + Writes the new values received into the input buffer to the general registers + @param SystemContext Register content at time of the exception + @param InBuffer Pointer to the input buffer received from gdb server + **/ + +VOID +EFIAPI +WriteGeneralRegisters ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ) +{ + UINTN i; + CHAR8 *InBufPtr; /// pointer to the input buffer + UINTN MinLength; + UINTN RegisterCount = MaxRegisterCount (); + + MinLength = (RegisterCount * 8) + 1; // 'G' plus the registers in ASCII format + + if (AsciiStrLen (InBuffer) < MinLength) { + //Bad message. Message is not the right length + SendError (GDB_EBADBUFSIZE); + return; + } + + InBufPtr = &InBuffer[1]; + + // Read the new values for the registers from the input buffer to an array, NewValueArray. + // The values in the array are in the gdb ordering + for (i = 0; i < RegisterCount; i++) { + InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr); + } + + SendSuccess (); +} + +// What about Thumb? +// Use SWI 0xdbdbdb as the debug instruction +#define GDB_ARM_BKPT 0xefdbdbdb + +BOOLEAN mSingleStepActive = FALSE; +UINT32 mSingleStepPC; +UINT32 mSingleStepData; +UINTN mSingleStepDataSize; + +typedef struct { + LIST_ENTRY Link; + UINT64 Signature; + UINT32 Address; + UINT32 Instruction; +} ARM_SOFTWARE_BREAKPOINT; + +#define ARM_SOFTWARE_BREAKPOINT_SIGNATURE SIGNATURE_64('A', 'R', 'M', 'B', 'R', 'K', 'P', 'T') +#define ARM_SOFTWARE_BREAKPOINT_FROM_LINK(a) CR(a, ARM_SOFTWARE_BREAKPOINT, Link, ARM_SOFTWARE_BREAKPOINT_SIGNATURE) + +LIST_ENTRY BreakpointList; + +/** + Insert Single Step in the SystemContext + + @param SystemContext Register content at time of the exception + **/ +VOID +AddSingleStep ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + if (mSingleStepActive) { + // Currently don't support nesting + return; + } + mSingleStepActive = TRUE; + + mSingleStepPC = SystemContext.SystemContextArm->PC; + + mSingleStepDataSize = sizeof (UINT32); + mSingleStepData = (*(UINT32 *)mSingleStepPC); + *(UINT32 *)mSingleStepPC = GDB_ARM_BKPT; + if (*(UINT32 *)mSingleStepPC != GDB_ARM_BKPT) { + // For some reason our breakpoint did not take + mSingleStepActive = FALSE; + } + + InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize); + //DEBUG((EFI_D_ERROR, "AddSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, mSingleStepData, *(UINT32 *)mSingleStepPC)); +} + + +/** + Remove Single Step in the SystemContext + + @param SystemContext Register content at time of the exception + **/ +VOID +RemoveSingleStep ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + if (!mSingleStepActive) { + return; + } + + if (mSingleStepDataSize == sizeof (UINT16)) { + *(UINT16 *)mSingleStepPC = (UINT16)mSingleStepData; + } else { + //DEBUG((EFI_D_ERROR, "RemoveSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, *(UINT32 *)mSingleStepPC, mSingleStepData)); + *(UINT32 *)mSingleStepPC = mSingleStepData; + } + InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize); + mSingleStepActive = FALSE; +} + + + +/** + Continue. addr is Address to resume. If addr is omitted, resume at current + Address. + + @param SystemContext Register content at time of the exception + **/ +VOID +EFIAPI +ContinueAtAddress ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ) +{ + if (PacketData[1] != '\0') { + SystemContext.SystemContextArm->PC = AsciiStrHexToUintn (&PacketData[1]); + } +} + + +/** ‘s [addr ]’ + Single step. addr is the Address at which to resume. If addr is omitted, resume + at same Address. + + @param SystemContext Register content at time of the exception + **/ +VOID +EFIAPI +SingleStep ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ) +{ + SendNotSupported (); +} + +UINTN +GetBreakpointDataAddress ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN BreakpointNumber + ) +{ + return 0; +} + +UINTN +GetBreakpointDetected ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + return 0; +} + +BREAK_TYPE +GetBreakpointType ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN BreakpointNumber + ) +{ + return NotSupported; +} + +ARM_SOFTWARE_BREAKPOINT * +SearchBreakpointList ( + IN UINT32 Address + ) +{ + LIST_ENTRY *Current; + ARM_SOFTWARE_BREAKPOINT *Breakpoint; + + Current = GetFirstNode (&BreakpointList); + while (!IsNull (&BreakpointList, Current)) { + Breakpoint = ARM_SOFTWARE_BREAKPOINT_FROM_LINK(Current); + + if (Address == Breakpoint->Address) { + return Breakpoint; + } + + Current = GetNextNode (&BreakpointList, Current); + } + + return NULL; +} + +VOID +SetBreakpoint ( + IN UINT32 Address + ) +{ + ARM_SOFTWARE_BREAKPOINT *Breakpoint; + + Breakpoint = SearchBreakpointList (Address); + + if (Breakpoint != NULL) { + return; + } + + // create and fill breakpoint structure + Breakpoint = AllocatePool (sizeof(ARM_SOFTWARE_BREAKPOINT)); + + Breakpoint->Signature = ARM_SOFTWARE_BREAKPOINT_SIGNATURE; + Breakpoint->Address = Address; + Breakpoint->Instruction = *(UINT32 *)Address; + + // Add it to the list + InsertTailList (&BreakpointList, &Breakpoint->Link); + + // Insert the software breakpoint + *(UINT32 *)Address = GDB_ARM_BKPT; + InvalidateInstructionCacheRange ((VOID *)Address, 4); + + //DEBUG((EFI_D_ERROR, "SetBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, Breakpoint->Instruction, *(UINT32 *)Address)); +} + +VOID +ClearBreakpoint ( + IN UINT32 Address + ) +{ + ARM_SOFTWARE_BREAKPOINT *Breakpoint; + + Breakpoint = SearchBreakpointList (Address); + + if (Breakpoint == NULL) { + return; + } + + // Add it to the list + RemoveEntryList (&Breakpoint->Link); + + // Restore the original instruction + *(UINT32 *)Address = Breakpoint->Instruction; + InvalidateInstructionCacheRange ((VOID *)Address, 4); + + //DEBUG((EFI_D_ERROR, "ClearBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, GDB_ARM_BKPT, *(UINT32 *)Address)); + + FreePool (Breakpoint); +} + +VOID +EFIAPI +InsertBreakPoint ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ) +{ + UINTN Type; + UINTN Address; + UINTN Length; + UINTN ErrorCode; + + ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length); + if (ErrorCode > 0) { + SendError ((UINT8)ErrorCode); + return; + } + + switch (Type) { + case 0: //Software breakpoint + break; + + default : + DEBUG((EFI_D_ERROR, "Insert breakpoint default: %x\n", Type)); + SendError (GDB_EINVALIDBRKPOINTTYPE); + return; + } + + SetBreakpoint (Address); + + SendSuccess (); +} + +VOID +EFIAPI +RemoveBreakPoint ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ) +{ + UINTN Type; + UINTN Address; + UINTN Length; + UINTN ErrorCode; + + //Parse breakpoint packet data + ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length); + if (ErrorCode > 0) { + SendError ((UINT8)ErrorCode); + return; + } + + switch (Type) { + case 0: //Software breakpoint + break; + + default: + SendError (GDB_EINVALIDBRKPOINTTYPE); + return; + } + + ClearBreakpoint (Address); + + SendSuccess (); +} + +VOID +InitializeProcessor ( + VOID + ) +{ + // Initialize breakpoint list + InitializeListHead (&BreakpointList); +} + +BOOLEAN +ValidateAddress ( + IN VOID *Address + ) +{ + if ((UINT32)Address < 0x80000000) { + return FALSE; + } else { + return TRUE; + } +} + +BOOLEAN +ValidateException ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINT32 ExceptionAddress; + UINT32 Instruction; + + // Is it a debugger SWI? + ExceptionAddress = SystemContext.SystemContextArm->PC -= 4; + Instruction = *(UINT32 *)ExceptionAddress; + if (Instruction != GDB_ARM_BKPT) { + return FALSE; + } + + // Special for SWI-based exception handling. SWI sets up the context + // to return to the instruction following the SWI instruction - NOT what we want + // for a debugger! + SystemContext.SystemContextArm->PC = ExceptionAddress; + + return TRUE; +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/GdbStub.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/GdbStub.c new file mode 100644 index 00000000..d37b3149 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/GdbStub.c @@ -0,0 +1,1251 @@ +/** @file + UEFI driver that implements a GDB stub + + Note: Any code in the path of the Serial IO output can not call DEBUG as will + will blow out the stack. Serial IO calls DEBUG, debug calls Serial IO, ... + + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + + +UINTN gMaxProcessorIndex = 0; + +// +// Buffers for basic gdb communication +// +CHAR8 gInBuffer[MAX_BUF_SIZE]; +CHAR8 gOutBuffer[MAX_BUF_SIZE]; + +// Assume gdb does a "qXfer:libraries:read::offset,length" when it connects so we can default +// this value to FALSE. Since gdb can reconnect its self a global default is not good enough +BOOLEAN gSymbolTableUpdate = FALSE; +EFI_EVENT gEvent; +VOID *gGdbSymbolEventHandlerRegistration = NULL; + +// +// Globals for returning XML from qXfer:libraries:read packet +// +UINTN gPacketqXferLibraryOffset = 0; +UINTN gEfiDebugImageTableEntry = 0; +EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *gDebugImageTableHeader = NULL; +EFI_DEBUG_IMAGE_INFO *gDebugTable = NULL; +CHAR8 gXferLibraryBuffer[2000]; + +GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexToStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + + +VOID +EFIAPI +GdbSymbolEventHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ +} + + +/** + The user Entry Point for Application. The user code starts with this function + as the real entry point for the image goes into a library that calls this + function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +GdbStubEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_DEBUG_SUPPORT_PROTOCOL *DebugSupport; + UINTN HandleCount; + EFI_HANDLE *Handles; + UINTN Index; + UINTN Processor; + BOOLEAN IsaSupported; + + Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&gDebugImageTableHeader); + if (EFI_ERROR (Status)) { + gDebugImageTableHeader = NULL; + } + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiDebugSupportProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Debug Support Protocol not found\n")); + + return Status; + } + + DebugSupport = NULL; + IsaSupported = FALSE; + do { + HandleCount--; + Status = gBS->HandleProtocol ( + Handles[HandleCount], + &gEfiDebugSupportProtocolGuid, + (VOID **) &DebugSupport + ); + if (!EFI_ERROR (Status)) { + if (CheckIsa (DebugSupport->Isa)) { + // We found what we are looking for so break out of the loop + IsaSupported = TRUE; + break; + } + } + } while (HandleCount > 0); + FreePool (Handles); + + if (!IsaSupported) { + DEBUG ((EFI_D_ERROR, "Debug Support Protocol does not support our ISA\n")); + + return EFI_NOT_FOUND; + } + + Status = DebugSupport->GetMaximumProcessorIndex (DebugSupport, &gMaxProcessorIndex); + ASSERT_EFI_ERROR (Status); + + DEBUG ((EFI_D_INFO, "Debug Support Protocol ISA %x\n", DebugSupport->Isa)); + DEBUG ((EFI_D_INFO, "Debug Support Protocol Processor Index %d\n", gMaxProcessorIndex)); + + // Call processor-specific init routine + InitializeProcessor (); + + for (Processor = 0; Processor <= gMaxProcessorIndex; Processor++) { + for (Index = 0; Index < MaxEfiException (); Index++) { + Status = DebugSupport->RegisterExceptionCallback (DebugSupport, Processor, GdbExceptionHandler, gExceptionType[Index].Exception); + ASSERT_EFI_ERROR (Status); + } + // + // Current edk2 DebugPort is not interrupt context safe so we can not use it + // + Status = DebugSupport->RegisterPeriodicCallback (DebugSupport, Processor, GdbPeriodicCallBack); + ASSERT_EFI_ERROR (Status); + } + + // + // This even fires every time an image is added. This allows the stub to know when gdb needs + // to update the symbol table. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + GdbSymbolEventHandler, + NULL, + &gEvent + ); + ASSERT_EFI_ERROR (Status); + + // + // Register for protocol notifications on this event + // + Status = gBS->RegisterProtocolNotify ( + &gEfiLoadedImageProtocolGuid, + gEvent, + &gGdbSymbolEventHandlerRegistration + ); + ASSERT_EFI_ERROR (Status); + + + if (PcdGetBool (PcdGdbSerial)) { + GdbInitializeSerialConsole (); + } + + return EFI_SUCCESS; +} + +/** + Transfer length bytes of input buffer, starting at Address, to memory. + + @param length the number of the bytes to be transferred/written + @param *address the start address of the transferring/writing the memory + @param *new_data the new data to be written to memory + **/ + +VOID +TransferFromInBufToMem ( + IN UINTN Length, + IN unsigned char *Address, + IN CHAR8 *NewData + ) +{ + CHAR8 c1; + CHAR8 c2; + + while (Length-- > 0) { + c1 = (CHAR8)HexCharToInt (*NewData++); + c2 = (CHAR8)HexCharToInt (*NewData++); + + if ((c1 < 0) || (c2 < 0)) { + Print ((CHAR16 *)L"Bad message from write to memory..\n"); + SendError (GDB_EBADMEMDATA); + return; + } + *Address++ = (UINT8)((c1 << 4) + c2); + } + + SendSuccess(); +} + + +/** + Transfer Length bytes of memory starting at Address to an output buffer, OutBuffer. This function will finally send the buffer + as a packet. + + @param Length the number of the bytes to be transferred/read + @param *address pointer to the start address of the transferring/reading the memory + **/ + +VOID +TransferFromMemToOutBufAndSend ( + IN UINTN Length, + IN unsigned char *Address + ) +{ + // there are Length bytes and every byte is represented as 2 hex chars + CHAR8 OutBuffer[MAX_BUF_SIZE]; + CHAR8 *OutBufPtr; // pointer to the output buffer + CHAR8 Char; + + if (ValidateAddress(Address) == FALSE) { + SendError(14); + return; + } + + OutBufPtr = OutBuffer; + while (Length > 0) { + + Char = mHexToStr[*Address >> 4]; + if ((Char >= 'A') && (Char <= 'F')) { + Char = Char - 'A' + 'a'; + } + *OutBufPtr++ = Char; + + Char = mHexToStr[*Address & 0x0f]; + if ((Char >= 'A') && (Char <= 'F')) { + Char = Char - 'A' + 'a'; + } + *OutBufPtr++ = Char; + + Address++; + Length--; + } + + *OutBufPtr = '\0' ; // the end of the buffer + SendPacket (OutBuffer); +} + + + +/** + Send a GDB Remote Serial Protocol Packet + + $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$', + the packet terminating character '#' and the two digit checksum. + + If an ack '+' is not sent resend the packet, but timeout eventually so we don't end up + in an infinite loop. This is so if you unplug the debugger code just keeps running + + @param PacketData Payload data for the packet + + + @retval Number of bytes of packet data sent. + +**/ +UINTN +SendPacket ( + IN CHAR8 *PacketData + ) +{ + UINT8 CheckSum; + UINTN Timeout; + CHAR8 *Ptr; + CHAR8 TestChar; + UINTN Count; + + Timeout = PcdGet32 (PcdGdbMaxPacketRetryCount); + + Count = 0; + do { + + Ptr = PacketData; + + if (Timeout-- == 0) { + // Only try a finite number of times so we don't get stuck in the loop + return Count; + } + + // Packet prefix + GdbPutChar ('$'); + + for (CheckSum = 0, Count =0 ; *Ptr != '\0'; Ptr++, Count++) { + GdbPutChar (*Ptr); + CheckSum = CheckSum + *Ptr; + } + + // Packet terminating character and checksum + GdbPutChar ('#'); + GdbPutChar (mHexToStr[CheckSum >> 4]); + GdbPutChar (mHexToStr[CheckSum & 0x0F]); + + TestChar = GdbGetChar (); + } while (TestChar != '+'); + + return Count; +} + +/** + Receive a GDB Remote Serial Protocol Packet + + $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$', + the packet terminating character '#' and the two digit checksum. + + If host re-starts sending a packet without ending the previous packet, only the last valid packet is processed. + (In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.) + + If an ack '+' is not sent resend the packet + + @param PacketData Payload data for the packet + + @retval Number of bytes of packet data received. + +**/ +UINTN +ReceivePacket ( + OUT CHAR8 *PacketData, + IN UINTN PacketDataSize + ) +{ + UINT8 CheckSum; + UINTN Index; + CHAR8 Char; + CHAR8 SumString[3]; + CHAR8 TestChar; + + ZeroMem (PacketData, PacketDataSize); + + for (;;) { + // wait for the start of a packet + TestChar = GdbGetChar (); + while (TestChar != '$') { + TestChar = GdbGetChar (); + }; + + retry: + for (Index = 0, CheckSum = 0; Index < (PacketDataSize - 1); Index++) { + Char = GdbGetChar (); + if (Char == '$') { + goto retry; + } + if (Char == '#') { + break; + } + + PacketData[Index] = Char; + CheckSum = CheckSum + Char; + } + PacketData[Index] = '\0'; + + if (Index == PacketDataSize) { + continue; + } + + SumString[0] = GdbGetChar (); + SumString[1] = GdbGetChar (); + SumString[2] = '\0'; + + if (AsciiStrHexToUintn (SumString) == CheckSum) { + // Ack: Success + GdbPutChar ('+'); + + // Null terminate the callers string + PacketData[Index] = '\0'; + return Index; + } else { + // Ack: Failure + GdbPutChar ('-'); + } + } + + //return 0; +} + + +/** + Empties the given buffer + @param Buf pointer to the first element in buffer to be emptied + **/ +VOID +EmptyBuffer ( + IN CHAR8 *Buf + ) +{ + *Buf = '\0'; +} + + +/** + Converts an 8-bit Hex Char into a INTN. + + @param Char the hex character to be converted into UINTN + @retval a INTN, from 0 to 15, that corresponds to Char + -1 if Char is not a hex character + **/ +INTN +HexCharToInt ( + IN CHAR8 Char + ) +{ + if ((Char >= 'A') && (Char <= 'F')) { + return Char - 'A' + 10; + } else if ((Char >= 'a') && (Char <= 'f')) { + return Char - 'a' + 10; + } else if ((Char >= '0') && (Char <= '9')) { + return Char - '0'; + } else { // if not a hex value, return a negative value + return -1; + } +} + + // 'E' + the biggest error number is 255, so its 2 hex digits + buffer end +CHAR8 *gError = "E__"; + +/** 'E NN' + Send an error with the given error number after converting to hex. + The error number is put into the buffer in hex. '255' is the biggest errno we can send. + ex: 162 will be sent as A2. + + @param errno the error number that will be sent + **/ +VOID +EFIAPI +SendError ( + IN UINT8 ErrorNum + ) +{ + // + // Replace _, or old data, with current errno + // + gError[1] = mHexToStr [ErrorNum >> 4]; + gError[2] = mHexToStr [ErrorNum & 0x0f]; + + SendPacket (gError); // send buffer +} + + + +/** + Send 'OK' when the function is done executing successfully. + **/ +VOID +EFIAPI +SendSuccess ( + VOID + ) +{ + SendPacket ("OK"); // send buffer +} + + +/** + Send empty packet to specify that particular command/functionality is not supported. + **/ +VOID +EFIAPI +SendNotSupported ( + VOID + ) +{ + SendPacket (""); +} + + +/** + Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints + + @param SystemContext Register content at time of the exception + @param GdbExceptionType GDB exception type + **/ +VOID +GdbSendTSignal ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINT8 GdbExceptionType + ) +{ + CHAR8 TSignalBuffer[128]; + CHAR8 *TSignalPtr; + UINTN BreakpointDetected; + BREAK_TYPE BreakType; + UINTN DataAddress; + CHAR8 *WatchStrPtr = NULL; + UINTN RegSize; + + TSignalPtr = &TSignalBuffer[0]; + + //Construct TSignal packet + *TSignalPtr++ = 'T'; + + // + // replace _, or previous value, with Exception type + // + *TSignalPtr++ = mHexToStr [GdbExceptionType >> 4]; + *TSignalPtr++ = mHexToStr [GdbExceptionType & 0x0f]; + + if (GdbExceptionType == GDB_SIGTRAP) { + if (gSymbolTableUpdate) { + // + // We can only send back on reason code. So if the flag is set it means the breakpoint is from our event handler + // + WatchStrPtr = "library:;"; + while (*WatchStrPtr != '\0') { + *TSignalPtr++ = *WatchStrPtr++; + } + gSymbolTableUpdate = FALSE; + } else { + + + // + // possible n:r pairs + // + + //Retrieve the breakpoint number + BreakpointDetected = GetBreakpointDetected (SystemContext); + + //Figure out if the exception is happend due to watch, rwatch or awatch. + BreakType = GetBreakpointType (SystemContext, BreakpointDetected); + + //INFO: rwatch is not supported due to the way IA32 debug registers work + if ((BreakType == DataWrite) || (BreakType == DataRead) || (BreakType == DataReadWrite)) { + + //Construct n:r pair + DataAddress = GetBreakpointDataAddress (SystemContext, BreakpointDetected); + + //Assign appropriate buffer to print particular watchpoint type + if (BreakType == DataWrite) { + WatchStrPtr = "watch"; + } else if (BreakType == DataRead) { + WatchStrPtr = "rwatch"; + } else if (BreakType == DataReadWrite) { + WatchStrPtr = "awatch"; + } + + while (*WatchStrPtr != '\0') { + *TSignalPtr++ = *WatchStrPtr++; + } + + *TSignalPtr++ = ':'; + + //Set up series of bytes in big-endian byte order. "awatch" won't work with little-endian byte order. + RegSize = REG_SIZE; + while (RegSize > 0) { + RegSize = RegSize-4; + *TSignalPtr++ = mHexToStr[(UINT8)(DataAddress >> RegSize) & 0xf]; + } + + //Always end n:r pair with ';' + *TSignalPtr++ = ';'; + } + } + } + + *TSignalPtr = '\0'; + + SendPacket (TSignalBuffer); +} + + +/** + Translates the EFI mapping to GDB mapping + + @param EFIExceptionType EFI Exception that is being processed + @retval UINTN that corresponds to EFIExceptionType's GDB exception type number + **/ +UINT8 +ConvertEFItoGDBtype ( + IN EFI_EXCEPTION_TYPE EFIExceptionType + ) +{ + UINTN Index; + + for (Index = 0; Index < MaxEfiException () ; Index++) { + if (gExceptionType[Index].Exception == EFIExceptionType) { + return gExceptionType[Index].SignalNo; + } + } + return GDB_SIGTRAP; // this is a GDB trap +} + + +/** "m addr,length" + Find the Length of the area to read and the start address. Finally, pass them to + another function, TransferFromMemToOutBufAndSend, that will read from that memory space and + send it as a packet. + **/ + +VOID +EFIAPI +ReadFromMemory ( + CHAR8 *PacketData + ) +{ + UINTN Address; + UINTN Length; + CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the address in hex chars + CHAR8 *AddrBufPtr; // pointer to the address buffer + CHAR8 *InBufPtr; /// pointer to the input buffer + + AddrBufPtr = AddressBuffer; + InBufPtr = &PacketData[1]; + while (*InBufPtr != ',') { + *AddrBufPtr++ = *InBufPtr++; + } + *AddrBufPtr = '\0'; + + InBufPtr++; // this skips ',' in the buffer + + /* Error checking */ + if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) { + Print((CHAR16 *)L"Address is too long\n"); + SendError (GDB_EBADMEMADDRBUFSIZE); + return; + } + + // 2 = 'm' + ',' + if (AsciiStrLen (PacketData) - AsciiStrLen (AddressBuffer) - 2 >= MAX_LENGTH_SIZE) { + Print((CHAR16 *)L"Length is too long\n"); + SendError (GDB_EBADMEMLENGTH); + return; + } + + Address = AsciiStrHexToUintn (AddressBuffer); + Length = AsciiStrHexToUintn (InBufPtr); + + TransferFromMemToOutBufAndSend (Length, (unsigned char *)Address); +} + + +/** "M addr,length :XX..." + Find the Length of the area in bytes to write and the start address. Finally, pass them to + another function, TransferFromInBufToMem, that will write to that memory space the info in + the input buffer. + **/ +VOID +EFIAPI +WriteToMemory ( + IN CHAR8 *PacketData + ) +{ + UINTN Address; + UINTN Length; + UINTN MessageLength; + CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the Address in hex chars + CHAR8 LengthBuffer[MAX_LENGTH_SIZE]; // the buffer that will hold the Length in hex chars + CHAR8 *AddrBufPtr; // pointer to the Address buffer + CHAR8 *LengthBufPtr; // pointer to the Length buffer + CHAR8 *InBufPtr; /// pointer to the input buffer + + AddrBufPtr = AddressBuffer; + LengthBufPtr = LengthBuffer; + InBufPtr = &PacketData[1]; + + while (*InBufPtr != ',') { + *AddrBufPtr++ = *InBufPtr++; + } + *AddrBufPtr = '\0'; + + InBufPtr++; // this skips ',' in the buffer + + while (*InBufPtr != ':') { + *LengthBufPtr++ = *InBufPtr++; + } + *LengthBufPtr = '\0'; + + InBufPtr++; // this skips ':' in the buffer + + Address = AsciiStrHexToUintn (AddressBuffer); + Length = AsciiStrHexToUintn (LengthBuffer); + + /* Error checking */ + + //Check if Address is not too long. + if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) { + Print ((CHAR16 *)L"Address too long..\n"); + SendError (GDB_EBADMEMADDRBUFSIZE); + return; + } + + //Check if message length is not too long + if (AsciiStrLen (LengthBuffer) >= MAX_LENGTH_SIZE) { + Print ((CHAR16 *)L"Length too long..\n"); + SendError (GDB_EBADMEMLENGBUFSIZE); + return; + } + + // Check if Message is not too long/short. + // 3 = 'M' + ',' + ':' + MessageLength = (AsciiStrLen (PacketData) - AsciiStrLen (AddressBuffer) - AsciiStrLen (LengthBuffer) - 3); + if (MessageLength != (2*Length)) { + //Message too long/short. New data is not the right size. + SendError (GDB_EBADMEMDATASIZE); + return; + } + TransferFromInBufToMem (Length, (unsigned char *)Address, InBufPtr); +} + +/** + Parses breakpoint packet data and captures Breakpoint type, Address and length. + In case of an error, function returns particular error code. Returning 0 meaning + no error. + + @param PacketData Pointer to the payload data for the packet. + @param Type Breakpoint type + @param Address Breakpoint address + @param Length Breakpoint length in Bytes (1 byte, 2 byte, 4 byte) + + @retval 1 Success + @retval {other} Particular error code + +**/ +UINTN +ParseBreakpointPacket ( + IN CHAR8 *PacketData, + OUT UINTN *Type, + OUT UINTN *Address, + OUT UINTN *Length + ) +{ + CHAR8 AddressBuffer[MAX_ADDR_SIZE]; + CHAR8 *AddressBufferPtr; + CHAR8 *PacketDataPtr; + + PacketDataPtr = &PacketData[1]; + AddressBufferPtr = AddressBuffer; + + *Type = AsciiStrHexToUintn (PacketDataPtr); + + //Breakpoint/watchpoint type should be between 0 to 4 + if (*Type > 4) { + Print ((CHAR16 *)L"Type is invalid\n"); + return 22; //EINVAL: Invalid argument. + } + + //Skip ',' in the buffer. + while (*PacketDataPtr++ != ','); + + //Parse Address information + while (*PacketDataPtr != ',') { + *AddressBufferPtr++ = *PacketDataPtr++; + } + *AddressBufferPtr = '\0'; + + //Check if Address is not too long. + if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) { + Print ((CHAR16 *)L"Address too long..\n"); + return 40; //EMSGSIZE: Message size too long. + } + + *Address = AsciiStrHexToUintn (AddressBuffer); + + PacketDataPtr++; //This skips , in the buffer + + //Parse Length information + *Length = AsciiStrHexToUintn (PacketDataPtr); + + //Length should be 1, 2 or 4 bytes + if (*Length > 4) { + Print ((CHAR16 *)L"Length is invalid\n"); + return 22; //EINVAL: Invalid argument + } + + return 0; //0 = No error +} + +UINTN +gXferObjectReadResponse ( + IN CHAR8 Type, + IN CHAR8 *Str + ) +{ + CHAR8 *OutBufPtr; // pointer to the output buffer + CHAR8 Char; + UINTN Count; + + // Response starts with 'm' or 'l' if it is the end + OutBufPtr = gOutBuffer; + *OutBufPtr++ = Type; + Count = 1; + + // Binary data encoding + OutBufPtr = gOutBuffer; + while (*Str != '\0') { + Char = *Str++; + if ((Char == 0x7d) || (Char == 0x23) || (Char == 0x24) || (Char == 0x2a)) { + // escape character + *OutBufPtr++ = 0x7d; + + Char ^= 0x20; + } + *OutBufPtr++ = Char; + Count++; + } + + *OutBufPtr = '\0' ; // the end of the buffer + SendPacket (gOutBuffer); + + return Count; +} + + +/** + Note: This should be a library function. In the Apple case you have to add + the size of the PE/COFF header into the starting address to make things work + right as there is no way to pad the Mach-O for the size of the PE/COFF header. + + + Returns a pointer to the PDB file name for a PE/COFF image that has been + loaded into system memory with the PE/COFF Loader Library functions. + + Returns the PDB file name for the PE/COFF image specified by Pe32Data. If + the PE/COFF image specified by Pe32Data is not a valid, then NULL is + returned. If the PE/COFF image specified by Pe32Data does not contain a + debug directory entry, then NULL is returned. If the debug directory entry + in the PE/COFF image specified by Pe32Data does not contain a PDB file name, + then NULL is returned. + If Pe32Data is NULL, then ASSERT(). + + @param Pe32Data Pointer to the PE/COFF image that is loaded in system + memory. + @param DebugBase Address that the debugger would use as the base of the image + + @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL + if it cannot be retrieved. DebugBase is only valid if PDB file name is + valid. + +**/ +VOID * +EFIAPI +PeCoffLoaderGetDebuggerInfo ( + IN VOID *Pe32Data, + OUT VOID **DebugBase + ) +{ + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; + UINTN DirCount; + VOID *CodeViewEntryPointer; + INTN TEImageAdjust; + UINT32 NumberOfRvaAndSizes; + UINT16 Magic; + UINTN SizeOfHeaders; + + ASSERT (Pe32Data != NULL); + + TEImageAdjust = 0; + DirectoryEntry = NULL; + DebugEntry = NULL; + NumberOfRvaAndSizes = 0; + SizeOfHeaders = 0; + + DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, so read the PE header after the DOS image header. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff)); + } else { + // + // DOS image header is not present, so PE header is at the image base. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; + } + + if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { + if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) { + DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG]; + TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize; + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te + + Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress + + TEImageAdjust); + } + SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize; + + // __APPLE__ check this math... + *DebugBase = ((CHAR8 *)Pe32Data) - TEImageAdjust; + } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { + + *DebugBase = Pe32Data; + + + // + // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic. + // It is due to backward-compatibility, for some system might + // generate PE32+ image with PE32 Magic. + // + switch (Hdr.Pe32->FileHeader.Machine) { + case EFI_IMAGE_MACHINE_IA32: + // + // Assume PE32 image with IA32 Machine field. + // + Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC; + break; + case EFI_IMAGE_MACHINE_X64: + case EFI_IMAGE_MACHINE_IA64: + // + // Assume PE32+ image with X64 or IPF Machine field + // + Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + break; + default: + // + // For unknown Machine field, use Magic in optional Header + // + Magic = Hdr.Pe32->OptionalHeader.Magic; + } + + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset get Debug Directory Entry + // + SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders; + NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress); + } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + // + // Use PE32+ offset get Debug Directory Entry + // + SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; + NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress); + } + + if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + DirectoryEntry = NULL; + DebugEntry = NULL; + } + } else { + return NULL; + } + + if (DebugEntry == NULL || DirectoryEntry == NULL) { + return NULL; + } + + for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) { + if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { + if (DebugEntry->SizeOfData > 0) { + CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust); + switch (* (UINT32 *) CodeViewEntryPointer) { + case CODEVIEW_SIGNATURE_NB10: + return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)); + case CODEVIEW_SIGNATURE_RSDS: + return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)); + case CODEVIEW_SIGNATURE_MTOC: + *DebugBase = (VOID *)(UINTN)((UINTN)DebugBase - SizeOfHeaders); + return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)); + default: + break; + } + } + } + } + + (void)SizeOfHeaders; + return NULL; +} + + +/** + Process "qXfer:object:read:annex:offset,length" request. + + Returns an XML document that contains loaded libraries. In our case it is + information in the EFI Debug Image Table converted into an XML document. + + GDB will call with an arbitrary length (it can't know the real length and + will reply with chunks of XML that are easy for us to deal with. Gdb will + keep calling until we say we are done. XML doc looks like: + + + + + + + + Since we can not allocate memory in interrupt context this module has + assumptions about how it will get called: + 1) Length will generally be max remote packet size (big enough) + 2) First Offset of an XML document read needs to be 0 + 3) This code will return back small chunks of the XML document on every read. + Each subsequent call will ask for the next available part of the document. + + Note: The only variable size element in the XML is: + " \n" and it is + based on the file path and name of the symbol file. If the symbol file name + is bigger than the max gdb remote packet size we could update this code + to respond back in chunks. + + @param Offset offset into special data area + @param Length number of bytes to read starting at Offset + + **/ +VOID +QxferLibrary ( + IN UINTN Offset, + IN UINTN Length + ) +{ + VOID *LoadAddress; + CHAR8 *Pdb; + UINTN Size; + + if (Offset != gPacketqXferLibraryOffset) { + SendError (GDB_EINVALIDARG); + Print (L"\nqXferLibrary (%d, %d) != %d\n", Offset, Length, gPacketqXferLibraryOffset); + + // Force a retry from the beginning + gPacketqXferLibraryOffset = 0; + + return; + } + + if (Offset == 0) { + gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', "\n"); + + // The owner of the table may have had to ralloc it so grab a fresh copy every time + // we assume qXferLibrary will get called over and over again until the entire XML table is + // returned in a tight loop. Since we are in the debugger the table should not get updated + gDebugTable = gDebugImageTableHeader->EfiDebugImageInfoTable; + gEfiDebugImageTableEntry = 0; + return; + } + + if (gDebugTable != NULL) { + for (; gEfiDebugImageTableEntry < gDebugImageTableHeader->TableSize; gEfiDebugImageTableEntry++, gDebugTable++) { + if (gDebugTable->NormalImage != NULL) { + if ((gDebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) && + (gDebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) { + Pdb = PeCoffLoaderGetDebuggerInfo ( + gDebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase, + &LoadAddress + ); + if (Pdb != NULL) { + Size = AsciiSPrint ( + gXferLibraryBuffer, + sizeof (gXferLibraryBuffer), + " \n", + Pdb, + LoadAddress + ); + if ((Size != 0) && (Size != (sizeof (gXferLibraryBuffer) - 1))) { + gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', gXferLibraryBuffer); + + // Update loop variables so we are in the right place when we get back + gEfiDebugImageTableEntry++; + gDebugTable++; + return; + } else { + // We could handle entires larger than sizeof (gXferLibraryBuffer) here if + // needed by breaking up into N packets + // " (fixed size) + // + // But right now we just skip any entry that is too big + } + } + } + } + } + } + + + gXferObjectReadResponse ('l', "\n"); + gPacketqXferLibraryOffset = 0; + return; +} + + +/** + Exception Handler for GDB. It will be called for all exceptions + registered via the gExceptionType[] array. + + @param ExceptionType Exception that is being processed + @param SystemContext Register content at time of the exception + **/ +VOID +EFIAPI +GdbExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINT8 GdbExceptionType; + CHAR8 *Ptr; + + + if (ValidateException (ExceptionType, SystemContext) == FALSE) { + return; + } + + RemoveSingleStep (SystemContext); + + GdbExceptionType = ConvertEFItoGDBtype (ExceptionType); + GdbSendTSignal (SystemContext, GdbExceptionType); + + for( ; ; ) { + ReceivePacket (gInBuffer, MAX_BUF_SIZE); + + switch (gInBuffer[0]) { + case '?': + GdbSendTSignal (SystemContext, GdbExceptionType); + break; + + case 'c': + ContinueAtAddress (SystemContext, gInBuffer); + return; + + case 'g': + ReadGeneralRegisters (SystemContext); + break; + + case 'G': + WriteGeneralRegisters (SystemContext, gInBuffer); + break; + + case 'H': + //Return "OK" packet since we don't have more than one thread. + SendSuccess (); + break; + + case 'm': + ReadFromMemory (gInBuffer); + break; + + case 'M': + WriteToMemory (gInBuffer); + break; + + case 'P': + WriteNthRegister (SystemContext, gInBuffer); + break; + + // + // Still debugging this code. Not used in Darwin + // + case 'q': + // General Query Packets + if (AsciiStrnCmp (gInBuffer, "qSupported", 10) == 0) { + // return what we currently support, we don't parse what gdb supports + AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "qXfer:libraries:read+;PacketSize=%d", MAX_BUF_SIZE); + SendPacket (gOutBuffer); + } else if (AsciiStrnCmp (gInBuffer, "qXfer:libraries:read::", 22) == 0) { + // ‘qXfer:libraries:read::offset,length + // gInBuffer[22] is offset string, ++Ptr is length string’ + for (Ptr = &gInBuffer[22]; *Ptr != ','; Ptr++); + + // Not sure if multi-radix support is required. Currently only support decimal + QxferLibrary (AsciiStrHexToUintn (&gInBuffer[22]), AsciiStrHexToUintn (++Ptr)); + } if (AsciiStrnCmp (gInBuffer, "qOffsets", 10) == 0) { + AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "Text=1000;Data=f000;Bss=f000"); + SendPacket (gOutBuffer); + } else { + //Send empty packet + SendNotSupported (); + } + break; + + case 's': + SingleStep (SystemContext, gInBuffer); + return; + + case 'z': + RemoveBreakPoint (SystemContext, gInBuffer); + break; + + case 'Z': + InsertBreakPoint (SystemContext, gInBuffer); + break; + + default: + //Send empty packet + SendNotSupported (); + break; + } + } +} + + +/** + Periodic callback for GDB. This function is used to catch a ctrl-c or other + break in type command from GDB. + + @param SystemContext Register content at time of the call + **/ +VOID +EFIAPI +GdbPeriodicCallBack ( + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + // + // gCtrlCBreakFlag may have been set from a previous F response package + // and we set the global as we need to process it at a point where we + // can update the system context. If we are in the middle of processing + // a F Packet it is not safe to read the GDB serial stream so we need + // to skip it on this check + // + if (!gCtrlCBreakFlag && !gProcessingFPacket) { + // + // Ctrl-C was not pending so grab any pending characters and see if they + // are a Ctrl-c (0x03). If so set the Ctrl-C global. + // + while (TRUE) { + if (!GdbIsCharAvailable ()) { + // + // No characters are pending so exit the loop + // + break; + } + + if (GdbGetChar () == 0x03) { + gCtrlCBreakFlag = TRUE; + // + // We have a ctrl-c so exit the loop + // + break; + } + } + } + + if (gCtrlCBreakFlag) { + // + // Update the context to force a single step trap when we exit the GDB + // stub. This will transfer control to GdbExceptionHandler () and let + // us break into the program. We don't want to break into the GDB stub. + // + AddSingleStep (SystemContext); + gCtrlCBreakFlag = FALSE; + } +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/GdbStub.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/GdbStub.inf new file mode 100644 index 00000000..f75fea0d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/GdbStub.inf @@ -0,0 +1,72 @@ +#/** @file +# UEFI GDB stub +# +# This is a shell application that will display Hello World. +# Copyright (c) 2008, Apple Inc. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GdbStub + FILE_GUID = 1F2CCB4F-D817-404E-98E7-80E4851FB33E + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = GdbStubEntry + +[Sources.common] + GdbStub.c + SerialIo.c + +[Sources.ARM] + Arm/Processor.c + +[Sources.IA32] + Ia32/Processor.c + +[Sources.X64] + X64/Processor.c + + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + UefiLib + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + BaseMemoryLib + MemoryAllocationLib + DevicePathLib + PcdLib + GdbSerialLib + PrintLib + CacheMaintenanceLib + + +[Protocols] + gEfiDebugSupportProtocolGuid + gEfiDebugPortProtocolGuid + gEfiSerialIoProtocolGuid + +[Guids] + gEfiDebugImageInfoTableGuid + +[FeaturePcd.common] + gEmbeddedTokenSpaceGuid.PcdGdbSerial + +[FixedPcd.common] + gEmbeddedTokenSpaceGuid.PcdGdbMaxPacketRetryCount diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/GdbStubInternal.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/GdbStubInternal.h new file mode 100644 index 00000000..468c89b7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/GdbStubInternal.h @@ -0,0 +1,749 @@ +/** @file + Private include file for GDB stub + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __GDB_STUB_INTERNAL__ +#define __GDB_STUB_INTERNAL__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern CONST CHAR8 mHexToStr[]; + +// maximum size of input and output buffers +// This value came from the show remote command of the gdb we tested against +#define MAX_BUF_SIZE 2000 + +// maximum size of address buffer +#define MAX_ADDR_SIZE 32 + +// maximum size of register number buffer +#define MAX_REG_NUM_BUF_SIZE 32 + +// maximum size of length buffer +#define MAX_LENGTH_SIZE 32 + +// maximum size of T signal members +#define MAX_T_SIGNAL_SIZE 64 + +// the mask used to clear all the cache +#define TF_BIT 0x00000100 + + +// +// GDB Signal definitions - generic names for interrupts +// +#define GDB_SIGILL 4 // Illegal instruction +#define GDB_SIGTRAP 5 // Trace Trap (Breakpoint and SingleStep) +#define GDB_SIGEMT 7 // Emulator Trap +#define GDB_SIGFPE 8 // Floating point exception +#define GDB_SIGSEGV 11 // Segment violation, page fault + + +// +// GDB File I/O Error values, zero means no error +// Includes all general GDB Unix like error values +// +#define GDB_EBADMEMADDRBUFSIZE 11 // the buffer that stores memory Address to be read from/written to is not the right size +#define GDB_EBADMEMLENGBUFSIZE 12 // the buffer that stores Length is not the right size +#define GDB_EBADMEMLENGTH 13 // Length, the given number of bytes to read or write, is not the right size +#define GDB_EBADMEMDATA 14 // one of the bytes or nibbles of the memory is less than 0 +#define GDB_EBADMEMDATASIZE 15 // the memory data, 'XX..', is too short or too long +#define GDB_EBADBUFSIZE 21 // the buffer created is not the correct size +#define GDB_EINVALIDARG 31 // argument is invalid +#define GDB_ENOSPACE 41 // +#define GDB_EINVALIDBRKPOINTTYPE 51 // the breakpoint type is not recognized +#define GDB_EINVALIDREGNUM 61 // given register number is not valid: either <0 or >=Number of Registers +#define GDB_EUNKNOWN 255 // unknown + + +// +// These devices are open by GDB so we can just read and write to them +// +#define GDB_STDIN 0x00 +#define GDB_STDOUT 0x01 +#define GDB_STDERR 0x02 + +// +//Define Register size for different architectures +// +#if defined (MDE_CPU_IA32) +#define REG_SIZE 32 +#elif defined (MDE_CPU_X64) +#define REG_SIZE 64 +#elif defined (MDE_CPU_ARM) +#define REG_SIZE 32 +#endif + +#define GDB_SERIAL_DEV_SIGNATURE SIGNATURE_32 ('g', 'd', 'b', 's') + +typedef struct { + VENDOR_DEVICE_PATH VendorDevice; + UINT32 Index; // Support more than one + EFI_DEVICE_PATH_PROTOCOL End; +} GDB_SERIAL_DEVICE_PATH; + +// +// Name: SERIAL_DEV +// Purpose: To provide device specific information +// Fields: +// Signature UINTN: The identity of the serial device +// SerialIo SERIAL_IO_PROTOCOL: Serial I/O protocol interface +// SerialMode SERIAL_IO_MODE: +// DevicePath EFI_DEVICE_PATH_PROTOCOL *: Device path of the serial device +// +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_SERIAL_IO_PROTOCOL SerialIo; + EFI_SERIAL_IO_MODE SerialMode; + GDB_SERIAL_DEVICE_PATH DevicePath; + INTN InFileDescriptor; + INTN OutFileDescriptor; +} GDB_SERIAL_DEV; + + +#define GDB_SERIAL_DEV_FROM_THIS(a) CR (a, GDB_SERIAL_DEV, SerialIo, GDB_SERIAL_DEV_SIGNATURE) + + +typedef struct { + EFI_EXCEPTION_TYPE Exception; + UINT8 SignalNo; +} EFI_EXCEPTION_TYPE_ENTRY; + + +#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) + +// +// Byte packed structure for DR6 +// 32-bits on IA-32 +// 64-bits on X64. The upper 32-bits on X64 are reserved +// +typedef union { + struct { + UINT32 B0:1; // Breakpoint condition detected + UINT32 B1:1; // Breakpoint condition detected + UINT32 B2:1; // Breakpoint condition detected + UINT32 B3:1; // Breakpoint condition detected + UINT32 Reserved_1:9; // Reserved + UINT32 BD:1; // Debug register access detected + UINT32 BS:1; // Single step + UINT32 BT:1; // Task switch + UINT32 Reserved_2:16; // Reserved + } Bits; + UINTN UintN; +} IA32_DR6; + +// +// Byte packed structure for DR7 +// 32-bits on IA-32 +// 64-bits on X64. The upper 32-bits on X64 are reserved +// +typedef union { + struct { + UINT32 L0:1; // Local breakpoint enable + UINT32 G0:1; // Global breakpoint enable + UINT32 L1:1; // Local breakpoint enable + UINT32 G1:1; // Global breakpoint enable + UINT32 L2:1; // Local breakpoint enable + UINT32 G2:1; // Global breakpoint enable + UINT32 L3:1; // Local breakpoint enable + UINT32 G3:1; // Global breakpoint enable + UINT32 LE:1; // Local exact breakpoint enable + UINT32 GE:1; // Global exact breakpoint enable + UINT32 Reserved_1:3; // Reserved + UINT32 GD:1; // Global detect enable + UINT32 Reserved_2:2; // Reserved + UINT32 RW0:2; // Read/Write field + UINT32 LEN0:2; // Length field + UINT32 RW1:2; // Read/Write field + UINT32 LEN1:2; // Length field + UINT32 RW2:2; // Read/Write field + UINT32 LEN2:2; // Length field + UINT32 RW3:2; // Read/Write field + UINT32 LEN3:2; // Length field + } Bits; + UINTN UintN; +} IA32_DR7; + +#endif /* if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) */ + +typedef enum { + InstructionExecution, //Hardware breakpoint + DataWrite, //watch + DataRead, //rwatch + DataReadWrite, //awatch + SoftwareBreakpoint, //Software breakpoint + NotSupported +} BREAK_TYPE; + +// +// Array of exception types that need to be hooked by the debugger +// +extern EFI_EXCEPTION_TYPE_ENTRY gExceptionType[]; + +// +// Set TRUE if F Reply package signals a ctrl-c. We can not process the Ctrl-c +// here we need to wait for the periodic callback to do this. +// +extern BOOLEAN gCtrlCBreakFlag; + +// +// If the periodic callback is called while we are processing an F packet we need +// to let the callback know to not read from the serial stream as it could steal +// characters from the F response packet +// +extern BOOLEAN gProcessingFPacket; + + +// The offsets of registers SystemContext. +// The fields in the array are in the gdb ordering. +// +extern UINTN gRegisterOffsets[]; + +/** + Return the number of entries in the gExceptionType[] + + @retval UINTN, the number of entries in the gExceptionType[] array. + **/ +UINTN +MaxEfiException ( + VOID + ); + + +/** + Return the number of entries in the gRegisters[] + + @retval UINTN, the number of entries (registers) in the gRegisters[] array. + **/ +UINTN +MaxRegisterCount ( + VOID + ); + + +/** + Check to see if the ISA is supported. + ISA = Instruction Set Architecture + + @retval TRUE if Isa is supported, + FALSE otherwise. + **/ +BOOLEAN +CheckIsa ( + IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa + ); + + +/** + Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints + + @param SystemContext Register content at time of the exception + @param GdbExceptionType GDB exception type + **/ + +VOID +GdbSendTSignal ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINT8 GdbExceptionType + ); + + +/** + Translates the EFI mapping to GDB mapping + + @param EFIExceptionType EFI Exception that is being processed + @retval UINTN that corresponds to EFIExceptionType's GDB exception type number + **/ +UINT8 +ConvertEFItoGDBtype ( + IN EFI_EXCEPTION_TYPE EFIExceptionType + ); + + +/** + Empties the given buffer + @param *Buf pointer to the first element in buffer to be emptied + **/ +VOID +EmptyBuffer ( + IN CHAR8 *Buf + ); + + +/** + Converts an 8-bit Hex Char into a INTN. + + @param Char - the hex character to be converted into UINTN + @retval a INTN, from 0 to 15, that corresponds to Char + -1 if Char is not a hex character + **/ +INTN +HexCharToInt ( + IN CHAR8 Char + ); + + +/** 'E NN' + Send an error with the given error number after converting to hex. + The error number is put into the buffer in hex. '255' is the biggest errno we can send. + ex: 162 will be sent as A2. + + @param errno the error number that will be sent + **/ +VOID +EFIAPI +SendError ( + IN UINT8 ErrorNum + ); + + +/** + Send 'OK' when the function is done executing successfully. + **/ +VOID +EFIAPI +SendSuccess ( + VOID + ); + + +/** + Send empty packet to specify that particular command/functionality is not supported. + **/ +VOID +EFIAPI +SendNotSupported ( + VOID + ); + +/** ‘p n’ + Reads the n-th register's value into an output buffer and sends it as a packet + @param SystemContext Register content at time of the exception + @param InBuffer This is the input buffer received from gdb server + **/ +VOID +ReadNthRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ); + + +/** ‘g’ + Reads the general registers into an output buffer and sends it as a packet + @param SystemContext Register content at time of the exception + **/ +VOID +EFIAPI +ReadGeneralRegisters ( + IN EFI_SYSTEM_CONTEXT SystemContext + ); + + +/** ‘P n...=r...’ + Writes the new value of n-th register received into the input buffer to the n-th register + @param SystemContext Register content at time of the exception + @param InBuffer This is the input buffer received from gdb server + **/ +VOID +EFIAPI +WriteNthRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ); + + +/** ‘G XX...’ + Writes the new values received into the input buffer to the general registers + @param SystemContext Register content at time of the exception + @param InBuffer Pointer to the input buffer received from gdb server + **/ + +VOID +EFIAPI +WriteGeneralRegisters ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ); + + +/** ‘m addr,length ’ + Find the Length of the area to read and the start address. Finally, pass them to + another function, TransferFromMemToOutBufAndSend, that will read from that memory space and + send it as a packet. + + @param *PacketData Pointer to Payload data for the packet + **/ +VOID +EFIAPI +ReadFromMemory ( + IN CHAR8 *PacketData + ); + + +/** ‘M addr,length :XX...’ + Find the Length of the area in bytes to write and the start address. Finally, pass them to + another function, TransferFromInBufToMem, that will write to that memory space the info in + the input buffer. + + @param PacketData Pointer to Payload data for the packet + **/ +VOID +EFIAPI +WriteToMemory ( + IN CHAR8 *PacketData + ); + + +/** ‘c [addr ]’ + Continue. addr is Address to resume. If addr is omitted, resume at current + Address. + + @param SystemContext Register content at time of the exception + @param *PacketData Pointer to PacketData + **/ + +VOID +EFIAPI +ContinueAtAddress ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ); + + +/** ‘s [addr ]’ + Single step. addr is the Address at which to resume. If addr is omitted, resume + at same Address. + + @param SystemContext Register content at time of the exception + @param PacketData Pointer to Payload data for the packet + **/ +VOID +EFIAPI +SingleStep ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ); + +/** + Insert Single Step in the SystemContext + + @param SystemContext Register content at time of the exception + **/ +VOID +AddSingleStep ( + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +/** + Remove Single Step in the SystemContext + + @param SystemContext Register content at time of the exception + **/ +VOID +RemoveSingleStep ( + IN EFI_SYSTEM_CONTEXT SystemContext + ); + + +/** + ‘Z1, [addr], [length]’ + ‘Z2, [addr], [length]’ + ‘Z3, [addr], [length]’ + ‘Z4, [addr], [length]’ + + Insert hardware breakpoint/watchpoint at address addr of size length + + @param SystemContext Register content at time of the exception + @param *PacketData Pointer to the Payload data for the packet + +**/ +VOID +EFIAPI +InsertBreakPoint( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ); + + +/** + ‘z1, [addr], [length]’ + ‘z2, [addr], [length]’ + ‘z3, [addr], [length]’ + ‘z4, [addr], [length]’ + + Remove hardware breakpoint/watchpoint at address addr of size length + + @param SystemContext Register content at time of the exception + @param *PacketData Pointer to the Payload data for the packet + +**/ +VOID +EFIAPI +RemoveBreakPoint( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ); + + +/** + Exception Handler for GDB. It will be called for all exceptions + registered via the gExceptionType[] array. + + @param ExceptionType Exception that is being processed + @param SystemContext Register content at time of the exception + + **/ +VOID +EFIAPI +GdbExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ); + + +/** + Periodic callback for GDB. This function is used to catch a ctrl-c or other + break in type command from GDB. + + @param SystemContext Register content at time of the call + + **/ +VOID +EFIAPI +GdbPeriodicCallBack ( + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ); + + +/** + Make two serial consoles: 1) StdIn and StdOut via GDB. 2) StdErr via GDB. + + These console show up on the remote system running GDB + +**/ + +VOID +GdbInitializeSerialConsole ( + VOID + ); + + +/** + Send a GDB Remote Serial Protocol Packet + + $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$', + the packet terminating character '#' and the two digit checksum. + + If an ack '+' is not sent resend the packet, but timeout eventually so we don't end up + in an infinite loop. This is so if you unplug the debugger code just keeps running + + @param PacketData Payload data for the packet + + @retval Number of bytes of packet data sent. + +**/ +UINTN +SendPacket ( + IN CHAR8 *PacketData + ); + + +/** + Receive a GDB Remote Serial Protocol Packet + + $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$', + the packet terminating character '#' and the two digit checksum. + + If host re-starts sending a packet without ending the previous packet, only the last valid packet is processed. + (In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.) + + If an ack '+' is not sent resend the packet + + @param PacketData Payload data for the packet + + @retval Number of bytes of packet data received. + + **/ +UINTN +ReceivePacket ( + OUT CHAR8 *PacketData, + IN UINTN PacketDataSize + ); + + +/** + Read data from a FileDescriptor. On success number of bytes read is returned. Zero indicates + the end of a file. On error -1 is returned. If count is zero, GdbRead returns zero. + + @param FileDescriptor Device to talk to. + @param Buffer Buffer to hold Count bytes that were read + @param Count Number of bytes to transfer. + + @retval -1 Error + @retval {other} Number of bytes read. + +**/ +INTN +GdbRead ( + IN INTN FileDescriptor, + OUT VOID *Buffer, + IN UINTN Count + ); + + +/** + Write data to a FileDescriptor. On success number of bytes written is returned. Zero indicates + nothing was written. On error -1 is returned. + + @param FileDescriptor Device to talk to. + @param Buffer Buffer to hold Count bytes that are to be written + @param Count Number of bytes to transfer. + + @retval -1 Error + @retval {other} Number of bytes written. + +**/ +INTN +GdbWrite ( + IN INTN FileDescriptor, + OUT CONST VOID *Buffer, + IN UINTN Count + ); + +UINTN * +FindPointerToRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN RegNumber + ); + +CHAR8 * +BasicReadRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN RegNumber, + IN CHAR8 *OutBufPtr + ); + +VOID +TransferFromInBufToMem ( + IN UINTN Length, + IN UINT8 *Address, + IN CHAR8 *NewData + ); + +VOID +TransferFromMemToOutBufAndSend ( + IN UINTN Length, + IN UINT8 *Address + ); + +CHAR8 * +BasicWriteRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN RegNumber, + IN CHAR8 *InBufPtr + ); + +VOID +PrintReg ( + EFI_SYSTEM_CONTEXT SystemContext + ); + +UINTN +ParseBreakpointPacket ( + IN CHAR8 *PacketData, + OUT UINTN *Type, + OUT UINTN *Address, + OUT UINTN *Length + ); + +UINTN +GetBreakpointDataAddress ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN BreakpointNumber + ); + +UINTN +GetBreakpointDetected ( + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +BREAK_TYPE +GetBreakpointType ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN BreakpointNumber + ); + +UINTN +ConvertLengthData ( + IN UINTN Length + ); + +EFI_STATUS +FindNextFreeDebugRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + OUT UINTN *Register + ); + +EFI_STATUS +EnableDebugRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN Register, + IN UINTN Address, + IN UINTN Length, + IN UINTN Type + ); + +EFI_STATUS +FindMatchingDebugRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN Address, + IN UINTN Length, + IN UINTN Type, + OUT UINTN *Register + ); + +EFI_STATUS +DisableDebugRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN Register + ); + +VOID +InitializeProcessor ( + VOID + ); + +BOOLEAN +ValidateAddress ( + IN VOID *Address + ); + +BOOLEAN +ValidateException ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/Ia32/Processor.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/Ia32/Processor.c new file mode 100644 index 00000000..19f52548 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/Ia32/Processor.c @@ -0,0 +1,987 @@ +/** @file + Processor specific parts of the GDB stub + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +// +// Array of exception types that need to be hooked by the debugger +// {EFI mapping, GDB mapping} +// +EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = { + { EXCEPT_IA32_DIVIDE_ERROR, GDB_SIGFPE }, + { EXCEPT_IA32_DEBUG, GDB_SIGTRAP }, + { EXCEPT_IA32_NMI, GDB_SIGEMT }, + { EXCEPT_IA32_BREAKPOINT, GDB_SIGTRAP }, + { EXCEPT_IA32_OVERFLOW, GDB_SIGSEGV }, + { EXCEPT_IA32_BOUND, GDB_SIGSEGV }, + { EXCEPT_IA32_INVALID_OPCODE, GDB_SIGILL }, + { EXCEPT_IA32_DOUBLE_FAULT, GDB_SIGEMT }, + { EXCEPT_IA32_STACK_FAULT, GDB_SIGSEGV }, + { EXCEPT_IA32_GP_FAULT, GDB_SIGSEGV }, + { EXCEPT_IA32_PAGE_FAULT, GDB_SIGSEGV }, + { EXCEPT_IA32_FP_ERROR, GDB_SIGEMT }, + { EXCEPT_IA32_ALIGNMENT_CHECK, GDB_SIGEMT }, + { EXCEPT_IA32_MACHINE_CHECK, GDB_SIGEMT } +}; + + +// The offsets of registers SystemContext. +// The fields in the array are in the gdb ordering. +// +//16 regs +UINTN gRegisterOffsets[] = { + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Eax), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ecx), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Edx), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ebx), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Esp), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ebp), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Esi), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Edi), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Eip), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Eflags), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Cs), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ss), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ds), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Es), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Fs), + OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Gs) +}; + + +//Debug only.. +VOID +PrintReg ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + Print ((CHAR16 *)L"EAX: %x ", SystemContext.SystemContextIa32->Eax); + Print ((CHAR16 *)L"ECX: %x ", SystemContext.SystemContextIa32->Ecx); + Print ((CHAR16 *)L"EDX: %x ", SystemContext.SystemContextIa32->Edx); + Print ((CHAR16 *)L"EBX: %x ", SystemContext.SystemContextIa32->Ebx); + Print ((CHAR16 *)L"ESP: %x ", SystemContext.SystemContextIa32->Esp); + Print ((CHAR16 *)L"EBP: %x ", SystemContext.SystemContextIa32->Ebp); + Print ((CHAR16 *)L"ESI: %x ", SystemContext.SystemContextIa32->Esi); + Print ((CHAR16 *)L"EDI: %x ", SystemContext.SystemContextIa32->Edi); + Print ((CHAR16 *)L"EIP: %x\n", SystemContext.SystemContextIa32->Eip); + Print ((CHAR16 *)L"EFlags: %x\n", SystemContext.SystemContextIa32->Eflags); +} + +//Debug only.. +VOID +PrintDRreg ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + Print ((CHAR16 *)L"DR0: %x ", SystemContext.SystemContextIa32->Dr0); + Print ((CHAR16 *)L"DR1: %x ", SystemContext.SystemContextIa32->Dr1); + Print ((CHAR16 *)L"DR2: %x ", SystemContext.SystemContextIa32->Dr2); + Print ((CHAR16 *)L"DR3: %x ", SystemContext.SystemContextIa32->Dr3); + Print ((CHAR16 *)L"DR6: %x ", SystemContext.SystemContextIa32->Dr6); + Print ((CHAR16 *)L"DR7: %x\n", SystemContext.SystemContextIa32->Dr7); +} + + +/** + Return the number of entries in the gExceptionType[] + + @retval UINTN, the number of entries in the gExceptionType[] array. + **/ +UINTN +MaxEfiException ( + VOID + ) +{ + return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY); +} + + +/** + Return the number of entries in the gRegisters[] + + @retval UINTN, the number of entries (registers) in the gRegisters[] array. + **/ +UINTN +MaxRegisterCount ( + VOID + ) +{ + return sizeof (gRegisterOffsets)/sizeof (UINTN); +} + + +/** + Check to see if the ISA is supported. + ISA = Instruction Set Architecture + + @retval TRUE if Isa is supported, + FALSE otherwise. +**/ +BOOLEAN +CheckIsa ( + IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa + ) +{ + return (BOOLEAN)(Isa == IsaIa32); +} + + +/** + This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering + It is, by default, set to find the register pointer of the IA32 member + + @param SystemContext Register content at time of the exception + @param RegNumber The register to which we want to find a pointer + @retval the pointer to the RegNumber-th pointer + **/ +UINTN * +FindPointerToRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN RegNumber + ) +{ + UINT8 *TempPtr; + TempPtr = ((UINT8 *)SystemContext.SystemContextIa32) + gRegisterOffsets[RegNumber]; + return (UINTN *)TempPtr; +} + + +/** + Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr + + @param SystemContext Register content at time of the exception + @param RegNumber the number of the register that we want to read + @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on. + @retval the pointer to the next character of the output buffer that is available to be written on. + **/ +CHAR8 * +BasicReadRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN RegNumber, + IN CHAR8 *OutBufPtr + ) +{ + UINTN RegSize; + + RegSize = 0; + while (RegSize < REG_SIZE) { + *OutBufPtr++ = mHexToStr[((*FindPointerToRegister (SystemContext, RegNumber) >> (RegSize+4)) & 0xf)]; + *OutBufPtr++ = mHexToStr[((*FindPointerToRegister (SystemContext, RegNumber) >> RegSize) & 0xf)]; + RegSize = RegSize + 8; + } + return OutBufPtr; +} + + +/** ‘p n’ + Reads the n-th register's value into an output buffer and sends it as a packet + + @param SystemContext Register content at time of the exception + @param InBuffer Pointer to the input buffer received from gdb server + **/ +VOID +EFIAPI +ReadNthRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ) +{ + UINTN RegNumber; + CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq) + CHAR8 *OutBufPtr; // pointer to the output buffer + + RegNumber = AsciiStrHexToUintn (&InBuffer[1]); + + if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount())) { + SendError (GDB_EINVALIDREGNUM); + return; + } + + OutBufPtr = OutBuffer; + OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr); + + *OutBufPtr = '\0'; // the end of the buffer + SendPacket(OutBuffer); +} + + +/** ‘g’ + Reads the general registers into an output buffer and sends it as a packet + + @param SystemContext Register content at time of the exception + **/ +VOID +EFIAPI +ReadGeneralRegisters ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINTN i; + CHAR8 OutBuffer[129]; // 16 regs, 8 hex chars each, and the end '\0' (escape seq) + CHAR8 *OutBufPtr; // pointer to the output buffer + + OutBufPtr = OutBuffer; + for (i = 0 ; i < MaxRegisterCount() ; i++) { // there are only 16 registers to read + OutBufPtr = BasicReadRegister (SystemContext, i, OutBufPtr); + } + + *OutBufPtr = '\0'; // the end of the buffer + SendPacket(OutBuffer); +} + + +/** + Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr + + @param SystemContext Register content at time of the exception + @param RegNumber the number of the register that we want to write + @param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on. + @retval the pointer to the next character of the input buffer that can be used + **/ +CHAR8 * +BasicWriteRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN RegNumber, + IN CHAR8 *InBufPtr + ) +{ + UINTN RegSize; + UINTN TempValue; // the value transferred from a hex char + UINT32 NewValue; // the new value of the RegNumber-th Register + + NewValue = 0; + RegSize = 0; + while (RegSize < REG_SIZE) { + TempValue = HexCharToInt(*InBufPtr++); + + if (TempValue < 0) { + SendError (GDB_EBADMEMDATA); + return NULL; + } + + NewValue += (TempValue << (RegSize+4)); + TempValue = HexCharToInt(*InBufPtr++); + + if (TempValue < 0) { + SendError (GDB_EBADMEMDATA); + return NULL; + } + + NewValue += (TempValue << RegSize); + RegSize = RegSize + 8; + } + *(FindPointerToRegister (SystemContext, RegNumber)) = NewValue; + return InBufPtr; +} + + +/** ‘P n...=r...’ + Writes the new value of n-th register received into the input buffer to the n-th register + + @param SystemContext Register content at time of the exception + @param InBuffer Pointer to the input buffer received from gdb server + **/ +VOID +EFIAPI +WriteNthRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ) +{ + UINTN RegNumber; + CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array + CHAR8 *RegNumBufPtr; + CHAR8 *InBufPtr; // pointer to the input buffer + + // find the register number to write + InBufPtr = &InBuffer[1]; + RegNumBufPtr = RegNumBuffer; + while (*InBufPtr != '=') { + *RegNumBufPtr++ = *InBufPtr++; + } + *RegNumBufPtr = '\0'; + RegNumber = AsciiStrHexToUintn (RegNumBuffer); + + // check if this is a valid Register Number + if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount())) { + SendError (GDB_EINVALIDREGNUM); + return; + } + InBufPtr++; // skips the '=' character + BasicWriteRegister (SystemContext, RegNumber, InBufPtr); + SendSuccess(); +} + + +/** ‘G XX...’ + Writes the new values received into the input buffer to the general registers + + @param SystemContext Register content at time of the exception + @param InBuffer Pointer to the input buffer received from gdb server + **/ +VOID +EFIAPI +WriteGeneralRegisters ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ) +{ + UINTN i; + CHAR8 *InBufPtr; /// pointer to the input buffer + + // check to see if the buffer is the right size which is + // 1 (for 'G') + 16 (for 16 registers) * 8 ( for 8 hex chars each) = 129 + if (AsciiStrLen(InBuffer) != 129) { // 16 regs, 8 hex chars each, and the end '\0' (escape seq) + //Bad message. Message is not the right length + SendError (GDB_EBADBUFSIZE); + return; + } + + InBufPtr = &InBuffer[1]; + + // Read the new values for the registers from the input buffer to an array, NewValueArray. + // The values in the array are in the gdb ordering + for (i=0; i < MaxRegisterCount(); i++) { // there are only 16 registers to write + InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr); + } + + SendSuccess(); +} + + +/** + Insert Single Step in the SystemContext + + @param SystemContext Register content at time of the exception + **/ +VOID +AddSingleStep ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + SystemContext.SystemContextIa32->Eflags |= TF_BIT; //Setting the TF bit. +} + + +/** + Remove Single Step in the SystemContext + + @param SystemContext Register content at time of the exception + **/ +VOID +RemoveSingleStep ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + SystemContext.SystemContextIa32->Eflags &= ~TF_BIT; // clearing the TF bit. +} + + + +/** ‘c [addr ]’ + Continue. addr is Address to resume. If addr is omitted, resume at current + Address. + + @param SystemContext Register content at time of the exception + **/ +VOID +EFIAPI +ContinueAtAddress ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ) +{ + if (PacketData[1] != '\0') { + SystemContext.SystemContextIa32->Eip = AsciiStrHexToUintn (&PacketData[1]); + } +} + + +/** ‘s [addr ]’ + Single step. addr is the Address at which to resume. If addr is omitted, resume + at same Address. + + @param SystemContext Register content at time of the exception + **/ +VOID +EFIAPI +SingleStep ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ) +{ + if (PacketData[1] != '\0') { + SystemContext.SystemContextIa32->Eip = AsciiStrHexToUintn (&PacketData[1]); + } + + AddSingleStep (SystemContext); +} + + +/** + Returns breakpoint data address from DR0-DR3 based on the input breakpoint number + + @param SystemContext Register content at time of the exception + @param BreakpointNumber Breakpoint number + + @retval Address Data address from DR0-DR3 based on the breakpoint number. + +**/ +UINTN +GetBreakpointDataAddress ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN BreakpointNumber + ) +{ + UINTN Address; + + if (BreakpointNumber == 1) { + Address = SystemContext.SystemContextIa32->Dr0; + } else if (BreakpointNumber == 2) { + Address = SystemContext.SystemContextIa32->Dr1; + } else if (BreakpointNumber == 3) { + Address = SystemContext.SystemContextIa32->Dr2; + } else if (BreakpointNumber == 4) { + Address = SystemContext.SystemContextIa32->Dr3; + } else { + Address = 0; + } + + return Address; +} + + +/** + Returns currently detected breakpoint value based on the register DR6 B0-B3 field. + If no breakpoint is detected then it returns 0. + + @param SystemContext Register content at time of the exception + + @retval {1-4} Currently detected breakpoint value + @retval 0 No breakpoint detected. + +**/ +UINTN +GetBreakpointDetected ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + IA32_DR6 Dr6; + UINTN BreakpointNumber; + + Dr6.UintN = SystemContext.SystemContextIa32->Dr6; + + if (Dr6.Bits.B0 == 1) { + BreakpointNumber = 1; + } else if (Dr6.Bits.B1 == 1) { + BreakpointNumber = 2; + } else if (Dr6.Bits.B2 == 1) { + BreakpointNumber = 3; + } else if (Dr6.Bits.B3 == 1) { + BreakpointNumber = 4; + } else { + BreakpointNumber = 0; //No breakpoint detected + } + + return BreakpointNumber; +} + + +/** + Returns Breakpoint type (InstructionExecution, DataWrite, DataRead or DataReadWrite) + based on the Breakpoint number + + @param SystemContext Register content at time of the exception + @param BreakpointNumber Breakpoint number + + @retval BREAK_TYPE Breakpoint type value read from register DR7 RWn field + For unknown value, it returns NotSupported. + +**/ +BREAK_TYPE +GetBreakpointType ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN BreakpointNumber + ) +{ + IA32_DR7 Dr7; + BREAK_TYPE Type = NotSupported; //Default is NotSupported type + + Dr7.UintN = SystemContext.SystemContextIa32->Dr7; + + if (BreakpointNumber == 1) { + Type = (BREAK_TYPE) Dr7.Bits.RW0; + } else if (BreakpointNumber == 2) { + Type = (BREAK_TYPE) Dr7.Bits.RW1; + } else if (BreakpointNumber == 3) { + Type = (BREAK_TYPE) Dr7.Bits.RW2; + } else if (BreakpointNumber == 4) { + Type = (BREAK_TYPE) Dr7.Bits.RW3; + } + + return Type; +} + + +/** + Parses Length and returns the length which DR7 LENn field accepts. + For example: If we receive 1-Byte length then we should return 0. + Zero gets written to DR7 LENn field. + + @param Length Breakpoint length in Bytes (1 byte, 2 byte, 4 byte) + + @retval Length Appropriate converted values which DR7 LENn field accepts. + +**/ +UINTN +ConvertLengthData ( + IN UINTN Length + ) +{ + if (Length == 1) { //1-Byte length + return 0; + } else if (Length == 2) { //2-Byte length + return 1; + } else if (Length == 4) { //4-Byte length + return 3; + } else { //Undefined or 8-byte length + return 2; + } +} + + +/** + Finds the next free debug register. If all the registers are occupied then + EFI_OUT_OF_RESOURCES is returned. + + @param SystemContext Register content at time of the exception + @param Register Register value (0 - 3 for the first free debug register) + + @retval EFI_STATUS Appropriate status value. + +**/ +EFI_STATUS +FindNextFreeDebugRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + OUT UINTN *Register + ) +{ + IA32_DR7 Dr7; + + Dr7.UintN = SystemContext.SystemContextIa32->Dr7; + + if (Dr7.Bits.G0 == 0) { + *Register = 0; + } else if (Dr7.Bits.G1 == 0) { + *Register = 1; + } else if (Dr7.Bits.G2 == 0) { + *Register = 2; + } else if (Dr7.Bits.G3 == 0) { + *Register = 3; + } else { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + + +/** + Enables the debug register. Writes Address value to appropriate DR0-3 register. + Sets LENn, Gn, RWn bits in DR7 register. + + @param SystemContext Register content at time of the exception + @param Register Register value (0 - 3) + @param Address Breakpoint address value + @param Type Breakpoint type (Instruction, Data write, Data read + or write etc.) + + @retval EFI_STATUS Appropriate status value. + +**/ +EFI_STATUS +EnableDebugRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN Register, + IN UINTN Address, + IN UINTN Length, + IN UINTN Type + ) +{ + IA32_DR7 Dr7; + + //Convert length data + Length = ConvertLengthData (Length); + + //For Instruction execution, length should be 0 + //(Ref. Intel reference manual 18.2.4) + if ((Type == 0) && (Length != 0)) { + return EFI_INVALID_PARAMETER; + } + + //Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle + //software breakpoint. We should send empty packet in both these cases. + if ((Type == (BREAK_TYPE)DataRead) || + (Type == (BREAK_TYPE)SoftwareBreakpoint)) { + return EFI_UNSUPPORTED; + } + + //Read DR7 so appropriate Gn, RWn and LENn bits can be modified. + Dr7.UintN = SystemContext.SystemContextIa32->Dr7; + + if (Register == 0) { + SystemContext.SystemContextIa32->Dr0 = Address; + Dr7.Bits.G0 = 1; + Dr7.Bits.RW0 = Type; + Dr7.Bits.LEN0 = Length; + } else if (Register == 1) { + SystemContext.SystemContextIa32->Dr1 = Address; + Dr7.Bits.G1 = 1; + Dr7.Bits.RW1 = Type; + Dr7.Bits.LEN1 = Length; + } else if (Register == 2) { + SystemContext.SystemContextIa32->Dr2 = Address; + Dr7.Bits.G2 = 1; + Dr7.Bits.RW2 = Type; + Dr7.Bits.LEN2 = Length; + } else if (Register == 3) { + SystemContext.SystemContextIa32->Dr3 = Address; + Dr7.Bits.G3 = 1; + Dr7.Bits.RW3 = Type; + Dr7.Bits.LEN3 = Length; + } else { + return EFI_INVALID_PARAMETER; + } + + //Update Dr7 with appropriate Gn, RWn and LENn bits + SystemContext.SystemContextIa32->Dr7 = Dr7.UintN; + + return EFI_SUCCESS; +} + + +/** + Returns register number 0 - 3 for the matching debug register. + This function compares incoming Address, Type, Length and + if there is a match then it returns the appropriate register number. + In case of mismatch, function returns EFI_NOT_FOUND message. + + @param SystemContext Register content at time of the exception + @param Address Breakpoint address value + @param Length Breakpoint length value + @param Type Breakpoint type (Instruction, Data write, + Data read or write etc.) + @param Register Register value to be returned + + @retval EFI_STATUS Appropriate status value. + +**/ +EFI_STATUS +FindMatchingDebugRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN Address, + IN UINTN Length, + IN UINTN Type, + OUT UINTN *Register + ) +{ + IA32_DR7 Dr7; + + //Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle + //software breakpoint. We should send empty packet in both these cases. + if ((Type == (BREAK_TYPE)DataRead) || + (Type == (BREAK_TYPE)SoftwareBreakpoint)) { + return EFI_UNSUPPORTED; + } + + //Convert length data + Length = ConvertLengthData(Length); + + Dr7.UintN = SystemContext.SystemContextIa32->Dr7; + + if ((Dr7.Bits.G0 == 1) && + (Dr7.Bits.LEN0 == Length) && + (Dr7.Bits.RW0 == Type) && + (Address == SystemContext.SystemContextIa32->Dr0)) { + *Register = 0; + } else if ((Dr7.Bits.G1 == 1) && + (Dr7.Bits.LEN1 == Length) && + (Dr7.Bits.RW1 == Type) && + (Address == SystemContext.SystemContextIa32->Dr1)) { + *Register = 1; + } else if ((Dr7.Bits.G2 == 1) && + (Dr7.Bits.LEN2 == Length) && + (Dr7.Bits.RW2 == Type) && + (Address == SystemContext.SystemContextIa32->Dr2)) { + *Register = 2; + } else if ((Dr7.Bits.G3 == 1) && + (Dr7.Bits.LEN3 == Length) && + (Dr7.Bits.RW3 == Type) && + (Address == SystemContext.SystemContextIa32->Dr3)) { + *Register = 3; + } else { + Print ((CHAR16 *)L"No match found..\n"); + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + + +/** + Disables the particular debug register. + + @param SystemContext Register content at time of the exception + @param Register Register to be disabled + + @retval EFI_STATUS Appropriate status value. + +**/ +EFI_STATUS +DisableDebugRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN Register + ) +{ + IA32_DR7 Dr7; + UINTN Address = 0; + + //Read DR7 register so appropriate Gn, RWn and LENn bits can be turned off. + Dr7.UintN = SystemContext.SystemContextIa32->Dr7; + + if (Register == 0) { + SystemContext.SystemContextIa32->Dr0 = Address; + Dr7.Bits.G0 = 0; + Dr7.Bits.RW0 = 0; + Dr7.Bits.LEN0 = 0; + } else if (Register == 1) { + SystemContext.SystemContextIa32->Dr1 = Address; + Dr7.Bits.G1 = 0; + Dr7.Bits.RW1 = 0; + Dr7.Bits.LEN1 = 0; + } else if (Register == 2) { + SystemContext.SystemContextIa32->Dr2 = Address; + Dr7.Bits.G2 = 0; + Dr7.Bits.RW2 = 0; + Dr7.Bits.LEN2 = 0; + } else if (Register == 3) { + SystemContext.SystemContextIa32->Dr3 = Address; + Dr7.Bits.G3 = 0; + Dr7.Bits.RW3 = 0; + Dr7.Bits.LEN3 = 0; + } else { + return EFI_INVALID_PARAMETER; + } + + //Update DR7 register so appropriate Gn, RWn and LENn bits can be turned off. + SystemContext.SystemContextIa32->Dr7 = Dr7.UintN; + + return EFI_SUCCESS; +} + + +/** + ‘Z1, [addr], [length]’ + ‘Z2, [addr], [length]’ + ‘Z3, [addr], [length]’ + ‘Z4, [addr], [length]’ + + Insert hardware breakpoint/watchpoint at address addr of size length + + @param SystemContext Register content at time of the exception + @param *PacketData Pointer to the Payload data for the packet + +**/ +VOID +EFIAPI +InsertBreakPoint ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ) +{ + UINTN Type; + UINTN Address; + UINTN Length; + UINTN Register; + EFI_STATUS Status; + BREAK_TYPE BreakType = NotSupported; + UINTN ErrorCode; + + ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length); + if (ErrorCode > 0) { + SendError ((UINT8)ErrorCode); + return; + } + + switch (Type) { + + case 0: //Software breakpoint + BreakType = SoftwareBreakpoint; + break; + + case 1: //Hardware breakpoint + BreakType = InstructionExecution; + break; + + case 2: //Write watchpoint + BreakType = DataWrite; + break; + + case 3: //Read watchpoint + BreakType = DataRead; + break; + + case 4: //Access watchpoint + BreakType = DataReadWrite; + break; + + default : + Print ((CHAR16 *)L"Insert breakpoint default: %x\n", Type); + SendError (GDB_EINVALIDBRKPOINTTYPE); + return; + } + + // Find next free debug register + Status = FindNextFreeDebugRegister (SystemContext, &Register); + if (EFI_ERROR(Status)) { + Print ((CHAR16 *)L"No space left on device\n"); + SendError (GDB_ENOSPACE); + return; + } + + // Write Address, length data at particular DR register + Status = EnableDebugRegister (SystemContext, Register, Address, Length, (UINTN)BreakType); + if (EFI_ERROR(Status)) { + + if (Status == EFI_UNSUPPORTED) { + Print ((CHAR16 *)L"Not supported\n"); + SendNotSupported (); + return; + } + + Print ((CHAR16 *)L"Invalid argument\n"); + SendError (GDB_EINVALIDARG); + return; + } + + SendSuccess (); +} + + +/** + ‘z1, [addr], [length]’ + ‘z2, [addr], [length]’ + ‘z3, [addr], [length]’ + ‘z4, [addr], [length]’ + + Remove hardware breakpoint/watchpoint at address addr of size length + + @param *PacketData Pointer to the Payload data for the packet + +**/ +VOID +EFIAPI +RemoveBreakPoint ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ) +{ + UINTN Type; + UINTN Address; + UINTN Length; + UINTN Register; + BREAK_TYPE BreakType = NotSupported; + EFI_STATUS Status; + UINTN ErrorCode; + + //Parse breakpoint packet data + ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length); + if (ErrorCode > 0) { + SendError ((UINT8)ErrorCode); + return; + } + + switch (Type) { + + case 0: //Software breakpoint + BreakType = SoftwareBreakpoint; + break; + + case 1: //Hardware breakpoint + BreakType = InstructionExecution; + break; + + case 2: //Write watchpoint + BreakType = DataWrite; + break; + + case 3: //Read watchpoint + BreakType = DataRead; + break; + + case 4: //Access watchpoint + BreakType = DataReadWrite; + break; + + default : + SendError (GDB_EINVALIDBRKPOINTTYPE); + return; + } + + //Find matching debug register + Status = FindMatchingDebugRegister (SystemContext, Address, Length, (UINTN)BreakType, &Register); + if (EFI_ERROR(Status)) { + + if (Status == EFI_UNSUPPORTED) { + Print ((CHAR16 *)L"Not supported.\n"); + SendNotSupported (); + return; + } + + Print ((CHAR16 *)L"No matching register found.\n"); + SendError (GDB_ENOSPACE); + return; + } + + //Remove breakpoint + Status = DisableDebugRegister (SystemContext, Register); + if (EFI_ERROR(Status)) { + Print ((CHAR16 *)L"Invalid argument.\n"); + SendError (GDB_EINVALIDARG); + return; + } + + SendSuccess (); +} + + +VOID +InitializeProcessor ( + VOID + ) +{ +} + +BOOLEAN +ValidateAddress ( + IN VOID *Address + ) +{ + return TRUE; +} + +BOOLEAN +ValidateException ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + return TRUE; +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/SerialIo.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/SerialIo.c new file mode 100644 index 00000000..8a0352dc --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/SerialIo.c @@ -0,0 +1,547 @@ +/** @file + Serial IO Abstraction for GDB stub. This allows an EFI consoles that shows up on the system + running GDB. One console for error information and another console for user input/output. + + Basic packet format is $packet-data#checksum. So every command has 4 bytes of overhead: $, + #, 0, 0. The 0 and 0 are the ascii characters for the checksum. + + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +// +// Set TRUE if F Reply package signals a ctrl-c. We can not process the Ctrl-c +// here we need to wait for the periodic callback to do this. +// +BOOLEAN gCtrlCBreakFlag = FALSE; + +// +// If the periodic callback is called while we are processing an F packet we need +// to let the callback know to not read from the serial stream as it could steal +// characters from the F response packet +// +BOOLEAN gProcessingFPacket = FALSE; + +/** + Process a control-C break message. + + Currently a place holder, remove the ASSERT when it gets implemented. + + @param ErrNo Error information from the F reply packet or other source + +**/ + +VOID +GdbCtrlCBreakMessage ( + IN UINTN ErrNo + ) +{ + // See D.10.5 of gdb.pdf + // This should look like a break message. Should look like SIGINT + + /* TODO: Make sure if we should do anything with ErrNo */ + //Turn on the global Ctrl-C flag. + gCtrlCBreakFlag = TRUE; +} + + +/** + Parse the F reply packet and extract the return value and an ErrNo if it exists. + + @param Packet Packet to parse like an F reply packet + @param ErrNo Buffer to hold Count bytes that were read + + @retval -1 Error, not a valid F reply packet + @retval other Return the return code from the F reply packet + +**/ +INTN +GdbParseFReplyPacket ( + IN CHAR8 *Packet, + OUT UINTN *ErrNo + ) +{ + INTN RetCode; + + if (Packet[0] != 'F') { + // A valid response would be an F packet + return -1; + } + + RetCode = AsciiStrHexToUintn (&Packet[1]); + + // Find 1st comma + for (;*Packet != '\0' && *Packet != ','; Packet++); + if (*Packet == '\0') { + *ErrNo = 0; + return RetCode; + } + + *ErrNo = AsciiStrHexToUintn (++Packet); + + // Find 2nd comma + for (;*Packet != '\0' && *Packet != ','; Packet++); + if (*Packet == '\0') { + return RetCode; + } + + if (*(++Packet) == 'C') { + GdbCtrlCBreakMessage (*ErrNo); + } + + return RetCode; +} + + +/** + Read data from a FileDescriptor. On success number of bytes read is returned. Zero indicates + the end of a file. On error -1 is returned. If count is zero, GdbRead returns zero. + + @param FileDescriptor Device to talk to. + @param Buffer Buffer to hold Count bytes that were read + @param Count Number of bytes to transfer. + + @retval -1 Error + @retval {other} Number of bytes read. + +**/ +INTN +GdbRead ( + IN INTN FileDescriptor, + OUT VOID *Buffer, + IN UINTN Count + ) +{ + CHAR8 Packet[128]; + UINTN Size; + INTN RetCode; + UINTN ErrNo; + BOOLEAN ReceiveDone = FALSE; + + // Send: + // "Fread,XX,YYYYYYYY,XX + // + // XX - FileDescriptor in ASCII + // YYYYYYYY - Buffer address in ASCII + // XX - Count in ASCII + // SS - check sum + // + Size = AsciiSPrint (Packet, sizeof (Packet), "Fread,%x,%x,%x", FileDescriptor, Buffer, Count); + // Packet array is too small if you got this ASSERT + ASSERT (Size < sizeof (Packet)); + + gProcessingFPacket = TRUE; + SendPacket (Packet); + Print ((CHAR16 *)L"Packet sent..\n"); + + do { + // Reply: + ReceivePacket (Packet, sizeof (Packet)); + Print ((CHAR16 *)L"Command received..%c\n", Packet[0]); + + // Process GDB commands + switch (Packet[0]) { + //Write memory command. + //M addr,length:XX... + case 'M': + WriteToMemory (Packet); + break; + + //Fretcode, errno, Ctrl-C flag + //retcode - Count read + case 'F': + //Once target receives F reply packet that means the previous + //transactions are finished. + ReceiveDone = TRUE; + break; + + //Send empty buffer + default : + SendNotSupported(); + break; + } + } while (ReceiveDone == FALSE); + + RetCode = GdbParseFReplyPacket (Packet, &ErrNo); + Print ((CHAR16 *)L"RetCode: %x..ErrNo: %x..\n", RetCode, ErrNo); + + if (ErrNo > 0) { + //Send error to the host if there is any. + SendError ((UINT8)ErrNo); + } + + gProcessingFPacket = FALSE; + + return RetCode; +} + + +/** + Write data to a FileDescriptor. On success number of bytes written is returned. Zero indicates + nothing was written. On error -1 is returned. + + @param FileDescriptor Device to talk to. + @param Buffer Buffer to hold Count bytes that are to be written + @param Count Number of bytes to transfer. + + @retval -1 Error + @retval {other} Number of bytes written. + +**/ +INTN +GdbWrite ( + IN INTN FileDescriptor, + OUT CONST VOID *Buffer, + IN UINTN Count + ) +{ + CHAR8 Packet[128]; + UINTN Size; + INTN RetCode; + UINTN ErrNo; + BOOLEAN ReceiveDone = FALSE; + + // Send: + // #Fwrite,XX,YYYYYYYY,XX$SS + // + // XX - FileDescriptor in ASCII + // YYYYYYYY - Buffer address in ASCII + // XX - Count in ASCII + // SS - check sum + // + Size = AsciiSPrint (Packet, sizeof (Packet), "Fwrite,%x,%x,%x", FileDescriptor, Buffer, Count); + // Packet array is too small if you got this ASSERT + ASSERT (Size < sizeof (Packet)); + + SendPacket (Packet); + Print ((CHAR16 *)L"Packet sent..\n"); + + do { + // Reply: + ReceivePacket (Packet, sizeof (Packet)); + Print ((CHAR16 *)L"Command received..%c\n", Packet[0]); + + // Process GDB commands + switch (Packet[0]) { + //Read memory command. + //m addr,length. + case 'm': + ReadFromMemory (Packet); + break; + + //Fretcode, errno, Ctrl-C flag + //retcode - Count read + case 'F': + //Once target receives F reply packet that means the previous + //transactions are finished. + ReceiveDone = TRUE; + break; + + //Send empty buffer + default : + SendNotSupported(); + break; + } + } while (ReceiveDone == FALSE); + + RetCode = GdbParseFReplyPacket (Packet, &ErrNo); + Print ((CHAR16 *)L"RetCode: %x..ErrNo: %x..\n", RetCode, ErrNo); + + //Send error to the host if there is any. + if (ErrNo > 0) { + SendError((UINT8)ErrNo); + } + + return RetCode; +} + + +/** + Reset the serial device. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The serial device could not be reset. + +**/ +EFI_STATUS +EFIAPI +GdbSerialReset ( + IN EFI_SERIAL_IO_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} + + +/** + Sets the baud rate, receive FIFO depth, transmit/receive time out, parity, + data buts, and stop bits on a serial device. + + @param This Protocol instance pointer. + @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the + device's default interface speed. + @param ReceiveFifoDepth The requested depth of the FIFO on the receive side of the + serial interface. A ReceiveFifoDepth value of 0 will use + the device's default FIFO depth. + @param Timeout The requested time out for a single character in microseconds. + This timeout applies to both the transmit and receive side of the + interface. A Timeout value of 0 will use the device's default time + out value. + @param Parity The type of parity to use on this serial device. A Parity value of + DefaultParity will use the device's default parity value. + @param DataBits The number of data bits to use on the serial device. A DataBits + value of 0 will use the device's default data bit setting. + @param StopBits The number of stop bits to use on this serial device. A StopBits + value of DefaultStopBits will use the device's default number of + stop bits. + + @retval EFI_SUCCESS The device was reset. + @retval EFI_DEVICE_ERROR The serial device could not be reset. + +**/ +EFI_STATUS +EFIAPI +GdbSerialSetAttributes ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT64 BaudRate, + IN UINT32 ReceiveFifoDepth, + IN UINT32 Timeout, + IN EFI_PARITY_TYPE Parity, + IN UINT8 DataBits, + IN EFI_STOP_BITS_TYPE StopBits + ) +{ + return EFI_UNSUPPORTED; +} + + +/** + Set the control bits on a serial device + + @param This Protocol instance pointer. + @param Control Set the bits of Control that are settable. + + @retval EFI_SUCCESS The new control bits were set on the serial device. + @retval EFI_UNSUPPORTED The serial device does not support this operation. + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +EFI_STATUS +EFIAPI +GdbSerialSetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT32 Control + ) +{ + return EFI_UNSUPPORTED; +} + + +/** + Retrieves the status of the control bits on a serial device + + @param This Protocol instance pointer. + @param Control A pointer to return the current Control signals from the serial device. + + @retval EFI_SUCCESS The control bits were read from the serial device. + @retval EFI_DEVICE_ERROR The serial device is not functioning correctly. + +**/ +EFI_STATUS +EFIAPI +GdbSerialGetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + OUT UINT32 *Control + ) +{ + return EFI_UNSUPPORTED; +} + + +/** + Writes data to a serial device. + + @param This Protocol instance pointer. + @param BufferSize On input, the size of the Buffer. On output, the amount of + data actually written. + @param Buffer The buffer of data to write + + @retval EFI_SUCCESS The data was written. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_TIMEOUT The data write was stopped due to a timeout. + +**/ +EFI_STATUS +EFIAPI +GdbSerialWrite ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + GDB_SERIAL_DEV *SerialDev; + UINTN Return; + + SerialDev = GDB_SERIAL_DEV_FROM_THIS (This); + + Return = GdbWrite (SerialDev->OutFileDescriptor, Buffer, *BufferSize); + if (Return == (UINTN)-1) { + return EFI_DEVICE_ERROR; + } + + if (Return != *BufferSize) { + *BufferSize = Return; + } + + return EFI_SUCCESS; +} + +/** + Writes data to a serial device. + + @param This Protocol instance pointer. + @param BufferSize On input, the size of the Buffer. On output, the amount of + data returned in Buffer. + @param Buffer The buffer to return the data into. + + @retval EFI_SUCCESS The data was read. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_TIMEOUT The data write was stopped due to a timeout. + +**/ + +EFI_STATUS +EFIAPI +GdbSerialRead ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + GDB_SERIAL_DEV *SerialDev; + UINTN Return; + + SerialDev = GDB_SERIAL_DEV_FROM_THIS (This); + + Return = GdbRead (SerialDev->InFileDescriptor, Buffer, *BufferSize); + if (Return == (UINTN)-1) { + return EFI_DEVICE_ERROR; + } + + if (Return != *BufferSize) { + *BufferSize = Return; + } + + return EFI_SUCCESS; +} + + +// +// Template used to initialize the GDB Serial IO protocols +// +GDB_SERIAL_DEV gdbSerialDevTemplate = { + GDB_SERIAL_DEV_SIGNATURE, + NULL, + + { // SerialIo + SERIAL_IO_INTERFACE_REVISION, + GdbSerialReset, + GdbSerialSetAttributes, + GdbSerialSetControl, + GdbSerialGetControl, + GdbSerialWrite, + GdbSerialRead, + NULL + }, + { // SerialMode + 0, // ControlMask + 0, // Timeout + 0, // BaudRate + 1, // RceiveFifoDepth + 0, // DataBits + 0, // Parity + 0 // StopBits + }, + { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH) + sizeof (UINT32)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH) + sizeof (UINT32)) >> 8) + }, + }, + EFI_SERIAL_IO_PROTOCOL_GUID + }, + 0, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)), + (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL) >> 8) + } + }, + }, + GDB_STDIN, + GDB_STDOUT +}; + + +/** + Make two serial consoles: 1) StdIn and StdOut via GDB. 2) StdErr via GDB. + + These console show up on the remote system running GDB + +**/ +VOID +GdbInitializeSerialConsole ( + VOID + ) +{ + EFI_STATUS Status; + GDB_SERIAL_DEV *StdOutSerialDev; + GDB_SERIAL_DEV *StdErrSerialDev; + + // Use the template to make a copy of the Serial Console private data structure. + StdOutSerialDev = AllocateCopyPool (sizeof (GDB_SERIAL_DEV), &gdbSerialDevTemplate); + ASSERT (StdOutSerialDev != NULL); + + // Fixup pointer after the copy + StdOutSerialDev->SerialIo.Mode = &StdOutSerialDev->SerialMode; + + StdErrSerialDev = AllocateCopyPool (sizeof (GDB_SERIAL_DEV), &gdbSerialDevTemplate); + ASSERT (StdErrSerialDev != NULL); + + // Fixup pointer and modify stuff that is different for StdError + StdErrSerialDev->SerialIo.Mode = &StdErrSerialDev->SerialMode; + StdErrSerialDev->DevicePath.Index = 1; + StdErrSerialDev->OutFileDescriptor = GDB_STDERR; + + // Make a new handle with Serial IO protocol and its device path on it. + Status = gBS->InstallMultipleProtocolInterfaces ( + &StdOutSerialDev->Handle, + &gEfiSerialIoProtocolGuid, &StdOutSerialDev->SerialIo, + &gEfiDevicePathProtocolGuid, &StdOutSerialDev->DevicePath, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // Make a new handle with Serial IO protocol and its device path on it. + Status = gBS->InstallMultipleProtocolInterfaces ( + &StdErrSerialDev->Handle, + &gEfiSerialIoProtocolGuid, &StdErrSerialDev->SerialIo, + &gEfiDevicePathProtocolGuid, &StdErrSerialDev->DevicePath, + NULL + ); + ASSERT_EFI_ERROR (Status); +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/X64/Processor.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/X64/Processor.c new file mode 100644 index 00000000..826e95a8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/GdbStub/X64/Processor.c @@ -0,0 +1,957 @@ +/** @file + Processor specific parts of the GDB stub + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +// +// Array of exception types that need to be hooked by the debugger +// +EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = { + { EXCEPT_X64_DIVIDE_ERROR, GDB_SIGFPE }, + { EXCEPT_X64_DEBUG, GDB_SIGTRAP }, + { EXCEPT_X64_NMI, GDB_SIGEMT }, + { EXCEPT_X64_BREAKPOINT, GDB_SIGTRAP }, + { EXCEPT_X64_OVERFLOW, GDB_SIGSEGV }, + { EXCEPT_X64_BOUND, GDB_SIGSEGV }, + { EXCEPT_X64_INVALID_OPCODE, GDB_SIGILL }, + { EXCEPT_X64_DOUBLE_FAULT, GDB_SIGEMT }, + { EXCEPT_X64_STACK_FAULT, GDB_SIGSEGV }, + { EXCEPT_X64_GP_FAULT, GDB_SIGSEGV }, + { EXCEPT_X64_PAGE_FAULT, GDB_SIGSEGV }, + { EXCEPT_X64_FP_ERROR, GDB_SIGEMT }, + { EXCEPT_X64_ALIGNMENT_CHECK, GDB_SIGEMT }, + { EXCEPT_X64_MACHINE_CHECK, GDB_SIGEMT } +}; + + +// The offsets of registers SystemContextX64. +// The fields in the array are in the gdb ordering. +// HAVE TO DOUBLE-CHECK THE ORDER of the 24 regs +// +UINTN gRegisterOffsets[] = { + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rax), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rcx), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rdx), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rbx), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rsp), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rbp), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rsi), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rdi), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rip), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rflags), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Cs), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Ss), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Ds), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Es), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Fs), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Gs), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R8), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R9), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R10), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R11), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R12), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R13), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R14), + OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R15) +}; + + +/** + Return the number of entries in the gExceptionType[] + + @retval UINTN, the number of entries in the gExceptionType[] array. + **/ +UINTN +MaxEfiException ( + VOID + ) +{ + return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY); +} + + +/** + Return the number of entries in the gRegisters[] + + @retval UINTN, the number of entries (registers) in the gRegisters[] array. + **/ +UINTN +MaxRegisterCount ( + VOID + ) +{ + return sizeof (gRegisterOffsets)/sizeof (UINTN); +} + + +/** + Check to see if the ISA is supported. + ISA = Instruction Set Architecture + + @retval TRUE if Isa is supported +**/ +BOOLEAN +CheckIsa ( + IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa + ) +{ + return (BOOLEAN)(Isa == IsaX64); +} + + +/** + This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering + It is, by default, set to find the register pointer of the X64 member + @param SystemContext Register content at time of the exception + @param RegNumber The register to which we want to find a pointer + @retval the pointer to the RegNumber-th pointer + **/ +UINTN * +FindPointerToRegister( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN RegNumber + ) +{ + UINT8 *TempPtr; + TempPtr = ((UINT8 *)SystemContext.SystemContextX64) + gRegisterOffsets[RegNumber]; + return (UINTN *)TempPtr; +} + + +/** + Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr + @param SystemContext Register content at time of the exception + @param RegNumber the number of the register that we want to read + @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on. + @retval the pointer to the next character of the output buffer that is available to be written on. + **/ +CHAR8 * +BasicReadRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN RegNumber, + IN CHAR8 *OutBufPtr + ) +{ + UINTN RegSize; + + RegSize = 0; + while (RegSize < 64) { + *OutBufPtr++ = mHexToStr[((*FindPointerToRegister(SystemContext, RegNumber) >> (RegSize+4)) & 0xf)]; + *OutBufPtr++ = mHexToStr[((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)]; + RegSize = RegSize + 8; + } + return OutBufPtr; +} + + +/** ‘p n’ + Reads the n-th register's value into an output buffer and sends it as a packet + @param SystemContext Register content at time of the exception + @param InBuffer Pointer to the input buffer received from gdb server + **/ +VOID +ReadNthRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ) +{ + UINTN RegNumber; + CHAR8 OutBuffer[17]; // 1 reg=16 hex chars, and the end '\0' (escape seq) + CHAR8 *OutBufPtr; // pointer to the output buffer + + RegNumber = AsciiStrHexToUintn (&InBuffer[1]); + + if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount())) { + SendError (GDB_EINVALIDREGNUM); + return; + } + + OutBufPtr = OutBuffer; + OutBufPtr = BasicReadRegister(SystemContext, RegNumber, OutBufPtr); + + *OutBufPtr = '\0'; // the end of the buffer + SendPacket (OutBuffer); +} + + +/** ‘g’ + Reads the general registers into an output buffer and sends it as a packet + + @param SystemContext Register content at time of the exception + **/ +VOID +EFIAPI +ReadGeneralRegisters ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + UINTN i; + CHAR8 OutBuffer[385]; // 24 regs, 16 hex chars each, and the end '\0' (escape seq) + CHAR8 *OutBufPtr; // pointer to the output buffer + + OutBufPtr = OutBuffer; + for(i = 0 ; i < MaxRegisterCount() ; i++) { // there are only 24 registers to read + OutBufPtr = BasicReadRegister(SystemContext, i, OutBufPtr); + } + + *OutBufPtr = '\0'; // the end of the buffer + SendPacket (OutBuffer); +} + + +/** + Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr + + @param SystemContext Register content at time of the exception + @param RegNumber the number of the register that we want to write + @param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on. + @retval the pointer to the next character of the input buffer that can be used + **/ +CHAR8 * +BasicWriteRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN RegNumber, + IN CHAR8 *InBufPtr + ) +{ + UINTN RegSize; + UINTN TempValue; // the value transferred from a hex char + UINT64 NewValue; // the new value of the RegNumber-th Register + + NewValue = 0; + RegSize = 0; + while (RegSize < 64) { + TempValue = HexCharToInt(*InBufPtr++); + + if (TempValue < 0) { + SendError (GDB_EBADMEMDATA); + return NULL; + } + + NewValue += (TempValue << (RegSize+4)); + TempValue = HexCharToInt(*InBufPtr++); + + if (TempValue < 0) { + SendError (GDB_EBADMEMDATA); + return NULL; + } + + NewValue += (TempValue << RegSize); + RegSize = RegSize + 8; + } + *(FindPointerToRegister(SystemContext, RegNumber)) = NewValue; + return InBufPtr; +} + + +/** ‘P n...=r...’ + Writes the new value of n-th register received into the input buffer to the n-th register + + @param SystemContext Register content at time of the exception + @param InBuffer Pointer to the input buffer received from gdb server + **/ +VOID +EFIAPI +WriteNthRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ) +{ + UINTN RegNumber; + CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array + CHAR8 *RegNumBufPtr; + CHAR8 *InBufPtr; // pointer to the input buffer + + // find the register number to write + InBufPtr = &InBuffer[1]; + RegNumBufPtr = RegNumBuffer; + while (*InBufPtr != '=') { + *RegNumBufPtr++ = *InBufPtr++; + } + *RegNumBufPtr = '\0'; + RegNumber = AsciiStrHexToUintn (RegNumBuffer); + + // check if this is a valid Register Number + if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount())) { + SendError (GDB_EINVALIDREGNUM); + return; + } + InBufPtr++; // skips the '=' character + BasicWriteRegister (SystemContext, RegNumber, InBufPtr); + SendSuccess(); +} + + +/** ‘G XX...’ + Writes the new values received into the input buffer to the general registers + + @param SystemContext Register content at time of the exception + @param InBuffer Pointer to the input buffer received from gdb server + **/ +VOID +EFIAPI +WriteGeneralRegisters ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ) +{ + UINTN i; + CHAR8 *InBufPtr; /// pointer to the input buffer + + // check to see if the buffer is the right size which is + // 1 (for 'G') + 16 (for 16 registers) * 8 ( for 8 hex chars each) = 385 + if (AsciiStrLen(InBuffer) != 385) { // 24 regs, 16 hex chars each, and the end '\0' (escape seq) + //Bad message. Message is not the right length + SendError (GDB_EBADBUFSIZE); + return; + } + + InBufPtr = &InBuffer[1]; + + // Read the new values for the registers from the input buffer to an array, NewValueArray. + // The values in the array are in the gdb ordering + for(i=0; i < MaxRegisterCount(); i++) { // there are only 16 registers to write + InBufPtr = BasicWriteRegister(SystemContext, i, InBufPtr); + } + + SendSuccess(); +} + + + /** + Insert Single Step in the SystemContext + + @param SystemContext Register content at time of the exception + **/ +VOID +AddSingleStep ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + SystemContext.SystemContextX64->Rflags |= TF_BIT; //Setting the TF bit. +} + + + +/** + Remove Single Step in the SystemContext + + @param SystemContext Register content at time of the exception + **/ +VOID +RemoveSingleStep ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + SystemContext.SystemContextX64->Rflags &= ~TF_BIT; // clearing the TF bit. +} + + + +/** ‘c [addr ]’ + Continue. addr is Address to resume. If addr is omitted, resume at current + Address. + + @param SystemContext Register content at time of the exception + **/ +VOID +EFIAPI +ContinueAtAddress ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ) +{ + if (PacketData[1] != '\0') { + SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn(&PacketData[1]); + } +} + + +/** ‘s [addr ]’ + Single step. addr is the Address at which to resume. If addr is omitted, resume + at same Address. + + @param SystemContext Register content at time of the exception + **/ +VOID +EFIAPI +SingleStep ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ) +{ + if (PacketData[1] != '\0') { + SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn (&PacketData[1]); + } + + AddSingleStep (SystemContext); +} + + +/** + Returns breakpoint data address from DR0-DR3 based on the input breakpoint + number + + @param SystemContext Register content at time of the exception + @param BreakpointNumber Breakpoint number + + @retval Address Data address from DR0-DR3 based on the + breakpoint number. + +**/ +UINTN +GetBreakpointDataAddress ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN BreakpointNumber + ) +{ + UINTN Address; + + if (BreakpointNumber == 1) { + Address = SystemContext.SystemContextIa32->Dr0; + } else if (BreakpointNumber == 2) { + Address = SystemContext.SystemContextIa32->Dr1; + } else if (BreakpointNumber == 3) { + Address = SystemContext.SystemContextIa32->Dr2; + } else if (BreakpointNumber == 4) { + Address = SystemContext.SystemContextIa32->Dr3; + } else { + Address = 0; + } + + return Address; +} + +/** + Returns currently detected breakpoint value based on the register + DR6 B0-B3 field. + If no breakpoint is detected then it returns 0. + + @param SystemContext Register content at time of the exception + + @retval {1-4} Currently detected breakpoint value + @retval 0 No breakpoint detected. + +**/ +UINTN +GetBreakpointDetected ( + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + IA32_DR6 Dr6; + UINTN BreakpointNumber; + + Dr6.UintN = SystemContext.SystemContextIa32->Dr6; + + if (Dr6.Bits.B0 == 1) { + BreakpointNumber = 1; + } else if (Dr6.Bits.B1 == 1) { + BreakpointNumber = 2; + } else if (Dr6.Bits.B2 == 1) { + BreakpointNumber = 3; + } else if (Dr6.Bits.B3 == 1) { + BreakpointNumber = 4; + } else { + BreakpointNumber = 0; //No breakpoint detected + } + + return BreakpointNumber; +} + +/** + Returns Breakpoint type (InstructionExecution, DataWrite, DataRead + or DataReadWrite) based on the Breakpoint number + + @param SystemContext Register content at time of the exception + @param BreakpointNumber Breakpoint number + + @retval BREAK_TYPE Breakpoint type value read from register DR7 RWn + field. For unknown value, it returns NotSupported. + +**/ +BREAK_TYPE +GetBreakpointType ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN BreakpointNumber + ) +{ + IA32_DR7 Dr7; + BREAK_TYPE Type = NotSupported; //Default is NotSupported type + + Dr7.UintN = SystemContext.SystemContextIa32->Dr7; + + if (BreakpointNumber == 1) { + Type = (BREAK_TYPE) Dr7.Bits.RW0; + } else if (BreakpointNumber == 2) { + Type = (BREAK_TYPE) Dr7.Bits.RW1; + } else if (BreakpointNumber == 3) { + Type = (BREAK_TYPE) Dr7.Bits.RW2; + } else if (BreakpointNumber == 4) { + Type = (BREAK_TYPE) Dr7.Bits.RW3; + } + + return Type; +} + + +/** + Parses Length and returns the length which DR7 LENn field accepts. + For example: If we receive 1-Byte length then we should return 0. + Zero gets written to DR7 LENn field. + + @param Length Breakpoint length in Bytes (1 byte, 2 byte, 4 byte) + + @retval Length Appropriate converted values which DR7 LENn field accepts. + +**/ +UINTN +ConvertLengthData ( + IN UINTN Length + ) +{ + if (Length == 1) { //1-Byte length + return 0; + } else if (Length == 2) { //2-Byte length + return 1; + } else if (Length == 4) { //4-Byte length + return 3; + } else { //Undefined or 8-byte length + return 2; + } +} + + +/** + Finds the next free debug register. If all the registers are occupied then + EFI_OUT_OF_RESOURCES is returned. + + @param SystemContext Register content at time of the exception + @param Register Register value (0 - 3 for the first free debug register) + + @retval EFI_STATUS Appropriate status value. + +**/ +EFI_STATUS +FindNextFreeDebugRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + OUT UINTN *Register + ) +{ + IA32_DR7 Dr7; + + Dr7.UintN = SystemContext.SystemContextIa32->Dr7; + + if (Dr7.Bits.G0 == 0) { + *Register = 0; + } else if (Dr7.Bits.G1 == 0) { + *Register = 1; + } else if (Dr7.Bits.G2 == 0) { + *Register = 2; + } else if (Dr7.Bits.G3 == 0) { + *Register = 3; + } else { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + + +/** + Enables the debug register. Writes Address value to appropriate DR0-3 register. + Sets LENn, Gn, RWn bits in DR7 register. + + @param SystemContext Register content at time of the exception + @param Register Register value (0 - 3) + @param Address Breakpoint address value + @param Type Breakpoint type (Instruction, Data write, + Data read or write etc.) + + @retval EFI_STATUS Appropriate status value. + +**/ +EFI_STATUS +EnableDebugRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN Register, + IN UINTN Address, + IN UINTN Length, + IN UINTN Type + ) +{ + IA32_DR7 Dr7; + + //Convert length data + Length = ConvertLengthData (Length); + + //For Instruction execution, length should be 0 + //(Ref. Intel reference manual 18.2.4) + if ((Type == 0) && (Length != 0)) { + return EFI_INVALID_PARAMETER; + } + + //Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle + //software breakpoint. We should send empty packet in both these cases. + if ((Type == (BREAK_TYPE)DataRead) || + (Type == (BREAK_TYPE)SoftwareBreakpoint)) { + return EFI_UNSUPPORTED; + } + + //Read DR7 so appropriate Gn, RWn and LENn bits can be modified. + Dr7.UintN = SystemContext.SystemContextIa32->Dr7; + + if (Register == 0) { + SystemContext.SystemContextIa32->Dr0 = Address; + Dr7.Bits.G0 = 1; + Dr7.Bits.RW0 = Type; + Dr7.Bits.LEN0 = Length; + } else if (Register == 1) { + SystemContext.SystemContextIa32->Dr1 = Address; + Dr7.Bits.G1 = 1; + Dr7.Bits.RW1 = Type; + Dr7.Bits.LEN1 = Length; + } else if (Register == 2) { + SystemContext.SystemContextIa32->Dr2 = Address; + Dr7.Bits.G2 = 1; + Dr7.Bits.RW2 = Type; + Dr7.Bits.LEN2 = Length; + } else if (Register == 3) { + SystemContext.SystemContextIa32->Dr3 = Address; + Dr7.Bits.G3 = 1; + Dr7.Bits.RW3 = Type; + Dr7.Bits.LEN3 = Length; + } else { + return EFI_INVALID_PARAMETER; + } + + //Update Dr7 with appropriate Gn, RWn and LENn bits + SystemContext.SystemContextIa32->Dr7 = Dr7.UintN; + + return EFI_SUCCESS; +} + + +/** + Returns register number 0 - 3 for the matching debug register. + This function compares incoming Address, Type, Length and + if there is a match then it returns the appropriate register number. + In case of mismatch, function returns EFI_NOT_FOUND message. + + @param SystemContext Register content at time of the exception + @param Address Breakpoint address value + @param Length Breakpoint length value + @param Type Breakpoint type (Instruction, Data write, Data read + or write etc.) + @param Register Register value to be returned + + @retval EFI_STATUS Appropriate status value. + +**/ +EFI_STATUS +FindMatchingDebugRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN Address, + IN UINTN Length, + IN UINTN Type, + OUT UINTN *Register + ) +{ + IA32_DR7 Dr7; + + //Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle + //software breakpoint. We should send empty packet in both these cases. + if ((Type == (BREAK_TYPE)DataRead) || + (Type == (BREAK_TYPE)SoftwareBreakpoint)) { + return EFI_UNSUPPORTED; + } + + //Convert length data + Length = ConvertLengthData(Length); + + Dr7.UintN = SystemContext.SystemContextIa32->Dr7; + + if ((Dr7.Bits.G0 == 1) && + (Dr7.Bits.LEN0 == Length) && + (Dr7.Bits.RW0 == Type) && + (Address == SystemContext.SystemContextIa32->Dr0)) { + *Register = 0; + } else if ((Dr7.Bits.G1 == 1) && + (Dr7.Bits.LEN1 == Length) && + (Dr7.Bits.RW1 == Type) && + (Address == SystemContext.SystemContextIa32->Dr1)) { + *Register = 1; + } else if ((Dr7.Bits.G2 == 1) && + (Dr7.Bits.LEN2 == Length) && + (Dr7.Bits.RW2 == Type) && + (Address == SystemContext.SystemContextIa32->Dr2)) { + *Register = 2; + } else if ((Dr7.Bits.G3 == 1) && + (Dr7.Bits.LEN3 == Length) && + (Dr7.Bits.RW3 == Type) && + (Address == SystemContext.SystemContextIa32->Dr3)) { + *Register = 3; + } else { + Print ((CHAR16 *)L"No match found..\n"); + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + + +/** + Disables the particular debug register. + + @param SystemContext Register content at time of the exception + @param Register Register to be disabled + + @retval EFI_STATUS Appropriate status value. + +**/ +EFI_STATUS +DisableDebugRegister ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN UINTN Register + ) +{ + IA32_DR7 Dr7; + UINTN Address = 0; + + //Read DR7 register so appropriate Gn, RWn and LENn bits can be turned off. + Dr7.UintN = SystemContext.SystemContextIa32->Dr7; + + if (Register == 0) { + SystemContext.SystemContextIa32->Dr0 = Address; + Dr7.Bits.G0 = 0; + Dr7.Bits.RW0 = 0; + Dr7.Bits.LEN0 = 0; + } else if (Register == 1) { + SystemContext.SystemContextIa32->Dr1 = Address; + Dr7.Bits.G1 = 0; + Dr7.Bits.RW1 = 0; + Dr7.Bits.LEN1 = 0; + } else if (Register == 2) { + SystemContext.SystemContextIa32->Dr2 = Address; + Dr7.Bits.G2 = 0; + Dr7.Bits.RW2 = 0; + Dr7.Bits.LEN2 = 0; + } else if (Register == 3) { + SystemContext.SystemContextIa32->Dr3 = Address; + Dr7.Bits.G3 = 0; + Dr7.Bits.RW3 = 0; + Dr7.Bits.LEN3 = 0; + } else { + return EFI_INVALID_PARAMETER; + } + + //Update DR7 register so appropriate Gn, RWn and LENn bits can be turned off. + SystemContext.SystemContextIa32->Dr7 = Dr7.UintN; + + return EFI_SUCCESS; +} + +/** + ‘Z1, [addr], [length]’ + ‘Z2, [addr], [length]’ + ‘Z3, [addr], [length]’ + ‘Z4, [addr], [length]’ + + Insert hardware breakpoint/watchpoint at address addr of size length + + @param SystemContext Register content at time of the exception + @param *PacketData Pointer to the Payload data for the packet + +**/ +VOID +EFIAPI +InsertBreakPoint ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ) +{ + UINTN Type; + UINTN Address; + UINTN Length; + UINTN Register; + EFI_STATUS Status; + BREAK_TYPE BreakType = NotSupported; + UINTN ErrorCode; + + ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length); + if (ErrorCode > 0) { + SendError ((UINT8)ErrorCode); + return; + } + + switch (Type) { + + case 0: //Software breakpoint + BreakType = SoftwareBreakpoint; + break; + + case 1: //Hardware breakpoint + BreakType = InstructionExecution; + break; + + case 2: //Write watchpoint + BreakType = DataWrite; + break; + + case 3: //Read watchpoint + BreakType = DataRead; + break; + + case 4: //Access watchpoint + BreakType = DataReadWrite; + break; + + default : + Print ((CHAR16 *)L"Insert breakpoint default: %x\n", Type); + SendError (GDB_EINVALIDBRKPOINTTYPE); + return; + } + + // Find next free debug register + Status = FindNextFreeDebugRegister (SystemContext, &Register); + if (EFI_ERROR(Status)) { + Print ((CHAR16 *)L"No space left on device\n"); + SendError (GDB_ENOSPACE); + return; + } + + // Write Address, length data at particular DR register + Status = EnableDebugRegister (SystemContext, Register, Address, Length, (UINTN)BreakType); + if (EFI_ERROR(Status)) { + + if (Status == EFI_UNSUPPORTED) { + Print ((CHAR16 *)L"Not supported\n"); + SendNotSupported(); + return; + } + + Print ((CHAR16 *)L"Invalid argument\n"); + SendError (GDB_EINVALIDARG); + return; + } + + SendSuccess (); +} + + +/** + ‘z1, [addr], [length]’ + ‘z2, [addr], [length]’ + ‘z3, [addr], [length]’ + ‘z4, [addr], [length]’ + + Remove hardware breakpoint/watchpoint at address addr of size length + + @param *PacketData Pointer to the Payload data for the packet + +**/ +VOID +EFIAPI +RemoveBreakPoint ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *PacketData + ) +{ + UINTN Type; + UINTN Address; + UINTN Length; + UINTN Register; + BREAK_TYPE BreakType = NotSupported; + EFI_STATUS Status; + UINTN ErrorCode; + + //Parse breakpoint packet data + ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length); + if (ErrorCode > 0) { + SendError ((UINT8)ErrorCode); + return; + } + + switch (Type) { + + case 0: //Software breakpoint + BreakType = SoftwareBreakpoint; + break; + + case 1: //Hardware breakpoint + BreakType = InstructionExecution; + break; + + case 2: //Write watchpoint + BreakType = DataWrite; + break; + + case 3: //Read watchpoint + BreakType = DataRead; + break; + + case 4: //Access watchpoint + BreakType = DataReadWrite; + break; + + default : + SendError (GDB_EINVALIDBRKPOINTTYPE); + return; + } + + //Find matching debug register + Status = FindMatchingDebugRegister (SystemContext, Address, Length, (UINTN)BreakType, &Register); + if (EFI_ERROR(Status)) { + + if (Status == EFI_UNSUPPORTED) { + Print ((CHAR16 *)L"Not supported.\n"); + SendNotSupported(); + return; + } + + Print ((CHAR16 *)L"No matching register found.\n"); + SendError (GDB_ENOSPACE); + return; + } + + //Remove breakpoint + Status = DisableDebugRegister(SystemContext, Register); + if (EFI_ERROR(Status)) { + Print ((CHAR16 *)L"Invalid argument.\n"); + SendError (GDB_EINVALIDARG); + return; + } + + SendSuccess (); +} + + +VOID +InitializeProcessor ( + VOID + ) +{ +} + +BOOLEAN +ValidateAddress ( + IN VOID *Address + ) +{ + return TRUE; +} + +BOOLEAN +ValidateException ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + return TRUE; +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/ConsolePrefFormSet.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/ConsolePrefFormSet.h new file mode 100644 index 00000000..4423f6a6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/ConsolePrefFormSet.h @@ -0,0 +1,17 @@ +/** @file +* +* Copyright (c) 2017, Linaro Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __CONSOLE_PREF_FORMSET_H__ +#define __CONSOLE_PREF_FORMSET_H__ + +#define CONSOLE_PREF_FORMSET_GUID \ + { 0x2d2358b4, 0xe96c, 0x484d, { 0xb2, 0xdd, 0x7c, 0x2e, 0xdf, 0xc7, 0xd5, 0x6f } } + +extern EFI_GUID gConsolePrefFormSetGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/DtPlatformDefaultDtbFile.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/DtPlatformDefaultDtbFile.h new file mode 100644 index 00000000..facc9fc1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/DtPlatformDefaultDtbFile.h @@ -0,0 +1,17 @@ +/** @file +* +* Copyright (c) 2017, Linaro Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __DT_PLATFORM_DEFAULT_DTB_FILE_H__ +#define __DT_PLATFORM_DEFAULT_DTB_FILE_H__ + +#define DT_PLATFORM_DEFAULT_DTB_FILE_GUID \ + { 0x25462cda, 0x221f, 0x47df, { 0xac, 0x1d, 0x25, 0x9c, 0xfa, 0xa4, 0xe3, 0x26 } } + +extern EFI_GUID gDtPlatformDefaultDtbFileGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/DtPlatformFormSet.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/DtPlatformFormSet.h new file mode 100644 index 00000000..141ae9e5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/DtPlatformFormSet.h @@ -0,0 +1,17 @@ +/** @file +* +* Copyright (c) 2017, Linaro Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __DT_PLATFORM_FORMSET_H__ +#define __DT_PLATFORM_FORMSET_H__ + +#define DT_PLATFORM_FORMSET_GUID \ + { 0x2b7a240d, 0xd5ad, 0x4fd6, { 0xbe, 0x1c, 0xdf, 0xa4, 0x41, 0x5f, 0x55, 0x26 } } + +extern EFI_GUID gDtPlatformFormSetGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/ExtractSection.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/ExtractSection.h new file mode 100644 index 00000000..aca7da59 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/ExtractSection.h @@ -0,0 +1,30 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __EXTRACT_SECTION_GUID_H__ +#define __EXTRACT_SECTION_GUID_H__ + +#include + + +// +// The GUID for this protocol mathes the Decompression scheme being used +// So for example LZMA would be gLzmaCustomDecompressGuid +// +typedef struct { + EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER SectionGetInfo; + EXTRACT_GUIDED_SECTION_DECODE_HANDLER SectionExtraction; +} EXTRACT_SECTION_DATA; + +typedef struct { + EFI_HOB_GUID_TYPE Hob; + EXTRACT_SECTION_DATA Data; +} EXTRACT_SECTION_HOB; + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/Fdt.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/Fdt.h new file mode 100644 index 00000000..cdebb77a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/Fdt.h @@ -0,0 +1,22 @@ +/** @file +* +* Copyright (c) 2013-2014, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __FDT_H__ +#define __FDT_H__ + +#define FDT_TABLE_GUID \ + { 0xb1b621d5, 0xf19c, 0x41a5, { 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } } + +extern EFI_GUID gFdtTableGuid; + +#define FDT_VARIABLE_GUID \ + { 0x25a4fd4a, 0x9703, 0x4ba9, { 0xa1, 0x90, 0xb7, 0xc8, 0x4e, 0xfb, 0x3e, 0x57 } } + +extern EFI_GUID gFdtVariableGuid; + +#endif /* __FDT_H__ */ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/FdtHob.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/FdtHob.h new file mode 100644 index 00000000..ac0b11ed --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/FdtHob.h @@ -0,0 +1,20 @@ +/** @file + GUID for the HOB that contains the copy of the flattened device tree blob + + Copyright (C) 2014, Linaro Ltd. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __FDT_HOB_H__ +#define __FDT_HOB_H__ + +#define FDT_HOB_GUID { \ + 0x16958446, 0x19B7, 0x480B, \ + { 0xB0, 0x47, 0x74, 0x85, 0xAD, 0x3F, 0x71, 0x6D } \ + } + +extern EFI_GUID gFdtHobGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/NvVarStoreFormatted.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/NvVarStoreFormatted.h new file mode 100644 index 00000000..16eb90ac --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/NvVarStoreFormatted.h @@ -0,0 +1,33 @@ +/** @file + EDKII NvVarStore Formatted GUID + + A NULL protocol instance with this GUID in the DXE and/or MM protocol + databases, and/or a NULL PPI with this GUID in the PPI database, implies that + a DXE or MM driver, or a PEIM, has verified (or dynamically ensured) that the + non-volatile variable store has valid and consistent headers + (EFI_FIRMWARE_VOLUME_HEADER and VARIABLE_STORE_HEADER). + + Said predicate is required by the read-only variable PEIM, and the read side + of the runtime variable DXE and MM drivers, immediately after they are + dispatched. This GUID presents platforms with one way to coordinate between + their module(s) that format the variable store FVB device and the variable + service drivers. + + Copyright (C) 2018, Red Hat, Inc. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + + +#ifndef __EDKII_NV_VAR_STORE_FORMATTED_H__ +#define __EDKII_NV_VAR_STORE_FORMATTED_H__ + +#define EDKII_NV_VAR_STORE_FORMATTED_GUID \ + { \ + 0xd1a86e3f, 0x0707, 0x4c35, \ + { 0x83, 0xcd, 0xdc, 0x2c, 0x29, 0xc8, 0x91, 0xa3 } \ + } + +extern EFI_GUID gEdkiiNvVarStoreFormattedGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/PlatformHasDeviceTree.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/PlatformHasDeviceTree.h new file mode 100644 index 00000000..640533e2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Guid/PlatformHasDeviceTree.h @@ -0,0 +1,29 @@ +/** @file + EDKII Platform Has Device Tree GUID + + A NULL protocol instance with this GUID in the DXE protocol database, and/or + a NULL PPI with this GUID in the PPI database, implies that the platform + provides the operating system with a Device Tree-based hardware description. + Note that this is not necessarily exclusive with different kinds of hardware + description (for example, an ACPI-based one). A platform driver and/or PEIM + is supposed to produce a single instance of the protocol and/or PPI (with + NULL contents), if appropriate. + + Copyright (C) 2017, Red Hat, Inc. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + + +#ifndef __EDKII_PLATFORM_HAS_DEVICE_TREE_H__ +#define __EDKII_PLATFORM_HAS_DEVICE_TREE_H__ + +#define EDKII_PLATFORM_HAS_DEVICE_TREE_GUID \ + { \ + 0x7ebb920d, 0x1aaf, 0x46d9, \ + { 0xb2, 0xaf, 0x54, 0x1e, 0x1d, 0xce, 0x14, 0x8b } \ + } + +extern EFI_GUID gEdkiiPlatformHasDeviceTreeGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/AcpiLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/AcpiLib.h new file mode 100644 index 00000000..de6cb3c3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/AcpiLib.h @@ -0,0 +1,131 @@ +/** @file + Helper Library for ACPI + + Copyright (c) 2014-2016, ARM Ltd. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __ACPI_LIB_H__ +#define __ACPI_LIB_H__ + +#include + +#include + +// +// Macros for the Generic Address Space +// +#define NULL_GAS { EFI_ACPI_5_0_SYSTEM_MEMORY, 0, 0, EFI_ACPI_5_0_UNDEFINED, 0L } +#define ARM_GAS8(Address) { EFI_ACPI_5_0_SYSTEM_MEMORY, 8, 0, EFI_ACPI_5_0_BYTE, Address } +#define ARM_GAS16(Address) { EFI_ACPI_5_0_SYSTEM_MEMORY, 16, 0, EFI_ACPI_5_0_WORD, Address } +#define ARM_GAS32(Address) { EFI_ACPI_5_0_SYSTEM_MEMORY, 32, 0, EFI_ACPI_5_0_DWORD, Address } +#define ARM_GASN(Address) { EFI_ACPI_5_0_SYSTEM_MEMORY, 0, 0, EFI_ACPI_5_0_DWORD, Address } + +// +// Macros for the Multiple APIC Description Table (MADT) +// +#define EFI_ACPI_5_0_GIC_DISTRIBUTOR_INIT(GicDistHwId, GicDistBase, GicDistVector) \ + { \ + EFI_ACPI_5_0_GICD, sizeof (EFI_ACPI_5_0_GIC_DISTRIBUTOR_STRUCTURE), EFI_ACPI_RESERVED_WORD, \ + GicDistHwId, GicDistBase, GicDistVector, EFI_ACPI_RESERVED_DWORD \ + } + +#define EFI_ACPI_6_0_GIC_DISTRIBUTOR_INIT(GicDistHwId, GicDistBase, GicDistVector, GicVersion) \ + { \ + EFI_ACPI_6_0_GICD, sizeof (EFI_ACPI_6_0_GIC_DISTRIBUTOR_STRUCTURE), EFI_ACPI_RESERVED_WORD, \ + GicDistHwId, GicDistBase, GicDistVector, GicVersion, \ + {EFI_ACPI_RESERVED_BYTE, EFI_ACPI_RESERVED_BYTE, EFI_ACPI_RESERVED_BYTE} \ + } + +// Note the parking protocol is configured by UEFI if required +#define EFI_ACPI_5_0_GIC_STRUCTURE_INIT(GicId, AcpiCpuId, Flags, PmuIrq, GicBase) \ + { \ + EFI_ACPI_5_0_GIC, sizeof (EFI_ACPI_5_0_GIC_STRUCTURE), EFI_ACPI_RESERVED_WORD, \ + GicId, AcpiCpuId, Flags, 0, PmuIrq, 0, GicBase \ + } + +// Note the parking protocol is configured by UEFI if required +#define EFI_ACPI_5_1_GICC_STRUCTURE_INIT(GicId, AcpiCpuUid, Mpidr, Flags, PmuIrq, \ + GicBase, GicVBase, GicHBase, GsivId, GicRBase) \ + { \ + EFI_ACPI_5_1_GIC, sizeof (EFI_ACPI_5_1_GIC_STRUCTURE), EFI_ACPI_RESERVED_WORD, \ + GicId, AcpiCpuUid, Flags, 0, PmuIrq, 0, GicBase, GicVBase, GicHBase, \ + GsivId, GicRBase, Mpidr \ + } + +#define EFI_ACPI_6_0_GICC_STRUCTURE_INIT(GicId, AcpiCpuUid, Mpidr, Flags, PmuIrq, \ + GicBase, GicVBase, GicHBase, GsivId, GicRBase, Efficiency) \ + { \ + EFI_ACPI_6_0_GIC, sizeof (EFI_ACPI_6_0_GIC_STRUCTURE), EFI_ACPI_RESERVED_WORD, \ + GicId, AcpiCpuUid, Flags, 0, PmuIrq, 0, GicBase, GicVBase, GicHBase, \ + GsivId, GicRBase, Mpidr, Efficiency, \ + {EFI_ACPI_RESERVED_BYTE, EFI_ACPI_RESERVED_BYTE, EFI_ACPI_RESERVED_BYTE} \ + } + +#define EFI_ACPI_6_3_GICC_STRUCTURE_INIT(GicId, AcpiCpuUid, Mpidr, Flags, PmuIrq, \ + GicBase, GicVBase, GicHBase, GsivId, GicRBase, Efficiency, SpeOvflIrq) \ + { \ + EFI_ACPI_6_0_GIC, sizeof (EFI_ACPI_6_3_GIC_STRUCTURE), EFI_ACPI_RESERVED_WORD, \ + GicId, AcpiCpuUid, Flags, 0, PmuIrq, 0, GicBase, GicVBase, GicHBase, \ + GsivId, GicRBase, Mpidr, Efficiency, EFI_ACPI_RESERVED_BYTE, SpeOvflIrq \ + } + +#define EFI_ACPI_6_0_GIC_MSI_FRAME_INIT(GicMsiFrameId, PhysicalBaseAddress, Flags, SPICount, SPIBase) \ + { \ + EFI_ACPI_6_0_GIC_MSI_FRAME, sizeof (EFI_ACPI_6_0_GIC_MSI_FRAME_STRUCTURE), EFI_ACPI_RESERVED_WORD, \ + GicMsiFrameId, PhysicalBaseAddress, Flags, SPICount, SPIBase \ + } + +// +// SBSA Generic Watchdog +// +#define EFI_ACPI_5_1_SBSA_GENERIC_WATCHDOG_STRUCTURE_INIT(RefreshFramePhysicalAddress, \ + ControlFramePhysicalAddress, WatchdogTimerGSIV, WatchdogTimerFlags) \ + { \ + EFI_ACPI_5_1_GTDT_SBSA_GENERIC_WATCHDOG, sizeof(EFI_ACPI_5_1_GTDT_SBSA_GENERIC_WATCHDOG_STRUCTURE), \ + EFI_ACPI_RESERVED_BYTE, RefreshFramePhysicalAddress, ControlFramePhysicalAddress, \ + WatchdogTimerGSIV, WatchdogTimerFlags \ + } + +typedef +BOOLEAN +(EFIAPI *EFI_LOCATE_ACPI_CHECK) ( + IN EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader + ); + +/** + Locate and Install the ACPI tables from the Firmware Volume if it verifies + the function condition. + + @param AcpiFile Guid of the ACPI file into the Firmware Volume + @param CheckAcpiTableFunction Function that checks if the ACPI table should be installed + + @return EFI_SUCCESS The function completed successfully. + @return EFI_NOT_FOUND The protocol could not be located. + @return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol. + +**/ +EFI_STATUS +LocateAndInstallAcpiFromFvConditional ( + IN CONST EFI_GUID* AcpiFile, + IN EFI_LOCATE_ACPI_CHECK CheckAcpiTableFunction + ); + +/** + Locate and Install the ACPI tables from the Firmware Volume + + @param AcpiFile Guid of the ACPI file into the Firmware Volume + + @return EFI_SUCCESS The function completed successfully. + @return EFI_NOT_FOUND The protocol could not be located. + @return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol. + +**/ +EFI_STATUS +LocateAndInstallAcpiFromFv ( + IN CONST EFI_GUID* AcpiFile + ); + +#endif // __ACPI_LIB_H__ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/AndroidBootImgLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/AndroidBootImgLib.h new file mode 100644 index 00000000..313243f2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/AndroidBootImgLib.h @@ -0,0 +1,65 @@ +/** @file + + Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
+ Copyright (c) 2017, Linaro. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __ABOOTIMG_H__ +#define __ABOOTIMG_H__ + +#include +#include +#include + +#include +#include + +#define ANDROID_BOOTIMG_KERNEL_ARGS_SIZE 512 + +#define ANDROID_BOOT_MAGIC "ANDROID!" +#define ANDROID_BOOT_MAGIC_LENGTH (sizeof (ANDROID_BOOT_MAGIC) - 1) + +// No documentation for this really - sizes of fields has been determined +// empirically. +#pragma pack(1) +/* https://android.googlesource.com/platform/system/core/+/master/mkbootimg/bootimg.h */ +typedef struct { + UINT8 BootMagic[ANDROID_BOOT_MAGIC_LENGTH]; + UINT32 KernelSize; + UINT32 KernelAddress; + UINT32 RamdiskSize; + UINT32 RamdiskAddress; + UINT32 SecondStageBootloaderSize; + UINT32 SecondStageBootloaderAddress; + UINT32 KernelTaggsAddress; + UINT32 PageSize; + UINT32 Reserved[2]; + CHAR8 ProductName[16]; + CHAR8 KernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE]; + UINT32 Id[32]; +} ANDROID_BOOTIMG_HEADER; +#pragma pack () + +/* Check Val (unsigned) is a power of 2 (has only one bit set) */ +#define IS_POWER_OF_2(Val) ((Val) != 0 && (((Val) & ((Val) - 1)) == 0)) +/* Android boot image page size is not specified, but it should be power of 2 + * and larger than boot header */ +#define IS_VALID_ANDROID_PAGE_SIZE(Val) \ + (IS_POWER_OF_2(Val) && (Val > sizeof(ANDROID_BOOTIMG_HEADER))) + +EFI_STATUS +AndroidBootImgGetImgSize ( + IN VOID *BootImg, + OUT UINTN *ImgSize + ); + +EFI_STATUS +AndroidBootImgBoot ( + IN VOID *Buffer, + IN UINTN BufferSize + ); + +#endif /* __ABOOTIMG_H__ */ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/DebugAgentTimerLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/DebugAgentTimerLib.h new file mode 100644 index 00000000..e411c85f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/DebugAgentTimerLib.h @@ -0,0 +1,56 @@ +/** @file + Platform specific Debug Agent abstraction for timer used by the agent. + + The timer is used by the debugger to break into a running program. + + Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __GDB_TIMER_LIB__ +#define __GDB_TIMER_LIB__ + + + +/** + Setup all the hardware needed for the debug agents timer. + + This function is used to set up debug environment. It may enable interrupts. + +**/ +VOID +EFIAPI +DebugAgentTimerIntialize ( + VOID + ); + + +/** + Set the period for the debug agent timer. Zero means disable the timer. + + @param[in] TimerPeriodMilliseconds Frequency of the debug agent timer. + +**/ +VOID +EFIAPI +DebugAgentTimerSetPeriod ( + IN UINT32 TimerPeriodMilliseconds + ); + + +/** + Perform End Of Interrupt for the debug agent timer. This is called in the + interrupt handler after the interrupt has been processed. + +**/ +VOID +EFIAPI +DebugAgentTimerEndOfInterrupt ( + VOID + ); + +#endif + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/DmaLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/DmaLib.h new file mode 100644 index 00000000..b8b48fa5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/DmaLib.h @@ -0,0 +1,181 @@ +/** @file + DMA abstraction library APIs. Based on UEFI PCI IO protocol DMA abstractions. + At some point these functions will probably end up in a non PCI protocol + for embedded systems. + + DMA Bus Master Read Operation: + Call DmaMap() for MapOperationBusMasterRead. + Program the DMA Bus Master with the DeviceAddress returned by DmaMap(). + Start the DMA Bus Master. + Wait for DMA Bus Master to complete the read operation. + Call DmaUnmap(). + + DMA Bus Master Write Operation: + Call DmaMap() for MapOperationBusMasterWrite. + Program the DMA Bus Master with the DeviceAddress returned by DmaMap(). + Start the DMA Bus Master. + Wait for DMA Bus Master to complete the write operation. + Call DmaUnmap(). + + DMA Bus Master Common Buffer Operation: + Call DmaAllocateBuffer() to allocate a common buffer. + Call DmaMap() for MapOperationBusMasterCommonBuffer. + Program the DMA Bus Master with the DeviceAddress returned by DmaMap(). + The common buffer can now be accessed equally by the processor and the DMA bus master. + Call DmaUnmap(). + Call DmaFreeBuffer(). + + Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __DMA_LIB_H__ +#define __DMA_LIB_H__ + +typedef enum { + /// + /// A read operation from system memory by a bus master. + /// + MapOperationBusMasterRead, + /// + /// A write operation from system memory by a bus master. + /// + MapOperationBusMasterWrite, + /// + /// Provides both read and write access to system memory by both the processor and a + /// bus master. The buffer is coherent from both the processor's and the bus master's point of view. + /// + MapOperationBusMasterCommonBuffer, + MapOperationMaximum +} DMA_MAP_OPERATION; + + + + +/** + Provides the DMA controller-specific addresses needed to access system memory. + + Operation is relative to the DMA bus master. + + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the DMA controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to DmaUnmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +EFI_STATUS +EFIAPI +DmaMap ( + IN DMA_MAP_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + + + + +/** + Completes the DmaMapBusMasterRead, DmaMapBusMasterWrite, or DmaMapBusMasterCommonBuffer + operation and releases any corresponding resources. + + @param Mapping The mapping value returned from DmaMap(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + +**/ +EFI_STATUS +EFIAPI +DmaUnmap ( + IN VOID *Mapping + ); + + +/** + Allocates pages that are suitable for an DmaMap() of type MapOperationBusMasterCommonBuffer. + mapping. + + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +DmaAllocateBuffer ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress + ); + + +/** + Frees memory that was allocated with DmaAllocateBuffer(). + + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with DmaAllocateBuffer(). + +**/ +EFI_STATUS +EFIAPI +DmaFreeBuffer ( + IN UINTN Pages, + IN VOID *HostAddress + ); + + +/** + Allocates pages that are suitable for an DmaMap() of type + MapOperationBusMasterCommonBuffer mapping, at the requested alignment. + + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param Alignment Alignment in bytes of the base of the returned + buffer (must be a power of 2) + @param HostAddress A pointer to store the base system memory address of the + allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +DmaAllocateAlignedBuffer ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment, + OUT VOID **HostAddress + ); + + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/DtPlatformDtbLoaderLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/DtPlatformDtbLoaderLib.h new file mode 100644 index 00000000..df7d8f35 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/DtPlatformDtbLoaderLib.h @@ -0,0 +1,33 @@ +/** @file +* +* Copyright (c) 2017, Linaro, Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __DT_PLATFORM_DTB_LOADER_LIB_H__ +#define __DT_PLATFORM_DTB_LOADER_LIB_H__ + +#include + +/** + Return a pool allocated copy of the DTB image that is appropriate for + booting the current platform via DT. + + @param[out] Dtb Pointer to the DTB copy + @param[out] DtbSize Size of the DTB copy + + @retval EFI_SUCCESS Operation completed successfully + @retval EFI_NOT_FOUND No suitable DTB image could be located + @retval EFI_OUT_OF_RESOURCES No pool memory available + +**/ +EFI_STATUS +EFIAPI +DtPlatformLoadDtb ( + OUT VOID **Dtb, + OUT UINTN *DtbSize + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/EfiFileLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/EfiFileLib.h new file mode 100644 index 00000000..c8d2dd05 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/EfiFileLib.h @@ -0,0 +1,344 @@ +/** @file + Library functions that perform file IO. Memory buffer, file system, and + firmware volume operations are supported. + + Copyright (c) 2007, Intel Corporation. All rights reserved.
+ Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + + Basic support for opening files on different device types. The device string + is in the form of DevType:Path. Current DevType is required as there is no + current mounted device concept of current working directory concept implement + by this library. + + Device names are case insensitive and only check the leading characters for + unique matches. Thus the following are all the same: + LoadFile0: + l0: + L0: + Lo0: + + Supported Device Names: + A0x1234:0x12 - A memory buffer starting at address 0x1234 for 0x12 bytes + l1: - EFI LoadFile device one. + B0: - EFI BlockIo zero. + fs3: - EFI Simple File System device 3 + Fv2: - EFI Firmware Volume device 2 + 1.2.3.4:name - TFTP IP and file name + +**/ + +#ifndef __EFI_FILE_LIB_H__ +#define __EFI_FILE_LIB_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PATHNAME 0x200 + +/// Type of the file that has been opened +typedef enum { + EfiOpenLoadFile, + EfiOpenMemoryBuffer, + EfiOpenFirmwareVolume, + EfiOpenFileSystem, + EfiOpenBlockIo, + EfiOpenTftp, + EfiOpenMaxValue +} EFI_OPEN_FILE_TYPE; + + +/// Public information about the open file +typedef struct { + UINTN Version; // Common information + EFI_OPEN_FILE_TYPE Type; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_STATUS LastError; + EFI_HANDLE EfiHandle; + CHAR8 *DeviceName; + CHAR8 *FileName; + + UINT64 CurrentPosition; // Information for Seek + UINT64 MaxPosition; + + UINTN BaseOffset; // Base offset for hexdump command + + UINTN Size; // Valid for all types other than l#: + UINT8 *Buffer; // Information valid for A#: + + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; // Information valid for Fv#: + EFI_GUID FvNameGuid; + EFI_SECTION_TYPE FvSectionType; + EFI_FV_FILETYPE FvType; + EFI_FV_FILE_ATTRIBUTES FvAttributes; + + EFI_PHYSICAL_ADDRESS FvStart; + UINTN FvSize; + UINTN FvHeaderSize; + + EFI_FILE *FsFileHandle; // Information valid for Fs#: + EFI_FILE_SYSTEM_INFO *FsInfo; + EFI_FILE_INFO *FsFileInfo; + EFI_BLOCK_IO_MEDIA *FsBlockIoMedia; // Information valid for Fs#: or B#: + EFI_BLOCK_IO_PROTOCOL *FsBlockIo; // Information valid for Fs#: or B#: + + UINTN DiskOffset; // Information valid for B#: + + EFI_LOAD_FILE_PROTOCOL *LoadFile; // Information valid for l#: + + EFI_IP_ADDRESS ServerIp; // Information valid for t: + BOOLEAN IsDirty; + BOOLEAN IsBufferValid; + +} EFI_OPEN_FILE; + + +/// Type of Seek to perform +typedef enum { + EfiSeekStart, + EfiSeekCurrent, + EfiSeekEnd, + EfiSeekMax +} EFI_SEEK_TYPE; + + +/** + Open a device named by PathName. The PathName includes a device name and + path separated by a :. See file header for more details on the PathName + syntax. There is no checking to prevent a file from being opened more than + one type. + + SectionType is only used to open an FV. Each file in an FV contains multiple + sections and only the SectionType section is opened. + + For any file that is opened with EfiOpen() must be closed with EfiClose(). + + @param PathName Path to parse to open + @param OpenMode Same as EFI_FILE.Open() + @param SectionType Section in FV to open. + + @return NULL Open failed + @return Valid EFI_OPEN_FILE handle + +**/ +EFI_OPEN_FILE * +EfiOpen ( + IN CHAR8 *PathName, + IN CONST UINT64 OpenMode, + IN CONST EFI_SECTION_TYPE SectionType + ); + +EFI_STATUS +EfiCopyFile ( + IN CHAR8 *DestinationFile, + IN CHAR8 *SourceFile + ); + +/** + Use DeviceType and Index to form a valid PathName and try and open it. + + @param DeviceType Device type to open + @param Index Device Index to use. Zero relative. + + @return NULL Open failed + @return Valid EFI_OPEN_FILE handle + +**/ +EFI_OPEN_FILE * +EfiDeviceOpenByType ( + IN EFI_OPEN_FILE_TYPE DeviceType, + IN UINTN Index + ); + + +/** + Close a file handle opened by EfiOpen() and free all resources allocated by + EfiOpen(). + + @param Stream Open File Handle + + @return EFI_INVALID_PARAMETER Stream is not an Open File + @return EFI_SUCCESS Steam closed + +**/ +EFI_STATUS +EfiClose ( + IN EFI_OPEN_FILE *Stream + ); + + +/** + Return the size of the file represented by Stream. Also return the current + Seek position. Opening a file will enable a valid file size to be returned. + LoadFile is an exception as a load file size is set to zero. + + @param Stream Open File Handle + + @return 0 Stream is not an Open File or a valid LoadFile handle + +**/ +UINTN +EfiTell ( + IN EFI_OPEN_FILE *Stream, + OUT UINT64 *CurrentPosition OPTIONAL + ); + + +/** + Seek to the Offset location in the file. LoadFile and FV device types do + not support EfiSeek(). It is not possible to grow the file size using + EfiSeek(). + + SeekType defines how use Offset to calculate the new file position: + EfiSeekStart : Position = Offset + EfiSeekCurrent: Position is Offset bytes from the current position + EfiSeekEnd : Only supported if Offset is zero to seek to end of file. + + @param Stream Open File Handle + @param Offset Offset to seek too. + @param SeekType Type of seek to perform + + + @return EFI_INVALID_PARAMETER Stream is not an Open File + @return EFI_UNSUPPORTED LoadFile and FV does not support Seek + @return EFI_NOT_FOUND Seek past the end of the file. + @return EFI_SUCCESS Steam closed + +**/ +EFI_STATUS +EfiSeek ( + IN EFI_OPEN_FILE *Stream, + IN EFI_LBA Offset, + IN EFI_SEEK_TYPE SeekType + ); + + +/** + Read BufferSize bytes from the current location in the file. For load file + and FV case you must read the entire file. + + @param Stream Open File Handle + @param Buffer Caller allocated buffer. + @param BufferSize Size of buffer in bytes. + + + @return EFI_SUCCESS Stream is not an Open File + @return EFI_END_OF_FILE Tried to read past the end of the file + @return EFI_INVALID_PARAMETER Stream is not an open file handle + @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read + @return "other" Error returned from device read + +**/ +EFI_STATUS +EfiRead ( + IN EFI_OPEN_FILE *Stream, + OUT VOID *Buffer, + OUT UINTN *BufferSize + ); + + +/** + Read the entire file into a buffer. This routine allocates the buffer and + returns it to the user full of the read data. + + This is very useful for load file where it's hard to know how big the buffer + must be. + + @param Stream Open File Handle + @param Buffer Pointer to buffer to return. + @param BufferSize Pointer to Size of buffer return.. + + + @return EFI_SUCCESS Stream is not an Open File + @return EFI_END_OF_FILE Tried to read past the end of the file + @return EFI_INVALID_PARAMETER Stream is not an open file handle + @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read + @return "other" Error returned from device read + +**/ +EFI_STATUS +EfiReadAllocatePool ( + IN EFI_OPEN_FILE *Stream, + OUT VOID **Buffer, + OUT UINTN *BufferSize + ); + + +/** + Write data back to the file. + + @param Stream Open File Handle + @param Buffer Pointer to buffer to return. + @param BufferSize Pointer to Size of buffer return.. + + + @return EFI_SUCCESS Stream is not an Open File + @return EFI_END_OF_FILE Tried to read past the end of the file + @return EFI_INVALID_PARAMETER Stream is not an open file handle + @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read + @return "other" Error returned from device write + +**/ +EFI_STATUS +EfiWrite ( + IN EFI_OPEN_FILE *Stream, + OUT VOID *Buffer, + OUT UINTN *BufferSize + ); + + +/** + Return the number of devices of the current type active in the system + + @param Type Device type to check + + @return 0 Invalid type + +**/ +UINTN +EfiGetDeviceCounts ( + IN EFI_OPEN_FILE_TYPE Type + ); + + +/** + Set the Current Working Directory (CWD). If a call is made to EfiOpen () and + the path does not contain a device name, The CWD is prepended to the path. + + @param Cwd Current Working Directory to set + + + @return EFI_SUCCESS CWD is set + @return EFI_INVALID_PARAMETER Cwd is not a valid device:path + +**/ +EFI_STATUS +EfiSetCwd ( + IN CHAR8 *Cwd + ); + +/** + Set the Current Working Directory (CWD). If a call is made to EfiOpen () and + the path does not contain a device name, The CWD is prepended to the path. + + @param Cwd Current Working Directory + + + @return NULL No CWD set + @return 'other' malloc'ed buffer contains CWD. + +**/ +CHAR8 * +EfiGetCwd ( + VOID + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/EfiResetSystemLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/EfiResetSystemLib.h new file mode 100644 index 00000000..a2df21ae --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/EfiResetSystemLib.h @@ -0,0 +1,52 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef __EFI_RESET_SYSTEM_LIB_H___ +#define __EFI_RESET_SYSTEM_LIB_H___ + + +/** + Resets the entire platform. + + @param ResetType The type of reset to perform. + @param ResetStatus The status code for the reset. + @param DataSize The size, in bytes, of WatchdogData. + @param ResetData For a ResetType of EfiResetCold, EfiResetWarm, or + EfiResetShutdown the data buffer starts with a Null-terminated + Unicode string, optionally followed by additional binary data. + +**/ +EFI_STATUS +EFIAPI +LibResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ); + + + +/** + Initialize any infrastructure required for LibResetSystem () to function. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +LibInitializeResetSystem ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/FdtLoadLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/FdtLoadLib.h new file mode 100644 index 00000000..2b83cbd4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/FdtLoadLib.h @@ -0,0 +1,42 @@ +/** @file +* +* Copyright (c) 2011-2014, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef _FDT_LOAD_LIB_H_ +#define _FDT_LOAD_LIB_H_ + +/** + Load and Install FDT from Semihosting + + @param Filename Name of the file to load from semihosting + + @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table + from semihosting + @return EFI_NOT_FOUND Fail to locate the file in semihosting + @return EFI_OUT_OF_RESOURCES Fail to allocate memory to contain the blob +**/ +EFI_STATUS +InstallFdtFromSemihosting ( + IN CONST CHAR16* FileName + ); + +/** + Load and Install FDT from Firmware Volume + + @param Filename Guid of the FDT blob to load from firmware volume + + @return EFI_SUCCESS Fdt Blob was successfully installed into the configuration table + from firmware volume + @return EFI_NOT_FOUND Failed to locate the file in firmware volume + @return EFI_OUT_OF_RESOURCES Failed to allocate memory to contain the blob +**/ +EFI_STATUS +InstallFdtFromFv ( + IN CONST EFI_GUID *FileName + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/GdbSerialLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/GdbSerialLib.h new file mode 100644 index 00000000..18bfbd9d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/GdbSerialLib.h @@ -0,0 +1,101 @@ +/** @file + Basic serial IO abstraction for GDB + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __GDB_SERIAL_LIB_H__ +#define __GDB_SERIAL_LIB_H__ + + + +/** + Sets the baud rate, receive FIFO depth, transmit/receive time out, parity, + data buts, and stop bits on a serial device. This call is optional as the serial + port will be set up with defaults base on PCD values. + + @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the + device's default interface speed. + @param Parity The type of parity to use on this serial device. A Parity value of + DefaultParity will use the device's default parity value. + @param DataBits The number of data bits to use on the serial device. A DataBits + value of 0 will use the device's default data bit setting. + @param StopBits The number of stop bits to use on this serial device. A StopBits + value of DefaultStopBits will use the device's default number of + stop bits. + + @retval EFI_SUCCESS The device was configured. + @retval EFI_DEVICE_ERROR The serial device could not be configured. + +**/ +RETURN_STATUS +EFIAPI +GdbSerialInit ( + IN UINT64 BaudRate, + IN UINT8 Parity, + IN UINT8 DataBits, + IN UINT8 StopBits + ); + + +/** + Check to see if a character is available from GDB. Do not read the character as that is + done via GdbGetChar(). + + @return TRUE - Character available + @return FALSE - Character not available + +**/ +BOOLEAN +EFIAPI +GdbIsCharAvailable ( + VOID + ); + +/** + Get a character from GDB. This function must be able to run in interrupt context. + + @return A character from GDB + +**/ +CHAR8 +EFIAPI +GdbGetChar ( + VOID + ); + + +/** + Send a character to GDB. This function must be able to run in interrupt context. + + + @param Char Send a character to GDB + +**/ + +VOID +EFIAPI +GdbPutChar ( + IN CHAR8 Char + ); + + +/** + Send an ASCII string to GDB. This function must be able to run in interrupt context. + + + @param String Send a string to GDB + +**/ + +VOID +GdbPutString ( + IN CHAR8 *String + ); + + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/HalRuntimeServicesLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/HalRuntimeServicesLib.h new file mode 100644 index 00000000..9c717712 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/HalRuntimeServicesLib.h @@ -0,0 +1,159 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef __RUNTIME_SERVICES_LIB_H__ +#define __RUNTIME_SERVICES_LIB_H__ + +VOID +LibMtcInitialize (VOID); + +VOID +LibMtcVirtualAddressChangeEvent (VOID); + +EFI_STATUS +EFIAPI +LibMtcGetNextHighMonotonicCount ( + OUT UINT32 *HighCount + ); + +EFI_STATUS +LibMtcGetNextMonotonicCount ( + OUT UINT64 *Count + ); + + + +VOID +LibVariableInitialize (VOID); + +VOID +LibVariableVirtualAddressChangeEvent (VOID); + +EFI_STATUS +LibGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +EFI_STATUS +LibGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ); + +EFI_STATUS +LibSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ); + +EFI_STATUS +LibQueryVariableInfo ( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize + ); + + + +VOID +LibResetInitializeReset (VOID); + +VOID +LibResetVirtualAddressChangeEvent (VOID); + +VOID +LibResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ); + + +VOID +LibCapsuleInitialize (VOID); + +VOID +LibCapsuleVirtualAddressChangeEvent (VOID); + +EFI_STATUS +LibUpdateCapsule ( + IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL + ); + +EFI_STATUS +QueryCapsuleCapabilities ( + IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + OUT UINT64 *MaxiumCapsuleSize, + OUT EFI_RESET_TYPE *ResetType + ); + + + +VOID +LibRtcInitialize (VOID); + +VOID +LibRtcVirtualAddressChangeEvent (VOID); + +EFI_STATUS +LibGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ); + +EFI_STATUS +LibSetTime ( + IN EFI_TIME *Time + ); + +EFI_STATUS +LibGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ); + +EFI_STATUS +LibSetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ); + + +VOID +LibReportStatusCodeInitialize (VOID); + +VOID +LibReportStatusCodeVirtualAddressChangeEvent (VOID); + +EFI_STATUS +LibReportStatusCode ( + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value, + IN UINT32 Instance, + IN EFI_GUID *CallerId, + IN EFI_STATUS_CODE_DATA *Data OPTIONAL + ); + + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/NorFlashInfoLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/NorFlashInfoLib.h new file mode 100644 index 00000000..40619d54 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/NorFlashInfoLib.h @@ -0,0 +1,90 @@ +/** @file +* +* Copyright (c) 2017 Marvell International Ltd. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __NOR_FLASH_ID_LIB_H__ +#define __NOR_FLASH_ID_LIB_H__ + +#include + +#define NOR_FLASH_MAX_ID_LEN 6 + +typedef struct { + /* Device name */ + UINT16 *Name; + + /* + * JEDEC ID + */ + UINT8 Id[NOR_FLASH_MAX_ID_LEN]; + UINT8 IdLen; + + UINT16 PageSize; + + /* + * Below parameters can be referred as BlockSize + * and BlockCount, when treating the NorFlash as + * block device. + */ + UINT32 SectorSize; + UINT32 SectorCount; + + UINT16 Flags; +#define NOR_FLASH_ERASE_4K (1 << 0) /* Use 4 KB erase blocks and CMD_ERASE_4K */ +#define NOR_FLASH_ERASE_32K (1 << 1) /* Use 32 KB erase blocks and CMD_ERASE_32K */ +#define NOR_FLASH_WRITE_FSR (1 << 2) /* Use flag status register for write */ +#define NOR_FLASH_4B_ADDR (1 << 3) /* Use 4B addressing */ +} NOR_FLASH_INFO; + +/* Vendor IDs */ +#define NOR_FLASH_ID_ATMEL 0x1f +#define NOR_FLASH_ID_EON 0x1c +#define NOR_FLASH_ID_GIGADEVICE 0xc8 +#define NOR_FLASH_ID_ISSI 0x9d +#define NOR_FLASH_ID_MACRONIX 0xc2 +#define NOR_FLASH_ID_SPANSION 0x01 +#define NOR_FLASH_ID_STMICRO 0x20 +#define NOR_FLASH_ID_SST 0xbf +#define NOR_FLASH_ID_WINDBOND 0xef + +/** + Return an allocated copy pool of the NOR flash information structure. + + @param[in] Id Pointer to an array with JEDEC ID obtained + from the NOR flash with READ_ID command + (0x9f) + @param[in out] FlashInfo Pointer to NOR flash information structure + @param[in] AllocateForRuntime A flag specifying a type of a copy pool + allocation (TRUE for runtime, FALSE for + normal) + + @retval EFI_SUCCESS Operation completed successfully + @retval EFI_NOT_FOUND No matching entry in NOR ID table found + @retval EFI_OUT_OF_RESOURCES No pool memory available + +**/ +EFI_STATUS +EFIAPI +NorFlashGetInfo ( + IN UINT8 *Id, + IN OUT NOR_FLASH_INFO **FlashInfo, + IN BOOLEAN AllocateForRuntime + ); + +/** + Print NOR flash information basing on data stored in + the NOR_FLASH_INFO structure. + + @param[in] FlashInfo Pointer to NOR flash information structure + +**/ +VOID +EFIAPI +NorFlashPrintInfo ( + IN NOR_FLASH_INFO *Info + ); +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/PrePiHobListPointerLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/PrePiHobListPointerLib.h new file mode 100644 index 00000000..3fe7c89c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/PrePiHobListPointerLib.h @@ -0,0 +1,38 @@ +/** @file +* +* Copyright (c) 2011, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __PREPI_HOBLIST_POINTER_LIB_H__ +#define __PREPI_HOBLIST_POINTER_LIB_H__ + +/** + Returns the pointer to the HOB list. + + This function returns the pointer to first HOB in the list. + + @return The pointer to the HOB list. + +**/ +VOID * +EFIAPI +PrePeiGetHobList ( + VOID + ); + +/** + Updates the pointer to the HOB list. + + @param HobList Hob list pointer to store + +**/ +EFI_STATUS +EFIAPI +PrePeiSetHobList ( + IN VOID *HobList + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/PrePiLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/PrePiLib.h new file mode 100644 index 00000000..dad1adf5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/PrePiLib.h @@ -0,0 +1,758 @@ +/** @file + Library that helps implement monolithic PEI. (SEC goes to DXE) + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __PRE_PI_LIB_H__ +#define __PRE_PI_LIB_H__ + +#include + +/** + This service enables discovery of additional firmware volumes. + + @param Instance This instance of the firmware volume to find. The value 0 is the + Boot Firmware Volume (BFV). + @param FwVolHeader Pointer to the firmware volume header of the volume to return. + + @retval EFI_SUCCESS The volume was found. + @retval EFI_NOT_FOUND The volume was not found. + @retval EFI_INVALID_PARAMETER FwVolHeader is NULL. + +**/ +EFI_STATUS +EFIAPI +FfsFindNextVolume ( + IN UINTN Instance, + IN OUT EFI_PEI_FV_HANDLE *VolumeHandle + ); + + +/** + This service enables discovery of additional firmware files. + + @param SearchType A filter to find files only of this type. + @param FwVolHeader Pointer to the firmware volume header of the volume to search. + This parameter must point to a valid FFS volume. + @param FileHeader Pointer to the current file from which to begin searching. + + @retval EFI_SUCCESS The file was found. + @retval EFI_NOT_FOUND The file was not found. + @retval EFI_NOT_FOUND The header checksum was not zero. + +**/ +EFI_STATUS +EFIAPI +FfsFindNextFile ( + IN EFI_FV_FILETYPE SearchType, + IN EFI_PEI_FV_HANDLE VolumeHandle, + IN OUT EFI_PEI_FILE_HANDLE *FileHandle + ); + + +/** + This service enables discovery sections of a given type within a valid FFS file. + + @param SearchType The value of the section type to find. + @param FfsFileHeader A pointer to the file header that contains the set of sections to + be searched. + @param SectionData A pointer to the discovered section, if successful. + + @retval EFI_SUCCESS The section was found. + @retval EFI_NOT_FOUND The section was not found. + +**/ +EFI_STATUS +EFIAPI +FfsFindSectionData ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData + ); + + +/** + Find a file in the volume by name + + @param FileName A pointer to the name of the file to + find within the firmware volume. + + @param VolumeHandle The firmware volume to search FileHandle + Upon exit, points to the found file's + handle or NULL if it could not be found. + + @retval EFI_SUCCESS File was found. + + @retval EFI_NOT_FOUND File was not found. + + @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or + FileName was NULL. + +**/ +EFI_STATUS +EFIAPI +FfsFindFileByName ( + IN CONST EFI_GUID *FileName, + IN CONST EFI_PEI_FV_HANDLE VolumeHandle, + OUT EFI_PEI_FILE_HANDLE *FileHandle + ); + + +/** + Get information about the file by name. + + @param FileHandle Handle of the file. + + @param FileInfo Upon exit, points to the file's + information. + + @retval EFI_SUCCESS File information returned. + + @retval EFI_INVALID_PARAMETER If FileHandle does not + represent a valid file. + + @retval EFI_INVALID_PARAMETER If FileInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +FfsGetFileInfo ( + IN CONST EFI_PEI_FILE_HANDLE FileHandle, + OUT EFI_FV_FILE_INFO *FileInfo + ); + + +/** + Get Information about the volume by name + + @param VolumeHandle Handle of the volume. + + @param VolumeInfo Upon exit, points to the volume's + information. + + @retval EFI_SUCCESS File information returned. + + @retval EFI_INVALID_PARAMETER If FileHandle does not + represent a valid file. + + @retval EFI_INVALID_PARAMETER If FileInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +FfsGetVolumeInfo ( + IN EFI_PEI_FV_HANDLE VolumeHandle, + OUT EFI_FV_INFO *VolumeInfo + ); + + + +/** + Get Fv image from the FV type file, then add FV & FV2 Hob. + + @param FileHandle File handle of a Fv type file. + + @retval EFI_NOT_FOUND FV image can't be found. + @retval EFI_SUCCESS Successfully to process it. + +**/ +EFI_STATUS +EFIAPI +FfsProcessFvFile ( + IN EFI_PEI_FILE_HANDLE FvFileHandle + ); + + +/** + Search through every FV until you find a file of type FileType + + @param FileType File handle of a Fv type file. + @param Volumehandle On success Volume Handle of the match + @param FileHandle On success File Handle of the match + + @retval EFI_NOT_FOUND FV image can't be found. + @retval EFI_SUCCESS Successfully found FileType + +**/ +EFI_STATUS +EFIAPI +FfsAnyFvFindFirstFile ( + IN EFI_FV_FILETYPE FileType, + OUT EFI_PEI_FV_HANDLE *VolumeHandle, + OUT EFI_PEI_FILE_HANDLE *FileHandle + ); + + +/** + Get Fv image from the FV type file, then add FV & FV2 Hob. + + @param FileHandle File handle of a Fv type file. + + + @retval EFI_NOT_FOUND FV image can't be found. + @retval EFI_SUCCESS Successfully to process it. + +**/ +EFI_STATUS +EFIAPI +FfsProcessFvFile ( + IN EFI_PEI_FILE_HANDLE FvFileHandle + ); + + +/** + This service enables PEIMs to ascertain the present value of the boot mode. + + + @retval BootMode + +**/ +EFI_BOOT_MODE +EFIAPI +GetBootMode ( + VOID + ); + + +/** + This service enables PEIMs to update the boot mode variable. + + @param BootMode The value of the boot mode to set. + + @retval EFI_SUCCESS The value was successfully updated + +**/ +EFI_STATUS +EFIAPI +SetBootMode ( + IN EFI_BOOT_MODE BootMode + ); + +/** + This service enables a PEIM to ascertain the address of the list of HOBs in memory. + + @param HobList A pointer to the list of HOBs that the PEI Foundation will initialize. + + @retval EFI_SUCCESS The list was successfully returned. + @retval EFI_NOT_AVAILABLE_YET The HOB list is not yet published. + +**/ +VOID * +EFIAPI +GetHobList ( + VOID + ); + + +/** + Updates the pointer to the HOB list. + + @param HobList Hob list pointer to store + +**/ +EFI_STATUS +EFIAPI +SetHobList ( + IN VOID *HobList + ); + +EFI_HOB_HANDOFF_INFO_TABLE* +HobConstructor ( + IN VOID *EfiMemoryBegin, + IN UINTN EfiMemoryLength, + IN VOID *EfiFreeMemoryBottom, + IN VOID *EfiFreeMemoryTop + ); + +/** + This service enables PEIMs to create various types of HOBs. + + @param Type The type of HOB to be installed. + @param Length The length of the HOB to be added. + + @retval !NULL The HOB was successfully created. + @retval NULL There is no additional space for HOB creation. + +**/ +VOID * +CreateHob ( + IN UINT16 HobType, + IN UINT16 HobLenght + ); + + +/** + Returns the next instance of a HOB type from the starting HOB. + + This function searches the first instance of a HOB type from the starting HOB pointer. + If there does not exist such HOB type from the starting HOB pointer, it will return NULL. + In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer + unconditionally: it returns HobStart back if HobStart itself meets the requirement; + caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + If HobStart is NULL, then ASSERT(). + + @param Type The HOB type to return. + @param HobStart The starting HOB pointer to search from. + + @return The next instance of a HOB type from the starting HOB. + +**/ +VOID * +EFIAPI +GetNextHob ( + IN UINT16 Type, + IN CONST VOID *HobStart + ); + +/** + Returns the first instance of a HOB type among the whole HOB list. + + This function searches the first instance of a HOB type among the whole HOB list. + If there does not exist such HOB type in the HOB list, it will return NULL. + + @param Type The HOB type to return. + + @return The next instance of a HOB type from the starting HOB. + +**/ +VOID * +EFIAPI +GetFirstHob ( + IN UINT16 Type + ); + +/** + This function searches the first instance of a HOB from the starting HOB pointer. + Such HOB should satisfy two conditions: + its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid. + If there does not exist such HOB from the starting HOB pointer, it will return NULL. + Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () + to extract the data section and its size info respectively. + In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer + unconditionally: it returns HobStart back if HobStart itself meets the requirement; + caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + If Guid is NULL, then ASSERT(). + If HobStart is NULL, then ASSERT(). + + @param Guid The GUID to match with in the HOB list. + @param HobStart A pointer to a Guid. + + @return The next instance of the matched GUID HOB from the starting HOB. + +**/ +VOID * +EFIAPI +GetNextGuidHob ( + IN CONST EFI_GUID *Guid, + IN CONST VOID *HobStart + ); + +/** + This function searches the first instance of a HOB among the whole HOB list. + Such HOB should satisfy two conditions: + its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid. + If there does not exist such HOB from the starting HOB pointer, it will return NULL. + Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () + to extract the data section and its size info respectively. + If Guid is NULL, then ASSERT(). + + @param Guid The GUID to match with in the HOB list. + + @return The first instance of the matched GUID HOB among the whole HOB list. + +**/ +VOID * +EFIAPI +GetFirstGuidHob ( + IN CONST EFI_GUID *Guid + ); + + +/** + Builds a HOB for a loaded PE32 module. + + This function builds a HOB for a loaded PE32 module. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If ModuleName is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + + @param ModuleName The GUID File Name of the module. + @param MemoryAllocationModule The 64 bit physical address of the module. + @param ModuleLength The length of the module in bytes. + @param EntryPoint The 64 bit physical address of the module entry point. + +**/ +VOID +EFIAPI +BuildModuleHob ( + IN CONST EFI_GUID *ModuleName, + IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule, + IN UINT64 ModuleLength, + IN EFI_PHYSICAL_ADDRESS EntryPoint + ); + +/** + Builds a HOB that describes a chunk of system memory. + + This function builds a HOB that describes a chunk of system memory. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param ResourceType The type of resource described by this HOB. + @param ResourceAttribute The resource attributes of the memory described by this HOB. + @param PhysicalStart The 64 bit physical address of memory described by this HOB. + @param NumberOfBytes The length of the memory described by this HOB in bytes. + +**/ +VOID +EFIAPI +BuildResourceDescriptorHob ( + IN EFI_RESOURCE_TYPE ResourceType, + IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute, + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes + ); + +/** + Builds a GUID HOB with a certain data length. + + This function builds a customized HOB tagged with a GUID for identification + and returns the start address of GUID HOB data so that caller can fill the customized data. + The HOB Header and Name field is already stripped. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If Guid is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + + @param Guid The GUID to tag the customized HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @return The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidHob ( + IN CONST EFI_GUID *Guid, + IN UINTN DataLength + ); + +/** + Copies a data buffer to a newly-built HOB. + + This function builds a customized HOB tagged with a GUID for identification, + copies the input data to the HOB data field and returns the start address of the GUID HOB data. + The HOB Header and Name field is already stripped. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If Guid is NULL, then ASSERT(). + If Data is NULL and DataLength > 0, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + + @param Guid The GUID to tag the customized HOB. + @param Data The data to be copied into the data field of the GUID HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @return The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidDataHob ( + IN CONST EFI_GUID *Guid, + IN VOID *Data, + IN UINTN DataLength + ); + +/** + Builds a Firmware Volume HOB. + + This function builds a Firmware Volume HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + +**/ +VOID +EFIAPI +BuildFvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Builds a Firmware Volume HOB and a resource descriptor hob + + This function builds a Firmware Volume HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + +**/ +VOID +EFIAPI +BuildFvHobs ( + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes, + IN EFI_RESOURCE_ATTRIBUTE_TYPE *ResourceAttribute OPTIONAL + ); + + +/** + Builds a EFI_HOB_TYPE_FV2 HOB. + + This function builds a EFI_HOB_TYPE_FV2 HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + @param FvName The name of the Firmware Volume. + @param FileName The name of the file. + +**/ +VOID +EFIAPI +BuildFv2Hob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN CONST EFI_GUID *FvName, + IN CONST EFI_GUID *FileName + ); + +/** + Builds a Capsule Volume HOB. + + This function builds a Capsule Volume HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Capsule Volume. + @param Length The size of the Capsule Volume in bytes. + +**/ +VOID +EFIAPI +BuildCvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Builds a HOB for the CPU. + + This function builds a HOB for the CPU. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param SizeOfMemorySpace The maximum physical memory addressability of the processor. + @param SizeOfIoSpace The maximum physical I/O addressability of the processor. + +**/ +VOID +EFIAPI +BuildCpuHob ( + IN UINT8 SizeOfMemorySpace, + IN UINT8 SizeOfIoSpace + ); + +/** + Builds a HOB for the Stack. + + This function builds a HOB for the stack. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the Stack. + @param Length The length of the stack in bytes. + +**/ +VOID +EFIAPI +BuildStackHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +/** + Update the Stack Hob if the stack has been moved + + @param BaseAddress The 64 bit physical address of the Stack. + @param Length The length of the stack in bytes. + +**/ +VOID +UpdateStackHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + + +/** + Builds a HOB for the BSP store. + + This function builds a HOB for BSP store. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the BSP. + @param Length The length of the BSP store in bytes. + @param MemoryType Type of memory allocated by this HOB. + +**/ +VOID +EFIAPI +BuildBspStoreHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_MEMORY_TYPE MemoryType + ); + +/** + Builds a HOB for the memory allocation. + + This function builds a HOB for the memory allocation. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the memory. + @param Length The length of the memory allocation in bytes. + @param MemoryType Type of memory allocated by this HOB. + +**/ +VOID +EFIAPI +BuildMemoryAllocationHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_MEMORY_TYPE MemoryType + ); + + +VOID +EFIAPI +BuildExtractSectionHob ( + IN EFI_GUID *Guid, + IN EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER SectionGetInfo, + IN EXTRACT_GUIDED_SECTION_DECODE_HANDLER SectionExtraction + ); + +VOID +EFIAPI +BuildPeCoffLoaderHob ( + VOID + ); + + +/** + Allocates one or more 4KB pages of type EfiBootServicesData. + + Allocates the number of 4KB pages of MemoryType and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePages ( + IN UINTN Pages + ); + +/** + Allocates a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a + pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePool ( + IN UINTN AllocationSize + ); + + +/** + Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedPages ( + IN UINTN Pages, + IN UINTN Alignment + ); + + +EFI_STATUS +EFIAPI +LoadPeCoffImage ( + IN VOID *PeCoffImage, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress, + OUT UINT64 *ImageSize, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint + ); + +EFI_STATUS +EFIAPI +LoadDxeCoreFromFfsFile ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN UINTN StackSize + ); + +EFI_STATUS +EFIAPI +LoadDxeCoreFromFv ( + IN UINTN *FvInstance, OPTIONAL + IN UINTN StackSize + ); + +EFI_STATUS +EFIAPI +DecompressFirstFv ( + VOID + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/RealTimeClockLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/RealTimeClockLib.h new file mode 100644 index 00000000..951bcd6d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/RealTimeClockLib.h @@ -0,0 +1,132 @@ +/** @file + Implement EFI RealTimeClock runtime services via Lib. + + Currently this driver does not support runtime virtual calling. + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __REAL_TIME_CLOCK_LIB__ +#define __REAL_TIME_CLOCK_LIB__ + + +/** + Returns the current time and date information, and the time-keeping capabilities + of the hardware platform. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time clock + device's capabilities. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ); + + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibSetTime ( + IN EFI_TIME *Time + ); + + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgement. + @param Time The current alarm setting. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Any parameter is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ); + + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If + Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +LibSetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ); + + + +/** + This is the declaration of an EFI image entry point. This can be the entry point to an application + written to this specification, an EFI boot service driver, or an EFI runtime driver. + + @param ImageHandle Handle that identifies the loaded image. + @param SystemTable System Table for this image. + + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +EFIAPI +LibRtcInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + + +/** + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +VOID +EFIAPI +LibRtcVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ); + + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/TimeBaseLib.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/TimeBaseLib.h new file mode 100644 index 00000000..d160db89 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Library/TimeBaseLib.h @@ -0,0 +1,178 @@ +/** @file +* +* Copyright (c) 2016, Hisilicon Limited. All rights reserved. +* Copyright (c) 2016-2019, Linaro Limited. All rights reserved. +* Copyright (c) 2021, Ampere Computing LLC. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef _TIME_BASE_LIB_H_ +#define _TIME_BASE_LIB_H_ + +#include + +// +// Convenience macros to obtain a build date +// +// These macros should work for any compiler that follows ISO/IEC 9899, +// in which case __DATE__ is defined as a "Mmm dd yyyy" 11 chars string, +// but add an explicit filter for compilers that have been validated. +// +#if (defined(__GNUC__) || defined(_MSC_VER) || defined(__clang__)) +#define TIME_BUILD_YEAR (__DATE__[7] == '?' ? 1900 \ + : (((__DATE__[7] - '0') * 1000 ) \ + + (__DATE__[8] - '0') * 100 \ + + (__DATE__[9] - '0') * 10 \ + + __DATE__[10] - '0')) +#define TIME_BUILD_MONTH ( __DATE__ [2] == '?' ? 1 \ + : __DATE__ [2] == 'n' ? ( \ + __DATE__ [1] == 'a' ? 1 : 6) \ + : __DATE__ [2] == 'b' ? 2 \ + : __DATE__ [2] == 'r' ? ( \ + __DATE__ [0] == 'M' ? 3 : 4) \ + : __DATE__ [2] == 'y' ? 5 \ + : __DATE__ [2] == 'l' ? 7 \ + : __DATE__ [2] == 'g' ? 8 \ + : __DATE__ [2] == 'p' ? 9 \ + : __DATE__ [2] == 't' ? 10 \ + : __DATE__ [2] == 'v' ? 11 \ + : 12) +#define TIME_BUILD_DAY ( __DATE__[4] == '?' ? 1 \ + : ((__DATE__[4] == ' ' ? 0 : \ + ((__DATE__[4] - '0') * 10)) \ + + __DATE__[5] - '0')) +#endif + +// Define EPOCH (1970-JANUARY-01) in the Julian Date representation +#define EPOCH_JULIAN_DATE 2440588 + +// Seconds per unit +#define SEC_PER_MIN ((UINTN) 60) +#define SEC_PER_HOUR ((UINTN) 3600) +#define SEC_PER_DAY ((UINTN) 86400) + +/** + Check if it is a leap year. + + @param Time The UEFI time to be checked. + + @retval TRUE It is a leap year. + @retval FALSE It is NOT a leap year. + +**/ +BOOLEAN +EFIAPI +IsLeapYear ( + IN EFI_TIME *Time + ); + +/** + Check if the day in the UEFI time is valid. + + @param Time The UEFI time to be checked. + + @retval TRUE Valid. + @retval FALSE Invalid. + +**/ +BOOLEAN +EFIAPI +IsDayValid ( + IN EFI_TIME *Time + ); + +/** + Check if the time zone is valid. + Valid values are between -1440 and 1440 or 2047 (EFI_UNSPECIFIED_TIMEZONE). + + @param TimeZone The time zone to be checked. + + @retval TRUE Valid. + @retval FALSE Invalid. + +**/ +BOOLEAN +EFIAPI +IsValidTimeZone ( + IN INT16 TimeZone + ); + +/** + Check if the daylight is valid. + Valid values are: + 0 : Time is not affected. + 1 : Time is affected, and has not been adjusted for daylight savings. + 3 : Time is affected, and has been adjusted for daylight savings. + All other values are invalid. + + @param Daylight The daylight to be checked. + + @retval TRUE Valid. + @retval FALSE Invalid. + +**/ +BOOLEAN +EFIAPI +IsValidDaylight ( + IN INT8 Daylight + ); + +/** + Check if the UEFI time is valid. + + @param Time The UEFI time to be checked. + + @retval TRUE Valid. + @retval FALSE Invalid. + +**/ +BOOLEAN +EFIAPI +IsTimeValid ( + IN EFI_TIME *Time + ); + +/** + Converts Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC) to EFI_TIME. + + @param EpochSeconds Epoch seconds. + @param Time The time converted to UEFI format. + +**/ +VOID +EFIAPI +EpochToEfiTime ( + IN UINTN EpochSeconds, + OUT EFI_TIME *Time + ); + +/** + Converts EFI_TIME to Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC). + + @param Time The UEFI time to be converted. + + @return Number of seconds. + +**/ +UINTN +EFIAPI +EfiTimeToEpoch ( + IN EFI_TIME *Time + ); + +/** + Get the day of the week from the UEFI time. + + @param Time The UEFI time to be calculated. + + @return The day of the week: Sunday=0, Monday=1, ... Saturday=6 + +**/ +UINTN +EfiTimeToWday ( + IN EFI_TIME *Time + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Ppi/EmbeddedGpio.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Ppi/EmbeddedGpio.h new file mode 100644 index 00000000..9b8822c9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Ppi/EmbeddedGpio.h @@ -0,0 +1,145 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __EMBEDDED_GPIO_PPI_H__ +#define __EMBEDDED_GPIO_PPI_H__ + +// +// Protocol interface structure +// +typedef struct _EMBEDDED_GPIO_PPI EMBEDDED_GPIO_PPI; + +// +// Data Types +// +typedef UINTN EMBEDDED_GPIO_PIN; + +#define GPIO(Port, Pin) ((EMBEDDED_GPIO_PIN)(((Port) << (16)) | (Pin))) +#define GPIO_PIN(x) ((EMBEDDED_GPIO_PIN)(x) & (0xFFFF)) +#define GPIO_PORT(x) ((EMBEDDED_GPIO_PIN)(x) >> (16)) + +typedef enum { + GPIO_MODE_INPUT = 0x00, + GPIO_MODE_OUTPUT_0 = 0x0E, + GPIO_MODE_OUTPUT_1 = 0x0F, + GPIO_MODE_SPECIAL_FUNCTION_2 = 0x02, + GPIO_MODE_SPECIAL_FUNCTION_3 = 0x03, + GPIO_MODE_SPECIAL_FUNCTION_4 = 0x04, + GPIO_MODE_SPECIAL_FUNCTION_5 = 0x05, + GPIO_MODE_SPECIAL_FUNCTION_6 = 0x06, + GPIO_MODE_SPECIAL_FUNCTION_7 = 0x07 +} EMBEDDED_GPIO_MODE; + +typedef enum { + GPIO_PULL_NONE, + GPIO_PULL_UP, + GPIO_PULL_DOWN +} EMBEDDED_GPIO_PULL; + +// +// Function Prototypes +// + +/** + + Gets the state of a GPIO pin + + @param This Pointer to protocol + @param Gpio Which pin to read + @param Value State of the pin + + @retval EFI_SUCCESS GPIO state returned in Value + @retval EFI_INVALID_PARAMETER Value is NULL + @retval EFI_NOT_FOUND Pin does not exit + +**/ +typedef +EFI_STATUS +(EFIAPI *EMBEDDED_GPIO_GET) ( + IN EMBEDDED_GPIO_PPI *This, + IN EMBEDDED_GPIO_PIN Gpio, + OUT UINTN *Value + ); + +/** + + Sets the state of a GPIO pin + + @param This Pointer to protocol + @param Gpio Which pin to modify + @param Mode Mode to set + + @retval EFI_SUCCESS GPIO set as requested + @retval EFI_INVALID_PARAMETER Invalid mode + @retval EFI_NOT_FOUND Pin does not exit + +**/ +typedef +EFI_STATUS +(EFIAPI *EMBEDDED_GPIO_SET) ( + IN EMBEDDED_GPIO_PPI *This, + IN EMBEDDED_GPIO_PIN Gpio, + IN EMBEDDED_GPIO_MODE Mode + ); + + +/** + + Gets the mode (function) of a GPIO pin + + @param This Pointer to protocol + @param Gpio Which pin + @param Mode Pointer to output mode value + + @retval EFI_SUCCESS Mode value retrieved + @retval EFI_INVALID_PARAMETER Mode is NULL + @retval EFI_NOT_FOUND Pin does not exit + +**/ +typedef +EFI_STATUS +(EFIAPI *EMBEDDED_GPIO_GET_MODE) ( + IN EMBEDDED_GPIO_PPI *This, + IN EMBEDDED_GPIO_PIN Gpio, + OUT EMBEDDED_GPIO_MODE *Mode + ); + + +/** + + Sets the pull-up / pull-down resistor of a GPIO pin + + @param This Pointer to PPI + @param Gpio Port/pin index + @param Pull The pullup/pulldown mode to set + + @retval EFI_SUCCESS Mode was set + @retval EFI_NOT_FOUND Pin does not exist + @retval EFI_UNSUPPORTED Action not supported + +**/ +typedef +EFI_STATUS +(EFIAPI *EMBEDDED_GPIO_SET_PULL) ( + IN EMBEDDED_GPIO_PPI *This, + IN EMBEDDED_GPIO_PIN Gpio, + IN EMBEDDED_GPIO_PULL Direction + ); + + +struct _EMBEDDED_GPIO_PPI { + EMBEDDED_GPIO_GET Get; + EMBEDDED_GPIO_SET Set; + EMBEDDED_GPIO_GET_MODE GetMode; + EMBEDDED_GPIO_SET_PULL SetPull; +}; + +extern EFI_GUID gEmbeddedGpioPpiGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/AndroidBootImg.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/AndroidBootImg.h new file mode 100644 index 00000000..af873fe1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/AndroidBootImg.h @@ -0,0 +1,41 @@ +/** @file + + Copyright (c) 2017, Linaro. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __ANDROID_BOOTIMG_PROTOCOL_H__ +#define __ANDROID_BOOTIMG_PROTOCOL_H__ + +// +// Protocol interface structure +// +typedef struct _ANDROID_BOOTIMG_PROTOCOL ANDROID_BOOTIMG_PROTOCOL; + +// +// Function Prototypes +// +typedef +EFI_STATUS +(EFIAPI *ANDROID_BOOTIMG_APPEND_KERNEL_ARGS) ( + IN CHAR16 *Args, + IN UINTN Size + ); + +typedef +EFI_STATUS +(EFIAPI *ANDROID_BOOTIMG_UPDATE_DTB) ( + IN EFI_PHYSICAL_ADDRESS OrigDtbBase, + OUT EFI_PHYSICAL_ADDRESS *NewDtbBase + ); + +struct _ANDROID_BOOTIMG_PROTOCOL { + ANDROID_BOOTIMG_APPEND_KERNEL_ARGS AppendArgs; + ANDROID_BOOTIMG_UPDATE_DTB UpdateDtb; +}; + +extern EFI_GUID gAndroidBootImgProtocolGuid; + +#endif /* __ANDROID_BOOTIMG_PROTOCOL_H__ */ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/AndroidFastbootPlatform.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/AndroidFastbootPlatform.h new file mode 100644 index 00000000..d3a5c0b4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/AndroidFastbootPlatform.h @@ -0,0 +1,139 @@ +/** @file + + Copyright (c) 2014, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __ANDROID_FASTBOOT_PLATFORM_H__ +#define __ANDROID_FASTBOOT_PLATFORM_H__ + +extern EFI_GUID gAndroidFastbootPlatformProtocolGuid; + +/* + Protocol for platform-specific operations initiated by Android Fastboot. + + Based on Fastboot Protocol version 0.4. See + system/core/fastboot/fastboot_protocol.txt in the AOSP source tree for more + info. + + Doesn't support image verification. +*/ + +/* + Do any initialisation that needs to be done in order to be able to respond to + commands. + + @retval EFI_SUCCESS Initialised successfully. + @retval !EFI_SUCCESS Error in initialisation. +*/ +typedef +EFI_STATUS +(*FASTBOOT_PLATFORM_INIT) ( + VOID + ); + +/* + To be called when Fastboot is finished and we aren't rebooting or booting an + image. Undo initialisation, free resources. +*/ +typedef +VOID +(*FASTBOOT_PLATFORM_UN_INIT) ( + VOID + ); + +/* + Flash the partition named (according to a platform-specific scheme) + PartitionName, with the image pointed to by Buffer, whose size is BufferSize. + + @param[in] PartitionName Null-terminated name of partition to write. + @param[in] BufferSize Size of Buffer in bytes. + @param[in] Buffer Data to write to partition. + + @retval EFI_NOT_FOUND No such partition. + @retval EFI_DEVICE_ERROR Flashing failed. +*/ +typedef +EFI_STATUS +(*FASTBOOT_PLATFORM_FLASH) ( + IN CHAR8 *PartitionName, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +/* + Erase the partition named PartitionName. + + @param[in] PartitionName Null-terminated name of partition to erase. + + @retval EFI_NOT_FOUND No such partition. + @retval EFI_DEVICE_ERROR Erasing failed. +*/ +typedef +EFI_STATUS +(*FASTBOOT_PLATFORM_ERASE) ( + IN CHAR8 *PartitionName + ); + +/* + If the variable referred to by Name exists, copy it (as a null-terminated + string) into Value. If it doesn't exist, put the Empty string in Value. + + Variable names and values may not be larger than 60 bytes, excluding the + terminal null character. This is a limitation of the Fastboot protocol. + + The Fastboot application will handle platform-nonspecific variables + (Currently "version" is the only one of these.) + + @param[in] Name Null-terminated name of Fastboot variable to retrieve. + @param[out] Value Caller-allocated buffer for null-terminated value of + variable. + + @retval EFI_SUCCESS The variable was retrieved, or it doesn't exist. + @retval EFI_DEVICE_ERROR There was an error looking up the variable. This + does _not_ include the variable not existing. +*/ +typedef +EFI_STATUS +(*FASTBOOT_PLATFORM_GETVAR) ( + IN CHAR8 *Name, + OUT CHAR8 *Value + ); + +/* + React to an OEM-specific command. + + Future versions of this function might want to allow the platform to do some + extra communication with the host. A way to do this would be to add a function + to the FASTBOOT_TRANSPORT_PROTOCOL that allows the implementation of + DoOemCommand to replace the ReceiveEvent with its own, and to restore the old + one when it's finished. + + However at the moment although the specification allows it, the AOSP fastboot + host application doesn't handle receiving any data from the client, and it + doesn't support a data phase for OEM commands. + + @param[in] Command Null-terminated command string. + + @retval EFI_SUCCESS The command executed successfully. + @retval EFI_NOT_FOUND The command wasn't recognised. + @retval EFI_DEVICE_ERROR There was an error executing the command. +*/ +typedef +EFI_STATUS +(*FASTBOOT_PLATFORM_OEM_COMMAND) ( + IN CHAR8 *Command + ); + +typedef struct _FASTBOOT_PLATFORM_PROTOCOL { + FASTBOOT_PLATFORM_INIT Init; + FASTBOOT_PLATFORM_UN_INIT UnInit; + FASTBOOT_PLATFORM_FLASH FlashPartition; + FASTBOOT_PLATFORM_ERASE ErasePartition; + FASTBOOT_PLATFORM_GETVAR GetVar; + FASTBOOT_PLATFORM_OEM_COMMAND DoOemCommand; +} FASTBOOT_PLATFORM_PROTOCOL; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/AndroidFastbootTransport.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/AndroidFastbootTransport.h new file mode 100644 index 00000000..3b4fe1af --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/AndroidFastbootTransport.h @@ -0,0 +1,125 @@ +/** @file + + Copyright (c) 2014, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +/* + Transport protocol over which Android Fastboot transactions can be made. + Fastboot is designed for USB, but this protocol is intended as an abstraction + so that it can be implemented over any transport mechanism. +*/ + +#ifndef __ANDROID_FASTBOOT_TRANSPORT_H__ +#define __ANDROID_FASTBOOT_TRANSPORT_H__ + +extern EFI_GUID gAndroidFastbootTransportProtocolGuid; + +/* + Set up the transport system for use by Fastboot. + e.g. For USB this probably means making the device enumerable. For TCP, + preparing to accept incoming connections. + + It is _not_ the responsibility of this protocol's implementer to unite the + data phase into a single buffer - that is handled by the Fastboot UEFI + application. As the Fastboot protocol spec says: "Short packets are always + acceptable and zero-length packets are ignored." + However the commands and responses must be in a single packet, and the order + of the packets must of course be maintained. + + If there is a fatal error in the receive channel, ReceiveEvent will be + signalled, and a subsequent call to Receive() will return an error. This + allows data transported prior to the error to be received. + + @param[in] ReceiveEvent Event to be Signalled when a packet has been received + and is ready to be retrieved via Receive(). + + @retval EFI_SUCCESS Initialised successfully. + @retval EFI_DEVICE_ERROR Error in initialising hardware + @retval (other) Error return from LocateProtocol functions. +*/ +typedef +EFI_STATUS +(*FASTBOOT_TRANSPORT_START) ( + IN EFI_EVENT ReceiveEvent + ); + +/* + Function to be called when all Fastboot transactions are finished, to + de-initialise the transport system. + e.g. A USB OTG system might want to get out of peripheral mode so it can be + a USB host. + + Note that this function will be called after an error is reported by Send or + Receive + + @retval EFI_SUCCESS De-initialised successfully. + @retval EFI_DEVICE_ERROR Error de-initialising hardware. +*/ +typedef +EFI_STATUS +(* FASTBOOT_TRANSPORT_STOP) ( + VOID + ); + +/* + Send data. This function can be used both for command responses like "OKAY" + and for the data phase (the protocol doesn't describe any situation when the + latter might be necessary, but does allow it) + + Transmission need not finish before the function returns. + If there is an error in transmission from which the transport system cannot + recover, FatalErrorEvent will be signalled. Otherwise, it is assumed that all + data was delivered successfully. + + @param[in] BufferSize Size in bytes of data to send. + @param[in] Buffer Data to send. + @param[in] FatalErrorEvent Event to signal if there was an error in + transmission from which the transport system + cannot recover. + + @retval EFI_SUCCESS The data was sent or queued for send. + @retval EFI_DEVICE_ERROR There was an error preparing to send the data. + */ +typedef +EFI_STATUS +(*FASTBOOT_TRANSPORT_SEND) ( + IN UINTN BufferSize, + IN CONST VOID *Buffer, + IN EFI_EVENT *FatalErrorEvent + ); + +/* + When the event has been Signalled to say data is available from the host, + this function is used to get data. In order to handle the case where several + packets are received before ReceiveEvent's notify function is called, packets + received are queued, and each call to this function returns the next packet in + the queue. It should therefore be called in a loop, the exit condition being a + return of EFI_NOT_READY. + + @param[out] Buffer Pointer to received data. Callee allocated - the + caller must free it with FreePool. + @param[out] BufferSize The size of received data in bytes + + @retval EFI_NOT_READY There is no data available + @retval EFI_DEVICE_ERROR There was a fatal error in the receive channel. + e.g. for USB the cable was unplugged or for TCP the + connection was closed by the remote host.. +*/ +typedef +EFI_STATUS +(*FASTBOOT_TRANSPORT_RECEIVE) ( + OUT UINTN *BufferSize, + OUT VOID **Buffer + ); + +typedef struct _FASTBOOT_TRANSPORT_PROTOCOL { + FASTBOOT_TRANSPORT_START Start; + FASTBOOT_TRANSPORT_STOP Stop; + FASTBOOT_TRANSPORT_SEND Send; + FASTBOOT_TRANSPORT_RECEIVE Receive; +} FASTBOOT_TRANSPORT_PROTOCOL; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/EmbeddedDevice.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/EmbeddedDevice.h new file mode 100644 index 00000000..5084accb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/EmbeddedDevice.h @@ -0,0 +1,52 @@ +/** @file + Deal with devices that just exist in memory space. + + To follow the EFI driver model you need a root handle to start with. An + EFI driver will have a driver binding protocol (Supported, Start, Stop) + that is used to layer on top of a handle via a gBS->ConnectController. + The first handle has to just be in the system to make that work. For + PCI it is a PCI Root Bridge IO protocol that provides the root. + + On an embedded system with MMIO device we need a handle to just + show up. That handle will have this protocol and a device path + protocol on it. + + For an ethernet device the device path must contain a MAC address device path + node. + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __EMBEDDED_DEVICE_PROTOCOL_H__ +#define __EMBEDDED_DEVICE_PROTOCOL_H__ + + +// +// Protocol GUID +// +// BF4B9D10-13EC-43dd-8880-E90B718F27DE + +#define EMBEDDED_DEVICE_PROTOCOL_GUID \ + { 0xbf4b9d10, 0x13ec, 0x43dd, { 0x88, 0x80, 0xe9, 0xb, 0x71, 0x8f, 0x27, 0xde } } + + + +typedef struct { + UINT16 VendorId; + UINT16 DeviceId; + UINT16 RevisionId; + UINT16 SubsystemId; + UINT16 SubsystemVendorId; + UINT8 ClassCode[3]; + UINT8 HeaderSize; + UINTN BaseAddress; +} EMBEDDED_DEVICE_PROTOCOL; + +extern EFI_GUID gEmbeddedDeviceGuid; + +#endif + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/EmbeddedExternalDevice.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/EmbeddedExternalDevice.h new file mode 100644 index 00000000..946c1ec2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/EmbeddedExternalDevice.h @@ -0,0 +1,88 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __EMBEDDED_EXTERNAL_DEVICE_H__ +#define __EMBEDDED_EXTERNAL_DEVICE_H__ + +// +// Protocol GUID +// +#define EMBEDDED_EXTERNAL_DEVICE_PROTOCOL_GUID { 0x735F8C64, 0xD696, 0x44D0, { 0xBD, 0xF2, 0x44, 0x7F, 0xD0, 0x5A, 0x54, 0x06 }} + +// +// Protocol interface structure +// +typedef struct _EMBEDDED_EXTERNAL_DEVICE EMBEDDED_EXTERNAL_DEVICE; + +// +// Function Prototypes +// +typedef +EFI_STATUS +(EFIAPI *EMBEDDED_EXTERNAL_DEVICE_READ) ( + IN EMBEDDED_EXTERNAL_DEVICE *This, + IN UINTN Register, + IN UINTN Length, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Read a set of contiguous external device registers. + +Arguments: + + This - pointer to protocol + Offset - starting register number + Length - number of bytes to read + Buffer - destination buffer + +Returns: + + EFI_SUCCESS - registers read successfully + +--*/ +; + +typedef +EFI_STATUS +(EFIAPI *EMBEDDED_EXTERNAL_DEVICE_WRITE) ( + IN EMBEDDED_EXTERNAL_DEVICE *This, + IN UINTN Register, + IN UINTN Length, + IN VOID *Buffer + ) +/*++ + +Routine Description: + + Write to a set of contiguous external device registers. + +Arguments: + + This - pointer to protocol + Offset - starting register number + Length - number of bytes to write + Buffer - source buffer + +Returns: + + EFI_SUCCESS - registers written successfully + +--*/ +; + +struct _EMBEDDED_EXTERNAL_DEVICE { + EMBEDDED_EXTERNAL_DEVICE_READ Read; + EMBEDDED_EXTERNAL_DEVICE_WRITE Write; +}; + +extern EFI_GUID gEmbeddedExternalDeviceProtocolGuid; + +#endif // __EMBEDDED_EXTERNAL_DEVICE_H__ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/EmbeddedGpio.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/EmbeddedGpio.h new file mode 100644 index 00000000..1421a9bb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/EmbeddedGpio.h @@ -0,0 +1,178 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __EMBEDDED_GPIO_H__ +#define __EMBEDDED_GPIO_H__ + +// +// Protocol interface structure +// +typedef struct _EMBEDDED_GPIO EMBEDDED_GPIO; + +// +// Data Types +// +typedef UINTN EMBEDDED_GPIO_PIN; + +#define GPIO(Port, Pin) ((EMBEDDED_GPIO_PIN)(((Port) << (16)) | (Pin))) +#define GPIO_PIN(x) ((EMBEDDED_GPIO_PIN)(x) & (0xFFFF)) +#define GPIO_PORT(x) ((EMBEDDED_GPIO_PIN)(x) >> (16)) + +typedef enum { + GPIO_MODE_INPUT = 0x00, + GPIO_MODE_OUTPUT_0 = 0x0E, + GPIO_MODE_OUTPUT_1 = 0x0F, + GPIO_MODE_SPECIAL_FUNCTION_2 = 0x02, + GPIO_MODE_SPECIAL_FUNCTION_3 = 0x03, + GPIO_MODE_SPECIAL_FUNCTION_4 = 0x04, + GPIO_MODE_SPECIAL_FUNCTION_5 = 0x05, + GPIO_MODE_SPECIAL_FUNCTION_6 = 0x06, + GPIO_MODE_SPECIAL_FUNCTION_7 = 0x07 +} EMBEDDED_GPIO_MODE; + +typedef enum { + GPIO_PULL_NONE, + GPIO_PULL_UP, + GPIO_PULL_DOWN +} EMBEDDED_GPIO_PULL; + +// +// Function Prototypes +// +typedef +EFI_STATUS +(EFIAPI *EMBEDDED_GPIO_GET) ( + IN EMBEDDED_GPIO *This, + IN EMBEDDED_GPIO_PIN Gpio, + OUT UINTN *Value + ); +/*++ + +Routine Description: + + Gets the state of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin to read + Value - state of the pin + +Returns: + + EFI_SUCCESS - GPIO state returned in Value + +--*/ + + +typedef +EFI_STATUS +(EFIAPI *EMBEDDED_GPIO_SET) ( + IN EMBEDDED_GPIO *This, + IN EMBEDDED_GPIO_PIN Gpio, + IN EMBEDDED_GPIO_MODE Mode + ); +/*++ + +Routine Description: + + Sets the state of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin to modify + Mode - mode to set + +Returns: + + EFI_SUCCESS - GPIO set as requested + +--*/ + + +typedef +EFI_STATUS +(EFIAPI *EMBEDDED_GPIO_GET_MODE) ( + IN EMBEDDED_GPIO *This, + IN EMBEDDED_GPIO_PIN Gpio, + OUT EMBEDDED_GPIO_MODE *Mode + ); +/*++ + +Routine Description: + + Gets the mode (function) of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin + Mode - pointer to output mode value + +Returns: + + EFI_SUCCESS - mode value retrieved + +--*/ + + +typedef +EFI_STATUS +(EFIAPI *EMBEDDED_GPIO_SET_PULL) ( + IN EMBEDDED_GPIO *This, + IN EMBEDDED_GPIO_PIN Gpio, + IN EMBEDDED_GPIO_PULL Direction + ); +/*++ + +Routine Description: + + Sets the pull-up / pull-down resistor of a GPIO pin + +Arguments: + + This - pointer to protocol + Gpio - which pin + Direction - pull-up, pull-down, or none + +Returns: + + EFI_SUCCESS - pin was set + +--*/ + + + +struct _EMBEDDED_GPIO { + EMBEDDED_GPIO_GET Get; + EMBEDDED_GPIO_SET Set; + EMBEDDED_GPIO_GET_MODE GetMode; + EMBEDDED_GPIO_SET_PULL SetPull; +}; + +extern EFI_GUID gEmbeddedGpioProtocolGuid; + +typedef struct _GPIO_CONTROLLER GPIO_CONTROLLER; +typedef struct _PLATFORM_GPIO_CONTROLLER PLATFORM_GPIO_CONTROLLER; + +struct _GPIO_CONTROLLER { + UINTN RegisterBase; + UINTN GpioIndex; + UINTN InternalGpioCount; +}; + +struct _PLATFORM_GPIO_CONTROLLER { + UINTN GpioCount; + UINTN GpioControllerCount; + GPIO_CONTROLLER *GpioController; +}; + +extern EFI_GUID gPlatformGpioProtocolGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/HardwareInterrupt.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/HardwareInterrupt.h new file mode 100644 index 00000000..ff7dc572 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/HardwareInterrupt.h @@ -0,0 +1,164 @@ +/** @file + Abstraction for hardware based interrupt routine + + On non IA-32 systems it is common to have a single hardware interrupt vector + and a 2nd layer of software that routes the interrupt handlers based on the + interrupt source. This protocol enables this routing. The driver implementing + this protocol is responsible for clearing the pending interrupt in the + interrupt routing hardware. The HARDWARE_INTERRUPT_HANDLER is responsible + for clearing interrupt sources from individual devices. + + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __HARDWARE_INTERRUPT_H__ +#define __HARDWARE_INTERRUPT_H__ + +#include + + +// +// Protocol GUID +// +// EAB39028-3D05-4316-AD0C-D64808DA3FF1 + +#define EFI_HARDWARE_INTERRUPT_PROTOCOL_GGUID \ + { 0x2890B3EA, 0x053D, 0x1643, { 0xAD, 0x0C, 0xD6, 0x48, 0x08, 0xDA, 0x3F, 0xF1 } } + + +typedef struct _EFI_HARDWARE_INTERRUPT_PROTOCOL EFI_HARDWARE_INTERRUPT_PROTOCOL; + + +typedef UINTN HARDWARE_INTERRUPT_SOURCE; + + +/** + C Interrupt Handler calledin the interrupt context when Source interrupt is active. + + @param Source Source of the interrupt. Hardware routing off a specific platform defines + what source means. + @param SystemContext Pointer to system register context. Mostly used by debuggers and will + update the system context after the return from the interrupt if + modified. Don't change these values unless you know what you are doing + +**/ +typedef +VOID +(EFIAPI *HARDWARE_INTERRUPT_HANDLER) ( + IN HARDWARE_INTERRUPT_SOURCE Source, + IN EFI_SYSTEM_CONTEXT SystemContext + ); + + +/** + Register Handler for the specified interrupt source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + @param Handler Callback for interrupt. NULL to unregister + + @retval EFI_SUCCESS Source was updated to support Handler. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +typedef +EFI_STATUS +(EFIAPI *HARDWARE_INTERRUPT_REGISTER) ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source, + IN HARDWARE_INTERRUPT_HANDLER Handler + ); + + +/** + Enable interrupt source Source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + + @retval EFI_SUCCESS Source interrupt enabled. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +typedef +EFI_STATUS +(EFIAPI *HARDWARE_INTERRUPT_ENABLE) ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source + ); + + + +/** + Disable interrupt source Source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + + @retval EFI_SUCCESS Source interrupt disabled. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +typedef +EFI_STATUS +(EFIAPI *HARDWARE_INTERRUPT_DISABLE) ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source + ); + + +/** + Return current state of interrupt source Source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + @param InterruptState TRUE: source enabled, FALSE: source disabled. + + @retval EFI_SUCCESS InterruptState is valid + @retval EFI_DEVICE_ERROR InterruptState is not valid + +**/ +typedef +EFI_STATUS +(EFIAPI *HARDWARE_INTERRUPT_INTERRUPT_STATE) ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source, + IN BOOLEAN *InterruptState + ); + +/** + Signal to the hardware that the End Of Interrupt state + has been reached. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + + @retval EFI_SUCCESS Source interrupt EOI'ed. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +typedef +EFI_STATUS +(EFIAPI *HARDWARE_INTERRUPT_END_OF_INTERRUPT) ( + IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source + ); + + +struct _EFI_HARDWARE_INTERRUPT_PROTOCOL { + HARDWARE_INTERRUPT_REGISTER RegisterInterruptSource; + HARDWARE_INTERRUPT_ENABLE EnableInterruptSource; + HARDWARE_INTERRUPT_DISABLE DisableInterruptSource; + HARDWARE_INTERRUPT_INTERRUPT_STATE GetInterruptSourceState; + HARDWARE_INTERRUPT_END_OF_INTERRUPT EndOfInterrupt; +}; + +extern EFI_GUID gHardwareInterruptProtocolGuid; + +#endif + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/HardwareInterrupt2.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/HardwareInterrupt2.h new file mode 100644 index 00000000..b4dbc10d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/HardwareInterrupt2.h @@ -0,0 +1,176 @@ +/** @file + + Copyright (c) 2016-2017, Linaro Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __HARDWARE_INTERRUPT2_H__ +#define __HARDWARE_INTERRUPT2_H__ + +#include + +// 22838932-1a2d-4a47-aaba-f3f7cf569470 + +#define EFI_HARDWARE_INTERRUPT2_PROTOCOL_GUID \ + { 0x32898322, 0x2d1a, 0x474a, \ + { 0xba, 0xaa, 0xf3, 0xf7, 0xcf, 0x56, 0x94, 0x70 } } + +typedef enum { + EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_LOW, + EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH, + EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_FALLING, + EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING, +} EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE; + +typedef struct _EFI_HARDWARE_INTERRUPT2_PROTOCOL \ + EFI_HARDWARE_INTERRUPT2_PROTOCOL; + +/** + Register Handler for the specified interrupt source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + @param Handler Callback for interrupt. NULL to unregister + + @retval EFI_SUCCESS Source was updated to support Handler. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +typedef +EFI_STATUS +(EFIAPI *HARDWARE_INTERRUPT2_REGISTER) ( + IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source, + IN HARDWARE_INTERRUPT_HANDLER Handler + ); + + +/** + Enable interrupt source Source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + + @retval EFI_SUCCESS Source interrupt enabled. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +typedef +EFI_STATUS +(EFIAPI *HARDWARE_INTERRUPT2_ENABLE) ( + IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source + ); + + +/** + Disable interrupt source Source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + + @retval EFI_SUCCESS Source interrupt disabled. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +typedef +EFI_STATUS +(EFIAPI *HARDWARE_INTERRUPT2_DISABLE) ( + IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source + ); + + +/** + Return current state of interrupt source Source. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + @param InterruptState TRUE: source enabled, FALSE: source disabled. + + @retval EFI_SUCCESS InterruptState is valid + @retval EFI_DEVICE_ERROR InterruptState is not valid + +**/ +typedef +EFI_STATUS +(EFIAPI *HARDWARE_INTERRUPT2_INTERRUPT_STATE) ( + IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source, + IN BOOLEAN *InterruptState + ); + +/** + Signal to the hardware that the End Of Interrupt state + has been reached. + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + + @retval EFI_SUCCESS Source interrupt EOI'ed. + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +typedef +EFI_STATUS +(EFIAPI *HARDWARE_INTERRUPT2_END_OF_INTERRUPT) ( + IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source + ); + +/** + Return the configured trigger type for an interrupt source + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + @param TriggerType The configured trigger type + + @retval EFI_SUCCESS Operation successful + @retval EFI_DEVICE_ERROR Information could not be returned + +**/ +typedef +EFI_STATUS +(EFIAPI *HARDWARE_INTERRUPT2_GET_TRIGGER_TYPE) ( + IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source, + OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE *TriggerType + ); + + +/** + Configure the trigger type for an interrupt source + + @param This Instance pointer for this protocol + @param Source Hardware source of the interrupt + @param TriggerType The trigger type to configure + + @retval EFI_SUCCESS Operation successful + @retval EFI_DEVICE_ERROR Hardware could not be programmed. + +**/ +typedef +EFI_STATUS +(EFIAPI *HARDWARE_INTERRUPT2_SET_TRIGGER_TYPE) ( + IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *This, + IN HARDWARE_INTERRUPT_SOURCE Source, + IN EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE TriggerType + ); + +struct _EFI_HARDWARE_INTERRUPT2_PROTOCOL { + HARDWARE_INTERRUPT2_REGISTER RegisterInterruptSource; + HARDWARE_INTERRUPT2_ENABLE EnableInterruptSource; + HARDWARE_INTERRUPT2_DISABLE DisableInterruptSource; + HARDWARE_INTERRUPT2_INTERRUPT_STATE GetInterruptSourceState; + HARDWARE_INTERRUPT2_END_OF_INTERRUPT EndOfInterrupt; + + // v2 members + HARDWARE_INTERRUPT2_GET_TRIGGER_TYPE GetTriggerType; + HARDWARE_INTERRUPT2_SET_TRIGGER_TYPE SetTriggerType; +}; + +extern EFI_GUID gHardwareInterrupt2ProtocolGuid; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/MmcHost.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/MmcHost.h new file mode 100644 index 00000000..03f4e7d0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/MmcHost.h @@ -0,0 +1,184 @@ +/** @file + Definition of the MMC Host Protocol + + Copyright (c) 2011-2014, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __MMC_HOST_H__ +#define __MMC_HOST_H__ + +/// +/// Global ID for the MMC Host Protocol +/// +#define EMBEDDED_MMC_HOST_PROTOCOL_GUID \ + { 0x3e591c00, 0x9e4a, 0x11df, {0x92, 0x44, 0x00, 0x02, 0xA5, 0xD5, 0xC5, 0x1B } } + +#define MMC_RESPONSE_TYPE_R1 0 +#define MMC_RESPONSE_TYPE_R1b 0 +#define MMC_RESPONSE_TYPE_R2 1 +#define MMC_RESPONSE_TYPE_R3 0 +#define MMC_RESPONSE_TYPE_R6 0 +#define MMC_RESPONSE_TYPE_R7 0 +#define MMC_RESPONSE_TYPE_OCR 0 +#define MMC_RESPONSE_TYPE_CID 1 +#define MMC_RESPONSE_TYPE_CSD 1 +#define MMC_RESPONSE_TYPE_RCA 0 + +typedef UINT32 MMC_RESPONSE_TYPE; + +typedef UINT32 MMC_CMD; + +#define MMC_CMD_WAIT_RESPONSE (1 << 16) +#define MMC_CMD_LONG_RESPONSE (1 << 17) +#define MMC_CMD_NO_CRC_RESPONSE (1 << 18) + +#define MMC_INDX(Index) ((Index) & 0xFFFF) +#define MMC_GET_INDX(MmcCmd) ((MmcCmd) & 0xFFFF) + +#define MMC_CMD0 (MMC_INDX(0) | MMC_CMD_NO_CRC_RESPONSE) +#define MMC_CMD1 (MMC_INDX(1) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_NO_CRC_RESPONSE) +#define MMC_CMD2 (MMC_INDX(2) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_LONG_RESPONSE) +#define MMC_CMD3 (MMC_INDX(3) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD5 (MMC_INDX(5) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_NO_CRC_RESPONSE) +#define MMC_CMD6 (MMC_INDX(6) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD7 (MMC_INDX(7) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD8 (MMC_INDX(8) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD9 (MMC_INDX(9) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_LONG_RESPONSE) +#define MMC_CMD11 (MMC_INDX(11) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD12 (MMC_INDX(12) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD13 (MMC_INDX(13) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD16 (MMC_INDX(16) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD17 (MMC_INDX(17) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD18 (MMC_INDX(18) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD20 (MMC_INDX(20) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD23 (MMC_INDX(23) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD24 (MMC_INDX(24) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD25 (MMC_INDX(25) | MMC_CMD_WAIT_RESPONSE) +#define MMC_CMD55 (MMC_INDX(55) | MMC_CMD_WAIT_RESPONSE) +#define MMC_ACMD41 (MMC_INDX(41) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_NO_CRC_RESPONSE) +#define MMC_ACMD51 (MMC_INDX(51) | MMC_CMD_WAIT_RESPONSE) + +// Valid responses for CMD1 in eMMC +#define EMMC_CMD1_CAPACITY_LESS_THAN_2GB 0x00FF8080 // Capacity <= 2GB, byte addressing used +#define EMMC_CMD1_CAPACITY_GREATER_THAN_2GB 0x40FF8080 // Capacity > 2GB, 512-byte sector addressing used + +#define MMC_STATUS_APP_CMD (1 << 5) + +typedef enum _MMC_STATE { + MmcInvalidState = 0, + MmcHwInitializationState, + MmcIdleState, + MmcReadyState, + MmcIdentificationState, + MmcStandByState, + MmcTransferState, + MmcSendingDataState, + MmcReceiveDataState, + MmcProgrammingState, + MmcDisconnectState, +} MMC_STATE; + +#define EMMCBACKWARD (0) +#define EMMCHS26 (1 << 0) // High-Speed @26MHz at rated device voltages +#define EMMCHS52 (1 << 1) // High-Speed @52MHz at rated device voltages +#define EMMCHS52DDR1V8 (1 << 2) // High-Speed Dual Data Rate @52MHz 1.8V or 3V I/O +#define EMMCHS52DDR1V2 (1 << 3) // High-Speed Dual Data Rate @52MHz 1.2V I/O +#define EMMCHS200SDR1V8 (1 << 4) // HS200 Single Data Rate @200MHz 1.8V I/O +#define EMMCHS200SDR1V2 (1 << 5) // HS200 Single Data Rate @200MHz 1.2V I/O +#define EMMCHS400DDR1V8 (1 << 6) // HS400 Dual Data Rate @400MHz 1.8V I/O +#define EMMCHS400DDR1V2 (1 << 7) // HS400 Dual Data Rate @400MHz 1.2V I/O + +/// +/// Forward declaration for EFI_MMC_HOST_PROTOCOL +/// +typedef struct _EFI_MMC_HOST_PROTOCOL EFI_MMC_HOST_PROTOCOL; + +typedef BOOLEAN (EFIAPI *MMC_ISCARDPRESENT) ( + IN EFI_MMC_HOST_PROTOCOL *This + ); + +typedef BOOLEAN (EFIAPI *MMC_ISREADONLY) ( + IN EFI_MMC_HOST_PROTOCOL *This + ); + +typedef EFI_STATUS (EFIAPI *MMC_BUILDDEVICEPATH) ( + IN EFI_MMC_HOST_PROTOCOL *This, + OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ); + +typedef EFI_STATUS (EFIAPI *MMC_NOTIFYSTATE) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_STATE State + ); + +typedef EFI_STATUS (EFIAPI *MMC_SENDCOMMAND) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_CMD Cmd, + IN UINT32 Argument + ); + +typedef EFI_STATUS (EFIAPI *MMC_RECEIVERESPONSE) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_RESPONSE_TYPE Type, + IN UINT32 *Buffer + ); + +typedef EFI_STATUS (EFIAPI *MMC_READBLOCKDATA) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Length, + OUT UINT32 *Buffer + ); + +typedef EFI_STATUS (EFIAPI *MMC_WRITEBLOCKDATA) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Length, + IN UINT32 *Buffer + ); + +typedef EFI_STATUS (EFIAPI *MMC_SETIOS) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN UINT32 BusClockFreq, + IN UINT32 BusWidth, + IN UINT32 TimingMode + ); + +typedef BOOLEAN (EFIAPI *MMC_ISMULTIBLOCK) ( + IN EFI_MMC_HOST_PROTOCOL *This + ); + +struct _EFI_MMC_HOST_PROTOCOL { + + UINT32 Revision; + MMC_ISCARDPRESENT IsCardPresent; + MMC_ISREADONLY IsReadOnly; + MMC_BUILDDEVICEPATH BuildDevicePath; + + MMC_NOTIFYSTATE NotifyState; + + MMC_SENDCOMMAND SendCommand; + MMC_RECEIVERESPONSE ReceiveResponse; + + MMC_READBLOCKDATA ReadBlockData; + MMC_WRITEBLOCKDATA WriteBlockData; + + MMC_SETIOS SetIos; + MMC_ISMULTIBLOCK IsMultiBlock; + +}; + +#define MMC_HOST_PROTOCOL_REVISION 0x00010002 // 1.2 + +#define MMC_HOST_HAS_SETIOS(Host) (Host->Revision >= MMC_HOST_PROTOCOL_REVISION && \ + Host->SetIos != NULL) +#define MMC_HOST_HAS_ISMULTIBLOCK(Host) (Host->Revision >= MMC_HOST_PROTOCOL_REVISION && \ + Host->IsMultiBlock != NULL) + +extern EFI_GUID gEmbeddedMmcHostProtocolGuid; + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/PeCoffLoader.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/PeCoffLoader.h new file mode 100644 index 00000000..a66d8f55 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/PeCoffLoader.h @@ -0,0 +1,235 @@ +/** @file + + Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+ Portions copyright (c) 2010, Apple Inc. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __PE_COFF_LOADER_H__ +#define __PE_COFF_LOADER_H__ + +// Needed for PE_COFF_LOADER_IMAGE_CONTEXT +#include + +// B323179B-97FB-477E-B0FE-D88591FA11AB +#define PE_COFF_LOADER_PROTOCOL_GUID \ + { 0xB323179B, 0x97FB, 0x477E, { 0xB0, 0xFE, 0xD8, 0x85, 0x91, 0xFA, 0x11, 0xAB } } + + +typedef struct _PE_COFF_LOADER_PROTOCOL PE_COFF_LOADER_PROTOCOL; + + + +/** + Retrieves information about a PE/COFF image. + + Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize, + DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and + DebugDirectoryEntryRva fields of the ImageContext structure. + If ImageContext is NULL, then return RETURN_INVALID_PARAMETER. + If the PE/COFF image accessed through the ImageRead service in the ImageContext + structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED. + If any errors occur while computing the fields of ImageContext, + then the error status is returned in the ImageError field of ImageContext. + If the image is a TE image, then SectionAlignment is set to 0. + The ImageRead and Handle fields of ImageContext structure must be valid prior + to invoking this service. + + @param ImageContext Pointer to the image context structure that describes the PE/COFF + image that needs to be examined by this function. + + @retval RETURN_SUCCESS The information on the PE/COFF image was collected. + @retval RETURN_INVALID_PARAMETER ImageContext is NULL. + @retval RETURN_UNSUPPORTED The PE/COFF image is not supported. + +**/ +typedef +RETURN_STATUS +(EFIAPI *PE_COFF_LOADER_GET_IMAGE_INFO) ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + + +/** + Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage(). + + If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of + ImageContext as the relocation base address. Otherwise, use the DestinationAddress field + of ImageContext as the relocation base address. The caller must allocate the relocation + fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function. + + The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, + ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, + DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of + the ImageContext structure must be valid prior to invoking this service. + + If ImageContext is NULL, then ASSERT(). + + Note that if the platform does not maintain coherency between the instruction cache(s) and the data + cache(s) in hardware, then the caller is responsible for performing cache maintenance operations + prior to transferring control to a PE/COFF image that is loaded using this library. + + @param ImageContext Pointer to the image context structure that describes the PE/COFF + image that is being relocated. + + @retval RETURN_SUCCESS The PE/COFF image was relocated. + Extended status information is in the ImageError field of ImageContext. + @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image. + Extended status information is in the ImageError field of ImageContext. + @retval RETURN_UNSUPPORTED A relocation record type is not supported. + Extended status information is in the ImageError field of ImageContext. + +**/ +typedef +RETURN_STATUS +(EFIAPI *PE_COFF_LOADER_RELOCATE_IMAGE) ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + + +/** + Loads a PE/COFF image into memory. + + Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer + specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate + the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function. + The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed. + The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize, + DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva + fields of the ImageContext structure must be valid prior to invoking this service. + + If ImageContext is NULL, then ASSERT(). + + Note that if the platform does not maintain coherency between the instruction cache(s) and the data + cache(s) in hardware, then the caller is responsible for performing cache maintenance operations + prior to transferring control to a PE/COFF image that is loaded using this library. + + @param ImageContext Pointer to the image context structure that describes the PE/COFF + image that is being loaded. + + @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by + the ImageAddress and ImageSize fields of ImageContext. + Extended status information is in the ImageError field of ImageContext. + @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer. + Extended status information is in the ImageError field of ImageContext. + @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations. + Extended status information is in the ImageError field of ImageContext. + @retval RETURN_INVALID_PARAMETER The image address is invalid. + Extended status information is in the ImageError field of ImageContext. + +**/ +typedef +RETURN_STATUS +(EFIAPI *PE_COFF_LOADER_LOAD_IMAGE) ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + + + +/** + Reads contents of a PE/COFF image from a buffer in system memory. + + This is the default implementation of a PE_COFF_LOADER_READ_FILE function + that assumes FileHandle pointer to the beginning of a PE/COFF image. + This function reads contents of the PE/COFF image that starts at the system memory + address specified by FileHandle. The read operation copies ReadSize bytes from the + PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer. + The size of the buffer actually read is returned in ReadSize. + + If FileHandle is NULL, then ASSERT(). + If ReadSize is NULL, then ASSERT(). + If Buffer is NULL, then ASSERT(). + + @param FileHandle Pointer to base of the input stream + @param FileOffset Offset into the PE/COFF image to begin the read operation. + @param ReadSize On input, the size in bytes of the requested read operation. + On output, the number of bytes actually read. + @param Buffer Output buffer that contains the data read from the PE/COFF image. + + @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into + the buffer. +**/ +typedef +RETURN_STATUS +(EFIAPI *PE_COFF_LOADER_READ_FROM_MEMORY) ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ); + + + +/** + Reapply fixups on a fixed up PE32/PE32+ image to allow virtual calling at EFI + runtime. + + This function reapplies relocation fixups to the PE/COFF image specified by ImageBase + and ImageSize so the image will execute correctly when the PE/COFF image is mapped + to the address specified by VirtualImageBase. RelocationData must be identical + to the FixupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure + after this PE/COFF image was relocated with PeCoffLoaderRelocateImage(). + + Note that if the platform does not maintain coherency between the instruction cache(s) and the data + cache(s) in hardware, then the caller is responsible for performing cache maintenance operations + prior to transferring control to a PE/COFF image that is loaded using this library. + + @param ImageBase Base address of a PE/COFF image that has been loaded + and relocated into system memory. + @param VirtImageBase The request virtual address that the PE/COFF image is to + be fixed up for. + @param ImageSize The size, in bytes, of the PE/COFF image. + @param RelocationData A pointer to the relocation data that was collected when the PE/COFF + image was relocated using PeCoffLoaderRelocateImage(). + +**/ +typedef +VOID +(EFIAPI *PE_COFF_LOADER_RELOCATE_IMAGE_FOR_RUNTIME) ( + IN PHYSICAL_ADDRESS ImageBase, + IN PHYSICAL_ADDRESS VirtImageBase, + IN UINTN ImageSize, + IN VOID *RelocationData + ); + + + +/** + Unloads a loaded PE/COFF image from memory and releases its taken resource. + Releases any environment specific resources that were allocated when the image + specified by ImageContext was loaded using PeCoffLoaderLoadImage(). + + For NT32 emulator, the PE/COFF image loaded by system needs to release. + For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded, + this function can simply return RETURN_SUCCESS. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the PE/COFF + image to be unloaded. + + @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully. +**/ +typedef +RETURN_STATUS +(EFIAPI *PE_COFF_LOADER_UNLOAD_IMAGE) ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + + +struct _PE_COFF_LOADER_PROTOCOL { + PE_COFF_LOADER_GET_IMAGE_INFO GetImageInfo; + PE_COFF_LOADER_LOAD_IMAGE LoadImage; + PE_COFF_LOADER_RELOCATE_IMAGE RelocateImage; + PE_COFF_LOADER_READ_FROM_MEMORY ReadFromMemory; + PE_COFF_LOADER_RELOCATE_IMAGE_FOR_RUNTIME RelocateImageForRuntime; + PE_COFF_LOADER_UNLOAD_IMAGE UnloadImage; +}; + + +extern EFI_GUID gPeCoffLoaderProtocolGuid; + + +#endif + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/PlatformBootManager.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/PlatformBootManager.h new file mode 100644 index 00000000..2361dcca --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/PlatformBootManager.h @@ -0,0 +1,80 @@ +/** @file + + Copyright (c) 2018, Linaro. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __PLATFORM_BOOT_MANAGER_PROTOCOL_H__ +#define __PLATFORM_BOOT_MANAGER_PROTOCOL_H__ + +// +// Protocol interface structure +// +typedef struct _PLATFORM_BOOT_MANAGER_PROTOCOL PLATFORM_BOOT_MANAGER_PROTOCOL; + +// +// Function Prototypes +// + +/* + Get predefined boot options for platform. + + @param[out] Count The number of elements in each of + BootOptions and BootKeys. On successful + return, Count is at least one. + + @param[out] BootOptions An array of platform boot options. + BootOptions is pool-allocated by + GET_PLATFORM_BOOT_OPTIONS_AND_KEYS, and + GET_PLATFORM_BOOT_OPTIONS_AND_KEYS populates + every element in BootOptions with + EfiBootManagerInitializeLoadOption(). + BootOptions shall not contain duplicate + entries. The caller is responsible for + releasing BootOptions after use with + EfiBootManagerFreeLoadOptions(). + + @param[out] BootKeys A pool-allocated array of platform boot + hotkeys. For every 0 <= Index < Count, if + BootOptions[Index] is not to be associated + with a hotkey, then BootKeys[Index] is + zero-filled. Otherwise, BootKeys[Index] + specifies the boot hotkey for + BootOptions[Index]. BootKeys shall not + contain duplicate entries (other than + zero-filled entries). The caller is + responsible for releasing BootKeys with + FreePool() after use. + + @retval EFI_SUCCESS Count, BootOptions and BootKeys have + been set. + + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. + + @retval EFI_UNSUPPORTED The platform doesn't provide boot options + as a feature. + + @retval EFI_NOT_FOUND The platform could provide boot options + as a feature, but none have been + configured. + + @return Error codes propagated from underlying + functions. +*/ +typedef +EFI_STATUS +(EFIAPI *GET_PLATFORM_BOOT_OPTIONS_AND_KEYS) ( + OUT UINTN *Count, + OUT EFI_BOOT_MANAGER_LOAD_OPTION **BootOptions, + OUT EFI_INPUT_KEY **BootKeys + ); + +struct _PLATFORM_BOOT_MANAGER_PROTOCOL { + GET_PLATFORM_BOOT_OPTIONS_AND_KEYS GetPlatformBootOptionsAndKeys; +}; + +extern EFI_GUID gPlatformBootManagerProtocolGuid; + +#endif /* __PLATFORM_BOOT_MANAGER_PROTOCOL_H__ */ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/PlatformVirtualKeyboard.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/PlatformVirtualKeyboard.h new file mode 100644 index 00000000..250cf361 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/PlatformVirtualKeyboard.h @@ -0,0 +1,59 @@ +/** @file + + Copyright (c) 2018, Linaro. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __PLATFORM_VIRTUAL_KEYBOARD_H__ +#define __PLATFORM_VIRTUAL_KEYBOARD_H__ + +// +// Protocol interface structure +// +typedef struct _PLATFORM_VIRTUAL_KBD_PROTOCOL PLATFORM_VIRTUAL_KBD_PROTOCOL; + +typedef struct _VIRTUAL_KBD_KEY VIRTUAL_KBD_KEY; + +#define VIRTUAL_KEYBOARD_KEY_SIGNATURE SIGNATURE_32 ('v', 'k', 'b', 'd') + +struct _VIRTUAL_KBD_KEY { + UINTN Signature; + EFI_INPUT_KEY Key; +}; + +typedef +EFI_STATUS +(EFIAPI *PLATFORM_VIRTUAL_KBD_REGISTER) ( + IN VOID + ); + +typedef +EFI_STATUS +(EFIAPI *PLATFORM_VIRTUAL_KBD_RESET) ( + IN VOID + ); + +typedef +BOOLEAN +(EFIAPI *PLATFORM_VIRTUAL_KBD_QUERY) ( + IN VIRTUAL_KBD_KEY *VirtualKey + ); + +typedef +EFI_STATUS +(EFIAPI *PLATFORM_VIRTUAL_KBD_CLEAR) ( + IN VIRTUAL_KBD_KEY *VirtualKey + ); + +struct _PLATFORM_VIRTUAL_KBD_PROTOCOL { + PLATFORM_VIRTUAL_KBD_REGISTER Register; + PLATFORM_VIRTUAL_KBD_RESET Reset; + PLATFORM_VIRTUAL_KBD_QUERY Query; + PLATFORM_VIRTUAL_KBD_CLEAR Clear; +}; + +extern EFI_GUID gPlatformVirtualKeyboardProtocolGuid; + +#endif /* __PLATFORM_VIRTUAL_KEYBOARD_H__ */ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/UsbDevice.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/UsbDevice.h new file mode 100644 index 00000000..794ac0af --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/Protocol/UsbDevice.h @@ -0,0 +1,112 @@ +/** @file + + Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __USB_DEVICE_PROTOCOL_H__ +#define __USB_DEVICE_PROTOCOL_H__ + +#include + +extern EFI_GUID gUsbDeviceProtocolGuid; + +/* + * Note: This Protocol is just the bare minimum for Android Fastboot. It + * only makes sense for devices that only do Bulk Transfers and only have one + * endpoint. + */ + +/* + Callback to be called when data is received. + Buffer is callee-allocated and it's the caller's responsibility to free it with + FreePool. + + @param[in] Size Size in bytes of data. + @param[in] Buffer Pointer to data. +*/ +typedef +VOID +(*USB_DEVICE_RX_CALLBACK) ( + IN UINTN Size, + IN VOID *Buffer + ); + +/* + Callback to be called when the host asks for data by sending an IN token + (excluding during the data stage of a control transfer). + When this function is called, data previously buffered by calling Send() has + been sent. + + @param[in]Endpoint Endpoint index, as specified in endpoint descriptors, of + the endpoint the IN token was sent to. +*/ +typedef +VOID +(*USB_DEVICE_TX_CALLBACK) ( + IN UINT8 EndpointIndex + ); + +/* + Put data in the Tx buffer to be sent on the next IN token. + Don't call this function again until the TxCallback has been called. + + @param[in]Endpoint Endpoint index, as specified in endpoint descriptors, of + the endpoint to send the data from. + @param[in]Size Size in bytes of data. + @param[in]Buffer Pointer to data. + + @retval EFI_SUCCESS The data was queued successfully. + @retval EFI_INVALID_PARAMETER There was an error sending the data. +*/ +typedef +EFI_STATUS +(*USB_DEVICE_SEND) ( + IN UINT8 EndpointIndex, + IN UINTN Size, + IN CONST VOID *Buffer + ); + +/* + Restart the USB peripheral controller and respond to enumeration. + + @param[in] DeviceDescriptor pointer to device descriptor + @param[in] Descriptors Array of pointers to buffers, where + Descriptors[n] contains the response to a + GET_DESCRIPTOR request for configuration n. From + USB Spec section 9.4.3: + "The first interface descriptor follows the + configuration descriptor. The endpoint + descriptors for the first interface follow the + first interface descriptor. If there are + additional interfaces, their interface + descriptor and endpoint descriptors follow the + first interface’s endpoint descriptors". + + The size of each buffer is the TotalLength + member of the Configuration Descriptor. + + The size of the array is + DeviceDescriptor->NumConfigurations. + @param[in]RxCallback See USB_DEVICE_RX_CALLBACK + @param[in]TxCallback See USB_DEVICE_TX_CALLBACK +*/ +typedef +EFI_STATUS +(*USB_DEVICE_START) ( + IN USB_DEVICE_DESCRIPTOR *DeviceDescriptor, + IN VOID **Descriptors, + IN USB_DEVICE_RX_CALLBACK RxCallback, + IN USB_DEVICE_TX_CALLBACK TxCallback + ); + +struct _USB_DEVICE_PROTOCOL { + USB_DEVICE_START Start; + USB_DEVICE_SEND Send; +}; + +typedef struct _USB_DEVICE_PROTOCOL USB_DEVICE_PROTOCOL; + +#endif //ifndef __USB_DEVICE_PROTOCOL_H__ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/fdt.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/fdt.h new file mode 100644 index 00000000..526aedb5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/fdt.h @@ -0,0 +1,111 @@ +#ifndef _FDT_H +#define _FDT_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * Copyright 2012 Kim Phillips, Freescale Semiconductor. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ASSEMBLY__ + +struct fdt_header { + fdt32_t magic; /* magic word FDT_MAGIC */ + fdt32_t totalsize; /* total size of DT block */ + fdt32_t off_dt_struct; /* offset to structure */ + fdt32_t off_dt_strings; /* offset to strings */ + fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ + fdt32_t version; /* format version */ + fdt32_t last_comp_version; /* last compatible version */ + + /* version 2 fields below */ + fdt32_t boot_cpuid_phys; /* Which physical CPU id we're + booting on */ + /* version 3 fields below */ + fdt32_t size_dt_strings; /* size of the strings block */ + + /* version 17 fields below */ + fdt32_t size_dt_struct; /* size of the structure block */ +}; + +struct fdt_reserve_entry { + fdt64_t address; + fdt64_t size; +}; + +struct fdt_node_header { + fdt32_t tag; + char name[0]; +}; + +struct fdt_property { + fdt32_t tag; + fdt32_t len; + fdt32_t nameoff; + char data[0]; +}; + +#endif /* !__ASSEMBLY */ + +#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ +#define FDT_TAGSIZE sizeof(fdt32_t) + +#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ +#define FDT_END_NODE 0x2 /* End node */ +#define FDT_PROP 0x3 /* Property: name off, + size, content */ +#define FDT_NOP 0x4 /* nop */ +#define FDT_END 0x9 + +#define FDT_V1_SIZE (7*sizeof(fdt32_t)) +#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) +#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) +#define FDT_V16_SIZE FDT_V3_SIZE +#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) + +#endif /* _FDT_H */ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/libfdt.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/libfdt.h new file mode 100644 index 00000000..313c72a2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/libfdt.h @@ -0,0 +1,1899 @@ +#ifndef _LIBFDT_H +#define _LIBFDT_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#define FDT_FIRST_SUPPORTED_VERSION 0x10 +#define FDT_LAST_SUPPORTED_VERSION 0x11 + +/* Error codes: informative error codes */ +#define FDT_ERR_NOTFOUND 1 + /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ +#define FDT_ERR_EXISTS 2 + /* FDT_ERR_EXISTS: Attempted to create a node or property which + * already exists */ +#define FDT_ERR_NOSPACE 3 + /* FDT_ERR_NOSPACE: Operation needed to expand the device + * tree, but its buffer did not have sufficient space to + * contain the expanded tree. Use fdt_open_into() to move the + * device tree to a buffer with more space. */ + +/* Error codes: codes for bad parameters */ +#define FDT_ERR_BADOFFSET 4 + /* FDT_ERR_BADOFFSET: Function was passed a structure block + * offset which is out-of-bounds, or which points to an + * unsuitable part of the structure for the operation. */ +#define FDT_ERR_BADPATH 5 + /* FDT_ERR_BADPATH: Function was passed a badly formatted path + * (e.g. missing a leading / for a function which requires an + * absolute path) */ +#define FDT_ERR_BADPHANDLE 6 + /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle. + * This can be caused either by an invalid phandle property + * length, or the phandle value was either 0 or -1, which are + * not permitted. */ +#define FDT_ERR_BADSTATE 7 + /* FDT_ERR_BADSTATE: Function was passed an incomplete device + * tree created by the sequential-write functions, which is + * not sufficiently complete for the requested operation. */ + +/* Error codes: codes for bad device tree blobs */ +#define FDT_ERR_TRUNCATED 8 + /* FDT_ERR_TRUNCATED: Structure block of the given device tree + * ends without an FDT_END tag. */ +#define FDT_ERR_BADMAGIC 9 + /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a + * device tree at all - it is missing the flattened device + * tree magic number. */ +#define FDT_ERR_BADVERSION 10 + /* FDT_ERR_BADVERSION: Given device tree has a version which + * can't be handled by the requested operation. For + * read-write functions, this may mean that fdt_open_into() is + * required to convert the tree to the expected version. */ +#define FDT_ERR_BADSTRUCTURE 11 + /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt + * structure block or other serious error (e.g. misnested + * nodes, or subnodes preceding properties). */ +#define FDT_ERR_BADLAYOUT 12 + /* FDT_ERR_BADLAYOUT: For read-write functions, the given + * device tree has it's sub-blocks in an order that the + * function can't handle (memory reserve map, then structure, + * then strings). Use fdt_open_into() to reorganize the tree + * into a form suitable for the read-write operations. */ + +/* "Can't happen" error indicating a bug in libfdt */ +#define FDT_ERR_INTERNAL 13 + /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. + * Should never be returned, if it is, it indicates a bug in + * libfdt itself. */ + +/* Errors in device tree content */ +#define FDT_ERR_BADNCELLS 14 + /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells + * or similar property with a bad format or value */ + +#define FDT_ERR_BADVALUE 15 + /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected + * value. For example: a property expected to contain a string list + * is not NUL-terminated within the length of its value. */ + +#define FDT_ERR_BADOVERLAY 16 + /* FDT_ERR_BADOVERLAY: The device tree overlay, while + * correctly structured, cannot be applied due to some + * unexpected or missing value, property or node. */ + +#define FDT_ERR_NOPHANDLES 17 + /* FDT_ERR_NOPHANDLES: The device tree doesn't have any + * phandle available anymore without causing an overflow */ + +#define FDT_ERR_MAX 17 + +/**********************************************************************/ +/* Low-level functions (you probably don't need these) */ +/**********************************************************************/ + +#ifndef SWIG /* This function is not useful in Python */ +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); +#endif +static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) +{ + return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); +} + +uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); + +/**********************************************************************/ +/* Traversal functions */ +/**********************************************************************/ + +int fdt_next_node(const void *fdt, int offset, int *depth); + +/** + * fdt_first_subnode() - get offset of first direct subnode + * + * @fdt: FDT blob + * @offset: Offset of node to check + * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none + */ +int fdt_first_subnode(const void *fdt, int offset); + +/** + * fdt_next_subnode() - get offset of next direct subnode + * + * After first calling fdt_first_subnode(), call this function repeatedly to + * get direct subnodes of a parent node. + * + * @fdt: FDT blob + * @offset: Offset of previous subnode + * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more + * subnodes + */ +int fdt_next_subnode(const void *fdt, int offset); + +/** + * fdt_for_each_subnode - iterate over all subnodes of a parent + * + * @node: child node (int, lvalue) + * @fdt: FDT blob (const void *) + * @parent: parent node (int) + * + * This is actually a wrapper around a for loop and would be used like so: + * + * fdt_for_each_subnode(node, fdt, parent) { + * Use node + * ... + * } + * + * if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) { + * Error handling + * } + * + * Note that this is implemented as a macro and @node is used as + * iterator in the loop. The parent variable be constant or even a + * literal. + * + */ +#define fdt_for_each_subnode(node, fdt, parent) \ + for (node = fdt_first_subnode(fdt, parent); \ + node >= 0; \ + node = fdt_next_subnode(fdt, node)) + +/**********************************************************************/ +/* General functions */ +/**********************************************************************/ +#define fdt_get_header(fdt, field) \ + (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) +#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) +#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) +#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) +#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) +#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) +#define fdt_version(fdt) (fdt_get_header(fdt, version)) +#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) +#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) + +#define __fdt_set_hdr(name) \ + static inline void fdt_set_##name(void *fdt, uint32_t val) \ + { \ + struct fdt_header *fdth = (struct fdt_header *)fdt; \ + fdth->name = cpu_to_fdt32(val); \ + } +__fdt_set_hdr(magic); +__fdt_set_hdr(totalsize); +__fdt_set_hdr(off_dt_struct); +__fdt_set_hdr(off_dt_strings); +__fdt_set_hdr(off_mem_rsvmap); +__fdt_set_hdr(version); +__fdt_set_hdr(last_comp_version); +__fdt_set_hdr(boot_cpuid_phys); +__fdt_set_hdr(size_dt_strings); +__fdt_set_hdr(size_dt_struct); +#undef __fdt_set_hdr + +/** + * fdt_check_header - sanity check a device tree or possible device tree + * @fdt: pointer to data which might be a flattened device tree + * + * fdt_check_header() checks that the given buffer contains what + * appears to be a flattened device tree with sane information in its + * header. + * + * returns: + * 0, if the buffer appears to contain a valid device tree + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings, as above + */ +int fdt_check_header(const void *fdt); + +/** + * fdt_move - move a device tree around in memory + * @fdt: pointer to the device tree to move + * @buf: pointer to memory where the device is to be moved + * @bufsize: size of the memory space at buf + * + * fdt_move() relocates, if possible, the device tree blob located at + * fdt to the buffer at buf of size bufsize. The buffer may overlap + * with the existing device tree blob at fdt. Therefore, + * fdt_move(fdt, fdt, fdt_totalsize(fdt)) + * should always succeed. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_move(const void *fdt, void *buf, int bufsize); + +/**********************************************************************/ +/* Read-only functions */ +/**********************************************************************/ + +/** + * fdt_string - retrieve a string from the strings block of a device tree + * @fdt: pointer to the device tree blob + * @stroffset: offset of the string within the strings block (native endian) + * + * fdt_string() retrieves a pointer to a single string from the + * strings block of the device tree blob at fdt. + * + * returns: + * a pointer to the string, on success + * NULL, if stroffset is out of bounds + */ +const char *fdt_string(const void *fdt, int stroffset); + +/** + * fdt_get_max_phandle - retrieves the highest phandle in a tree + * @fdt: pointer to the device tree blob + * + * fdt_get_max_phandle retrieves the highest phandle in the given + * device tree. This will ignore badly formatted phandles, or phandles + * with a value of 0 or -1. + * + * returns: + * the highest phandle on success + * 0, if no phandle was found in the device tree + * -1, if an error occurred + */ +uint32_t fdt_get_max_phandle(const void *fdt); + +/** + * fdt_num_mem_rsv - retrieve the number of memory reserve map entries + * @fdt: pointer to the device tree blob + * + * Returns the number of entries in the device tree blob's memory + * reservation map. This does not include the terminating 0,0 entry + * or any other (0,0) entries reserved for expansion. + * + * returns: + * the number of entries + */ +int fdt_num_mem_rsv(const void *fdt); + +/** + * fdt_get_mem_rsv - retrieve one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address, @size: pointers to 64-bit variables + * + * On success, *address and *size will contain the address and size of + * the n-th reserve map entry from the device tree blob, in + * native-endian format. + * + * returns: + * 0, on success + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); + +/** + * fdt_subnode_offset_namelen - find a subnode based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_subnode_offset(), but only examine the first + * namelen characters of name for matching the subnode name. This is + * useful for finding subnodes based on a portion of a larger string, + * such as a full path. + */ +#ifndef SWIG /* Not available in Python */ +int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, + const char *name, int namelen); +#endif +/** + * fdt_subnode_offset - find a subnode of a given node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_subnode_offset() finds a subnode of the node at structure block + * offset parentoffset with the given name. name may include a unit + * address, in which case fdt_subnode_offset() will find the subnode + * with that unit address, or the unit address may be omitted, in + * which case fdt_subnode_offset() will find an arbitrary subnode + * whose name excluding unit address matches the given name. + * + * returns: + * structure block offset of the requested subnode (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); + +/** + * fdt_path_offset_namelen - find a tree node by its full path + * @fdt: pointer to the device tree blob + * @path: full path of the node to locate + * @namelen: number of characters of path to consider + * + * Identical to fdt_path_offset(), but only consider the first namelen + * characters of path as the path name. + */ +#ifndef SWIG /* Not available in Python */ +int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); +#endif + +/** + * fdt_path_offset - find a tree node by its full path + * @fdt: pointer to the device tree blob + * @path: full path of the node to locate + * + * fdt_path_offset() finds a node of a given path in the device tree. + * Each path component may omit the unit address portion, but the + * results of this are undefined if any such path component is + * ambiguous (that is if there are multiple nodes at the relevant + * level matching the given component, differentiated only by unit + * address). + * + * returns: + * structure block offset of the node with the requested path (>=0), on + * success + * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid + * -FDT_ERR_NOTFOUND, if the requested node does not exist + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_path_offset(const void *fdt, const char *path); + +/** + * fdt_get_name - retrieve the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the starting node + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_name() retrieves the name (including unit address) of the + * device tree node at structure block offset nodeoffset. If lenp is + * non-NULL, the length of this name is also returned, in the integer + * pointed to by lenp. + * + * returns: + * pointer to the node's name, on success + * If lenp is non-NULL, *lenp contains the length of that name + * (>=0) + * NULL, on error + * if lenp is non-NULL *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); + +/** + * fdt_first_property_offset - find the offset of a node's first property + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * + * fdt_first_property_offset() finds the first property of the node at + * the given structure block offset. + * + * returns: + * structure block offset of the property (>=0), on success + * -FDT_ERR_NOTFOUND, if the requested node has no properties + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_first_property_offset(const void *fdt, int nodeoffset); + +/** + * fdt_next_property_offset - step through a node's properties + * @fdt: pointer to the device tree blob + * @offset: structure block offset of a property + * + * fdt_next_property_offset() finds the property immediately after the + * one at the given structure block offset. This will be a property + * of the same node as the given property. + * + * returns: + * structure block offset of the next property (>=0), on success + * -FDT_ERR_NOTFOUND, if the given property is the last in its node + * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_next_property_offset(const void *fdt, int offset); + +/** + * fdt_for_each_property_offset - iterate over all properties of a node + * + * @property_offset: property offset (int, lvalue) + * @fdt: FDT blob (const void *) + * @node: node offset (int) + * + * This is actually a wrapper around a for loop and would be used like so: + * + * fdt_for_each_property_offset(property, fdt, node) { + * Use property + * ... + * } + * + * if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) { + * Error handling + * } + * + * Note that this is implemented as a macro and property is used as + * iterator in the loop. The node variable can be constant or even a + * literal. + */ +#define fdt_for_each_property_offset(property, fdt, node) \ + for (property = fdt_first_property_offset(fdt, node); \ + property >= 0; \ + property = fdt_next_property_offset(fdt, property)) + +/** + * fdt_get_property_by_offset - retrieve the property at a given offset + * @fdt: pointer to the device tree blob + * @offset: offset of the property to retrieve + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property_by_offset() retrieves a pointer to the + * fdt_property structure within the device tree blob at the given + * offset. If lenp is non-NULL, the length of the property value is + * also returned, in the integer pointed to by lenp. + * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp); + +/** + * fdt_get_property_namelen - find a property based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_get_property(), but only examine the first namelen + * characters of name for matching the property name. + */ +#ifndef SWIG /* Not available in Python */ +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int nodeoffset, + const char *name, + int namelen, int *lenp); +#endif + +/** + * fdt_get_property - find a given property in a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_get_property() retrieves a pointer to the fdt_property + * structure within the device tree blob corresponding to the property + * named 'name' of the node at offset nodeoffset. If lenp is + * non-NULL, the length of the property value is also returned, in the + * integer pointed to by lenp. + * + * returns: + * pointer to the structure representing the property + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, + const char *name, int *lenp); +static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, + const char *name, + int *lenp) +{ + return (struct fdt_property *)(uintptr_t) + fdt_get_property(fdt, nodeoffset, name, lenp); +} + +/** + * fdt_getprop_by_offset - retrieve the value of a property at a given offset + * @fdt: pointer to the device tree blob + * @ffset: offset of the property to read + * @namep: pointer to a string variable (will be overwritten) or NULL + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop_by_offset() retrieves a pointer to the value of the + * property at structure block offset 'offset' (this will be a pointer + * to within the device blob itself, not a copy of the value). If + * lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by lenp. If namep is non-NULL, + * the property's namne will also be returned in the char * pointed to + * by namep (this will be a pointer to within the device tree's string + * block, not a new copy of the name). + * + * returns: + * pointer to the property's value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * if namep is non-NULL *namep contiains a pointer to the property + * name. + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#ifndef SWIG /* This function is not useful in Python */ +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp); +#endif + +/** + * fdt_getprop_namelen - get property value based on substring + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @namelen: number of characters of name to consider + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * Identical to fdt_getprop(), but only examine the first namelen + * characters of name for matching the property name. + */ +#ifndef SWIG /* Not available in Python */ +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp); +static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, + const char *name, int namelen, + int *lenp) +{ + return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, + namelen, lenp); +} +#endif + +/** + * fdt_getprop - retrieve the value of a given property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to find + * @name: name of the property to find + * @lenp: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_getprop() retrieves a pointer to the value of the property + * named 'name' of the node at offset nodeoffset (this will be a + * pointer to within the device blob itself, not a copy of the value). + * If lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by lenp. + * + * returns: + * pointer to the property's value + * if lenp is non-NULL, *lenp contains the length of the property + * value (>=0) + * NULL, on error + * if lenp is non-NULL, *lenp contains an error code (<0): + * -FDT_ERR_NOTFOUND, node does not have named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +const void *fdt_getprop(const void *fdt, int nodeoffset, + const char *name, int *lenp); +static inline void *fdt_getprop_w(void *fdt, int nodeoffset, + const char *name, int *lenp) +{ + return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); +} + +/** + * fdt_get_phandle - retrieve the phandle of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of the node + * + * fdt_get_phandle() retrieves the phandle of the device tree node at + * structure block offset nodeoffset. + * + * returns: + * the phandle of the node at nodeoffset, on success (!= 0, != -1) + * 0, if the node has no phandle, or another error occurs + */ +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); + +/** + * fdt_get_alias_namelen - get alias based on substring + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * @namelen: number of characters of name to consider + * + * Identical to fdt_get_alias(), but only examine the first namelen + * characters of name for matching the alias name. + */ +#ifndef SWIG /* Not available in Python */ +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen); +#endif + +/** + * fdt_get_alias - retrieve the path referenced by a given alias + * @fdt: pointer to the device tree blob + * @name: name of the alias th look up + * + * fdt_get_alias() retrieves the value of a given alias. That is, the + * value of the property named 'name' in the node /aliases. + * + * returns: + * a pointer to the expansion of the alias named 'name', if it exists + * NULL, if the given alias or the /aliases node does not exist + */ +const char *fdt_get_alias(const void *fdt, const char *name); + +/** + * fdt_get_path - determine the full path of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose path to find + * @buf: character buffer to contain the returned path (will be overwritten) + * @buflen: size of the character buffer at buf + * + * fdt_get_path() computes the full path of the node at offset + * nodeoffset, and records that path in the buffer at buf. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + * 0, on success + * buf contains the absolute path of the node at + * nodeoffset, as a NUL-terminated string. + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) + * characters and will not fit in the given buffer. + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); + +/** + * fdt_supernode_atdepth_offset - find a specific ancestor of a node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * @supernodedepth: depth of the ancestor to find + * @nodedepth: pointer to an integer variable (will be overwritten) or NULL + * + * fdt_supernode_atdepth_offset() finds an ancestor of the given node + * at a specific depth from the root (where the root itself has depth + * 0, its immediate subnodes depth 1 and so forth). So + * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); + * will always return 0, the offset of the root node. If the node at + * nodeoffset has depth D, then: + * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); + * will return nodeoffset itself. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + * structure block offset of the node at node offset's ancestor + * of depth supernodedepth (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of + * nodeoffset + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, + int supernodedepth, int *nodedepth); + +/** + * fdt_node_depth - find the depth of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_node_depth() finds the depth of a given node. The root node + * has depth 0, its immediate subnodes depth 1 and so forth. + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset. + * + * returns: + * depth of the node at nodeoffset (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_depth(const void *fdt, int nodeoffset); + +/** + * fdt_parent_offset - find the parent of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose parent to find + * + * fdt_parent_offset() locates the parent node of a given node (that + * is, it finds the offset of the node which contains the node at + * nodeoffset as a subnode). + * + * NOTE: This function is expensive, as it must scan the device tree + * structure from the start to nodeoffset, *twice*. + * + * returns: + * structure block offset of the parent of the node at nodeoffset + * (>=0), on success + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_parent_offset(const void *fdt, int nodeoffset); + +/** + * fdt_node_offset_by_prop_value - find nodes with a given property value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @propname: property name to check + * @propval: property value to search for + * @proplen: length of the value in propval + * + * fdt_node_offset_by_prop_value() returns the offset of the first + * node after startoffset, which has a property named propname whose + * value is of length proplen and has value equal to propval; or if + * startoffset is -1, the very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, + * propval, proplen); + * while (offset != -FDT_ERR_NOTFOUND) { + * // other code here + * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, + * propval, proplen); + * } + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + * structure block offset of the located node (>= 0, >startoffset), + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, + const char *propname, + const void *propval, int proplen); + +/** + * fdt_node_offset_by_phandle - find the node with a given phandle + * @fdt: pointer to the device tree blob + * @phandle: phandle value + * + * fdt_node_offset_by_phandle() returns the offset of the node + * which has the given phandle value. If there is more than one node + * in the tree with the given phandle (an invalid tree), results are + * undefined. + * + * returns: + * structure block offset of the located node (>= 0), on success + * -FDT_ERR_NOTFOUND, no node with that phandle exists + * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); + +/** + * fdt_node_check_compatible: check a node's compatible property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @compatible: string to match against + * + * + * fdt_node_check_compatible() returns 0 if the given node contains a + * 'compatible' property with the given string as one of its elements, + * it returns non-zero otherwise, or on error. + * + * returns: + * 0, if the node has a 'compatible' property listing the given string + * 1, if the node has a 'compatible' property, but it does not list + * the given string + * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property + * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_check_compatible(const void *fdt, int nodeoffset, + const char *compatible); + +/** + * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value + * @fdt: pointer to the device tree blob + * @startoffset: only find nodes after this offset + * @compatible: 'compatible' string to match against + * + * fdt_node_offset_by_compatible() returns the offset of the first + * node after startoffset, which has a 'compatible' property which + * lists the given compatible string; or if startoffset is -1, the + * very first such node in the tree. + * + * To iterate through all nodes matching the criterion, the following + * idiom can be used: + * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); + * while (offset != -FDT_ERR_NOTFOUND) { + * // other code here + * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); + * } + * + * Note the -1 in the first call to the function, if 0 is used here + * instead, the function will never locate the root node, even if it + * matches the criterion. + * + * returns: + * structure block offset of the located node (>= 0, >startoffset), + * on success + * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the + * tree after startoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, standard meanings + */ +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, + const char *compatible); + +/** + * fdt_stringlist_contains - check a string list property for a string + * @strlist: Property containing a list of strings to check + * @listlen: Length of property + * @str: String to search for + * + * This is a utility function provided for convenience. The list contains + * one or more strings, each terminated by \0, as is found in a device tree + * "compatible" property. + * + * @return: 1 if the string is found in the list, 0 not found, or invalid list + */ +int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); + +/** + * fdt_stringlist_count - count the number of strings in a string list + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @return: + * the number of strings in the given property + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist + */ +int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); + +/** + * fdt_stringlist_search - find a string in a string list and return its index + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @string: string to look up in the string list + * + * Note that it is possible for this function to succeed on property values + * that are not NUL-terminated. That's because the function will stop after + * finding the first occurrence of @string. This can for example happen with + * small-valued cell properties, such as #address-cells, when searching for + * the empty string. + * + * @return: + * the index of the string in the list of strings + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist or does not contain + * the given string + */ +int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, + const char *string); + +/** + * fdt_stringlist_get() - obtain the string at a given index in a string list + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of a tree node + * @property: name of the property containing the string list + * @index: index of the string to return + * @lenp: return location for the string length or an error code on failure + * + * Note that this will successfully extract strings from properties with + * non-NUL-terminated values. For example on small-valued cell properties + * this function will return the empty string. + * + * If non-NULL, the length of the string (on success) or a negative error-code + * (on failure) will be stored in the integer pointer to by lenp. + * + * @return: + * A pointer to the string at the given index in the string list or NULL on + * failure. On success the length of the string will be stored in the memory + * location pointed to by the lenp parameter, if non-NULL. On failure one of + * the following negative error codes will be returned in the lenp parameter + * (if non-NULL): + * -FDT_ERR_BADVALUE if the property value is not NUL-terminated + * -FDT_ERR_NOTFOUND if the property does not exist + */ +const char *fdt_stringlist_get(const void *fdt, int nodeoffset, + const char *property, int index, + int *lenp); + +/**********************************************************************/ +/* Read-only functions (addressing related) */ +/**********************************************************************/ + +/** + * FDT_MAX_NCELLS - maximum value for #address-cells and #size-cells + * + * This is the maximum value for #address-cells, #size-cells and + * similar properties that will be processed by libfdt. IEE1275 + * requires that OF implementations handle values up to 4. + * Implementations may support larger values, but in practice higher + * values aren't used. + */ +#define FDT_MAX_NCELLS 4 + +/** + * fdt_address_cells - retrieve address size for a bus represented in the tree + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to find the address size for + * + * When the node has a valid #address-cells property, returns its value. + * + * returns: + * 0 <= n < FDT_MAX_NCELLS, on success + * 2, if the node has no #address-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #address-cells property + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_address_cells(const void *fdt, int nodeoffset); + +/** + * fdt_size_cells - retrieve address range size for a bus represented in the + * tree + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to find the address range size for + * + * When the node has a valid #size-cells property, returns its value. + * + * returns: + * 0 <= n < FDT_MAX_NCELLS, on success + * 2, if the node has no #address-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #size-cells property + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_size_cells(const void *fdt, int nodeoffset); + + +/**********************************************************************/ +/* Write-in-place functions */ +/**********************************************************************/ + +/** + * fdt_setprop_inplace_namelen_partial - change a property's value, + * but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @namelen: number of characters of name to consider + * @idx: index of the property to change in the array + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * Identical to fdt_setprop_inplace(), but modifies the given property + * starting from the given index, and using only the first characters + * of the name. It is useful when you want to manipulate only one value of + * an array and you have a string that doesn't end with \0. + */ +#ifndef SWIG /* Not available in Python */ +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len); +#endif + +/** + * fdt_setprop_inplace - change a property's value, but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * fdt_setprop_inplace() replaces the value of a given property with + * the data in val, of length len. This function cannot change the + * size of a property, and so will only work if len is equal to the + * current length of the property. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if len is not equal to the property's current length + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#ifndef SWIG /* Not available in Python */ +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len); +#endif + +/** + * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to replace the property with + * + * fdt_setprop_inplace_u32() replaces the value of a given property + * with the 32-bit integer value in val, converting val to big-endian + * if necessary. This function cannot change the size of a property, + * and so will only work if the property already exists and has length + * 4. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value to replace the property with + * + * fdt_setprop_inplace_u64() replaces the value of a given property + * with the 64-bit integer value in val, converting val to big-endian + * if necessary. This function cannot change the size of a property, + * and so will only work if the property already exists and has length + * 8. + * + * This function will alter only the bytes in the blob which contain + * the given property value, and will not alter or move any other part + * of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, if the property's length is not equal to 8 + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, + const char *name, uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_inplace_cell - change the value of a single-cell property + * + * This is an alternative name for fdt_setprop_inplace_u32() + */ +static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val); +} + +/** + * fdt_nop_property - replace a property with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_nop_property() will replace a given property's representation + * in the blob with FDT_NOP tags, effectively removing it from the + * tree. + * + * This function will alter only the bytes in the blob which contain + * the property, and will not alter or move any other part of the + * tree. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_nop_property(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_nop_node - replace a node (subtree) with nop tags + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_nop_node() will replace a given node's representation in the + * blob, including all its subnodes, if any, with FDT_NOP tags, + * effectively removing it from the tree. + * + * This function will alter only the bytes in the blob which contain + * the node and its properties and subnodes, and will not alter or + * move any other part of the tree. + * + * returns: + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_nop_node(void *fdt, int nodeoffset); + +/**********************************************************************/ +/* Sequential write functions */ +/**********************************************************************/ + +int fdt_create(void *buf, int bufsize); +int fdt_resize(void *fdt, void *buf, int bufsize); +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); +int fdt_finish_reservemap(void *fdt); +int fdt_begin_node(void *fdt, const char *name); +int fdt_property(void *fdt, const char *name, const void *val, int len); +static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_property(fdt, name, &tmp, sizeof(tmp)); +} +static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_property(fdt, name, &tmp, sizeof(tmp)); +} +static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) +{ + return fdt_property_u32(fdt, name, val); +} + +/** + * fdt_property_placeholder - add a new property and return a ptr to its value + * + * @fdt: pointer to the device tree blob + * @name: name of property to add + * @len: length of property value in bytes + * @valp: returns a pointer to where where the value should be placed + * + * returns: + * 0, on success + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_NOSPACE, standard meanings + */ +int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp); + +#define fdt_property_string(fdt, name, str) \ + fdt_property(fdt, name, str, strlen(str)+1) +int fdt_end_node(void *fdt); +int fdt_finish(void *fdt); + +/**********************************************************************/ +/* Read-write functions */ +/**********************************************************************/ + +int fdt_create_empty_tree(void *buf, int bufsize); +int fdt_open_into(const void *fdt, void *buf, int bufsize); +int fdt_pack(void *fdt); + +/** + * fdt_add_mem_rsv - add one memory reserve map entry + * @fdt: pointer to the device tree blob + * @address, @size: 64-bit values (native endian) + * + * Adds a reserve map entry to the given blob reserving a region at + * address address of length size. + * + * This function will insert data into the reserve map and will + * therefore change the indexes of some entries in the table. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new reservation entry + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); + +/** + * fdt_del_mem_rsv - remove a memory reserve map entry + * @fdt: pointer to the device tree blob + * @n: entry to remove + * + * fdt_del_mem_rsv() removes the n-th memory reserve map entry from + * the blob. + * + * This function will delete data from the reservation table and will + * therefore change the indexes of some entries in the table. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there + * are less than n+1 reserve map entries) + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_del_mem_rsv(void *fdt, int n); + +/** + * fdt_set_name - change the name of a given node + * @fdt: pointer to the device tree blob + * @nodeoffset: structure block offset of a node + * @name: name to give the node + * + * fdt_set_name() replaces the name (including unit address, if any) + * of the given node with the given string. NOTE: this function can't + * efficiently check if the new name is unique amongst the given + * node's siblings; results are undefined if this function is invoked + * with a name equal to one of the given node's siblings. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob + * to contain the new name + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, standard meanings + */ +int fdt_set_name(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_setprop - create or change a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: pointer to data to set the property value to + * @len: length of the property value + * + * fdt_setprop() sets the value of the named property in the given + * node to the given value and length, creating the property if it + * does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_setprop _placeholder - allocate space for a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @len: length of the property value + * @prop_data: return pointer to property data + * + * fdt_setprop_placeholer() allocates the named property in the given node. + * If the property exists it is resized. In either case a pointer to the + * property data is returned. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, + int len, void **prop_data); + +/** + * fdt_setprop_u32 - set a property to a 32-bit integer + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value for the property (native endian) + * + * fdt_setprop_u32() sets the value of the named property in the given + * node to the given 32-bit integer value (converting to big-endian if + * necessary), or creates a new property with that value if it does + * not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, + uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_u64 - set a property to a 64-bit integer + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value for the property (native endian) + * + * fdt_setprop_u64() sets the value of the named property in the given + * node to the given 64-bit integer value (converting to big-endian if + * necessary), or creates a new property with that value if it does + * not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, + uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_setprop_cell - set a property to a single cell value + * + * This is an alternative name for fdt_setprop_u32() + */ +static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, + uint32_t val) +{ + return fdt_setprop_u32(fdt, nodeoffset, name, val); +} + +/** + * fdt_setprop_string - set a property to a string value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value for the property + * + * fdt_setprop_string() sets the value of the named property in the + * given node to the given string value (using the length of the + * string to determine the new length of the property), or creates a + * new property with that value if it does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_setprop_string(fdt, nodeoffset, name, str) \ + fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + + +/** + * fdt_setprop_empty - set a property to an empty value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * + * fdt_setprop_empty() sets the value of the named property in the + * given node to an empty (zero length) value, or creates a new empty + * property if it does not already exist. + * + * This function may insert or delete data from the blob, and will + * therefore change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_setprop_empty(fdt, nodeoffset, name) \ + fdt_setprop((fdt), (nodeoffset), (name), NULL, 0) + +/** + * fdt_appendprop - append to or create a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to append to + * @val: pointer to data to append to the property value + * @len: length of the data to append to the property value + * + * fdt_appendprop() appends the value to the named property in the + * given node, creating the property if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len); + +/** + * fdt_appendprop_u32 - append a 32-bit integer value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to append to the property (native endian) + * + * fdt_appendprop_u32() appends the given 32-bit integer value + * (converting to big-endian if necessary) to the value of the named + * property in the given node, or creates a new property with that + * value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + fdt32_t tmp = cpu_to_fdt32(val); + return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_appendprop_u64 - append a 64-bit integer value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 64-bit integer value to append to the property (native endian) + * + * fdt_appendprop_u64() appends the given 64-bit integer value + * (converting to big-endian if necessary) to the value of the named + * property in the given node, or creates a new property with that + * value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, + const char *name, uint64_t val) +{ + fdt64_t tmp = cpu_to_fdt64(val); + return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/** + * fdt_appendprop_cell - append a single cell value to a property + * + * This is an alternative name for fdt_appendprop_u32() + */ +static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, + const char *name, uint32_t val) +{ + return fdt_appendprop_u32(fdt, nodeoffset, name, val); +} + +/** + * fdt_appendprop_string - append a string to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @str: string value to append to the property + * + * fdt_appendprop_string() appends the given string to the value of + * the named property in the given node, or creates a new property + * with that value if it does not already exist. + * + * This function may insert data into the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to + * contain the new property value + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_TRUNCATED, standard meanings + */ +#define fdt_appendprop_string(fdt, nodeoffset, name, str) \ + fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) + +/** + * fdt_delprop - delete a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to nop + * @name: name of the property to nop + * + * fdt_del_property() will delete the given property. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_NOTFOUND, node does not have the named property + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_delprop(void *fdt, int nodeoffset, const char *name); + +/** + * fdt_add_subnode_namelen - creates a new node based on substring + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * @namelen: number of characters of name to consider + * + * Identical to fdt_add_subnode(), but use only the first namelen + * characters of name as the name of the new node. This is useful for + * creating subnodes based on a portion of a larger string, such as a + * full path. + */ +#ifndef SWIG /* Not available in Python */ +int fdt_add_subnode_namelen(void *fdt, int parentoffset, + const char *name, int namelen); +#endif + +/** + * fdt_add_subnode - creates a new node + * @fdt: pointer to the device tree blob + * @parentoffset: structure block offset of a node + * @name: name of the subnode to locate + * + * fdt_add_subnode() creates a new node as a subnode of the node at + * structure block offset parentoffset, with the given name (which + * should include the unit address, if any). + * + * This function will insert data into the blob, and will therefore + * change the offsets of some existing nodes. + + * returns: + * structure block offset of the created nodeequested subnode (>=0), on + * success + * -FDT_ERR_NOTFOUND, if the requested subnode does not exist + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag + * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of + * the given name + * -FDT_ERR_NOSPACE, if there is insufficient free space in the + * blob to contain the new node + * -FDT_ERR_NOSPACE + * -FDT_ERR_BADLAYOUT + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings. + */ +int fdt_add_subnode(void *fdt, int parentoffset, const char *name); + +/** + * fdt_del_node - delete a node (subtree) + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node to nop + * + * fdt_del_node() will remove the given node, including all its + * subnodes if any, from the blob. + * + * This function will delete data from the blob, and will therefore + * change the offsets of some existing nodes. + * + * returns: + * 0, on success + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_del_node(void *fdt, int nodeoffset); + +/** + * fdt_overlay_apply - Applies a DT overlay on a base DT + * @fdt: pointer to the base device tree blob + * @fdto: pointer to the device tree overlay blob + * + * fdt_overlay_apply() will apply the given device tree overlay on the + * given base device tree. + * + * Expect the base device tree to be modified, even if the function + * returns an error. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there's not enough space in the base device tree + * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or + * properties in the base DT + * -FDT_ERR_BADPHANDLE, + * -FDT_ERR_BADOVERLAY, + * -FDT_ERR_NOPHANDLES, + * -FDT_ERR_INTERNAL, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADOFFSET, + * -FDT_ERR_BADPATH, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_overlay_apply(void *fdt, void *fdto); + +/**********************************************************************/ +/* Debugging / informational functions */ +/**********************************************************************/ + +const char *fdt_strerror(int errval); + +#endif /* _LIBFDT_H */ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/libfdt_env.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/libfdt_env.h new file mode 100644 index 00000000..863e54e9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Include/libfdt_env.h @@ -0,0 +1,83 @@ +/** @file +* +* Copyright (c) 2011-2014, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef _LIBFDT_ENV_H +#define _LIBFDT_ENV_H + +#include +#include + +typedef UINT16 fdt16_t; +typedef UINT32 fdt32_t; +typedef UINT64 fdt64_t; + +typedef UINT8 uint8_t; +typedef UINT16 uint16_t; +typedef UINT32 uint32_t; +typedef UINT64 uint64_t; +typedef UINTN uintptr_t; +typedef UINTN size_t; + +static inline uint16_t fdt16_to_cpu(fdt16_t x) +{ + return SwapBytes16 (x); +} +#define cpu_to_fdt16(x) fdt16_to_cpu(x) + +static inline uint32_t fdt32_to_cpu(fdt32_t x) +{ + return SwapBytes32 (x); +} +#define cpu_to_fdt32(x) fdt32_to_cpu(x) + +static inline uint64_t fdt64_to_cpu(fdt64_t x) +{ + return SwapBytes64 (x); +} +#define cpu_to_fdt64(x) fdt64_to_cpu(x) + +static inline void* memcpy(void* dest, const void* src, size_t len) { + return CopyMem (dest, src, len); +} + +static inline void *memmove(void *dest, const void *src, size_t n) { + return CopyMem (dest, src, n); +} + +static inline void *memset(void *s, int c, size_t n) { + return SetMem (s, n, c); +} + +static inline int memcmp(const void* dest, const void* src, int len) { + return CompareMem (dest, src, len); +} + +static inline void *memchr(const void *s, int c, size_t n) { + return ScanMem8 (s, n, c); +} + +static inline size_t strlen (const char* str) { + return AsciiStrLen (str); +} + +static inline char *strchr(const char *s, int c) { + char pattern[2]; + pattern[0] = c; + pattern[1] = 0; + return AsciiStrStr (s, pattern); +} + +static inline size_t strnlen (const char* str, size_t strsz ) { + return AsciiStrnLenS (str, strsz); +} + +static inline size_t strncmp (const char* str1, const char* str2, size_t strsz ) { + return AsciiStrnCmp (str1, str2, strsz); +} + +#endif /* _LIBFDT_ENV_H */ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.c new file mode 100644 index 00000000..e71bbad7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.c @@ -0,0 +1,172 @@ +/** @file +* +* Copyright (c) 2014-2015, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include + +#include +#include +#include + +#include +#include + +#include + +/** + Locate and Install the ACPI tables from the Firmware Volume if it verifies + the function condition. + + @param AcpiFile Guid of the ACPI file into the Firmware Volume + @param CheckAcpiTableFunction Function that checks if the ACPI table should be installed + + @return EFI_SUCCESS The function completed successfully. + @return EFI_NOT_FOUND The protocol could not be located. + @return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol. + +**/ +EFI_STATUS +LocateAndInstallAcpiFromFvConditional ( + IN CONST EFI_GUID* AcpiFile, + IN EFI_LOCATE_ACPI_CHECK CheckAcpiTableFunction + ) +{ + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + UINT32 FvStatus; + UINTN Index; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance; + INTN SectionInstance; + UINTN SectionSize; + EFI_ACPI_COMMON_HEADER *AcpiTable; + UINTN AcpiTableSize; + UINTN AcpiTableKey; + BOOLEAN Valid; + + // Ensure the ACPI Table is present + Status = gBS->LocateProtocol ( + &gEfiAcpiTableProtocolGuid, + NULL, + (VOID**)&AcpiProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FvStatus = 0; + SectionInstance = 0; + + // Locate all the Firmware Volume protocols. + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Looking for FV with ACPI storage file + for (Index = 0; Index < NumberOfHandles; Index++) { + // + // Get the protocol on this handle + // This should not fail because of LocateHandleBuffer + // + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolume2ProtocolGuid, + (VOID**) &FvInstance + ); + if (EFI_ERROR (Status)) { + goto FREE_HANDLE_BUFFER; + } + + while (Status == EFI_SUCCESS) { + // AcpiTable must be allocated by ReadSection (ie: AcpiTable == NULL) + AcpiTable = NULL; + + // See if it has the ACPI storage file + Status = FvInstance->ReadSection ( + FvInstance, + AcpiFile, + EFI_SECTION_RAW, + SectionInstance, + (VOID**) &AcpiTable, + &SectionSize, + &FvStatus + ); + if (!EFI_ERROR (Status)) { + AcpiTableKey = 0; + AcpiTableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Length; + ASSERT (SectionSize >= AcpiTableSize); + + DEBUG ((EFI_D_ERROR, "- Found '%c%c%c%c' ACPI Table\n", + (((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature & 0xFF), + ((((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature >> 8) & 0xFF), + ((((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature >> 16) & 0xFF), + ((((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature >> 24) & 0xFF))); + + // Is the ACPI table valid? + if (CheckAcpiTableFunction) { + Valid = CheckAcpiTableFunction ((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable); + } else { + Valid = TRUE; + } + + // Install the ACPI Table + if (Valid) { + Status = AcpiProtocol->InstallAcpiTable ( + AcpiProtocol, + AcpiTable, + AcpiTableSize, + &AcpiTableKey + ); + } + + // Free memory allocated by ReadSection + gBS->FreePool (AcpiTable); + + if (EFI_ERROR (Status)) { + break; + } + + // Increment the section instance + SectionInstance++; + } + } + } + +FREE_HANDLE_BUFFER: + // + // Free any allocated buffers + // + gBS->FreePool (HandleBuffer); + + return EFI_SUCCESS; +} + +/** + Locate and Install the ACPI tables from the Firmware Volume + + @param AcpiFile Guid of the ACPI file into the Firmware Volume + + @return EFI_SUCCESS The function completed successfully. + @return EFI_NOT_FOUND The protocol could not be located. + @return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol. + +**/ +EFI_STATUS +LocateAndInstallAcpiFromFv ( + IN CONST EFI_GUID* AcpiFile + ) +{ + return LocateAndInstallAcpiFromFvConditional (AcpiFile, NULL); +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.inf new file mode 100644 index 00000000..7f0fb091 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.inf @@ -0,0 +1,31 @@ +#/** @file +# +# Copyright (c) 2014, ARM Ltd. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AcpiLib + FILE_GUID = 24b9d62c-5a36-417b-94b6-38dbaea90dcf + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = AcpiLib + +[Sources.common] + AcpiLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + DebugLib + UefiBootServicesTableLib + +[Protocols] + gEfiAcpiTableProtocolGuid + gEfiFirmwareVolume2ProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c new file mode 100644 index 00000000..444884c9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c @@ -0,0 +1,470 @@ +/** @file + + Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
+ Copyright (c) 2017, Linaro. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define FDT_ADDITIONAL_ENTRIES_SIZE 0x400 + +typedef struct { + MEMMAP_DEVICE_PATH Node1; + EFI_DEVICE_PATH_PROTOCOL End; +} MEMORY_DEVICE_PATH; + +STATIC ANDROID_BOOTIMG_PROTOCOL *mAndroidBootImg; + +STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate = +{ + { + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + { + (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), + (UINT8)((sizeof (MEMMAP_DEVICE_PATH)) >> 8), + }, + }, // Header + 0, // StartingAddress (set at runtime) + 0 // EndingAddress (set at runtime) + }, // Node1 + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } + } // End +}; + +EFI_STATUS +AndroidBootImgGetImgSize ( + IN VOID *BootImg, + OUT UINTN *ImgSize + ) +{ + ANDROID_BOOTIMG_HEADER *Header; + + Header = (ANDROID_BOOTIMG_HEADER *) BootImg; + + if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC, + ANDROID_BOOT_MAGIC_LENGTH) != 0) { + return EFI_INVALID_PARAMETER; + } + + /* The page size is not specified, but it should be power of 2 at least */ + ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); + + /* Get real size of abootimg */ + *ImgSize = ALIGN_VALUE (Header->KernelSize, Header->PageSize) + + ALIGN_VALUE (Header->RamdiskSize, Header->PageSize) + + ALIGN_VALUE (Header->SecondStageBootloaderSize, Header->PageSize) + + Header->PageSize; + return EFI_SUCCESS; +} + +EFI_STATUS +AndroidBootImgGetKernelInfo ( + IN VOID *BootImg, + OUT VOID **Kernel, + OUT UINTN *KernelSize + ) +{ + ANDROID_BOOTIMG_HEADER *Header; + + Header = (ANDROID_BOOTIMG_HEADER *) BootImg; + + if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC, + ANDROID_BOOT_MAGIC_LENGTH) != 0) { + return EFI_INVALID_PARAMETER; + } + + if (Header->KernelSize == 0) { + return EFI_NOT_FOUND; + } + + ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); + + *KernelSize = Header->KernelSize; + *Kernel = (VOID *)((UINTN)BootImg + Header->PageSize); + return EFI_SUCCESS; +} + +EFI_STATUS +AndroidBootImgGetRamdiskInfo ( + IN VOID *BootImg, + OUT VOID **Ramdisk, + OUT UINTN *RamdiskSize + ) +{ + ANDROID_BOOTIMG_HEADER *Header; + + Header = (ANDROID_BOOTIMG_HEADER *)BootImg; + + if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC, + ANDROID_BOOT_MAGIC_LENGTH) != 0) { + return EFI_INVALID_PARAMETER; + } + + ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); + + *RamdiskSize = Header->RamdiskSize; + + if (Header->RamdiskSize != 0) { + *Ramdisk = (VOID *)((INTN)BootImg + + Header->PageSize + + ALIGN_VALUE (Header->KernelSize, Header->PageSize)); + } + return EFI_SUCCESS; +} + +EFI_STATUS +AndroidBootImgGetSecondBootLoaderInfo ( + IN VOID *BootImg, + OUT VOID **Second, + OUT UINTN *SecondSize + ) +{ + ANDROID_BOOTIMG_HEADER *Header; + + Header = (ANDROID_BOOTIMG_HEADER *)BootImg; + + if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC, + ANDROID_BOOT_MAGIC_LENGTH) != 0) { + return EFI_INVALID_PARAMETER; + } + + ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); + + *SecondSize = Header->SecondStageBootloaderSize; + + if (Header->SecondStageBootloaderSize != 0) { + *Second = (VOID *)((UINTN)BootImg + + Header->PageSize + + ALIGN_VALUE (Header->KernelSize, Header->PageSize) + + ALIGN_VALUE (Header->RamdiskSize, Header->PageSize)); + } + return EFI_SUCCESS; +} + +EFI_STATUS +AndroidBootImgGetKernelArgs ( + IN VOID *BootImg, + OUT CHAR8 *KernelArgs + ) +{ + ANDROID_BOOTIMG_HEADER *Header; + + Header = (ANDROID_BOOTIMG_HEADER *) BootImg; + AsciiStrnCpyS (KernelArgs, ANDROID_BOOTIMG_KERNEL_ARGS_SIZE, Header->KernelArgs, + ANDROID_BOOTIMG_KERNEL_ARGS_SIZE); + + return EFI_SUCCESS; +} + +EFI_STATUS +AndroidBootImgGetFdt ( + IN VOID *BootImg, + IN VOID **FdtBase + ) +{ + UINTN SecondLoaderSize; + EFI_STATUS Status; + + /* Check whether FDT is located in second boot region as some vendor do so, + * because second loader is never used as far as I know. */ + Status = AndroidBootImgGetSecondBootLoaderInfo ( + BootImg, + FdtBase, + &SecondLoaderSize + ); + return Status; +} + +EFI_STATUS +AndroidBootImgUpdateArgs ( + IN VOID *BootImg, + OUT VOID *KernelArgs + ) +{ + CHAR8 ImageKernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE]; + EFI_STATUS Status; + + // Get kernel arguments from Android boot image + Status = AndroidBootImgGetKernelArgs (BootImg, ImageKernelArgs); + if (EFI_ERROR (Status)) { + return Status; + } + AsciiStrToUnicodeStrS (ImageKernelArgs, KernelArgs, + ANDROID_BOOTIMG_KERNEL_ARGS_SIZE >> 1); + // Append platform kernel arguments + if(mAndroidBootImg->AppendArgs) { + Status = mAndroidBootImg->AppendArgs (KernelArgs, + ANDROID_BOOTIMG_KERNEL_ARGS_SIZE); + } + return Status; +} + +EFI_STATUS +AndroidBootImgLocateFdt ( + IN VOID *BootImg, + IN VOID **FdtBase + ) +{ + INTN Err; + EFI_STATUS Status; + + Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, FdtBase); + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + Status = AndroidBootImgGetFdt (BootImg, FdtBase); + if (EFI_ERROR (Status)) { + return Status; + } + Err = fdt_check_header (*FdtBase); + if (Err != 0) { + DEBUG ((DEBUG_ERROR, "ERROR: Device Tree header not valid (Err:%d)\n", + Err)); + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + +INTN +AndroidBootImgGetChosenNode ( + IN INTN UpdatedFdtBase + ) +{ + INTN ChosenNode; + + ChosenNode = fdt_subnode_offset ((CONST VOID *)UpdatedFdtBase, 0, "chosen"); + if (ChosenNode < 0) { + ChosenNode = fdt_add_subnode((VOID *)UpdatedFdtBase, 0, "chosen"); + if (ChosenNode < 0) { + DEBUG ((DEBUG_ERROR, "Fail to find fdt node chosen!\n")); + return 0; + } + } + return ChosenNode; +} + +EFI_STATUS +AndroidBootImgSetProperty64 ( + IN INTN UpdatedFdtBase, + IN INTN ChosenNode, + IN CHAR8 *PropertyName, + IN UINT64 Val + ) +{ + INTN Err; + struct fdt_property *Property; + int Len; + + Property = fdt_get_property_w((VOID *)UpdatedFdtBase, ChosenNode, + PropertyName, &Len); + if (NULL == Property && Len == -FDT_ERR_NOTFOUND) { + Val = cpu_to_fdt64(Val); + Err = fdt_appendprop ((VOID *)UpdatedFdtBase, ChosenNode, + PropertyName, &Val, sizeof (UINT64)); + if (Err) { + DEBUG ((DEBUG_ERROR, "fdt_appendprop() fail: %a\n", fdt_strerror (Err))); + return EFI_INVALID_PARAMETER; + } + } else if (Property != NULL) { + Err = fdt_setprop_u64((VOID *)UpdatedFdtBase, ChosenNode, + PropertyName, Val); + if (Err) { + DEBUG ((DEBUG_ERROR, "fdt_setprop_u64() fail: %a\n", fdt_strerror (Err))); + return EFI_INVALID_PARAMETER; + } + } else { + DEBUG ((DEBUG_ERROR, "Failed to set fdt Property %a\n", PropertyName)); + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + +EFI_STATUS +AndroidBootImgUpdateFdt ( + IN VOID *BootImg, + IN VOID *FdtBase, + IN VOID *RamdiskData, + IN UINTN RamdiskSize + ) +{ + INTN ChosenNode, Err, NewFdtSize; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS UpdatedFdtBase, NewFdtBase; + + NewFdtSize = (UINTN)fdt_totalsize (FdtBase) + + FDT_ADDITIONAL_ENTRIES_SIZE; + Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, + EFI_SIZE_TO_PAGES (NewFdtSize), &UpdatedFdtBase); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "Warning: Failed to reallocate FDT, err %d.\n", + Status)); + return Status; + } + + // Load the Original FDT tree into the new region + Err = fdt_open_into(FdtBase, (VOID*)(INTN)UpdatedFdtBase, NewFdtSize); + if (Err) { + DEBUG ((DEBUG_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Err))); + Status = EFI_INVALID_PARAMETER; + goto Fdt_Exit; + } + + ChosenNode = AndroidBootImgGetChosenNode(UpdatedFdtBase); + if (!ChosenNode) { + goto Fdt_Exit; + } + + Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode, + "linux,initrd-start", + (UINTN)RamdiskData); + if (EFI_ERROR (Status)) { + goto Fdt_Exit; + } + + Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode, + "linux,initrd-end", + (UINTN)RamdiskData + RamdiskSize); + if (EFI_ERROR (Status)) { + goto Fdt_Exit; + } + + if (mAndroidBootImg->UpdateDtb) { + Status = mAndroidBootImg->UpdateDtb (UpdatedFdtBase, &NewFdtBase); + if (EFI_ERROR (Status)) { + goto Fdt_Exit; + } + + Status = gBS->InstallConfigurationTable ( + &gFdtTableGuid, + (VOID *)(UINTN)NewFdtBase + ); + } + + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + +Fdt_Exit: + gBS->FreePages (UpdatedFdtBase, EFI_SIZE_TO_PAGES (NewFdtSize)); + return Status; +} + +EFI_STATUS +AndroidBootImgBoot ( + IN VOID *Buffer, + IN UINTN BufferSize + ) +{ + EFI_STATUS Status; + VOID *Kernel; + UINTN KernelSize; + MEMORY_DEVICE_PATH KernelDevicePath; + EFI_HANDLE ImageHandle; + VOID *NewKernelArg; + EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; + VOID *RamdiskData; + UINTN RamdiskSize; + IN VOID *FdtBase; + + Status = gBS->LocateProtocol (&gAndroidBootImgProtocolGuid, NULL, + (VOID **) &mAndroidBootImg); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = AndroidBootImgGetKernelInfo ( + Buffer, + &Kernel, + &KernelSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + NewKernelArg = AllocateZeroPool (ANDROID_BOOTIMG_KERNEL_ARGS_SIZE); + if (NewKernelArg == NULL) { + DEBUG ((DEBUG_ERROR, "Fail to allocate memory\n")); + return EFI_OUT_OF_RESOURCES; + } + + Status = AndroidBootImgUpdateArgs (Buffer, NewKernelArg); + if (EFI_ERROR (Status)) { + FreePool (NewKernelArg); + return Status; + } + + Status = AndroidBootImgGetRamdiskInfo ( + Buffer, + &RamdiskData, + &RamdiskSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = AndroidBootImgLocateFdt (Buffer, &FdtBase); + if (EFI_ERROR (Status)) { + FreePool (NewKernelArg); + return Status; + } + + Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize); + if (EFI_ERROR (Status)) { + FreePool (NewKernelArg); + return Status; + } + + KernelDevicePath = mMemoryDevicePathTemplate; + + KernelDevicePath.Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel; + KernelDevicePath.Node1.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel + + KernelSize; + + Status = gBS->LoadImage (TRUE, gImageHandle, + (EFI_DEVICE_PATH *)&KernelDevicePath, + (VOID*)(UINTN)Kernel, KernelSize, &ImageHandle); + if (EFI_ERROR (Status)) { + // + // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created + // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now. + // If the caller doesn't have the option to defer the execution of an image, we should + // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak. + // + if (Status == EFI_SECURITY_VIOLATION) { + gBS->UnloadImage (ImageHandle); + } + return Status; + } + + // Set kernel arguments + Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, + (VOID **) &ImageInfo); + ImageInfo->LoadOptions = NewKernelArg; + ImageInfo->LoadOptionsSize = StrLen (NewKernelArg) * sizeof (CHAR16); + + // Before calling the image, enable the Watchdog Timer for the 5 Minute period + gBS->SetWatchdogTimer (5 * 60, 0x10000, 0, NULL); + // Start the image + Status = gBS->StartImage (ImageHandle, NULL, NULL); + // Clear the Watchdog Timer if the image returns + gBS->SetWatchdogTimer (0, 0x10000, 0, NULL); + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf new file mode 100644 index 00000000..2e3b6f50 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf @@ -0,0 +1,44 @@ +#/** @file +# +# Copyright (c) 2013-2015, ARM Ltd. All rights reserved.
+# Copyright (c) 2017, Linaro. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = AndroidBootImgLib + FILE_GUID = ed3b8739-6fa7-4cb1-8aeb-2496f8fcaefa + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = AndroidBootImgLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = ARM AARCH64 +# + +[Sources] + AndroidBootImgLib.c + +[LibraryClasses] + DebugLib + FdtLib + PrintLib + UefiBootServicesTableLib + UefiLib + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[Protocols] + gAndroidBootImgProtocolGuid + gEfiLoadedImageProtocolGuid + +[Guids] + gFdtTableGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.c new file mode 100644 index 00000000..5d458213 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.c @@ -0,0 +1,195 @@ +/** @file + Generic ARM implementation of DmaLib.h + + Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include + + +STATIC +PHYSICAL_ADDRESS +HostToDeviceAddress ( + IN VOID *Address + ) +{ + return (PHYSICAL_ADDRESS)(UINTN)Address + PcdGet64 (PcdDmaDeviceOffset); +} + +/** + Provides the DMA controller-specific addresses needed to access system memory. + + Operation is relative to the DMA bus master. + + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the DMA controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +EFI_STATUS +EFIAPI +DmaMap ( + IN DMA_MAP_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + if (HostAddress == NULL || + NumberOfBytes == NULL || + DeviceAddress == NULL || + Mapping == NULL ) { + return EFI_INVALID_PARAMETER; + } + *DeviceAddress = HostToDeviceAddress (HostAddress); + *Mapping = NULL; + return EFI_SUCCESS; +} + + +/** + Completes the DmaMapBusMasterRead(), DmaMapBusMasterWrite(), or DmaMapBusMasterCommonBuffer() + operation and releases any corresponding resources. + + @param Mapping The mapping value returned from DmaMap*(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + +**/ +EFI_STATUS +EFIAPI +DmaUnmap ( + IN VOID *Mapping + ) +{ + return EFI_SUCCESS; +} + +/** + Allocates pages that are suitable for an DmaMap() of type MapOperationBusMasterCommonBuffer. + mapping. + + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +DmaAllocateBuffer ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress + ) +{ + return DmaAllocateAlignedBuffer (MemoryType, Pages, 0, HostAddress); +} + + +/** + Allocates pages that are suitable for an DmaMap() of type + MapOperationBusMasterCommonBuffer mapping, at the requested alignment. + + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param Alignment Alignment in bytes of the base of the returned + buffer (must be a power of 2) + @param HostAddress A pointer to store the base system memory address of the + allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +DmaAllocateAlignedBuffer ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment, + OUT VOID **HostAddress + ) +{ + if (Alignment == 0) { + Alignment = EFI_PAGE_SIZE; + } + + if (HostAddress == NULL || + (Alignment & (Alignment - 1)) != 0) { + return EFI_INVALID_PARAMETER; + } + + // + // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData + // + if (MemoryType == EfiBootServicesData) { + *HostAddress = AllocateAlignedPages (Pages, Alignment); + } else if (MemoryType == EfiRuntimeServicesData) { + *HostAddress = AllocateAlignedRuntimePages (Pages, Alignment); + } else { + return EFI_INVALID_PARAMETER; + } + + if (*HostAddress == NULL) { + return EFI_OUT_OF_RESOURCES; + } + return EFI_SUCCESS; +} + + +/** + Frees memory that was allocated with DmaAllocateBuffer(). + + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with DmaAllocateBuffer(). + +**/ +EFI_STATUS +EFIAPI +DmaFreeBuffer ( + IN UINTN Pages, + IN VOID *HostAddress + ) +{ + if (HostAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + FreePages (HostAddress, Pages); + return EFI_SUCCESS; +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.inf new file mode 100644 index 00000000..7e518d9f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.inf @@ -0,0 +1,30 @@ +#/** @file +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+# Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = CoherentDmaLib + FILE_GUID = 0F2A0816-D319-4ee7-A6B8-D58524E4428F + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DmaLib + +[Sources] + CoherentDmaLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + DebugLib + MemoryAllocationLib + +[Pcd] + gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLib.c new file mode 100644 index 00000000..dac101e7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLib.c @@ -0,0 +1,57 @@ +/** @file + Null Debug Agent timer. + + The debug agent uses the timer so the debugger can break into running programs. + If you link against this library you will not be able to break into a running + program with the debugger. + + Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +/** + Setup all the hardware needed for the debug agents timer. + + This function is used to set up debug environment. It may enable interrupts. + +**/ +VOID +EFIAPI +DebugAgentTimerIntialize ( + VOID + ) +{ +} + + +/** + Set the period for the debug agent timer. Zero means disable the timer. + + @param[in] TimerPeriodMilliseconds Frequency of the debug agent timer. + +**/ +VOID +EFIAPI +DebugAgentTimerSetPeriod ( + IN UINT32 TimerPeriodMilliseconds + ) +{ +} + + +/** + Perform End Of Interrupt for the debug agent timer. This is called in the + interrupt handler after the interrupt has been processed. + +**/ +VOID +EFIAPI +DebugAgentTimerEndOfInterrupt ( + VOID + ) +{ +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf new file mode 100644 index 00000000..48e83cae --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf @@ -0,0 +1,32 @@ +#/** @file +# Component description file for Base PCI Cf8 Library. +# +# PCI CF8 Library that uses I/O ports 0xCF8 and 0xCFC to perform PCI Configuration cycles. +# Layers on top of an I/O Library instance. +# Copyright (c) 2007, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DebugAgentTimerLibNull + FILE_GUID = 02f04694-2c0a-4f1e-b0ce-64be25890b03 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DebugAgentTimerLib|SEC BASE DXE_CORE + + +[Sources.common] + DebugAgentTimerLib.c + + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + IoLib + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.c new file mode 100644 index 00000000..53c2050a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.c @@ -0,0 +1,54 @@ +/** @file +* +* Copyright (c) 2017, Linaro, Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include + +#include +#include +#include + +/** + Return a pool allocated copy of the DTB image that is appropriate for + booting the current platform via DT. + + @param[out] Dtb Pointer to the DTB copy + @param[out] DtbSize Size of the DTB copy + + @retval EFI_SUCCESS Operation completed successfully + @retval EFI_NOT_FOUND No suitable DTB image could be located + @retval EFI_OUT_OF_RESOURCES No pool memory available + +**/ +EFI_STATUS +EFIAPI +DtPlatformLoadDtb ( + OUT VOID **Dtb, + OUT UINTN *DtbSize + ) +{ + EFI_STATUS Status; + VOID *OrigDtb; + VOID *CopyDtb; + UINTN OrigDtbSize; + + Status = GetSectionFromAnyFv (&gDtPlatformDefaultDtbFileGuid, + EFI_SECTION_RAW, 0, &OrigDtb, &OrigDtbSize); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + CopyDtb = AllocateCopyPool (OrigDtbSize, OrigDtb); + if (CopyDtb == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *Dtb = CopyDtb; + *DtbSize = OrigDtbSize; + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.inf new file mode 100644 index 00000000..9e27c453 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.inf @@ -0,0 +1,30 @@ +/** @file +* +* Copyright (c) 2017, Linaro, Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = DxeDtPlatformDtbLoaderLibDefault + FILE_GUID = 419a1910-70da-4c99-8696-ba81a57be508 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = DtPlatformDtbLoaderLib|DXE_DRIVER + +[Sources] + DxeDtPlatformDtbLoaderLibDefault.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + BaseLib + DxeServicesLib + MemoryAllocationLib + +[Guids] + gDtPlatformDefaultDtbFileGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/FdtLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/FdtLib.inf new file mode 100644 index 00000000..d4cb9a0e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/FdtLib.inf @@ -0,0 +1,41 @@ +#/* @file +# Copyright (c) 2011-2014, ARM Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FdtLib + FILE_GUID = 6b2478c0-be23-11e0-a28c-0002a5d5c51b + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = FdtLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = ARM AARCH64 +# + +[Sources] + libfdt_internal.h + fdt_empty_tree.c + fdt_overlay.c + fdt_ro.c + fdt_rw.c + fdt_strerror.c + fdt_strtoul.c + fdt_sw.c + fdt_wip.c + fdt.c + fdt_addresses.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + BaseLib + DebugLib diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/Makefile.libfdt b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/Makefile.libfdt new file mode 100644 index 00000000..09c322ed --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/Makefile.libfdt @@ -0,0 +1,11 @@ +# Makefile.libfdt +# +# This is not a complete Makefile of itself. Instead, it is designed to +# be easily embeddable into other systems of Makefiles. +# +LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 +LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h +LIBFDT_VERSION = version.lds +LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \ + fdt_addresses.c +LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/TODO b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/TODO new file mode 100644 index 00000000..288437e3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/TODO @@ -0,0 +1,3 @@ +- Tree traversal functions +- Graft function +- Complete libfdt.h documenting comments diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt.c new file mode 100644 index 00000000..22286a1a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt.c @@ -0,0 +1,251 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +int fdt_check_header(const void *fdt) +{ + if (fdt_magic(fdt) == FDT_MAGIC) { + /* Complete tree */ + if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { + /* Unfinished sequential-write blob */ + if (fdt_size_dt_struct(fdt) == 0) + return -FDT_ERR_BADSTATE; + } else { + return -FDT_ERR_BADMAGIC; + } + + return 0; +} + +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) +{ + unsigned absoffset = offset + fdt_off_dt_struct(fdt); + + if ((absoffset < offset) + || ((absoffset + len) < absoffset) + || (absoffset + len) > fdt_totalsize(fdt)) + return NULL; + + if (fdt_version(fdt) >= 0x11) + if (((offset + len) < offset) + || ((offset + len) > fdt_size_dt_struct(fdt))) + return NULL; + + return _fdt_offset_ptr(fdt, offset); +} + +uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) +{ + const fdt32_t *tagp, *lenp; + uint32_t tag; + int offset = startoffset; + const char *p; + + *nextoffset = -FDT_ERR_TRUNCATED; + tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); + if (!tagp) + return FDT_END; /* premature end */ + tag = fdt32_to_cpu(*tagp); + offset += FDT_TAGSIZE; + + *nextoffset = -FDT_ERR_BADSTRUCTURE; + switch (tag) { + case FDT_BEGIN_NODE: + /* skip name */ + do { + p = fdt_offset_ptr(fdt, offset++, 1); + } while (p && (*p != '\0')); + if (!p) + return FDT_END; /* premature end */ + break; + + case FDT_PROP: + lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); + if (!lenp) + return FDT_END; /* premature end */ + /* skip-name offset, length and value */ + offset += sizeof(struct fdt_property) - FDT_TAGSIZE + + fdt32_to_cpu(*lenp); + break; + + case FDT_END: + case FDT_END_NODE: + case FDT_NOP: + break; + + default: + return FDT_END; + } + + if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) + return FDT_END; /* premature end */ + + *nextoffset = FDT_TAGALIGN(offset); + return tag; +} + +int _fdt_check_node_offset(const void *fdt, int offset) +{ + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int _fdt_check_prop_offset(const void *fdt, int offset) +{ + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int fdt_next_node(const void *fdt, int offset, int *depth) +{ + int nextoffset = 0; + uint32_t tag; + + if (offset >= 0) + if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) + return nextoffset; + + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_PROP: + case FDT_NOP: + break; + + case FDT_BEGIN_NODE: + if (depth) + (*depth)++; + break; + + case FDT_END_NODE: + if (depth && ((--(*depth)) < 0)) + return nextoffset; + break; + + case FDT_END: + if ((nextoffset >= 0) + || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) + return -FDT_ERR_NOTFOUND; + else + return nextoffset; + } + } while (tag != FDT_BEGIN_NODE); + + return offset; +} + +int fdt_first_subnode(const void *fdt, int offset) +{ + int depth = 0; + + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth != 1) + return -FDT_ERR_NOTFOUND; + + return offset; +} + +int fdt_next_subnode(const void *fdt, int offset) +{ + int depth = 1; + + /* + * With respect to the parent, the depth of the next subnode will be + * the same as the last. + */ + do { + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth < 1) + return -FDT_ERR_NOTFOUND; + } while (depth > 1); + + return offset; +} + +const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) +{ + int len = strlen(s) + 1; + const char *last = strtab + tabsize - len; + const char *p; + + for (p = strtab; p <= last; p++) + if (memcmp(p, s, len) == 0) + return p; + return NULL; +} + +int fdt_move(const void *fdt, void *buf, int bufsize) +{ + FDT_CHECK_HEADER(fdt); + + if (fdt_totalsize(fdt) > bufsize) + return -FDT_ERR_NOSPACE; + + memmove(buf, fdt, fdt_totalsize(fdt)); + return 0; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_addresses.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_addresses.c new file mode 100644 index 00000000..eff4dbcc --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_addresses.c @@ -0,0 +1,96 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2014 David Gibson + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +int fdt_address_cells(const void *fdt, int nodeoffset) +{ + const fdt32_t *ac; + int val; + int len; + + ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); + if (!ac) + return 2; + + if (len != sizeof(*ac)) + return -FDT_ERR_BADNCELLS; + + val = fdt32_to_cpu(*ac); + if ((val <= 0) || (val > FDT_MAX_NCELLS)) + return -FDT_ERR_BADNCELLS; + + return val; +} + +int fdt_size_cells(const void *fdt, int nodeoffset) +{ + const fdt32_t *sc; + int val; + int len; + + sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len); + if (!sc) + return 2; + + if (len != sizeof(*sc)) + return -FDT_ERR_BADNCELLS; + + val = fdt32_to_cpu(*sc); + if ((val < 0) || (val > FDT_MAX_NCELLS)) + return -FDT_ERR_BADNCELLS; + + return val; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_empty_tree.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_empty_tree.c new file mode 100644 index 00000000..f2ae9b77 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_empty_tree.c @@ -0,0 +1,83 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2012 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +int fdt_create_empty_tree(void *buf, int bufsize) +{ + int err; + + err = fdt_create(buf, bufsize); + if (err) + return err; + + err = fdt_finish_reservemap(buf); + if (err) + return err; + + err = fdt_begin_node(buf, ""); + if (err) + return err; + + err = fdt_end_node(buf); + if (err) + return err; + + err = fdt_finish(buf); + if (err) + return err; + + return fdt_open_into(buf, buf, bufsize); +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_overlay.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_overlay.c new file mode 100644 index 00000000..804852c6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_overlay.c @@ -0,0 +1,914 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2016 Free Electrons + * Copyright (C) 2016 NextThing Co. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +/** + * overlay_get_target_phandle - retrieves the target phandle of a fragment + * @fdto: pointer to the device tree overlay blob + * @fragment: node offset of the fragment in the overlay + * + * overlay_get_target_phandle() retrieves the target phandle of an + * overlay fragment when that fragment uses a phandle (target + * property) instead of a path (target-path property). + * + * returns: + * the phandle pointed by the target property + * 0, if the phandle was not found + * -1, if the phandle was malformed + */ +static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) +{ + const fdt32_t *val; + int len; + + val = fdt_getprop(fdto, fragment, "target", &len); + if (!val) + return 0; + + if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) + return (uint32_t)-1; + + return fdt32_to_cpu(*val); +} + +/** + * overlay_get_target - retrieves the offset of a fragment's target + * @fdt: Base device tree blob + * @fdto: Device tree overlay blob + * @fragment: node offset of the fragment in the overlay + * @pathp: pointer which receives the path of the target (or NULL) + * + * overlay_get_target() retrieves the target offset in the base + * device tree of a fragment, no matter how the actual targetting is + * done (through a phandle or a path) + * + * returns: + * the targetted node offset in the base device tree + * Negative error code on error + */ +static int overlay_get_target(const void *fdt, const void *fdto, + int fragment, char const **pathp) +{ + uint32_t phandle; + const char *path = NULL; + int path_len = 0, ret; + + /* Try first to do a phandle based lookup */ + phandle = overlay_get_target_phandle(fdto, fragment); + if (phandle == (uint32_t)-1) + return -FDT_ERR_BADPHANDLE; + + /* no phandle, try path */ + if (!phandle) { + /* And then a path based lookup */ + path = fdt_getprop(fdto, fragment, "target-path", &path_len); + if (path) + ret = fdt_path_offset(fdt, path); + else + ret = path_len; + } else + ret = fdt_node_offset_by_phandle(fdt, phandle); + + /* + * If we haven't found either a target or a + * target-path property in a node that contains a + * __overlay__ subnode (we wouldn't be called + * otherwise), consider it a improperly written + * overlay + */ + if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) + ret = -FDT_ERR_BADOVERLAY; + + /* return on error */ + if (ret < 0) + return ret; + + /* return pointer to path (if available) */ + if (pathp) + *pathp = path ? path : NULL; + + return ret; +} + +/** + * overlay_phandle_add_offset - Increases a phandle by an offset + * @fdt: Base device tree blob + * @node: Device tree overlay blob + * @name: Name of the property to modify (phandle or linux,phandle) + * @delta: offset to apply + * + * overlay_phandle_add_offset() increments a node phandle by a given + * offset. + * + * returns: + * 0 on success. + * Negative error code on error + */ +static int overlay_phandle_add_offset(void *fdt, int node, + const char *name, uint32_t delta) +{ + const fdt32_t *val; + uint32_t adj_val; + int len; + + val = fdt_getprop(fdt, node, name, &len); + if (!val) + return len; + + if (len != sizeof(*val)) + return -FDT_ERR_BADPHANDLE; + + adj_val = fdt32_to_cpu(*val); + if ((adj_val + delta) < adj_val) + return -FDT_ERR_NOPHANDLES; + + adj_val += delta; + if (adj_val == (uint32_t)-1) + return -FDT_ERR_NOPHANDLES; + + return fdt_setprop_inplace_u32(fdt, node, name, adj_val); +} + +/** + * overlay_adjust_node_phandles - Offsets the phandles of a node + * @fdto: Device tree overlay blob + * @node: Offset of the node we want to adjust + * @delta: Offset to shift the phandles of + * + * overlay_adjust_node_phandles() adds a constant to all the phandles + * of a given node. This is mainly use as part of the overlay + * application process, when we want to update all the overlay + * phandles to not conflict with the overlays of the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_adjust_node_phandles(void *fdto, int node, + uint32_t delta) +{ + int child; + int ret; + + ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); + if (ret && ret != -FDT_ERR_NOTFOUND) + return ret; + + ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); + if (ret && ret != -FDT_ERR_NOTFOUND) + return ret; + + fdt_for_each_subnode(child, fdto, node) { + ret = overlay_adjust_node_phandles(fdto, child, delta); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay + * @fdto: Device tree overlay blob + * @delta: Offset to shift the phandles of + * + * overlay_adjust_local_phandles() adds a constant to all the + * phandles of an overlay. This is mainly use as part of the overlay + * application process, when we want to update all the overlay + * phandles to not conflict with the overlays of the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) +{ + /* + * Start adjusting the phandles from the overlay root + */ + return overlay_adjust_node_phandles(fdto, 0, delta); +} + +/** + * overlay_update_local_node_references - Adjust the overlay references + * @fdto: Device tree overlay blob + * @tree_node: Node offset of the node to operate on + * @fixup_node: Node offset of the matching local fixups node + * @delta: Offset to shift the phandles of + * + * overlay_update_local_nodes_references() update the phandles + * pointing to a node within the device tree overlay by adding a + * constant delta. + * + * This is mainly used as part of a device tree application process, + * where you want the device tree overlays phandles to not conflict + * with the ones from the base device tree before merging them. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_update_local_node_references(void *fdto, + int tree_node, + int fixup_node, + uint32_t delta) +{ + int fixup_prop; + int fixup_child; + int ret; + + fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { + const fdt32_t *fixup_val; + const char *tree_val; + const char *name; + int fixup_len; + int tree_len; + int i; + + fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, + &name, &fixup_len); + if (!fixup_val) + return fixup_len; + + if (fixup_len % sizeof(uint32_t)) + return -FDT_ERR_BADOVERLAY; + + tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); + if (!tree_val) { + if (tree_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + + return tree_len; + } + + for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { + fdt32_t adj_val; + uint32_t poffset; + + poffset = fdt32_to_cpu(fixup_val[i]); + + /* + * phandles to fixup can be unaligned. + * + * Use a memcpy for the architectures that do + * not support unaligned accesses. + */ + memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); + + adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); + + ret = fdt_setprop_inplace_namelen_partial(fdto, + tree_node, + name, + strlen(name), + poffset, + &adj_val, + sizeof(adj_val)); + if (ret == -FDT_ERR_NOSPACE) + return -FDT_ERR_BADOVERLAY; + + if (ret) + return ret; + } + } + + fdt_for_each_subnode(fixup_child, fdto, fixup_node) { + const char *fixup_child_name = fdt_get_name(fdto, fixup_child, + NULL); + int tree_child; + + tree_child = fdt_subnode_offset(fdto, tree_node, + fixup_child_name); + if (tree_child == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + if (tree_child < 0) + return tree_child; + + ret = overlay_update_local_node_references(fdto, + tree_child, + fixup_child, + delta); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_update_local_references - Adjust the overlay references + * @fdto: Device tree overlay blob + * @delta: Offset to shift the phandles of + * + * overlay_update_local_references() update all the phandles pointing + * to a node within the device tree overlay by adding a constant + * delta to not conflict with the base overlay. + * + * This is mainly used as part of a device tree application process, + * where you want the device tree overlays phandles to not conflict + * with the ones from the base device tree before merging them. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_update_local_references(void *fdto, uint32_t delta) +{ + int fixups; + + fixups = fdt_path_offset(fdto, "/__local_fixups__"); + if (fixups < 0) { + /* There's no local phandles to adjust, bail out */ + if (fixups == -FDT_ERR_NOTFOUND) + return 0; + + return fixups; + } + + /* + * Update our local references from the root of the tree + */ + return overlay_update_local_node_references(fdto, 0, fixups, + delta); +} + +/** + * overlay_fixup_one_phandle - Set an overlay phandle to the base one + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * @symbols_off: Node offset of the symbols node in the base device tree + * @path: Path to a node holding a phandle in the overlay + * @path_len: number of path characters to consider + * @name: Name of the property holding the phandle reference in the overlay + * @name_len: number of name characters to consider + * @poffset: Offset within the overlay property where the phandle is stored + * @label: Label of the node referenced by the phandle + * + * overlay_fixup_one_phandle() resolves an overlay phandle pointing to + * a node in the base device tree. + * + * This is part of the device tree overlay application process, when + * you want all the phandles in the overlay to point to the actual + * base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_one_phandle(void *fdt, void *fdto, + int symbols_off, + const char *path, uint32_t path_len, + const char *name, uint32_t name_len, + int poffset, const char *label) +{ + const char *symbol_path; + uint32_t phandle; + fdt32_t phandle_prop; + int symbol_off, fixup_off; + int prop_len; + + if (symbols_off < 0) + return symbols_off; + + symbol_path = fdt_getprop(fdt, symbols_off, label, + &prop_len); + if (!symbol_path) + return prop_len; + + symbol_off = fdt_path_offset(fdt, symbol_path); + if (symbol_off < 0) + return symbol_off; + + phandle = fdt_get_phandle(fdt, symbol_off); + if (!phandle) + return -FDT_ERR_NOTFOUND; + + fixup_off = fdt_path_offset_namelen(fdto, path, path_len); + if (fixup_off == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + if (fixup_off < 0) + return fixup_off; + + phandle_prop = cpu_to_fdt32(phandle); + return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, + name, name_len, poffset, + &phandle_prop, + sizeof(phandle_prop)); +}; + +unsigned long strtoul(const char *nptr, char **endptr, int base); + +/** + * overlay_fixup_phandle - Set an overlay phandle to the base one + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * @symbols_off: Node offset of the symbols node in the base device tree + * @property: Property offset in the overlay holding the list of fixups + * + * overlay_fixup_phandle() resolves all the overlay phandles pointed + * to in a __fixups__ property, and updates them to match the phandles + * in use in the base device tree. + * + * This is part of the device tree overlay application process, when + * you want all the phandles in the overlay to point to the actual + * base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, + int property) +{ + const char *value; + const char *label; + int len; + + value = fdt_getprop_by_offset(fdto, property, + &label, &len); + if (!value) { + if (len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + + return len; + } + + do { + const char *path, *name, *fixup_end; + const char *fixup_str = value; + uint32_t path_len, name_len; + uint32_t fixup_len; + char *sep, *endptr; + int poffset, ret; + + fixup_end = memchr(value, '\0', len); + if (!fixup_end) + return -FDT_ERR_BADOVERLAY; + fixup_len = fixup_end - fixup_str; + + len -= fixup_len + 1; + value += fixup_len + 1; + + path = fixup_str; + sep = memchr(fixup_str, ':', fixup_len); + if (!sep || *sep != ':') + return -FDT_ERR_BADOVERLAY; + + path_len = sep - path; + if (path_len == (fixup_len - 1)) + return -FDT_ERR_BADOVERLAY; + + fixup_len -= path_len + 1; + name = sep + 1; + sep = memchr(name, ':', fixup_len); + if (!sep || *sep != ':') + return -FDT_ERR_BADOVERLAY; + + name_len = sep - name; + if (!name_len) + return -FDT_ERR_BADOVERLAY; + + poffset = strtoul(sep + 1, &endptr, 10); + if ((*endptr != '\0') || (endptr <= (sep + 1))) + return -FDT_ERR_BADOVERLAY; + + ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, + path, path_len, name, name_len, + poffset, label); + if (ret) + return ret; + } while (len > 0); + + return 0; +} + +/** + * overlay_fixup_phandles - Resolve the overlay phandles to the base + * device tree + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_fixup_phandles() resolves all the overlay phandles pointing + * to nodes in the base device tree. + * + * This is one of the steps of the device tree overlay application + * process, when you want all the phandles in the overlay to point to + * the actual base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_phandles(void *fdt, void *fdto) +{ + int fixups_off, symbols_off; + int property; + + /* We can have overlays without any fixups */ + fixups_off = fdt_path_offset(fdto, "/__fixups__"); + if (fixups_off == -FDT_ERR_NOTFOUND) + return 0; /* nothing to do */ + if (fixups_off < 0) + return fixups_off; + + /* And base DTs without symbols */ + symbols_off = fdt_path_offset(fdt, "/__symbols__"); + if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) + return symbols_off; + + fdt_for_each_property_offset(property, fdto, fixups_off) { + int ret; + + ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_apply_node - Merges a node into the base device tree + * @fdt: Base Device Tree blob + * @target: Node offset in the base device tree to apply the fragment to + * @fdto: Device tree overlay blob + * @node: Node offset in the overlay holding the changes to merge + * + * overlay_apply_node() merges a node into a target base device tree + * node pointed. + * + * This is part of the final step in the device tree overlay + * application process, when all the phandles have been adjusted and + * resolved and you just have to merge overlay into the base device + * tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_apply_node(void *fdt, int target, + void *fdto, int node) +{ + int property; + int subnode; + + fdt_for_each_property_offset(property, fdto, node) { + const char *name; + const void *prop; + int prop_len; + int ret; + + prop = fdt_getprop_by_offset(fdto, property, &name, + &prop_len); + if (prop_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + if (prop_len < 0) + return prop_len; + + ret = fdt_setprop(fdt, target, name, prop, prop_len); + if (ret) + return ret; + } + + fdt_for_each_subnode(subnode, fdto, node) { + const char *name = fdt_get_name(fdto, subnode, NULL); + int nnode; + int ret; + + nnode = fdt_add_subnode(fdt, target, name); + if (nnode == -FDT_ERR_EXISTS) { + nnode = fdt_subnode_offset(fdt, target, name); + if (nnode == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + } + + if (nnode < 0) + return nnode; + + ret = overlay_apply_node(fdt, nnode, fdto, subnode); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_merge - Merge an overlay into its base device tree + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_merge() merges an overlay into its base device tree. + * + * This is the next to last step in the device tree overlay application + * process, when all the phandles have been adjusted and resolved and + * you just have to merge overlay into the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_merge(void *fdt, void *fdto) +{ + int fragment; + + fdt_for_each_subnode(fragment, fdto, 0) { + int overlay; + int target; + int ret; + + /* + * Each fragments will have an __overlay__ node. If + * they don't, it's not supposed to be merged + */ + overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); + if (overlay == -FDT_ERR_NOTFOUND) + continue; + + if (overlay < 0) + return overlay; + + target = overlay_get_target(fdt, fdto, fragment, NULL); + if (target < 0) + return target; + + ret = overlay_apply_node(fdt, target, fdto, overlay); + if (ret) + return ret; + } + + return 0; +} + +static int get_path_len(const void *fdt, int nodeoffset) +{ + int len = 0, namelen; + const char *name; + + FDT_CHECK_HEADER(fdt); + + for (;;) { + name = fdt_get_name(fdt, nodeoffset, &namelen); + if (!name) + return namelen; + + /* root? we're done */ + if (namelen == 0) + break; + + nodeoffset = fdt_parent_offset(fdt, nodeoffset); + if (nodeoffset < 0) + return nodeoffset; + len += namelen + 1; + } + + /* in case of root pretend it's "/" */ + if (len == 0) + len++; + return len; +} + +/** + * overlay_symbol_update - Update the symbols of base tree after a merge + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_symbol_update() updates the symbols of the base tree with the + * symbols of the applied overlay + * + * This is the last step in the device tree overlay application + * process, allowing the reference of overlay symbols by subsequent + * overlay operations. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_symbol_update(void *fdt, void *fdto) +{ + int root_sym, ov_sym, prop, path_len, fragment, target; + int len, frag_name_len, ret, rel_path_len; + const char *s, *e; + const char *path; + const char *name; + const char *frag_name; + const char *rel_path; + const char *target_path; + char *buf; + void *p; + + ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); + + /* if no overlay symbols exist no problem */ + if (ov_sym < 0) + return 0; + + root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); + + /* it no root symbols exist we should create them */ + if (root_sym == -FDT_ERR_NOTFOUND) + root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); + + /* any error is fatal now */ + if (root_sym < 0) + return root_sym; + + /* iterate over each overlay symbol */ + fdt_for_each_property_offset(prop, fdto, ov_sym) { + path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); + if (!path) + return path_len; + + /* verify it's a string property (terminated by a single \0) */ + if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) + return -FDT_ERR_BADVALUE; + + /* keep end marker to avoid strlen() */ + e = path + path_len; + + /* format: //__overlay__/ */ + + if (*path != '/') + return -FDT_ERR_BADVALUE; + + /* get fragment name first */ + s = strchr(path + 1, '/'); + if (!s) + return -FDT_ERR_BADOVERLAY; + + frag_name = path + 1; + frag_name_len = s - path - 1; + + /* verify format; safe since "s" lies in \0 terminated prop */ + len = sizeof("/__overlay__/") - 1; + if ((e - s) < len || memcmp(s, "/__overlay__/", len)) + return -FDT_ERR_BADOVERLAY; + + rel_path = s + len; + rel_path_len = e - rel_path; + + /* find the fragment index in which the symbol lies */ + ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, + frag_name_len); + /* not found? */ + if (ret < 0) + return -FDT_ERR_BADOVERLAY; + fragment = ret; + + /* an __overlay__ subnode must exist */ + ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); + if (ret < 0) + return -FDT_ERR_BADOVERLAY; + + /* get the target of the fragment */ + ret = overlay_get_target(fdt, fdto, fragment, &target_path); + if (ret < 0) + return ret; + target = ret; + + /* if we have a target path use */ + if (!target_path) { + ret = get_path_len(fdt, target); + if (ret < 0) + return ret; + len = ret; + } else { + len = strlen(target_path); + } + + ret = fdt_setprop_placeholder(fdt, root_sym, name, + len + (len > 1) + rel_path_len + 1, &p); + if (ret < 0) + return ret; + + if (!target_path) { + /* again in case setprop_placeholder changed it */ + ret = overlay_get_target(fdt, fdto, fragment, &target_path); + if (ret < 0) + return ret; + target = ret; + } + + buf = p; + if (len > 1) { /* target is not root */ + if (!target_path) { + ret = fdt_get_path(fdt, target, buf, len + 1); + if (ret < 0) + return ret; + } else + memcpy(buf, target_path, len + 1); + + } else + len--; + + buf[len] = '/'; + memcpy(buf + len + 1, rel_path, rel_path_len); + buf[len + 1 + rel_path_len] = '\0'; + } + + return 0; +} + +int fdt_overlay_apply(void *fdt, void *fdto) +{ + uint32_t delta = fdt_get_max_phandle(fdt); + int ret; + + FDT_CHECK_HEADER(fdt); + FDT_CHECK_HEADER(fdto); + + ret = overlay_adjust_local_phandles(fdto, delta); + if (ret) + goto err; + + ret = overlay_update_local_references(fdto, delta); + if (ret) + goto err; + + ret = overlay_fixup_phandles(fdt, fdto); + if (ret) + goto err; + + ret = overlay_merge(fdt, fdto); + if (ret) + goto err; + + ret = overlay_symbol_update(fdt, fdto); + if (ret) + goto err; + + /* + * The overlay has been damaged, erase its magic. + */ + fdt_set_magic(fdto, ~0); + + return 0; + +err: + /* + * The overlay might have been damaged, erase its magic. + */ + fdt_set_magic(fdto, ~0); + + /* + * The base device tree might have been damaged, erase its + * magic. + */ + fdt_set_magic(fdt, ~0); + + return ret; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_ro.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_ro.c new file mode 100644 index 00000000..08de2cce --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_ro.c @@ -0,0 +1,703 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int _fdt_nodename_eq(const void *fdt, int offset, + const char *s, int len) +{ + const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); + + if (!p) + /* short match */ + return 0; + + if (memcmp(p, s, len) != 0) + return 0; + + if (p[len] == '\0') + return 1; + else if (!memchr(s, '@', len) && (p[len] == '@')) + return 1; + else + return 0; +} + +const char *fdt_string(const void *fdt, int stroffset) +{ + return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; +} + +static int _fdt_string_eq(const void *fdt, int stroffset, + const char *s, int len) +{ + const char *p = fdt_string(fdt, stroffset); + + return (strlen(p) == len) && (memcmp(p, s, len) == 0); +} + +uint32_t fdt_get_max_phandle(const void *fdt) +{ + uint32_t max_phandle = 0; + int offset; + + for (offset = fdt_next_node(fdt, -1, NULL);; + offset = fdt_next_node(fdt, offset, NULL)) { + uint32_t phandle; + + if (offset == -FDT_ERR_NOTFOUND) + return max_phandle; + + if (offset < 0) + return (uint32_t)-1; + + phandle = fdt_get_phandle(fdt, offset); + if (phandle == (uint32_t)-1) + continue; + + if (phandle > max_phandle) + max_phandle = phandle; + } + + return 0; +} + +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) +{ + FDT_CHECK_HEADER(fdt); + *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); + *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); + return 0; +} + +int fdt_num_mem_rsv(const void *fdt) +{ + int i = 0; + + while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) + i++; + return i; +} + +static int _nextprop(const void *fdt, int offset) +{ + uint32_t tag; + int nextoffset; + + do { + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_END: + if (nextoffset >= 0) + return -FDT_ERR_BADSTRUCTURE; + else + return nextoffset; + + case FDT_PROP: + return offset; + } + offset = nextoffset; + } while (tag == FDT_NOP); + + return -FDT_ERR_NOTFOUND; +} + +int fdt_subnode_offset_namelen(const void *fdt, int offset, + const char *name, int namelen) +{ + int depth; + + FDT_CHECK_HEADER(fdt); + + for (depth = 0; + (offset >= 0) && (depth >= 0); + offset = fdt_next_node(fdt, offset, &depth)) + if ((depth == 1) + && _fdt_nodename_eq(fdt, offset, name, namelen)) + return offset; + + if (depth < 0) + return -FDT_ERR_NOTFOUND; + return offset; /* error */ +} + +int fdt_subnode_offset(const void *fdt, int parentoffset, + const char *name) +{ + return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) +{ + const char *end = path + namelen; + const char *p = path; + int offset = 0; + + FDT_CHECK_HEADER(fdt); + + /* see if we have an alias */ + if (*path != '/') { + const char *q = memchr(path, '/', end - p); + + if (!q) + q = end; + + p = fdt_get_alias_namelen(fdt, p, q - p); + if (!p) + return -FDT_ERR_BADPATH; + offset = fdt_path_offset(fdt, p); + + p = q; + } + + while (p < end) { + const char *q; + + while (*p == '/') { + p++; + if (p == end) + return offset; + } + q = memchr(p, '/', end - p); + if (! q) + q = end; + + offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); + if (offset < 0) + return offset; + + p = q; + } + + return offset; +} + +int fdt_path_offset(const void *fdt, const char *path) +{ + return fdt_path_offset_namelen(fdt, path, strlen(path)); +} + +const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) +{ + const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); + int err; + + if (((err = fdt_check_header(fdt)) != 0) + || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) + goto fail; + + if (len) + *len = strlen(nh->name); + + return nh->name; + + fail: + if (len) + *len = err; + return NULL; +} + +int fdt_first_property_offset(const void *fdt, int nodeoffset) +{ + int offset; + + if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) + return offset; + + return _nextprop(fdt, offset); +} + +int fdt_next_property_offset(const void *fdt, int offset) +{ + if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) + return offset; + + return _nextprop(fdt, offset); +} + +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp) +{ + int err; + const struct fdt_property *prop; + + if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { + if (lenp) + *lenp = err; + return NULL; + } + + prop = _fdt_offset_ptr(fdt, offset); + + if (lenp) + *lenp = fdt32_to_cpu(prop->len); + + return prop; +} + +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int offset, + const char *name, + int namelen, int *lenp) +{ + for (offset = fdt_first_property_offset(fdt, offset); + (offset >= 0); + (offset = fdt_next_property_offset(fdt, offset))) { + const struct fdt_property *prop; + + if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { + offset = -FDT_ERR_INTERNAL; + break; + } + if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), + name, namelen)) + return prop; + } + + if (lenp) + *lenp = offset; + return NULL; +} + +const struct fdt_property *fdt_get_property(const void *fdt, + int nodeoffset, + const char *name, int *lenp) +{ + return fdt_get_property_namelen(fdt, nodeoffset, name, + strlen(name), lenp); +} + +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); + if (!prop) + return NULL; + + return prop->data; +} + +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset(fdt, offset, lenp); + if (!prop) + return NULL; + if (namep) + *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); + return prop->data; +} + +const void *fdt_getprop(const void *fdt, int nodeoffset, + const char *name, int *lenp) +{ + return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); +} + +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) +{ + const fdt32_t *php; + int len; + + /* FIXME: This is a bit sub-optimal, since we potentially scan + * over all the properties twice. */ + php = fdt_getprop(fdt, nodeoffset, "phandle", &len); + if (!php || (len != sizeof(*php))) { + php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); + if (!php || (len != sizeof(*php))) + return 0; + } + + return fdt32_to_cpu(*php); +} + +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen) +{ + int aliasoffset; + + aliasoffset = fdt_path_offset(fdt, "/aliases"); + if (aliasoffset < 0) + return NULL; + + return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); +} + +const char *fdt_get_alias(const void *fdt, const char *name) +{ + return fdt_get_alias_namelen(fdt, name, strlen(name)); +} + +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) +{ + int pdepth = 0, p = 0; + int offset, depth, namelen; + const char *name; + + FDT_CHECK_HEADER(fdt); + + if (buflen < 2) + return -FDT_ERR_NOSPACE; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + while (pdepth > depth) { + do { + p--; + } while (buf[p-1] != '/'); + pdepth--; + } + + if (pdepth >= depth) { + name = fdt_get_name(fdt, offset, &namelen); + if (!name) + return namelen; + if ((p + namelen + 1) <= buflen) { + memcpy(buf + p, name, namelen); + p += namelen; + buf[p++] = '/'; + pdepth++; + } + } + + if (offset == nodeoffset) { + if (pdepth < (depth + 1)) + return -FDT_ERR_NOSPACE; + + if (p > 1) /* special case so that root path is "/", not "" */ + p--; + buf[p] = '\0'; + return 0; + } + } + + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + + return offset; /* error from fdt_next_node() */ +} + +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, + int supernodedepth, int *nodedepth) +{ + int offset, depth; + int supernodeoffset = -FDT_ERR_INTERNAL; + + FDT_CHECK_HEADER(fdt); + + if (supernodedepth < 0) + return -FDT_ERR_NOTFOUND; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + if (depth == supernodedepth) + supernodeoffset = offset; + + if (offset == nodeoffset) { + if (nodedepth) + *nodedepth = depth; + + if (supernodedepth > depth) + return -FDT_ERR_NOTFOUND; + else + return supernodeoffset; + } + } + + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + + return offset; /* error from fdt_next_node() */ +} + +int fdt_node_depth(const void *fdt, int nodeoffset) +{ + int nodedepth; + int err; + + err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); + if (err) + return (err < 0) ? err : -FDT_ERR_INTERNAL; + return nodedepth; +} + +int fdt_parent_offset(const void *fdt, int nodeoffset) +{ + int nodedepth = fdt_node_depth(fdt, nodeoffset); + + if (nodedepth < 0) + return nodedepth; + return fdt_supernode_atdepth_offset(fdt, nodeoffset, + nodedepth - 1, NULL); +} + +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, + const char *propname, + const void *propval, int proplen) +{ + int offset; + const void *val; + int len; + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_getprop(), then if that didn't + * find what we want, we scan over them again making our way + * to the next node. Still it's the easiest to implement + * approach; performance can come later. */ + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + val = fdt_getprop(fdt, offset, propname, &len); + if (val && (len == proplen) + && (memcmp(val, propval, len) == 0)) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} + +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) +{ + int offset; + + if ((phandle == 0) || (phandle == -1)) + return -FDT_ERR_BADPHANDLE; + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we + * potentially scan each property of a node in + * fdt_get_phandle(), then if that didn't find what + * we want, we scan over them again making our way to the next + * node. Still it's the easiest to implement approach; + * performance can come later. */ + for (offset = fdt_next_node(fdt, -1, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + if (fdt_get_phandle(fdt, offset) == phandle) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} + +int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) +{ + int len = strlen(str); + const char *p; + + while (listlen >= len) { + if (memcmp(str, strlist, len+1) == 0) + return 1; + p = memchr(strlist, '\0', listlen); + if (!p) + return 0; /* malformed strlist.. */ + listlen -= (p-strlist) + 1; + strlist = p + 1; + } + return 0; +} + +int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) +{ + const char *list, *end; + int length, count = 0; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return length; + + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; + + list += length; + count++; + } + + return count; +} + +int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, + const char *string) +{ + int length, len, idx = 0; + const char *list, *end; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return length; + + len = strlen(string) + 1; + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; + + if (length == len && memcmp(list, string, length) == 0) + return idx; + + list += length; + idx++; + } + + return -FDT_ERR_NOTFOUND; +} + +const char *fdt_stringlist_get(const void *fdt, int nodeoffset, + const char *property, int idx, + int *lenp) +{ + const char *list, *end; + int length; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) { + if (lenp) + *lenp = length; + + return NULL; + } + + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) { + if (lenp) + *lenp = -FDT_ERR_BADVALUE; + + return NULL; + } + + if (idx == 0) { + if (lenp) + *lenp = length - 1; + + return list; + } + + list += length; + idx--; + } + + if (lenp) + *lenp = -FDT_ERR_NOTFOUND; + + return NULL; +} + +int fdt_node_check_compatible(const void *fdt, int nodeoffset, + const char *compatible) +{ + const void *prop; + int len; + + prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); + if (!prop) + return len; + + return !fdt_stringlist_contains(prop, len, compatible); +} + +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, + const char *compatible) +{ + int offset, err; + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_node_check_compatible(), then if + * that didn't find what we want, we scan over them again + * making our way to the next node. Still it's the easiest to + * implement approach; performance can come later. */ + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + err = fdt_node_check_compatible(fdt, offset, compatible); + if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) + return err; + else if (err == 0) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_rw.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_rw.c new file mode 100644 index 00000000..5c3a2bb0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_rw.c @@ -0,0 +1,505 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int _fdt_blocks_misordered(const void *fdt, + int mem_rsv_size, int struct_size) +{ + return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) + || (fdt_off_dt_struct(fdt) < + (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) + || (fdt_off_dt_strings(fdt) < + (fdt_off_dt_struct(fdt) + struct_size)) + || (fdt_totalsize(fdt) < + (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); +} + +static int _fdt_rw_check_header(void *fdt) +{ + FDT_CHECK_HEADER(fdt); + + if (fdt_version(fdt) < 17) + return -FDT_ERR_BADVERSION; + if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), + fdt_size_dt_struct(fdt))) + return -FDT_ERR_BADLAYOUT; + if (fdt_version(fdt) > 17) + fdt_set_version(fdt, 17); + + return 0; +} + +#define FDT_RW_CHECK_HEADER(fdt) \ + { \ + int __err; \ + if ((__err = _fdt_rw_check_header(fdt)) != 0) \ + return __err; \ + } + +static inline int _fdt_data_size(void *fdt) +{ + return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); +} + +static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) +{ + char *p = splicepoint; + char *end = (char *)fdt + _fdt_data_size(fdt); + + if (((p + oldlen) < p) || ((p + oldlen) > end)) + return -FDT_ERR_BADOFFSET; + if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) + return -FDT_ERR_BADOFFSET; + if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) + return -FDT_ERR_NOSPACE; + memmove(p + newlen, p + oldlen, end - p - oldlen); + return 0; +} + +static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, + int oldn, int newn) +{ + int delta = (newn - oldn) * sizeof(*p); + int err; + err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); + if (err) + return err; + fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); + fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); + return 0; +} + +static int _fdt_splice_struct(void *fdt, void *p, + int oldlen, int newlen) +{ + int delta = newlen - oldlen; + int err; + + if ((err = _fdt_splice(fdt, p, oldlen, newlen))) + return err; + + fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); + fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); + return 0; +} + +static int _fdt_splice_string(void *fdt, int newlen) +{ + void *p = (char *)fdt + + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); + int err; + + if ((err = _fdt_splice(fdt, p, 0, newlen))) + return err; + + fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); + return 0; +} + +static int _fdt_find_add_string(void *fdt, const char *s) +{ + char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); + const char *p; + char *new; + int len = strlen(s) + 1; + int err; + + p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); + if (p) + /* found it */ + return (p - strtab); + + new = strtab + fdt_size_dt_strings(fdt); + err = _fdt_splice_string(fdt, len); + if (err) + return err; + + memcpy(new, s, len); + return (new - strtab); +} + +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) +{ + struct fdt_reserve_entry *re; + int err; + + FDT_RW_CHECK_HEADER(fdt); + + re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); + err = _fdt_splice_mem_rsv(fdt, re, 0, 1); + if (err) + return err; + + re->address = cpu_to_fdt64(address); + re->size = cpu_to_fdt64(size); + return 0; +} + +int fdt_del_mem_rsv(void *fdt, int n) +{ + struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); + + FDT_RW_CHECK_HEADER(fdt); + + if (n >= fdt_num_mem_rsv(fdt)) + return -FDT_ERR_NOTFOUND; + + return _fdt_splice_mem_rsv(fdt, re, 1, 0); +} + +static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) +{ + int oldlen; + int err; + + *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (!*prop) + return oldlen; + + if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(len)))) + return err; + + (*prop)->len = cpu_to_fdt32(len); + return 0; +} + +static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) +{ + int proplen; + int nextoffset; + int namestroff; + int err; + + if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) + return nextoffset; + + namestroff = _fdt_find_add_string(fdt, name); + if (namestroff < 0) + return namestroff; + + *prop = _fdt_offset_ptr_w(fdt, nextoffset); + proplen = sizeof(**prop) + FDT_TAGALIGN(len); + + err = _fdt_splice_struct(fdt, *prop, 0, proplen); + if (err) + return err; + + (*prop)->tag = cpu_to_fdt32(FDT_PROP); + (*prop)->nameoff = cpu_to_fdt32(namestroff); + (*prop)->len = cpu_to_fdt32(len); + return 0; +} + +int fdt_set_name(void *fdt, int nodeoffset, const char *name) +{ + char *namep; + int oldlen, newlen; + int err; + + FDT_RW_CHECK_HEADER(fdt); + + namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); + if (!namep) + return oldlen; + + newlen = strlen(name); + + err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), + FDT_TAGALIGN(newlen+1)); + if (err) + return err; + + memcpy(namep, name, newlen+1); + return 0; +} + +int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, + int len, void **prop_data) +{ + struct fdt_property *prop; + int err; + + FDT_RW_CHECK_HEADER(fdt); + + err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); + if (err == -FDT_ERR_NOTFOUND) + err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + + *prop_data = prop->data; + return 0; +} + +int fdt_setprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + void *prop_data; + int err; + + err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data); + if (err) + return err; + + if (len) + memcpy(prop_data, val, len); + return 0; +} + +int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + struct fdt_property *prop; + int err, oldlen, newlen; + + FDT_RW_CHECK_HEADER(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (prop) { + newlen = len + oldlen; + err = _fdt_splice_struct(fdt, prop->data, + FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(newlen)); + if (err) + return err; + prop->len = cpu_to_fdt32(newlen); + memcpy(prop->data + oldlen, val, len); + } else { + err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + memcpy(prop->data, val, len); + } + return 0; +} + +int fdt_delprop(void *fdt, int nodeoffset, const char *name) +{ + struct fdt_property *prop; + int len, proplen; + + FDT_RW_CHECK_HEADER(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); + if (!prop) + return len; + + proplen = sizeof(*prop) + FDT_TAGALIGN(len); + return _fdt_splice_struct(fdt, prop, proplen, 0); +} + +int fdt_add_subnode_namelen(void *fdt, int parentoffset, + const char *name, int namelen) +{ + struct fdt_node_header *nh; + int offset, nextoffset; + int nodelen; + int err; + uint32_t tag; + fdt32_t *endtag; + + FDT_RW_CHECK_HEADER(fdt); + + offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); + if (offset >= 0) + return -FDT_ERR_EXISTS; + else if (offset != -FDT_ERR_NOTFOUND) + return offset; + + /* Try to place the new node after the parent's properties */ + fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + } while ((tag == FDT_PROP) || (tag == FDT_NOP)); + + nh = _fdt_offset_ptr_w(fdt, offset); + nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; + + err = _fdt_splice_struct(fdt, nh, 0, nodelen); + if (err) + return err; + + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); + memcpy(nh->name, name, namelen); + endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); + *endtag = cpu_to_fdt32(FDT_END_NODE); + + return offset; +} + +int fdt_add_subnode(void *fdt, int parentoffset, const char *name) +{ + return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_del_node(void *fdt, int nodeoffset) +{ + int endoffset; + + FDT_RW_CHECK_HEADER(fdt); + + endoffset = _fdt_node_end_offset(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + + return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), + endoffset - nodeoffset, 0); +} + +static void _fdt_packblocks(const char *old, char *new, + int mem_rsv_size, int struct_size) +{ + int mem_rsv_off, struct_off, strings_off; + + mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); + struct_off = mem_rsv_off + mem_rsv_size; + strings_off = struct_off + struct_size; + + memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); + fdt_set_off_mem_rsvmap(new, mem_rsv_off); + + memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); + fdt_set_off_dt_struct(new, struct_off); + fdt_set_size_dt_struct(new, struct_size); + + memmove(new + strings_off, old + fdt_off_dt_strings(old), + fdt_size_dt_strings(old)); + fdt_set_off_dt_strings(new, strings_off); + fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); +} + +int fdt_open_into(const void *fdt, void *buf, int bufsize) +{ + int err; + int mem_rsv_size, struct_size; + int newsize; + const char *fdtstart = fdt; + const char *fdtend = fdtstart + fdt_totalsize(fdt); + char *tmp; + + FDT_CHECK_HEADER(fdt); + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + + if (fdt_version(fdt) >= 17) { + struct_size = fdt_size_dt_struct(fdt); + } else { + struct_size = 0; + while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) + ; + if (struct_size < 0) + return struct_size; + } + + if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { + /* no further work necessary */ + err = fdt_move(fdt, buf, bufsize); + if (err) + return err; + fdt_set_version(buf, 17); + fdt_set_size_dt_struct(buf, struct_size); + fdt_set_totalsize(buf, bufsize); + return 0; + } + + /* Need to reorder */ + newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size + + struct_size + fdt_size_dt_strings(fdt); + + if (bufsize < newsize) + return -FDT_ERR_NOSPACE; + + /* First attempt to build converted tree at beginning of buffer */ + tmp = buf; + /* But if that overlaps with the old tree... */ + if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { + /* Try right after the old tree instead */ + tmp = (char *)(uintptr_t)fdtend; + if ((tmp + newsize) > ((char *)buf + bufsize)) + return -FDT_ERR_NOSPACE; + } + + _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); + memmove(buf, tmp, newsize); + + fdt_set_magic(buf, FDT_MAGIC); + fdt_set_totalsize(buf, bufsize); + fdt_set_version(buf, 17); + fdt_set_last_comp_version(buf, 16); + fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); + + return 0; +} + +int fdt_pack(void *fdt) +{ + int mem_rsv_size; + + FDT_RW_CHECK_HEADER(fdt); + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); + fdt_set_totalsize(fdt, _fdt_data_size(fdt)); + + return 0; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strerror.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strerror.c new file mode 100644 index 00000000..9677a188 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strerror.c @@ -0,0 +1,102 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +struct fdt_errtabent { + const char *str; +}; + +#define FDT_ERRTABENT(val) \ + [(val)] = { .str = #val, } + +static struct fdt_errtabent fdt_errtable[] = { + FDT_ERRTABENT(FDT_ERR_NOTFOUND), + FDT_ERRTABENT(FDT_ERR_EXISTS), + FDT_ERRTABENT(FDT_ERR_NOSPACE), + + FDT_ERRTABENT(FDT_ERR_BADOFFSET), + FDT_ERRTABENT(FDT_ERR_BADPATH), + FDT_ERRTABENT(FDT_ERR_BADPHANDLE), + FDT_ERRTABENT(FDT_ERR_BADSTATE), + + FDT_ERRTABENT(FDT_ERR_TRUNCATED), + FDT_ERRTABENT(FDT_ERR_BADMAGIC), + FDT_ERRTABENT(FDT_ERR_BADVERSION), + FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), + FDT_ERRTABENT(FDT_ERR_BADLAYOUT), + FDT_ERRTABENT(FDT_ERR_INTERNAL), + FDT_ERRTABENT(FDT_ERR_BADNCELLS), + FDT_ERRTABENT(FDT_ERR_BADVALUE), + FDT_ERRTABENT(FDT_ERR_BADOVERLAY), + FDT_ERRTABENT(FDT_ERR_NOPHANDLES), +}; +#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) + +const char *fdt_strerror(int errval) +{ + if (errval > 0) + return ""; + else if (errval == 0) + return ""; + else if (errval > -FDT_ERRTABSIZE) { + const char *s = fdt_errtable[-errval].str; + + if (s) + return s; + } + + return ""; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strtoul.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strtoul.c new file mode 100644 index 00000000..013ea58a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strtoul.c @@ -0,0 +1,32 @@ +#/* @file +# Copyright (c) 2018, Linaro Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#*/ + +#include +#include +#include + +unsigned long strtoul(const char *nptr, char **endptr, int base) +{ + RETURN_STATUS Status; + UINTN ReturnValue; + + ASSERT (base == 10 || base == 16); + + if (base == 10) { + Status = AsciiStrDecimalToUintnS (nptr, endptr, &ReturnValue); + } else if (base == 16) { + Status = AsciiStrHexToUintnS (nptr, endptr, &ReturnValue); + } else { + Status = RETURN_INVALID_PARAMETER; + } + + if (RETURN_ERROR (Status)) { + return MAX_UINTN; + } + + return ReturnValue; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_sw.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_sw.c new file mode 100644 index 00000000..2bd15e7a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_sw.c @@ -0,0 +1,300 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +static int _fdt_sw_check_header(void *fdt) +{ + if (fdt_magic(fdt) != FDT_SW_MAGIC) + return -FDT_ERR_BADMAGIC; + /* FIXME: should check more details about the header state */ + return 0; +} + +#define FDT_SW_CHECK_HEADER(fdt) \ + { \ + int err; \ + if ((err = _fdt_sw_check_header(fdt)) != 0) \ + return err; \ + } + +static void *_fdt_grab_space(void *fdt, size_t len) +{ + int offset = fdt_size_dt_struct(fdt); + int spaceleft; + + spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) + - fdt_size_dt_strings(fdt); + + if ((offset + len < offset) || (offset + len > spaceleft)) + return NULL; + + fdt_set_size_dt_struct(fdt, offset + len); + return _fdt_offset_ptr_w(fdt, offset); +} + +int fdt_create(void *buf, int bufsize) +{ + void *fdt = buf; + + if (bufsize < sizeof(struct fdt_header)) + return -FDT_ERR_NOSPACE; + + memset(buf, 0, bufsize); + + fdt_set_magic(fdt, FDT_SW_MAGIC); + fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); + fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); + fdt_set_totalsize(fdt, bufsize); + + fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), + sizeof(struct fdt_reserve_entry))); + fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); + fdt_set_off_dt_strings(fdt, bufsize); + + return 0; +} + +int fdt_resize(void *fdt, void *buf, int bufsize) +{ + size_t headsize, tailsize; + char *oldtail, *newtail; + + FDT_SW_CHECK_HEADER(fdt); + + headsize = fdt_off_dt_struct(fdt); + tailsize = fdt_size_dt_strings(fdt); + + if ((headsize + tailsize) > bufsize) + return -FDT_ERR_NOSPACE; + + oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; + newtail = (char *)buf + bufsize - tailsize; + + /* Two cases to avoid clobbering data if the old and new + * buffers partially overlap */ + if (buf <= fdt) { + memmove(buf, fdt, headsize); + memmove(newtail, oldtail, tailsize); + } else { + memmove(newtail, oldtail, tailsize); + memmove(buf, fdt, headsize); + } + + fdt_set_off_dt_strings(buf, bufsize); + fdt_set_totalsize(buf, bufsize); + + return 0; +} + +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) +{ + struct fdt_reserve_entry *re; + int offset; + + FDT_SW_CHECK_HEADER(fdt); + + if (fdt_size_dt_struct(fdt)) + return -FDT_ERR_BADSTATE; + + offset = fdt_off_dt_struct(fdt); + if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) + return -FDT_ERR_NOSPACE; + + re = (struct fdt_reserve_entry *)((char *)fdt + offset); + re->address = cpu_to_fdt64(addr); + re->size = cpu_to_fdt64(size); + + fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); + + return 0; +} + +int fdt_finish_reservemap(void *fdt) +{ + return fdt_add_reservemap_entry(fdt, 0, 0); +} + +int fdt_begin_node(void *fdt, const char *name) +{ + struct fdt_node_header *nh; + int namelen = strlen(name) + 1; + + FDT_SW_CHECK_HEADER(fdt); + + nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); + if (! nh) + return -FDT_ERR_NOSPACE; + + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + memcpy(nh->name, name, namelen); + return 0; +} + +int fdt_end_node(void *fdt) +{ + fdt32_t *en; + + FDT_SW_CHECK_HEADER(fdt); + + en = _fdt_grab_space(fdt, FDT_TAGSIZE); + if (! en) + return -FDT_ERR_NOSPACE; + + *en = cpu_to_fdt32(FDT_END_NODE); + return 0; +} + +static int _fdt_find_add_string(void *fdt, const char *s) +{ + char *strtab = (char *)fdt + fdt_totalsize(fdt); + const char *p; + int strtabsize = fdt_size_dt_strings(fdt); + int len = strlen(s) + 1; + int struct_top, offset; + + p = _fdt_find_string(strtab - strtabsize, strtabsize, s); + if (p) + return p - strtab; + + /* Add it */ + offset = -strtabsize - len; + struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + if (fdt_totalsize(fdt) + offset < struct_top) + return 0; /* no more room :( */ + + memcpy(strtab + offset, s, len); + fdt_set_size_dt_strings(fdt, strtabsize + len); + return offset; +} + +int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) +{ + struct fdt_property *prop; + int nameoff; + + FDT_SW_CHECK_HEADER(fdt); + + nameoff = _fdt_find_add_string(fdt, name); + if (nameoff == 0) + return -FDT_ERR_NOSPACE; + + prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); + if (! prop) + return -FDT_ERR_NOSPACE; + + prop->tag = cpu_to_fdt32(FDT_PROP); + prop->nameoff = cpu_to_fdt32(nameoff); + prop->len = cpu_to_fdt32(len); + *valp = prop->data; + return 0; +} + +int fdt_property(void *fdt, const char *name, const void *val, int len) +{ + void *ptr; + int ret; + + ret = fdt_property_placeholder(fdt, name, len, &ptr); + if (ret) + return ret; + memcpy(ptr, val, len); + return 0; +} + +int fdt_finish(void *fdt) +{ + char *p = (char *)fdt; + fdt32_t *end; + int oldstroffset, newstroffset; + uint32_t tag; + int offset, nextoffset; + + FDT_SW_CHECK_HEADER(fdt); + + /* Add terminator */ + end = _fdt_grab_space(fdt, sizeof(*end)); + if (! end) + return -FDT_ERR_NOSPACE; + *end = cpu_to_fdt32(FDT_END); + + /* Relocate the string table */ + oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); + newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); + fdt_set_off_dt_strings(fdt, newstroffset); + + /* Walk the structure, correcting string offsets */ + offset = 0; + while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { + if (tag == FDT_PROP) { + struct fdt_property *prop = + _fdt_offset_ptr_w(fdt, offset); + int nameoff; + + nameoff = fdt32_to_cpu(prop->nameoff); + nameoff += fdt_size_dt_strings(fdt); + prop->nameoff = cpu_to_fdt32(nameoff); + } + offset = nextoffset; + } + if (nextoffset < 0) + return nextoffset; + + /* Finally, adjust the header */ + fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); + fdt_set_magic(fdt, FDT_MAGIC); + return 0; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_wip.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_wip.c new file mode 100644 index 00000000..5e859198 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_wip.c @@ -0,0 +1,139 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include +#include + +#include "libfdt_internal.h" + +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len) +{ + void *propval; + int proplen; + + propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, + &proplen); + if (!propval) + return proplen; + + if (proplen < (len + idx)) + return -FDT_ERR_NOSPACE; + + memcpy((char *)propval + idx, val, len); + return 0; +} + +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + const void *propval; + int proplen; + + propval = fdt_getprop(fdt, nodeoffset, name, &proplen); + if (!propval) + return proplen; + + if (proplen != len) + return -FDT_ERR_NOSPACE; + + return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, + strlen(name), 0, + val, len); +} + +static void _fdt_nop_region(void *start, int len) +{ + fdt32_t *p; + + for (p = start; (char *)p < ((char *)start + len); p++) + *p = cpu_to_fdt32(FDT_NOP); +} + +int fdt_nop_property(void *fdt, int nodeoffset, const char *name) +{ + struct fdt_property *prop; + int len; + + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); + if (!prop) + return len; + + _fdt_nop_region(prop, len + sizeof(*prop)); + + return 0; +} + +int _fdt_node_end_offset(void *fdt, int offset) +{ + int depth = 0; + + while ((offset >= 0) && (depth >= 0)) + offset = fdt_next_node(fdt, offset, &depth); + + return offset; +} + +int fdt_nop_node(void *fdt, int nodeoffset) +{ + int endoffset; + + endoffset = _fdt_node_end_offset(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + + _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), + endoffset - nodeoffset); + return 0; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/libfdt_internal.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/libfdt_internal.h new file mode 100644 index 00000000..02cfa6fb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/libfdt_internal.h @@ -0,0 +1,95 @@ +#ifndef _LIBFDT_INTERNAL_H +#define _LIBFDT_INTERNAL_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) + +#define FDT_CHECK_HEADER(fdt) \ + { \ + int __err; \ + if ((__err = fdt_check_header(fdt)) != 0) \ + return __err; \ + } + +int _fdt_check_node_offset(const void *fdt, int offset); +int _fdt_check_prop_offset(const void *fdt, int offset); +const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); +int _fdt_node_end_offset(void *fdt, int nodeoffset); + +static inline const void *_fdt_offset_ptr(const void *fdt, int offset) +{ + return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; +} + +static inline void *_fdt_offset_ptr_w(void *fdt, int offset) +{ + return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset); +} + +static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) +{ + const struct fdt_reserve_entry *rsv_table = + (const struct fdt_reserve_entry *) + ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); + + return rsv_table + n; +} +static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) +{ + return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n); +} + +#define FDT_SW_MAGIC (~FDT_MAGIC) + +#endif /* _LIBFDT_INTERNAL_H */ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/version.lds b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/version.lds new file mode 100644 index 00000000..1f4e1eab --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/version.lds @@ -0,0 +1,67 @@ +LIBFDT_1.2 { + global: + fdt_next_node; + fdt_check_header; + fdt_move; + fdt_string; + fdt_num_mem_rsv; + fdt_get_mem_rsv; + fdt_subnode_offset_namelen; + fdt_subnode_offset; + fdt_path_offset_namelen; + fdt_path_offset; + fdt_get_name; + fdt_get_property_namelen; + fdt_get_property; + fdt_getprop_namelen; + fdt_getprop; + fdt_get_phandle; + fdt_get_alias_namelen; + fdt_get_alias; + fdt_get_path; + fdt_supernode_atdepth_offset; + fdt_node_depth; + fdt_parent_offset; + fdt_node_offset_by_prop_value; + fdt_node_offset_by_phandle; + fdt_node_check_compatible; + fdt_node_offset_by_compatible; + fdt_setprop_inplace; + fdt_nop_property; + fdt_nop_node; + fdt_create; + fdt_add_reservemap_entry; + fdt_finish_reservemap; + fdt_begin_node; + fdt_property; + fdt_end_node; + fdt_finish; + fdt_open_into; + fdt_pack; + fdt_add_mem_rsv; + fdt_del_mem_rsv; + fdt_set_name; + fdt_setprop; + fdt_delprop; + fdt_add_subnode_namelen; + fdt_add_subnode; + fdt_del_node; + fdt_strerror; + fdt_offset_ptr; + fdt_next_tag; + fdt_appendprop; + fdt_create_empty_tree; + fdt_first_property_offset; + fdt_get_property_by_offset; + fdt_getprop_by_offset; + fdt_next_property_offset; + fdt_first_subnode; + fdt_next_subnode; + fdt_address_cells; + fdt_size_cells; + fdt_stringlist_contains; + fdt_resize; + + local: + *; +}; diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c new file mode 100644 index 00000000..552c8928 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c @@ -0,0 +1,181 @@ +/** @file + Basic serial IO abstraction for GDB + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#include + + +EFI_DEBUGPORT_PROTOCOL *gDebugPort = NULL; +UINTN gTimeOut = 0; + +/** + The constructor function initializes the UART. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +RETURN_STATUS +EFIAPI +GdbSerialLibDebugPortConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gEfiDebugPortProtocolGuid, NULL, (VOID **)&gDebugPort); + if (!EFI_ERROR (Status)) { + gTimeOut = PcdGet32 (PcdGdbMaxPacketRetryCount); + gDebugPort->Reset (gDebugPort); + } + + return Status; +} + + + +/** + Sets the baud rate, receive FIFO depth, transmit/receive time out, parity, + data buts, and stop bits on a serial device. This call is optional as the serial + port will be set up with defaults base on PCD values. + + @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the + device's default interface speed. + @param Parity The type of parity to use on this serial device. A Parity value of + DefaultParity will use the device's default parity value. + @param DataBits The number of data bits to use on the serial device. A DataBits + value of 0 will use the device's default data bit setting. + @param StopBits The number of stop bits to use on this serial device. A StopBits + value of DefaultStopBits will use the device's default number of + stop bits. + + @retval EFI_SUCCESS The device was configured. + @retval EFI_DEVICE_ERROR The serial device could not be configured. + +**/ +RETURN_STATUS +EFIAPI +GdbSerialInit ( + IN UINT64 BaudRate, + IN UINT8 Parity, + IN UINT8 DataBits, + IN UINT8 StopBits + ) +{ + EFI_STATUS Status; + + Status = gDebugPort->Reset (gDebugPort); + return Status; +} + + +/** + Check to see if a character is available from GDB. Do not read the character as that is + done via GdbGetChar(). + + @return TRUE - Character available + @return FALSE - Character not available + +**/ +BOOLEAN +EFIAPI +GdbIsCharAvailable ( + VOID + ) +{ + EFI_STATUS Status; + + Status = gDebugPort->Poll (gDebugPort); + + return (Status == EFI_SUCCESS ? TRUE : FALSE); +} + + +/** + Get a character from GDB. This function must be able to run in interrupt context. + + @return A character from GDB + +**/ +CHAR8 +EFIAPI +GdbGetChar ( + VOID + ) +{ + EFI_STATUS Status; + CHAR8 Char; + UINTN BufferSize; + + do { + BufferSize = sizeof (Char); + Status = gDebugPort->Read (gDebugPort, gTimeOut, &BufferSize, &Char); + } while (EFI_ERROR (Status) || BufferSize != sizeof (Char)); + + return Char; +} + + +/** + Send a character to GDB. This function must be able to run in interrupt context. + + + @param Char Send a character to GDB + +**/ + +VOID +EFIAPI +GdbPutChar ( + IN CHAR8 Char + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + + do { + BufferSize = sizeof (Char); + Status = gDebugPort->Write (gDebugPort, gTimeOut, &BufferSize, &Char); + } while (EFI_ERROR (Status) || BufferSize != sizeof (Char)); + + return; +} + +/** + Send an ASCII string to GDB. This function must be able to run in interrupt context. + + + @param String Send a string to GDB + +**/ + +VOID +GdbPutString ( + IN CHAR8 *String + ) +{ + // We could performance enhance this function by calling gDebugPort->Write () + while (*String != '\0') { + GdbPutChar (*String); + String++; + } +} + + + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf new file mode 100644 index 00000000..ab647e20 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf @@ -0,0 +1,44 @@ +#/** @file +# Component description file for Base PCI Cf8 Library. +# +# PCI CF8 Library that uses I/O ports 0xCF8 and 0xCFC to perform PCI Configuration cycles. +# Layers on top of an I/O Library instance. +# Copyright (c) 2007, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GdbSerialDebugPortLib + FILE_GUID = 42ABB10A-660A-4BEC-AEFA-CC94AB4D993D + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = GdbSerialLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER + + CONSTRUCTOR = GdbSerialLibDebugPortConstructor + + +[Sources.common] + GdbSerialDebugPortLib.c + + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + DebugLib + IoLib + +[Protocols.common] + gEfiDebugPortProtocolGuid + +[FixedPcd.common] + gEmbeddedTokenSpaceGuid.PcdGdbBaudRate|115200 + gEmbeddedTokenSpaceGuid.PcdGdbDataBits|8 + gEmbeddedTokenSpaceGuid.PcdGdbParity|1 + gEmbeddedTokenSpaceGuid.PcdGdbStopBits|1 + gEmbeddedTokenSpaceGuid.PcdGdbMaxPacketRetryCount diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c new file mode 100644 index 00000000..b788b769 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c @@ -0,0 +1,256 @@ +/** @file + Basic serial IO abstraction for GDB + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + + +//--------------------------------------------- +// UART Register Offsets +//--------------------------------------------- +#define BAUD_LOW_OFFSET 0x00 +#define BAUD_HIGH_OFFSET 0x01 +#define IER_OFFSET 0x01 +#define LCR_SHADOW_OFFSET 0x01 +#define FCR_SHADOW_OFFSET 0x02 +#define IR_CONTROL_OFFSET 0x02 +#define FCR_OFFSET 0x02 +#define EIR_OFFSET 0x02 +#define BSR_OFFSET 0x03 +#define LCR_OFFSET 0x03 +#define MCR_OFFSET 0x04 +#define LSR_OFFSET 0x05 +#define MSR_OFFSET 0x06 + +//--------------------------------------------- +// UART Register Bit Defines +//--------------------------------------------- +#define LSR_TXRDY 0x20U +#define LSR_RXDA 0x01U +#define DLAB 0x01U +#define ENABLE_FIFO 0x01U +#define CLEAR_FIFOS 0x06U + + + +// IO Port Base for the UART +UINTN gPort; + + +/** + The constructor function initializes the UART. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +RETURN_STATUS +EFIAPI +GdbSerialLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT64 BaudRate; + UINT8 DataBits; + UINT8 Parity; + UINT8 StopBits; + + gPort = (UINTN)PcdGet32 (PcdGdbUartPort); + + BaudRate = PcdGet64 (PcdGdbBaudRate); + Parity = PcdGet8 (PcdGdbParity); + DataBits = PcdGet8 (PcdGdbDataBits); + StopBits = PcdGet8 (PcdGdbStopBits); + + return GdbSerialInit (BaudRate, Parity, DataBits, StopBits); +} + + + +/** + Sets the baud rate, receive FIFO depth, transmit/receive time out, parity, + data buts, and stop bits on a serial device. This call is optional as the serial + port will be set up with defaults base on PCD values. + + @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the + device's default interface speed. + @param Parity The type of parity to use on this serial device. A Parity value of + DefaultParity will use the device's default parity value. + @param DataBits The number of data bits to use on the serial device. A DataBits + value of 0 will use the device's default data bit setting. + @param StopBits The number of stop bits to use on this serial device. A StopBits + value of DefaultStopBits will use the device's default number of + stop bits. + + @retval EFI_SUCCESS The device was configured. + @retval EFI_DEVICE_ERROR The serial device could not be configured. + +**/ +RETURN_STATUS +EFIAPI +GdbSerialInit ( + IN UINT64 BaudRate, + IN UINT8 Parity, + IN UINT8 DataBits, + IN UINT8 StopBits + ) +{ + UINTN Divisor; + UINT8 OutputData; + UINT8 Data; + UINT8 BreakSet = 0; + + // + // We assume the UART has been turned on to decode gPort address range + // + + // + // Map 5..8 to 0..3 + // + Data = (UINT8) (DataBits - (UINT8)5); + + // + // Calculate divisor for baud generator + // + Divisor = 115200/(UINTN)BaudRate; + + // + // Set communications format + // + OutputData = (UINT8)((DLAB << 7) | ((BreakSet << 6) | ((Parity << 3) | ((StopBits << 2) | Data)))); + IoWrite8 (gPort + LCR_OFFSET, OutputData); + + // + // Configure baud rate + // + IoWrite8 (gPort + BAUD_HIGH_OFFSET, (UINT8)(Divisor >> 8)); + IoWrite8 (gPort + BAUD_LOW_OFFSET, (UINT8)(Divisor & 0xff)); + + + // + // Switch back to bank 0 + // + OutputData = (UINT8)((~DLAB<<7)|((BreakSet<<6)|((Parity<<3)|((StopBits<<2)| Data)))); + IoWrite8 (gPort + LCR_OFFSET, OutputData); + + // Not sure this is the right place to enable the FIFOs.... + // We probably need the FIFO enabled to not drop input + IoWrite8 (gPort + FCR_SHADOW_OFFSET, ENABLE_FIFO); + + + // Configure the UART hardware here + return RETURN_SUCCESS; +} + + +/** + Check to see if a character is available from GDB. Do not read the character as that is + done via GdbGetChar(). + + @return TRUE - Character available + @return FALSE - Character not available + +**/ +BOOLEAN +EFIAPI +GdbIsCharAvailable ( + VOID + ) +{ + UINT8 Data; + + Data = IoRead8 (gPort + LSR_OFFSET); + + return ((Data & LSR_RXDA) == LSR_RXDA); +} + + +/** + Get a character from GDB. This function must be able to run in interrupt context. + + @return A character from GDB + +**/ +CHAR8 +EFIAPI +GdbGetChar ( + VOID + ) +{ + UINT8 Data; + CHAR8 Char; + + // Wait for the serial port to be ready + do { + Data = IoRead8 (gPort + LSR_OFFSET); + } while ((Data & LSR_RXDA) == 0); + + Char = IoRead8 (gPort); + + // Make this an EFI_D_INFO after we get everything debugged. + DEBUG ((EFI_D_ERROR, "<%c<", Char)); + return Char; +} + + +/** + Send a character to GDB. This function must be able to run in interrupt context. + + + @param Char Send a character to GDB + +**/ + +VOID +EFIAPI +GdbPutChar ( + IN CHAR8 Char + ) +{ + UINT8 Data; + + // Make this an EFI_D_INFO after we get everything debugged. + DEBUG ((EFI_D_ERROR, ">%c>", Char)); + + // Wait for the serial port to be ready + do { + Data = IoRead8 (gPort + LSR_OFFSET); + } while ((Data & LSR_TXRDY) == 0); + + IoWrite8 (gPort, Char); +} + +/** + Send an ASCII string to GDB. This function must be able to run in interrupt context. + + + @param String Send a string to GDB + +**/ + +VOID +GdbPutString ( + IN CHAR8 *String + ) +{ + while (*String != '\0') { + GdbPutChar (*String); + String++; + } +} + + + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf new file mode 100644 index 00000000..4ae9f4d5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf @@ -0,0 +1,41 @@ +#/** @file +# Component description file for Base PCI Cf8 Library. +# +# PCI CF8 Library that uses I/O ports 0xCF8 and 0xCFC to perform PCI Configuration cycles. +# Layers on top of an I/O Library instance. +# Copyright (c) 2007, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GdbSerialLib + FILE_GUID = 9999B4EE-081F-4501-AEDC-137A534BAF69 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = GdbSerialLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER + + CONSTRUCTOR = GdbSerialLibConstructor + + +[Sources.common] + GdbSerialLib.c + + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + DebugLib + IoLib + +[FixedPcd.common] + gEmbeddedTokenSpaceGuid.PcdGdbBaudRate|115200 + gEmbeddedTokenSpaceGuid.PcdGdbDataBits|8 + gEmbeddedTokenSpaceGuid.PcdGdbParity|1 + gEmbeddedTokenSpaceGuid.PcdGdbStopBits|1 + gEmbeddedTokenSpaceGuid.PcdGdbUartPort diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c new file mode 100644 index 00000000..bd9cab9f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c @@ -0,0 +1,624 @@ +/** @file + + Generic non-coherent implementation of DmaLib.h + + Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Copyright (c) 2015 - 2017, Linaro, Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef struct { + EFI_PHYSICAL_ADDRESS HostAddress; + VOID *BufferAddress; + UINTN NumberOfBytes; + DMA_MAP_OPERATION Operation; + BOOLEAN DoubleBuffer; +} MAP_INFO_INSTANCE; + + +typedef struct { + LIST_ENTRY Link; + VOID *HostAddress; + UINTN NumPages; + UINT64 Attributes; +} UNCACHED_ALLOCATION; + +STATIC EFI_CPU_ARCH_PROTOCOL *mCpu; +STATIC LIST_ENTRY UncachedAllocationList; + +STATIC PHYSICAL_ADDRESS mDmaHostAddressLimit; + +STATIC +PHYSICAL_ADDRESS +HostToDeviceAddress ( + IN VOID *Address + ) +{ + return (PHYSICAL_ADDRESS)(UINTN)Address + PcdGet64 (PcdDmaDeviceOffset); +} + +/** + Allocates one or more 4KB pages of a certain memory type at a specified + alignment. + + Allocates the number of 4KB pages specified by Pages of a certain memory type + with an alignment specified by Alignment. The allocated buffer is returned. + If Pages is 0, then NULL is returned. If there is not enough memory at the + specified alignment remaining to satisfy the request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param MemoryType The type of memory to allocate. + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. + Must be a power of two. + If Alignment is zero, then byte alignment is + used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +STATIC +VOID * +InternalAllocateAlignedPages ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Memory; + UINTN AlignedMemory; + UINTN AlignmentMask; + UINTN UnalignedPages; + UINTN RealPages; + + // + // Alignment must be a power of two or zero. + // + ASSERT ((Alignment & (Alignment - 1)) == 0); + + if (Pages == 0) { + return NULL; + } + if (Alignment > EFI_PAGE_SIZE) { + // + // Calculate the total number of pages since alignment is larger than page + // size. + // + AlignmentMask = Alignment - 1; + RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment); + // + // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not + // overflow. + // + ASSERT (RealPages > Pages); + + Memory = mDmaHostAddressLimit; + Status = gBS->AllocatePages (AllocateMaxAddress, MemoryType, RealPages, + &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask; + UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory); + if (UnalignedPages > 0) { + // + // Free first unaligned page(s). + // + Status = gBS->FreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages); + UnalignedPages = RealPages - Pages - UnalignedPages; + if (UnalignedPages > 0) { + // + // Free last unaligned page(s). + // + Status = gBS->FreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + } else { + // + // Do not over-allocate pages in this case. + // + Memory = mDmaHostAddressLimit; + Status = gBS->AllocatePages (AllocateMaxAddress, MemoryType, Pages, + &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + AlignedMemory = (UINTN)Memory; + } + return (VOID *)AlignedMemory; +} + +/** + Provides the DMA controller-specific addresses needed to access system memory. + + Operation is relative to the DMA bus master. + + @param Operation Indicates if the bus master is going to read or + write to system memory. + @param HostAddress The system memory address to map to the DMA + controller. + @param NumberOfBytes On input the number of bytes to map. On output + the number of bytes that were mapped. + @param DeviceAddress The resulting map address for the bus master + controller to use to access the host's + HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned + NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common + buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack + of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested + address. + +**/ +EFI_STATUS +EFIAPI +DmaMap ( + IN DMA_MAP_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + MAP_INFO_INSTANCE *Map; + VOID *Buffer; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; + UINTN AllocSize; + + if (HostAddress == NULL || + NumberOfBytes == NULL || + DeviceAddress == NULL || + Mapping == NULL ) { + return EFI_INVALID_PARAMETER; + } + + if (Operation >= MapOperationMaximum) { + return EFI_INVALID_PARAMETER; + } + + *DeviceAddress = HostToDeviceAddress (HostAddress); + + // Remember range so we can flush on the other side + Map = AllocatePool (sizeof (MAP_INFO_INSTANCE)); + if (Map == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (((UINTN)HostAddress + *NumberOfBytes) > mDmaHostAddressLimit) { + + if (Operation == MapOperationBusMasterCommonBuffer) { + goto CommonBufferError; + } + + AllocSize = ALIGN_VALUE (*NumberOfBytes, mCpu->DmaBufferAlignment); + Map->BufferAddress = InternalAllocateAlignedPages (EfiBootServicesData, + EFI_SIZE_TO_PAGES (AllocSize), + mCpu->DmaBufferAlignment); + if (Map->BufferAddress == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMapInfo; + } + + if (Map->Operation == MapOperationBusMasterRead) { + CopyMem (Map->BufferAddress, (VOID *)(UINTN)HostAddress, *NumberOfBytes); + } + mCpu->FlushDataCache (mCpu, (UINTN)Map->BufferAddress, AllocSize, + EfiCpuFlushTypeWriteBack); + + *DeviceAddress = HostToDeviceAddress (Map->BufferAddress); + } else if (Operation != MapOperationBusMasterRead && + ((((UINTN)HostAddress & (mCpu->DmaBufferAlignment - 1)) != 0) || + ((*NumberOfBytes & (mCpu->DmaBufferAlignment - 1)) != 0))) { + + // Get the cacheability of the region + Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor); + if (EFI_ERROR(Status)) { + goto FreeMapInfo; + } + + // If the mapped buffer is not an uncached buffer + if ((GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) != 0) { + // + // Operations of type MapOperationBusMasterCommonBuffer are only allowed + // on uncached buffers. + // + if (Operation == MapOperationBusMasterCommonBuffer) { + goto CommonBufferError; + } + + // + // If the buffer does not fill entire cache lines we must double buffer + // into a suitably aligned allocation that allows us to invalidate the + // cache without running the risk of corrupting adjacent unrelated data. + // Note that pool allocations are guaranteed to be 8 byte aligned, so + // we only have to add (alignment - 8) worth of padding. + // + Map->DoubleBuffer = TRUE; + AllocSize = ALIGN_VALUE (*NumberOfBytes, mCpu->DmaBufferAlignment) + + (mCpu->DmaBufferAlignment - 8); + Map->BufferAddress = AllocatePool (AllocSize); + if (Map->BufferAddress == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMapInfo; + } + + Buffer = ALIGN_POINTER (Map->BufferAddress, mCpu->DmaBufferAlignment); + *DeviceAddress = HostToDeviceAddress (Buffer); + + // + // Get rid of any dirty cachelines covering the double buffer. This + // prevents them from being written back unexpectedly, potentially + // overwriting the data we receive from the device. + // + mCpu->FlushDataCache (mCpu, (UINTN)Buffer, *NumberOfBytes, + EfiCpuFlushTypeWriteBack); + } else { + Map->DoubleBuffer = FALSE; + } + } else { + Map->DoubleBuffer = FALSE; + + DEBUG_CODE_BEGIN (); + + // + // The operation type check above only executes if the buffer happens to be + // misaligned with respect to CWG, but even if it is aligned, we should not + // allow arbitrary buffers to be used for creating consistent mappings. + // So duplicate the check here when running in DEBUG mode, just to assert + // that we are not trying to create a consistent mapping for cached memory. + // + Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor); + ASSERT_EFI_ERROR(Status); + + ASSERT (Operation != MapOperationBusMasterCommonBuffer || + (GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) == 0); + + DEBUG_CODE_END (); + + // Flush the Data Cache (should not have any effect if the memory region is + // uncached) + mCpu->FlushDataCache (mCpu, (UINTN)HostAddress, *NumberOfBytes, + EfiCpuFlushTypeWriteBackInvalidate); + } + + Map->HostAddress = (UINTN)HostAddress; + Map->NumberOfBytes = *NumberOfBytes; + Map->Operation = Operation; + + *Mapping = Map; + + return EFI_SUCCESS; + +CommonBufferError: + DEBUG ((DEBUG_ERROR, + "%a: Operation type 'MapOperationBusMasterCommonBuffer' is only " + "supported\non memory regions that were allocated using " + "DmaAllocateBuffer ()\n", __FUNCTION__)); + Status = EFI_UNSUPPORTED; +FreeMapInfo: + FreePool (Map); + + return Status; +} + + +/** + Completes the DmaMapBusMasterRead(), DmaMapBusMasterWrite(), or + DmaMapBusMasterCommonBuffer() operation and releases any corresponding + resources. + + @param Mapping The mapping value returned from DmaMap*(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_DEVICE_ERROR The data was not committed to the target system + memory. + @retval EFI_INVALID_PARAMETER An inconsistency was detected between the + mapping type and the DoubleBuffer field + +**/ +EFI_STATUS +EFIAPI +DmaUnmap ( + IN VOID *Mapping + ) +{ + MAP_INFO_INSTANCE *Map; + EFI_STATUS Status; + VOID *Buffer; + UINTN AllocSize; + + if (Mapping == NULL) { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Map = (MAP_INFO_INSTANCE *)Mapping; + + Status = EFI_SUCCESS; + if (((UINTN)Map->HostAddress + Map->NumberOfBytes) > mDmaHostAddressLimit) { + AllocSize = ALIGN_VALUE (Map->NumberOfBytes, mCpu->DmaBufferAlignment); + if (Map->Operation == MapOperationBusMasterWrite) { + mCpu->FlushDataCache (mCpu, (UINTN)Map->BufferAddress, AllocSize, + EfiCpuFlushTypeInvalidate); + CopyMem ((VOID *)(UINTN)Map->HostAddress, Map->BufferAddress, + Map->NumberOfBytes); + } + FreePages (Map->BufferAddress, EFI_SIZE_TO_PAGES (AllocSize)); + } else if (Map->DoubleBuffer) { + + ASSERT (Map->Operation == MapOperationBusMasterWrite); + + if (Map->Operation != MapOperationBusMasterWrite) { + Status = EFI_INVALID_PARAMETER; + } else { + Buffer = ALIGN_POINTER (Map->BufferAddress, mCpu->DmaBufferAlignment); + + mCpu->FlushDataCache (mCpu, (UINTN)Buffer, Map->NumberOfBytes, + EfiCpuFlushTypeInvalidate); + + CopyMem ((VOID *)(UINTN)Map->HostAddress, Buffer, Map->NumberOfBytes); + + FreePool (Map->BufferAddress); + } + } else { + if (Map->Operation == MapOperationBusMasterWrite) { + // + // Make sure we read buffer from uncached memory and not the cache + // + mCpu->FlushDataCache (mCpu, Map->HostAddress, Map->NumberOfBytes, + EfiCpuFlushTypeInvalidate); + } + } + + FreePool (Map); + + return Status; +} + +/** + Allocates pages that are suitable for an DmaMap() of type + MapOperationBusMasterCommonBuffer mapping. + + @param MemoryType The type of memory to allocate, + EfiBootServicesData or EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory + address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +DmaAllocateBuffer ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress + ) +{ + return DmaAllocateAlignedBuffer (MemoryType, Pages, 0, HostAddress); +} + +/** + Allocates pages that are suitable for an DmaMap() of type + MapOperationBusMasterCommonBuffer mapping, at the requested alignment. + + @param MemoryType The type of memory to allocate, + EfiBootServicesData or EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param Alignment Alignment in bytes of the base of the returned + buffer (must be a power of 2) + @param HostAddress A pointer to store the base system memory + address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +DmaAllocateAlignedBuffer ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment, + OUT VOID **HostAddress + ) +{ + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; + VOID *Allocation; + UINT64 MemType; + UNCACHED_ALLOCATION *Alloc; + EFI_STATUS Status; + + if (Alignment == 0) { + Alignment = EFI_PAGE_SIZE; + } + + if (HostAddress == NULL || + (Alignment & (Alignment - 1)) != 0) { + return EFI_INVALID_PARAMETER; + } + + if (MemoryType == EfiBootServicesData || + MemoryType == EfiRuntimeServicesData) { + Allocation = InternalAllocateAlignedPages (MemoryType, Pages, Alignment); + } else { + return EFI_INVALID_PARAMETER; + } + + if (Allocation == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // Get the cacheability of the region + Status = gDS->GetMemorySpaceDescriptor ((UINTN)Allocation, &GcdDescriptor); + if (EFI_ERROR(Status)) { + goto FreeBuffer; + } + + // Choose a suitable uncached memory type that is supported by the region + if (GcdDescriptor.Capabilities & EFI_MEMORY_WC) { + MemType = EFI_MEMORY_WC; + } else if (GcdDescriptor.Capabilities & EFI_MEMORY_UC) { + MemType = EFI_MEMORY_UC; + } else { + Status = EFI_UNSUPPORTED; + goto FreeBuffer; + } + + Alloc = AllocatePool (sizeof *Alloc); + if (Alloc == NULL) { + goto FreeBuffer; + } + + Alloc->HostAddress = Allocation; + Alloc->NumPages = Pages; + Alloc->Attributes = GcdDescriptor.Attributes; + + InsertHeadList (&UncachedAllocationList, &Alloc->Link); + + // Remap the region with the new attributes + Status = gDS->SetMemorySpaceAttributes ((PHYSICAL_ADDRESS)(UINTN)Allocation, + EFI_PAGES_TO_SIZE (Pages), + MemType); + if (EFI_ERROR (Status)) { + goto FreeAlloc; + } + + Status = mCpu->FlushDataCache (mCpu, + (PHYSICAL_ADDRESS)(UINTN)Allocation, + EFI_PAGES_TO_SIZE (Pages), + EfiCpuFlushTypeInvalidate); + if (EFI_ERROR (Status)) { + goto FreeAlloc; + } + + *HostAddress = Allocation; + + return EFI_SUCCESS; + +FreeAlloc: + RemoveEntryList (&Alloc->Link); + FreePool (Alloc); + +FreeBuffer: + FreePages (Allocation, Pages); + return Status; +} + + +/** + Frees memory that was allocated with DmaAllocateBuffer(). + + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated + range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and + Pages was not allocated with + DmaAllocateBuffer(). + +**/ +EFI_STATUS +EFIAPI +DmaFreeBuffer ( + IN UINTN Pages, + IN VOID *HostAddress + ) +{ + LIST_ENTRY *Link; + UNCACHED_ALLOCATION *Alloc; + BOOLEAN Found; + EFI_STATUS Status; + + if (HostAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + for (Link = GetFirstNode (&UncachedAllocationList), Found = FALSE; + !IsNull (&UncachedAllocationList, Link); + Link = GetNextNode (&UncachedAllocationList, Link)) { + + Alloc = BASE_CR (Link, UNCACHED_ALLOCATION, Link); + if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) { + Found = TRUE; + break; + } + } + + if (!Found) { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList (&Alloc->Link); + + Status = gDS->SetMemorySpaceAttributes ((PHYSICAL_ADDRESS)(UINTN)HostAddress, + EFI_PAGES_TO_SIZE (Pages), + Alloc->Attributes); + if (EFI_ERROR (Status)) { + goto FreeAlloc; + } + + // + // If we fail to restore the original attributes, it is better to leak the + // memory than to return it to the heap + // + FreePages (HostAddress, Pages); + +FreeAlloc: + FreePool (Alloc); + return Status; +} + + +EFI_STATUS +EFIAPI +NonCoherentDmaLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + InitializeListHead (&UncachedAllocationList); + + // + // Ensure that the combination of DMA addressing offset and limit produces + // a sane value. + // + ASSERT (PcdGet64 (PcdDmaDeviceLimit) > PcdGet64 (PcdDmaDeviceOffset)); + + mDmaHostAddressLimit = PcdGet64 (PcdDmaDeviceLimit) - + PcdGet64 (PcdDmaDeviceOffset); + + // Get the Cpu protocol for later use + return gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu); +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf new file mode 100644 index 00000000..56491c3f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf @@ -0,0 +1,44 @@ +#/** @file +# +# Generic non-coherent implementation of DmaLib.h +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+# Copyright (c) 2015 - 2017, Linaro, Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = NonCoherentDmaLib + FILE_GUID = 43ad4920-db15-4e24-9889-2db568431fbd + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = DmaLib + CONSTRUCTOR = NonCoherentDmaLibConstructor + +[Sources] + NonCoherentDmaLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + DxeServicesTableLib + IoLib + MemoryAllocationLib + UefiBootServicesTableLib + +[Protocols] + gEfiCpuArchProtocolGuid + +[Pcd] + gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset + gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit + +[Depex] + gEfiCpuArchProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.c new file mode 100644 index 00000000..9763323a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.c @@ -0,0 +1,220 @@ +/** @file +* +* Copyright (c) 2017 Marvell International Ltd. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include + +#include +#include +#include +#include +#include +#include + +STATIC CONST NOR_FLASH_INFO NorFlashIds[] = { + /* ATMEL */ + {L"at45db011d", {0x1f, 0x22, 0x00}, 3, 256, 64 * 1024, 4, NOR_FLASH_ERASE_4K}, + {L"at45db021d", {0x1f, 0x23, 0x00}, 3, 256, 64 * 1024, 8, NOR_FLASH_ERASE_4K}, + {L"at45db041d", {0x1f, 0x24, 0x00}, 3, 256, 64 * 1024, 8, NOR_FLASH_ERASE_4K}, + {L"at45db081d", {0x1f, 0x25, 0x00}, 3, 256, 64 * 1024, 16, NOR_FLASH_ERASE_4K}, + {L"at45db161d", {0x1f, 0x26, 0x00}, 3, 256, 64 * 1024, 32, NOR_FLASH_ERASE_4K}, + {L"at45db321d", {0x1f, 0x27, 0x00}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"at45db641d", {0x1f, 0x28, 0x00}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"at25df321a", {0x1f, 0x47, 0x01}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"at25df321", {0x1f, 0x47, 0x00}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"at26df081a", {0x1f, 0x45, 0x01}, 3, 256, 64 * 1024, 16, NOR_FLASH_ERASE_4K}, + /* EON */ + {L"en25q32b", {0x1c, 0x30, 0x16}, 3, 256, 64 * 1024, 64, 0}, + {L"en25q64", {0x1c, 0x30, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"en25q128b", {0x1c, 0x30, 0x18}, 3, 256, 64 * 1024, 256, 0}, + {L"en25s64", {0x1c, 0x38, 0x17}, 3, 256, 64 * 1024, 128, 0}, + /* GIGADEVICE */ + {L"gd25q64b", {0xc8, 0x40, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"gd25lq32", {0xc8, 0x60, 0x16}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + /* ISSI */ + {L"is25lp032", {0x9d, 0x60, 0x16}, 3, 256, 64 * 1024, 64, 0}, + {L"is25lp064", {0x9d, 0x60, 0x17}, 3, 256, 64 * 1024, 128, 0}, + {L"is25lp128", {0x9d, 0x60, 0x18}, 3, 256, 64 * 1024, 256, 0}, + /* MACRONIX */ + {L"mx25l2006e", {0xc2, 0x20, 0x12}, 3, 256, 64 * 1024, 4, 0}, + {L"mx25l4005", {0xc2, 0x20, 0x13}, 3, 256, 64 * 1024, 8, 0}, + {L"mx25l8005", {0xc2, 0x20, 0x14}, 3, 256, 64 * 1024, 16, 0}, + {L"mx25l1605d", {0xc2, 0x20, 0x15}, 3, 256, 64 * 1024, 32, 0}, + {L"mx25l3205d", {0xc2, 0x20, 0x16}, 3, 256, 64 * 1024, 64, 0}, + {L"mx25l6405d", {0xc2, 0x20, 0x17}, 3, 256, 64 * 1024, 128, 0}, + {L"mx25l12805", {0xc2, 0x20, 0x18}, 3, 256, 64 * 1024, 256, 0}, + {L"mx25l25635f", {0xc2, 0x20, 0x19}, 3, 256, 64 * 1024, 512, 0}, + {L"mx25l51235f", {0xc2, 0x20, 0x1a}, 3, 256, 64 * 1024, 1024, 0}, + {L"mx25l12855e", {0xc2, 0x26, 0x18}, 3, 256, 64 * 1024, 256, 0}, + {L"mx66u51235f", {0xc2, 0x25, 0x3a}, 3, 256, 64 * 1024, 1024, 0}, + {L"mx66u1g45g", {0xc2, 0x25, 0x3b}, 3, 256, 64 * 1024, 2048, 0}, + {L"mx66l1g45g", {0xc2, 0x20, 0x1b}, 3, 256, 64 * 1024, 2048, 0}, + /* SPANSION */ + {L"s25fl008a", {0x01, 0x02, 0x13}, 3, 256, 64 * 1024, 16, 0}, + {L"s25fl016a", {0x01, 0x02, 0x14}, 3, 256, 64 * 1024, 32, 0}, + {L"s25fl032a", {0x01, 0x02, 0x15}, 3, 256, 64 * 1024, 64, 0}, + {L"s25fl064a", {0x01, 0x02, 0x16}, 3, 256, 64 * 1024, 128, 0}, + {L"s25fl116k", {0x01, 0x40, 0x15}, 3, 256, 64 * 1024, 128, 0}, + {L"s25fl164k", {0x01, 0x40, 0x17, 0x01, 0x40}, 5, 256, 64 * 1024, 128, 0}, + {L"s25fl128p_256k", {0x01, 0x20, 0x18, 0x03, 0x00}, 5, 256, 256 * 1024, 64, 0}, + {L"s25fl128p_64k", {0x01, 0x20, 0x18, 0x03, 0x01}, 5, 256, 64 * 1024, 256, 0}, + {L"s25fl032p", {0x01, 0x02, 0x15, 0x4d, 0x00}, 5, 256, 64 * 1024, 64, 0}, + {L"s25fl064p", {0x01, 0x02, 0x16, 0x4d, 0x00}, 5, 256, 64 * 1024, 128, 0}, + {L"s25fl128s_256k", {0x01, 0x20, 0x18, 0x4d, 0x00}, 5, 256, 256 * 1024, 64, 0}, + {L"s25fl128s_64k", {0x01, 0x20, 0x18, 0x4d, 0x01}, 5, 256, 64 * 1024, 256, 0}, + {L"s25fl256s_256k", {0x01, 0x02, 0x19, 0x4d, 0x00}, 5, 256, 256 * 1024, 128, 0}, + {L"s25fl256s_64k", {0x01, 0x02, 0x19, 0x4d, 0x01}, 5, 256, 64 * 1024, 512, 0}, + {L"s25fl512s_256k", {0x01, 0x02, 0x20, 0x4d, 0x00}, 5, 256, 256 * 1024, 256, 0}, + {L"s25fl512s_64k", {0x01, 0x02, 0x20, 0x4d, 0x01}, 5, 256, 64 * 1024, 1024, 0}, + {L"s25fl512s_512k", {0x01, 0x02, 0x20, 0x4f, 0x00}, 5, 256, 256 * 1024, 256, 0}, + /* STMICRO */ + {L"m25p10", {0x20, 0x20, 0x11}, 3, 256, 32 * 1024, 4, 0}, + {L"m25p20", {0x20, 0x20, 0x12}, 3, 256, 64 * 1024, 4, 0}, + {L"m25p40", {0x20, 0x20, 0x13}, 3, 256, 64 * 1024, 8, 0}, + {L"m25p80", {0x20, 0x20, 0x14}, 3, 256, 64 * 1024, 16, 0}, + {L"m25p16", {0x20, 0x20, 0x15}, 3, 256, 64 * 1024, 32, 0}, + {L"m25pE16", {0x20, 0x80, 0x15, 0x10, 0x00}, 5, 256, 64 * 1024, 32, 0}, + {L"m25pX16", {0x20, 0x71, 0x15, 0x10, 0x00}, 5, 256, 64 * 1024, 32, 0}, + {L"m25p32", {0x20, 0x20, 0x16}, 3, 256, 64 * 1024, 64, 0}, + {L"m25p64", {0x20, 0x20, 0x17}, 3, 256, 64 * 1024, 128, 0}, + {L"m25p128", {0x20, 0x20, 0x18}, 3, 256, 256 * 1024, 64, 0}, + {L"m25pX64", {0x20, 0x71, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"n25q016a", {0x20, 0xbb, 0x15}, 3, 256, 64 * 1024, 32, NOR_FLASH_ERASE_4K}, + {L"n25q32", {0x20, 0xba, 0x16}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"n25q32a", {0x20, 0xbb, 0x16}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"n25q64", {0x20, 0xba, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"n25q64a", {0x20, 0xbb, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"n25q128", {0x20, 0xba, 0x18}, 3, 256, 64 * 1024, 256, 0}, + {L"n25q128a", {0x20, 0xbb, 0x18}, 3, 256, 64 * 1024, 256, 0}, + {L"n25q256", {0x20, 0xba, 0x19}, 3, 256, 64 * 1024, 512, NOR_FLASH_ERASE_4K}, + {L"n25q256a", {0x20, 0xbb, 0x19}, 3, 256, 64 * 1024, 512, NOR_FLASH_ERASE_4K}, + {L"n25q512", {0x20, 0xba, 0x20}, 3, 256, 64 * 1024, 1024, NOR_FLASH_WRITE_FSR | NOR_FLASH_ERASE_4K}, + {L"n25q512a", {0x20, 0xbb, 0x20}, 3, 256, 64 * 1024, 1024, NOR_FLASH_WRITE_FSR | NOR_FLASH_ERASE_4K}, + {L"n25q1024", {0x20, 0xba, 0x21}, 3, 256, 64 * 1024, 2048, NOR_FLASH_WRITE_FSR | NOR_FLASH_ERASE_4K}, + {L"n25q1024a", {0x20, 0xbb, 0x21}, 3, 256, 64 * 1024, 2048, NOR_FLASH_WRITE_FSR | NOR_FLASH_ERASE_4K}, + {L"mt25qu02g", {0x20, 0xbb, 0x22}, 3, 256, 64 * 1024, 4096, NOR_FLASH_WRITE_FSR | NOR_FLASH_ERASE_4K}, + {L"mt25ql02g", {0x20, 0xba, 0x22}, 3, 256, 64 * 1024, 4096, NOR_FLASH_WRITE_FSR | NOR_FLASH_ERASE_4K}, + /* SST */ + {L"sst25vf040b", {0xbf, 0x25, 0x8d}, 3, 256, 64 * 1024, 8, NOR_FLASH_ERASE_4K}, + {L"sst25vf080b", {0xbf, 0x25, 0x8e}, 3, 256, 64 * 1024, 16, NOR_FLASH_ERASE_4K}, + {L"sst25vf016b", {0xbf, 0x25, 0x41}, 3, 256, 64 * 1024, 32, NOR_FLASH_ERASE_4K}, + {L"sst25vf032b", {0xbf, 0x25, 0x4a}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"sst25vf064c", {0xbf, 0x25, 0x4b}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"sst25wf512", {0xbf, 0x25, 0x01}, 3, 256, 64 * 1024, 1, NOR_FLASH_ERASE_4K}, + {L"sst25wf010", {0xbf, 0x25, 0x02}, 3, 256, 64 * 1024, 2, NOR_FLASH_ERASE_4K}, + {L"sst25wf020", {0xbf, 0x25, 0x03}, 3, 256, 64 * 1024, 4, NOR_FLASH_ERASE_4K}, + {L"sst25wf040", {0xbf, 0x25, 0x04}, 3, 256, 64 * 1024, 8, NOR_FLASH_ERASE_4K}, + {L"sst25wf040b", {0x62, 0x16, 0x13}, 3, 256, 64 * 1024, 8, NOR_FLASH_ERASE_4K}, + {L"sst25wf080", {0xbf, 0x25, 0x05}, 3, 256, 64 * 1024, 16, NOR_FLASH_ERASE_4K}, + /* WINBOND */ + {L"w25p80", {0xef, 0x20, 0x14}, 3, 256, 64 * 1024, 16, 0}, + {L"w25p16", {0xef, 0x20, 0x15}, 3, 256, 64 * 1024, 32, 0}, + {L"w25p32", {0xef, 0x20, 0x16}, 3, 256, 64 * 1024, 64, 0}, + {L"w25x40", {0xef, 0x30, 0x13}, 3, 256, 64 * 1024, 8, NOR_FLASH_ERASE_4K}, + {L"w25x16", {0xef, 0x30, 0x15}, 3, 256, 64 * 1024, 32, NOR_FLASH_ERASE_4K}, + {L"w25x32", {0xef, 0x30, 0x16}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"w25x64", {0xef, 0x30, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"w25q80bl", {0xef, 0x40, 0x14}, 3, 256, 64 * 1024, 16, NOR_FLASH_ERASE_4K}, + {L"w25q16cl", {0xef, 0x40, 0x15}, 3, 256, 64 * 1024, 32, NOR_FLASH_ERASE_4K}, + {L"w25q32bv", {0xef, 0x40, 0x16}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"w25q64cv", {0xef, 0x40, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"w25q128bv", {0xef, 0x40, 0x18}, 3, 256, 64 * 1024, 256, NOR_FLASH_ERASE_4K}, + {L"w25q256", {0xef, 0x40, 0x19}, 3, 256, 64 * 1024, 512, NOR_FLASH_ERASE_4K}, + {L"w25q80bw", {0xef, 0x50, 0x14}, 3, 256, 64 * 1024, 16, NOR_FLASH_ERASE_4K}, + {L"w25q16dw", {0xef, 0x60, 0x15}, 3, 256, 64 * 1024, 32, NOR_FLASH_ERASE_4K}, + {L"w25q32dw", {0xef, 0x60, 0x16}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"w25q64dw", {0xef, 0x60, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"w25q128fw", {0xef, 0x60, 0x18}, 3, 256, 64 * 1024, 256, NOR_FLASH_ERASE_4K}, + {}, /* Empty entry to terminate the list */ +}; + +/** + Return an allocated copy pool of the NOR flash information structure. + + @param[in] Id Pointer to an array with JEDEC ID obtained + from the NOR flash with READ_ID command + (0x9f) + @param[in out] FlashInfo Pointer to NOR flash information structure + @param[in] AllocateForRuntime A flag specifying a type of a copy pool + allocation (TRUE for runtime, FALSE for + normal) + + @retval EFI_SUCCESS Operation completed successfully + @retval EFI_NOT_FOUND No matching entry in NOR ID table found + @retval EFI_OUT_OF_RESOURCES No pool memory available + +**/ +EFI_STATUS +EFIAPI +NorFlashGetInfo ( + IN UINT8 *Id, + IN OUT NOR_FLASH_INFO **FlashInfo, + IN BOOLEAN AllocateForRuntime + ) +{ + CONST NOR_FLASH_INFO *TmpInfo; + + /* + * Iterate over NorFlashIds table, in order to find matching entry. + */ + TmpInfo = NorFlashIds; + for (; TmpInfo->Name != NULL; TmpInfo++) { + if (CompareMem (TmpInfo->Id, Id, TmpInfo->IdLen) == 0) { + break; + } + } + + /* + * Matching entry was not found. + */ + if (TmpInfo->Name == NULL) { + return EFI_NOT_FOUND; + } + + /* + * Allocate and copy NOR flash information structure. + */ + if (AllocateForRuntime) { + *FlashInfo = AllocateRuntimeCopyPool (sizeof (NOR_FLASH_INFO), TmpInfo); + } else { + *FlashInfo = AllocateCopyPool (sizeof (NOR_FLASH_INFO), TmpInfo); + } + if (FlashInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Print NOR flash information basing on data stored in + the NOR_FLASH_INFO structure. + + @param[in] FlashInfo Pointer to NOR flash information structure + +**/ +VOID +EFIAPI +NorFlashPrintInfo ( + IN NOR_FLASH_INFO *Info + ) +{ + UINTN EraseSize; + + if (Info->Flags & NOR_FLASH_ERASE_4K) { + EraseSize = SIZE_4KB; + } else { + EraseSize = Info->SectorSize; + } + + DEBUG ((DEBUG_ERROR, + "Detected %s SPI NOR flash with page size %d B, erase size %d KB, total %d MB\n", + Info->Name, + Info->PageSize, + EraseSize / 1024, + (Info->SectorSize * Info->SectorCount) / 1024 / 1024)); +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.inf new file mode 100644 index 00000000..71e30a3a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.inf @@ -0,0 +1,27 @@ +/** @file +* +* Copyright (c) 2017 Marvell International Ltd. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = NorFlashInfoLib + FILE_GUID = 6b639c7e-9b53-4e9f-89a3-2e711729709c + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = NorFlashInfoLib + +[Sources] + NorFlashInfoLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + MemoryAllocationLib diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.c new file mode 100644 index 00000000..9e4a4a49 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.c @@ -0,0 +1,35 @@ +/** @file + A hook-in library for: + - MdeModulePkg/Universal/Variable/Pei/VariablePei.inf + - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf + - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf + + Plugging this library instance into one of the above modules makes that + variable service backend wait for another platform module to dynamically + initialize or verify EFI_FIRMWARE_VOLUME_HEADER and VARIABLE_STORE_HEADER in + the non-volatile variable store FVB device. The initialization / verification + is signaled by installing gEdkiiNvVarStoreFormattedGuid into the + phase-matching PPI or protocol database, with a NULL interface. (Note that + installing gEdkiiNvVarStoreFormattedGuid into either the DXE or the MM + protocol database will unblock VariableSmm -- refer to EFI_SECTION_MM_DEPEX + in the PI spec.) + + Copyright (C) 2018, Red Hat, Inc. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +RETURN_STATUS +EFIAPI +NvVarStoreFormattedInitialize ( + VOID + ) +{ + // + // Do nothing, just imbue VariablePei / VariableRuntimeDxe / VariableSmm with + // a PPI or protocol dependency on EDKII_NV_VAR_STORE_FORMATTED_GUID. + // + return RETURN_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf new file mode 100644 index 00000000..4c91b6d8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf @@ -0,0 +1,46 @@ +## @file +# A hook-in library for: +# - MdeModulePkg/Universal/Variable/Pei/VariablePei.inf +# - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf +# - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf +# +# Plugging this library instance into one of the above modules makes that +# variable service backend wait for another platform module to dynamically +# initialize or verify EFI_FIRMWARE_VOLUME_HEADER and VARIABLE_STORE_HEADER in +# the non-volatile variable store FVB device. The initialization / verification +# is signaled by installing gEdkiiNvVarStoreFormattedGuid into the +# phase-matching PPI or protocol database, with a NULL interface. (Note that +# installing gEdkiiNvVarStoreFormattedGuid into either the DXE or the MM +# protocol database will unblock VariableSmm -- refer to EFI_SECTION_MM_DEPEX +# in the PI spec.) +# +# Copyright (C) 2018, Red Hat, Inc. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.27 + BASE_NAME = NvVarStoreFormattedLib + FILE_GUID = 78f76ae8-ae62-4455-8148-c3a7ebaaa3f3 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = NvVarStoreFormattedLib|PEIM DXE_RUNTIME_DRIVER DXE_DRIVER DXE_SMM_DRIVER + CONSTRUCTOR = NvVarStoreFormattedInitialize + +[Sources] + NvVarStoreFormattedLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +# +# The matching DEPEX section below will generate the EFI_SECTION_PEI_DEPEX, +# EFI_SECTION_DXE_DEPEX or EFI_SECTION_MM_DEPEX leaf section for the PEIM +# (EFI_FV_FILETYPE_PEIM), DXE_RUNTIME_DRIVER/DXE_DRIVER (EFI_FV_FILETYPE_DRIVER), or +# DXE_SMM_DRIVER (EFI_FV_FILETYPE_MM) module, respectively. +# +[Depex.common.PEIM, Depex.common.DXE_RUNTIME_DRIVER, Depex.common.DXE_DRIVER, Depex.common.DXE_SMM_DRIVER] + gEdkiiNvVarStoreFormattedGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.c new file mode 100644 index 00000000..54603e90 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.c @@ -0,0 +1,30 @@ +/** @file + A hook-in library for MdeModulePkg/Universal/Acpi/AcpiTableDxe. + + Plugging this library instance into AcpiTableDxe makes + EFI_ACPI_TABLE_PROTOCOL and (if enabled) EFI_ACPI_SDT_PROTOCOL depend on the + platform's dynamic decision whether to expose an ACPI-based hardware + description to the operating system. + + Universal and platform specific DXE drivers that produce ACPI tables depend + on EFI_ACPI_TABLE_PROTOCOL / EFI_ACPI_SDT_PROTOCOL in turn. + + Copyright (C) 2017, Red Hat, Inc. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +RETURN_STATUS +EFIAPI +PlatformHasAcpiInitialize ( + VOID + ) +{ + // + // Do nothing, just imbue AcpiTableDxe with a protocol dependency on + // EDKII_PLATFORM_HAS_ACPI_GUID. + // + return RETURN_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.inf new file mode 100644 index 00000000..71d0dabb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.inf @@ -0,0 +1,34 @@ +## @file +# A hook-in library for MdeModulePkg/Universal/Acpi/AcpiTableDxe. +# +# Plugging this library instance into AcpiTableDxe makes +# EFI_ACPI_TABLE_PROTOCOL and (if enabled) EFI_ACPI_SDT_PROTOCOL depend on the +# platform's dynamic decision whether to expose an ACPI-based hardware +# description to the operating system. +# +# Universal and platform specific DXE drivers that produce ACPI tables depend +# on EFI_ACPI_TABLE_PROTOCOL / EFI_ACPI_SDT_PROTOCOL in turn. +# +# Copyright (C) 2017, Red Hat, Inc. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.25 + BASE_NAME = PlatformHasAcpiLib + FILE_GUID = 29beb028-0958-447b-be0a-12229235d77d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformHasAcpiLib|DXE_DRIVER + CONSTRUCTOR = PlatformHasAcpiInitialize + +[Sources] + PlatformHasAcpiLib.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[Depex] + gEdkiiPlatformHasAcpiGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c new file mode 100644 index 00000000..f5beb66f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c @@ -0,0 +1,255 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +#define PRE_PI_EXTRACT_GUIDED_SECTION_DATA_GUID { 0x385A982C, 0x2F49, 0x4043, { 0xA5, 0x1E, 0x49, 0x01, 0x02, 0x5C, 0x8B, 0x6B }} + +typedef struct { + UINT32 NumberOfExtractHandler; + GUID *ExtractHandlerGuidTable; + EXTRACT_GUIDED_SECTION_DECODE_HANDLER *ExtractDecodeHandlerTable; + EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER *ExtractGetInfoHandlerTable; +} PRE_PI_EXTRACT_GUIDED_SECTION_DATA; + +PRE_PI_EXTRACT_GUIDED_SECTION_DATA * +GetSavedData ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + GUID SavedDataGuid = PRE_PI_EXTRACT_GUIDED_SECTION_DATA_GUID; + + GuidHob = GetFirstGuidHob(&SavedDataGuid); + GuidHob++; + + return (PRE_PI_EXTRACT_GUIDED_SECTION_DATA *)GuidHob; +} + +RETURN_STATUS +EFIAPI +ExtractGuidedSectionRegisterHandlers ( + IN CONST GUID *SectionGuid, + IN EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER GetInfoHandler, + IN EXTRACT_GUIDED_SECTION_DECODE_HANDLER DecodeHandler + ) +{ + PRE_PI_EXTRACT_GUIDED_SECTION_DATA *SavedData; + UINT32 Index; + // + // Check input parameter. + // + if (SectionGuid == NULL) { + return RETURN_INVALID_PARAMETER; + } + + SavedData = GetSavedData(); + + // + // Search the match registered GetInfo handler for the input guided section. + // + for (Index = 0; Index < SavedData->NumberOfExtractHandler; Index ++) { + if (CompareGuid (&SavedData->ExtractHandlerGuidTable[Index], SectionGuid)) { + break; + } + } + + // + // If the guided handler has been registered before, only update its handler. + // + if (Index < SavedData->NumberOfExtractHandler) { + SavedData->ExtractDecodeHandlerTable [Index] = DecodeHandler; + SavedData->ExtractGetInfoHandlerTable [Index] = GetInfoHandler; + return RETURN_SUCCESS; + } + + // + // Check the global table is enough to contain new Handler. + // + if (SavedData->NumberOfExtractHandler >= PcdGet32 (PcdMaximumGuidedExtractHandler)) { + return RETURN_OUT_OF_RESOURCES; + } + + // + // Register new Handler and guid value. + // + CopyGuid (&SavedData->ExtractHandlerGuidTable [SavedData->NumberOfExtractHandler], SectionGuid); + SavedData->ExtractDecodeHandlerTable [SavedData->NumberOfExtractHandler] = DecodeHandler; + SavedData->ExtractGetInfoHandlerTable [SavedData->NumberOfExtractHandler++] = GetInfoHandler; + + return RETURN_SUCCESS; +} + +UINTN +EFIAPI +ExtractGuidedSectionGetGuidList ( + IN OUT GUID **ExtractHandlerGuidTable + ) +{ + PRE_PI_EXTRACT_GUIDED_SECTION_DATA *SavedData; + + ASSERT(ExtractHandlerGuidTable != NULL); + + SavedData = GetSavedData(); + + *ExtractHandlerGuidTable = SavedData->ExtractHandlerGuidTable; + return SavedData->NumberOfExtractHandler; +} + +RETURN_STATUS +EFIAPI +ExtractGuidedSectionGetInfo ( + IN CONST VOID *InputSection, + OUT UINT32 *OutputBufferSize, + OUT UINT32 *ScratchBufferSize, + OUT UINT16 *SectionAttribute + ) +{ + PRE_PI_EXTRACT_GUIDED_SECTION_DATA *SavedData; + UINT32 Index; + EFI_GUID *SectionDefinitionGuid; + + if (InputSection == NULL) { + return RETURN_INVALID_PARAMETER; + } + + ASSERT (OutputBufferSize != NULL); + ASSERT (ScratchBufferSize != NULL); + ASSERT (SectionAttribute != NULL); + + SavedData = GetSavedData(); + + if (IS_SECTION2 (InputSection)) { + SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid); + } else { + SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid); + } + + // + // Search the match registered GetInfo handler for the input guided section. + // + for (Index = 0; Index < SavedData->NumberOfExtractHandler; Index ++) { + if (CompareGuid (&SavedData->ExtractHandlerGuidTable[Index], SectionDefinitionGuid)) { + break; + } + } + + // + // Not found, the input guided section is not supported. + // + if (Index == SavedData->NumberOfExtractHandler) { + return RETURN_INVALID_PARAMETER; + } + + // + // Call the match handler to getinfo for the input section data. + // + return SavedData->ExtractGetInfoHandlerTable [Index] ( + InputSection, + OutputBufferSize, + ScratchBufferSize, + SectionAttribute + ); +} + +RETURN_STATUS +EFIAPI +ExtractGuidedSectionDecode ( + IN CONST VOID *InputSection, + OUT VOID **OutputBuffer, + OUT VOID *ScratchBuffer, OPTIONAL + OUT UINT32 *AuthenticationStatus + ) +{ + PRE_PI_EXTRACT_GUIDED_SECTION_DATA *SavedData; + UINT32 Index; + EFI_GUID *SectionDefinitionGuid; + + if (InputSection == NULL) { + return RETURN_INVALID_PARAMETER; + } + + ASSERT (OutputBuffer != NULL); + ASSERT (AuthenticationStatus != NULL); + + SavedData = GetSavedData(); + + if (IS_SECTION2 (InputSection)) { + SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid); + } else { + SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid); + } + + // + // Search the match registered GetInfo handler for the input guided section. + // + for (Index = 0; Index < SavedData->NumberOfExtractHandler; Index ++) { + if (CompareGuid (&SavedData->ExtractHandlerGuidTable[Index], SectionDefinitionGuid)) { + break; + } + } + + // + // Not found, the input guided section is not supported. + // + if (Index == SavedData->NumberOfExtractHandler) { + return RETURN_INVALID_PARAMETER; + } + + // + // Call the match handler to getinfo for the input section data. + // + return SavedData->ExtractDecodeHandlerTable [Index] ( + InputSection, + OutputBuffer, + ScratchBuffer, + AuthenticationStatus + ); +} + +RETURN_STATUS +EFIAPI +ExtractGuidedSectionLibConstructor ( + VOID + ) +{ + PRE_PI_EXTRACT_GUIDED_SECTION_DATA SavedData; + GUID HobGuid = PRE_PI_EXTRACT_GUIDED_SECTION_DATA_GUID; + + // + // Allocate global pool space to store the registered handler and its guid value. + // + SavedData.ExtractHandlerGuidTable = (GUID *)AllocatePool(PcdGet32(PcdMaximumGuidedExtractHandler) * sizeof(GUID)); + if (SavedData.ExtractHandlerGuidTable == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + + SavedData.ExtractDecodeHandlerTable = (EXTRACT_GUIDED_SECTION_DECODE_HANDLER *)AllocatePool(PcdGet32(PcdMaximumGuidedExtractHandler) * sizeof(EXTRACT_GUIDED_SECTION_DECODE_HANDLER)); + if (SavedData.ExtractDecodeHandlerTable == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + + SavedData.ExtractGetInfoHandlerTable = (EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER *)AllocatePool(PcdGet32(PcdMaximumGuidedExtractHandler) * sizeof(EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER)); + if (SavedData.ExtractGetInfoHandlerTable == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + + // + // the initialized number is Zero. + // + SavedData.NumberOfExtractHandler = 0; + + BuildGuidDataHob(&HobGuid, &SavedData, sizeof(SavedData)); + + return RETURN_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf new file mode 100644 index 00000000..52966c70 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf @@ -0,0 +1,30 @@ +#/** @file +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PrePiExtractGuidedSectionLib + FILE_GUID = 36F6E94E-6E8E-488E-89A4-7AD911C5AFB1 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ExtractGuidedSectionLib + + CONSTRUCTOR = ExtractGuidedSectionLibConstructor + +[Sources.common] + PrePiExtractGuidedSectionLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + +[FixedPcd.common] + gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/Hob.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/Hob.c new file mode 100644 index 00000000..ab9c3b8b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/Hob.c @@ -0,0 +1,849 @@ +/** @file + + Copyright (c) 2010, Apple Inc. All rights reserved.
+ Copyright (c) 2017, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +VOID +BuildMemoryTypeInformationHob ( + VOID + ); + +/** + Returns the pointer to the HOB list. + + This function returns the pointer to first HOB in the list. + + @return The pointer to the HOB list. + +**/ +VOID * +EFIAPI +GetHobList ( + VOID + ) +{ + return PrePeiGetHobList (); +} + + + +/** + Updates the pointer to the HOB list. + + @param HobList Hob list pointer to store + +**/ +EFI_STATUS +EFIAPI +SetHobList ( + IN VOID *HobList + ) +{ + return PrePeiSetHobList (HobList); +} + +/** + + +**/ +EFI_HOB_HANDOFF_INFO_TABLE* +HobConstructor ( + IN VOID *EfiMemoryBegin, + IN UINTN EfiMemoryLength, + IN VOID *EfiFreeMemoryBottom, + IN VOID *EfiFreeMemoryTop + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *Hob; + EFI_HOB_GENERIC_HEADER *HobEnd; + + Hob = EfiFreeMemoryBottom; + HobEnd = (EFI_HOB_GENERIC_HEADER *)(Hob+1); + + Hob->Header.HobType = EFI_HOB_TYPE_HANDOFF; + Hob->Header.HobLength = sizeof(EFI_HOB_HANDOFF_INFO_TABLE); + Hob->Header.Reserved = 0; + + HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; + HobEnd->HobLength = sizeof(EFI_HOB_GENERIC_HEADER); + HobEnd->Reserved = 0; + + Hob->Version = EFI_HOB_HANDOFF_TABLE_VERSION; + Hob->BootMode = BOOT_WITH_FULL_CONFIGURATION; + + Hob->EfiMemoryTop = (UINTN)EfiMemoryBegin + EfiMemoryLength; + Hob->EfiMemoryBottom = (UINTN)EfiMemoryBegin; + Hob->EfiFreeMemoryTop = (UINTN)EfiFreeMemoryTop; + Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS)(UINTN)(HobEnd+1); + Hob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS)(UINTN)HobEnd; + + return Hob; +} + +VOID * +CreateHob ( + IN UINT16 HobType, + IN UINT16 HobLength + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob; + EFI_HOB_GENERIC_HEADER *HobEnd; + EFI_PHYSICAL_ADDRESS FreeMemory; + VOID *Hob; + + HandOffHob = GetHobList (); + + HobLength = (UINT16)((HobLength + 0x7) & (~0x7)); + + FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom; + + if (FreeMemory < HobLength) { + return NULL; + } + + Hob = (VOID*) (UINTN) HandOffHob->EfiEndOfHobList; + ((EFI_HOB_GENERIC_HEADER*) Hob)->HobType = HobType; + ((EFI_HOB_GENERIC_HEADER*) Hob)->HobLength = HobLength; + ((EFI_HOB_GENERIC_HEADER*) Hob)->Reserved = 0; + + HobEnd = (EFI_HOB_GENERIC_HEADER*) ((UINTN)Hob + HobLength); + HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd; + + HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; + HobEnd->HobLength = sizeof(EFI_HOB_GENERIC_HEADER); + HobEnd->Reserved = 0; + HobEnd++; + HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd; + + return Hob; +} + +/** + Builds a HOB that describes a chunk of system memory. + + This function builds a HOB that describes a chunk of system memory. + If there is no additional space for HOB creation, then ASSERT(). + + @param ResourceType The type of resource described by this HOB. + @param ResourceAttribute The resource attributes of the memory described by this HOB. + @param PhysicalStart The 64 bit physical address of memory described by this HOB. + @param NumberOfBytes The length of the memory described by this HOB in bytes. + +**/ +VOID +EFIAPI +BuildResourceDescriptorHob ( + IN EFI_RESOURCE_TYPE ResourceType, + IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute, + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes + ) +{ + EFI_HOB_RESOURCE_DESCRIPTOR *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)); + ASSERT(Hob != NULL); + + Hob->ResourceType = ResourceType; + Hob->ResourceAttribute = ResourceAttribute; + Hob->PhysicalStart = PhysicalStart; + Hob->ResourceLength = NumberOfBytes; +} + +VOID +EFIAPI +BuildFvHobs ( + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes, + IN EFI_RESOURCE_ATTRIBUTE_TYPE *ResourceAttribute + ) +{ + + EFI_RESOURCE_ATTRIBUTE_TYPE Resource; + + BuildFvHob (PhysicalStart, NumberOfBytes); + + if (ResourceAttribute == NULL) { + Resource = (EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_TESTED | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE); + } else { + Resource = *ResourceAttribute; + } + + BuildResourceDescriptorHob (EFI_RESOURCE_FIRMWARE_DEVICE, Resource, PhysicalStart, NumberOfBytes); +} + +/** + Returns the next instance of a HOB type from the starting HOB. + + This function searches the first instance of a HOB type from the starting HOB pointer. + If there does not exist such HOB type from the starting HOB pointer, it will return NULL. + In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer + unconditionally: it returns HobStart back if HobStart itself meets the requirement; + caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + If HobStart is NULL, then ASSERT(). + + @param Type The HOB type to return. + @param HobStart The starting HOB pointer to search from. + + @return The next instance of a HOB type from the starting HOB. + +**/ +VOID * +EFIAPI +GetNextHob ( + IN UINT16 Type, + IN CONST VOID *HobStart + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + ASSERT (HobStart != NULL); + + Hob.Raw = (UINT8 *) HobStart; + // + // Parse the HOB list until end of list or matching type is found. + // + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType == Type) { + return Hob.Raw; + } + Hob.Raw = GET_NEXT_HOB (Hob); + } + return NULL; +} + + + +/** + Returns the first instance of a HOB type among the whole HOB list. + + This function searches the first instance of a HOB type among the whole HOB list. + If there does not exist such HOB type in the HOB list, it will return NULL. + + @param Type The HOB type to return. + + @return The next instance of a HOB type from the starting HOB. + +**/ +VOID * +EFIAPI +GetFirstHob ( + IN UINT16 Type + ) +{ + VOID *HobList; + + HobList = GetHobList (); + return GetNextHob (Type, HobList); +} + + +/** + This function searches the first instance of a HOB from the starting HOB pointer. + Such HOB should satisfy two conditions: + its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid. + If there does not exist such HOB from the starting HOB pointer, it will return NULL. + Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () + to extract the data section and its size info respectively. + In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer + unconditionally: it returns HobStart back if HobStart itself meets the requirement; + caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + If Guid is NULL, then ASSERT(). + If HobStart is NULL, then ASSERT(). + + @param Guid The GUID to match with in the HOB list. + @param HobStart A pointer to a Guid. + + @return The next instance of the matched GUID HOB from the starting HOB. + +**/ +VOID * +EFIAPI +GetNextGuidHob ( + IN CONST EFI_GUID *Guid, + IN CONST VOID *HobStart + ){ + EFI_PEI_HOB_POINTERS GuidHob; + + GuidHob.Raw = (UINT8 *) HobStart; + while ((GuidHob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GuidHob.Raw)) != NULL) { + if (CompareGuid (Guid, &GuidHob.Guid->Name)) { + break; + } + GuidHob.Raw = GET_NEXT_HOB (GuidHob); + } + return GuidHob.Raw; +} + + +/** + This function searches the first instance of a HOB among the whole HOB list. + Such HOB should satisfy two conditions: + its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid. + If there does not exist such HOB from the starting HOB pointer, it will return NULL. + Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () + to extract the data section and its size info respectively. + If Guid is NULL, then ASSERT(). + + @param Guid The GUID to match with in the HOB list. + + @return The first instance of the matched GUID HOB among the whole HOB list. + +**/ +VOID * +EFIAPI +GetFirstGuidHob ( + IN CONST EFI_GUID *Guid + ) +{ + VOID *HobList; + + HobList = GetHobList (); + return GetNextGuidHob (Guid, HobList); +} + + +/** + Get the Boot Mode from the HOB list. + + This function returns the system boot mode information from the + PHIT HOB in HOB list. + + @param VOID + + @return The Boot Mode. + +**/ +EFI_BOOT_MODE +EFIAPI +GetBootMode ( + VOID + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = GetHobList (); + return Hob.HandoffInformationTable->BootMode; +} + + +/** + Get the Boot Mode from the HOB list. + + This function returns the system boot mode information from the + PHIT HOB in HOB list. + + @param VOID + + @return The Boot Mode. + +**/ +EFI_STATUS +EFIAPI +SetBootMode ( + IN EFI_BOOT_MODE BootMode + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = GetHobList (); + Hob.HandoffInformationTable->BootMode = BootMode; + return BootMode; +} + +/** + Builds a HOB for a loaded PE32 module. + + This function builds a HOB for a loaded PE32 module. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If ModuleName is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + + @param ModuleName The GUID File Name of the module. + @param MemoryAllocationModule The 64 bit physical address of the module. + @param ModuleLength The length of the module in bytes. + @param EntryPoint The 64 bit physical address of the module entry point. + +**/ +VOID +EFIAPI +BuildModuleHob ( + IN CONST EFI_GUID *ModuleName, + IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule, + IN UINT64 ModuleLength, + IN EFI_PHYSICAL_ADDRESS EntryPoint + ) +{ + EFI_HOB_MEMORY_ALLOCATION_MODULE *Hob; + + ASSERT (((MemoryAllocationModule & (EFI_PAGE_SIZE - 1)) == 0) && + ((ModuleLength & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE)); + + CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid); + Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule; + Hob->MemoryAllocationHeader.MemoryLength = ModuleLength; + Hob->MemoryAllocationHeader.MemoryType = EfiBootServicesCode; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->MemoryAllocationHeader.Reserved, sizeof (Hob->MemoryAllocationHeader.Reserved)); + + CopyGuid (&Hob->ModuleName, ModuleName); + Hob->EntryPoint = EntryPoint; +} + +/** + Builds a GUID HOB with a certain data length. + + This function builds a customized HOB tagged with a GUID for identification + and returns the start address of GUID HOB data so that caller can fill the customized data. + The HOB Header and Name field is already stripped. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If Guid is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + + @param Guid The GUID to tag the customized HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @return The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidHob ( + IN CONST EFI_GUID *Guid, + IN UINTN DataLength + ) +{ + EFI_HOB_GUID_TYPE *Hob; + + // + // Make sure that data length is not too long. + // + ASSERT (DataLength <= (0xffff - sizeof (EFI_HOB_GUID_TYPE))); + + Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16) (sizeof (EFI_HOB_GUID_TYPE) + DataLength)); + CopyGuid (&Hob->Name, Guid); + return Hob + 1; +} + + +/** + Copies a data buffer to a newly-built HOB. + + This function builds a customized HOB tagged with a GUID for identification, + copies the input data to the HOB data field and returns the start address of the GUID HOB data. + The HOB Header and Name field is already stripped. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If Guid is NULL, then ASSERT(). + If Data is NULL and DataLength > 0, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + + @param Guid The GUID to tag the customized HOB. + @param Data The data to be copied into the data field of the GUID HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @return The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidDataHob ( + IN CONST EFI_GUID *Guid, + IN VOID *Data, + IN UINTN DataLength + ) +{ + VOID *HobData; + + ASSERT (Data != NULL || DataLength == 0); + + HobData = BuildGuidHob (Guid, DataLength); + + return CopyMem (HobData, Data, DataLength); +} + + +/** + Builds a Firmware Volume HOB. + + This function builds a Firmware Volume HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + +**/ +VOID +EFIAPI +BuildFvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + EFI_HOB_FIRMWARE_VOLUME *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV, sizeof (EFI_HOB_FIRMWARE_VOLUME)); + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +} + + +/** + Builds a EFI_HOB_TYPE_FV2 HOB. + + This function builds a EFI_HOB_TYPE_FV2 HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + @param FvName The name of the Firmware Volume. + @param FileName The name of the file. + +**/ +VOID +EFIAPI +BuildFv2Hob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN CONST EFI_GUID *FvName, + IN CONST EFI_GUID *FileName + ) +{ + EFI_HOB_FIRMWARE_VOLUME2 *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV2, sizeof (EFI_HOB_FIRMWARE_VOLUME2)); + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; + CopyGuid (&Hob->FvName, FvName); + CopyGuid (&Hob->FileName, FileName); +} + +/** + Builds a EFI_HOB_TYPE_FV3 HOB. + + This function builds a EFI_HOB_TYPE_FV3 HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + @param AuthenticationStatus The authentication status. + @param ExtractedFv TRUE if the FV was extracted as a file within + another firmware volume. FALSE otherwise. + @param FvName The name of the Firmware Volume. + Valid only if IsExtractedFv is TRUE. + @param FileName The name of the file. + Valid only if IsExtractedFv is TRUE. + +**/ +VOID +EFIAPI +BuildFv3Hob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT32 AuthenticationStatus, + IN BOOLEAN ExtractedFv, + IN CONST EFI_GUID *FvName, OPTIONAL + IN CONST EFI_GUID *FileName OPTIONAL + ) +{ + EFI_HOB_FIRMWARE_VOLUME3 *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV3, sizeof (EFI_HOB_FIRMWARE_VOLUME3)); + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; + Hob->AuthenticationStatus = AuthenticationStatus; + Hob->ExtractedFv = ExtractedFv; + if (ExtractedFv) { + CopyGuid (&Hob->FvName, FvName); + CopyGuid (&Hob->FileName, FileName); + } +} + +/** + Builds a Capsule Volume HOB. + + This function builds a Capsule Volume HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Capsule Volume. + @param Length The size of the Capsule Volume in bytes. + +**/ +VOID +EFIAPI +BuildCvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + ASSERT (FALSE); +} + + +/** + Builds a HOB for the CPU. + + This function builds a HOB for the CPU. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param SizeOfMemorySpace The maximum physical memory addressability of the processor. + @param SizeOfIoSpace The maximum physical I/O addressability of the processor. + +**/ +VOID +EFIAPI +BuildCpuHob ( + IN UINT8 SizeOfMemorySpace, + IN UINT8 SizeOfIoSpace + ) +{ + EFI_HOB_CPU *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_CPU, sizeof (EFI_HOB_CPU)); + + Hob->SizeOfMemorySpace = SizeOfMemorySpace; + Hob->SizeOfIoSpace = SizeOfIoSpace; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->Reserved, sizeof (Hob->Reserved)); +} + + +/** + Builds a HOB for the Stack. + + This function builds a HOB for the stack. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the Stack. + @param Length The length of the stack in bytes. + +**/ +VOID +EFIAPI +BuildStackHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + EFI_HOB_MEMORY_ALLOCATION_STACK *Hob; + + ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) && + ((Length & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_STACK)); + + CopyGuid (&(Hob->AllocDescriptor.Name), &gEfiHobMemoryAllocStackGuid); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; + Hob->AllocDescriptor.MemoryLength = Length; + Hob->AllocDescriptor.MemoryType = EfiBootServicesData; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved)); +} + + +/** + Update the Stack Hob if the stack has been moved + + @param BaseAddress The 64 bit physical address of the Stack. + @param Length The length of the stack in bytes. + +**/ +VOID +UpdateStackHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = GetHobList (); + while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) { + if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &(Hob.MemoryAllocationStack->AllocDescriptor.Name))) { + // + // Build a new memory allocation HOB with old stack info with EfiConventionalMemory type + // to be reclaimed by DXE core. + // + BuildMemoryAllocationHob ( + Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress, + Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength, + EfiConventionalMemory + ); + // + // Update the BSP Stack Hob to reflect the new stack info. + // + Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress = BaseAddress; + Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength = Length; + break; + } + Hob.Raw = GET_NEXT_HOB (Hob); + } +} + + + +/** + Builds a HOB for the memory allocation. + + This function builds a HOB for the memory allocation. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the memory. + @param Length The length of the memory allocation in bytes. + @param MemoryType Type of memory allocated by this HOB. + +**/ +VOID +EFIAPI +BuildMemoryAllocationHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_MEMORY_TYPE MemoryType + ) +{ + EFI_HOB_MEMORY_ALLOCATION *Hob; + + ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) && + ((Length & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION)); + + ZeroMem (&(Hob->AllocDescriptor.Name), sizeof (EFI_GUID)); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; + Hob->AllocDescriptor.MemoryLength = Length; + Hob->AllocDescriptor.MemoryType = MemoryType; + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved)); +} + + + +VOID +EFIAPI +BuildExtractSectionHob ( + IN EFI_GUID *Guid, + IN EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER SectionGetInfo, + IN EXTRACT_GUIDED_SECTION_DECODE_HANDLER SectionExtraction + ) +{ + EXTRACT_SECTION_DATA Data; + + Data.SectionGetInfo = SectionGetInfo; + Data.SectionExtraction = SectionExtraction; + BuildGuidDataHob (Guid, &Data, sizeof (Data)); +} + +PE_COFF_LOADER_PROTOCOL gPeCoffProtocol = { + PeCoffLoaderGetImageInfo, + PeCoffLoaderLoadImage, + PeCoffLoaderRelocateImage, + PeCoffLoaderImageReadFromMemory, + PeCoffLoaderRelocateImageForRuntime, + PeCoffLoaderUnloadImage +}; + + + +VOID +EFIAPI +BuildPeCoffLoaderHob ( + VOID + ) +{ + VOID *Ptr; + + Ptr = &gPeCoffProtocol; + BuildGuidDataHob (&gPeCoffLoaderProtocolGuid, &Ptr, sizeof (VOID *)); +} + +// May want to put this into a library so you only need the PCD settings if you are using the feature? +VOID +BuildMemoryTypeInformationHob ( + VOID + ) +{ + EFI_MEMORY_TYPE_INFORMATION Info[10]; + + Info[0].Type = EfiACPIReclaimMemory; + Info[0].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiACPIReclaimMemory); + Info[1].Type = EfiACPIMemoryNVS; + Info[1].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiACPIMemoryNVS); + Info[2].Type = EfiReservedMemoryType; + Info[2].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiReservedMemoryType); + Info[3].Type = EfiRuntimeServicesData; + Info[3].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiRuntimeServicesData); + Info[4].Type = EfiRuntimeServicesCode; + Info[4].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiRuntimeServicesCode); + Info[5].Type = EfiBootServicesCode; + Info[5].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiBootServicesCode); + Info[6].Type = EfiBootServicesData; + Info[6].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiBootServicesData); + Info[7].Type = EfiLoaderCode; + Info[7].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiLoaderCode); + Info[8].Type = EfiLoaderData; + Info[8].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiLoaderData); + + // Terminator for the list + Info[9].Type = EfiMaxMemoryType; + Info[9].NumberOfPages = 0; + + + BuildGuidDataHob (&gEfiMemoryTypeInformationGuid, &Info, sizeof (Info)); +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf new file mode 100644 index 00000000..b9103a93 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf @@ -0,0 +1,57 @@ +#/** @file +# Hob lib that does not contain the APIs as they are already in the PrePiLib +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PrePiHobLib + FILE_GUID = AEF7D85A-6A91-4ACD-9A28-193DEFB325FB + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = HobLib + + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources.common] + Hob.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + PrePiHobListPointerLib + +[Guids] + gEfiHobMemoryAllocModuleGuid + gEfiHobMemoryAllocStackGuid + +[FixedPcd.common] + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData + +[FeaturePcd] + gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/FwVol.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/FwVol.c new file mode 100644 index 00000000..0ecd211c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/FwVol.c @@ -0,0 +1,878 @@ +/** @file + Implementation of the 6 PEI Ffs (FV) APIs in library form. + + This code only knows about a FV if it has a EFI_HOB_TYPE_FV entry in the HOB list + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + + +#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \ + (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)) + + +/** + Returns the highest bit set of the State field + + @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY + in the Attributes field. + @param FfsHeader Pointer to FFS File Header + + + @retval the highest bit in the State field + +**/ +STATIC +EFI_FFS_FILE_STATE +GetFileState( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +{ + EFI_FFS_FILE_STATE FileState; + EFI_FFS_FILE_STATE HighestBit; + + FileState = FfsHeader->State; + + if (ErasePolarity != 0) { + FileState = (EFI_FFS_FILE_STATE)~FileState; + } + + HighestBit = 0x80; + while (HighestBit != 0 && (HighestBit & FileState) == 0) { + HighestBit >>= 1; + } + + return HighestBit; +} + + +/** + Calculates the checksum of the header of a file. + The header is a zero byte checksum, so zero means header is good + + @param FfsHeader Pointer to FFS File Header + + @retval Checksum of the header + +**/ +STATIC +UINT8 +CalculateHeaderChecksum ( + IN EFI_FFS_FILE_HEADER *FileHeader + ) +{ + UINT8 *Ptr; + UINTN Index; + UINT8 Sum; + + Sum = 0; + Ptr = (UINT8 *)FileHeader; + + for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER) - 3; Index += 4) { + Sum = (UINT8)(Sum + Ptr[Index]); + Sum = (UINT8)(Sum + Ptr[Index+1]); + Sum = (UINT8)(Sum + Ptr[Index+2]); + Sum = (UINT8)(Sum + Ptr[Index+3]); + } + + for (; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) { + Sum = (UINT8)(Sum + Ptr[Index]); + } + + // + // State field (since this indicates the different state of file). + // + Sum = (UINT8)(Sum - FileHeader->State); + // + // Checksum field of the file is not part of the header checksum. + // + Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File); + + return Sum; +} + + +/** + Given a FileHandle return the VolumeHandle + + @param FileHandle File handle to look up + @param VolumeHandle Match for FileHandle + + @retval TRUE VolumeHandle is valid + +**/ +STATIC +BOOLEAN +EFIAPI +FileHandleToVolume ( + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT EFI_PEI_FV_HANDLE *VolumeHandle + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = GetHobList (); + if (Hob.Raw == NULL) { + return FALSE; + } + + do { + Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw); + if (Hob.Raw != NULL) { + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(Hob.FirmwareVolume->BaseAddress); + if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) && \ + ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) { + *VolumeHandle = (EFI_PEI_FV_HANDLE)FwVolHeader; + return TRUE; + } + + Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob)); + } + } while (Hob.Raw != NULL); + + return FALSE; +} + + + +/** + Given the input file pointer, search for the next matching file in the + FFS volume as defined by SearchType. The search starts from FileHeader inside + the Firmware Volume defined by FwVolHeader. + + @param FileHandle File handle to look up + @param VolumeHandle Match for FileHandle + + +**/ +EFI_STATUS +FindFileEx ( + IN CONST EFI_PEI_FV_HANDLE FvHandle, + IN CONST EFI_GUID *FileName, OPTIONAL + IN EFI_FV_FILETYPE SearchType, + IN OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FFS_FILE_HEADER **FileHeader; + EFI_FFS_FILE_HEADER *FfsFileHeader; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo; + UINT32 FileLength; + UINT32 FileOccupiedSize; + UINT32 FileOffset; + UINT64 FvLength; + UINT8 ErasePolarity; + UINT8 FileState; + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvHandle; + FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle; + + FvLength = FwVolHeader->FvLength; + if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) { + ErasePolarity = 1; + } else { + ErasePolarity = 0; + } + + // + // If FileHeader is not specified (NULL) or FileName is not NULL, + // start with the first file in the firmware volume. Otherwise, + // start from the FileHeader. + // + if ((*FileHeader == NULL) || (FileName != NULL)) { + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength); + if (FwVolHeader->ExtHeaderOffset != 0) { + FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)FwVolHeader) + FwVolHeader->ExtHeaderOffset); + FfsFileHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FwVolExHeaderInfo) + FwVolExHeaderInfo->ExtHeaderSize); + } + } else { + // + // Length is 24 bits wide so mask upper 8 bits + // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF; + FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8); + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize); + } + + // FFS files begin with a header that is aligned on an 8-byte boundary + FfsFileHeader = ALIGN_POINTER (FfsFileHeader, 8); + + FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader); + ASSERT (FileOffset <= 0xFFFFFFFF); + + while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) { + // + // Get FileState which is the highest bit of the State + // + FileState = GetFileState (ErasePolarity, FfsFileHeader); + + switch (FileState) { + + case EFI_FILE_HEADER_INVALID: + FileOffset += sizeof(EFI_FFS_FILE_HEADER); + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER)); + break; + + case EFI_FILE_DATA_VALID: + case EFI_FILE_MARKED_FOR_UPDATE: + if (CalculateHeaderChecksum (FfsFileHeader) != 0) { + ASSERT (FALSE); + *FileHeader = NULL; + return EFI_NOT_FOUND; + } + + FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); + + if (FileName != NULL) { + if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) { + *FileHeader = FfsFileHeader; + return EFI_SUCCESS; + } + } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) && + (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) { + *FileHeader = FfsFileHeader; + return EFI_SUCCESS; + } + + FileOffset += FileOccupiedSize; + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); + break; + + case EFI_FILE_DELETED: + FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); + FileOffset += FileOccupiedSize; + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); + break; + + default: + *FileHeader = NULL; + return EFI_NOT_FOUND; + } + } + + + *FileHeader = NULL; + return EFI_NOT_FOUND; +} + + +/** + Go through the file to search SectionType section, + when meeting an encapsuled section. + + @param SectionType - Filter to find only section of this type. + @param Section - From where to search. + @param SectionSize - The file size to search. + @param OutputBuffer - Pointer to the section to search. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FfsProcessSection ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_COMMON_SECTION_HEADER *Section, + IN UINTN SectionSize, + OUT VOID **OutputBuffer + ) +{ + EFI_STATUS Status; + UINT32 SectionLength; + UINT32 ParsedLength; + EFI_COMPRESSION_SECTION *CompressionSection; + EFI_COMPRESSION_SECTION2 *CompressionSection2; + UINT32 DstBufferSize; + VOID *ScratchBuffer; + UINT32 ScratchBufferSize; + VOID *DstBuffer; + UINT16 SectionAttribute; + UINT32 AuthenticationStatus; + CHAR8 *CompressedData; + UINTN CompressedDataLength; + + + *OutputBuffer = NULL; + ParsedLength = 0; + Status = EFI_NOT_FOUND; + while (ParsedLength < SectionSize) { + if (IS_SECTION2 (Section)) { + ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF); + } + + if (Section->Type == SectionType) { + if (IS_SECTION2 (Section)) { + *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2)); + } else { + *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER)); + } + + return EFI_SUCCESS; + } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) { + + if (Section->Type == EFI_SECTION_COMPRESSION) { + if (IS_SECTION2 (Section)) { + CompressionSection2 = (EFI_COMPRESSION_SECTION2 *) Section; + SectionLength = SECTION2_SIZE (Section); + + if (CompressionSection2->CompressionType != EFI_STANDARD_COMPRESSION) { + return EFI_UNSUPPORTED; + } + + CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION2 *) Section + 1); + CompressedDataLength = (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION2); + } else { + CompressionSection = (EFI_COMPRESSION_SECTION *) Section; + SectionLength = SECTION_SIZE (Section); + + if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) { + return EFI_UNSUPPORTED; + } + + CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1); + CompressedDataLength = (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION); + } + + Status = UefiDecompressGetInfo ( + CompressedData, + CompressedDataLength, + &DstBufferSize, + &ScratchBufferSize + ); + } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { + Status = ExtractGuidedSectionGetInfo ( + Section, + &DstBufferSize, + &ScratchBufferSize, + &SectionAttribute + ); + } + + if (EFI_ERROR (Status)) { + // + // GetInfo failed + // + DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status)); + return EFI_NOT_FOUND; + } + // + // Allocate scratch buffer + // + ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); + if (ScratchBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Allocate destination buffer, extra one page for adjustment + // + DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); + if (DstBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header + // to make section data at page alignment. + // + if (IS_SECTION2 (Section)) + DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER2); + else + DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); + // + // Call decompress function + // + if (Section->Type == EFI_SECTION_COMPRESSION) { + if (IS_SECTION2 (Section)) { + CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION2 *) Section + 1); + } + else { + CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1); + } + + Status = UefiDecompress ( + CompressedData, + DstBuffer, + ScratchBuffer + ); + } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { + Status = ExtractGuidedSectionDecode ( + Section, + &DstBuffer, + ScratchBuffer, + &AuthenticationStatus + ); + } + + if (EFI_ERROR (Status)) { + // + // Decompress failed + // + DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status)); + return EFI_NOT_FOUND; + } else { + return FfsProcessSection ( + SectionType, + DstBuffer, + DstBufferSize, + OutputBuffer + ); + } + } + + if (IS_SECTION2 (Section)) { + SectionLength = SECTION2_SIZE (Section); + } else { + SectionLength = SECTION_SIZE (Section); + } + // + // SectionLength is adjusted it is 4 byte aligned. + // Go to the next section + // + SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4); + ASSERT (SectionLength != 0); + ParsedLength += SectionLength; + Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength); + } + + return EFI_NOT_FOUND; +} + + + +/** + This service enables discovery sections of a given type within a valid FFS file. + + @param SearchType The value of the section type to find. + @param FfsFileHeader A pointer to the file header that contains the set of sections to + be searched. + @param SectionData A pointer to the discovered section, if successful. + + @retval EFI_SUCCESS The section was found. + @retval EFI_NOT_FOUND The section was not found. + +**/ +EFI_STATUS +EFIAPI +FfsFindSectionData ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData + ) +{ + EFI_FFS_FILE_HEADER *FfsFileHeader; + UINT32 FileSize; + EFI_COMMON_SECTION_HEADER *Section; + + FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle); + + // + // Size is 24 bits wide so mask upper 8 bits. + // Does not include FfsFileHeader header size + // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1); + FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + FileSize -= sizeof (EFI_FFS_FILE_HEADER); + + return FfsProcessSection ( + SectionType, + Section, + FileSize, + SectionData + ); +} + + + + + + +/** + This service enables discovery of additional firmware files. + + @param SearchType A filter to find files only of this type. + @param FwVolHeader Pointer to the firmware volume header of the volume to search. + This parameter must point to a valid FFS volume. + @param FileHeader Pointer to the current file from which to begin searching. + + @retval EFI_SUCCESS The file was found. + @retval EFI_NOT_FOUND The file was not found. + @retval EFI_NOT_FOUND The header checksum was not zero. + +**/ +EFI_STATUS +EFIAPI +FfsFindNextFile ( + IN UINT8 SearchType, + IN EFI_PEI_FV_HANDLE VolumeHandle, + IN OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle); +} + + +/** + This service enables discovery of additional firmware volumes. + + @param Instance This instance of the firmware volume to find. The value 0 is the + Boot Firmware Volume (BFV). + @param FwVolHeader Pointer to the firmware volume header of the volume to return. + + @retval EFI_SUCCESS The volume was found. + @retval EFI_NOT_FOUND The volume was not found. + +**/ +EFI_STATUS +EFIAPI +FfsFindNextVolume ( + IN UINTN Instance, + IN OUT EFI_PEI_FV_HANDLE *VolumeHandle + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + + Hob.Raw = GetHobList (); + if (Hob.Raw == NULL) { + return EFI_NOT_FOUND; + } + + do { + Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw); + if (Hob.Raw != NULL) { + if (Instance-- == 0) { + *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress); + return EFI_SUCCESS; + } + + Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob)); + } + } while (Hob.Raw != NULL); + + return EFI_NOT_FOUND; + +} + + +/** + Find a file in the volume by name + + @param FileName A pointer to the name of the file to + find within the firmware volume. + + @param VolumeHandle The firmware volume to search FileHandle + Upon exit, points to the found file's + handle or NULL if it could not be found. + + @retval EFI_SUCCESS File was found. + + @retval EFI_NOT_FOUND File was not found. + + @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or + FileName was NULL. + +**/ +EFI_STATUS +EFIAPI +FfsFindFileByName ( + IN CONST EFI_GUID *FileName, + IN EFI_PEI_FV_HANDLE VolumeHandle, + OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle); + if (Status == EFI_NOT_FOUND) { + *FileHandle = NULL; + } + return Status; +} + + + + +/** + Get information about the file by name. + + @param FileHandle Handle of the file. + + @param FileInfo Upon exit, points to the file's + information. + + @retval EFI_SUCCESS File information returned. + + @retval EFI_INVALID_PARAMETER If FileHandle does not + represent a valid file. + + @retval EFI_INVALID_PARAMETER If FileInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +FfsGetFileInfo ( + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT EFI_FV_FILE_INFO *FileInfo + ) +{ + UINT8 FileState; + UINT8 ErasePolarity; + EFI_FFS_FILE_HEADER *FileHeader; + EFI_PEI_FV_HANDLE VolumeHandle; + + if ((FileHandle == NULL) || (FileInfo == NULL)) { + return EFI_INVALID_PARAMETER; + } + + VolumeHandle = 0; + // + // Retrieve the FirmwareVolume which the file resides in. + // + if (!FileHandleToVolume(FileHandle, &VolumeHandle)) { + return EFI_INVALID_PARAMETER; + } + + if (((EFI_FIRMWARE_VOLUME_HEADER*)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) { + ErasePolarity = 1; + } else { + ErasePolarity = 0; + } + + // + // Get FileState which is the highest bit of the State + // + FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle); + + switch (FileState) { + case EFI_FILE_DATA_VALID: + case EFI_FILE_MARKED_FOR_UPDATE: + break; + default: + return EFI_INVALID_PARAMETER; + } + + FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle; + CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID)); + FileInfo->FileType = FileHeader->Type; + FileInfo->FileAttributes = FileHeader->Attributes; + FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER); + FileInfo->Buffer = (FileHeader + 1); + return EFI_SUCCESS; +} + + +/** + Get Information about the volume by name + + @param VolumeHandle Handle of the volume. + + @param VolumeInfo Upon exit, points to the volume's + information. + + @retval EFI_SUCCESS File information returned. + + @retval EFI_INVALID_PARAMETER If FileHandle does not + represent a valid file. + + @retval EFI_INVALID_PARAMETER If FileInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +FfsGetVolumeInfo ( + IN EFI_PEI_FV_HANDLE VolumeHandle, + OUT EFI_FV_INFO *VolumeInfo + ) +{ + EFI_FIRMWARE_VOLUME_HEADER FwVolHeader; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo; + + if (VolumeInfo == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // VolumeHandle may not align at 8 byte, + // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte. + // So, Copy FvHeader into the local FvHeader structure. + // + CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + // + // Check Fv Image Signature + // + if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + VolumeInfo->FvAttributes = FwVolHeader.Attributes; + VolumeInfo->FvStart = (VOID *) VolumeHandle; + VolumeInfo->FvSize = FwVolHeader.FvLength; + CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID)); + + if (FwVolHeader.ExtHeaderOffset != 0) { + FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset); + CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID)); + } + return EFI_SUCCESS; +} + + + +/** + Search through every FV until you find a file of type FileType + + @param FileType File handle of a Fv type file. + @param Volumehandle On success Volume Handle of the match + @param FileHandle On success File Handle of the match + + @retval EFI_NOT_FOUND FV image can't be found. + @retval EFI_SUCCESS Successfully found FileType + +**/ +EFI_STATUS +EFIAPI +FfsAnyFvFindFirstFile ( + IN EFI_FV_FILETYPE FileType, + OUT EFI_PEI_FV_HANDLE *VolumeHandle, + OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + UINTN Instance; + + // + // Search every FV for the DXE Core + // + Instance = 0; + *FileHandle = NULL; + + while (1) + { + Status = FfsFindNextVolume (Instance++, VolumeHandle); + if (EFI_ERROR (Status)) + { + break; + } + + Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle); + if (!EFI_ERROR (Status)) + { + break; + } + } + + return Status; +} + + + +/** + Get Fv image from the FV type file, then add FV & FV2 Hob. + + @param FileHandle File handle of a Fv type file. + + + @retval EFI_NOT_FOUND FV image can't be found. + @retval EFI_SUCCESS Successfully to process it. + +**/ +EFI_STATUS +EFIAPI +FfsProcessFvFile ( + IN EFI_PEI_FILE_HANDLE FvFileHandle + ) +{ + EFI_STATUS Status; + EFI_PEI_FV_HANDLE FvImageHandle; + EFI_FV_INFO FvImageInfo; + UINT32 FvAlignment; + VOID *FvBuffer; + EFI_PEI_HOB_POINTERS HobFv2; + + FvBuffer = NULL; + + + // + // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already + // been extracted. + // + HobFv2.Raw = GetHobList (); + while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) { + if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) { + // + // this FILE has been dispatched, it will not be dispatched again. + // + return EFI_SUCCESS; + } + HobFv2.Raw = GET_NEXT_HOB (HobFv2); + } + + // + // Find FvImage in FvFile + // + Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, FvFileHandle, (VOID **)&FvImageHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Collect FvImage Info. + // + ZeroMem (&FvImageInfo, sizeof (FvImageInfo)); + Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo); + ASSERT_EFI_ERROR (Status); + + // + // FvAlignment must be more than 8 bytes required by FvHeader structure. + // + FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16); + if (FvAlignment < 8) { + FvAlignment = 8; + } + + // + // Check FvImage + // + if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) { + FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment); + if (FvBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize); + // + // Update FvImageInfo after reload FvImage to new aligned memory + // + FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo); + } + + + // + // Inform HOB consumer phase, i.e. DXE core, the existence of this FV + // + BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, FvImageInfo.FvSize); + + // + // Makes the encapsulated volume show up in DXE phase to skip processing of + // encapsulated file again. + // + BuildFv2Hob ( + (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, + FvImageInfo.FvSize, + &FvImageInfo.FvName, + &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name) + ); + + return EFI_SUCCESS; +} + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePi.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePi.h new file mode 100644 index 00000000..7a92be53 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePi.h @@ -0,0 +1,41 @@ +/** @file + Library that helps implement monolithic PEI (i.e. PEI part of SEC) + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PI_PEI_H_ +#define _PI_PEI_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#define GET_HOB_TYPE(Hob) ((Hob).Header->HobType) +#define GET_HOB_LENGTH(Hob) ((Hob).Header->HobLength) +#define GET_NEXT_HOB(Hob) ((Hob).Raw + GET_HOB_LENGTH (Hob)) +#define END_OF_HOB_LIST(Hob) (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_END_OF_HOB_LIST) + +// +// Get the data and data size field of GUID +// +#define GET_GUID_HOB_DATA(GuidHob) ((VOID *) (((UINT8 *) &((GuidHob)->Name)) + sizeof (EFI_GUID))) +#define GET_GUID_HOB_DATA_SIZE(GuidHob) (((GuidHob)->Header).HobLength - sizeof (EFI_HOB_GUID_TYPE)) + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.c new file mode 100644 index 00000000..1ff83b28 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.c @@ -0,0 +1,251 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +// +// Hack to work in NT32 +// +EFI_STATUS + +EFIAPI + +SecWinNtPeiLoadFile ( + IN VOID *Pe32Data, + IN EFI_PHYSICAL_ADDRESS *ImageAddress, + IN UINT64 *ImageSize, + IN EFI_PHYSICAL_ADDRESS *EntryPoint + ); + +STATIC +VOID* +EFIAPI +AllocateCodePages ( + IN UINTN Pages + ) +{ + VOID *Alloc; + EFI_PEI_HOB_POINTERS Hob; + + Alloc = AllocatePages (Pages); + if (Alloc == NULL) { + return NULL; + } + + // find the HOB we just created, and change the type to EfiBootServicesCode + Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION); + while (Hob.Raw != NULL) { + if (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress == (UINTN)Alloc) { + Hob.MemoryAllocation->AllocDescriptor.MemoryType = EfiBootServicesCode; + return Alloc; + } + Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (Hob)); + } + + ASSERT (FALSE); + + FreePages (Alloc, Pages); + return NULL; +} + + +EFI_STATUS +EFIAPI +LoadPeCoffImage ( + IN VOID *PeCoffImage, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress, + OUT UINT64 *ImageSize, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint + ) +{ + RETURN_STATUS Status; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + VOID *Buffer; + + ZeroMem (&ImageContext, sizeof (ImageContext)); + + ImageContext.Handle = PeCoffImage; + ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; + + Status = PeCoffLoaderGetImageInfo (&ImageContext); + ASSERT_EFI_ERROR (Status); + + + // + // Allocate Memory for the image + // + Buffer = AllocateCodePages (EFI_SIZE_TO_PAGES((UINT32)ImageContext.ImageSize)); + ASSERT (Buffer != 0); + + + ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; + + // + // Load the image to our new buffer + // + Status = PeCoffLoaderLoadImage (&ImageContext); + ASSERT_EFI_ERROR (Status); + + // + // Relocate the image in our new buffer + // + Status = PeCoffLoaderRelocateImage (&ImageContext); + ASSERT_EFI_ERROR (Status); + + + *ImageAddress = ImageContext.ImageAddress; + *ImageSize = ImageContext.ImageSize; + *EntryPoint = ImageContext.EntryPoint; + + // + // Flush not needed for all architectures. We could have a processor specific + // function in this library that does the no-op if needed. + // + InvalidateInstructionCacheRange ((VOID *)(UINTN)*ImageAddress, (UINTN)*ImageSize); + + return Status; +} + + + +typedef +VOID +(EFIAPI *DXE_CORE_ENTRY_POINT) ( + IN VOID *HobStart + ); + +EFI_STATUS +EFIAPI +LoadDxeCoreFromFfsFile ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN UINTN StackSize + ) +{ + EFI_STATUS Status; + VOID *PeCoffImage; + EFI_PHYSICAL_ADDRESS ImageAddress; + UINT64 ImageSize; + EFI_PHYSICAL_ADDRESS EntryPoint; + VOID *BaseOfStack; + VOID *TopOfStack; + VOID *Hob; + EFI_FV_FILE_INFO FvFileInfo; + + Status = FfsFindSectionData (EFI_SECTION_PE32, FileHandle, &PeCoffImage); + if (EFI_ERROR (Status)) { + return Status; + } + + + Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint); +// For NT32 Debug Status = SecWinNtPeiLoadFile (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint); + ASSERT_EFI_ERROR (Status); + + // + // Extract the DxeCore GUID file name. + // + Status = FfsGetFileInfo (FileHandle, &FvFileInfo); + ASSERT_EFI_ERROR (Status); + + BuildModuleHob (&FvFileInfo.FileName, (EFI_PHYSICAL_ADDRESS)(UINTN)ImageAddress, EFI_SIZE_TO_PAGES ((UINT32) ImageSize) * EFI_PAGE_SIZE, EntryPoint); + + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading DxeCore at 0x%10p EntryPoint=0x%10p\n", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)EntryPoint)); + + Hob = GetHobList (); + if (StackSize == 0) { + // User the current stack + + ((DXE_CORE_ENTRY_POINT)(UINTN)EntryPoint) (Hob); + } else { + + // + // Allocate 128KB for the Stack + // + BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (StackSize)); + ASSERT (BaseOfStack != NULL); + + // + // Compute the top of the stack we were allocated. Pre-allocate a UINTN + // for safety. + // + TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (StackSize) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT); + TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); + + // + // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. + // + UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, StackSize); + + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT)(UINTN)EntryPoint, + Hob, + NULL, + TopOfStack + ); + + } + + // Should never get here as DXE Core does not return + DEBUG ((EFI_D_ERROR, "DxeCore returned\n")); + ASSERT (FALSE); + + return EFI_DEVICE_ERROR; +} + + + +EFI_STATUS +EFIAPI +LoadDxeCoreFromFv ( + IN UINTN *FvInstance, OPTIONAL + IN UINTN StackSize + ) +{ + EFI_STATUS Status; + EFI_PEI_FV_HANDLE VolumeHandle; + EFI_PEI_FILE_HANDLE FileHandle = NULL; + + if (FvInstance != NULL) { + // + // Caller passed in a specific FV to try, so only try that one + // + Status = FfsFindNextVolume (*FvInstance, &VolumeHandle); + if (!EFI_ERROR (Status)) { + Status = FfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE, VolumeHandle, &FileHandle); + } + } else { + Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, &FileHandle); + } + + if (!EFI_ERROR (Status)) { + return LoadDxeCoreFromFfsFile (FileHandle, StackSize); + } + + return Status; +} + + +EFI_STATUS +EFIAPI +DecompressFirstFv ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PEI_FV_HANDLE VolumeHandle; + EFI_PEI_FILE_HANDLE FileHandle; + + Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, &VolumeHandle, &FileHandle); + if (!EFI_ERROR (Status)) { + Status = FfsProcessFvFile (FileHandle); + } + + return Status; +} + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf new file mode 100644 index 00000000..5c56451e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf @@ -0,0 +1,74 @@ +#/** @file +# Component description file for Apple Pre PI Library +# +# LIbrary helps you build a platform that skips PEI and loads DXE Core +# directly. Helps building HOBs, reading data from the FV, and doing +# decompression. +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2008, Apple Inc. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PrePiLib + FILE_GUID = 1F3A3278-82EB-4C0D-86F1-5BCDA5846CB2 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PrePiLib + + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources.common] + PrePi.h + FwVol.c + PrePiLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + BaseMemoryLib + UefiDecompressLib + PeCoffLib + CacheMaintenanceLib + PrintLib + SerialPortLib + ExtractGuidedSectionLib + TimerLib + PerformanceLib + HobLib + +[Guids] + gEfiMemoryTypeInformationGuid + +[Protocols] + gPeCoffLoaderProtocolGuid + + +[FixedPcd.common] + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize + + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData + +[FeaturePcd] + gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/MemoryAllocationLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/MemoryAllocationLib.c new file mode 100644 index 00000000..939516d7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/MemoryAllocationLib.c @@ -0,0 +1,246 @@ +/** @file + Implementation of the 6 PEI Ffs (FV) APIs in library form. + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include + + + +/** + Allocates one or more 4KB pages of type EfiBootServicesData. + + Allocates the number of 4KB pages of MemoryType and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePages ( + IN UINTN Pages + ) +{ + EFI_PEI_HOB_POINTERS Hob; + EFI_PHYSICAL_ADDRESS Offset; + + Hob.Raw = GetHobList (); + + // Check to see if on 4k boundary + Offset = Hob.HandoffInformationTable->EfiFreeMemoryTop & 0xFFF; + if (Offset != 0) { + // If not aligned, make the allocation aligned. + Hob.HandoffInformationTable->EfiFreeMemoryTop -= Offset; + } + + // + // Verify that there is sufficient memory to satisfy the allocation + // + if (Hob.HandoffInformationTable->EfiFreeMemoryTop - ((Pages * EFI_PAGE_SIZE) + sizeof (EFI_HOB_MEMORY_ALLOCATION)) < Hob.HandoffInformationTable->EfiFreeMemoryBottom) { + return 0; + } else { + // + // Update the PHIT to reflect the memory usage + // + Hob.HandoffInformationTable->EfiFreeMemoryTop -= Pages * EFI_PAGE_SIZE; + + // This routine used to create a memory allocation HOB a la PEI, but that's not + // necessary for us. + + // + // Create a memory allocation HOB. + // + BuildMemoryAllocationHob ( + Hob.HandoffInformationTable->EfiFreeMemoryTop, + Pages * EFI_PAGE_SIZE, + EfiBootServicesData + ); + return (VOID *)(UINTN)Hob.HandoffInformationTable->EfiFreeMemoryTop; + } +} + + +/** + Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedPages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + VOID *Memory; + UINTN AlignmentMask; + + // + // Alignment must be a power of two or zero. + // + ASSERT ((Alignment & (Alignment - 1)) == 0); + + if (Pages == 0) { + return NULL; + } + // + // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow. + // + ASSERT (Pages <= (MAX_ADDRESS - EFI_SIZE_TO_PAGES (Alignment))); + // + // We would rather waste some memory to save PEI code size. + // + Memory = (VOID *)(UINTN)AllocatePages (Pages + EFI_SIZE_TO_PAGES (Alignment)); + if (Alignment == 0) { + AlignmentMask = Alignment; + } else { + AlignmentMask = Alignment - 1; + } + return (VOID *) (UINTN) (((UINTN) Memory + AlignmentMask) & ~AlignmentMask); +} + + +/** + Frees one or more 4KB pages that were previously allocated with one of the page allocation + functions in the Memory Allocation Library. + + Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer + must have been allocated on a previous call to the page allocation services of the Memory + Allocation Library. If it is not possible to free allocated pages, then this function will + perform no actions. + + If Buffer was not allocated with a page allocation function in the Memory Allocation Library, + then ASSERT(). + If Pages is zero, then ASSERT(). + + @param Buffer Pointer to the buffer of pages to free. + @param Pages The number of 4 KB pages to free. + +**/ +VOID +EFIAPI +FreePages ( + IN VOID *Buffer, + IN UINTN Pages + ) +{ + // For now, we do not support the ability to free pages in the PrePei Memory Allocator. + // The allocated memory is lost. +} + +/** + Allocates a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a + pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePool ( + IN UINTN AllocationSize + ) +{ + EFI_HOB_MEMORY_POOL *Hob; + + Hob = GetHobList (); + + + // + // Verify that there is sufficient memory to satisfy the allocation + // + if (AllocationSize > 0x10000) { + // Please call AllocatePages for big allocations + return 0; + } else { + + Hob = (EFI_HOB_MEMORY_POOL *)CreateHob (EFI_HOB_TYPE_MEMORY_POOL, + (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + + AllocationSize)); + return (VOID *)(Hob + 1); + } +} + +/** + Allocates and zeros a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateZeroPool ( + IN UINTN AllocationSize + ) +{ + VOID *Buffer; + + Buffer = AllocatePool (AllocationSize); + if (Buffer == NULL) { + return NULL; + } + + ZeroMem (Buffer, AllocationSize); + + return Buffer; +} + +/** + Frees a buffer that was previously allocated with one of the pool allocation functions in the + Memory Allocation Library. + + Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the + pool allocation services of the Memory Allocation Library. If it is not possible to free pool + resources, then this function will perform no actions. + + If Buffer was not allocated with a pool allocation function in the Memory Allocation Library, + then ASSERT(). + + @param Buffer Pointer to the buffer to free. + +**/ +VOID +EFIAPI +FreePool ( + IN VOID *Buffer + ) +{ + // Not implemented yet +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf new file mode 100644 index 00000000..034a9a46 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf @@ -0,0 +1,33 @@ +#/** @file +# +# Copyright (c) 2011, ARM Ltd. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PrePiMemoryAllocationLib + FILE_GUID = 4f14c900-51a9-11e0-afbf-0002a5d5c51b + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + LIBRARY_CLASS = MemoryAllocationLib + + +# +# VALID_ARCHITECTURES = ARM +# + +[Sources] + MemoryAllocationLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + DebugLib + BaseMemoryLib + PrePiLib + #PeiServicesLib + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c new file mode 100644 index 00000000..73c53411 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c @@ -0,0 +1,169 @@ +/** @file + Implement EFI RealTimeClock runtime services via RTC Lib. + + Currently this driver does not support runtime virtual calling. + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + + +/** + Returns the current time and date information, and the time-keeping capabilities + of the hardware platform. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time clock + device's capabilities. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +{ + // + // Fill in Time and Capabilities via data from you RTC + // + return EFI_DEVICE_ERROR; +} + + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibSetTime ( + IN EFI_TIME *Time + ) +{ + // + // Use Time, to set the time in your RTC hardware + // + return EFI_DEVICE_ERROR; +} + + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgement. + @param Time The current alarm setting. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Any parameter is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +{ + // Not a required feature + return EFI_UNSUPPORTED; +} + + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If + Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +LibSetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ) +{ + // Not a required feature + return EFI_UNSUPPORTED; +} + + + +/** + This is the declaration of an EFI image entry point. This can be the entry point to an application + written to this specification, an EFI boot service driver, or an EFI runtime driver. + + @param ImageHandle Handle that identifies the loaded image. + @param SystemTable System Table for this image. + + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +EFIAPI +LibRtcInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + // + // Do some initialization if required to turn on the RTC + // + return EFI_SUCCESS; +} + + +/** + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +VOID +EFIAPI +LibRtcVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Only needed if you are going to support the OS calling RTC functions in virtual mode. + // You will need to call EfiConvertPointer (). To convert any stored physical addresses + // to virtual address. After the OS transitions to calling in virtual mode, all future + // runtime calls will be made in virtual mode. + // + return; +} + + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf new file mode 100644 index 00000000..6fa6cfb4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf @@ -0,0 +1,31 @@ +#/** @file +# Memory Status Code Library for UEFI drivers +# +# Lib to provide memory journal status code reporting Routines +# Copyright (c) 2006, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TemplateRealTimeClockLib + FILE_GUID = B661E02D-A90B-42AB-A5F9-CF841AAA43D9 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RealTimeClockLib + + +[Sources.common] + RealTimeClockLib.c + + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + IoLib + DebugLib diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c new file mode 100644 index 00000000..79d1732b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c @@ -0,0 +1,97 @@ +/** @file + Template library implementation to support ResetSystem Runtime call. + + Fill in the templates with what ever makes you system reset. + + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include + +#include +#include +#include + + +/** + Resets the entire platform. + + @param ResetType The type of reset to perform. + @param ResetStatus The status code for the reset. + @param DataSize The size, in bytes, of WatchdogData. + @param ResetData For a ResetType of EfiResetCold, EfiResetWarm, or + EfiResetShutdown the data buffer starts with a Null-terminated + Unicode string, optionally followed by additional binary data. + +**/ +EFI_STATUS +EFIAPI +LibResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ) +{ + UINTN Address; + UINT8 Data; + + + switch (ResetType) { + case EfiResetCold: + // system power cycle + + // Example using IoLib functions to do IO. + Address = 0x12345678; + Data = MmioRead8 (Address); + MmioWrite8 (Address, Data | 0x01); + + // Note this is a bad example asa MmioOr8 (Address, 0x01) does the same thing + break; + + case EfiResetWarm: + // not a full power cycle, maybe memory stays around. + // if not support do the same thing as EfiResetCold. + break; + + case EfiResetShutdown: + // turn off the system. + // if not support do the same thing as EfiResetCold. + break; + + default: + return EFI_INVALID_PARAMETER; + } + + // + // If we reset, we would not have returned... + // + return EFI_DEVICE_ERROR; +} + + + +/** + Initialize any infrastructure required for LibResetSystem () to function. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +LibInitializeResetSystem ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EFI_SUCCESS; +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf new file mode 100644 index 00000000..41e15641 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf @@ -0,0 +1,30 @@ +#/** @file +# Memory Status Code Library for UEFI drivers +# +# Lib to provide memory journal status code reporting Routines +# Copyright (c) 2006, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TemplateResetSystemLib + FILE_GUID = 40BAFDE5-4CC8-4FBE-A8BA-071890076E50 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = EfiResetSystemLib + + +[Sources.common] + ResetSystemLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + IoLib + DebugLib diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c new file mode 100644 index 00000000..2a3962c4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c @@ -0,0 +1,289 @@ +/** @file +* +* Copyright (c) 2016, Hisilicon Limited. All rights reserved. +* Copyright (c) 2016-2019, Linaro Limited. All rights reserved. +* Copyright (c) 2021, Ampere Computing LLC. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include +#include + +/** + Converts Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC) to EFI_TIME. + + @param EpochSeconds Epoch seconds. + @param Time The time converted to UEFI format. + +**/ +VOID +EFIAPI +EpochToEfiTime ( + IN UINTN EpochSeconds, + OUT EFI_TIME *Time + ) +{ + UINTN a; + UINTN b; + UINTN c; + UINTN d; + UINTN g; + UINTN j; + UINTN m; + UINTN y; + UINTN da; + UINTN db; + UINTN dc; + UINTN dg; + UINTN hh; + UINTN mm; + UINTN ss; + UINTN J; + + J = (EpochSeconds / 86400) + 2440588; + j = J + 32044; + g = j / 146097; + dg = j % 146097; + c = (((dg / 36524) + 1) * 3) / 4; + dc = dg - (c * 36524); + b = dc / 1461; + db = dc % 1461; + a = (((db / 365) + 1) * 3) / 4; + da = db - (a * 365); + y = (g * 400) + (c * 100) + (b * 4) + a; + m = (((da * 5) + 308) / 153) - 2; + d = da - (((m + 4) * 153) / 5) + 122; + + Time->Year = (UINT16)(y - 4800 + ((m + 2) / 12)); + Time->Month = ((m + 2) % 12) + 1; + Time->Day = (UINT8)(d + 1); + + ss = EpochSeconds % 60; + a = (EpochSeconds - ss) / 60; + mm = a % 60; + b = (a - mm) / 60; + hh = b % 24; + + Time->Hour = (UINT8)hh; + Time->Minute = (UINT8)mm; + Time->Second = (UINT8)ss; + Time->Nanosecond = 0; + +} + +/** + Calculate Epoch days. + + @param Time The UEFI time to be calculated. + + @return Number of days. + +**/ +UINTN +EFIAPI +EfiGetEpochDays ( + IN EFI_TIME *Time + ) +{ + UINTN a; + UINTN y; + UINTN m; + UINTN JulianDate; // Absolute Julian Date representation of the supplied Time + UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY + + a = (14 - Time->Month) / 12 ; + y = Time->Year + 4800 - a; + m = Time->Month + (12*a) - 3; + + JulianDate = Time->Day + ((153*m + 2)/5) + (365*y) + (y/4) - (y/100) + (y/400) - 32045; + + ASSERT (JulianDate >= EPOCH_JULIAN_DATE); + EpochDays = JulianDate - EPOCH_JULIAN_DATE; + + return EpochDays; +} + +/** + Converts EFI_TIME to Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC). + + @param Time The UEFI time to be converted. + + @return Number of seconds. + +**/ +UINTN +EFIAPI +EfiTimeToEpoch ( + IN EFI_TIME *Time + ) +{ + UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY + UINTN EpochSeconds; + + EpochDays = EfiGetEpochDays (Time); + + EpochSeconds = (EpochDays * SEC_PER_DAY) + ((UINTN)Time->Hour * SEC_PER_HOUR) + (Time->Minute * SEC_PER_MIN) + Time->Second; + + return EpochSeconds; +} + +/** + Get the day of the week from the UEFI time. + + @param Time The UEFI time to be calculated. + + @return The day of the week: Sunday=0, Monday=1, ... Saturday=6 + +**/ +UINTN +EfiTimeToWday ( + IN EFI_TIME *Time + ) +{ + UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY + + EpochDays = EfiGetEpochDays (Time); + + // 4=1/1/1970 was a Thursday + + return (EpochDays + 4) % 7; +} + +/** + Check if it is a leap year. + + @param Time The UEFI time to be checked. + + @retval TRUE It is a leap year. + @retval FALSE It is NOT a leap year. + +**/ +BOOLEAN +EFIAPI +IsLeapYear ( + IN EFI_TIME *Time + ) +{ + if (Time->Year % 4 == 0) { + if (Time->Year % 100 == 0) { + if (Time->Year % 400 == 0) { + return TRUE; + } else { + return FALSE; + } + } else { + return TRUE; + } + } else { + return FALSE; + } +} + +/** + Check if the day in the UEFI time is valid. + + @param Time The UEFI time to be checked. + + @retval TRUE Valid. + @retval FALSE Invalid. + +**/ +BOOLEAN +EFIAPI +IsDayValid ( + IN EFI_TIME *Time + ) +{ + STATIC CONST INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + if (Time->Day < 1 || + Time->Day > DayOfMonth[Time->Month - 1] || + (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28)) + ) { + return FALSE; + } + + return TRUE; +} + +/** + Check if the time zone is valid. + Valid values are between -1440 and 1440 or 2047 (EFI_UNSPECIFIED_TIMEZONE). + + @param TimeZone The time zone to be checked. + + @retval TRUE Valid. + @retval FALSE Invalid. + +**/ +BOOLEAN +EFIAPI +IsValidTimeZone ( + IN INT16 TimeZone + ) +{ + return TimeZone == EFI_UNSPECIFIED_TIMEZONE || + (TimeZone >= -1440 && TimeZone <= 1440); +} + +/** + Check if the daylight is valid. + Valid values are: + 0 : Time is not affected. + 1 : Time is affected, and has not been adjusted for daylight savings. + 3 : Time is affected, and has been adjusted for daylight savings. + All other values are invalid. + + @param Daylight The daylight to be checked. + + @retval TRUE Valid. + @retval FALSE Invalid. + +**/ +BOOLEAN +EFIAPI +IsValidDaylight ( + IN INT8 Daylight + ) +{ + return Daylight == 0 || + Daylight == EFI_TIME_ADJUST_DAYLIGHT || + Daylight == (EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT); +} + +/** + Check if the UEFI time is valid. + + @param Time The UEFI time to be checked. + + @retval TRUE Valid. + @retval FALSE Invalid. + +**/ +BOOLEAN +EFIAPI +IsTimeValid ( + IN EFI_TIME *Time + ) +{ + // Check the input parameters are within the range specified by UEFI + if ((Time->Year < 2000) || + (Time->Year > 2099) || + (Time->Month < 1 ) || + (Time->Month > 12 ) || + (!IsDayValid (Time) ) || + (Time->Hour > 23 ) || + (Time->Minute > 59 ) || + (Time->Second > 59 ) || + (Time->Nanosecond > 999999999) || + (!IsValidTimeZone(Time->TimeZone)) || + (!IsValidDaylight(Time->Daylight))) { + return FALSE; + } + + return TRUE; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf new file mode 100644 index 00000000..249da54b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf @@ -0,0 +1,28 @@ +#/** @file +# +# Copyright (c) 2016, Hisilicon Limited. All rights reserved. +# Copyright (c) 2016, Linaro Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TimeBaseLib + FILE_GUID = B1B07E01-6896-448C-8E75-F0E119ABDF49 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = TimeBaseLib + +[Sources.common] + TimeBaseLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + DebugLib + +[Pcd] diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c new file mode 100644 index 00000000..c93bf408 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c @@ -0,0 +1,418 @@ +/** @file + * + * Implement virtual EFI RealTimeClock runtime services. + * + * Coypright (c) 2019, Pete Batard + * Copyright (c) 2018, Andrei Warkentin + * Copyright (c) 2011-2014, ARM Ltd. All rights reserved. + * Copyright (c) 2008-2010, Apple Inc. All rights reserved. + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + * Based on ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.inf + * + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +STATIC CONST CHAR16 mEpochVariableName[] = L"RtcEpochSeconds"; +STATIC CONST CHAR16 mTimeZoneVariableName[] = L"RtcTimeZone"; +STATIC CONST CHAR16 mDaylightVariableName[] = L"RtcDaylight"; + +/** + Returns the current time and date information, and the time-keeping capabilities + of the virtual RTC. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time clock + device's capabilities. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +{ + EFI_STATUS Status; + INT16 TimeZone; + UINT8 Daylight; + UINT64 Freq; + UINT64 Counter; + UINT64 Remainder; + UINTN EpochSeconds; + UINTN Size; + + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Get the counter frequency + Freq = GetPerformanceCounterProperties (NULL, NULL); + if (Freq == 0) { + return EFI_DEVICE_ERROR; + } + + // Get the epoch time from non-volatile storage + Size = sizeof (UINTN); + EpochSeconds = 0; + Status = EfiGetVariable ( + (CHAR16 *)mEpochVariableName, + &gEfiCallerIdGuid, + NULL, + &Size, + (VOID *)&EpochSeconds + ); + // Fall back to compilation-time epoch if not set + if (EFI_ERROR (Status)) { + ASSERT(Status != EFI_INVALID_PARAMETER); + ASSERT(Status != EFI_BUFFER_TOO_SMALL); + // + // The following is intended to produce a compilation error on build + // environments where BUILD_EPOCH can not be set from inline shell. + // If you are attempting to use this library on such an environment, please + // contact the edk2 mailing list, so we can try to add support for it. + // + EpochSeconds = BUILD_EPOCH; + DEBUG (( + DEBUG_INFO, + "LibGetTime: %s non volatile variable was not found - Using compilation time epoch.\n", + mEpochVariableName + )); + + EfiSetVariable ( + (CHAR16 *)mEpochVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (EpochSeconds), + &EpochSeconds + ); + } + Counter = GetPerformanceCounter (); + EpochSeconds += DivU64x64Remainder (Counter, Freq, &Remainder); + + // Get the current time zone information from non-volatile storage + Size = sizeof (TimeZone); + Status = EfiGetVariable ( + (CHAR16 *)mTimeZoneVariableName, + &gEfiCallerIdGuid, + NULL, + &Size, + (VOID *)&TimeZone + ); + + if (EFI_ERROR (Status)) { + ASSERT(Status != EFI_INVALID_PARAMETER); + ASSERT(Status != EFI_BUFFER_TOO_SMALL); + + if (Status != EFI_NOT_FOUND) { + return Status; + } + + // The time zone variable does not exist in non-volatile storage, so create it. + Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE; + // Store it + Status = EfiSetVariable ( + (CHAR16 *)mTimeZoneVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + Size, + (VOID *)&(Time->TimeZone) + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "LibGetTime: Failed to save %s variable to non-volatile storage, Status = %r\n", + mTimeZoneVariableName, + Status + )); + return Status; + } + } else { + // Got the time zone + Time->TimeZone = TimeZone; + + // Check TimeZone bounds: -1440 to 1440 or 2047 + if (((Time->TimeZone < -1440) || (Time->TimeZone > 1440)) + && (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE)) { + Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE; + } + + // Adjust for the correct time zone + if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) { + EpochSeconds += Time->TimeZone * SEC_PER_MIN; + } + } + + // Get the current daylight information from non-volatile storage + Size = sizeof (Daylight); + Status = EfiGetVariable ( + (CHAR16 *)mDaylightVariableName, + &gEfiCallerIdGuid, + NULL, + &Size, + (VOID *)&Daylight + ); + + if (EFI_ERROR (Status)) { + ASSERT(Status != EFI_INVALID_PARAMETER); + ASSERT(Status != EFI_BUFFER_TOO_SMALL); + + if (Status != EFI_NOT_FOUND) { + return Status; + } + + // The daylight variable does not exist in non-volatile storage, so create it. + Time->Daylight = 0; + // Store it + Status = EfiSetVariable ( + (CHAR16 *)mDaylightVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + Size, + (VOID *)&(Time->Daylight) + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "LibGetTime: Failed to save %s variable to non-volatile storage, Status = %r\n", + mDaylightVariableName, + Status + )); + return Status; + } + } else { + // Got the daylight information + Time->Daylight = Daylight; + + // Adjust for the correct period + if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) { + // Convert to adjusted time, i.e. spring forwards one hour + EpochSeconds += SEC_PER_HOUR; + } + } + + EpochToEfiTime (EpochSeconds, Time); + + // Because we use the performance counter, we can fill the Nanosecond attribute + // provided that the remainder doesn't overflow 64-bit during multiplication. + if (Remainder <= 18446744073U) { + Time->Nanosecond = (UINT32)(MultU64x64 (Remainder, 1000000000U) / Freq); + } else { + DEBUG ((DEBUG_WARN, "LibGetTime: Nanosecond value not set (64-bit overflow).\n")); + } + + if (Capabilities) { + Capabilities->Accuracy = 0; + Capabilities->Resolution = 1; + Capabilities->SetsToZero = FALSE; + } + + return EFI_SUCCESS; +} + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibSetTime ( + IN EFI_TIME *Time + ) +{ + EFI_STATUS Status; + UINT64 Freq; + UINT64 Counter; + UINT64 Remainder; + UINTN EpochSeconds; + + if (!IsTimeValid (Time)) { + return EFI_INVALID_PARAMETER; + } + + EpochSeconds = EfiTimeToEpoch (Time); + + // Adjust for the correct time zone, i.e. convert to UTC time zone + if ((Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) + && (EpochSeconds > Time->TimeZone * SEC_PER_MIN)) { + EpochSeconds -= Time->TimeZone * SEC_PER_MIN; + } + + // Adjust for the correct period + if (((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) + && (EpochSeconds > SEC_PER_HOUR)) { + // Convert to un-adjusted time, i.e. fall back one hour + EpochSeconds -= SEC_PER_HOUR; + } + + // Use the performance counter to subtract the number of seconds + // since platform reset. Without this, setting time from the shell + // and immediately reading it back would result in a forward time + // offset, of the duration during which the platform has been up. + Freq = GetPerformanceCounterProperties (NULL, NULL); + if (Freq != 0) { + Counter = GetPerformanceCounter (); + if (EpochSeconds > DivU64x64Remainder (Counter, Freq, &Remainder)) { + EpochSeconds -= DivU64x64Remainder (Counter, Freq, &Remainder); + } + } + + // Save the current time zone information into non-volatile storage + Status = EfiSetVariable ( + (CHAR16 *)mTimeZoneVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (Time->TimeZone), + (VOID *)&(Time->TimeZone) + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n", + mTimeZoneVariableName, + Status + )); + return Status; + } + + // Save the current daylight information into non-volatile storage + Status = EfiSetVariable ( + (CHAR16 *)mDaylightVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(Time->Daylight), + (VOID *)&(Time->Daylight) + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n", + mDaylightVariableName, + Status + )); + return Status; + } + + Status = EfiSetVariable ( + (CHAR16 *)mEpochVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (EpochSeconds), + &EpochSeconds + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n", + mDaylightVariableName, + Status + )); + return Status; + } + + return EFI_SUCCESS; +} + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgement. + @param Time The current alarm setting. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Any parameter is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If + Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +LibSetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This is the declaration of an EFI image entry point. This can be the entry point to an application + written to this specification, an EFI boot service driver, or an EFI runtime driver. + + @param ImageHandle Handle that identifies the loaded image. + @param SystemTable System Table for this image. + + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +EFIAPI +LibRtcInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EFI_SUCCESS; +} + +/** + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +VOID +EFIAPI +LibRtcVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + return; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf new file mode 100644 index 00000000..873b8de6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf @@ -0,0 +1,37 @@ +#/** @file +# +# Implement virtual EFI RealTimeClock runtime services. +# +# Copyright (c) 2019, Pete Batard +# Copyright (c) 2018, Andrei Warkentin +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = VirtualRealTimeClockLib + FILE_GUID = 1E27D461-78F3-4F7D-B1C2-F72384F13A6E + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RealTimeClockLib + +[Sources.common] + VirtualRealTimeClockLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + IoLib + DebugLib + TimerLib + TimeBaseLib + UefiRuntimeLib + +# Current usage of this library expects GCC in a UNIX-like shell environment with the date command +[BuildOptions] + GCC:*_*_*_CC_FLAGS = -DBUILD_EPOCH=`date +%s` diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/MetronomeDxe/Metronome.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/MetronomeDxe/Metronome.c new file mode 100644 index 00000000..e70b5d2a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/MetronomeDxe/Metronome.c @@ -0,0 +1,134 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Copyright (c) 2013, ARM Ltd. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +EFI_STATUS +EFIAPI +WaitForTick ( + IN EFI_METRONOME_ARCH_PROTOCOL *This, + IN UINT32 TickNumber + ); + +/** + Interface structure for the Metronome Architectural Protocol. + + @par Protocol Description: + This protocol provides access to a known time source in the platform to the + core. The core uses this known time source to produce core services that + require calibrated delays. + + @param WaitForTick + Waits for a specified number of ticks from a known time source + in the platform. The actual time passed between entry of this + function and the first tick is between 0 and TickPeriod 100 nS + units. If you want to guarantee that at least TickPeriod time + has elapsed, wait for two ticks. + + @param TickPeriod + The period of platform's known time source in 100 nS units. + This value on any platform must be at least 10 uS, and must not + exceed 200 uS. The value in this field is a constant that must + not be modified after the Metronome architectural protocol is + installed. All consumers must treat this as a read-only field. + +**/ +EFI_METRONOME_ARCH_PROTOCOL gMetronome = { + WaitForTick, + FixedPcdGet32 (PcdMetronomeTickPeriod) +}; + + +/** + The WaitForTick() function waits for the number of ticks specified by + TickNumber from a known time source in the platform. If TickNumber of + ticks are detected, then EFI_SUCCESS is returned. The actual time passed + between entry of this function and the first tick is between 0 and + TickPeriod 100 nS units. If you want to guarantee that at least TickPeriod + time has elapsed, wait for two ticks. This function waits for a hardware + event to determine when a tick occurs. It is possible for interrupt + processing, or exception processing to interrupt the execution of the + WaitForTick() function. Depending on the hardware source for the ticks, it + is possible for a tick to be missed. This function cannot guarantee that + ticks will not be missed. If a timeout occurs waiting for the specified + number of ticks, then EFI_TIMEOUT is returned. + + @param This The EFI_METRONOME_ARCH_PROTOCOL instance. + @param TickNumber Number of ticks to wait. + + @retval EFI_SUCCESS The wait for the number of ticks specified by TickNumber + succeeded. + @retval EFI_TIMEOUT A timeout occurred waiting for the specified number of ticks. + +**/ +EFI_STATUS +EFIAPI +WaitForTick ( + IN EFI_METRONOME_ARCH_PROTOCOL *This, + IN UINT32 TickNumber + ) +{ + // + // Compute how long to stall the CPU. + // gMetronome.TickPeriod is in 100 ns units so it needs to be divided by 10 + // to get it in microseconds units. + // + MicroSecondDelay (TickNumber * gMetronome.TickPeriod / 10); + return EFI_SUCCESS; +} + + +EFI_HANDLE gMetronomeHandle = NULL; + + + +/** + Initialize the state information for the CPU Architectural Protocol + + @param ImageHandle of the loaded driver + @param SystemTable Pointer to the System Table + + @retval EFI_SUCCESS Protocol registered + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure + @retval EFI_DEVICE_ERROR Hardware problems + +**/ +EFI_STATUS +EFIAPI +MetronomeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Do any hardware init required to make WaitForTick () to work here. + // + + Status = gBS->InstallMultipleProtocolInterfaces ( + &gMetronomeHandle, + &gEfiMetronomeArchProtocolGuid, &gMetronome, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf new file mode 100644 index 00000000..16fadbe8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf @@ -0,0 +1,44 @@ +#/** @file +# +# Component description file for Bds module +# +# Copyright (c) 2008, Apple Inc. All rights reserved. +# Copyright (c) 2012, ARM Ltd. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MetronomeDxe + FILE_GUID = 4C6E0267-C77D-410D-8100-1495911A989D + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = MetronomeInitialize + +[Sources.common] + Metronome.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + BaseLib + UefiLib + UefiBootServicesTableLib + DebugLib + PrintLib + UefiDriverEntryPoint + TimerLib + +[FixedPcd] + gEmbeddedTokenSpaceGuid.PcdMetronomeTickPeriod + +[Protocols] + gEfiMetronomeArchProtocolGuid + +[depex] + TRUE diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClock.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClock.c new file mode 100644 index 00000000..5081d612 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClock.c @@ -0,0 +1,227 @@ +/** @file + Implement EFI RealTimeClock runtime services via RTC Lib. + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+ Copyright (c) 2021, Ampere Computing LLC. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +EFI_HANDLE mHandle = NULL; + +// +// These values can be set by SetTime () and need to be returned by GetTime () +// but cannot usually be kept by the RTC hardware, so we store them in a UEFI +// variable instead. +// +typedef struct { + INT16 TimeZone; + UINT8 Daylight; +} NON_VOLATILE_TIME_SETTINGS; + +STATIC CONST CHAR16 mTimeSettingsVariableName[] = L"RtcTimeSettings"; +STATIC NON_VOLATILE_TIME_SETTINGS mTimeSettings; + +/** + Returns the current time and date information, and the time-keeping capabilities + of the hardware platform. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time clock + device's capabilities. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +EFI_STATUS +EFIAPI +GetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +{ + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Set these first so the RealTimeClockLib implementation + // can override them based on its own settings. + // + Time->TimeZone = mTimeSettings.TimeZone; + Time->Daylight = mTimeSettings.Daylight; + + return LibGetTime (Time, Capabilities); +} + + + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +EFI_STATUS +EFIAPI +SetTime ( + IN EFI_TIME *Time + ) +{ + EFI_STATUS Status; + BOOLEAN TimeSettingsChanged; + + if (Time == NULL || !IsTimeValid (Time)) { + return EFI_INVALID_PARAMETER; + } + + TimeSettingsChanged = FALSE; + if (mTimeSettings.TimeZone != Time->TimeZone || + mTimeSettings.Daylight != Time->Daylight) { + + mTimeSettings.TimeZone = Time->TimeZone; + mTimeSettings.Daylight = Time->Daylight; + TimeSettingsChanged = TRUE; + } + + Status = LibSetTime (Time); + if (EFI_ERROR (Status)) { + return Status; + } + + if (TimeSettingsChanged) { + Status = EfiSetVariable ( + (CHAR16 *)mTimeSettingsVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (mTimeSettings), + (VOID *)&mTimeSettings); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + return EFI_SUCCESS; +} + + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgement. + @param Time The current alarm setting. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Any parameter is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + +**/ +EFI_STATUS +EFIAPI +GetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +{ + return LibGetWakeupTime (Enabled, Pending, Time); +} + + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If + Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +SetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ) +{ + return LibSetWakeupTime (Enabled, Time); +} + + + +/** + This is the declaration of an EFI image entry point. This can be the entry point to an application + written to this specification, an EFI boot service driver, or an EFI runtime driver. + + @param ImageHandle Handle that identifies the loaded image. + @param SystemTable System Table for this image. + + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +EFIAPI +InitializeRealTimeClock ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINTN Size; + + Status = LibRtcInitialize (ImageHandle, SystemTable); + if (EFI_ERROR (Status)) { + return Status; + } + + Size = sizeof (mTimeSettings); + Status = EfiGetVariable ((CHAR16 *)mTimeSettingsVariableName, + &gEfiCallerIdGuid, NULL, &Size, (VOID *)&mTimeSettings); + if (EFI_ERROR (Status) || + !IsValidTimeZone (mTimeSettings.TimeZone) || + !IsValidDaylight (mTimeSettings.Daylight)) { + DEBUG ((DEBUG_WARN, "%a: using default timezone/daylight settings\n", + __FUNCTION__)); + + mTimeSettings.TimeZone = EFI_UNSPECIFIED_TIMEZONE; + mTimeSettings.Daylight = 0; + } + + SystemTable->RuntimeServices->GetTime = GetTime; + SystemTable->RuntimeServices->SetTime = SetTime; + SystemTable->RuntimeServices->GetWakeupTime = GetWakeupTime; + SystemTable->RuntimeServices->SetWakeupTime = SetWakeupTime; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &mHandle, + &gEfiRealTimeClockArchProtocolGuid, + NULL, + NULL + ); + + return Status; +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf new file mode 100644 index 00000000..2f3a8234 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf @@ -0,0 +1,42 @@ +#/** @file +# Real Time Clock Architectural Protocol Driver as defined in PI +# +# Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.
+# Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+# Copyright (c) 2021, Ampere Computing LLC. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = RealTimeClock + FILE_GUID = B336F62D-4135-4A55-AE4E-4971BBF0885D + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeRealTimeClock + +[Sources.common] + RealTimeClock.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + DebugLib + RealTimeClockLib + TimeBaseLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeLib + +[Protocols] + gEfiRealTimeClockArchProtocolGuid + +[Depex] + gEfiVariableArchProtocolGuid + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf new file mode 100644 index 00000000..233b483b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf @@ -0,0 +1,45 @@ +#/** @file +# Reset Architectural Protocol Driver as defined in PI +# +# This Reset module simulates system reset by process exit on NT. +# Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Reset + FILE_GUID = 16036A73-E8EF-46D0-953C-9B8E96527D13 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeReset + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 +# + +[Sources.common] + reset.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + EfiResetSystemLib + +[Protocols] + gEfiResetArchProtocolGuid # PROTOCOL ALWAYS_PRODUCED + +[Depex] + TRUE + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/ResetRuntimeDxe/reset.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/ResetRuntimeDxe/reset.c new file mode 100644 index 00000000..48510215 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/ResetRuntimeDxe/reset.c @@ -0,0 +1,68 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + + +/** + Resets the entire platform. + + @param ResetType The type of reset to perform. + @param ResetStatus The status code for the reset. + @param DataSize The size, in bytes, of WatchdogData. + @param ResetData For a ResetType of EfiResetCold, EfiResetWarm, or + EfiResetShutdown the data buffer starts with a Null-terminated + Unicode string, optionally followed by additional binary data. + +**/ +VOID +EFIAPI +ResetSystemViaLib ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN VOID *ResetData OPTIONAL + ) +{ + LibResetSystem (ResetType, ResetStatus, DataSize, ResetData); + return; +} + + + +EFI_STATUS +EFIAPI +InitializeReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + LibInitializeResetSystem (ImageHandle, SystemTable); + + SystemTable->RuntimeServices->ResetSystem = ResetSystemViaLib; + + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiResetArchProtocolGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EFI.CMM b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EFI.CMM new file mode 100644 index 00000000..833d5405 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EFI.CMM @@ -0,0 +1,34 @@ +; +; Copyright (c) 2011, Hewlett-Packard Company. All rights reserved.
+; +; SPDX-License-Identifier: BSD-2-Clause-Patent +; + +;choose hex mode for input + radix hex + + menu.rp + ( + add + toolbar + ( + separator + toolitem "Reset Target" "RS" "sys.ResetTarget" + separator + toolitem "Load EFI DXE Symbols" "DX" "do EfiLoadDxe" + toolitem "Load EFI Runtime Symbols" "RT" "do EfiLoadRuntimeDxe" + ) + ) + + system.config.debugaccessport 0 + system.config.corebase 0x80001000 + system.attach + break.sel.program onchip + + setup.var %hex.on + setup.var %decimal.OFF + + +enddo + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiLoadDxe.cmm b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiLoadDxe.cmm new file mode 100644 index 00000000..2bcf5620 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiLoadDxe.cmm @@ -0,0 +1,129 @@ +; +; Copyright (c) 2011, Hewlett-Packard Company. All rights reserved.
+; +; SPDX-License-Identifier: BSD-2-Clause-Patent +; + + LOCAL &maxmem &systbl &memsize + + &memsize=0x20000000 ; default to 512MB + + gosub FindSystemTable &memsize + ENTRY &systbl + + if &systbl!=0 + ( + print "found system table at &systbl" + gosub FindDebugInfo &systbl + ) + else + ( + print "ERROR: system table not found, check memory size" + ) + enddo + +FindSystemTable: + LOCAL &TopOfRam &offset + ENTRY &TopOfRam + + print "FindSystemTable" + print "top of mem is &TopOfRam$" + + &offset=&TopOfRam + + ; align to highest 4MB boundary + &offset=&offset&0xFFC00000 + + ; start at top and look on 4MB boundaries for system table ptr structure + while &offset>0 + ( + ; low signature match + if Data.Long(a:&offset)==0x20494249 + ( + ; high signature match + if Data.Long(a:&offset+4)==0x54535953 + ( + ; less than 4GB? + if Data.Long(a:&offset+0x0c)==0 + ( + ; less than top of ram? + if Data.Long(a:&offset+8)<&TopOfRam + ( + return Data.Long(a:&offset+8) + ) + ) + ) + ) + + if &offset<0x400000 + ( + return 0 + ) + &offset=&offset-0x400000 + ) + + return 0 + + +FindDebugInfo: + LOCAL &SystemTable &CfgTableEntries &ConfigTable &i &offset &dbghdr &dbgentries &dbgptr &dbginfo &loadedimg + ENTRY &SystemTable + + print "FindDebugInfo" + + &dbgentries=0 + &CfgTableEntries=Data.Long(a:&SystemTable+0x40) + &ConfigTable=Data.Long(a:&SystemTable+0x44) + + print "config table is at &ConfigTable (&CfgTableEntries entries)" + + ; now search for debug info entry with guid 49152E77-1ADA-4764-B7A2-7AFEFED95E8B + ; 0x49152E77 0x47641ADA 0xFE7AA2B7 0x8B5ED9FE + &i=0 + while &i<&CfgTableEntries + ( + &offset=&ConfigTable+(&i*0x14) + if Data.Long(a:&offset)==0x49152E77 + ( + if Data.Long(a:&offset+4)==0x47641ADA + ( + if Data.Long(a:&offset+8)==0xFE7AA2B7 + ( + if Data.Long(a:&offset+0xc)==0x8B5ED9FE + ( + &dbghdr=Data.Long(a:&offset+0x10) + &dbgentries=Data.Long(a:&dbghdr+4) + &dbgptr=Data.Long(a:&dbghdr+8) + ) + ) + ) + ) + + &i=&i+1 + ) + + if &dbgentries==0 + ( + print "no debug entries found" + return + ) + + print "debug table at &dbgptr (&dbgentries entries)" + + symbol.reset + + &i=0 + while &i<&dbgentries + ( + &dbginfo=Data.Long(a:&dbgptr+(&i*4)) + if &dbginfo!=0 + ( + if Data.Long(a:&dbginfo)==1 ; normal debug info type + ( + &loadedimg=Data.Long(a:&dbginfo+4) + do EfiProcessPeImage Data.Long(a:&loadedimg+0x20) + ) + ) + &i=&i+1 + ) + return diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiLoadFv.cmm b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiLoadFv.cmm new file mode 100644 index 00000000..efb59f78 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiLoadFv.cmm @@ -0,0 +1,125 @@ +; +; Copyright (c) 2011, Hewlett-Packard Company. All rights reserved.
+; +; SPDX-License-Identifier: BSD-2-Clause-Patent +; + + LOCAL &fvbase &fvsig &fvsig &ffsoffset &ffsfilesize &ffsfileaddr + ENTRY &fvbase + + &fvsig=Data.Long(a:&fvbase+0x28) + if &fvsig!=0x4856465F + ( + print "FV does not have proper signature, exiting" + return + ) + + print "FV signature found" + + &fvlen=Data.Long(a:&fvbase+0x20) + + ; first ffs file is after fv header, use headerlength field + &ffsoffset=(Data.Long(a:&fvbase+0x30)&0xffff) + + ; loop through ffs files + &ffsfilesize=1 + while (&ffsfilesize!=0)&&(&ffsoffset<(&fvlen)) + ( + &ffsfileaddr=&fvbase+&ffsoffset + ;print "found ffs file at &ffsfileaddr" + + ; process ffs file and increment by ffs file size field + gosub ProcessFfsFile &ffsfileaddr + + &ffsfilesize=(Data.Long(a:&ffsfileaddr+0x14)&0x00ffffff) + ;print "ffsfilesize is &ffsfilesize" + + &ffsoffset=&ffsoffset+&ffsfilesize + + &ffsfilesize=(Data.Long(a:&fvbase+&ffsoffset+0x14)&0x00ffffff) + ;print "ffsfilesize now is &ffsfilesize" + if &ffsfilesize==0xffffff + ( + enddo + ) + + ; align to next 8 byte boundary + if (&ffsoffset&0x7)!=0 + ( + &ffsoffset=&ffsoffset+(0x8-(&ffsoffset&0x7)) + ) + + ) ; end fv ffs loop + +enddo + +ProcessFfsFile: + LOCAL &ffsfilestart &ffsfilesize &ffsfiletype &secoffset &secsize + ENTRY &ffsfilestart + + ;print "processing ffs file at &ffsfilestart" + &ffsfilesize=Data.Long(a:&ffsfilestart+0x14) + &ffsfiletype=(&ffsfilesize&0xff000000)>>24. + &ffsfilesize=&ffsfilesize&0x00ffffff + + if &ffsfiletype==0 + ( + return + ) + + print "ffs file at &ffsfilestart size &ffsfilesize type &ffsfiletype" + + &secoffset=&ffsfilestart+0x18 + + ; loop through sections in file + while &secoffset<(&ffsfilestart+&ffsfilesize) + ( + print "secoffset at &secoffset" + + ; process fv section and increment section offset by size + &secsize=(Data.Long(a:&secoffset)&0x00ffffff) + + gosub ProcessFvSection &secoffset + + + &secoffset=(&secoffset+&secsize) + + ;print "secsize is &secsize" + ;print "secoffset at &secoffset" + + ; align to next 4 byte boundary + if (&secoffset&0x3)!=0 + ( + &secoffset=&secoffset+(0x4-(&secoffset&0x3)) + ) + ) ; end section loop + return + + +ProcessFvSection: + LOCAL &secstart §ionsize §iontype &secoffset &secsize + ENTRY &secstart + + §ionsize=Data.Long(a:&secstart) + §iontype=((§ionsize&0xff000000)>>24.) + §ionsize=§ionsize&0x00ffffff; + + print "fv section at &secstart size §ionsize type §iontype" + + if §iontype==0x10 ; PE32 + ( + do EfiProcessPeImage (&secstart+0x4) + ) + else + ( + if §iontype==0x12 ; TE + ( + do EfiProcessTeImage (&secstart+0x4) + ) + else + ( + print "unknown section type" + ) + ) + + return diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiProcessPeImage.cmm b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiProcessPeImage.cmm new file mode 100644 index 00000000..70a3a797 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiProcessPeImage.cmm @@ -0,0 +1,71 @@ +; +; Copyright (c) 2011, Hewlett-Packard Company. All rights reserved.
+; +; SPDX-License-Identifier: BSD-2-Clause-Patent +; + + LOCAL &imgstart &filehdrstart &debugdirentryrva &debugtype &debugrva &dwarfsig &baseofcode &baseofdata &elfbase &elfpath &pathoffset + ENTRY &imgstart + + &imgstart=&imgstart + print "PE32 image found at &imgstart" + + ; offset from dos hdr to PE file hdr + &filehdrstart=&imgstart+Data.Long(c:&imgstart+0x3C) + + ; offset to debug dir in PE hdrs + &debugdirentryrva=Data.Long(c:&filehdrstart+0xA8) + if &debugdirentryrva==0 + ( + print "no debug dir for image at &imgstart" + enddo + ) + + &debugtype=Data.Long(c:&imgstart+&debugdirentryrva+0xc) + if (&debugtype!=0xdf)&&(&debugtype!=0x02) + ( + print "debug type is not dwarf for image at &imgstart, it's &debugtype" + enddo + ) + + &debugrva=Data.Long(c:&imgstart+&debugdirentryrva+0x14) + &dwarfsig=Data.Long(c:&imgstart+&debugrva) + + if &dwarfsig==0x66727764 + ( + &pathoffset=0xc + ) + else + ( + if &dwarfsig==0x3031424E + ( + &pathoffset=0x10 + ) + else + ( + print "debug signature not found for image at &imgstart, its &dwarfsig" + enddo + ) + ) + + &elfpath=Data.String(c:&imgstart+&debugrva+&pathoffset) + + &baseofcode=&imgstart+Data.Long(c:&filehdrstart+0x28) + &baseofdata=&imgstart+Data.Long(c:&filehdrstart+0x2c) + + if (&baseofcode<&baseofdata)&&(&baseofcode!=0) + ( + &elfbase=&baseofcode; + ) + else + ( + &elfbase=&baseofdata; + ) + + print "found path &elfpath" + ON ERROR GOSUB + return + data.load.elf &elfpath &elfbase /NOCODE /NOCLEAR + ON error + +enddo diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiProcessTeImage.cmm b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiProcessTeImage.cmm new file mode 100644 index 00000000..c23722d8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/EfiProcessTeImage.cmm @@ -0,0 +1,64 @@ +; +; Copyright (c) 2011, Hewlett-Packard Company. All rights reserved.
+; +; SPDX-License-Identifier: BSD-2-Clause-Patent +; + + LOCAL &imgstart &strippedsize &debugdirentryrva &debugtype &debugrva &dwarfsig &elfbase &elfpath &pathoffset + ENTRY &imgstart + + &imgstart=&imgstart + print "TE image found at &imgstart" + + ; determine pe header bytes removed to account for in rva references + &strippedsize=(Data.Long(a:&imgstart+0x4)&0xffff0000)>>16. + &strippedsize=&strippedsize-0x28 + + &debugdirentryrva=Data.Long(a:&imgstart+0x20) + if &debugdirentryrva==0 + ( + print "no debug dir for image at &imgstart" + enddo + ) + &debugdirentryrva=&debugdirentryrva-&strippedsize + + &debugtype=Data.Long(a:&imgstart+&debugdirentryrva+0xc) + if (&debugtype!=0xdf)&&(&debugtype!=0x02) + ( + print "debug type is not dwarf for image at &imgstart, it's &debugtype" + enddo + ) + + &debugrva=Data.Long(a:&imgstart+&debugdirentryrva+0x14) + &debugrva=&debugrva-&strippedsize; + &dwarfsig=Data.Long(a:&imgstart+&debugrva); + if &dwarfsig==0x66727764 + ( + &pathoffset=0xc + ) + else + ( + if &dwarfsig==0x3031424E + ( + &pathoffset=0x10 + ) + else + ( + print "debug signature not found for image at &imgstart, its &dwarfsig" + enddo + ) + ) + + &elfpath=Data.String(c:&imgstart+&debugrva+&pathoffset) + + ; elf base is baseofcode (we hope that for TE images it's not baseofdata) + &elfbase=&imgstart+Data.Long(a:&imgstart+0xc)-&strippedsize + + print "found path &elfpath" + ; $fprintf 50, "load /ni /np /a %s &0x%x\n",elfpath,elfbase$; + ON ERROR GOSUB + return + data.load.elf &elfpath &elfbase /NOCODE /NOCLEAR + ON error + +enddo diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/Readme.md b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/Readme.md new file mode 100644 index 00000000..845bc469 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/Readme.md @@ -0,0 +1,16 @@ +# DXE Phase Debug +Update the memsize variable in EfiLoadDxe.cmm for the actual amount of memory +available in your system. Allow your system to boot to the point that the DXE +core is initialized (so that the System Table and Debug Information table is +present in memory) and execute this script (using the toolbar button or +'do EfiLoadDxe' from the command area). It will scan memory for the debug info +table and load modules in it. + +# SEC/PEI Phase Debug +There is no way to autodetect where these images reside so you must pass an +address for the memory-mapped Firmware Volume containing these images. To do +this, enter 'do EfiLoadFv ' where is the base address for the +firmware volume containing the SEC or PEI code. To be more efficient you may +want to create a script that calls this, like MyBoardLoadSec.cmm which contains +the call to EfiLoadFv. You can them map this script to a T32 menu or toolbar +button for quick access. diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/T32.CMM b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/T32.CMM new file mode 100644 index 00000000..fa7a4ab4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Scripts/LauterbachT32/T32.CMM @@ -0,0 +1,59 @@ +; +; Copyright (c) 2011, Hewlett-Packard Company. All rights reserved.
+; +; SPDX-License-Identifier: BSD-2-Clause-Patent +; + +; Copy this to your C:\T32 directory +;Default startup program for TRACE32 +; +;This startup program can be modified according to your needs. + +; update this path to reflect YOUR current working dir +GLOBAL &wcdir +&wcdir="D:\bios" + +;choose hex mode for input + radix hex + +;Add some extra buttons to the toolbar + + menu.rp + ( + add + toolbar + ( + separator + toolitem "Source/List" ":list" "Data.List" + toolitem "Memory Dump" ":dump" "Data.dump" + toolitem "Register" ":reg" "Register" + separator + toolitem "Watch" ":varwatch" "Var.Watch" + toolitem "Stack" ":varframe" "Var.Frame /l /c" + toolitem "Automatic Watch" ":varref" "Var.Ref" + separator + toolitem "List Breakpoints" ":break" "Break.List" + toolitem "List Symbols" ":symbols" "sYmbol.Browse" + toolitem "System Settings" ":config" "SYStem" + separator + ) + ) + + if language()!="" + ( + local &menuname + &menuname="~~/t32"+language()+".men" + if os.file(&menuname) + menu.rp &menuname + ) + +;Recall and Define History File + autostore , history bookmark + +; Execute EFI setup script + chdir &wcdir\Platform\T32_Scripts + do EFI + +enddo + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOut.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOut.c new file mode 100644 index 00000000..ab11da1b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOut.c @@ -0,0 +1,753 @@ +/** @file + Simple Console that sits on a SerialLib. + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +/* + Symbols used in table below +=========================== + ESC = 0x1B + CSI = 0x9B + DEL = 0x7f + ^ = CTRL + ++=========+======+===========+==========+==========+ +| | EFI | UEFI 2.0 | | | +| | Scan | | VT100+ | | +| KEY | Code | PC ANSI | VTUTF8 | VT100 | ++=========+======+===========+==========+==========+ +| NULL | 0x00 | | | | +| UP | 0x01 | ESC [ A | ESC [ A | ESC [ A | +| DOWN | 0x02 | ESC [ B | ESC [ B | ESC [ B | +| RIGHT | 0x03 | ESC [ C | ESC [ C | ESC [ C | +| LEFT | 0x04 | ESC [ D | ESC [ D | ESC [ D | +| HOME | 0x05 | ESC [ H | ESC h | ESC [ H | +| END | 0x06 | ESC [ F | ESC k | ESC [ K | +| INSERT | 0x07 | ESC [ @ | ESC + | ESC [ @ | +| | | ESC [ L | | ESC [ L | +| DELETE | 0x08 | ESC [ X | ESC - | ESC [ P | +| PG UP | 0x09 | ESC [ I | ESC ? | ESC [ V | +| | | | | ESC [ ? | +| PG DOWN | 0x0A | ESC [ G | ESC / | ESC [ U | +| | | | | ESC [ / | +| F1 | 0x0B | ESC [ M | ESC 1 | ESC O P | +| F2 | 0x0C | ESC [ N | ESC 2 | ESC O Q | +| F3 | 0x0D | ESC [ O | ESC 3 | ESC O w | +| F4 | 0x0E | ESC [ P | ESC 4 | ESC O x | +| F5 | 0x0F | ESC [ Q | ESC 5 | ESC O t | +| F6 | 0x10 | ESC [ R | ESC 6 | ESC O u | +| F7 | 0x11 | ESC [ S | ESC 7 | ESC O q | +| F8 | 0x12 | ESC [ T | ESC 8 | ESC O r | +| F9 | 0x13 | ESC [ U | ESC 9 | ESC O p | +| F10 | 0x14 | ESC [ V | ESC 0 | ESC O M | +| Escape | 0x17 | ESC | ESC | ESC | +| F11 | 0x15 | | ESC ! | | +| F12 | 0x16 | | ESC @ | | ++=========+======+===========+==========+==========+ + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#define MODE0_COLUMN_COUNT 80 +#define MODE0_ROW_COUNT 25 + + +EFI_STATUS +EFIAPI +TextInReset( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + + +EFI_STATUS +EFIAPI +ReadKeyStroke( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ); + + +EFI_STATUS +EFIAPI +TextOutReset( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +CHAR8 * +EFIAPI +SafeUnicodeStrToAsciiStr ( + IN CONST CHAR16 *Source, + OUT CHAR8 *Destination + ); + +EFI_STATUS +EFIAPI +OutputString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *String + ); + + +EFI_STATUS +EFIAPI +TestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *String + ); + + +EFI_STATUS +EFIAPI +QueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ); + + +EFI_STATUS +EFIAPI +SetMode( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ); + + +EFI_STATUS +EFIAPI +SetAttribute( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ); + + +EFI_STATUS +EFIAPI +ClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ); + + +EFI_STATUS +EFIAPI +SetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ); + + +EFI_STATUS +EFIAPI +EnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Enable + ); + + + EFI_SIMPLE_TEXT_INPUT_PROTOCOL mSimpleTextIn = { + TextInReset, + ReadKeyStroke, + NULL +}; + + EFI_SIMPLE_TEXT_OUTPUT_MODE mSimpleTextOutMode = { + 1, + 0, + EFI_TEXT_ATTR( EFI_LIGHTGRAY, EFI_BLACK ), + 0, + 0, + TRUE +}; + +EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL mSimpleTextOut = { + TextOutReset, + OutputString, + TestString, + QueryMode, + SetMode, + SetAttribute, + ClearScreen, + SetCursorPosition, + EnableCursor, + &mSimpleTextOutMode +}; + +EFI_HANDLE mInstallHandle = NULL; + +typedef struct { + VENDOR_DEVICE_PATH Guid; + UART_DEVICE_PATH Uart; + EFI_DEVICE_PATH_PROTOCOL End; +} SIMPLE_TEXT_OUT_DEVICE_PATH; + +SIMPLE_TEXT_OUT_DEVICE_PATH mDevicePath = { + { + { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0} }, + EFI_CALLER_ID_GUID + }, + { + { MESSAGING_DEVICE_PATH, MSG_UART_DP, { sizeof (UART_DEVICE_PATH), 0} }, + 0, // Reserved + FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate + FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits + FixedPcdGet8 (PcdUartDefaultParity), // Parity (N) + FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits + }, + { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0} } +}; + + + + +BOOLEAN +TextOutIsValidAscii ( + IN CHAR16 Ascii + ) +{ + // + // valid ASCII code lies in the extent of 0x20 - 0x7F + // + if ((Ascii >= 0x20) && (Ascii <= 0x7F)) { + return TRUE; + } + + return FALSE; +} + + +BOOLEAN +TextOutIsValidEfiCntlChar ( + IN CHAR16 Char + ) +{ + // + // only support four control characters. + // + if (Char == CHAR_NULL || + Char == CHAR_BACKSPACE || + Char == CHAR_LINEFEED || + Char == CHAR_CARRIAGE_RETURN || + Char == CHAR_TAB ) { + return TRUE; + } + + return FALSE; +} + + +VOID +EFIAPI +WaitForKeyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + if (SerialPortPoll ()) { + gBS->SignalEvent (Event); + } +} + + +EFI_STATUS +EFIAPI +TextInReset ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +ReadKeyStroke ( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +{ + CHAR8 Char; + + if (!SerialPortPoll ()) { + return EFI_NOT_READY; + } + + SerialPortRead ((UINT8 *)&Char, 1); + + // + // Check for ESC sequence. This code is not technically correct VT100 code. + // An illegal ESC sequence represents an ESC and the characters that follow. + // This code will eat one or two chars after an escape. This is done to + // prevent some complex FIFOing of the data. It is good enough to get + // the arrow and delete keys working + // + Key->UnicodeChar = 0; + Key->ScanCode = SCAN_NULL; + if (Char == 0x1b) { + SerialPortRead ((UINT8 *)&Char, 1); + if (Char == '[') { + SerialPortRead ((UINT8 *)&Char, 1); + switch (Char) { + case 'A': + Key->ScanCode = SCAN_UP; + break; + case 'B': + Key->ScanCode = SCAN_DOWN; + break; + case 'C': + Key->ScanCode = SCAN_RIGHT; + break; + case 'D': + Key->ScanCode = SCAN_LEFT; + break; + case 'H': + Key->ScanCode = SCAN_HOME; + break; + case 'K': + case 'F': // PC ANSI + Key->ScanCode = SCAN_END; + break; + case '@': + case 'L': + Key->ScanCode = SCAN_INSERT; + break; + case 'P': + case 'X': // PC ANSI + Key->ScanCode = SCAN_DELETE; + break; + case 'U': + case '/': + case 'G': // PC ANSI + Key->ScanCode = SCAN_PAGE_DOWN; + break; + case 'V': + case '?': + case 'I': // PC ANSI + Key->ScanCode = SCAN_PAGE_UP; + break; + + // PCANSI that does not conflict with VT100 + case 'M': + Key->ScanCode = SCAN_F1; + break; + case 'N': + Key->ScanCode = SCAN_F2; + break; + case 'O': + Key->ScanCode = SCAN_F3; + break; + case 'Q': + Key->ScanCode = SCAN_F5; + break; + case 'R': + Key->ScanCode = SCAN_F6; + break; + case 'S': + Key->ScanCode = SCAN_F7; + break; + case 'T': + Key->ScanCode = SCAN_F8; + break; + + default: + Key->UnicodeChar = Char; + break; + } + } else if (Char == '0') { + SerialPortRead ((UINT8 *)&Char, 1); + switch (Char) { + case 'P': + Key->ScanCode = SCAN_F1; + break; + case 'Q': + Key->ScanCode = SCAN_F2; + break; + case 'w': + Key->ScanCode = SCAN_F3; + break; + case 'x': + Key->ScanCode = SCAN_F4; + break; + case 't': + Key->ScanCode = SCAN_F5; + break; + case 'u': + Key->ScanCode = SCAN_F6; + break; + case 'q': + Key->ScanCode = SCAN_F7; + break; + case 'r': + Key->ScanCode = SCAN_F8; + break; + case 'p': + Key->ScanCode = SCAN_F9; + break; + case 'm': + Key->ScanCode = SCAN_F10; + break; + default : + break; + } + } + } else if (Char < ' ') { + if ((Char == CHAR_BACKSPACE) || + (Char == CHAR_TAB) || + (Char == CHAR_LINEFEED) || + (Char == CHAR_CARRIAGE_RETURN)) { + // Only let through EFI required control characters + Key->UnicodeChar = (CHAR16)Char; + } + } else if (Char == 0x7f) { + Key->ScanCode = SCAN_DELETE; + } else { + Key->UnicodeChar = (CHAR16)Char; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +TextOutReset ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + EFI_STATUS Status; + + This->SetAttribute( + This, + EFI_TEXT_ATTR(This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK) + ); + + Status = This->SetMode (This, 0); + + return Status; +} + +CHAR8 * +EFIAPI +SafeUnicodeStrToAsciiStr ( + IN CONST CHAR16 *Source, + OUT CHAR8 *Destination + ) +{ + CHAR8 *ReturnValue; + + ASSERT (Destination != NULL); + + // + // ASSERT if Source is long than PcdMaximumUnicodeStringLength. + // Length tests are performed inside StrLen(). + // + ASSERT (StrSize (Source) != 0); + + // + // Source and Destination should not overlap + // + ASSERT ((UINTN) ((CHAR16 *) Destination - Source) > StrLen (Source)); + ASSERT ((UINTN) ((CHAR8 *) Source - Destination) > StrLen (Source)); + + + ReturnValue = Destination; + while (*Source != '\0') { + // + // If any non-ascii characters in Source then replace it with '?'. + // + if (*Source < 0x80) { + *Destination = (CHAR8) *Source; + } else { + *Destination = '?'; + + //Surrogate pair check. + if ((*Source >= 0xD800) && (*Source <= 0xDFFF)) { + Source++; + } + } + + Destination++; + Source++; + } + + *Destination = '\0'; + + // + // ASSERT Original Destination is less long than PcdMaximumAsciiStringLength. + // Length tests are performed inside AsciiStrLen(). + // + ASSERT (AsciiStrSize (ReturnValue) != 0); + + return ReturnValue; +} + +EFI_STATUS +EFIAPI +OutputString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *String + ) +{ + UINTN Size; + CHAR8* OutputString; + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode; + UINTN MaxColumn; + UINTN MaxRow; + + Size = StrLen(String) + 1; + OutputString = AllocatePool(Size); + + //If there is any non-ascii characters in String buffer then replace it with '?' + //Eventually, UnicodeStrToAsciiStr API should be fixed. + SafeUnicodeStrToAsciiStr(String, OutputString); + SerialPortWrite ((UINT8 *)OutputString, Size - 1); + + // + // Parse each character of the string to output + // to update the cursor position information + // + Mode = This->Mode; + + Status = This->QueryMode ( + This, + Mode->Mode, + &MaxColumn, + &MaxRow + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (; *String != CHAR_NULL; String++) { + + switch (*String) { + case CHAR_BACKSPACE: + if (Mode->CursorColumn > 0) { + Mode->CursorColumn--; + } + break; + + case CHAR_LINEFEED: + if (Mode->CursorRow < (INT32) (MaxRow - 1)) { + Mode->CursorRow++; + } + break; + + case CHAR_CARRIAGE_RETURN: + Mode->CursorColumn = 0; + break; + + default: + if (Mode->CursorColumn >= (INT32) (MaxColumn - 1)) { + // Move the cursor as if we print CHAR_CARRIAGE_RETURN & CHAR_LINE_FEED + // CHAR_LINEFEED + if (Mode->CursorRow < (INT32) (MaxRow - 1)) { + Mode->CursorRow++; + } + // CHAR_CARIAGE_RETURN + Mode->CursorColumn = 0; + } else { + Mode->CursorColumn++; + } + break; + } + } + + FreePool(OutputString); + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +TestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *String + ) +{ + CHAR8 Character; + + for ( ; *String != CHAR_NULL; String++) { + Character = (CHAR8)*String; + if (!(TextOutIsValidAscii (Character) || TextOutIsValidEfiCntlChar (Character))) { + return EFI_UNSUPPORTED; + } + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +QueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +{ + if (This->Mode->MaxMode > 1) { + return EFI_DEVICE_ERROR; + } + + if (ModeNumber == 0) { + *Columns = MODE0_COLUMN_COUNT; + *Rows = MODE0_ROW_COUNT; + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +SetMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +{ + if (ModeNumber != 0) { + return EFI_UNSUPPORTED; + } + + This->Mode->Mode = 0; + This->ClearScreen (This); + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +SetAttribute( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ) +{ + This->Mode->Attribute = (INT32)Attribute; + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +ClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ) +{ + EFI_STATUS Status; + + Status = This->SetCursorPosition (This, 0, 0); + return Status; +} + + +EFI_STATUS +EFIAPI +SetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +{ + EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode; + EFI_STATUS Status; + UINTN MaxColumn; + UINTN MaxRow; + + Mode = This->Mode; + + Status = This->QueryMode( + This, + Mode->Mode, + &MaxColumn, + &MaxRow + ); + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + if ((Column >= MaxColumn) || (Row >= MaxRow)) { + return EFI_UNSUPPORTED; + } + + Mode->CursorColumn = (INT32)Column; + Mode->CursorRow = (INT32)Row; + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +EnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Enable + ) +{ + if (!Enable) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +SimpleTextInOutEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + WaitForKeyEvent, + NULL, + &mSimpleTextIn.WaitForKey + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->InstallMultipleProtocolInterfaces( + &mInstallHandle, + &gEfiSimpleTextInProtocolGuid, &mSimpleTextIn, + &gEfiSimpleTextOutProtocolGuid, &mSimpleTextOut, + &gEfiDevicePathProtocolGuid, &mDevicePath, + NULL + ); + if (!EFI_ERROR (Status)) { + gST->ConOut = &mSimpleTextOut; + gST->ConIn = &mSimpleTextIn; + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOutSerial.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOutSerial.inf new file mode 100644 index 00000000..dd060d8f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOutSerial.inf @@ -0,0 +1,56 @@ +#/** @file +# +# Component description file for Bds module +# +# Copyright (c) 2008, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SimpleTextInOutSerial + FILE_GUID = 6696936D-3637-467C-87CB-14EA8248948C + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = SimpleTextInOutEntryPoint + + +[Sources.common] + SimpleTextInOut.c + + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + BaseLib + ReportStatusCodeLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + UefiDriverEntryPoint + SerialPortLib + +[Guids] + + +[Protocols] + gEfiSimpleTextInProtocolGuid + gEfiSimpleTextOutProtocolGuid + gEfiSerialIoProtocolGuid + gEfiDevicePathProtocolGuid + +[FixedPcd] + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits + + +[depex] + TRUE diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/ComponentName.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/ComponentName.c new file mode 100644 index 00000000..3a559d38 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/ComponentName.c @@ -0,0 +1,156 @@ +/** @file + Component Name Protocol implementation for the MMC DXE driver + + Copyright (c) 2011, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Mmc.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gMmcComponentName = { + MmcGetDriverName, + MmcGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gMmcComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) MmcGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) MmcGetControllerName, + "en" +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE +mMmcDriverNameTable[] = { + {"eng;en", L"MMC/SD Card Interface Driver"}, + {NULL, NULL} +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + @param DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +MmcGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mMmcDriverNameTable, + DriverName, + (BOOLEAN)(This == &gMmcComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + @param ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + @param Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + @param ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +MmcGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/Diagnostics.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/Diagnostics.c new file mode 100644 index 00000000..7a9b37ad --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/Diagnostics.c @@ -0,0 +1,253 @@ +/** @file + Diagnostics Protocol implementation for the MMC DXE driver + + Copyright (c) 2011-2020, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +#include "Mmc.h" + +#define DIAGNOSTIC_LOGBUFFER_MAXCHAR 1024 + +CHAR16* mLogBuffer = NULL; +UINTN mLogRemainChar = 0; + +CHAR16* +DiagnosticInitLog ( + UINTN MaxBufferChar + ) +{ + mLogRemainChar = MaxBufferChar; + mLogBuffer = AllocatePool ((UINTN)MaxBufferChar * sizeof (CHAR16)); + return mLogBuffer; +} + +UINTN +DiagnosticLog ( + CONST CHAR16* Str + ) +{ + UINTN len = StrLen (Str); + if (len < mLogRemainChar) { + StrCpyS (mLogBuffer, mLogRemainChar, Str); + mLogRemainChar -= len; + mLogBuffer += len; + return len; + } else { + return 0; + } +} + +VOID +GenerateRandomBuffer ( + VOID* Buffer, + UINTN BufferSize + ) +{ + UINT64 i; + UINT64* Buffer64 = (UINT64*)Buffer; + + for (i = 0; i < (BufferSize >> 3); i++) { + *Buffer64 = i | LShiftU64 (~i, 32); + Buffer64++; + } +} + +BOOLEAN +CompareBuffer ( + VOID *BufferA, + VOID *BufferB, + UINTN BufferSize + ) +{ + UINTN i; + UINT64* BufferA64 = (UINT64*)BufferA; + UINT64* BufferB64 = (UINT64*)BufferB; + + for (i = 0; i < (BufferSize >> 3); i++) { + if (*BufferA64 != *BufferB64) { + DEBUG ((EFI_D_ERROR, "CompareBuffer: Error at %i", i)); + DEBUG ((EFI_D_ERROR, "(0x%lX) != (0x%lX)\n", *BufferA64, *BufferB64)); + return FALSE; + } + BufferA64++; + BufferB64++; + } + return TRUE; +} + +EFI_STATUS +MmcReadWriteDataTest ( + MMC_HOST_INSTANCE *MmcHostInstance, + EFI_LBA Lba, + UINTN BufferSize + ) +{ + VOID *BackBuffer; + VOID *WriteBuffer; + VOID *ReadBuffer; + EFI_STATUS Status; + + // Check if a Media is Present + if (!MmcHostInstance->BlockIo.Media->MediaPresent) { + DiagnosticLog (L"ERROR: No Media Present\n"); + return EFI_NO_MEDIA; + } + + if (MmcHostInstance->State != MmcTransferState) { + DiagnosticLog (L"ERROR: Not ready for Transfer state\n"); + return EFI_NOT_READY; + } + + BackBuffer = AllocatePool (BufferSize); + WriteBuffer = AllocatePool (BufferSize); + ReadBuffer = AllocatePool (BufferSize); + + // Read (and save) buffer at a specific location + Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,BackBuffer); + if (Status != EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Read Block (1)\n"); + return Status; + } + + // Write buffer at the same location + GenerateRandomBuffer (WriteBuffer,BufferSize); + Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,WriteBuffer); + if (Status != EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Write Block (1)\n"); + return Status; + } + + // Read the buffer at the same location + Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,ReadBuffer); + if (Status != EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Read Block (2)\n"); + return Status; + } + + // Check that is conform + if (!CompareBuffer (ReadBuffer,WriteBuffer,BufferSize)) { + DiagnosticLog (L"ERROR: Fail to Read/Write Block (1)\n"); + return EFI_INVALID_PARAMETER; + } + + // Restore content at the original location + Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,BackBuffer); + if (Status != EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Write Block (2)\n"); + return Status; + } + + // Read the restored content + Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,ReadBuffer); + if (Status != EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Read Block (3)\n"); + return Status; + } + + // Check the content is correct + if (!CompareBuffer (ReadBuffer,BackBuffer,BufferSize)) { + DiagnosticLog (L"ERROR: Fail to Read/Write Block (2)\n"); + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MmcDriverDiagnosticsRunDiagnostics ( + IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType, + IN CHAR8 *Language, + OUT EFI_GUID **ErrorType, + OUT UINTN *BufferSize, + OUT CHAR16 **Buffer + ) +{ + LIST_ENTRY *CurrentLink; + MMC_HOST_INSTANCE *MmcHostInstance; + EFI_STATUS Status; + + if ((Language == NULL) || + (ErrorType == NULL) || + (Buffer == NULL) || + (ControllerHandle == NULL) || + (BufferSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Check Language is supported (i.e. is "en-*" - only English is supported) + if (AsciiStrnCmp (Language, "en", 2) != 0) { + return EFI_UNSUPPORTED; + } + + Status = EFI_SUCCESS; + *ErrorType = NULL; + *BufferSize = DIAGNOSTIC_LOGBUFFER_MAXCHAR; + *Buffer = DiagnosticInitLog (DIAGNOSTIC_LOGBUFFER_MAXCHAR); + + DiagnosticLog (L"MMC Driver Diagnostics\n"); + + // Find the MMC Host instance on which we have been asked to run diagnostics + MmcHostInstance = NULL; + CurrentLink = mMmcHostPool.ForwardLink; + while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) { + MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink); + ASSERT(MmcHostInstance != NULL); + if (MmcHostInstance->MmcHandle == ControllerHandle) { + break; + } + CurrentLink = CurrentLink->ForwardLink; + } + + // If we didn't find the controller, return EFI_UNSUPPORTED + if ((MmcHostInstance == NULL) + || (MmcHostInstance->MmcHandle != ControllerHandle)) { + return EFI_UNSUPPORTED; + } + + // LBA=1 Size=BlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block\n"); + Status = MmcReadWriteDataTest (MmcHostInstance, 1, MmcHostInstance->BlockIo.Media->BlockSize); + + // LBA=2 Size=BlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: Second Block\n"); + Status = MmcReadWriteDataTest (MmcHostInstance, 2, MmcHostInstance->BlockIo.Media->BlockSize); + + // LBA=10 Size=BlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: Any Block\n"); + Status = MmcReadWriteDataTest ( + MmcHostInstance, + RShiftU64 (MmcHostInstance->BlockIo.Media->LastBlock, 1), + MmcHostInstance->BlockIo.Media->BlockSize + ); + + // LBA=LastBlock Size=BlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: Last Block\n"); + Status = MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock, MmcHostInstance->BlockIo.Media->BlockSize); + + // LBA=1 Size=2*BlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block / 2 BlockSSize\n"); + Status = MmcReadWriteDataTest (MmcHostInstance, 1, 2 * MmcHostInstance->BlockIo.Media->BlockSize); + + return Status; +} + +// +// EFI Driver Diagnostics 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gMmcDriverDiagnostics2 = { + (EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS) MmcDriverDiagnosticsRunDiagnostics, + "en" +}; diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/Mmc.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/Mmc.c new file mode 100644 index 00000000..682d0828 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/Mmc.c @@ -0,0 +1,452 @@ +/** @file + Main file of the MMC Dxe driver. The driver entrypoint is defined into this file. + + Copyright (c) 2011-2013, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include + +#include "Mmc.h" + +EFI_BLOCK_IO_MEDIA mMmcMediaTemplate = { + SIGNATURE_32('m','m','c','o'), // MediaId + TRUE, // RemovableMedia + FALSE, // MediaPresent + FALSE, // LogicalPartition + FALSE, // ReadOnly + FALSE, // WriteCaching + 512, // BlockSize + 4, // IoAlign + 0, // Pad + 0 // LastBlock +}; + +// +// This device structure is serviced as a header. +// Its next field points to the first root bridge device node. +// +LIST_ENTRY mMmcHostPool; + +/** + Event triggered by the timer to check if any cards have been removed + or if new ones have been plugged in +**/ + +EFI_EVENT gCheckCardsEvent; + +/** + Initialize the MMC Host Pool to support multiple MMC devices +**/ +VOID +InitializeMmcHostPool ( + VOID + ) +{ + InitializeListHead (&mMmcHostPool); +} + +/** + Insert a new Mmc Host controller to the pool +**/ +VOID +InsertMmcHost ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + InsertTailList (&mMmcHostPool, &(MmcHostInstance->Link)); +} + +/* + Remove a new Mmc Host controller to the pool +*/ +VOID +RemoveMmcHost ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + RemoveEntryList (&(MmcHostInstance->Link)); +} + +MMC_HOST_INSTANCE* CreateMmcHostInstance ( + IN EFI_MMC_HOST_PROTOCOL* MmcHost + ) +{ + EFI_STATUS Status; + MMC_HOST_INSTANCE* MmcHostInstance; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + MmcHostInstance = AllocateZeroPool (sizeof (MMC_HOST_INSTANCE)); + if (MmcHostInstance == NULL) { + return NULL; + } + + MmcHostInstance->Signature = MMC_HOST_INSTANCE_SIGNATURE; + + MmcHostInstance->State = MmcHwInitializationState; + + MmcHostInstance->BlockIo.Media = AllocateCopyPool (sizeof(EFI_BLOCK_IO_MEDIA), &mMmcMediaTemplate); + if (MmcHostInstance->BlockIo.Media == NULL) { + goto FREE_INSTANCE; + } + + MmcHostInstance->BlockIo.Revision = EFI_BLOCK_IO_INTERFACE_REVISION; + MmcHostInstance->BlockIo.Reset = MmcReset; + MmcHostInstance->BlockIo.ReadBlocks = MmcReadBlocks; + MmcHostInstance->BlockIo.WriteBlocks = MmcWriteBlocks; + MmcHostInstance->BlockIo.FlushBlocks = MmcFlushBlocks; + + MmcHostInstance->MmcHost = MmcHost; + + // Create DevicePath for the new MMC Host + Status = MmcHost->BuildDevicePath (MmcHost, &NewDevicePathNode); + if (EFI_ERROR (Status)) { + goto FREE_MEDIA; + } + + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH); + if (DevicePath == NULL) { + goto FREE_MEDIA; + } + + SetDevicePathEndNode (DevicePath); + MmcHostInstance->DevicePath = AppendDevicePathNode (DevicePath, NewDevicePathNode); + + // Publish BlockIO protocol interface + Status = gBS->InstallMultipleProtocolInterfaces ( + &MmcHostInstance->MmcHandle, + &gEfiBlockIoProtocolGuid,&MmcHostInstance->BlockIo, + &gEfiDevicePathProtocolGuid,MmcHostInstance->DevicePath, + NULL + ); + if (EFI_ERROR(Status)) { + goto FREE_DEVICE_PATH; + } + + return MmcHostInstance; + +FREE_DEVICE_PATH: + FreePool(DevicePath); + +FREE_MEDIA: + FreePool(MmcHostInstance->BlockIo.Media); + +FREE_INSTANCE: + FreePool(MmcHostInstance); + + return NULL; +} + +EFI_STATUS DestroyMmcHostInstance ( + IN MMC_HOST_INSTANCE* MmcHostInstance + ) +{ + EFI_STATUS Status; + + // Uninstall Protocol Interfaces + Status = gBS->UninstallMultipleProtocolInterfaces ( + MmcHostInstance->MmcHandle, + &gEfiBlockIoProtocolGuid,&(MmcHostInstance->BlockIo), + &gEfiDevicePathProtocolGuid,MmcHostInstance->DevicePath, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // Free Memory allocated for the instance + if (MmcHostInstance->BlockIo.Media) { + FreePool(MmcHostInstance->BlockIo.Media); + } + if (MmcHostInstance->CardInfo.ECSDData) { + FreePages (MmcHostInstance->CardInfo.ECSDData, EFI_SIZE_TO_PAGES (sizeof (ECSD))); + } + FreePool (MmcHostInstance); + + return Status; +} + +/** + This function checks if the controller implement the Mmc Host and the Device Path Protocols +**/ +EFI_STATUS +EFIAPI +MmcDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + //EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_MMC_HOST_PROTOCOL *MmcHost; + EFI_DEV_PATH_PTR Node; + + // + // Check RemainingDevicePath validation + // + if (RemainingDevicePath != NULL) { + // + // Check if RemainingDevicePath is the End of Device Path Node, + // if yes, go on checking other conditions + // + if (!IsDevicePathEnd (RemainingDevicePath)) { + // + // If RemainingDevicePath isn't the End of Device Path Node, + // check its validation + // + Node.DevPath = RemainingDevicePath; + if (Node.DevPath->Type != HARDWARE_DEVICE_PATH || + Node.DevPath->SubType != HW_VENDOR_DP || + DevicePathNodeLength(Node.DevPath) != sizeof(VENDOR_DEVICE_PATH)) { + return EFI_UNSUPPORTED; + } + } + } + + // + // Check if Mmc Host protocol is installed by platform + // + Status = gBS->OpenProtocol ( + Controller, + &gEmbeddedMmcHostProtocolGuid, + (VOID **) &MmcHost, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Close the Mmc Host used to perform the supported test + // + gBS->CloseProtocol ( + Controller, + &gEmbeddedMmcHostProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; +} + +/** + +**/ +EFI_STATUS +EFIAPI +MmcDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + MMC_HOST_INSTANCE *MmcHostInstance; + EFI_MMC_HOST_PROTOCOL *MmcHost; + + // + // Check RemainingDevicePath validation + // + if (RemainingDevicePath != NULL) { + // + // Check if RemainingDevicePath is the End of Device Path Node, + // if yes, return EFI_SUCCESS + // + if (IsDevicePathEnd (RemainingDevicePath)) { + return EFI_SUCCESS; + } + } + + // + // Get the Mmc Host protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEmbeddedMmcHostProtocolGuid, + (VOID **) &MmcHost, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + return Status; + } + + MmcHostInstance = CreateMmcHostInstance(MmcHost); + if (MmcHostInstance != NULL) { + // Add the handle to the pool + InsertMmcHost (MmcHostInstance); + + MmcHostInstance->Initialized = FALSE; + + // Detect card presence now + CheckCardsCallback (NULL, NULL); + } + + return EFI_SUCCESS; +} + +/** + +**/ +EFI_STATUS +EFIAPI +MmcDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + LIST_ENTRY *CurrentLink; + MMC_HOST_INSTANCE *MmcHostInstance; + + MMC_TRACE("MmcDriverBindingStop()"); + + // For each MMC instance + CurrentLink = mMmcHostPool.ForwardLink; + while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) { + MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink); + ASSERT(MmcHostInstance != NULL); + + // Close gEmbeddedMmcHostProtocolGuid + Status = gBS->CloseProtocol ( + Controller, + &gEmbeddedMmcHostProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // Remove MMC Host Instance from the pool + RemoveMmcHost (MmcHostInstance); + + // Destroy MmcHostInstance + DestroyMmcHostInstance (MmcHostInstance); + } + + return Status; +} + +VOID +EFIAPI +CheckCardsCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + LIST_ENTRY *CurrentLink; + MMC_HOST_INSTANCE *MmcHostInstance; + EFI_STATUS Status; + + CurrentLink = mMmcHostPool.ForwardLink; + while (CurrentLink != NULL && CurrentLink != &mMmcHostPool) { + MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink); + ASSERT(MmcHostInstance != NULL); + + if (MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost) == !MmcHostInstance->Initialized) { + MmcHostInstance->State = MmcHwInitializationState; + MmcHostInstance->BlockIo.Media->MediaPresent = !MmcHostInstance->Initialized; + MmcHostInstance->Initialized = !MmcHostInstance->Initialized; + + if (MmcHostInstance->BlockIo.Media->MediaPresent) { + InitializeMmcDevice (MmcHostInstance); + } + + Status = gBS->ReinstallProtocolInterface ( + (MmcHostInstance->MmcHandle), + &gEfiBlockIoProtocolGuid, + &(MmcHostInstance->BlockIo), + &(MmcHostInstance->BlockIo) + ); + + if (EFI_ERROR(Status)) { + Print(L"MMC Card: Error reinstalling BlockIo interface\n"); + } + } + + CurrentLink = CurrentLink->ForwardLink; + } +} + + +EFI_DRIVER_BINDING_PROTOCOL gMmcDriverBinding = { + MmcDriverBindingSupported, + MmcDriverBindingStart, + MmcDriverBindingStop, + 0xa, + NULL, + NULL +}; + +/** + +**/ +EFI_STATUS +EFIAPI +MmcDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Initializes MMC Host pool + // + InitializeMmcHostPool (); + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gMmcDriverBinding, + ImageHandle, + &gMmcComponentName, + &gMmcComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + // Install driver diagnostics + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiDriverDiagnostics2ProtocolGuid,&gMmcDriverDiagnostics2, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // Use a timer to detect if a card has been plugged in or removed + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL | EVT_TIMER, + TPL_CALLBACK, + CheckCardsCallback, + NULL, + &gCheckCardsEvent); + ASSERT_EFI_ERROR (Status); + + Status = gBS->SetTimer( + gCheckCardsEvent, + TimerPeriodic, + (UINT64)(10*1000*200)); // 200 ms + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/Mmc.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/Mmc.h new file mode 100644 index 00000000..a0830d0b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/Mmc.h @@ -0,0 +1,523 @@ +/** @file + Main Header file for the MMC DXE driver + + Copyright (c) 2011-2015, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __MMC_H +#define __MMC_H + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define MMC_TRACE(txt) DEBUG((EFI_D_BLKIO, "MMC: " txt "\n")) + +#define MMC_IOBLOCKS_READ 0 +#define MMC_IOBLOCKS_WRITE 1 + +#define MMC_OCR_POWERUP 0x80000000 + +#define MMC_OCR_ACCESS_MASK 0x3 /* bit[30-29] */ +#define MMC_OCR_ACCESS_BYTE 0x1 /* bit[29] */ +#define MMC_OCR_ACCESS_SECTOR 0x2 /* bit[30] */ + +#define MMC_CSD_GET_CCC(Response) (Response[2] >> 20) +#define MMC_CSD_GET_TRANSPEED(Response) (Response[3] & 0xFF) +#define MMC_CSD_GET_READBLLEN(Response) ((Response[2] >> 16) & 0xF) +#define MMC_CSD_GET_WRITEBLLEN(Response) ((Response[0] >> 22) & 0xF) +#define MMC_CSD_GET_FILEFORMAT(Response) ((Response[0] >> 10) & 0x3) +#define MMC_CSD_GET_FILEFORMATGRP(Response) ((Response[0] >> 15) & 0x1) +#define MMC_CSD_GET_DEVICESIZE(csd) (((Response[1] >> 30) & 0x3) | ((Response[2] & 0x3FF) << 2)) +#define HC_MMC_CSD_GET_DEVICESIZE(Response) ((Response[1] >> 16) | ((Response[2] & 0x40) << 16)); +#define MMC_CSD_GET_DEVICESIZEMULT(csd) ((Response[1] >> 15) & 0x7) + +#define MMC_R0_READY_FOR_DATA (1 << 8) + +#define MMC_R0_CURRENTSTATE(Response) ((Response[0] >> 9) & 0xF) + +#define MMC_R0_STATE_IDLE 0 +#define MMC_R0_STATE_READY 1 +#define MMC_R0_STATE_IDENT 2 +#define MMC_R0_STATE_STDBY 3 +#define MMC_R0_STATE_TRAN 4 +#define MMC_R0_STATE_DATA 5 + +#define EMMC_CMD6_ARG_ACCESS(x) (((x) & 0x3) << 24) +#define EMMC_CMD6_ARG_INDEX(x) (((x) & 0xFF) << 16) +#define EMMC_CMD6_ARG_VALUE(x) (((x) & 0xFF) << 8) +#define EMMC_CMD6_ARG_CMD_SET(x) (((x) & 0x7) << 0) + +#define SWITCH_CMD_DATA_LENGTH 64 +#define SD_HIGH_SPEED_SUPPORTED 0x20000 +#define SD_DEFAULT_SPEED 25000000 +#define SD_HIGH_SPEED 50000000 +#define SWITCH_CMD_SUCCESS_MASK 0x0f000000 + +#define SD_CARD_CAPACITY 0x00000002 + +#define BUSWIDTH_4 4 + +typedef enum { + UNKNOWN_CARD, + MMC_CARD, //MMC card + MMC_CARD_HIGH, //MMC Card with High capacity + EMMC_CARD, //eMMC 4.41 card + SD_CARD, //SD 1.1 card + SD_CARD_2, //SD 2.0 or above standard card + SD_CARD_2_HIGH //SD 2.0 or above high capacity card +} CARD_TYPE; + +typedef struct { + UINT32 Reserved0: 7; // 0 + UINT32 V170_V195: 1; // 1.70V - 1.95V + UINT32 V200_V260: 7; // 2.00V - 2.60V + UINT32 V270_V360: 9; // 2.70V - 3.60V + UINT32 RESERVED_1: 5; // Reserved + UINT32 AccessMode: 2; // 00b (byte mode), 10b (sector mode) + UINT32 PowerUp: 1; // This bit is set to LOW if the card has not finished the power up routine +} OCR; + +typedef struct { + UINT8 SD_SPEC: 4; // SD Memory Card - Spec. Version [59:56] + UINT8 SCR_STRUCTURE: 4; // SCR Structure [63:60] + UINT8 SD_BUS_WIDTHS: 4; // DAT Bus widths supported [51:48] + UINT8 DATA_STAT_AFTER_ERASE: 1; // Data Status after erases [55] + UINT8 SD_SECURITY: 3; // CPRM Security Support [54:52] + UINT8 EX_SECURITY_1: 1; // Extended Security Support [43] + UINT8 SD_SPEC4: 1; // Spec. Version 4.00 or higher [42] + UINT8 RESERVED_1: 2; // Reserved [41:40] + UINT8 SD_SPEC3: 1; // Spec. Version 3.00 or higher [47] + UINT8 EX_SECURITY_2: 3; // Extended Security Support [46:44] + UINT8 CMD_SUPPORT: 4; // Command Support bits [35:32] + UINT8 RESERVED_2: 4; // Reserved [39:36] + UINT32 RESERVED_3; // Manufacturer Usage [31:0] +} SCR; + +typedef struct { + UINT32 NOT_USED; // 1 [0:0] + UINT32 CRC; // CRC7 checksum [7:1] + UINT32 MDT; // Manufacturing date [19:8] + UINT32 RESERVED_1; // Reserved [23:20] + UINT32 PSN; // Product serial number [55:24] + UINT8 PRV; // Product revision [63:56] + UINT8 PNM[5]; // Product name [64:103] + UINT16 OID; // OEM/Application ID [119:104] + UINT8 MID; // Manufacturer ID [127:120] +} CID; + +typedef struct { + UINT8 NOT_USED: 1; // Not used, always 1 [0:0] + UINT8 CRC: 7; // CRC [7:1] + + UINT8 RESERVED_1: 2; // Reserved [9:8] + UINT8 FILE_FORMAT: 2; // File format [11:10] + UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12] + UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13] + UINT8 COPY: 1; // Copy flag (OTP) [14:14] + UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15] + + UINT16 RESERVED_2: 5; // Reserved [20:16] + UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21] + UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22] + UINT16 R2W_FACTOR: 3; // Write speed factor [28:26] + UINT16 RESERVED_3: 2; // Reserved [30:29] + UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31] + + UINT32 WP_GRP_SIZE: 7; // Write protect group size [38:32] + UINT32 SECTOR_SIZE: 7; // Erase sector size [45:39] + UINT32 ERASE_BLK_EN: 1; // Erase single block enable [46:46] + UINT32 C_SIZE_MULT: 3; // Device size multiplier [49:47] + UINT32 VDD_W_CURR_MAX: 3; // Max. write current @ VDD max [52:50] + UINT32 VDD_W_CURR_MIN: 3; // Max. write current @ VDD min [55:53] + UINT32 VDD_R_CURR_MAX: 3; // Max. read current @ VDD max [58:56] + UINT32 VDD_R_CURR_MIN: 3; // Max. read current @ VDD min [61:59] + UINT32 C_SIZELow2: 2; // Device size [63:62] + + UINT32 C_SIZEHigh10: 10;// Device size [73:64] + UINT32 RESERVED_4: 2; // Reserved [75:74] + UINT32 DSR_IMP: 1; // DSR implemented [76:76] + UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77] + UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78] + UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79] + UINT32 READ_BL_LEN: 4; // Max. read data block length [83:80] + UINT32 CCC: 12;// Card command classes [95:84] + + UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96] + UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104] + UINT8 TAAC ; // Data read access-time 1 [119:112] + + UINT8 RESERVED_5: 2; // Reserved [121:120] + UINT8 SPEC_VERS: 4; // System specification version [125:122] + UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126] +} CSD; + +typedef struct { + UINT8 RESERVED_1[16]; // Reserved [15:0] + UINT8 SECURE_REMOVAL_TYPE; // Secure Removal Type [16:16] + UINT8 PRODUCT_STATE_AWARENESS_ENABLEMENT; // Product state awareness enablement [17:17] + UINT8 MAX_PRE_LOADING_DATA_SIZE[4]; // MAX pre loading data size [21:18] + UINT8 PRE_LOADING_DATA_SIZE[4]; // Pre loading data size [25:22] + UINT8 FFU_STATUS; // FFU Status [26:26] + UINT8 RESERVED_2[2]; // Reserved [28:27] + UINT8 MODE_OPERATION_CODES; // Mode operation codes [29:29] + UINT8 MODE_CONFIG; // Mode config [30:30] + UINT8 RESERVED_3; // Reserved [31:31] + UINT8 FLUSH_CACHE; // Flushing of the cache [32:32] + UINT8 CACHE_CTRL; // Control to turn the cache ON/OFF [33:33] + UINT8 POWER_OFF_NOTIFICATION; // Power Off Notification [34:34] + UINT8 PACKED_FAILURE_INDEX; // Packed command failure index [35:35] + UINT8 PACKED_COMMAND_STATUS; // Packed command status [36:36] + UINT8 CONTEXT_CONF[15]; // Context configuration [51:37] + UINT8 EXT_PARTITIONS_ATTRIBUTE[2]; // Extended partitions attribute [53:52] + UINT8 EXCEPTION_EVENTS_STATUS[2]; // Exception events status [55:54] + UINT8 EXCEPTION_EVENTS_CTRL[2]; // Exception events control [57:56] + UINT8 DYNCAP_NEEDED; // Number of addressed group to be released [58:58] + UINT8 CLASS_6_CTRL; // Class 6 commands control [59:59] + UINT8 INI_TIMEOUT_EMU; // 1st initialization after disabling sector size emulation [60:60] + UINT8 DATA_SECTOR_SIZE; // Sector size [61:61] + UINT8 USE_NATIVE_SECTOR; // Sector size emulation [62:62] + UINT8 NATIVE_SECTOR_SIZE; // Native sector size [63:63] + UINT8 VENDOR_SPECIFIC_FIELD[64]; // Vendor specific fields [127:64] + UINT8 RESERVED_4[2]; // Reserved [129:128] + UINT8 PROGRAM_CID_CSD_DDR_SUPPORT; // Program CID/CSD in DDR mode support [130:130] + UINT8 PERIODIC_WAKEUP; // Periodic wake-up [131:131] + UINT8 TCASE_SUPPORT; // Package case temperature is controlled [132:132] + UINT8 PRODUCTION_STATE_AWARENESS; // Production state awareness [133:133] + UINT8 SECTOR_BAD_BLK_MGMNT; // Bad block management mode [134:134] + UINT8 RESERVED_5; // Reserved [135:135] + UINT8 ENH_START_ADDR[4]; // Enhanced user data start address [139:136] + UINT8 ENH_SIZE_MULT[3]; // Enhanced user data area size [142:140] + UINT8 GP_SIZE_MULT[12]; // General purpose partition size [154:143] + UINT8 PARTITION_SETTING_COMPLETED; // Partitioning setting [155:155] + UINT8 PARTITIONS_ATTRIBUTE; // Partitions attribute [156:156] + UINT8 MAX_ENH_SIZE_MULT[3]; // Max enhanced area size [159:157] + UINT8 PARTITIONING_SUPPORT; // Partitioning [160:160] + UINT8 HPI_MGMT; // HPI management [161:161] + UINT8 RST_N_FUNCTION; // H/W reset function [162:162] + UINT8 BKOPS_EN; // Enable background operations handshake [163:163] + UINT8 BKOPS_START; // Manually start background operations [164:164] + UINT8 SANITIZE_START; // Start sanitize operation [165:165] + UINT8 WR_REL_PARAM; // Write reliability parameter register [166:166] + UINT8 WR_REL_SET; // Write reliability setting register [167:167] + UINT8 RPMB_SIZE_MULT; // RPMB size [168:168] + UINT8 FW_CONFIG; // FW configuration [169:169] + UINT8 RESERVED_6; // Reserved [170:170] + UINT8 USER_WP; // User area write protection register [171:171] + UINT8 RESERVED_7; // Reserved [172:172] + UINT8 BOOT_WP; // Boot area write protection register [173:173] + UINT8 BOOT_WP_STATUS; // Boot write protection register [174:174] + UINT8 ERASE_GROUP_DEF; // High-density erase group definition [175:175] + UINT8 RESERVED_8; // Reserved [176:176] + UINT8 BOOT_BUS_CONDITIONS; // Boot bus conditions [177:177] + UINT8 BOOT_CONFIG_PROT; // Boot config protection [178:178] + UINT8 PARTITION_CONFIG; // Partition config [179:179] + UINT8 RESERVED_9; // Reserved [180:180] + UINT8 ERASED_MEM_CONT; // Erased memory content [181:181] + UINT8 RESERVED_10; // Reserved [182:182] + UINT8 BUS_WIDTH; // Bus width mode [183:183] + UINT8 RESERVED_11; // Reserved [184:184] + UINT8 HS_TIMING; // High-speed interface timing [185:185] + UINT8 RESERVED_12; // Reserved [186:186] + UINT8 POWER_CLASS; // Power class [187:187] + UINT8 RESERVED_13; // Reserved [188:188] + UINT8 CMD_SET_REV; // Command set revision [189:189] + UINT8 RESERVED_14; // Reserved [190:190] + UINT8 CMD_SET; // Command set [191:191] + UINT8 EXT_CSD_REV; // Extended CSD revision [192:192] + UINT8 RESERVED_15; // Reserved [193:193] + UINT8 CSD_STRUCTURE; // CSD Structure [194:194] + UINT8 RESERVED_16; // Reserved [195:195] + UINT8 DEVICE_TYPE; // Device type [196:196] + UINT8 DRIVER_STRENGTH; // I/O Driver strength [197:197] + UINT8 OUT_OF_INTERRUPT_TIME; // Out-of-interrupt busy timing [198:198] + UINT8 PARTITION_SWITCH_TIME; // Partition switching timing [199:199] + UINT8 PWR_CL_52_195; // Power class for 52MHz at 1.95V 1 R [200:200] + UINT8 PWR_CL_26_195; // Power class for 26MHz at 1.95V 1 R [201:201] + UINT8 PWR_CL_52_360; // Power class for 52MHz at 3.6V 1 R [202:202] + UINT8 PWR_CL_26_360; // Power class for 26MHz at 3.6V 1 R [203:203] + UINT8 RESERVED_17; // Reserved [204:204] + UINT8 MIN_PERF_R_4_26; // Minimum read performance for 4bit at 26MHz [205:205] + UINT8 MIN_PERF_W_4_26; // Minimum write performance for 4bit at 26MHz [206:206] + UINT8 MIN_PERF_R_8_26_4_52; // Minimum read performance for 8bit at 26MHz, for 4bit at 52MHz [207:207] + UINT8 MIN_PERF_W_8_26_4_52; // Minimum write performance for 8bit at 26MHz, for 4bit at 52MHz [208:208] + UINT8 MIN_PERF_R_8_52; // Minimum read performance for 8bit at 52MHz [209:209] + UINT8 MIN_PERF_W_8_52; // Minimum write performance for 8bit at 52MHz [210:210] + UINT8 RESERVED_18; // Reserved [211:211] + UINT32 SECTOR_COUNT; // Sector count [215:212] + UINT8 SLEEP_NOTIFICATION_TIME; // Sleep notification timeout [216:216] + UINT8 S_A_TIMEOUT; // Sleep/awake timeout [217:217] + UINT8 PRODUCTION_STATE_AWARENESS_TIMEOUT; // Production state awareness timeout [218:218] + UINT8 S_C_VCCQ; // Sleep current (VCCQ) [219:219] + UINT8 S_C_VCC; // Sleep current (VCC) [220:220] + UINT8 HC_WP_GRP_SIZE; // High-capacity write protect group size [221:221] + UINT8 REL_WR_SECTOR_C; // Reliable write sector count [222:222] + UINT8 ERASE_TIMEOUT_MULT; // High-capacity erase timeout [223:223] + UINT8 HC_ERASE_GRP_SIZE; // High-capacity erase unit size [224:224] + UINT8 ACC_SIZE; // Access size [225:225] + UINT8 BOOT_SIZE_MULTI; // Boot partition size [226:226] + UINT8 RESERVED_19; // Reserved [227:227] + UINT8 BOOT_INFO; // Boot information [228:228] + UINT8 SECURE_TRIM_MULT; // Secure TRIM Multiplier [229:229] + UINT8 SECURE_ERASE_MULT; // Secure Erase Multiplier [230:230] + UINT8 SECURE_FEATURE_SUPPORT; // Secure Feature Support [231:231] + UINT8 TRIM_MULT; // TRIM Multiplier [232:232] + UINT8 RESERVED_20; // Reserved [233:233] + UINT8 MIN_PREF_DDR_R_8_52; // Minimum read performance for 8bit at 52MHz in DDR mode [234:234] + UINT8 MIN_PREF_DDR_W_8_52; // Minimum write performance for 8bit at 52MHz in DDR mode [235:235] + UINT8 PWR_CL_200_130; // Power class for 200MHz at VCCQ=1.3V, VCC=3.6V [236:236] + UINT8 PWR_CL_200_195; // Power class for 200MHz at VCCQ=1.95V, VCC=3.6V [237:237] + UINT8 PWR_CL_DDR_52_195; // Power class for 52MHz, DDR at 1.95V [238:238] + UINT8 PWR_CL_DDR_52_360; // Power class for 52Mhz, DDR at 3.6V [239:239] + UINT8 RESERVED_21; // Reserved [240:240] + UINT8 INI_TIMEOUT_AP; // 1st initialization time after partitioning [241:241] + UINT8 CORRECTLY_PRG_SECTORS_NUM[4]; // Number of correctly programmed sectors [245:242] + UINT8 BKOPS_STATUS; // Background operations status [246:246] + UINT8 POWER_OFF_LONG_TIME; // Power off notification (long) timeout [247:247] + UINT8 GENERIC_CMD6_TIME; // Generic CMD6 timeout [248:248] + UINT8 CACHE_SIZE[4]; // Cache size [252:249] + UINT8 PWR_CL_DDR_200_360; // Power class for 200MHz, DDR at VCC=3.6V [253:253] + UINT8 FIRMWARE_VERSION[8]; // Firmware version [261:254] + UINT8 DEVICE_VERSION[2]; // Device version [263:262] + UINT8 OPTIMAL_TRIM_UNIT_SIZE; // Optimal trim unit size [264:264] + UINT8 OPTIMAL_WRITE_SIZE; // Optimal write size [265:265] + UINT8 OPTIMAL_READ_SIZE; // Optimal read size [266:266] + UINT8 PRE_EOL_INFO; // Pre EOL information [267:267] + UINT8 DEVICE_LIFE_TIME_EST_TYP_A; // Device life time estimation type A [268:268] + UINT8 DEVICE_LIFE_TIME_EST_TYP_B; // Device life time estimation type B [269:269] + UINT8 VENDOR_PROPRIETARY_HEALTH_REPORT[32]; // Vendor proprietary health report [301:270] + UINT8 NUMBER_OF_FW_SECTORS_CORRECTLY_PROGRAMMED[4]; // Number of FW sectors correctly programmed [305:302] + UINT8 RESERVED_22[181]; // Reserved [486:306] + UINT8 FFU_ARG[4]; // FFU argument [490:487] + UINT8 OPERATION_CODE_TIMEOUT; // Operation codes timeout [491:491] + UINT8 FFU_FEATURES; // FFU features [492:492] + UINT8 SUPPORTED_MODES; // Supported modes [493:493] + UINT8 EXT_SUPPORT; // Extended partitions attribute support [494:494] + UINT8 LARGE_UNIT_SIZE_M1; // Large unit size [495:495] + UINT8 CONTEXT_CAPABILITIES; // Context management capabilities [496:496] + UINT8 TAG_RES_SIZE; // Tag resource size [497:497] + UINT8 TAG_UNIT_SIZE; // Tag unit size [498:498] + UINT8 DATA_TAG_SUPPORT; // Data tag support [499:499] + UINT8 MAX_PACKED_WRITES; // Max packed write commands [500:500] + UINT8 MAX_PACKED_READS; // Max packed read commands [501:501] + UINT8 BKOPS_SUPPORT; // Background operations support [502:502] + UINT8 HPI_FEATURES; // HPI features [503:503] + UINT8 S_CMD_SET; // Supported command sets [504:504] + UINT8 EXT_SECURITY_ERR; // Extended security commands error [505:505] + UINT8 RESERVED_23[6]; // Reserved [511:506] +} ECSD; + +typedef struct { + UINT16 RCA; + CARD_TYPE CardType; + OCR OCRData; + CID CIDData; + CSD CSDData; + ECSD *ECSDData; // MMC V4 extended card specific +} CARD_INFO; + +typedef struct _MMC_HOST_INSTANCE { + UINTN Signature; + LIST_ENTRY Link; + EFI_HANDLE MmcHandle; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + MMC_STATE State; + EFI_BLOCK_IO_PROTOCOL BlockIo; + CARD_INFO CardInfo; + EFI_MMC_HOST_PROTOCOL *MmcHost; + + BOOLEAN Initialized; +} MMC_HOST_INSTANCE; + +#define MMC_HOST_INSTANCE_SIGNATURE SIGNATURE_32('m', 'm', 'c', 'h') +#define MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS(a) CR (a, MMC_HOST_INSTANCE, BlockIo, MMC_HOST_INSTANCE_SIGNATURE) +#define MMC_HOST_INSTANCE_FROM_LINK(a) CR (a, MMC_HOST_INSTANCE, Link, MMC_HOST_INSTANCE_SIGNATURE) + + +EFI_STATUS +EFIAPI +MmcGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +MmcGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +extern EFI_COMPONENT_NAME_PROTOCOL gMmcComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gMmcComponentName2; + +extern EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gMmcDriverDiagnostics2; + +extern LIST_ENTRY mMmcHostPool; + +/** + Reset the block device. + + This function implements EFI_BLOCK_IO_PROTOCOL.Reset(). + It resets the block device hardware. + ExtendedVerification is ignored in this implementation. + + @param This Indicates a pointer to the calling context. + @param ExtendedVerification Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + + @retval EFI_SUCCESS The block device was reset. + @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset. + +**/ +EFI_STATUS +EFIAPI +MmcReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Reads the requested number of blocks from the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks(). + It reads the requested number of blocks from the device. + All the blocks are read, or an error is returned. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the read request is for. + @param Lba The starting logical block address to read from on the device. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic block size of the device. + @param Buffer A pointer to the destination buffer for the data. The caller is + responsible for either having implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +MmcReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + Writes a specified number of blocks to the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks(). + It writes a specified number of blocks to the device. + All blocks are written, or an error is returned. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the write request is for. + @param Lba The starting logical block address to be written. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic block size of the device. + @param Buffer Pointer to the source buffer for the data. + + @retval EFI_SUCCESS The data were written correctly to the device. + @retval EFI_WRITE_PROTECTED The device cannot be written to. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic + block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +MmcWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +/** + Flushes all modified data to a physical block device. + + @param This Indicates a pointer to the calling context. + + @retval EFI_SUCCESS All outstanding data were written correctly to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data. + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +EFI_STATUS +EFIAPI +MmcFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ); + +EFI_STATUS +MmcNotifyState ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN MMC_STATE State + ); + +EFI_STATUS +InitializeMmcDevice ( + IN MMC_HOST_INSTANCE *MmcHost + ); + +VOID +EFIAPI +CheckCardsCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +VOID +PrintCSD ( + IN UINT32* Csd + ); + +VOID +PrintRCA ( + IN UINT32 Rca + ); + +VOID +PrintOCR ( + IN UINT32 Ocr + ); + +VOID +PrintResponseR1 ( + IN UINT32 Response + ); + +VOID +PrintCID ( + IN UINT32* Cid + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c new file mode 100644 index 00000000..d9f97acb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c @@ -0,0 +1,396 @@ +/** @file +* +* Copyright (c) 2011-2020, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include + +#include "Mmc.h" + +EFI_STATUS +MmcNotifyState ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN MMC_STATE State + ) +{ + MmcHostInstance->State = State; + return MmcHostInstance->MmcHost->NotifyState (MmcHostInstance->MmcHost, State); +} + +EFI_STATUS +EFIAPI +MmcGetCardStatus ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_STATUS Status; + UINT32 Response[4]; + UINTN CmdArg; + EFI_MMC_HOST_PROTOCOL *MmcHost; + + Status = EFI_SUCCESS; + MmcHost = MmcHostInstance->MmcHost; + CmdArg = 0; + + if (MmcHost == NULL) { + return EFI_INVALID_PARAMETER; + } + if (MmcHostInstance->State != MmcHwInitializationState) { + //Get the Status of the card. + CmdArg = MmcHostInstance->CardInfo.RCA << 16; + Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcGetCardStatus(MMC_CMD13): Error and Status = %r\n", Status)); + return Status; + } + + //Read Response + MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response); + PrintResponseR1 (Response[0]); + } + + return Status; +} + +EFI_STATUS +EFIAPI +MmcReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + MMC_HOST_INSTANCE *MmcHostInstance; + + MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); + + if (MmcHostInstance->MmcHost == NULL) { + // Nothing to do + return EFI_SUCCESS; + } + + // If a card is not present then clear all media settings + if (!MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost)) { + MmcHostInstance->BlockIo.Media->MediaPresent = FALSE; + MmcHostInstance->BlockIo.Media->LastBlock = 0; + MmcHostInstance->BlockIo.Media->BlockSize = 512; // Should be zero but there is a bug in DiskIo + MmcHostInstance->BlockIo.Media->ReadOnly = FALSE; + + // Indicate that the driver requires initialization + MmcHostInstance->State = MmcHwInitializationState; + + return EFI_SUCCESS; + } + + // Implement me. Either send a CMD0 (could not work for some MMC host) or just turn off/turn + // on power and restart Identification mode + return EFI_SUCCESS; +} + +EFI_STATUS +MmcDetectCard ( + EFI_MMC_HOST_PROTOCOL *MmcHost + ) +{ + if (!MmcHost->IsCardPresent (MmcHost)) { + return EFI_NO_MEDIA; + } else { + return EFI_SUCCESS; + } +} + +EFI_STATUS +MmcStopTransmission ( + EFI_MMC_HOST_PROTOCOL *MmcHost + ) +{ + EFI_STATUS Status; + UINT32 Response[4]; + // Command 12 - Stop transmission (ends read or write) + // Normally only needed for streaming transfers or after error. + Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0); + if (!EFI_ERROR (Status)) { + MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response); + } + return Status; +} + +#define MMCI0_BLOCKLEN 512 +#define MMCI0_TIMEOUT 10000 + +STATIC +EFI_STATUS +MmcTransferBlock ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINTN Cmd, + IN UINTN Transfer, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN CmdArg; + INTN Timeout; + UINT32 Response[4]; + MMC_HOST_INSTANCE *MmcHostInstance; + EFI_MMC_HOST_PROTOCOL *MmcHost; + + MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); + MmcHost = MmcHostInstance->MmcHost; + + if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) { + //Set command argument based on the card capacity + //if 0 : SDSC card + //if 1 : SDXC/SDHC + if (MmcHostInstance->CardInfo.OCRData.AccessMode & SD_CARD_CAPACITY) { + CmdArg = Lba; + } else { + CmdArg = MultU64x32 (Lba, This->Media->BlockSize); + } + } else { + //Set command argument based on the card access mode (Byte mode or Block mode) + if ((MmcHostInstance->CardInfo.OCRData.AccessMode & MMC_OCR_ACCESS_MASK) == + MMC_OCR_ACCESS_SECTOR) { + CmdArg = Lba; + } else { + CmdArg = MultU64x32 (Lba, This->Media->BlockSize); + } + } + + Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a(MMC_CMD%d): Error %r\n", __func__, Cmd, Status)); + return Status; + } + + if (Transfer == MMC_IOBLOCKS_READ) { + // Read Data + Status = MmcHost->ReadBlockData (MmcHost, Lba, BufferSize, Buffer); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_BLKIO, "%a(): Error Read Block Data and Status = %r\n", __func__, Status)); + MmcStopTransmission (MmcHost); + return Status; + } + Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a() : Error MmcProgrammingState\n", __func__)); + return Status; + } + } else { + // Write Data + Status = MmcHost->WriteBlockData (MmcHost, Lba, BufferSize, Buffer); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_BLKIO, "%a(): Error Write Block Data and Status = %r\n", __func__, Status)); + MmcStopTransmission (MmcHost); + return Status; + } + } + + // Command 13 - Read status and wait for programming to complete (return to tran) + Timeout = MMCI0_TIMEOUT; + CmdArg = MmcHostInstance->CardInfo.RCA << 16; + Response[0] = 0; + while(!(Response[0] & MMC_R0_READY_FOR_DATA) + && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN) + && Timeout--) { + Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg); + if (!EFI_ERROR (Status)) { + MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response); + if (Response[0] & MMC_R0_READY_FOR_DATA) { + break; // Prevents delay once finished + } + } + } + + if (BufferSize > This->Media->BlockSize) { + Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_BLKIO, "%a(): Error and Status:%r\n", __func__, Status)); + } + MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response); + } + + Status = MmcNotifyState (MmcHostInstance, MmcTransferState); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcTransferState\n")); + return Status; + } + return Status; +} + +EFI_STATUS +MmcIoBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINTN Transfer, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + UINT32 Response[4]; + EFI_STATUS Status; + UINTN CmdArg; + INTN Timeout; + UINTN Cmd; + MMC_HOST_INSTANCE *MmcHostInstance; + EFI_MMC_HOST_PROTOCOL *MmcHost; + UINTN BytesRemainingToBeTransfered; + UINTN BlockCount; + UINTN ConsumeSize; + UINT32 MaxBlock; + UINTN RemainingBlock; + + BlockCount = 1; + MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); + ASSERT (MmcHostInstance != NULL); + MmcHost = MmcHostInstance->MmcHost; + ASSERT (MmcHost); + + if (This->Media->MediaId != MediaId) { + return EFI_MEDIA_CHANGED; + } + + if ((MmcHost == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Check if a Card is Present + if (!MmcHostInstance->BlockIo.Media->MediaPresent) { + return EFI_NO_MEDIA; + } + + // Reading 0 Byte is valid + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + // The buffer size must be an exact multiple of the block size + if ((BufferSize % This->Media->BlockSize) != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + if (MMC_HOST_HAS_ISMULTIBLOCK(MmcHost) && MmcHost->IsMultiBlock(MmcHost)) { + BlockCount = BufferSize / This->Media->BlockSize; + } + + // All blocks must be within the device + if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)) { + return EFI_INVALID_PARAMETER; + } + + if ((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) { + return EFI_WRITE_PROTECTED; + } + + // Check the alignment + if ((This->Media->IoAlign > 2) && (((UINTN)Buffer & (This->Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + // Max block number in single cmd is 65535 blocks. + MaxBlock = 0xFFFF; + RemainingBlock = BlockCount; + BytesRemainingToBeTransfered = BufferSize; + while (BytesRemainingToBeTransfered > 0) { + + if (RemainingBlock <= MaxBlock) { + BlockCount = RemainingBlock; + } else { + BlockCount = MaxBlock; + } + + // Check if the Card is in Ready status + CmdArg = MmcHostInstance->CardInfo.RCA << 16; + Response[0] = 0; + Timeout = 20; + while( (!(Response[0] & MMC_R0_READY_FOR_DATA)) + && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN) + && Timeout--) { + Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg); + if (!EFI_ERROR (Status)) { + MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response); + } + } + + if (0 == Timeout) { + DEBUG ((EFI_D_ERROR, "The Card is busy\n")); + return EFI_NOT_READY; + } + + if (Transfer == MMC_IOBLOCKS_READ) { + if (BlockCount == 1) { + // Read a single block + Cmd = MMC_CMD17; + } else { + // Read multiple blocks + Cmd = MMC_CMD18; + } + } else { + if (BlockCount == 1) { + // Write a single block + Cmd = MMC_CMD24; + } else { + // Write multiple blocks + Cmd = MMC_CMD25; + } + } + + ConsumeSize = BlockCount * This->Media->BlockSize; + if (BytesRemainingToBeTransfered < ConsumeSize) { + ConsumeSize = BytesRemainingToBeTransfered; + } + Status = MmcTransferBlock (This, Cmd, Transfer, MediaId, Lba, ConsumeSize, Buffer); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a(): Failed to transfer block and Status:%r\n", __func__, Status)); + } + + RemainingBlock -= BlockCount; + BytesRemainingToBeTransfered -= ConsumeSize; + if (BytesRemainingToBeTransfered > 0) { + Lba += BlockCount; + Buffer = (UINT8 *)Buffer + ConsumeSize; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +MmcReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer); +} + +EFI_STATUS +EFIAPI +MmcWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer); +} + +EFI_STATUS +EFIAPI +MmcFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcDebug.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcDebug.c new file mode 100644 index 00000000..6c53b955 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcDebug.c @@ -0,0 +1,162 @@ +/** @file +* +* Copyright (c) 2011-2013, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include "Mmc.h" + +#if !defined(MDEPKG_NDEBUG) +CONST CHAR8* mStrUnit[] = { "100kbit/s", "1Mbit/s", "10Mbit/s", "100MBit/s", + "Unknown", "Unknown", "Unknown", "Unknown" }; +CONST CHAR8* mStrValue[] = { "1.0", "1.2", "1.3", "1.5", "2.0", "2.5", "3.0", "3.5", "4.0", "4.5", "5.0", + "Unknown", "Unknown", "Unknown", "Unknown" }; +#endif + +VOID +PrintCID ( + IN UINT32* Cid + ) +{ + DEBUG ((EFI_D_ERROR, "- PrintCID\n")); + DEBUG ((EFI_D_ERROR, "\t- Manufacturing date: %d/%d\n", (Cid[0] >> 8) & 0xF, (Cid[0] >> 12) & 0xFF)); + DEBUG ((EFI_D_ERROR, "\t- Product serial number: 0x%X%X\n", Cid[1] & 0xFFFFFF, (Cid[0] >> 24) & 0xFF)); + DEBUG ((EFI_D_ERROR, "\t- Product revision: %d\n", Cid[1] >> 24)); + //DEBUG ((EFI_D_ERROR, "\t- Product name: %s\n", (char*)(Cid + 2))); + DEBUG ((EFI_D_ERROR, "\t- OEM ID: %c%c\n", (Cid[3] >> 8) & 0xFF, (Cid[3] >> 16) & 0xFF)); +} + + +VOID +PrintCSD ( + IN UINT32* Csd + ) +{ + UINTN Value; + + if (((Csd[2] >> 30) & 0x3) == 0) { + DEBUG ((EFI_D_ERROR, "- PrintCSD Version 1.01-1.10/Version 2.00/Standard Capacity\n")); + } else if (((Csd[2] >> 30) & 0x3) == 1) { + DEBUG ((EFI_D_ERROR, "- PrintCSD Version 2.00/High Capacity\n")); + } else { + DEBUG ((EFI_D_ERROR, "- PrintCSD Version Higher than v3.3\n")); + } + + DEBUG ((EFI_D_ERROR, "\t- Supported card command class: 0x%X\n", MMC_CSD_GET_CCC (Csd))); + DEBUG ((EFI_D_ERROR, "\t- Speed: %a %a\n",mStrValue[(MMC_CSD_GET_TRANSPEED (Csd) >> 3) & 0xF],mStrUnit[MMC_CSD_GET_TRANSPEED (Csd) & 7])); + DEBUG ((EFI_D_ERROR, "\t- Maximum Read Data Block: %d\n",2 << (MMC_CSD_GET_READBLLEN (Csd)-1))); + DEBUG ((EFI_D_ERROR, "\t- Maximum Write Data Block: %d\n",2 << (MMC_CSD_GET_WRITEBLLEN (Csd)-1))); + + if (!MMC_CSD_GET_FILEFORMATGRP (Csd)) { + Value = MMC_CSD_GET_FILEFORMAT (Csd); + if (Value == 0) { + DEBUG ((EFI_D_ERROR, "\t- Format (0): Hard disk-like file system with partition table\n")); + } else if (Value == 1) { + DEBUG ((EFI_D_ERROR, "\t- Format (1): DOS FAT (floppy-like) with boot sector only (no partition table)\n")); + } else if (Value == 2) { + DEBUG ((EFI_D_ERROR, "\t- Format (2): Universal File Format\n")); + } else { + DEBUG ((EFI_D_ERROR, "\t- Format (3): Others/Unknown\n")); + } + } else { + DEBUG ((EFI_D_ERROR, "\t- Format: Reserved\n")); + } +} + +VOID +PrintRCA ( + IN UINT32 Rca + ) +{ + DEBUG ((EFI_D_ERROR, "- PrintRCA: 0x%X\n", Rca)); + DEBUG ((EFI_D_ERROR, "\t- Status: 0x%X\n", Rca & 0xFFFF)); + DEBUG ((EFI_D_ERROR, "\t- RCA: 0x%X\n", (Rca >> 16) & 0xFFFF)); +} + +VOID +PrintOCR ( + IN UINT32 Ocr + ) +{ + UINTN MinV; + UINTN MaxV; + UINTN Volts; + UINTN Loop; + + MinV = 36; // 3.6 + MaxV = 20; // 2.0 + Volts = 20; // 2.0 + + // The MMC register bits [23:8] indicate the working range of the card + for (Loop = 8; Loop < 24; Loop++) { + if (Ocr & (1 << Loop)) { + if (MinV > Volts) { + MinV = Volts; + } + if (MaxV < Volts) { + MaxV = Volts + 1; + } + } + Volts++; + } + + DEBUG ((EFI_D_ERROR, "- PrintOCR Ocr (0x%X)\n",Ocr)); + DEBUG ((EFI_D_ERROR, "\t- Card operating voltage: %d.%d to %d.%d\n", MinV/10, MinV % 10, MaxV/10, MaxV % 10)); + if (((Ocr >> 29) & 3) == 0) { + DEBUG ((EFI_D_ERROR, "\t- AccessMode: Byte Mode\n")); + } else { + DEBUG ((EFI_D_ERROR, "\t- AccessMode: Block Mode (0x%X)\n", ((Ocr >> 29) & 3))); + } + + if (Ocr & MMC_OCR_POWERUP) { + DEBUG ((EFI_D_ERROR, "\t- PowerUp\n")); + } else { + DEBUG ((EFI_D_ERROR, "\t- Voltage Not Supported\n")); + } +} + +VOID +PrintResponseR1 ( + IN UINT32 Response + ) +{ + DEBUG ((EFI_D_INFO, "Response: 0x%X\n", Response)); + if (Response & MMC_R0_READY_FOR_DATA) { + DEBUG ((EFI_D_INFO, "\t- READY_FOR_DATA\n")); + } + + switch ((Response >> 9) & 0xF) { + case 0: + DEBUG ((EFI_D_INFO, "\t- State: Idle\n")); + break; + case 1: + DEBUG ((EFI_D_INFO, "\t- State: Ready\n")); + break; + case 2: + DEBUG ((EFI_D_INFO, "\t- State: Ident\n")); + break; + case 3: + DEBUG ((EFI_D_INFO, "\t- State: StandBy\n")); + break; + case 4: + DEBUG ((EFI_D_INFO, "\t- State: Tran\n")); + break; + case 5: + DEBUG ((EFI_D_INFO, "\t- State: Data\n")); + break; + case 6: + DEBUG ((EFI_D_INFO, "\t- State: Rcv\n")); + break; + case 7: + DEBUG ((EFI_D_INFO, "\t- State: Prg\n")); + break; + case 8: + DEBUG ((EFI_D_INFO, "\t- State: Dis\n")); + break; + default: + DEBUG ((EFI_D_INFO, "\t- State: Reserved\n")); + break; + } +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf new file mode 100644 index 00000000..17130b11 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf @@ -0,0 +1,45 @@ +#/** @file +# Build file for the MMC DXE driver +# +# Copyright (c) 2011-2015, ARM Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = MmcDxe + FILE_GUID = b6f44cc0-9e45-11df-be21-0002a5d5c51b + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = MmcDxeInitialize + +[Sources.common] + ComponentName.c + Mmc.c + MmcBlockIo.c + MmcIdentification.c + MmcDebug.c + Diagnostics.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + UefiLib + UefiDriverEntryPoint + BaseMemoryLib + +[Protocols] + gEfiDiskIoProtocolGuid + gEfiBlockIoProtocolGuid + gEfiDevicePathProtocolGuid + gEmbeddedMmcHostProtocolGuid + gEfiDriverDiagnostics2ProtocolGuid + +[Depex] + TRUE diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c new file mode 100644 index 00000000..ecf3eb36 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c @@ -0,0 +1,799 @@ +/** @file +* +* Copyright (c) 2011-2015, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include + +#include "Mmc.h" + +typedef union { + UINT32 Raw; + OCR Ocr; +} OCR_RESPONSE; + +#define MAX_RETRY_COUNT 1000 +#define CMD_RETRY_COUNT 20 +#define RCA_SHIFT_OFFSET 16 +#define EMMC_CARD_SIZE 512 +#define EMMC_ECSD_SIZE_OFFSET 53 + +#define EXTCSD_BUS_WIDTH 183 +#define EXTCSD_HS_TIMING 185 + +#define EMMC_TIMING_BACKWARD 0 +#define EMMC_TIMING_HS 1 +#define EMMC_TIMING_HS200 2 +#define EMMC_TIMING_HS400 3 + +#define EMMC_BUS_WIDTH_1BIT 0 +#define EMMC_BUS_WIDTH_4BIT 1 +#define EMMC_BUS_WIDTH_8BIT 2 +#define EMMC_BUS_WIDTH_DDR_4BIT 5 +#define EMMC_BUS_WIDTH_DDR_8BIT 6 + +#define EMMC_SWITCH_ERROR (1 << 7) + +#define SD_BUS_WIDTH_1BIT (1 << 0) +#define SD_BUS_WIDTH_4BIT (1 << 2) + +#define SD_CCC_SWITCH (1 << 10) + +#define DEVICE_STATE(x) (((x) >> 9) & 0xf) +typedef enum _EMMC_DEVICE_STATE { + EMMC_IDLE_STATE = 0, + EMMC_READY_STATE, + EMMC_IDENT_STATE, + EMMC_STBY_STATE, + EMMC_TRAN_STATE, + EMMC_DATA_STATE, + EMMC_RCV_STATE, + EMMC_PRG_STATE, + EMMC_DIS_STATE, + EMMC_BTST_STATE, + EMMC_SLP_STATE +} EMMC_DEVICE_STATE; + +UINT32 mEmmcRcaCount = 0; + +STATIC +EFI_STATUS +EFIAPI +EmmcGetDeviceState ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + OUT EMMC_DEVICE_STATE *State + ) +{ + EFI_MMC_HOST_PROTOCOL *Host; + EFI_STATUS Status; + UINT32 Data, RCA; + + if (State == NULL) { + return EFI_INVALID_PARAMETER; + } + + Host = MmcHostInstance->MmcHost; + RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET; + Status = Host->SendCommand (Host, MMC_CMD13, RCA); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get card status, Status=%r.\n", Status)); + return Status; + } + Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R1, &Data); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get response of CMD13, Status=%r.\n", Status)); + return Status; + } + if (Data & EMMC_SWITCH_ERROR) { + DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to switch expected mode, Status=%r.\n", Status)); + return EFI_DEVICE_ERROR; + } + *State = DEVICE_STATE(Data); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +EmmcSetEXTCSD ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + UINT32 ExtCmdIndex, + UINT32 Value + ) +{ + EFI_MMC_HOST_PROTOCOL *Host; + EMMC_DEVICE_STATE State; + EFI_STATUS Status; + UINT32 Argument; + + Host = MmcHostInstance->MmcHost; + Argument = EMMC_CMD6_ARG_ACCESS(3) | EMMC_CMD6_ARG_INDEX(ExtCmdIndex) | + EMMC_CMD6_ARG_VALUE(Value) | EMMC_CMD6_ARG_CMD_SET(1); + Status = Host->SendCommand (Host, MMC_CMD6, Argument); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to send CMD6, Status=%r.\n", Status)); + return Status; + } + // Make sure device exiting prog mode + do { + Status = EmmcGetDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to get device state, Status=%r.\n", Status)); + return Status; + } + } while (State == EMMC_PRG_STATE); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +EmmcIdentificationMode ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN OCR_RESPONSE Response + ) +{ + EFI_MMC_HOST_PROTOCOL *Host; + EFI_BLOCK_IO_MEDIA *Media; + EFI_STATUS Status; + EMMC_DEVICE_STATE State; + UINT32 RCA; + + Host = MmcHostInstance->MmcHost; + Media = MmcHostInstance->BlockIo.Media; + + // Fetch card identity register + Status = Host->SendCommand (Host, MMC_CMD2, 0); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD2, Status=%r.\n", Status)); + return Status; + } + + Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CIDData)); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CID retrieval error, Status=%r.\n", Status)); + return Status; + } + + // Assign a relative address value to the card + MmcHostInstance->CardInfo.RCA = ++mEmmcRcaCount; // TODO: might need a more sophisticated way of doing this + RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET; + Status = Host->SendCommand (Host, MMC_CMD3, RCA); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): RCA set error, Status=%r.\n", Status)); + return Status; + } + + // Fetch card specific data + Status = Host->SendCommand (Host, MMC_CMD9, RCA); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD9, Status=%r.\n", Status)); + return Status; + } + + Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CSDData)); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CSD retrieval error, Status=%r.\n", Status)); + return Status; + } + + // Select the card + Status = Host->SendCommand (Host, MMC_CMD7, RCA); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status)); + } + + if (MMC_HOST_HAS_SETIOS(Host)) { + // Set 1-bit bus width + Status = Host->SetIos (Host, 0, 1, EMMCBACKWARD); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set 1-bit bus width error, Status=%r.\n", Status)); + return Status; + } + + // Set 1-bit bus width for EXTCSD + Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_1BIT); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set extcsd bus width error, Status=%r.\n", Status)); + return Status; + } + } + + // Fetch ECSD + MmcHostInstance->CardInfo.ECSDData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (ECSD))); + if (MmcHostInstance->CardInfo.ECSDData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = Host->SendCommand (Host, MMC_CMD8, 0); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD fetch error, Status=%r.\n", Status)); + } + + Status = Host->ReadBlockData (Host, 0, 512, (UINT32 *)MmcHostInstance->CardInfo.ECSDData); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD read error, Status=%r.\n", Status)); + goto FreePageExit; + } + + // Make sure device exiting data mode + do { + Status = EmmcGetDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to get device state, Status=%r.\n", Status)); + goto FreePageExit; + } + } while (State == EMMC_DATA_STATE); + + // Set up media + Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards + Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN; + Media->ReadOnly = MmcHostInstance->CardInfo.CSDData.PERM_WRITE_PROTECT; + Media->LogicalBlocksPerPhysicalBlock = 1; + Media->IoAlign = 4; + // Compute last block using bits [215:212] of the ECSD + Media->LastBlock = MmcHostInstance->CardInfo.ECSDData->SECTOR_COUNT - 1; // eMMC isn't supposed to report this for + // Cards <2GB in size, but the model does. + + // Setup card type + MmcHostInstance->CardInfo.CardType = EMMC_CARD; + return EFI_SUCCESS; + +FreePageExit: + FreePages (MmcHostInstance->CardInfo.ECSDData, EFI_SIZE_TO_PAGES (sizeof (ECSD))); + return Status; +} + +STATIC +EFI_STATUS +InitializeEmmcDevice ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_MMC_HOST_PROTOCOL *Host; + EFI_STATUS Status = EFI_SUCCESS; + ECSD *ECSDData; + UINT32 BusClockFreq, Idx, BusMode; + UINT32 TimingMode[4] = {EMMCHS52DDR1V2, EMMCHS52DDR1V8, EMMCHS52, EMMCHS26}; + + Host = MmcHostInstance->MmcHost; + ECSDData = MmcHostInstance->CardInfo.ECSDData; + if (ECSDData->DEVICE_TYPE == EMMCBACKWARD) + return EFI_SUCCESS; + + if (!MMC_HOST_HAS_SETIOS(Host)) { + return EFI_SUCCESS; + } + Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_HS_TIMING, EMMC_TIMING_HS); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to switch high speed mode, Status:%r.\n", Status)); + return Status; + } + + for (Idx = 0; Idx < 4; Idx++) { + switch (TimingMode[Idx]) { + case EMMCHS52DDR1V2: + case EMMCHS52DDR1V8: + case EMMCHS52: + BusClockFreq = 52000000; + break; + case EMMCHS26: + BusClockFreq = 26000000; + break; + default: + return EFI_UNSUPPORTED; + } + Status = Host->SetIos (Host, BusClockFreq, 8, TimingMode[Idx]); + if (!EFI_ERROR (Status)) { + switch (TimingMode[Idx]) { + case EMMCHS52DDR1V2: + case EMMCHS52DDR1V8: + BusMode = EMMC_BUS_WIDTH_DDR_8BIT; + break; + case EMMCHS52: + case EMMCHS26: + BusMode = EMMC_BUS_WIDTH_8BIT; + break; + default: + return EFI_UNSUPPORTED; + } + Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, BusMode); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to set EXTCSD bus width, Status:%r\n", Status)); + } + return Status; + } + } + return Status; +} + +STATIC +UINT32 +CreateSwitchCmdArgument ( + IN UINT32 Mode, + IN UINT8 Group, + IN UINT8 Value + ) +{ + UINT32 Argument; + + Argument = Mode << 31 | 0x00FFFFFF; + Argument &= ~(0xF << (Group * 4)); + Argument |= Value << (Group * 4); + + return Argument; +} + +STATIC +EFI_STATUS +InitializeSdMmcDevice ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + UINT32 CmdArg; + UINT32 Response[4]; + UINT32 Buffer[128]; + UINT32 Speed; + UINTN BlockSize; + UINTN CardSize; + UINTN NumBlocks; + BOOLEAN CccSwitch; + SCR Scr; + EFI_STATUS Status; + EFI_MMC_HOST_PROTOCOL *MmcHost; + + Speed = SD_DEFAULT_SPEED; + MmcHost = MmcHostInstance->MmcHost; + + // Send a command to get Card specific data + CmdArg = MmcHostInstance->CardInfo.RCA << 16; + Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD9): Error, Status=%r\n", Status)); + return Status; + } + + // Read Response + Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(): Failed to receive CSD, Status=%r\n", Status)); + return Status; + } + PrintCSD (Response); + if (MMC_CSD_GET_CCC(Response) & SD_CCC_SWITCH) { + CccSwitch = TRUE; + } else { + CccSwitch = FALSE; + } + + if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) { + CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response); + NumBlocks = ((CardSize + 1) * 1024); + BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response); + } else { + CardSize = MMC_CSD_GET_DEVICESIZE (Response); + NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2)); + BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response); + } + + // For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes. + if (BlockSize > 512) { + NumBlocks = MultU64x32 (NumBlocks, BlockSize / 512); + BlockSize = 512; + } + + MmcHostInstance->BlockIo.Media->LastBlock = (NumBlocks - 1); + MmcHostInstance->BlockIo.Media->BlockSize = BlockSize; + MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly (MmcHost); + MmcHostInstance->BlockIo.Media->MediaPresent = TRUE; + MmcHostInstance->BlockIo.Media->MediaId++; + + CmdArg = MmcHostInstance->CardInfo.RCA << 16; + Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD7): Error and Status = %r\n", Status)); + return Status; + } + + Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a (MMC_CMD55): Error and Status = %r\n", __FUNCTION__, Status)); + return Status; + } + Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a (MMC_CMD55): Error and Status = %r\n", __FUNCTION__, Status)); + return Status; + } + if ((Response[0] & MMC_STATUS_APP_CMD) == 0) { + return EFI_SUCCESS; + } + + /* SCR */ + Status = MmcHost->SendCommand (MmcHost, MMC_ACMD51, 0); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a(MMC_ACMD51): Error and Status = %r\n", __func__, Status)); + return Status; + } else { + Status = MmcHost->ReadBlockData (MmcHost, 0, 8, Buffer); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a(MMC_ACMD51): ReadBlockData Error and Status = %r\n", __func__, Status)); + return Status; + } + CopyMem (&Scr, Buffer, 8); + if (Scr.SD_SPEC == 2) { + if (Scr.SD_SPEC3 == 1) { + if (Scr.SD_SPEC4 == 1) { + DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 4.xx\n")); + } else { + DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 3.0x\n")); + } + } else { + if (Scr.SD_SPEC4 == 0) { + DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 2.0\n")); + } else { + DEBUG ((EFI_D_ERROR, "Found invalid SD Card\n")); + } + } + } else { + if ((Scr.SD_SPEC3 == 0) && (Scr.SD_SPEC4 == 0)) { + if (Scr.SD_SPEC == 1) { + DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 1.10\n")); + } else { + DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 1.0\n")); + } + } else { + DEBUG ((EFI_D_ERROR, "Found invalid SD Card\n")); + } + } + } + if (CccSwitch) { + /* SD Switch, Mode:0, Group:0, Value:0 */ + CmdArg = CreateSwitchCmdArgument(0, 0, 0); + Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, CmdArg); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a (MMC_CMD6): Error and Status = %r\n", __FUNCTION__, Status)); + return Status; + } else { + Status = MmcHost->ReadBlockData (MmcHost, 0, SWITCH_CMD_DATA_LENGTH, Buffer); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a (MMC_CMD6): ReadBlockData Error and Status = %r\n", __FUNCTION__, Status)); + return Status; + } + } + + if (!(Buffer[3] & SD_HIGH_SPEED_SUPPORTED)) { + DEBUG ((DEBUG_INFO, "%a : High Speed not supported by Card\n", __FUNCTION__)); + } else { + Speed = SD_HIGH_SPEED; + + /* SD Switch, Mode:1, Group:0, Value:1 */ + CmdArg = CreateSwitchCmdArgument(1, 0, 1); + Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, CmdArg); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a (MMC_CMD6): Error and Status = %r\n", __FUNCTION__, Status)); + return Status; + } else { + Status = MmcHost->ReadBlockData (MmcHost, 0, SWITCH_CMD_DATA_LENGTH, Buffer); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a (MMC_CMD6): ReadBlockData Error and Status = %r\n", __FUNCTION__, Status)); + return Status; + } + + if ((Buffer[4] & SWITCH_CMD_SUCCESS_MASK) != 0x01000000) { + DEBUG((DEBUG_ERROR, "Problem switching SD card into high-speed mode\n")); + return Status; + } + } + } + } + if (Scr.SD_BUS_WIDTHS & SD_BUS_WIDTH_4BIT) { + CmdArg = MmcHostInstance->CardInfo.RCA << 16; + Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a (MMC_CMD55): Error and Status = %r\n", __FUNCTION__, Status)); + return Status; + } + /* Width: 4 */ + Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, 2); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a (MMC_CMD6): Error and Status = %r\n", __FUNCTION__, Status)); + return Status; + } + } + if (MMC_HOST_HAS_SETIOS(MmcHost)) { + Status = MmcHost->SetIos (MmcHost, Speed, BUSWIDTH_4, EMMCBACKWARD); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a (SetIos): Error and Status = %r\n", __FUNCTION__, Status)); + return Status; + } + } + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +MmcIdentificationMode ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_STATUS Status; + UINT32 Response[4]; + UINTN Timeout; + UINTN CmdArg; + BOOLEAN IsHCS; + EFI_MMC_HOST_PROTOCOL *MmcHost; + OCR_RESPONSE OcrResponse; + + MmcHost = MmcHostInstance->MmcHost; + CmdArg = 0; + IsHCS = FALSE; + + if (MmcHost == NULL) { + return EFI_INVALID_PARAMETER; + } + + // We can get into this function if we restart the identification mode + if (MmcHostInstance->State == MmcHwInitializationState) { + // Initialize the MMC Host HW + Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState, Status=%r.\n", Status)); + return Status; + } + } + + Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error, Status=%r.\n", Status)); + return Status; + } + Status = MmcNotifyState (MmcHostInstance, MmcIdleState); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState, Status=%r.\n", Status)); + return Status; + } + + // Send CMD1 to get OCR (MMC) + // This command only valid for MMC and eMMC + Timeout = MAX_RETRY_COUNT; + do { + Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, EMMC_CMD1_CAPACITY_GREATER_THAN_2GB); + if (EFI_ERROR (Status)) + break; + Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, (UINT32 *)&OcrResponse); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status)); + return Status; + } + Timeout--; + } while (!OcrResponse.Ocr.PowerUp && (Timeout > 0)); + if (Status == EFI_SUCCESS) { + if (!OcrResponse.Ocr.PowerUp) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD1): Card initialisation failure, Status=%r.\n", Status)); + return EFI_DEVICE_ERROR; + } + OcrResponse.Ocr.PowerUp = 0; + if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB) { + MmcHostInstance->CardInfo.OCRData.AccessMode = BIT1; + } + else { + MmcHostInstance->CardInfo.OCRData.AccessMode = 0x0; + } + // Check whether MMC or eMMC + if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB || + OcrResponse.Raw == EMMC_CMD1_CAPACITY_LESS_THAN_2GB) { + return EmmcIdentificationMode (MmcHostInstance, OcrResponse); + } + } + + // Are we using SDIO ? + Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0); + if (Status == EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported, Status=%r.\n", Status)); + return EFI_UNSUPPORTED; + } + + // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1) + CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0); + Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg); + if (Status == EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n")); + IsHCS = TRUE; + Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive response to CMD8, Status=%r.\n", Status)); + return Status; + } + PrintResponseR1 (Response[0]); + // Check if it is valid response + if (Response[0] != CmdArg) { + DEBUG ((EFI_D_ERROR, "The Card is not usable\n")); + return EFI_UNSUPPORTED; + } + } else { + DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n")); + } + + // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1) + Timeout = MAX_RETRY_COUNT; + while (Timeout > 0) { + // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command + Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0); + if (Status == EFI_SUCCESS) { + DEBUG ((EFI_D_INFO, "Card should be SD\n")); + if (IsHCS) { + MmcHostInstance->CardInfo.CardType = SD_CARD_2; + } else { + MmcHostInstance->CardInfo.CardType = SD_CARD; + } + + // Note: The first time CmdArg will be zero + CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0]; + if (IsHCS) { + CmdArg |= BIT30; + } + Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg); + if (!EFI_ERROR (Status)) { + Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status)); + return Status; + } + ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0]; + } + } else { + DEBUG ((EFI_D_INFO, "Card should be MMC\n")); + MmcHostInstance->CardInfo.CardType = MMC_CARD; + + Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000); + if (!EFI_ERROR (Status)) { + Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status)); + return Status; + } + ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0]; + } + } + + if (!EFI_ERROR (Status)) { + if (!MmcHostInstance->CardInfo.OCRData.PowerUp) { + gBS->Stall (1); + Timeout--; + } else { + if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) { + MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH; + DEBUG ((EFI_D_ERROR, "High capacity card.\n")); + } + break; // The MMC/SD card is ready. Continue the Identification Mode + } + } else { + gBS->Stall (1); + Timeout--; + } + } + + if (Timeout == 0) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n")); + return EFI_NO_MEDIA; + } else { + PrintOCR (Response[0]); + } + + Status = MmcNotifyState (MmcHostInstance, MmcReadyState); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n")); + return Status; + } + + Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n")); + return Status; + } + Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive CID, Status=%r.\n", Status)); + return Status; + } + + PrintCID (Response); + + Status = MmcHost->NotifyState (MmcHost, MmcIdentificationState); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n")); + return Status; + } + + // + // Note, SD specifications say that "if the command execution causes a state change, it + // will be visible to the host in the response to the next command" + // The status returned for this CMD3 will be 2 - identification + // + CmdArg = 1; + Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n")); + return Status; + } + + Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive RCA, Status=%r.\n", Status)); + return Status; + } + PrintRCA (Response[0]); + + // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card + if (MmcHostInstance->CardInfo.CardType != MMC_CARD) { + MmcHostInstance->CardInfo.RCA = Response[0] >> 16; + } else { + MmcHostInstance->CardInfo.RCA = CmdArg; + } + Status = MmcNotifyState (MmcHostInstance, MmcStandByState); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n")); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +InitializeMmcDevice ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_STATUS Status; + EFI_MMC_HOST_PROTOCOL *MmcHost; + UINTN BlockCount; + + BlockCount = 1; + MmcHost = MmcHostInstance->MmcHost; + + Status = MmcIdentificationMode (MmcHostInstance); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error in Identification Mode, Status=%r\n", Status)); + return Status; + } + + Status = MmcNotifyState (MmcHostInstance, MmcTransferState); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error MmcTransferState, Status=%r\n", Status)); + return Status; + } + + if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) { + Status = InitializeSdMmcDevice (MmcHostInstance); + } else { + Status = InitializeEmmcDevice (MmcHostInstance); + } + if (EFI_ERROR (Status)) { + return Status; + } + + // Set Block Length + Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n", + MmcHostInstance->BlockIo.Media->BlockSize, Status)); + return Status; + } + + // Block Count (not used). Could return an error for SD card + if (MmcHostInstance->CardInfo.CardType == MMC_CARD) { + Status = MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD23): Error, Status=%r\n", Status)); + return Status; + } + } + + return EFI_SUCCESS; +} -- cgit v1.2.3