From 2ef2b01e07c02db339f34004445734a2dbdd80e1 Mon Sep 17 00:00:00 2001 From: AJFISH Date: Sun, 6 Dec 2009 01:57:05 +0000 Subject: Adding support for BeagleBoard. ArmPkg - Supoprt for ARM specific things that can change as the architecture changes. Plus semihosting JTAG drivers. EmbeddedPkg - Generic support for an embeddded platform. Including a light weight command line shell. BeagleBoardPkg - Platform specifics for BeagleBoard. SD Card works, but USB has issues. Looks like a bug in the open source USB stack (Our internal stack works fine). git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9518 6f19259b-4bc3-4df7-8a09-765794883524 --- EmbeddedPkg/DebugSupportDxe/DebugSupport.c | 119 ++ EmbeddedPkg/DebugSupportDxe/DebugSupportDxe.inf | 28 + EmbeddedPkg/Ebl/CmdTemplate.c | 65 + EmbeddedPkg/Ebl/Command.c | 978 +++++++++++++ EmbeddedPkg/Ebl/Dir.c | 305 ++++ EmbeddedPkg/Ebl/Ebl.h | 194 +++ EmbeddedPkg/Ebl/Ebl.inf | 110 ++ EmbeddedPkg/Ebl/EfiDevice.c | 969 +++++++++++++ EmbeddedPkg/Ebl/Hob.c | 232 +++ EmbeddedPkg/Ebl/HwDebug.c | 342 +++++ EmbeddedPkg/Ebl/HwIoDebug.c | 153 ++ EmbeddedPkg/Ebl/Main.c | 616 ++++++++ EmbeddedPkg/Ebl/Network.c | 104 ++ EmbeddedPkg/Ebl/Script.c | 126 ++ EmbeddedPkg/EblExternCmd/EntryPointGlue.c | 152 ++ EmbeddedPkg/EblExternCmd/Main.c | 52 + .../EmbeddedMonotonicCounter.c | 82 ++ .../EmbeddedMonotonicCounter.inf | 29 + EmbeddedPkg/EmbeddedPkg.dec | 126 ++ EmbeddedPkg/EmbeddedPkg.dsc | 266 ++++ EmbeddedPkg/EmbeddedPkg.fdf | 141 ++ EmbeddedPkg/GdbStub/Arm/Processor.c | 717 ++++++++++ EmbeddedPkg/GdbStub/GdbStub.c | 1264 +++++++++++++++++ EmbeddedPkg/GdbStub/GdbStub.inf | 78 + EmbeddedPkg/GdbStub/GdbStubInternal.h | 746 ++++++++++ EmbeddedPkg/GdbStub/Ia32/Processor.c | 993 +++++++++++++ EmbeddedPkg/GdbStub/SerialIo.c | 551 ++++++++ EmbeddedPkg/GdbStub/X64/Processor.c | 963 +++++++++++++ .../Include/Library/EblAddExternalCommandLib.h | 122 ++ EmbeddedPkg/Include/Library/EblCmdLib.h | 48 + EmbeddedPkg/Include/Library/EblNetworkLib.h | 68 + EmbeddedPkg/Include/Library/EfiFileLib.h | 315 +++++ EmbeddedPkg/Include/Library/EfiResetSystemLib.h | 58 + EmbeddedPkg/Include/Library/GdbSerialLib.h | 107 ++ .../Include/Library/HalRuntimeServicesLib.h | 165 +++ EmbeddedPkg/Include/Library/PrePiLib.h | 766 ++++++++++ EmbeddedPkg/Include/Library/RealTimeClockLib.h | 138 ++ .../Protocol/DebugSupportPeriodicCallback.h | 42 + EmbeddedPkg/Include/Protocol/EblAddCommand.h | 156 ++ EmbeddedPkg/Include/Protocol/EmbeddedDevice.h | 58 + .../Include/Protocol/EmbeddedExternalDevice.h | 94 ++ EmbeddedPkg/Include/Protocol/EmbeddedGpio.h | 167 +++ EmbeddedPkg/Include/Protocol/HardwareInterrupt.h | 151 ++ .../EblAddExternalCommandLib.c | 156 ++ .../EblAddExternalCommandLib.inf | 47 + EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.c | 28 + .../Library/EblCmdLibNull/EblCmdLibNull.inf | 45 + EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.c | 173 +++ .../Library/EblNetworkLib/EblNetworkLib.inf | 28 + EmbeddedPkg/Library/EfiFileLib/EfiFileLib.c | 1483 ++++++++++++++++++++ EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf | 64 + .../GdbSerialDebugPortLib/GdbSerialDebugPortLib.c | 187 +++ .../GdbSerialDebugPortLib.inf | 50 + EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c | 262 ++++ EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf | 47 + .../Library/HalRuntimeServicesExampleLib/Capsule.c | 288 ++++ .../Library/HalRuntimeServicesExampleLib/Mtc.c | 226 +++ .../ReportStatusCode.c | 198 +++ .../Library/HalRuntimeServicesExampleLib/Reset.c | 63 + .../Library/HalRuntimeServicesExampleLib/Rtc.c | 861 ++++++++++++ .../HalRuntimeServicesExampleLib/Variable.c | 306 ++++ .../PrePiExtractGuidedSectionLib.c | 247 ++++ .../PrePiExtractGuidedSectionLib.inf | 24 + EmbeddedPkg/Library/PrePiLib/FwVol.c | 841 +++++++++++ EmbeddedPkg/Library/PrePiLib/Hob.c | 808 +++++++++++ EmbeddedPkg/Library/PrePiLib/Memory.c | 160 +++ EmbeddedPkg/Library/PrePiLib/PrePi.h | 44 + EmbeddedPkg/Library/PrePiLib/PrePiLib.c | 231 +++ EmbeddedPkg/Library/PrePiLib/PrePiLib.inf | 90 ++ EmbeddedPkg/Library/PrePiLib/ReportStatusCode.c | 327 +++++ EmbeddedPkg/Library/SemiHostingDebugLib/DebugLib.c | 258 ++++ .../SemiHostingDebugLib/SemiHostingDebugLib.inf | 46 + .../SemiHostingSerialPortLib.inf | 35 + .../SemiHostingSerialPortLib/SerialPortLib.c | 145 ++ .../TemplateRealTimeClockLib/RealTimeClockLib.c | 175 +++ .../TemplateRealTimeClockLib.inf | 38 + .../TemplateResetSystemLib/ResetSystemLib.c | 103 ++ .../TemplateResetSystemLib.inf | 36 + .../TemplateSerialPortLib/TemplateSerialPortLib.c | 99 ++ .../TemplateSerialPortLib.inf | 37 + .../RealTimeClockRuntimeDxe/RealTimeClock.c | 158 +++ .../RealTimeClockRuntimeDxe.inf | 45 + EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf | 51 + EmbeddedPkg/ResetRuntimeDxe/reset.c | 74 + EmbeddedPkg/SerialDxe/SerialDxe.inf | 54 + EmbeddedPkg/SerialDxe/SerialIo.c | 258 ++++ .../SimpleTextInOutSerial/SimpleTextInOut.c | 671 +++++++++ .../SimpleTextInOutSerial.inf | 56 + EmbeddedPkg/TemplateBds/BdsEntry.c | 183 +++ EmbeddedPkg/TemplateBds/BdsEntry.h | 62 + EmbeddedPkg/TemplateBds/FirmwareVolume.c | 160 +++ EmbeddedPkg/TemplateBds/TemplateBds.inf | 68 + EmbeddedPkg/TemplateCpuDxe/Arm/Exception.c | 250 ++++ EmbeddedPkg/TemplateCpuDxe/Arm/Exceptions.S | 158 +++ EmbeddedPkg/TemplateCpuDxe/Arm/Exceptions.asm | 152 ++ EmbeddedPkg/TemplateCpuDxe/CpuDxe.c | 323 +++++ EmbeddedPkg/TemplateCpuDxe/CpuDxe.h | 124 ++ EmbeddedPkg/TemplateCpuDxe/IA32/Exception.c | 183 +++ EmbeddedPkg/TemplateCpuDxe/TemplateCpuDxe.inf | 71 + EmbeddedPkg/TemplateCpuDxe/X64/Exception.c | 183 +++ EmbeddedPkg/TemplateMetronomeDxe/Metronome.c | 132 ++ .../TemplateMetronomeDxe/TemplateMetronomeDxe.inf | 50 + EmbeddedPkg/TemplateSec/TemplateSec.c | 76 + EmbeddedPkg/TemplateSec/TemplateSec.inf | 66 + EmbeddedPkg/TemplateTimerDxe/TemplateTimerDxe.inf | 56 + EmbeddedPkg/TemplateTimerDxe/Timer.c | 373 +++++ 106 files changed, 25249 insertions(+) create mode 100644 EmbeddedPkg/DebugSupportDxe/DebugSupport.c create mode 100644 EmbeddedPkg/DebugSupportDxe/DebugSupportDxe.inf create mode 100644 EmbeddedPkg/Ebl/CmdTemplate.c create mode 100644 EmbeddedPkg/Ebl/Command.c create mode 100644 EmbeddedPkg/Ebl/Dir.c create mode 100644 EmbeddedPkg/Ebl/Ebl.h create mode 100644 EmbeddedPkg/Ebl/Ebl.inf create mode 100644 EmbeddedPkg/Ebl/EfiDevice.c create mode 100644 EmbeddedPkg/Ebl/Hob.c create mode 100644 EmbeddedPkg/Ebl/HwDebug.c create mode 100644 EmbeddedPkg/Ebl/HwIoDebug.c create mode 100644 EmbeddedPkg/Ebl/Main.c create mode 100644 EmbeddedPkg/Ebl/Network.c create mode 100644 EmbeddedPkg/Ebl/Script.c create mode 100644 EmbeddedPkg/EblExternCmd/EntryPointGlue.c create mode 100644 EmbeddedPkg/EblExternCmd/Main.c create mode 100644 EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.c create mode 100644 EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf create mode 100644 EmbeddedPkg/EmbeddedPkg.dec create mode 100644 EmbeddedPkg/EmbeddedPkg.dsc create mode 100644 EmbeddedPkg/EmbeddedPkg.fdf create mode 100644 EmbeddedPkg/GdbStub/Arm/Processor.c create mode 100644 EmbeddedPkg/GdbStub/GdbStub.c create mode 100644 EmbeddedPkg/GdbStub/GdbStub.inf create mode 100644 EmbeddedPkg/GdbStub/GdbStubInternal.h create mode 100644 EmbeddedPkg/GdbStub/Ia32/Processor.c create mode 100644 EmbeddedPkg/GdbStub/SerialIo.c create mode 100644 EmbeddedPkg/GdbStub/X64/Processor.c create mode 100644 EmbeddedPkg/Include/Library/EblAddExternalCommandLib.h create mode 100644 EmbeddedPkg/Include/Library/EblCmdLib.h create mode 100644 EmbeddedPkg/Include/Library/EblNetworkLib.h create mode 100644 EmbeddedPkg/Include/Library/EfiFileLib.h create mode 100644 EmbeddedPkg/Include/Library/EfiResetSystemLib.h create mode 100644 EmbeddedPkg/Include/Library/GdbSerialLib.h create mode 100644 EmbeddedPkg/Include/Library/HalRuntimeServicesLib.h create mode 100644 EmbeddedPkg/Include/Library/PrePiLib.h create mode 100644 EmbeddedPkg/Include/Library/RealTimeClockLib.h create mode 100644 EmbeddedPkg/Include/Protocol/DebugSupportPeriodicCallback.h create mode 100644 EmbeddedPkg/Include/Protocol/EblAddCommand.h create mode 100644 EmbeddedPkg/Include/Protocol/EmbeddedDevice.h create mode 100644 EmbeddedPkg/Include/Protocol/EmbeddedExternalDevice.h create mode 100644 EmbeddedPkg/Include/Protocol/EmbeddedGpio.h create mode 100644 EmbeddedPkg/Include/Protocol/HardwareInterrupt.h create mode 100644 EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.c create mode 100644 EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.inf create mode 100644 EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.c create mode 100644 EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.inf create mode 100644 EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.c create mode 100644 EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.inf create mode 100644 EmbeddedPkg/Library/EfiFileLib/EfiFileLib.c create mode 100644 EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf create mode 100644 EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c create mode 100644 EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf create mode 100644 EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c create mode 100644 EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf create mode 100644 EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Capsule.c create mode 100644 EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Mtc.c create mode 100644 EmbeddedPkg/Library/HalRuntimeServicesExampleLib/ReportStatusCode.c create mode 100644 EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Reset.c create mode 100644 EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c create mode 100644 EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Variable.c create mode 100644 EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c create mode 100644 EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf create mode 100644 EmbeddedPkg/Library/PrePiLib/FwVol.c create mode 100644 EmbeddedPkg/Library/PrePiLib/Hob.c create mode 100644 EmbeddedPkg/Library/PrePiLib/Memory.c create mode 100644 EmbeddedPkg/Library/PrePiLib/PrePi.h create mode 100644 EmbeddedPkg/Library/PrePiLib/PrePiLib.c create mode 100644 EmbeddedPkg/Library/PrePiLib/PrePiLib.inf create mode 100644 EmbeddedPkg/Library/PrePiLib/ReportStatusCode.c create mode 100644 EmbeddedPkg/Library/SemiHostingDebugLib/DebugLib.c create mode 100644 EmbeddedPkg/Library/SemiHostingDebugLib/SemiHostingDebugLib.inf create mode 100644 EmbeddedPkg/Library/SemiHostingSerialPortLib/SemiHostingSerialPortLib.inf create mode 100644 EmbeddedPkg/Library/SemiHostingSerialPortLib/SerialPortLib.c create mode 100644 EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c create mode 100644 EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf create mode 100644 EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c create mode 100644 EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf create mode 100644 EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.c create mode 100644 EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.inf create mode 100644 EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClock.c create mode 100644 EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf create mode 100644 EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf create mode 100644 EmbeddedPkg/ResetRuntimeDxe/reset.c create mode 100644 EmbeddedPkg/SerialDxe/SerialDxe.inf create mode 100644 EmbeddedPkg/SerialDxe/SerialIo.c create mode 100644 EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOut.c create mode 100644 EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOutSerial.inf create mode 100644 EmbeddedPkg/TemplateBds/BdsEntry.c create mode 100644 EmbeddedPkg/TemplateBds/BdsEntry.h create mode 100644 EmbeddedPkg/TemplateBds/FirmwareVolume.c create mode 100644 EmbeddedPkg/TemplateBds/TemplateBds.inf create mode 100644 EmbeddedPkg/TemplateCpuDxe/Arm/Exception.c create mode 100755 EmbeddedPkg/TemplateCpuDxe/Arm/Exceptions.S create mode 100755 EmbeddedPkg/TemplateCpuDxe/Arm/Exceptions.asm create mode 100644 EmbeddedPkg/TemplateCpuDxe/CpuDxe.c create mode 100644 EmbeddedPkg/TemplateCpuDxe/CpuDxe.h create mode 100644 EmbeddedPkg/TemplateCpuDxe/IA32/Exception.c create mode 100644 EmbeddedPkg/TemplateCpuDxe/TemplateCpuDxe.inf create mode 100644 EmbeddedPkg/TemplateCpuDxe/X64/Exception.c create mode 100644 EmbeddedPkg/TemplateMetronomeDxe/Metronome.c create mode 100644 EmbeddedPkg/TemplateMetronomeDxe/TemplateMetronomeDxe.inf create mode 100644 EmbeddedPkg/TemplateSec/TemplateSec.c create mode 100644 EmbeddedPkg/TemplateSec/TemplateSec.inf create mode 100644 EmbeddedPkg/TemplateTimerDxe/TemplateTimerDxe.inf create mode 100644 EmbeddedPkg/TemplateTimerDxe/Timer.c (limited to 'EmbeddedPkg') diff --git a/EmbeddedPkg/DebugSupportDxe/DebugSupport.c b/EmbeddedPkg/DebugSupportDxe/DebugSupport.c new file mode 100644 index 0000000000..26f4c387dc --- /dev/null +++ b/EmbeddedPkg/DebugSupportDxe/DebugSupport.c @@ -0,0 +1,119 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include + +#include +#include +#include + +EFI_STATUS +EFIAPI +DebugSupportGetMaximumProcessorIndex ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + OUT UINTN *MaxProcessorIndex + ) +{ + if (MaxProcessorIndex == NULL) { + return EFI_INVALID_PARAMETER; + } + + *MaxProcessorIndex = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DebugSupportRegisterPeriodicCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_PERIODIC_CALLBACK PeriodicCallback + ) +{ + TIMER_DEBUG_SUPPORT_PROTOCOL *Timer; + EFI_STATUS Status; + + Status = gBS->LocateProtocol(&gTimerDebugSupportProtocolGuid, NULL, (VOID **)&Timer); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Timer->RegisterPeriodicCallback(Timer, PeriodicCallback); + + return Status; +} + +EFI_STATUS +EFIAPI +DebugSupportRegisterExceptionCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_EXCEPTION_CALLBACK ExceptionCallback, + IN EFI_EXCEPTION_TYPE ExceptionType + ) +{ + EFI_CPU_ARCH_PROTOCOL *Cpu; + EFI_STATUS Status; + + Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Cpu->RegisterInterruptHandler(Cpu, ExceptionType, (EFI_CPU_INTERRUPT_HANDLER)ExceptionCallback); + + return Status; +} + +EFI_STATUS +EFIAPI +DebugSupportInvalidateInstructionCache ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN VOID *Start, + IN UINT64 Length + ) +{ + InvalidateInstructionCacheRange(Start, Length); + return EFI_SUCCESS; +} + +EFI_DEBUG_SUPPORT_PROTOCOL mDebugSupport = { + IsaArm, + DebugSupportGetMaximumProcessorIndex, + DebugSupportRegisterPeriodicCallback, + DebugSupportRegisterExceptionCallback, + DebugSupportInvalidateInstructionCache +}; + +EFI_STATUS +DebugSupportDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle = NULL; + + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiDebugSupportProtocolGuid); + Status = gBS->InstallMultipleProtocolInterfaces(&Handle, &gEfiDebugSupportProtocolGuid, &mDebugSupport, NULL); + + return Status; +} + diff --git a/EmbeddedPkg/DebugSupportDxe/DebugSupportDxe.inf b/EmbeddedPkg/DebugSupportDxe/DebugSupportDxe.inf new file mode 100644 index 0000000000..d3dab66ab7 --- /dev/null +++ b/EmbeddedPkg/DebugSupportDxe/DebugSupportDxe.inf @@ -0,0 +1,28 @@ +#%HEADER% +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmDebugSupportDxe + FILE_GUID = 2e7c151b-cbd8-4df6-a0e3-cde660067c6a + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = DebugSupportDxeInitialize + +[Sources.common] + DebugSupport.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedePkg/EmbeddedePkg.dec + +[LibraryClasses] + BaseMemoryLib + CacheMaintenanceLib + UefiDriverEntryPoint + ArmLib + +[Protocols] + gEfiCpuArchProtocolGuid + gEfiDebugSupportProtocolGuid + gTimerDebugSupportProtocolGuid + diff --git a/EmbeddedPkg/Ebl/CmdTemplate.c b/EmbeddedPkg/Ebl/CmdTemplate.c new file mode 100644 index 0000000000..456c4afe72 --- /dev/null +++ b/EmbeddedPkg/Ebl/CmdTemplate.c @@ -0,0 +1,65 @@ +/** @file + %CommandName% for EBL (Embedded Boot Loader) + + Copyright (c) 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: CmdTemplate.c + + Search/Replace %CommandName% with the name of your new command + +**/ + +#include "Ebl.h" + + +/** + Fill Me In + + Argv[0] - "%CommandName%" + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +Ebl%CommandName%Cmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + return EFI_SUCCESS; +} + + +GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmd%CommandName%Template[] = +{ + { + "%CommandName%", + " [show args] ; explain args and command", + NULL, + Ebl%CommandName%Cmd + } +}; + + +/** + Initialize the commands in this in this file +**/ +VOID +EblInitialize%CommandName%Cmd ( + VOID + ) +{ + EblAddCommands (mCmd%CommandName%Template, sizeof (mCmd%CommandName%Template)/sizeof (EBL_COMMAND_TABLE)); +} + diff --git a/EmbeddedPkg/Ebl/Command.c b/EmbeddedPkg/Ebl/Command.c new file mode 100644 index 0000000000..7899a0f442 --- /dev/null +++ b/EmbeddedPkg/Ebl/Command.c @@ -0,0 +1,978 @@ +/** @file + Basic commands and command processing infrastructure for EBL + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ebl.h" +#include +#include + +UINTN mCmdTableMaxIndex = EBL_MAX_COMMAND_COUNT; +UINTN mCmdTableNextFreeIndex = 0; +EBL_COMMAND_TABLE *mCmdTable[EBL_MAX_COMMAND_COUNT]; + +/** + Converts a lowercase Ascii character to upper one + + If Chr is lowercase Ascii character, then converts it to upper one. + + If Value >= 0xA0, then ASSERT(). + If (Value & 0x0F) >= 0x0A, then ASSERT(). + + @param chr one Ascii character + + @return The uppercase value of Ascii character + +**/ +STATIC +CHAR8 +AsciiToUpper ( + IN CHAR8 Chr + ) +{ + return (UINT8) ((Chr >= 'a' && Chr <= 'z') ? Chr - ('a' - 'A') : Chr); +} + + +/** + Case insensitve comparison of two Null-terminated Unicode strings with maximum + lengths, and returns the difference between the first mismatched Unicode + characters. + This function compares the Null-terminated Unicode string FirstString to the + Null-terminated Unicode string SecondString. At most, Length Unicode + characters will be compared. If Length is 0, then 0 is returned. If + FirstString is identical to SecondString, then 0 is returned. Otherwise, the + value returned is the first mismatched Unicode character in SecondString + subtracted from the first mismatched Unicode character in FirstString. + + @param FirstString Pointer to a Null-terminated ASCII string. + @param SecondString Pointer to a Null-terminated ASCII string. + @param Length Max length to compare. + + @retval 0 FirstString is identical to SecondString using case insensitive + comparisons. + @retval !=0 FirstString is not identical to SecondString using case + insensitive comparisons. + +**/ +INTN +EFIAPI +AsciiStrniCmp ( + IN CONST CHAR8 *FirstString, + IN CONST CHAR8 *SecondString, + IN UINTN Length + ) +{ + if (Length == 0) { + return 0; + } + + while ((AsciiToUpper (*FirstString) != '\0') && + (AsciiToUpper (*FirstString) == AsciiToUpper (*SecondString)) && + (Length > 1)) { + FirstString++; + SecondString++; + Length--; + } + + return AsciiToUpper (*FirstString) - AsciiToUpper (*SecondString); +} + + + +/** + Add a command to the mCmdTable. If there is no free space in the command + table ASSERT. The mCmdTable is maintained in alphabetical order and the + new entry is inserted into its sorted possition. + + @param Entry Commnad Entry to add to the CmdTable + +**/ +VOID +EFIAPI +EblAddCommand ( + IN const EBL_COMMAND_TABLE *Entry + ) +{ + UINTN Count; + + if (mCmdTableNextFreeIndex == EBL_MAX_COMMAND_COUNT) { + // + // Ran out of space to store commands. Increase EBL_MAX_COMMAND_COUNT + // + ASSERT (FALSE); + return; + } + + // + // Add command and Insertion sort array in the process + // + mCmdTable[mCmdTableNextFreeIndex] = (EBL_COMMAND_TABLE *)Entry; + if (mCmdTableNextFreeIndex != 0) { + for (Count = mCmdTableNextFreeIndex; Count > 0; Count--) { + if (AsciiStriCmp (mCmdTable[Count - 1]->Name, Entry->Name) <= 0) { + break; + } + + mCmdTable[Count] = mCmdTable[Count - 1]; + } + mCmdTable[Count] = (EBL_COMMAND_TABLE *)Entry; + } + + mCmdTableNextFreeIndex++; +} + + +/** + Add an set of commands to the command table. Most commonly used on static + array of commands. + + @param EntryArray Pointer to array of command entries + @param ArrayCount Number of commnad entries to add + +**/ +VOID +EFIAPI +EblAddCommands ( + IN const EBL_COMMAND_TABLE *EntryArray, + IN UINTN ArrayCount + ) +{ + UINTN Index; + + for (Index = 0; Index < ArrayCount; Index++) { + EblAddCommand (&EntryArray[Index]); + } +} + + +EBL_ADD_COMMAND_PROTOCOL gEblAddCommand = { + EblAddCommand, + EblAddCommands, + EblGetCharKey, + EblAnyKeyToContinueQtoQuit +}; + + + +/** + Return the best matching command for the passed in command name. The match + does not have to be exact, it just needs to be unqiue. This enables commands + to be shortend to the smallest set of starting characters that is unique. + + @param CommandName Name of command to search for + + @return NULL CommandName did not match or was not unique + Other Pointer to EBL_COMMAND_TABLE entry for CommandName + +**/ +EBL_COMMAND_TABLE * +EblGetCommand ( + IN CHAR8 *CommandName + ) +{ + UINTN Index; + UINTN BestMatchCount; + UINTN Length; + EBL_COMMAND_TABLE *Match; + + Length = AsciiStrLen (CommandName); + for (Index = 0, BestMatchCount = 0, Match = NULL; Index < mCmdTableNextFreeIndex; Index++) { + if (AsciiStriCmp (mCmdTable[Index]->Name, CommandName) == 0) { + // match a command exactly + return mCmdTable[Index]; + } + + if (AsciiStrniCmp (CommandName, mCmdTable[Index]->Name, Length) == 0) { + // partial match, so keep looking to make sure there is only one partial match + BestMatchCount++; + Match = mCmdTable[Index]; + } + } + + if (BestMatchCount == 1) { + return Match; + } + + // + // We had no matches or too many matches + // + return NULL; +} + + + +/** + List out help information on all the commands or print extended information + about a specific passed in command. + + Argv[0] - "help" + Argv[1] - Command to display help about + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblHelpCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + UINTN Index; + CHAR8 *Ptr; + UINTN CurrentRow; + + if (Argc == 1) { + // Print all the commands + AsciiPrint ("Embedded Boot Loader (EBL) commands (help command for more info):\n"); + for (Index = 0; Index < mCmdTableNextFreeIndex; Index++) { + EblSetTextColor (EFI_YELLOW); + AsciiPrint (" %a", mCmdTable[Index]->Name); + EblSetTextColor (0); + AsciiPrint ("%a\n", mCmdTable[Index]->HelpSummary); + } + } else if (Argv[1] != NULL) { + // Print specific help + for (Index = 0, CurrentRow = 0; Index < mCmdTableNextFreeIndex; Index++) { + if (AsciiStriCmp (Argv[1], mCmdTable[Index]->Name) == 0) { + Ptr = (mCmdTable[Index]->Help == NULL) ? mCmdTable[Index]->HelpSummary : mCmdTable[Index]->Help; + AsciiPrint ("%a%a\n", Argv[1], Ptr); + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { + break; + } + } + } + } + + return EFI_SUCCESS; +} + + +/** + Exit the EBL. If the commnad processor sees EFI_ABORTED return status it will + exit the EBL. + + Argv[0] - "exit" + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_ABORTED + +**/ +EFI_STATUS +EblExitCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + UINTN MemoryMapSize; + EFI_MEMORY_DESCRIPTOR *MemoryMap; + UINTN MapKey; + UINTN DescriptorSize; + UINTN DescriptorVersion; + UINTN Pages; + + if (Argc > 1) { + if (AsciiStriCmp (Argv[1], "efi") != 0) { + return EFI_ABORTED; + } + } else if (Argc == 1) { + return EFI_ABORTED; + } + + MemoryMap = NULL; + MemoryMapSize = 0; + do { + Status = gBS->GetMemoryMap ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + + Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1; + MemoryMap = AllocatePages (Pages); + + // + // Get System MemoryMap + // + Status = gBS->GetMemoryMap ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + // Don't do anything between the GetMemoryMap() and ExitBootServices() + if (!EFI_ERROR (Status)) { + Status = gBS->ExitBootServices (gImageHandle, MapKey); + if (EFI_ERROR (Status)) { + FreePages (MemoryMap, Pages); + MemoryMap = NULL; + MemoryMapSize = 0; + } + } + } + } while (EFI_ERROR (Status)); + + // + // At this point it is very dangerous to do things EFI as most of EFI is now gone. + // This command is useful if you are working with a debugger as it will shutdown + // DMA and other things that could break a soft resets. + // + CpuDeadLoop (); + + // Should never get here, but makes the compiler happy + return EFI_ABORTED; +} + + +/** + Update the screen by decrementing the timeout value. + This AsciiPrint has to match the AsciiPrint in + EblPauseCmd. + + @param ElaspedTime Current timout value remaining + +**/ +VOID +EFIAPI +EblPauseCallback ( + IN UINTN ElapsedTime + ) +{ + AsciiPrint ("\b\b\b\b\b\b\b\b\b\b\b\b \b\b%3d seconds", ElapsedTime); +} + +/** + Pause until a key is pressed and abort the remaining commands on the command + line. If no key is pressed continue processing the command line. This command + allows the user to stop an operation from happening and return control to the + command prompt. + + Argv[0] - "pause" + Argv[1] - timeout value is decimal seconds + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS Timeout expired with no input + @return EFI_TIMEOUT Stop procesing other commands on the same command line + +**/ +EFI_STATUS +EblPauseCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + UINTN Delay; + EFI_INPUT_KEY Key; + + Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]); + + AsciiPrint ("Hit any key to break. You have %3d seconds", Delay); + Status = EblGetCharKey (&Key, Delay, EblPauseCallback); + AsciiPrint ("\n"); + + // If we timeout then the pause succeded thus return success + // If we get a key return timout to stop other commnad on this cmd line + return (Status == EFI_SUCCESS) ? EFI_TIMEOUT : EFI_SUCCESS;; +} + + +/** + On a debug build issue a software breakpoint to enter the debugger + + Argv[0] - "break" + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblBreakPointCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + CpuBreakpoint (); + return EFI_SUCCESS; +} + + +/** + Reset the system. If no Argument do a Cold reset. If argument use that reset type + (W)arm = Warm Reset + (S)hutdown = Shutdown Reset + + Argv[0] - "reset" + Argv[1] - warm or shutdown reset type + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblResetCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_RESET_TYPE ResetType; + + ResetType = EfiResetCold; + if (Argc > 1) { + switch (*Argv[1]) { + case 'W': + case 'w': + ResetType = EfiResetWarm; + break; + case 'S': + case 's': + ResetType = EfiResetShutdown; + } + } + + gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL); + return EFI_SUCCESS; +} + + +/** + Toggle page break global. This turns on and off prompting to Quit or hit any + key to continue when a command is about to scroll the screen with its output + + Argv[0] - "page" + Argv[1] - on or off + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblPageCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + if (Argc <= 1) { + // toggle setting + gPageBreak = (gPageBreak) ? FALSE : TRUE; + } else { + // use argv to set the value + if ((Argv[1][0] == 'o') || (Argv[1][0] == 'O')) { + if ((Argv[1][1] == 'n') || (Argv[1][1] == 'N')) { + gPageBreak = TRUE; + } else if ((Argv[1][1] == 'f') || (Argv[1][1] == 'F')) { + gPageBreak = FALSE; + } else { + return EFI_INVALID_PARAMETER; + } + } + } + return EFI_SUCCESS; +} + +EFI_STATUS +EblSleepCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + UINTN Delay; + + Delay = (Argc == 1)? 10 : AsciiStrDecimalToUintn (Argv[1]); + + gBS->Stall (Delay * 1000000); + + return EFI_SUCCESS; +} + +CHAR8 +ConvertToTextLine ( + IN CHAR8 Character + ) +{ + if (Character < ' ' || Character > '~') + { + return '.'; + } + else + { + return Character; + } +} + +UINTN +GetBytes ( + IN UINT8 *Address, + IN UINTN Bytes + ) +{ + UINTN Result = 0; + + if (Bytes >= 1) + Result = *Address++; + + if (Bytes >= 2) + Result = (Result << 8) + *Address++; + + if (Bytes >= 3) + Result = (Result << 8) + *Address++; + + return Result; +} + +CHAR8 mBlanks[] = " "; + +EFI_STATUS +OutputData ( + IN UINT8 *Address, + IN UINTN Length, + IN UINTN Width, + IN UINTN Offset + ) +{ + UINT8 *EndAddress; + UINTN Line; + CHAR8 TextLine[0x11]; + UINTN CurrentRow = 0; + UINTN Bytes; + UINTN Spaces = 0; + CHAR8 Blanks[80]; + + AsciiStrCpy (Blanks, mBlanks); + for (EndAddress = Address + Length; Address < EndAddress; Offset += Line) + { + AsciiPrint ("%08x: ", Offset); + for (Line = 0; (Line < 0x10) && (Address < EndAddress);) + { + Bytes = EndAddress - Address; + + switch (Width) + { + case 4: + if (Bytes >= 4) + { + AsciiPrint ("%08x ", *((UINT32 *)Address)); + TextLine[Line++] = ConvertToTextLine(*Address++); + TextLine[Line++] = ConvertToTextLine(*Address++); + TextLine[Line++] = ConvertToTextLine(*Address++); + TextLine[Line++] = ConvertToTextLine(*Address++); + } + else + { + AsciiPrint ("%08x ", GetBytes(Address, Bytes)); + Address += Bytes; + Line += Bytes; + } + break; + + case 2: + if (Bytes >= 2) + { + AsciiPrint ("%04x ", *((UINT16 *)Address)); + TextLine[Line++] = ConvertToTextLine(*Address++); + TextLine[Line++] = ConvertToTextLine(*Address++); + } + else + { + AsciiPrint ("%04x ", GetBytes(Address, Bytes)); + Address += Bytes; + Line += Bytes; + } + break; + + case 1: + AsciiPrint ("%02x ", *((UINT8 *)Address)); + TextLine[Line++] = ConvertToTextLine(*Address++); + break; + + default: + AsciiPrint ("Width must be 1, 2, or 4!\n"); + return EFI_INVALID_PARAMETER; + } + } + + // Pad spaces + if (Line < 0x10) + { + switch (Width) + { + case 4: + Spaces = 9 * ((0x10 - Line)/4); + break; + case 2: + Spaces = 5 * ((0x10 - Line)/2); + break; + case 1: + Spaces = 3 * (0x10 - Line); + break; + } + + Blanks[Spaces] = '\0'; + + AsciiPrint(Blanks); + + Blanks[Spaces] = ' '; + } + + TextLine[Line] = 0; + AsciiPrint ("|%a|\n", TextLine); + + if (EblAnyKeyToContinueQtoQuit(&CurrentRow, FALSE)) + { + return EFI_END_OF_FILE; + } + } + + if (Length % Width != 0) + { + AsciiPrint ("%08x\n", Offset); + } + + return EFI_SUCCESS; +} + +#define HEXDUMP_CHUNK 1024 + +EFI_STATUS +EblHexdumpCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_OPEN_FILE *File; + VOID *Location; + UINTN Size; + UINTN Width = 1; + UINTN Offset = 0; + EFI_STATUS Status; + UINTN Chunk = HEXDUMP_CHUNK; + + if ((Argc < 2) || (Argc > 3)) + { + return EFI_INVALID_PARAMETER; + } + + if (Argc == 3) + { + Width = AsciiStrDecimalToUintn(Argv[2]); + } + + if ((Width != 1) && (Width != 2) && (Width != 4)) + { + return EFI_INVALID_PARAMETER; + } + + File = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0); + if (File == NULL) + { + return EFI_NOT_FOUND; + } + + Location = AllocatePool(Chunk); + Size = EfiTell(File, NULL); + + for (Offset = 0; Offset + HEXDUMP_CHUNK <= Size; Offset += Chunk) + { + Chunk = HEXDUMP_CHUNK; + + Status = EfiRead(File, Location, &Chunk); + if (EFI_ERROR(Status)) + { + AsciiPrint ("Error reading file content\n"); + goto Exit; + } + + Status = OutputData(Location, Chunk, Width, File->BaseOffset + Offset); + if (EFI_ERROR(Status)) + { + if (Status == EFI_END_OF_FILE) { + Status = EFI_SUCCESS; + } + goto Exit; + } + } + + // Any left over? + if (Offset < Size) + { + Chunk = Size - Offset; + Status = EfiRead(File, Location, &Chunk); + if (EFI_ERROR(Status)) + { + AsciiPrint ("Error reading file content\n"); + goto Exit; + } + + Status = OutputData(Location, Chunk, Width, File->BaseOffset + Offset); + if (EFI_ERROR(Status)) + { + if (Status == EFI_END_OF_FILE) { + Status = EFI_SUCCESS; + } + goto Exit; + } + } + +Exit: + EfiClose(File); + + FreePool(Location); + + return EFI_SUCCESS; +} + +#define USE_DISKIO 1 + +EFI_STATUS +EblDiskIoCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + UINTN Offset; + UINT8 *EndOffset; + UINTN Length; + UINTN Line; + UINT8 *Buffer; + UINT8 *BufferOffset; + CHAR8 TextLine[0x11]; +#if USE_DISKIO + EFI_DISK_IO_PROTOCOL *DiskIo; +#else + EFI_BLOCK_IO_PROTOCOL *BlockIo; + UINTN Lba; +#endif + + if (AsciiStrCmp(Argv[1], "r") == 0) + { + Offset = AsciiStrHexToUintn(Argv[2]); + Length = AsciiStrHexToUintn(Argv[3]); + +#if USE_DISKIO + Status = gBS->LocateProtocol(&gEfiDiskIoProtocolGuid, NULL, (VOID **)&DiskIo); + if (EFI_ERROR(Status)) + { + AsciiPrint("Did not locate DiskIO\n"); + return Status; + } + + Buffer = AllocatePool(Length); + BufferOffset = Buffer; + + Status = DiskIo->ReadDisk(DiskIo, SIGNATURE_32('f','l','s','h'), Offset, Length, Buffer); + if (EFI_ERROR(Status)) + { + AsciiPrint("DiskIO read failed\n"); + gBS->FreePool(Buffer); + return Status; + } +#else + Status = gBS->LocateProtocol(&gEfiBlockIoProtocolGuid, NULL, (VOID **)&BlockIo); + if (EFI_ERROR(Status)) + { + AsciiPrint("Did not locate BlockIo\n"); + return Status; + } + + Length = BlockIo->Media->BlockSize; + Buffer = AllocatePool(Length); + BufferOffset = Buffer; + Lba = Offset/BlockIo->Media->BlockSize; + + Status = BlockIo->ReadBlocks(BlockIo, BlockIo->Media->MediaId, Lba, Length, Buffer); + if (EFI_ERROR(Status)) + { + AsciiPrint("BlockIo read failed\n"); + gBS->FreePool(Buffer); + return Status; + } + + // Whack offset to what we actually read from + Offset = Lba * BlockIo->Media->BlockSize; + + Length = 0x100; +#endif + + for (EndOffset = BufferOffset + Length; BufferOffset < EndOffset; Offset += 0x10) + { + AsciiPrint ("%08x: ", Offset); + + for (Line = 0; Line < 0x10; Line++) + { + AsciiPrint ("%02x ", *BufferOffset); + + if (*BufferOffset < ' ' || *BufferOffset > '~') + TextLine[Line] = '.'; + else + TextLine[Line] = *BufferOffset; + + BufferOffset++; + } + + TextLine[Line] = '\0'; + AsciiPrint ("|%a|\n", TextLine); + } + + gBS->FreePool(Buffer); + + return EFI_SUCCESS; + } + else if (AsciiStrCmp(Argv[1], "w") == 0) + { + Offset = AsciiStrHexToUintn(Argv[2]); + Length = AsciiStrHexToUintn(Argv[3]); + Buffer = (UINT8 *)AsciiStrHexToUintn(Argv[4]); + +#if USE_DISKIO + Status = gBS->LocateProtocol(&gEfiDiskIoProtocolGuid, NULL, (VOID **)&DiskIo); + if (EFI_ERROR(Status)) + { + AsciiPrint("Did not locate DiskIO\n"); + return Status; + } + + Status = DiskIo->WriteDisk(DiskIo, SIGNATURE_32('f','l','s','h'), Offset, Length, Buffer); + if (EFI_ERROR(Status)) + { + AsciiPrint("DiskIO write failed\n"); + return Status; + } + +#else +#endif + + return EFI_SUCCESS; + } + else + { + return EFI_INVALID_PARAMETER; + } +} + +GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdTemplate[] = +{ + { + "reset", + " [type]; Reset system. type = [warm] [shutdown] default is cold reset", + NULL, + EblResetCmd + }, + { + "exit", + "; Exit EBL", + NULL, + EblExitCmd + }, + { + "help", + " [cmd]; Help on cmd or a list of all commands if cmd is ommited", + NULL, + EblHelpCmd + }, + { + "break", + "; Generate debugging breakpoint", + NULL, + EblBreakPointCmd + }, + { + "page", + " [on|off]]; toggle promting on command output larger than screen", + NULL, + EblPageCmd + }, + { + "pause", + " [sec]; Pause for sec[10] seconds. ", + NULL, + EblPauseCmd + }, + { + "sleep", + " [sec]; Sleep for sec[10] seconds. ", + NULL, + EblSleepCmd + }, + { + "hexdump", + " filename ; dump a file as hex bytes", + NULL, + EblHexdumpCmd + }, + { + "diskio", + " [r|w] offset [length [dataptr]]; do a DiskIO read or write ", + NULL, + EblDiskIoCmd + } +}; + + +EFI_HANDLE gExternalCmdHandle = NULL; + +/** + Initialize the commands in this in this file +**/ +VOID +EblInitializeCmdTable ( + VOID + ) +{ + + EblAddCommands (mCmdTemplate, sizeof (mCmdTemplate)/sizeof (EBL_COMMAND_TABLE)); + + gBS->InstallProtocolInterface ( + &gExternalCmdHandle, + &gEfiEblAddCommandProtocolGuid, + EFI_NATIVE_INTERFACE, + &gEblAddCommand + ); + +} + + +VOID +EblShutdownExternalCmdTable ( + VOID + ) +{ + gBS->UninstallProtocolInterface (gExternalCmdHandle, &gEfiEblAddCommandProtocolGuid, &gEblAddCommand); +} + + diff --git a/EmbeddedPkg/Ebl/Dir.c b/EmbeddedPkg/Ebl/Dir.c new file mode 100644 index 0000000000..4e9f7b98b2 --- /dev/null +++ b/EmbeddedPkg/Ebl/Dir.c @@ -0,0 +1,305 @@ +/** @file + Dir for EBL (Embedded Boot Loader) + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: CmdTemplate.c + + Search/Replace Dir with the name of your new command + +**/ + +#include "Ebl.h" + + +GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *gFvFileType[] = { + "All", + "Raw", + "Freeform", + "SEC", + "PeiCore", + "DxeCore", + "PEIM", + "Driver", + "Combo Driver", + "Application", + "NULL", + "FV" +}; + + +/** + Perform a dir on a device. The device must support Simple File System Protocol + or the FV protocol. + + Argv[0] - "dir" + Argv[1] - Device Name:path. Path is optional + Argv[2] - Optional filename to match on. A leading * means match substring + Argv[3] - Optional FV file type + + dir fs1:\efi ; perform a dir on fs1: device in the efi directory + dir fs1:\efi *.efi; perform a dir on fs1: device in the efi directory but + only print out files that contain the string *.efi + dir fv1:\ ; perform a dir on fv1: device in the efi directory + NOTE: fv devices do not contian subdirs + dir fv1:\ * PEIM ; will match all files of type SEC + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblDirCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + EFI_OPEN_FILE *File; + EFI_FILE_INFO *DirInfo; + UINTN ReadSize; + UINTN CurrentRow; + CHAR16 *MatchSubString; + EFI_STATUS GetNextFileStatus; + UINTN Key; + EFI_FV_FILETYPE SearchType; + EFI_FV_FILETYPE Type; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINTN Size; + EFI_GUID NameGuid; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; + UINT32 AuthenticationStatus; + VOID *Section; + UINTN SectionSize; + EFI_FV_FILETYPE Index; + UINTN Length; + UINTN BestMatchCount; + CHAR16 UnicodeFileName[MAX_CMD_LINE]; + + + if (Argc <= 1) { + // CWD not currently supported + return EFI_SUCCESS; + } + + File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); + if (File == NULL) { + return EFI_SUCCESS; + } + + if (File->Type == EfiOpenFirmwareVolume) { + // FV Dir + + SearchType = EFI_FV_FILETYPE_ALL; + UnicodeFileName[0] = '\0'; + MatchSubString = &UnicodeFileName[0]; + if (Argc > 2) { + AsciiStrToUnicodeStr (Argv[2], UnicodeFileName); + if (UnicodeFileName[0] == '*') { + // Handle *Name substring matching + MatchSubString = &UnicodeFileName[1]; + } + + // Handle file type matchs + if (Argc > 3) { + // match a specific file type, always last argument + Length = AsciiStrLen (Argv[3]); + for (Index = 1, BestMatchCount = 0; Index < sizeof (gFvFileType)/sizeof (CHAR8 *); Index++) { + if (AsciiStriCmp (gFvFileType[Index], Argv[3]) == 0) { + // exact match + SearchType = Index; + break; + } + + if (AsciiStrniCmp (Argv[3], gFvFileType[Index], Length) == 0) { + // partial match, so keep looking to make sure there is only one partial match + BestMatchCount++; + SearchType = Index; + } + } + + if (BestMatchCount > 1) { + SearchType = EFI_FV_FILETYPE_ALL; + } + } + } + + Fv = File->Fv; + Key = 0; + CurrentRow = 0; + do { + Type = SearchType; + GetNextFileStatus = Fv->GetNextFile ( + Fv, + &Key, + &Type, + &NameGuid, + &Attributes, + &Size + ); + if (!EFI_ERROR (GetNextFileStatus)) { + // Calculate size of entire file + Section = NULL; + Size = 0; + Status = Fv->ReadFile ( + Fv, + &NameGuid, + Section, + &Size, + &Type, + &Attributes, + &AuthenticationStatus + ); + if (!((Status == EFI_BUFFER_TOO_SMALL) || !EFI_ERROR (Status))) { + // EFI_SUCCESS or EFI_BUFFER_TOO_SMALL mean size is valid + Size = 0; + } + + // read the UI seciton to do a name match. + Section = NULL; + Status = Fv->ReadSection ( + Fv, + &NameGuid, + EFI_SECTION_USER_INTERFACE, + 0, + &Section, + &SectionSize, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + if (StrStr (Section, MatchSubString) != NULL) { + AsciiPrint (" %g %s %a %,d\n", &NameGuid, Section, gFvFileType[Type], Size); + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { + break; + } + } + FreePool (Section); + } else { + if (*MatchSubString == '\0') { + AsciiPrint (" %g %a %,d\n", &NameGuid, gFvFileType[Type], Size); + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { + break; + } + } + } + } + } while (!EFI_ERROR (GetNextFileStatus)); + + } else if ((File->Type == EfiOpenFileSystem) || (File->Type == EfiOpenBlockIo)) { + // Simple File System DIR + + if (File->FsFileInfo == NULL) { + return EFI_SUCCESS; + } + + if (!(File->FsFileInfo->Attribute & EFI_FILE_DIRECTORY)) { + return EFI_SUCCESS; + } + + // Handle *Name substring matching + MatchSubString = NULL; + UnicodeFileName[0] = '\0'; + if (Argc > 2) { + AsciiStrToUnicodeStr (Argv[2], UnicodeFileName); + if (UnicodeFileName[0] == '*') { + MatchSubString = &UnicodeFileName[1]; + } + } + + File->FsFileHandle->SetPosition (File->FsFileHandle, 0); + for (CurrentRow = 0;;) { + // First read gets the size + DirInfo = NULL; + ReadSize = 0; + Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo); + if (Status == EFI_BUFFER_TOO_SMALL) { + // Allocate the buffer for the real read + DirInfo = AllocatePool (ReadSize); + if (DirInfo == NULL) { + goto Done; + } + + // Read the data + Status = File->FsFileHandle->Read (File->FsFileHandle, &ReadSize, DirInfo); + if ((EFI_ERROR (Status)) || (ReadSize == 0)) { + break; + } + } else { + break; + } + + if (MatchSubString != NULL) { + if (StrStr (&DirInfo->FileName[0], MatchSubString) == NULL) { + // does not match *name argument, so skip + continue; + } + } else if (UnicodeFileName[0] != '\0') { + // is not an exact match for name argument, so skip + if (StrCmp (&DirInfo->FileName[0], UnicodeFileName) != 0) { + continue; + } + } + + if (DirInfo->Attribute & EFI_FILE_DIRECTORY) { + AsciiPrint (" %s\n", &DirInfo->FileName[0]); + } else { + AsciiPrint ("%,14ld %s\n", DirInfo->FileSize, &DirInfo->FileName[0]); + } + + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { + break; + } + + FreePool (DirInfo); + } + +Done: + if (DirInfo != NULL) { + FreePool (DirInfo); + } + } + + EfiClose (File); + + return EFI_SUCCESS; +} + + + +GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDirTemplate[] = +{ + { + "dir", + " dirdev [*match]; directory listing of dirdev. opt match a substring", + NULL, + EblDirCmd + } +}; + + +/** + Initialize the commands in this in this file +**/ +VOID +EblInitializeDirCmd ( + VOID + ) +{ + if (FeaturePcdGet (PcdEmbeddedDirCmd)) { + EblAddCommands (mCmdDirTemplate, sizeof (mCmdDirTemplate)/sizeof (EBL_COMMAND_TABLE)); + } +} + diff --git a/EmbeddedPkg/Ebl/Ebl.h b/EmbeddedPkg/Ebl/Ebl.h new file mode 100644 index 0000000000..705511a0e4 --- /dev/null +++ b/EmbeddedPkg/Ebl/Ebl.h @@ -0,0 +1,194 @@ +/** @file + Include flie for basic command line parser for EBL (Embedded Boot Loader) + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EBL_H__ +#define __EBL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// Prompt for the command line +// +#define CMD_SEPERATOR ';' +#define EBL_MAX_COMMAND_COUNT 0x100 +#define MAX_CMD_HISTORY 16 +#define MAX_CMD_LINE 256 +#define MAX_ARGS 32 + +#define EBL_CR 0x0a +#define EBL_LF 0x0d + +#define EFI_SET_TIMER_TO_SECOND 10000000 + + + +EBL_COMMAND_TABLE * +EblGetCommand ( + IN CHAR8 *CommandName + ); + + +EFI_STATUS +EblPathToDevice ( + IN CHAR8 *Path, + OUT EFI_HANDLE *DeviceHandle, + OUT EFI_DEVICE_PATH_PROTOCOL **PathDevicePath, + OUT VOID **Buffer, + OUT UINTN *BufferSize + ); + +BOOLEAN +EblAnyKeyToContinueQtoQuit ( + IN UINTN *CurrentRow, + IN BOOLEAN PrefixNewline + ); + +VOID +EblUpdateDeviceLists ( + VOID + ); + +VOID +EblInitializeCmdTable ( + VOID + ); + +VOID +EblShutdownExternalCmdTable ( + VOID + ); + +VOID +EblSetTextColor ( + UINTN Attribute + ); + + +EFI_STATUS +EblGetCharKey ( + IN OUT EFI_INPUT_KEY *Key, + IN UINTN TimoutInSec, + IN EBL_GET_CHAR_CALL_BACK CallBack OPTIONAL + ); + +// BugBug: Move me to a library +INTN +EFIAPI +AsciiStrniCmp ( + IN CONST CHAR8 *FirstString, + IN CONST CHAR8 *SecondString, + IN UINTN Length + ); + + +VOID +EblInitializeDeviceCmd ( + VOID + ); + +VOID +EblInitializemdHwDebugCmds ( + VOID + ); + +VOID +EblInitializeDirCmd ( + VOID + ); + +VOID +EblInitializeHobCmd ( + VOID + ); + +VOID +EblInitializemdHwIoDebugCmds ( + VOID + ); + +VOID +EblInitializeScriptCmd ( + VOID + ); + +VOID +EblInitializeNetworkCmd ( + VOID + ); + +CHAR8 * +ParseArguments ( + IN CHAR8 *CmdLine, + OUT UINTN *Argc, + OUT CHAR8 **Argv + ); + +EFI_STATUS +ProcessCmdLine ( + IN CHAR8 *CmdLine, + IN UINTN MaxCmdLineSize + ); + +EFI_STATUS +OutputData ( + IN UINT8 *Address, + IN UINTN Length, + IN UINTN Width, + IN UINTN Offset + ); + +extern UINTN gScreenColumns; +extern UINTN gScreenRows; +extern BOOLEAN gPageBreak; +extern CHAR8 *gMemMapType[]; + +#endif + diff --git a/EmbeddedPkg/Ebl/Ebl.inf b/EmbeddedPkg/Ebl/Ebl.inf new file mode 100644 index 0000000000..f3413546be --- /dev/null +++ b/EmbeddedPkg/Ebl/Ebl.inf @@ -0,0 +1,110 @@ +#%HEADER% +#/** @file +# EBL Applicaiton +# +# This is a shell application that will display Hello World. +# Copyright (c) 2007, Intel Corporation. +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Ebl + FILE_GUID = 3CEF354A-3B7A-4519-AD70-72A134698311 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = EdkBootLoaderEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +[Sources.common] + Main.c + Command.c + EfiDevice.c + HwDebug.c + HwIoDebug.c + Dir.c + Hob.c + Script.c + Ebl.h + Network.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + DebugLib + UefiLib + UefiApplicationEntryPoint + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + BaseMemoryLib + MemoryAllocationLib + DevicePathLib + IoLib + PrintLib + PcdLib + EfiFileLib + HobLib + BaseLib + EblCmdLib + EblNetworkLib + +[LibraryClasses.ARM] + SemihostLib + +[Protocols.common] + gEfiFirmwareVolume2ProtocolGuid + gEfiFirmwareVolumeBlockProtocolGuid + gEfiBlockIoProtocolGuid + gEfiSimpleFileSystemProtocolGuid + gEfiLoadFileProtocolGuid + gEfiLoadedImageProtocolGuid + gEfiPxeBaseCodeProtocolGuid + gEfiEblAddCommandProtocolGuid + gEfiDiskIoProtocolGuid + gEfiPciIoProtocolGuid + gEfiSimpleNetworkProtocolGuid + +[Guids.common] + gEfiDxeServicesTableGuid + gEfiFileInfoGuid + gEfiHobMemoryAllocModuleGuid + gEfiMemoryTypeInformationGuid + +[FeaturePcd.common] + gEmbeddedTokenSpaceGuid.PcdEmbeddedMacBoot + gEmbeddedTokenSpaceGuid.PcdEmbeddedDirCmd + gEmbeddedTokenSpaceGuid.PcdEmbeddedHobCmd + gEmbeddedTokenSpaceGuid.PcdEmbeddedHwDebugCmd + gEmbeddedTokenSpaceGuid.PcdEmbeddedIoEnable + gEmbeddedTokenSpaceGuid.PcdEmbeddedScriptCmd + gEmbeddedTokenSpaceGuid.PcdEmbeddedPciDebugCmd + +[FixedPcd.common] + gEmbeddedTokenSpaceGuid.PcdEmbeddedAutomaticBootCommand + gEmbeddedTokenSpaceGuid.PcdEmbeddedDefaultTextColor + gEmbeddedTokenSpaceGuid.PcdEmbeddedMemVariableStoreSize + gEmbeddedTokenSpaceGuid.PcdEmbeddedShellCharacterEcho + gEmbeddedTokenSpaceGuid.PcdEmbeddedPrompt + diff --git a/EmbeddedPkg/Ebl/EfiDevice.c b/EmbeddedPkg/Ebl/EfiDevice.c new file mode 100644 index 0000000000..7633d66934 --- /dev/null +++ b/EmbeddedPkg/Ebl/EfiDevice.c @@ -0,0 +1,969 @@ +/** @file + EBL commands for EFI and PI Devices + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ebl.h" + + +EFI_DXE_SERVICES *gDS = NULL; + + +/** + Print information about the File System device. + + @param File Open File for the device + +**/ +VOID +EblPrintFsInfo ( + IN EFI_OPEN_FILE *File + ) +{ + if (File == NULL) { + return; + } + + AsciiPrint (" %a: ", File->DeviceName); + if (File->FsInfo != NULL) { + AsciiPrint ("%s: ", File->FsInfo->VolumeLabel); + if (File->FsInfo->ReadOnly) { + AsciiPrint ("ReadOnly"); + } + } + + AsciiPrint ("\n"); + EfiClose (File); +} + + +/** + Print information about the FV devices. + + @param File Open File for the device + +**/ +VOID +EblPrintFvbInfo ( + IN EFI_OPEN_FILE *File + ) +{ + if (File == NULL) { + return; + } + + AsciiPrint (" %a: 0x%08lx - 0x%08lx : 0x%08x\n", File->DeviceName, File->FvStart, File->FvStart + File->FvSize - 1, File->FvSize); + EfiClose (File); +} + + +/** + Print information about the Blk IO devices. + If the device supports PXE dump out extra information + + @param File Open File for the device + +**/ +VOID +EblPrintBlkIoInfo ( + IN EFI_OPEN_FILE *File + ) +{ + UINT64 DeviceSize; + + + if (File == NULL) { + return; + } + + AsciiPrint (" %a: ", File->DeviceName); + if (File->FsBlockIoMedia.RemovableMedia) { + AsciiPrint ("Removable "); + } + if (!File->FsBlockIoMedia.MediaPresent) { + AsciiPrint ("No Media "); + } + if (File->FsBlockIoMedia.LogicalPartition) { + AsciiPrint ("Partition "); + } + DeviceSize = MultU64x32 (File->FsBlockIoMedia.LastBlock + 1, File->FsBlockIoMedia.BlockSize); + AsciiPrint ("Size = 0x%lX\n", DeviceSize); + + EfiClose (File); +} + + + /** + Print information about the Load File devices. + If the device supports PXE dump out extra information + + @param File Open File for the device + +**/ +VOID +EblPrintLoadFileInfo ( + IN EFI_OPEN_FILE *File + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; + MAC_ADDR_DEVICE_PATH *MacAddr; + UINTN HwAddressSize; + UINTN Index; + + if (File == NULL) { + return; + } + + AsciiPrint (" %a: %a ", File->DeviceName, EblLoadFileBootTypeString (File->EfiHandle)); + + if (File->DevicePath != NULL) { + // Try to print out the MAC address + for (DevicePathNode = File->DevicePath; + !IsDevicePathEnd (DevicePathNode); + DevicePathNode = NextDevicePathNode (DevicePathNode)) { + + if ((DevicePathType (DevicePathNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (DevicePathNode) == MSG_MAC_ADDR_DP)) { + MacAddr = (MAC_ADDR_DEVICE_PATH *)DevicePathNode; + + HwAddressSize = sizeof (EFI_MAC_ADDRESS); + if (MacAddr->IfType == 0x01 || MacAddr->IfType == 0x00) { + HwAddressSize = 6; + } + + AsciiPrint ("MAC "); + for (Index = 0; Index < HwAddressSize; Index++) { + AsciiPrint ("%02x", MacAddr->MacAddress.Addr[Index] & 0xff); + } + } + } + } + + AsciiPrint ("\n"); + EfiClose (File); + return; +} + + + +/** + Dump information about devices in the system. + + fv: PI Firmware Volume + fs: EFI Simple File System + blk: EFI Block IO + LoadFile: EFI Load File Protocol (commonly PXE network boot) + + Argv[0] - "device" + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblDeviceCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + UINTN Index; + UINTN CurrentRow; + UINTN Max; + + CurrentRow = 0; + + // Need to call here to make sure Device Counts are valid + EblUpdateDeviceLists (); + + Max = EfiGetDeviceCounts (EfiOpenFirmwareVolume); + if (Max != 0) { + AsciiPrint ("Firmware Volume Devices:\n"); + for (Index = 0; Index < Max; Index++) { + EblPrintFvbInfo (EfiDeviceOpenByType (EfiOpenFirmwareVolume, Index)); + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { + break; + } + } + } + + Max = EfiGetDeviceCounts (EfiOpenFileSystem); + if (Max != 0) { + AsciiPrint ("File System Devices:\n"); + for (Index = 0; Index < Max; Index++) { + EblPrintFsInfo (EfiDeviceOpenByType (EfiOpenFileSystem, Index)); + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { + break; + } + } + } + + Max = EfiGetDeviceCounts (EfiOpenBlockIo); + if (Max != 0) { + AsciiPrint ("Block IO Devices:\n"); + for (Index = 0; Index < Max; Index++) { + EblPrintBlkIoInfo (EfiDeviceOpenByType (EfiOpenBlockIo, Index)); + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { + break; + } + } + } + + Max = EfiGetDeviceCounts (EfiOpenLoadFile); + if (Max != 0) { + AsciiPrint ("LoadFile Devices: (usually network)\n"); + for (Index = 0; Index < Max; Index++) { + EblPrintLoadFileInfo (EfiDeviceOpenByType (EfiOpenLoadFile, Index)); + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { + break; + } + } + } + + return EFI_SUCCESS; +} + + +/** + Start an EFI image (PE32+ with EFI defined entry point). + + Argv[0] - "start" + Argv[1] - device name and path + Argv[2] - "" string to pass into image being started + + start fs1:\Temp\Fv.Fv "arg to pass" ; load an FV from the disk and pass the + ; ascii string arg to pass to the image + start fv0:\FV ; load an FV from an FV (not common) + start LoadFile0: ; load an FV via a PXE boot + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblStartCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + EFI_OPEN_FILE *File; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_HANDLE ImageHandle; + UINTN ExitDataSize; + CHAR16 *ExitData; + VOID *Buffer; + UINTN BufferSize; + EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; + + ImageHandle = NULL; + + if (Argc < 2) { + return EFI_INVALID_PARAMETER; + } + + File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); + if (File == NULL) { + return EFI_INVALID_PARAMETER; + } + + DevicePath = File->DevicePath; + if (DevicePath != NULL) { + // check for device path form: blk, fv, fs, and loadfile + Status = gBS->LoadImage (FALSE, gImageHandle, DevicePath, NULL, 0, &ImageHandle); + } else { + // Check for buffer form: A0x12345678:0x1234 syntax. + // Means load using buffer starting at 0x12345678 of size 0x1234. + + Status = EfiReadAllocatePool (File, &Buffer, &BufferSize); + if (EFI_ERROR (Status)) { + EfiClose (File); + return Status; + } + Status = gBS->LoadImage (FALSE, gImageHandle, DevicePath, Buffer, BufferSize, &ImageHandle); + + FreePool (Buffer); + } + + EfiClose (File); + + if (!EFI_ERROR (Status)) { + if (Argc >= 3) { + // Argv[2] is a "" string that we pass directly to the EFI application without the "" + // We don't pass Argv[0] to the EFI Application (it's name) just the args + Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo); + ASSERT_EFI_ERROR (Status); + + ImageInfo->LoadOptionsSize = (UINT32)AsciiStrSize (Argv[2]); + ImageInfo->LoadOptions = AllocatePool (ImageInfo->LoadOptionsSize); + AsciiStrCpy (ImageInfo->LoadOptions, Argv[2]); + } + + // Transfer control to the EFI image we loaded with LoadImage() + Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData); + } + + return Status; +} + + +/** + Load a Firmware Volume (FV) into memory from a device. This causes drivers in + the FV to be dispatched if the dependancies of the drivers are met. + + Argv[0] - "loadfv" + Argv[1] - device name and path + + loadfv fs1:\Temp\Fv.Fv ; load an FV from the disk + loadfv fv0:\FV ; load an FV from an FV (not common) + loadfv LoadFile0: ; load an FV via a PXE boot + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblLoadFvCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + EFI_OPEN_FILE *File; + VOID *FvStart; + UINTN FvSize; + EFI_HANDLE FvHandle; + + + if (Argc < 2) { + return EFI_INVALID_PARAMETER; + } + + File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); + if (File == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (File->Type == EfiOpenMemoryBuffer) { + // If it is a address just use it. + Status = gDS->ProcessFirmwareVolume (File->Buffer, File->Size, &FvHandle); + } else { + // If it is a file read it into memory and use it + Status = EfiReadAllocatePool (File, &FvStart, &FvSize); + EfiClose (File); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gDS->ProcessFirmwareVolume (FvStart, FvSize, &FvHandle); + FreePool (FvStart); + } + return Status; +} + + +/** + Perform an EFI connect to connect devices that follow the EFI driver model. + If it is a PI system also call the dispatcher in case a new FV was made + availible by one of the connect EFI drivers (this is not a common case). + + Argv[0] - "connect" + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblConnectCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + BOOLEAN Dispatch; + EFI_OPEN_FILE *File; + + + if (Argc > 1) { + if ((*Argv[1] == 'd') || (*Argv[1] == 'D')) { + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < HandleCount; Index++) { + gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); + } + + // + // Given we disconnect our console we should go and do a connect now + // + } else { + File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); + if (File != NULL) { + AsciiPrint ("Connecting %a\n", Argv[1]); + gBS->ConnectController (File->EfiHandle, NULL, NULL, TRUE); + EfiClose (File); + return EFI_SUCCESS; + } + } + } + + Dispatch = FALSE; + do { + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < HandleCount; Index++) { + gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); + } + + FreePool (HandleBuffer); + + // + // Check to see if it's possible to dispatch an more DXE drivers. + // The BdsLibConnectAllEfi () may have made new DXE drivers show up. + // If anything is Dispatched Status == EFI_SUCCESS and we will try + // the connect again. + // + if (gDS == NULL) { + Status = EFI_NOT_FOUND; + } else { + Status = gDS->Dispatch (); + if (!EFI_ERROR (Status)) { + Dispatch = TRUE; + } + } + + } while (!EFI_ERROR (Status)); + + if (Dispatch) { + AsciiPrint ("Connected and dispatched\n"); + } else { + AsciiPrint ("Connect\n"); + } + + return EFI_SUCCESS; +} + + + +CHAR8 *gMemMapType[] = { + "reserved ", + "LoaderCode", + "LoaderData", + "BS_code ", + "BS_data ", + "RT_code ", + "RT_data ", + "available ", + "Unusable ", + "ACPI_recl ", + "ACPI_NVS ", + "MemMapIO ", + "MemPortIO ", + "PAL_code " +}; + + +/** + Dump out the EFI memory map + + Argv[0] - "memmap" + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblMemMapCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + EFI_MEMORY_DESCRIPTOR *MemMap; + EFI_MEMORY_DESCRIPTOR *OrigMemMap; + UINTN MemMapSize; + UINTN MapKey; + UINTN DescriptorSize; + UINT32 DescriptorVersion; + UINT64 PageCount[EfiMaxMemoryType]; + UINTN Index; + UINT64 EntrySize; + UINTN CurrentRow; + UINT64 TotalMemory; + + ZeroMem (PageCount, sizeof (PageCount)); + + AsciiPrint ("EFI Memory Map\n"); + + // First call is to figure out how big the buffer needs to be + MemMapSize = 0; + MemMap = NULL; + Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion); + if (Status == EFI_BUFFER_TOO_SMALL) { + // In case the AllocatPool changes the memory map we added in some extra descriptors + MemMapSize += (DescriptorSize * 0x100); + OrigMemMap = MemMap = AllocatePool (MemMapSize); + if (OrigMemMap != NULL) { + // 2nd time we get the data + Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion); + if (!EFI_ERROR (Status)) { + for (Index = 0, CurrentRow = 0; Index < MemMapSize/DescriptorSize; Index++) { + EntrySize = LShiftU64 (MemMap->NumberOfPages, 12); + AsciiPrint ("\n%a %016lx - %016lx: # %08lx %016lx", gMemMapType[MemMap->Type % EfiMaxMemoryType], MemMap->PhysicalStart, MemMap->PhysicalStart + EntrySize -1, MemMap->NumberOfPages, MemMap->Attribute); + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { + break; + } + + PageCount[MemMap->Type % EfiMaxMemoryType] += MemMap->NumberOfPages; + MemMap = NEXT_MEMORY_DESCRIPTOR (MemMap, DescriptorSize); + } + } + + for (Index = 0, TotalMemory = 0; Index < EfiMaxMemoryType; Index++) { + if (PageCount[Index] != 0) { + AsciiPrint ("\n %a %,7ld Pages (%,14ld)", gMemMapType[Index], PageCount[Index], LShiftU64 (PageCount[Index], 12)); + if (Index == EfiLoaderCode || + Index == EfiLoaderData || + Index == EfiBootServicesCode || + Index == EfiBootServicesData || + Index == EfiRuntimeServicesCode || + Index == EfiRuntimeServicesData || + Index == EfiConventionalMemory || + Index == EfiACPIReclaimMemory || + Index == EfiACPIMemoryNVS || + Index == EfiPalCode + ) { + // Count total memory + TotalMemory += PageCount[Index]; + } + } + } + + AsciiPrint ("\nTotal Memory: %,ld MB (%,ld bytes)\n", RShiftU64 (TotalMemory, 8), LShiftU64 (TotalMemory, 12)); + + FreePool (OrigMemMap); + + } + } + + return EFI_SUCCESS; +} + + + + +/** + Load a file into memory and optionally jump to it. A load addres can be + specified or automatically allocated. A quoted command line can optionally + be passed into the image. + + Argv[0] - "go" + Argv[1] - Device Name:path for the file to load + Argv[2] - Address to load to or '*' if the load address will be allocated + Argv[3] - Optional Entry point to the image. Image will be called if present + Argv[4] - "" string that will be passed as Argc & Argv to EntryPoint. Needs + to include the command name + + go fv1:\EblCmdX 0x10000 0x10010 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX + from FV1 to location 0x10000 and call the entry point at 0x10010 passing + in "EblCmdX Arg2 Arg3 Arg4" as the arguments. + + go fv0:\EblCmdX * 0x10 "EblCmdX Arg2 Arg3 Arg4"; - load EblCmdX from FS0 + to location allocated by this comamnd and call the entry point at offset 0x10 + passing in "EblCmdX Arg2 Arg3 Arg4" as the arguments. + + go fv1:\EblCmdX 0x10000; Load EblCmdX to address 0x10000 and return + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblGoCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + EFI_OPEN_FILE *File; + VOID *Address; + UINTN Size; + EBL_COMMMAND EntryPoint; + UINTN EntryPointArgc; + CHAR8 *EntryPointArgv[MAX_ARGS]; + + + if (Argc <= 2) { + // device name and laod address are required + return EFI_SUCCESS; + } + + File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); + if (File == NULL) { + AsciiPrint (" %a is not a valid path\n", Argv[1]); + return EFI_SUCCESS; + } + + EntryPoint = (EBL_COMMMAND)((Argc > 3) ? (UINTN)AsciiStrHexToUintn (Argv[3]) : (UINTN)NULL); + if (Argv[2][0] == '*') { + // * Means allocate the buffer + Status = EfiReadAllocatePool (File, &Address, &Size); + + // EntryPoint is relatvie to the start of the image + EntryPoint = (EBL_COMMMAND)((UINTN)EntryPoint + (UINTN)Address); + + } else { + Address = (VOID *)AsciiStrHexToUintn (Argv[2]); + Size = File->Size; + + // File->Size for LoadFile is lazy so we need to use the tell to figure it out + EfiTell (File, NULL); + Status = EfiRead (File, Address, &Size); + } + + if (!EFI_ERROR (Status)) { + AsciiPrint ("Loaded %,d bytes to 0x%08x\n", Size, Address); + + if (Argc > 3) { + if (Argc > 4) { + ParseArguments (Argv[4], &EntryPointArgc, EntryPointArgv); + } else { + EntryPointArgc = 1; + EntryPointArgv[0] = File->FileName; + } + + Status = EntryPoint (EntryPointArgc, EntryPointArgv); + } + } + + EfiClose (File); + return Status; +} + +#define FILE_COPY_CHUNK 0x20000 + +EFI_STATUS +EblFileCopyCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_OPEN_FILE *Source = NULL; + EFI_OPEN_FILE *Destination = NULL; + EFI_STATUS Status = EFI_SUCCESS; + VOID *Buffer = NULL; + UINTN Size; + UINTN Offset; + UINTN Chunk = FILE_COPY_CHUNK; + + if (Argc < 3) { + return EFI_INVALID_PARAMETER; + } + + Source = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0); + if (Source == NULL) { + AsciiPrint("Source file open error.\n"); + return EFI_NOT_FOUND; + } + + Destination = EfiOpen(Argv[2], EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); + if (Destination == NULL) { + AsciiPrint("Destination file open error.\n"); + return EFI_NOT_FOUND; + } + + Buffer = AllocatePool(FILE_COPY_CHUNK); + if (Buffer == NULL) { + goto Exit; + } + + Size = EfiTell(Source, NULL); + + for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size; Offset += Chunk) { + Chunk = FILE_COPY_CHUNK; + + Status = EfiRead(Source, Buffer, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("Read file error\n"); + goto Exit; + } + + Status = EfiWrite(Destination, Buffer, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("Write file error\n"); + goto Exit; + } + } + + // Any left over? + if (Offset < Size) { + Chunk = Size - Offset; + + Status = EfiRead(Source, Buffer, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("Read file error\n"); + goto Exit; + } + + Status = EfiWrite(Destination, Buffer, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("Write file error\n"); + goto Exit; + } + } + +Exit: + if (Source != NULL) { + Status = EfiClose(Source); + if (EFI_ERROR(Status)) { + AsciiPrint("Source close error %r\n", Status); + } + } + + if (Destination != NULL) { + Status = EfiClose(Destination); + if (EFI_ERROR(Status)) { + AsciiPrint("Destination close error %r\n", Status); + } + } + + if (Buffer != NULL) { + FreePool(Buffer); + } + + return Status; +} + +EFI_STATUS +EblFileDiffCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_OPEN_FILE *File1 = NULL; + EFI_OPEN_FILE *File2 = NULL; + EFI_STATUS Status = EFI_SUCCESS; + VOID *Buffer1 = NULL; + VOID *Buffer2 = NULL; + UINTN Size1; + UINTN Size2; + UINTN Offset; + UINTN Chunk = FILE_COPY_CHUNK; + + if (Argc != 3) { + return EFI_INVALID_PARAMETER; + } + + File1 = EfiOpen(Argv[1], EFI_FILE_MODE_READ, 0); + if (File1 == NULL) { + AsciiPrint("File 1 open error.\n"); + return EFI_NOT_FOUND; + } + + File2 = EfiOpen(Argv[2], EFI_FILE_MODE_READ, 0); + if (File2 == NULL) { + AsciiPrint("File 2 open error.\n"); + return EFI_NOT_FOUND; + } + + Size1 = EfiTell(File1, NULL); + Size2 = EfiTell(File2, NULL); + + if (Size1 != Size2) { + AsciiPrint("Files differ.\n"); + goto Exit; + } + + Buffer1 = AllocatePool(FILE_COPY_CHUNK); + if (Buffer1 == NULL) { + goto Exit; + } + + Buffer2 = AllocatePool(FILE_COPY_CHUNK); + if (Buffer2 == NULL) { + goto Exit; + } + + for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size1; Offset += Chunk) { + Chunk = FILE_COPY_CHUNK; + + Status = EfiRead(File1, Buffer1, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("File 1 read error\n"); + goto Exit; + } + + Status = EfiRead(File2, Buffer2, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("File 2 read error\n"); + goto Exit; + } + + if (CompareMem(Buffer1, Buffer2, Chunk) != 0) { + AsciiPrint("Files differ.\n"); + goto Exit; + }; + } + + // Any left over? + if (Offset < Size1) { + Chunk = Size1 - Offset; + + Status = EfiRead(File1, Buffer1, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("File 1 read error\n"); + goto Exit; + } + + Status = EfiRead(File2, Buffer2, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("File 2 read error\n"); + goto Exit; + } + } + + if (CompareMem(Buffer1, Buffer2, Chunk) != 0) { + AsciiPrint("Files differ.\n"); + } else { + AsciiPrint("Files are identical.\n"); + } + +Exit: + if (File1 != NULL) { + Status = EfiClose(File1); + if (EFI_ERROR(Status)) { + AsciiPrint("File 1 close error %r\n", Status); + } + } + + if (File2 != NULL) { + Status = EfiClose(File2); + if (EFI_ERROR(Status)) { + AsciiPrint("File 2 close error %r\n", Status); + } + } + + if (Buffer1 != NULL) { + FreePool(Buffer1); + } + + if (Buffer2 != NULL) { + FreePool(Buffer2); + } + + return Status; +} + +GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDeviceTemplate[] = +{ + { + "connect", + "[d]; Connect all EFI devices. d means disconnect", + NULL, + EblConnectCmd + }, + { + "device", + "; Show information about boot devices", + NULL, + EblDeviceCmd + }, + { + "go", + " dev:path loadaddress entrypoint args; load to given address and jump in", + NULL, + EblGoCmd + }, + { + "loadfv", + " devname; Load PI FV from device", + NULL, + EblLoadFvCmd + }, + { + "start", + " path; EFI Boot Device:filepath. fs1:\\EFI\\BOOT.EFI", + NULL, + EblStartCmd + }, + { + "memmap", + "; dump EFI memory map", + NULL, + EblMemMapCmd + }, + { + "cp", + " file1 file2; copy file", + NULL, + EblFileCopyCmd + }, + { + "diff", + " file1 file2; compare files", + NULL, + EblFileDiffCmd + } +}; + + +/** + Initialize the commands in this in this file +**/ + +VOID +EblInitializeDeviceCmd ( + VOID + ) +{ + EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS); + EblAddCommands (mCmdDeviceTemplate, sizeof (mCmdDeviceTemplate)/sizeof (EBL_COMMAND_TABLE)); +} + diff --git a/EmbeddedPkg/Ebl/Hob.c b/EmbeddedPkg/Ebl/Hob.c new file mode 100644 index 0000000000..c541f66968 --- /dev/null +++ b/EmbeddedPkg/Ebl/Hob.c @@ -0,0 +1,232 @@ +/** @file + Hob command for EBL (Embedded Boot Loader) + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: Hob.c + + Search/Replace Dir with the name of your new command + + Boot Mode: + ========== + BOOT_WITH_FULL_CONFIGURATION 0x00 + BOOT_WITH_MINIMAL_CONFIGURATION 0x01 + BOOT_ASSUMING_NO_CONFIGURATION_CHANGES 0x02 + BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS 0x03 + BOOT_WITH_DEFAULT_SETTINGS 0x04 + BOOT_ON_S4_RESUME 0x05 + BOOT_ON_S5_RESUME 0x06 + BOOT_ON_S2_RESUME 0x10 + BOOT_ON_S3_RESUME 0x11 + BOOT_ON_FLASH_UPDATE 0x12 + BOOT_IN_RECOVERY_MODE 0x20 + BOOT_IN_RECOVERY_MODE_MASK 0x40 + BOOT_SPECIAL_MASK 0x80 + + Mem Alloc HOB Type: + =================== + typedef enum { + EfiReservedMemoryType = 0x00 + EfiLoaderCode = 0x01 + EfiLoaderData = 0x02 + EfiBootServicesCode = 0x03 + EfiBootServicesData = 0x04 + EfiRuntimeServicesCode = 0x05 + EfiRuntimeServicesData = 0x06 + EfiConventionalMemory = 0x07 + EfiUnusableMemory = 0x08 + EfiACPIReclaimMemory = 0x09 + EfiACPIMemoryNVS = 0x0a + EfiMemoryMappedIO = 0x0b + EfiMemoryMappedIOPortSpace = 0x0c + EfiPalCode = 0x0d + EfiMaxMemoryType = 0x0e + } EFI_MEMORY_TYPE; + + Resource Hob Tye: + ================= + EFI_RESOURCE_SYSTEM_MEMORY 0 + EFI_RESOURCE_MEMORY_MAPPED_IO 1 + EFI_RESOURCE_IO 2 + EFI_RESOURCE_FIRMWARE_DEVICE 3 + EFI_RESOURCE_MEMORY_MAPPED_IO_PORT 4 + EFI_RESOURCE_MEMORY_RESERVED 5 + EFI_RESOURCE_IO_RESERVED 6 + EFI_RESOURCE_MAX_MEMORY_TYPE 7 + + Resource Hob Attribute (last thing printed): + ============================================ + EFI_RESOURCE_ATTRIBUTE_PRESENT 0x00000001 + EFI_RESOURCE_ATTRIBUTE_INITIALIZED 0x00000002 + EFI_RESOURCE_ATTRIBUTE_TESTED 0x00000004 + EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC 0x00000008 + EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC 0x00000010 + EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 0x00000020 + EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 0x00000040 + EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED 0x00000080 + EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED 0x00000100 + EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED 0x00000200 + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE 0x00000400 + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE 0x00000800 + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE 0x00001000 + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE 0x00002000 + EFI_RESOURCE_ATTRIBUTE_16_BIT_IO 0x00004000 + EFI_RESOURCE_ATTRIBUTE_32_BIT_IO 0x00008000 + EFI_RESOURCE_ATTRIBUTE_64_BIT_IO 0x00010000 + EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED 0x00020000 + +**/ + +#include "Ebl.h" +// BugBug: Autogen does not allow this to be included currently +//#include + +GLOBAL_REMOVE_IF_UNREFERENCED char *mHobResourceType[] = { + "Memory ", + "MMIO ", + "IO ", + "Firmware ", + "MMIO Port ", + "Reserved ", + "IO Reserved", + "Illegal " +}; + + +/** + Dump out the HOBs in the system. HOBs are defined in the PI specificaiton + and they are used to hand off information from PEI to DXE. + + Argv[0] - "hob" + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblHobCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + UINTN CurrentRow; + EFI_PEI_HOB_POINTERS Hob; + EFI_MEMORY_TYPE_INFORMATION *EfiMemoryTypeInformation; + UINTN Index; + + CurrentRow = 0; + for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) { + if (Hob.Header->HobType == EFI_HOB_TYPE_HANDOFF) { + AsciiPrint ("PHIT HOB Ver %x Boot Mode %02x Top %lx Bottom %lx\n", + Hob.HandoffInformationTable->Version, + Hob.HandoffInformationTable->BootMode, + Hob.HandoffInformationTable->EfiMemoryTop, + Hob.HandoffInformationTable->EfiMemoryBottom + ); + + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { + return EFI_SUCCESS; + } + + AsciiPrint (" Free Top %lx Free Bottom %lx End Of HOB %lx\n", + Hob.HandoffInformationTable->EfiFreeMemoryTop, + Hob.HandoffInformationTable->EfiFreeMemoryBottom, + Hob.HandoffInformationTable->EfiEndOfHobList + ); + + } else if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) { + // mod(%) on array index is just to prevent buffer overrun + AsciiPrint ("Mem Alloc HOB %a %g %08lx:%lx\n", + (Hob.MemoryAllocation->AllocDescriptor.MemoryType < EfiMaxMemoryType) ? gMemMapType[Hob.MemoryAllocation->AllocDescriptor.MemoryType] : "ILLEGAL TYPE", + &Hob.MemoryAllocation->AllocDescriptor.Name, + Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, + Hob.MemoryAllocation->AllocDescriptor.MemoryLength + ); + if (CompareGuid (&gEfiHobMemoryAllocModuleGuid, &Hob.MemoryAllocation->AllocDescriptor.Name)) { + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { + return EFI_SUCCESS; + } + AsciiPrint (" Module Name %g EntryPoint %lx\n", &Hob.MemoryAllocationModule->ModuleName, Hob.MemoryAllocationModule->EntryPoint); + } + } else if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + AsciiPrint ("Resource HOB %a %g %08lx:%lx\n Attributes: %08x\n", + (Hob.ResourceDescriptor->ResourceType < EFI_RESOURCE_MAX_MEMORY_TYPE) ? mHobResourceType[Hob.ResourceDescriptor->ResourceType] : mHobResourceType[EFI_RESOURCE_MAX_MEMORY_TYPE], + &Hob.ResourceDescriptor->Owner, + Hob.ResourceDescriptor->PhysicalStart, + Hob.ResourceDescriptor->ResourceLength, + Hob.ResourceDescriptor->ResourceAttribute + ); + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { + return EFI_SUCCESS; + } + } else if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION) { + AsciiPrint ("GUID HOB %g\n", &Hob.Guid->Name); + if (CompareGuid (&gEfiMemoryTypeInformationGuid, &Hob.Guid->Name)) { + EfiMemoryTypeInformation = GET_GUID_HOB_DATA (Hob.Guid); + for (Index = 0; Index < (GET_GUID_HOB_DATA_SIZE (Hob.Guid)/sizeof (EFI_MEMORY_TYPE_INFORMATION)); Index++, EfiMemoryTypeInformation++) { + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { + return EFI_SUCCESS; + } + AsciiPrint (" %a 0x%08x\n", + (EfiMemoryTypeInformation->Type < EfiMaxMemoryType) ? gMemMapType[EfiMemoryTypeInformation->Type] : "END ", + EfiMemoryTypeInformation->NumberOfPages + ); + } + } + } else if (Hob.Header->HobType == EFI_HOB_TYPE_FV) { + AsciiPrint ("FV HOB %08lx:%08lx\n", Hob.FirmwareVolume->BaseAddress, Hob.FirmwareVolume->Length); + } else if (Hob.Header->HobType == EFI_HOB_TYPE_CPU) { + AsciiPrint ("CPU HOB: Mem %x IO %x\n", Hob.Cpu->SizeOfMemorySpace, Hob.Cpu->SizeOfIoSpace); + } else if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_POOL) { + AsciiPrint ("Mem Pool HOB:\n"); +/* Not in PI + } else if (Hob.Header->HobType == EFI_HOB_TYPE_CV) { + AsciiPrint ("CV HOB: %08lx:%08lx\n", Hob.CapsuleVolume->BaseAddress, Hob.CapsuleVolume->Length); + */ + } + + if (EblAnyKeyToContinueQtoQuit (&CurrentRow, FALSE)) { + break; + } + } + + return EFI_SUCCESS; +} + + +GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdHobTemplate[] = +{ + { + "hob", + "; dump HOBs", + NULL, + EblHobCmd + } +}; + + +/** + Initialize the commands in this in this file +**/ +VOID +EblInitializeHobCmd ( + VOID + ) +{ + if (FeaturePcdGet (PcdEmbeddedHobCmd)) { + EblAddCommands (mCmdHobTemplate, sizeof (mCmdHobTemplate)/sizeof (EBL_COMMAND_TABLE)); + } +} + diff --git a/EmbeddedPkg/Ebl/HwDebug.c b/EmbeddedPkg/Ebl/HwDebug.c new file mode 100644 index 0000000000..6ffbaf1170 --- /dev/null +++ b/EmbeddedPkg/Ebl/HwDebug.c @@ -0,0 +1,342 @@ +/** @file + Basic command line parser for EBL (Embedded Boot Loader) + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: HwDebug.c + + Commands useful for debugging hardware. + +**/ + +#include "Ebl.h" + + +/** + Dump memory + + Argv[0] - "md" + Argv[1] - Hex Address to dump + Argv[2] - Number of hex bytes to dump (0x20 is default) + Argv[3] - [1|2|4|8] byte width of the dump + + md 0x123445678 50 4 ; Dump 0x50 4 byte quantities starting at 0x123445678 + md 0x123445678 40 ; Dump 0x40 1 byte quantities starting at 0x123445678 + md 0x123445678 ; Dump 0x20 1 byte quantities starting at 0x123445678 + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblMdCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + STATIC UINT8 *Address = NULL; + STATIC UINTN Length = 0x20; + STATIC UINTN Width = 1; + + switch (Argc) + { + case 4: + Width = AsciiStrHexToUintn(Argv[3]); + case 3: + Length = AsciiStrHexToUintn(Argv[2]); + case 2: + Address = (UINT8 *)AsciiStrHexToUintn(Argv[1]); + default: + break; + } + + OutputData(Address, Length, Width, (UINTN)Address); + + Address += Length; + + return EFI_SUCCESS; +} + + +/** + Fill Memory with data + + Argv[0] - "mfill" + Argv[1] - Hex Address to fill + Argv[2] - Data to write (0x00 is default) + Argv[3] - Number of units to dump. + Argv[4] - [1|2|4|8] byte width of the dump + + mf 0x123445678 aa 1 100 ; Start at 0x123445678 and write aa (1 byte) to the next 100 bytes + mf 0x123445678 aa 4 100 ; Start at 0x123445678 and write aa (4 byte) to the next 400 bytes + mf 0x123445678 aa ; Start at 0x123445678 and write aa (4 byte) to the next 1 byte + mf 0x123445678 ; Start at 0x123445678 and write 00 (4 byte) to the next 1 byte + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblMfillCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + UINTN Address; + UINTN EndAddress; + UINT32 Data; + UINTN Length; + UINTN Width; + + if (Argc < 2) { + return EFI_INVALID_PARAMETER; + } + + Address = AsciiStrHexToUintn (Argv[1]); + Data = (Argc > 2) ? (UINT32)AsciiStrHexToUintn (Argv[2]) : 0; + Width = (Argc > 3) ? AsciiStrHexToUintn (Argv[3]) : 4; + Length = (Argc > 4) ? AsciiStrHexToUintn (Argv[4]) : 1; + + for (EndAddress = Address + (Length * Width); Address < EndAddress; Address += Width) { + if (Width == 4) { + MmioWrite32 (Address, Data); + } else if (Width == 2) { + MmioWrite32 (Address, (UINT16)Data); + } else { + MmioWrite32 (Address, (UINT8)Data); + } + } + + return EFI_SUCCESS; +} + + +// +// Strings for PCI Class code [2] +// +CHAR8 *gPciDevClass[] = { + "Old Device ", + "Mass storage ", + "Network ", + "Display ", + "Multimedia ", + "Memory controller ", + "Bridge device ", + "simple communications ", + "base system peripherals", + "Input devices ", + "Docking stations ", + "Processors ", + "serial bus ", +}; + + +CHAR8 *gPciSerialClassCodes[] = { + "Mass storage ", + "Firewire ", + "ACCESS bus ", + "SSA ", + "USB " +}; + + +/** + PCI Dump + + Argv[0] - "pci" + Argv[1] - bus + Argv[2] - dev + Argv[3] - func + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblPciCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *Pci; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Seg; + UINTN Bus; + UINTN Dev; + UINTN Func; + UINTN BusArg; + UINTN DevArg; + UINTN FuncArg; + UINTN Index; + UINTN Count; + PCI_TYPE_GENERIC PciHeader; + PCI_TYPE_GENERIC *Header; + PCI_BRIDGE_CONTROL_REGISTER *Bridge; + PCI_DEVICE_HEADER_TYPE_REGION *Device; + PCI_DEVICE_INDEPENDENT_REGION *Hdr; + CHAR8 *Str; + UINTN ThisBus; + + + BusArg = (Argc > 1) ? AsciiStrDecimalToUintn (Argv[1]) : 0; + DevArg = (Argc > 2) ? AsciiStrDecimalToUintn (Argv[2]) : 0; + FuncArg = (Argc > 3) ? AsciiStrDecimalToUintn (Argv[3]) : 0; + + Header = &PciHeader; + + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPciIoProtocolGuid, NULL, &HandleCount, &HandleBuffer); + if (EFI_ERROR (Status)) { + AsciiPrint ("No PCI devices found in the system\n"); + return EFI_SUCCESS; + } + + if (Argc == 1) { + // Dump all PCI devices + AsciiPrint ("BusDevFun VendorId DeviceId Device Class Sub-Class\n"); + AsciiPrint ("_____________________________________________________________"); + for (ThisBus = 0; ThisBus <= PCI_MAX_BUS; ThisBus++) { + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&Pci); + if (!EFI_ERROR (Status)) { + Pci->GetLocation (Pci, &Seg, &Bus, &Dev, &Func); + if (ThisBus != Bus) { + continue; + } + AsciiPrint ("\n%03d.%02d.%02d", Bus, Dev, Func); + Status = Pci->Pci.Read (Pci, EfiPciIoWidthUint32, 0, sizeof (PciHeader)/sizeof (UINT32), &PciHeader); + if (!EFI_ERROR (Status)) { + Hdr = &PciHeader.Bridge.Hdr; + + if (Hdr->ClassCode[2] < sizeof (gPciDevClass)/sizeof (VOID *)) { + Str = gPciDevClass[Hdr->ClassCode[2]]; + if (Hdr->ClassCode[2] == PCI_CLASS_SERIAL) { + if (Hdr->ClassCode[1] < sizeof (gPciSerialClassCodes)/sizeof (VOID *)) { + // print out Firewire or USB inplace of Serial Bus controllers + Str = gPciSerialClassCodes[Hdr->ClassCode[1]]; + } + } + } else { + Str = "Unknown device "; + } + AsciiPrint (" 0x%04x 0x%04x %a 0x%02x", Hdr->VendorId, Hdr->DeviceId, Str, Hdr->ClassCode[1]); + } + if (Seg != 0) { + // Only print Segment if it is non zero. If you only have one PCI segment it is + // redundent to print it out + AsciiPrint (" Seg:%d", Seg); + } + } + } + } + AsciiPrint ("\n"); + } else { + // Dump specific PCI device + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **)&Pci); + if (!EFI_ERROR (Status)) { + Pci->GetLocation (Pci, &Seg, &Bus, &Dev, &Func); + if ((Bus == BusArg) && (Dev == DevArg) && (Func == FuncArg)) { + // Only print Segment if it is non zero. If you only have one PCI segment it is + // redundent to print it out + if (Seg != 0) { + AsciiPrint ("Seg:%d ", Seg); + } + AsciiPrint ("Bus:%d Dev:%d Func:%d ", Bus, Dev, Func); + + Status = Pci->Pci.Read (Pci, EfiPciIoWidthUint32, 0, sizeof (PciHeader)/sizeof (UINT32), Header); + if (!EFI_ERROR (Status)) { + Hdr = &PciHeader.Bridge.Hdr; + if (IS_PCI_BRIDGE (&PciHeader.Bridge)) { + Bridge = &PciHeader.Bridge.Bridge; + AsciiPrint ( + "PCI Bridge. Bus Primary %d Secondary %d Subordinate %d\n", + Bridge->PrimaryBus, Bridge->SecondaryBus, Bridge->SubordinateBus + ); + AsciiPrint (" Bar 0: 0x%08x Bar 1: 0x%08x\n", Bridge->Bar[0], Bridge->Bar[1]); + } else { + Device = &PciHeader.Device.Device; + AsciiPrint ( + "VendorId: 0x%04x DeviceId: 0x%04x SubSusVendorId: 0x%04x SubSysDeviceId: 0x%04x\n", + Hdr->VendorId, Hdr->DeviceId, Device->SubsystemVendorID, Device->SubsystemID + ); + AsciiPrint (" Class Code: 0x%02x 0x%02x 0x%02x\n", Hdr->ClassCode[2], Hdr->ClassCode[1], Hdr->ClassCode[0]); + for (Count = 0; Count < 6; Count++) { + AsciiPrint (" Bar %d: 0x%08x\n", Count, Device->Bar[Count]); + } + } + } + + AsciiPrint ("\n"); + break; + } + } + } + } + + FreePool (HandleBuffer); + return EFI_SUCCESS; +} + + +GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdPciDebugTemplate[] = { + "pci", + " [bus] [dev] [func]; Dump PCI", + NULL, + EblPciCmd +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdHwDebugTemplate[] = +{ + { + "md", + " [Addr] [Len] [1|2|4]; Memory Dump from Addr Len bytes", + NULL, + EblMdCmd + }, + { + "mfill", + " Addr Len [data] [1|2|4]; Memory Fill Addr Len*(1|2|4) bytes of data(0)", + NULL, + EblMfillCmd + }, +}; + + + +/** + Initialize the commands in this in this file +**/ +VOID +EblInitializemdHwDebugCmds ( + VOID + ) +{ + if (FeaturePcdGet (PcdEmbeddedHwDebugCmd)) { + EblAddCommands (mCmdHwDebugTemplate, sizeof (mCmdHwDebugTemplate)/sizeof (EBL_COMMAND_TABLE)); + } + if (FeaturePcdGet (PcdEmbeddedPciDebugCmd)) { + EblAddCommands (mCmdPciDebugTemplate, sizeof (mCmdPciDebugTemplate)/sizeof (EBL_COMMAND_TABLE)); + } +} + diff --git a/EmbeddedPkg/Ebl/HwIoDebug.c b/EmbeddedPkg/Ebl/HwIoDebug.c new file mode 100644 index 0000000000..2d23e7c936 --- /dev/null +++ b/EmbeddedPkg/Ebl/HwIoDebug.c @@ -0,0 +1,153 @@ +/** @file + Hardware IO based debug commands + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Commands useful for debugging hardware. IO commands seperated out as not all + processor architectures support the IO command. + +**/ + +#include "Ebl.h" + + + +/** + Read from IO space + + Argv[0] - "ioread" + Argv[1] - Hex IO address + Argv[2] - IO Width [1|2|4] with a default of 1 + + ior 0x3f8 4 ;Do a 32-bit IO Read from 0x3f8 + ior 0x3f8 1 ;Do a 8-bit IO Read from 0x3f8 + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblIoReadCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + UINTN Width; + UINTN Port; + UINTN Data; + + if (Argc < 2) { + return EFI_INVALID_PARAMETER; + } + + Port = AsciiStrHexToUintn (Argv[1]); + Width = (Argc > 2) ? AsciiStrHexToUintn (Argv[2]) : 1; + + if (Width == 1) { + Data = IoRead8 (Port); + } else if (Width == 2) { + Data = IoRead16 (Port); + } else if (Width == 4) { + Data = IoRead32 (Port); + } else { + return EFI_INVALID_PARAMETER; + } + + AsciiPrint ("0x%04x = 0x%x", Port, Data); + + return EFI_SUCCESS; +} + + +/** + Write to IO space + + Argv[0] - "iowrite" + Argv[1] - Hex IO address + Argv[2] - Hex data to write + Argv[3] - IO Width [1|2|4] with a default of 1 + + iow 0x3f8 af 4 ;Do a 32-bit IO write of af to 0x3f8 + iow 0x3f8 af ;Do an 8-bit IO write of af to 0x3f8 + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblIoWriteCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + UINTN Width; + UINTN Port; + UINTN Data; + + if (Argc < 3) { + return EFI_INVALID_PARAMETER; + } + + Port = AsciiStrHexToUintn (Argv[1]); + Data = AsciiStrHexToUintn (Argv[2]); + Width = (Argc > 3) ? AsciiStrHexToUintn (Argv[3]) : 1; + + if (Width == 1) { + IoWrite8 (Port, (UINT8)Data); + } else if (Width == 2) { + IoWrite16 (Port, (UINT16)Data); + } else if (Width == 4) { + IoWrite32 (Port, (UINT32)Data); + } else { + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + + +GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdHwIoDebugTemplate[] = +{ + { + "ioread", + " Port [1|2|4]; IO read of width[1] byte(s) from Port", + NULL, + EblIoReadCmd + }, + { + "iowrite", + " Port Data [1|2|4]; IO write Data of width[1] byte(s) to Port", + NULL, + EblIoWriteCmd + } +}; + + + +/** + Initialize the commands in this in this file +**/ +VOID +EblInitializemdHwIoDebugCmds ( + VOID + ) +{ + if (FeaturePcdGet (PcdEmbeddedIoEnable)) { + EblAddCommands (mCmdHwIoDebugTemplate, sizeof (mCmdHwIoDebugTemplate)/sizeof (EBL_COMMAND_TABLE)); + } +} + diff --git a/EmbeddedPkg/Ebl/Main.c b/EmbeddedPkg/Ebl/Main.c new file mode 100644 index 0000000000..5d1a37916f --- /dev/null +++ b/EmbeddedPkg/Ebl/Main.c @@ -0,0 +1,616 @@ +/** @file + Basic command line parser for EBL (Embedded Boot Loader) + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +#include "Ebl.h" + +// Globals for command history processing +INTN mCmdHistoryEnd = -1; +INTN mCmdHistoryStart = -1; +INTN mCmdHistoryCurrent = -1; +CHAR8 mCmdHistory[MAX_CMD_HISTORY][MAX_CMD_LINE]; +CHAR8 *mCmdBlank = ""; + +// Globals to remember current screen geometry +UINTN gScreenColumns; +UINTN gScreenRows; + +// Global to turn on/off breaking commands with prompts before they scroll the screen +BOOLEAN gPageBreak = TRUE; + +VOID +RingBufferIncrement ( + IN INTN *Value + ) +{ + *Value = *Value + 1; + + if (*Value >= MAX_CMD_HISTORY) { + *Value = 0; + } +} + +VOID +RingBufferDecrement ( + IN INTN *Value + ) +{ + *Value = *Value - 1; + + if (*Value < 0) { + *Value = MAX_CMD_HISTORY - 1; + } +} + +/** + Save this command in the circular history buffer. Older commands are + overwritten with newer commands. + + @param Cmd Command line to archive the history of. + + @return None + +**/ +VOID +SetCmdHistory ( + IN CHAR8 *Cmd + ) +{ + // Don't bother adding empty commands to the list + if (AsciiStrLen(Cmd) != 0) { + + // First entry + if (mCmdHistoryStart == -1) { + mCmdHistoryStart = 0; + mCmdHistoryEnd = 0; + } else { + // Record the new command at the next index + RingBufferIncrement(&mCmdHistoryStart); + + // If the next index runs into the end index, shuffle end back by one + if (mCmdHistoryStart == mCmdHistoryEnd) { + RingBufferIncrement(&mCmdHistoryEnd); + } + } + + // Copy the new command line into the ring buffer + AsciiStrnCpy(&mCmdHistory[mCmdHistoryStart][0], Cmd, MAX_CMD_LINE); + } + + // Reset the command history for the next up arrow press + mCmdHistoryCurrent = mCmdHistoryStart; +} + + +/** + Retreave data from the Command History buffer. Direction maps into up arrow + an down arrow on the command line + + @param Direction Command forward or back + + @return The Command history based on the Direction + +**/ +CHAR8 * +GetCmdHistory ( + IN UINT16 Direction + ) +{ + CHAR8 *HistoricalCommand = NULL; + + // No history yet? + if (mCmdHistoryCurrent == -1) { + HistoricalCommand = mCmdBlank; + goto Exit; + } + + if (Direction == SCAN_UP) { + HistoricalCommand = &mCmdHistory[mCmdHistoryCurrent][0]; + + // if we just echoed the last command, hang out there, don't wrap around + if (mCmdHistoryCurrent == mCmdHistoryEnd) { + goto Exit; + } + + // otherwise, back up by one + RingBufferDecrement(&mCmdHistoryCurrent); + + } else if (Direction == SCAN_DOWN) { + + // if we last echoed the start command, put a blank prompt out + if (mCmdHistoryCurrent == mCmdHistoryStart) { + HistoricalCommand = mCmdBlank; + goto Exit; + } + + // otherwise increment the current pointer and return that command + RingBufferIncrement(&mCmdHistoryCurrent); + RingBufferIncrement(&mCmdHistoryCurrent); + + HistoricalCommand = &mCmdHistory[mCmdHistoryCurrent][0]; + RingBufferDecrement(&mCmdHistoryCurrent); + } + +Exit: + return HistoricalCommand; +} + + +/** + Parse the CmdLine and break it up into Argc (arg count) and Argv (array of + pointers to each argument). The Cmd buffer is altered and seperators are + converted to string terminators. This allows Argv to point into CmdLine. + A CmdLine can support multiple commands. The next command in the command line + is returned if it exists. + + @param CmdLine String to parse for a set of commands + @param Argc Returns the number of arguments in the CmdLine current command + @param Argv Argc pointers to each string in CmdLine + + @return Next Command in the command line or NULL if non exists +**/ +CHAR8 * +ParseArguments ( + IN CHAR8 *CmdLine, + OUT UINTN *Argc, + OUT CHAR8 **Argv + ) +{ + UINTN Arg; + CHAR8 *Char; + BOOLEAN LookingForArg; + BOOLEAN InQuote; + + *Argc = 0; + if (AsciiStrLen (CmdLine) == 0) { + return NULL; + } + + // Walk a single command line. A CMD_SEPERATOR allows mult commands on a single line + InQuote = FALSE; + LookingForArg = TRUE; + for (Char = CmdLine, Arg = 0; *Char != '\0'; Char++) { + if (!InQuote && *Char == CMD_SEPERATOR) { + break; + } + + // Perform any text coversion here + if (*Char == '\t') { + // TAB to space + *Char = ' '; + } + + if (LookingForArg) { + // Look for the beging of an Argv[] entry + if (*Char == '"') { + Argv[Arg++] = ++Char; + LookingForArg = FALSE; + InQuote = TRUE; + } else if (*Char != ' ') { + Argv[Arg++] = Char; + LookingForArg = FALSE; + } + } else { + // Looking for the terminator of an Argv[] entry + if ((InQuote && (*Char == '"')) || (!InQuote && (*Char == ' '))) { + *Char = '\0'; + LookingForArg = TRUE; + } + } + } + + *Argc = Arg; + + if (*Char == CMD_SEPERATOR) { + // Replace the command delimeter with null and return pointer to next command line + *Char = '\0'; + return ++Char; + } + + return NULL; +} + + +/** + Return a keypress or optionally timeout if a timeout value was passed in. + An optional callback funciton is called evey second when waiting for a + timeout. + + @param Key EFI Key information returned + @param TimeoutInSec Number of seconds to wait to timeout + @param CallBack Callback called every second during the timeout wait + + @return EFI_SUCCESS Key was returned + @return EFI_TIMEOUT If the TimoutInSec expired + +**/ +EFI_STATUS +EblGetCharKey ( + IN OUT EFI_INPUT_KEY *Key, + IN UINTN TimeoutInSec, + IN EBL_GET_CHAR_CALL_BACK CallBack OPTIONAL + ) +{ + EFI_STATUS Status; + UINTN WaitCount; + UINTN WaitIndex; + EFI_EVENT WaitList[2]; + + WaitCount = 1; + WaitList[0] = gST->ConIn->WaitForKey; + if (TimeoutInSec != 0) { + // Create a time event for 1 sec duration if we have a timeout + gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &WaitList[1]); + gBS->SetTimer (WaitList[1], TimerPeriodic, EFI_SET_TIMER_TO_SECOND); + WaitCount++; + } + + for (;;) { + Status = gBS->WaitForEvent (WaitCount, WaitList, &WaitIndex); + ASSERT_EFI_ERROR (Status); + + switch (WaitIndex) { + case 0: + // Key event signaled + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key); + if (!EFI_ERROR (Status)) { + if (WaitCount == 2) { + gBS->CloseEvent (WaitList[1]); + } + return EFI_SUCCESS; + } + break; + + case 1: + // Periodic 1 sec timer signaled + TimeoutInSec--; + if (CallBack != NULL) { + // Call the users callback function if registered + CallBack (TimeoutInSec); + } + if (TimeoutInSec == 0) { + gBS->CloseEvent (WaitList[1]); + return EFI_TIMEOUT; + } + break; + default: + ASSERT (FALSE); + } + } +} + + +/** + This routine is used prevent command output data from scrolling off the end + of the screen. The global gPageBreak is used to turn on or off this feature. + If the CurrentRow is near the end of the screen pause and print out a prompt + If the use hits Q to quit return TRUE else for any other key return FALSE. + PrefixNewline is used to figure out if a newline is needed before the prompt + string. This depends on the last print done before calling this function. + CurrentRow is updated by one on a call or set back to zero if a prompt is + needed. + + @param CurrentRow Used to figure out if its the end of the page and updated + @param PrefixNewline Did previous print issue a newline + + @return TRUE if Q was hit to quit, FALSE in all other cases. + +**/ +BOOLEAN +EblAnyKeyToContinueQtoQuit ( + IN UINTN *CurrentRow, + IN BOOLEAN PrefixNewline + ) +{ + EFI_INPUT_KEY InputKey; + + if (!gPageBreak) { + // global disable for this feature + return FALSE; + } + + if (*CurrentRow >= (gScreenRows - 2)) { + if (PrefixNewline) { + AsciiPrint ("\n"); + } + AsciiPrint ("Any key to continue (Q to quit): "); + EblGetCharKey (&InputKey, 0, NULL); + AsciiPrint ("\n"); + + // Time to promt to stop the screen. We have to leave space for the prompt string + *CurrentRow = 0; + if (InputKey.UnicodeChar == 'Q' || InputKey.UnicodeChar == 'q') { + return TRUE; + } + } else { + *CurrentRow += 1; + } + + return FALSE; +} + + +/** + Set the text color of the EFI Console. If a zero is passed in reset to + default text/background color. + + @param Attribute For text and background color + +**/ +VOID +EblSetTextColor ( + UINTN Attribute + ) +{ + if (Attribute == 0) { + // Set the text color back to default + Attribute = (UINTN)PcdGet32 (PcdEmbeddedDefaultTextColor); + } + + gST->ConOut->SetAttribute (gST->ConOut, Attribute); +} + + +/** + Collect the keyboard input for a cmd line. Carage Return, New Line, or ESC + terminates the command line. You can edit the command line via left arrow, + delete and backspace and they all back up and erase the command line. + No edit of commnad line is possible without deletion at this time! + The up arrow and down arrow fill Cmd with information from the history + buffer. + + @param Cmd Command line to return + @param CmdMaxSize Maximum size of Cmd + + @return The Status of EblGetCharKey() + +**/ +EFI_STATUS +GetCmd ( + IN OUT CHAR8 *Cmd, + IN UINTN CmdMaxSize + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN Index2; + CHAR8 Char; + CHAR8 *History; + EFI_INPUT_KEY Key; + + for (Index = 0; Index < CmdMaxSize - 1;) { + Status = EblGetCharKey (&Key, 0, NULL); + if (EFI_ERROR (Status)) { + Cmd[Index] = '\0'; + AsciiPrint ("\n"); + return Status; + } + + Char = (CHAR8)Key.UnicodeChar; + if ((Char == '\n') || (Char == '\r') || (Char == 0x7f)) { + Cmd[Index] = '\0'; + if (FixedPcdGetBool(PcdEmbeddedShellCharacterEcho) == TRUE) { + AsciiPrint ("\n\r"); + } + return EFI_SUCCESS; + } else if ((Char == '\b') || (Key.ScanCode == SCAN_LEFT) || (Key.ScanCode == SCAN_DELETE)){ + if (Index != 0) { + Index--; + // + // Update the display + // + AsciiPrint ("\b \b"); + } + } else if ((Key.ScanCode == SCAN_UP) || Key.ScanCode == SCAN_DOWN) { + History = GetCmdHistory (Key.ScanCode); + // + // Clear display line + // + for (Index2 = 0; Index2 < Index; Index2++) { + AsciiPrint ("\b \b"); + } + AsciiPrint (History); + Index = AsciiStrLen (History); + AsciiStrnCpy (Cmd, History, CmdMaxSize); + } else { + Cmd[Index++] = Char; + if (FixedPcdGetBool(PcdEmbeddedShellCharacterEcho) == TRUE) { + AsciiPrint ("%c", Char); + } + } + } + + return EFI_SUCCESS; +} + + +/** + Print the boot up banner for the EBL. +**/ +VOID +EblPrintStartupBanner ( + VOID + ) +{ + AsciiPrint ("Embedded Boot Loader ("); + EblSetTextColor (EFI_YELLOW); + AsciiPrint ("EBL"); + EblSetTextColor (0); + AsciiPrint (") prototype. Built at %a on %a\n",__TIME__, __DATE__); + AsciiPrint ("THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN 'AS IS' BASIS,\nWITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\n"); + AsciiPrint ("Please send feedback to dev@edk2.tianocore.org\n"); +} + + +/** + Print the prompt for the EBL. +**/ +VOID +EblPrompt ( + VOID + ) +{ + EblSetTextColor (EFI_YELLOW); + AsciiPrint ((CHAR8 *)PcdGetPtr (PcdEmbeddedPrompt)); + EblSetTextColor (0); + AsciiPrint ("%a", ">"); +} + + + +/** + Parse a command line and execute the commands. The ; seperator allows + multiple commands for each command line. Stop processing if one of the + commands returns an error. + + @param CmdLine Command Line to process. + @param MaxCmdLineSize MaxSize of the Command line + + @return EFI status of the Command + +**/ +EFI_STATUS +ProcessCmdLine ( + IN CHAR8 *CmdLine, + IN UINTN MaxCmdLineSize + ) +{ + EFI_STATUS Status; + EBL_COMMAND_TABLE *Cmd; + CHAR8 *Ptr; + UINTN Argc; + CHAR8 *Argv[MAX_ARGS]; + + // Parse the command line. The loop processes commands seperated by ; + for (Ptr = CmdLine, Status = EFI_SUCCESS; Ptr != NULL;) { + Ptr = ParseArguments (Ptr, &Argc, Argv); + if (Argc != 0) { + Cmd = EblGetCommand (Argv[0]); + if (Cmd != NULL) { + // Execute the Command! + Status = Cmd->Command (Argc, Argv); + if (Status == EFI_ABORTED) { + // exit command so lets exit + break; + } else if (Status == EFI_TIMEOUT) { + // pause command got imput so don't process any more cmd on this cmd line + break; + } else if (EFI_ERROR (Status)) { + AsciiPrint ("%a returned %r error\n", Cmd->Name, Status); + // if any command fails stop processing CmdLine + break; + } + } + } + } + + return Status; +} + + + +/** + Embedded Boot Loader (EBL) - A simple EFI command line application for embedded + devices. PcdEmbeddedAutomaticBootCommand is a complied in commnad line that + gets executed automatically. The ; seperator allows multiple commands + for each command line. + + @param ImageHandle EFI ImageHandle for this application. + @param SystemTable EFI system table + + @return EFI status of the applicaiton + +**/ +EFI_STATUS +EFIAPI +EdkBootLoaderEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + CHAR8 CmdLine[MAX_CMD_LINE]; + CHAR16 *CommandLineVariable = NULL; + CHAR16 *CommandLineVariableName = L"default-cmdline"; + UINTN CommandLineVariableSize = 0; + EFI_GUID VendorGuid; + + // Initialize tables of commnads + EblInitializeCmdTable (); + EblInitializeDeviceCmd (); + EblInitializemdHwDebugCmds (); + EblInitializemdHwIoDebugCmds (); + EblInitializeDirCmd (); + EblInitializeHobCmd (); + EblInitializeScriptCmd (); + EblInitializeExternalCmd (); + EblInitializeNetworkCmd(); + + if (FeaturePcdGet (PcdEmbeddedMacBoot)) { + // A MAC will boot in graphics mode, so turn it back to text here + // This protocol was removed from edk2. It is only an edk thing. We need to make our own copy. + // DisableQuietBoot (); + + // Enable the biggest output screen size possible + gST->ConOut->SetMode (gST->ConOut, (UINTN)gST->ConOut->Mode->MaxMode - 1); + + // Disable the 5 minute EFI watchdog time so we don't get automatically reset + gBS->SetWatchdogTimer (0, 0, 0, NULL); + } + + // Save current screen mode + gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &gScreenColumns, &gScreenRows); + + EblPrintStartupBanner (); + + // Parse command line and handle commands seperated by ; + // The loop prints the prompt gets user input and saves history + + // Look for a variable with a default command line, otherwise use the Pcd + ZeroMem(&VendorGuid, sizeof(EFI_GUID)); + + Status = gRT->GetVariable(CommandLineVariableName, &VendorGuid, NULL, &CommandLineVariableSize, CommandLineVariable); + if (Status == EFI_BUFFER_TOO_SMALL) { + CommandLineVariable = AllocatePool(CommandLineVariableSize); + + Status = gRT->GetVariable(CommandLineVariableName, &VendorGuid, NULL, &CommandLineVariableSize, CommandLineVariable); + if (!EFI_ERROR(Status)) { + UnicodeStrToAsciiStr(CommandLineVariable, CmdLine); + } + + FreePool(CommandLineVariable); + } + + if (EFI_ERROR(Status)) { + AsciiStrCpy (CmdLine, (CHAR8 *)PcdGetPtr (PcdEmbeddedAutomaticBootCommand)); + } + + for (;;) { + Status = ProcessCmdLine (CmdLine, MAX_CMD_LINE); + if (Status == EFI_ABORTED) { + // if a command returns EFI_ABORTED then exit the EBL + EblShutdownExternalCmdTable (); + return EFI_SUCCESS; + } + + // get the command line from the user + EblPrompt (); + GetCmd (CmdLine, MAX_CMD_LINE); + SetCmdHistory (CmdLine); + } +} + + diff --git a/EmbeddedPkg/Ebl/Network.c b/EmbeddedPkg/Ebl/Network.c new file mode 100644 index 0000000000..c566dda49a --- /dev/null +++ b/EmbeddedPkg/Ebl/Network.c @@ -0,0 +1,104 @@ +/** @file + EBL commands for Network Devices + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ebl.h" + +EFI_STATUS +ParseIp ( + IN CHAR8 *String, + OUT EFI_IP_ADDRESS *Address + ) +{ + Address->v4.Addr[0] = AsciiStrDecimalToUintn(String); + String = AsciiStrStr(String, ".") + 1; + Address->v4.Addr[1] = AsciiStrDecimalToUintn(String); + String = AsciiStrStr(String, ".") + 1; + Address->v4.Addr[2] = AsciiStrDecimalToUintn(String); + String = AsciiStrStr(String, ".") + 1; + Address->v4.Addr[3] = AsciiStrDecimalToUintn(String); + + return EFI_SUCCESS; +} + +EFI_STATUS +EblIpCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status = EFI_INVALID_PARAMETER; + EFI_MAC_ADDRESS Mac; + EFI_IP_ADDRESS Ip; + + if (Argc == 1) { + // Get current IP/MAC + + // Get current MAC address + Status = EblGetCurrentMacAddress (&Mac); + if (EFI_ERROR (Status)) { + goto Exit; + } + + AsciiPrint ("MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", Mac.Addr[0], Mac.Addr[1], Mac.Addr[2], Mac.Addr[3], Mac.Addr[4], Mac.Addr[5]); + + // Get current IP address + Status = EblGetCurrentIpAddress (&Ip); + if (EFI_ERROR(Status)) { + AsciiPrint("IP Address is not configured.\n"); + Status = EFI_SUCCESS; + goto Exit; + } + + AsciiPrint("IP Address: %d.%d.%d.%d\n", Ip.v4.Addr[0], Ip.v4.Addr[1],Ip.v4.Addr[2], Ip.v4.Addr[3]); + + } else if ((Argv[1][0] == 'r') && (Argc == 2)) { + // Get new address via dhcp + Status = EblPerformDHCP (TRUE); + } else if ((Argv[1][0] == 's') && (Argc == 3)) { + // Set static IP + Status = ParseIp (Argv[2], &Ip); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Status = EblSetStationIp (&Ip, NULL); + } + +Exit: + return Status; +} + +GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdNetworkTemplate[] = +{ + { + "ip", + " ; print current ip address\n\r [r]; request DHCP address\n\r [s] ipaddr; set static IP address", + NULL, + EblIpCmd + } +}; + + +/** + Initialize the commands in this in this file +**/ +VOID +EblInitializeNetworkCmd ( + VOID + ) +{ + EblAddCommands (mCmdNetworkTemplate, sizeof (mCmdNetworkTemplate)/sizeof (EBL_COMMAND_TABLE)); +} + diff --git a/EmbeddedPkg/Ebl/Script.c b/EmbeddedPkg/Ebl/Script.c new file mode 100644 index 0000000000..2229005d1c --- /dev/null +++ b/EmbeddedPkg/Ebl/Script.c @@ -0,0 +1,126 @@ +/** @file + Script command allows the execution of commands from a text file + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: EfiDevice.c + +**/ + +#include "Ebl.h" + + +/** + Execute the passed in file like a series of commands. The ; can be used on + a single line to indicate multiple commands per line. The Ascii text file + can contain any number of lines. The following line termination forms are + supported: + LF : Unix, Mac OS X*, BeOS + CR+LF: MS-DOS*, Microsoft Windows* + CR : Commodore, Apple II, and realy Mac OS + LF+CR: for simplicity and completeness + + Argv[0] - "script" + Argv[1] - Device Name:path for the file to load + + script fv1:\script.txt + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblScriptCmd ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + EFI_STATUS Status; + EFI_OPEN_FILE *File; + VOID *Address; + UINTN Size; + CHAR8 *Ptr; + CHAR8 *ScanPtr; + UINTN CmdLineSize; + + + + if (Argc < 2) { + // file name required + return EFI_SUCCESS; + } + + File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0); + if (File == NULL) { + AsciiPrint (" %a is not a valid path\n", Argv[1]); + return EFI_SUCCESS; + } + + Status = EfiReadAllocatePool (File, &Address, &Size); + if (!EFI_ERROR (Status)) { + // Loop through each line in the text file + for (Ptr = (CHAR8 *)Address; (Ptr < (((CHAR8 *)Address) + Size)) && !EFI_ERROR (Status); Ptr += CmdLineSize) { + for (CmdLineSize = 0, ScanPtr = Ptr; ; CmdLineSize++, ScanPtr++) { + // look for the end of the line + if ((*ScanPtr == EBL_CR) || (*ScanPtr == EBL_LF)) { + // convert to NULL as this is what input routine would do + *ScanPtr = 0; + if ((*(ScanPtr + 1) == EBL_CR) || (*(ScanPtr + 1) == EBL_LF)) { + // if its a set get the 2nd EOL char + CmdLineSize++; + *(ScanPtr + 1) = 0; + } + CmdLineSize++; + break; + } + + } + + Status = ProcessCmdLine (Ptr, CmdLineSize); + } + + FreePool (Address); + } + + EfiClose (File); + return Status; +} + + + +GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mScriptTemplate[] = { + { + "script", + " device:path; load an ascii file and execute it like commands", + NULL, + EblScriptCmd + } +}; + + +/** + Initialize the commands in this in this file +**/ + +VOID +EblInitializeScriptCmd ( + VOID + ) +{ + if (FeaturePcdGet (PcdEmbeddedScriptCmd)) { + EblAddCommands (mScriptTemplate, sizeof (mScriptTemplate)/sizeof (EBL_COMMAND_TABLE)); + } +} + diff --git a/EmbeddedPkg/EblExternCmd/EntryPointGlue.c b/EmbeddedPkg/EblExternCmd/EntryPointGlue.c new file mode 100644 index 0000000000..1e26fb5159 --- /dev/null +++ b/EmbeddedPkg/EblExternCmd/EntryPointGlue.c @@ -0,0 +1,152 @@ +/** @file + Glue code that contains the EFI entry point and converts it to an EBL + ASCII Argc, Argv sytle entry point + + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +#define CMD_SEPERATOR ';' +#define MAX_ARGS 32 + +EFI_STATUS +EblMain ( + IN UINTN Argc, + IN CHAR8 **Argv + ); + + +/// +/// EdkExternCmdEntry() & ParseArguments() convert the standard EFI entry point +/// into Argc, Argv form that calls EblMain(). +/// + + +/** + Parse the CmdLine and break it up into Argc (arg count) and Argv (array of + pointers to each argument). The Cmd buffer is altered and seperators are + converted to string terminators. This allows Argv to point into CmdLine. + A CmdLine can support multiple commands. The next command in the command line + is returned if it exists. + + @param CmdLine String to parse for a set of commands + @param CmdLineSize Size of CmdLine in bytes + @param Argc Returns the number of arguments in the CmdLine current command + @param Argv Argc pointers to each string in CmdLine + + @return Next Command in the command line or NULL if non exists +**/ +VOID +ParseArguments ( + IN CHAR8 *CmdLine, + IN UINTN CmdLineSize, + OUT UINTN *Argc, + OUT CHAR8 **Argv + ) +{ + UINTN Arg; + CHAR8 *Char; + BOOLEAN LookingForArg; + BOOLEAN InQuote; + UINTN Index; + + *Argc = 0; + if ((CmdLineSize == 0) || (AsciiStrLen (CmdLine) == 0)) { + // basic error checking failed on the arguments + return; + } + + // Walk a single command line. A CMD_SEPERATOR allows mult commands on a single line + InQuote = FALSE; + LookingForArg = TRUE; + for (Char = CmdLine, Arg = 0, Index = 0; *Char != '\0' && *Char != CMD_SEPERATOR; Char++, Index++) { + // Perform any text coversion here + if (*Char == '\t') { + // TAB to space + *Char = ' '; + } + + if (LookingForArg) { + // Look for the beging of an Argv[] entry + if (*Char == '"') { + Argv[Arg++] = ++Char; + LookingForArg = FALSE; + InQuote = TRUE; + } else if (*Char != ' ') { + Argv[Arg++] = Char; + LookingForArg = FALSE; + } + } else { + // Looking for the terminator of an Argv[] entry + if ((InQuote && (*Char == '"')) || (!InQuote && (*Char == ' '))) { + *Char = '\0'; + LookingForArg = TRUE; + } + } + + if ((Arg >= MAX_ARGS) || (Index > CmdLineSize)) { + // Error check buffer and exit since it does not look valid + break; + } + } + + *Argc = Arg; + + if (*Char == CMD_SEPERATOR) { + // Replace the command delimeter with null + *Char = '\0'; + } + + return; +} + + + + +/** + Embedded Boot Loader (EBL) - A simple EFI command line application for embedded + devices. PcdEmbeddedAutomaticBootCommand is a complied in commnad line that + gets executed automatically. The ; seperator allows multiple commands + for each command line. + + @param ImageHandle EFI ImageHandle for this application. + @param SystemTable EFI system table + + @return EFI status of the applicaiton + +**/ +EFI_STATUS +EFIAPI +EdkExternCmdEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; + UINTN Argc; + CHAR8 *Argv[MAX_ARGS]; + + Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo); + if (EFI_ERROR (Status)) { + Argc = 0; + } else { + // Looks like valid commands were passed in. + ParseArguments (ImageInfo->LoadOptions, ImageInfo->LoadOptionsSize, &Argc, Argv); + } + + return EblMain (Argc, Argv); +} + + diff --git a/EmbeddedPkg/EblExternCmd/Main.c b/EmbeddedPkg/EblExternCmd/Main.c new file mode 100644 index 0000000000..04f1eab600 --- /dev/null +++ b/EmbeddedPkg/EblExternCmd/Main.c @@ -0,0 +1,52 @@ +/** @file + Example of an external EBL command. It's loaded via EBL start command. + Argc and Argv are passed in via "" of the EBL command line. + + Start fs0:\EdkExternCmd.efi "Argv[0] Argv[1] 2" + + will launch this command with + Argv[0] = "Argv[0]" + Argv[1] = "Argv[2]" + Argv[2] = "3" + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + + +/** + Entry point with Argc, Argv. Put your code here. + + @param Argc Number of command arguments in Argv + @param Argv Array of strings that represent the parsed command line. + Argv[0] is the comamnd name + + @return EFI_SUCCESS + +**/ +EFI_STATUS +EblMain ( + IN UINTN Argc, + IN CHAR8 **Argv + ) +{ + UINTN Index; + + AsciiPrint ("Hello World\n"); + for (Index = 0; Index < Argc; Index++) { + AsciiPrint ("Argv[%d] = %a\n", Index, Argv[Index]); + } + + return EFI_SUCCESS; +} + diff --git a/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.c b/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.c new file mode 100644 index 0000000000..66ebe67a92 --- /dev/null +++ b/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.c @@ -0,0 +1,82 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 = 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 Architctural Protocol onto a new handle + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiMonotonicCounterArchProtocolGuid, NULL, + NULL + ); + return Status; +} diff --git a/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf b/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf new file mode 100644 index 0000000000..8508ac53a3 --- /dev/null +++ b/EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf @@ -0,0 +1,29 @@ +#%HEADER% +[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/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec new file mode 100644 index 0000000000..22ee365e7b --- /dev/null +++ b/EmbeddedPkg/EmbeddedPkg.dec @@ -0,0 +1,126 @@ +#%HEADER% +#/** @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. +# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License which accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[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] + EfiFileLib|Include/Library/EfiFileLib.h + PrePiLib|Include/Library/PrePiLib.h + RealTimeClockLib|Include/Library/RealTimeClockLib.h + EfiResetSystemLib|Include/Library/EfiResetSystemLib.h + EblCmdLib|Include/Library/EblCmdLib.h + EblAddExternalCommandLib|Library/EblAddExternalCommandLib.h + EblNetworkLib|Library/EblNetworkLib.h + GdbSerialLib|Include/Library/GdbSerialLib.h + + +[Guids.common] + gEmbeddedTokenSpaceGuid = { 0xe0d8ca17, 0x4276, 0x4386, { 0xbb, 0x79, 0x48, 0xcb, 0x81, 0x3d, 0x3c, 0x4f }} + +[Protocols.common] + gHardwareInterruptProtocolGuid = { 0x2890B3EA, 0x053D, 0x1643, { 0xAD, 0x0C, 0xD6, 0x48, 0x08, 0xDA, 0x3F, 0xF1 } } + gEfiDebugSupportPeriodicCallbackProtocolGuid = { 0x9546e07c, 0x2cbb, 0x4c88, { 0x98, 0x6c, 0xcd, 0x34, 0x10, 0x86, 0xf0, 0x44 } } + gEfiEblAddCommandProtocolGuid = { 0xaeda2428, 0x9a22, 0x4637, { 0x9b, 0x21, 0x54, 0x5e, 0x28, 0xfb, 0xb8, 0x29 } } + 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 }} + +[PcdsFeatureFlag.common] + gEmbeddedTokenSpaceGuid.PcdEmbeddedMacBoot|FALSE|BOOLEAN|0x00000001 + gEmbeddedTokenSpaceGuid.PcdEmbeddedDirCmd|TRUE|BOOLEAN|0x00000002 + gEmbeddedTokenSpaceGuid.PcdEmbeddedHobCmd|TRUE|BOOLEAN|0x00000003 + gEmbeddedTokenSpaceGuid.PcdEmbeddedHwDebugCmd|TRUE|BOOLEAN|0x00000004 + gEmbeddedTokenSpaceGuid.PcdEmbeddedIoEnable|FALSE|BOOLEAN|0x00000005 + gEmbeddedTokenSpaceGuid.PcdEmbeddedScriptCmd|FALSE|BOOLEAN|0x00000006 + gEmbeddedTokenSpaceGuid.PcdEmbeddedPciDebugCmd|FALSE|BOOLEAN|0x00000041 + gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob|FALSE|BOOLEAN|0x0000001b + gEmbeddedTokenSpaceGuid.PcdCacheEnable|FALSE|BOOLEAN|0x00000042 + gEmbeddedTokenSpaceGuid.PcdGdbSerial|FALSE|BOOLEAN|0x0000004d + + +[PcdsFixedAtBuild.common] + gEmbeddedTokenSpaceGuid.PcdEmbeddedAutomaticBootCommand|L""|VOID*|0x00000007 + gEmbeddedTokenSpaceGuid.PcdEmbeddedDefaultTextColor|0x07|UINT32|0x00000008 + gEmbeddedTokenSpaceGuid.PcdEmbeddedMemVariableStoreSize|0x10000|UINT32|0x00000009 + gEmbeddedTokenSpaceGuid.PcdEmbeddedPrompt|"Ebl"|VOID*|0x00000034 + + gEmbeddedTokenSpaceGuid.PcdPrePiHobBase|131072|UINT32|0x00000040 + gEmbeddedTokenSpaceGuid.PcdPrePiStackBase|0|UINT32|0x0000000b + gEmbeddedTokenSpaceGuid.PcdPrePiStackSize|131072|UINT32|0x0000000c + gEmbeddedTokenSpaceGuid.PcdPrePiTempMemorySize|0|UINT32|0x000000d + gEmbeddedTokenSpaceGuid.PcdPrePiBfvBaseAddress|0|UINT32|0x000000e + gEmbeddedTokenSpaceGuid.PcdPrePiBfvSize|0|UINT32|0x0000000f + gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32|UINT8|0x00000010 + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0|UINT8|0x00000011 + + gEmbeddedTokenSpaceGuid.PcdFlashFvMainBase|0x0|UINT32|0x00000043 + gEmbeddedTokenSpaceGuid.PcdFlashFvMainOffset|0x0|UINT32|0x00000044 + gEmbeddedTokenSpaceGuid.PcdFlashFvMainSize|0x0|UINT32|0x000000045 + + +# 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.PcdEmbeddedFdBaseAddress|0xffff0000|UINT32|0x00000030 + gEmbeddedTokenSpaceGuid.PcdEmbeddedFdSize|0x0000000|UINT32|0x00000031 + gEmbeddedTokenSpaceGuid.PcdEmbeddedPerformanceCounterFreqencyInHz|0x0000000|UINT64|0x00000032 + gEmbeddedTokenSpaceGuid.PcdEmbeddedFdPerformanceCounterPeriodInNanoseconds|0x0000000|UINT32|0x00000033 + +# Shell characteristics + gEmbeddedTokenSpaceGuid.PcdEmbeddedShellCharacterEcho|TRUE|BOOLEAN|0x00000046 + + 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 + + + diff --git a/EmbeddedPkg/EmbeddedPkg.dsc b/EmbeddedPkg/EmbeddedPkg.dsc new file mode 100644 index 0000000000..d1a4ed8da3 --- /dev/null +++ b/EmbeddedPkg/EmbeddedPkg.dsc @@ -0,0 +1,266 @@ +#%HEADER% +#/** @file +# Embedded Package +# +# +# Copyright (c) 2007, Intel Corporation +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +################################################################################ +# +# 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|IPF|ARM + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = EmbeddedPkg/EmbeddedPkg.fdf + + +################################################################################ +# +# 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. +# +################################################################################ +[LibraryClasses.common] +# DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.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 + EfiFileLib|EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf + + TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf + + ReportStatusCodeLib|IntelFrameworkModulePkg/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|EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.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 + 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 + EblCmdLib|EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.inf + + EblNetworkLib|EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.inf + + +[LibraryClasses.common.DXE_DRIVER] + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + ReportStatusCodeLib|IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf + + +[LibraryClasses.common.UEFI_APPLICATION] + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + ReportStatusCodeLib|IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf + +[LibraryClasses.common.UEFI_DRIVER] + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + ReportStatusCodeLib|IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf + +[LibraryClasses.common.SEC] + ExtractGuidedSectionLib|EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf + +[LibraryClasses.ARM] + SemihostLib|ArmPkg/Library/SemihostLib/SemihostLib.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 + + # + # Control what commands are supported from the UI + # Turn these on and off to add features or save size + # + gEmbeddedTokenSpaceGuid.PcdEmbeddedMacBoot|TRUE + gEmbeddedTokenSpaceGuid.PcdEmbeddedDirCmd|TRUE + gEmbeddedTokenSpaceGuid.PcdEmbeddedHobCmd|TRUE + gEmbeddedTokenSpaceGuid.PcdEmbeddedHwDebugCmd|TRUE + gEmbeddedTokenSpaceGuid.PcdEmbeddedIoEnable|FALSE + gEmbeddedTokenSpaceGuid.PcdEmbeddedScriptCmd|FALSE + gEmbeddedTokenSpaceGuid.PcdEmbeddedPciDebugCmd|TRUE + + 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.PcdEmbeddedAutomaticBootCommand|L""|VOID*|2 + gEmbeddedTokenSpaceGuid.PcdEmbeddedDefaultTextColor|0x07 + gEmbeddedTokenSpaceGuid.PcdEmbeddedMemVariableStoreSize|0x10000 + + gEmbeddedTokenSpaceGuid.PcdPrePiHobBase|0 + gEmbeddedTokenSpaceGuid.PcdPrePiStackBase|0 + gEmbeddedTokenSpaceGuid.PcdPrePiStackSize|0 + gEmbeddedTokenSpaceGuid.PcdPrePiTempMemorySize|0 + gEmbeddedTokenSpaceGuid.PcdPrePiBfvBaseAddress|0 + gEmbeddedTokenSpaceGuid.PcdPrePiBfvSize|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 fragements 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 + + +[PcdsFixedAtBuild.ARM] + gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32 + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0 + +[PcdsFixedAtBuild.IA32] + gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|36 + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|16 + +[PcdsFixedAtBuild.X64] + gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|52 + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|16 + + + +[PcdsFixedAtBuild.IPF] + gEfiMdePkgTokenSpaceGuid.PcdIoBlockBaseAddressForIpf|0x0ffffc000000 + +# +# This makes it so you can source level debug with NT32. VC++ debugger limitiation! +# +#[BuildOptions] +# DEBUG_*_IA32_DLINK_FLAGS = /EXPORT:InitializeDriver=$(IMAGE_ENTRY_POINT) /ALIGN:4096 /SUBSYSTEM:CONSOLE +# RELEASE_*_IA32_DLINK_FLAGS = /ALIGN:4096 +# *_*_IA32_CC_FLAGS = /D EFI_SPECIFICATION_VERSION=0x0002000A /D TIANO_RELEASE_VERSION=0x00080006 + + +################################################################################ +# +# Components Section - list of all Modules needed by this Platform +# +################################################################################ +[Components.common] + EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.inf + EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.inf + EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf + EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf # ApplePkg + EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf # ApplePkg + EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf + EmbeddedPkg/Library/PrePiLib/PrePiLib.inf + EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.inf + EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf + EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf + +####ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf ??? + + + EmbeddedPkg/Ebl/Ebl.inf +#### EmbeddedPkg/EblExternCmd/EblExternCmd.inf + EmbeddedPkg/EmbeddedMonotonicCounter/EmbeddedMonotonicCounter.inf + EmbeddedPkg/GdbStub/GdbStub.inf + EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf + EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf + EmbeddedPkg/SerialDxe/SerialDxe.inf + EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOutSerial.inf + EmbeddedPkg/TemplateBds/TemplateBds.inf + EmbeddedPkg/TemplateCpuDxe/TemplateCpuDxe.inf + EmbeddedPkg/TemplateMetronomeDxe/TemplateMetronomeDxe.inf + EmbeddedPkg/TemplateSec/TemplateSec.inf + EmbeddedPkg/TemplateTimerDxe/TemplateTimerDxe.inf + + + + diff --git a/EmbeddedPkg/EmbeddedPkg.fdf b/EmbeddedPkg/EmbeddedPkg.fdf new file mode 100644 index 0000000000..67e329e89d --- /dev/null +++ b/EmbeddedPkg/EmbeddedPkg.fdf @@ -0,0 +1,141 @@ +# This is Ebl FDF file +# +# Copyright (c) 2008, Intel Corporation +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +################################################################################ +# +# FV Section +# +# [FV] section is used to define what components or modules are placed within a flash +# device file. This section also defines order the components and modules are positioned +# within the image. The [FV] section consists of define statements, set statements and +# module statements. +# +################################################################################ +[FV.FvLoad] +FvAlignment = 16 #FV alignment and FV attributes setting. +ERASE_POLARITY = 1 +MEMORY_MAPPED = TRUE +STICKY_WRITE = TRUE +LOCK_CAP = TRUE +LOCK_STATUS = TRUE +WRITE_DISABLED_CAP = TRUE +WRITE_ENABLED_CAP = TRUE +WRITE_STATUS = TRUE +WRITE_LOCK_CAP = TRUE +WRITE_LOCK_STATUS = TRUE +READ_DISABLED_CAP = TRUE +READ_ENABLED_CAP = TRUE +READ_STATUS = TRUE +READ_LOCK_CAP = TRUE +READ_LOCK_STATUS = TRUE + +################################################################################ +# +# The INF statements point to module INF files, which will be placed into this FV image. +# Parsing tools will scan the INF file to determine the type of component or module. +# The component or module type is used to reference the standard rules +# defined elsewhere in the FDF file. +# +# The format for INF statements is: +# INF $(PathAndInfFileName) +# +################################################################################ +INF EmbeddedPkg/Ebl/Ebl.inf + +################################################################################ +# +# Rules are use with the [FV] section's module INF type to define +# how an FFS file is created for a given INF file. The following Rule are the default +# rules for the different module type. User can add the customized rules to define the +# content of the FFS file. +# +################################################################################ + + +############################################################################ +# Example of a DXE_DRIVER FFS file with a Checksum encapsulation section # +############################################################################ +# +#[Rule.Common.DXE_DRIVER] +# FILE DRIVER = $(NAMED_GUID) { +# DXE_DEPEX DXE_DEPEX Optional |.depex +# COMPRESS PI_STD { +# GUIDED { +# PE32 PE32 |.efi +# UI STRING="$(MODULE_NAME)" Optional +# VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) +# } +# } +# } +# +############################################################################ + +[Rule.Common.SEC] + FILE SEC = $(NAMED_GUID) { + PE32 PE32 |.efi + } + +[Rule.Common.PEI_CORE] + FILE PEI_CORE = $(NAMED_GUID) { + PE32 PE32 |.efi + UI STRING ="$(MODULE_NAME)" Optional + } + +[Rule.Common.PEIM] + FILE PEIM = $(NAMED_GUID) { + PEI_DEPEX PEI_DEPEX Optional |.depex + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.PEIM.TIANOCOMPRESSED] + FILE PEIM = $(NAMED_GUID) DEBUG_MYTOOLS_IA32 { + PEI_DEPEX PEI_DEPEX Optional |.depex + GUIDED A31280AD-481E-41B6-95E8-127F4C984779 PROCESSING_REQUIRED = TRUE { + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + } + } + +[Rule.Common.DXE_CORE] + FILE DXE_CORE = $(NAMED_GUID) { + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.UEFI_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional |.depex + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.DXE_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional |.depex + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.DXE_RUNTIME_DRIVER] + FILE DRIVER = $(NAMED_GUID) { + DXE_DEPEX DXE_DEPEX Optional |.depex + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + } + +[Rule.Common.UEFI_APPLICATION] + FILE APPLICATION = $(NAMED_GUID) { + PE32 PE32 |.efi + UI STRING="$(MODULE_NAME)" Optional + } diff --git a/EmbeddedPkg/GdbStub/Arm/Processor.c b/EmbeddedPkg/GdbStub/Arm/Processor.c new file mode 100644 index 0000000000..e620d344e6 --- /dev/null +++ b/EmbeddedPkg/GdbStub/Arm/Processor.c @@ -0,0 +1,717 @@ +/** @file + Processor specific parts of the GDB stub + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +/** @file + + Copyright (c) 2008, Apple, Inc + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 + 0x00000FFF, + 0x00000FFF, + 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; +} + + +/** ‘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[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); +} + + +/** ‘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 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 Ponter 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; +} + + + +/** ‘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.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/EmbeddedPkg/GdbStub/GdbStub.c b/EmbeddedPkg/GdbStub/GdbStub.c new file mode 100644 index 0000000000..b121e413f3 --- /dev/null +++ b/EmbeddedPkg/GdbStub/GdbStub.c @@ -0,0 +1,1264 @@ +/** @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 Serail IO, ... + + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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); + + // Make this an EFI_D_INFO after we get everything debugged. + DEBUG ((EFI_D_ERROR, "Debug Support Protocol ISA %x\n", DebugSupport->Isa)); + DEBUG ((EFI_D_ERROR, "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 notifactions 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 teminating 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 infinit 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 teminating character '#' and the two digit checksum. + + If host re-starts sending a packet without ending the previous packet, only the last valid packet is proccessed. + (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 corressponds 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 i; + + for (i=0; i < MaxEfiException() ; i++) { + if (gExceptionType[i].Exception == EFIExceptionType) { + return gExceptionType[i].SignalNo; + } + } + return GDB_SIGTRAP; // this is a GDB trap +} + + +/** "m addr,length" + Find the Length of the area to read and the start addres. 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 addres. 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; + + // responce 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 unknow 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 + infomration in the EFI Debug Inmage 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 interupt 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 subseqent call will ask for the next availble 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 Hanldler 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 suports + 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 trasfer 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/EmbeddedPkg/GdbStub/GdbStub.inf b/EmbeddedPkg/GdbStub/GdbStub.inf new file mode 100644 index 0000000000..2b54f0abef --- /dev/null +++ b/EmbeddedPkg/GdbStub/GdbStub.inf @@ -0,0 +1,78 @@ +#%HEADER% +#/** @file +# UEFI GDB stub +# +# This is a shell application that will display Hello World. +# Copyright (c) 2008, Apple, Inc. +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +################################################################################ +# +# 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/EmbeddedPkg/GdbStub/GdbStubInternal.h b/EmbeddedPkg/GdbStub/GdbStubInternal.h new file mode 100644 index 0000000000..20231cff82 --- /dev/null +++ b/EmbeddedPkg/GdbStub/GdbStubInternal.h @@ -0,0 +1,746 @@ +/** @file + Private include file for GDB stub + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 // Setgment 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 leess 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; // Suport 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 serail stream as it could steal +// characters from the F reponse 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 corressponds 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 +SendSuccess ( + VOID + ); + + +/** + Send empty packet to specify that particular command/functionality is not supported. + **/ +VOID +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 +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 +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 +WriteGeneralRegisters ( + IN EFI_SYSTEM_CONTEXT SystemContext, + IN CHAR8 *InBuffer + ); + + +/** ‘m addr,length ’ + Find the Length of the area to read and the start addres. 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 +ReadFromMemory ( + IN CHAR8 *PacketData + ); + + +/** ‘M addr,length :XX...’ + Find the Length of the area in bytes to write and the start addres. 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 +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 +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 +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 Hanldler 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 serail 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 teminating 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 infinit 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 teminating character '#' and the two digit checksum. + + If host re-starts sending a packet without ending the previous packet, only the last valid packet is proccessed. + (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/EmbeddedPkg/GdbStub/Ia32/Processor.c b/EmbeddedPkg/GdbStub/Ia32/Processor.c new file mode 100644 index 0000000000..90a2224edf --- /dev/null +++ b/EmbeddedPkg/GdbStub/Ia32/Processor.c @@ -0,0 +1,993 @@ +/** @file + Processor specific parts of the GDB stub + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 Ponter 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 maching 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/EmbeddedPkg/GdbStub/SerialIo.c b/EmbeddedPkg/GdbStub/SerialIo.c new file mode 100644 index 0000000000..5afaed06b9 --- /dev/null +++ b/EmbeddedPkg/GdbStub/SerialIo.c @@ -0,0 +1,551 @@ +/** @file + Serial IO Abstraction for GDB stub. This allows an EFI consoles that shows up on the system + running GDB. One consle for error information and another console for user input/output. + + Basic packet format is $packet-data#checksum. So every comand 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. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 serail stream as it could steal +// characters from the F reponse packet +// +BOOLEAN gProcessingFPacket = FALSE; + +/** + Process a control-C break message. + + Currently a place holder, remove the ASSERT when it gets implemented. + + @param ErrNo Error infomration 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 responce 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/receice 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 ReveiveFifoDepth The requested depth of the FIFO on the receive side of the + serial interface. A ReceiveFifoDepth value of 0 will use + the device's dfault 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 + vaule 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 thecontrol 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 initailize 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/EmbeddedPkg/GdbStub/X64/Processor.c b/EmbeddedPkg/GdbStub/X64/Processor.c new file mode 100644 index 0000000000..0758bc4a84 --- /dev/null +++ b/EmbeddedPkg/GdbStub/X64/Processor.c @@ -0,0 +1,963 @@ +/** @file + Processor specific parts of the GDB stub + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 Ponter 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 maching 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/EmbeddedPkg/Include/Library/EblAddExternalCommandLib.h b/EmbeddedPkg/Include/Library/EblAddExternalCommandLib.h new file mode 100644 index 0000000000..c3f1678180 --- /dev/null +++ b/EmbeddedPkg/Include/Library/EblAddExternalCommandLib.h @@ -0,0 +1,122 @@ +/** @file + Include flie for basic command line parser for EBL (Embedded Boot Loader) + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EBL_ADD_EXTERNAL_COMMAND_LIB_H__ +#define __EBL_ADD_EXTERNAL_COMMAND_LIB_H__ + +#include +#include + + +EFI_STATUS +EFIAPI +EblAddExternalCommands ( + IN const EBL_COMMAND_TABLE *EntryArray, + IN UINTN ArrayCount + ); + +/** + + Return a keypress or optionally timeout if a timeout value was passed in. + + An optional callback funciton is called evey second when waiting for a + + timeout. + + + + @param Key EFI Key information returned + + @param TimeoutInSec Number of seconds to wait to timeout + + @param CallBack Callback called every second during the timeout wait + + + + @return EFI_SUCCESS Key was returned + + @return EFI_TIMEOUT If the TimoutInSec expired + + + +**/ + +EFI_STATUS + +EFIAPI + +EblGetCharKey ( + + IN OUT EFI_INPUT_KEY *Key, + + IN UINTN TimeoutInSec, + + IN EBL_GET_CHAR_CALL_BACK CallBack OPTIONAL + + ); + + + + + +/** + + This routine is used prevent command output data from scrolling off the end + + of the screen. The global gPageBreak is used to turn on or off this feature. + + If the CurrentRow is near the end of the screen pause and print out a prompt + + If the use hits Q to quit return TRUE else for any other key return FALSE. + + PrefixNewline is used to figure out if a newline is needed before the prompt + + string. This depends on the last print done before calling this function. + + CurrentRow is updated by one on a call or set back to zero if a prompt is + + needed. + + + + @param CurrentRow Used to figure out if its the end of the page and updated + + @param PrefixNewline Did previous print issue a newline + + + + @return TRUE if Q was hit to quit, FALSE in all other cases. + + + +**/ + +BOOLEAN + +EFIAPI + +EblAnyKeyToContinueQtoQuit ( + + IN UINTN *CurrentRow, + + IN BOOLEAN PrefixNewline + + ); + + + +#endif + diff --git a/EmbeddedPkg/Include/Library/EblCmdLib.h b/EmbeddedPkg/Include/Library/EblCmdLib.h new file mode 100644 index 0000000000..70ed3c8c71 --- /dev/null +++ b/EmbeddedPkg/Include/Library/EblCmdLib.h @@ -0,0 +1,48 @@ +/** @file + Include flie for basic command line parser for EBL (Embedded Boot Loader) + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EBL_LIB_H__ +#define __EBL_LIB_H__ + +#include +#include + + +VOID +EblAddCommand ( + IN const EBL_COMMAND_TABLE *Entry + ); + +VOID +EblAddCommands ( + IN const EBL_COMMAND_TABLE *EntryArray, + IN UINTN ArrayCount + ); + + +// +// LIbrary constructor called directly from Ebl Code. +// This module calls EblAddCommand () or EblAddCommands () to register new commands +// +VOID +EblInitializeExternalCmd ( + VOID + ); + + + +#endif + diff --git a/EmbeddedPkg/Include/Library/EblNetworkLib.h b/EmbeddedPkg/Include/Library/EblNetworkLib.h new file mode 100644 index 0000000000..5c9ec03cfc --- /dev/null +++ b/EmbeddedPkg/Include/Library/EblNetworkLib.h @@ -0,0 +1,68 @@ +/** @file + Abstractions for Ebl network accesses. + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EBL_NETWORK_LIB_H__ +#define __EBL_NETWORK_LIB_H__ + +#include + + +EFI_STATUS +EFIAPI +EblGetCurrentIpAddress ( + IN OUT EFI_IP_ADDRESS *Ip + ); + +EFI_STATUS +EFIAPI +EblGetCurrentMacAddress ( + IN OUT EFI_MAC_ADDRESS *Mac + ); + +CHAR8 * +EFIAPI +EblLoadFileBootTypeString ( + IN EFI_HANDLE Handle + ); + +EFI_STATUS +EFIAPI +EblPerformDHCP ( + IN BOOLEAN SortOffers + ); + +EFI_STATUS +EFIAPI +EblSetStationIp ( + IN EFI_IP_ADDRESS *NewStationIp, OPTIONAL + IN EFI_IP_ADDRESS *NewSubnetMask OPTIONAL + ); + +EFI_STATUS +EFIAPI +EblMtftp ( + IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation, + IN OUT VOID *BufferPtr OPTIONAL, + IN BOOLEAN Overwrite, + IN OUT UINT64 *BufferSize, + IN UINTN *BlockSize OPTIONAL, + IN EFI_IP_ADDRESS *ServerIp, + IN UINT8 *Filename OPTIONAL, + IN EFI_PXE_BASE_CODE_MTFTP_INFO *Info OPTIONAL, + IN BOOLEAN DontUseBuffer + ); + +#endif + diff --git a/EmbeddedPkg/Include/Library/EfiFileLib.h b/EmbeddedPkg/Include/Library/EfiFileLib.h new file mode 100644 index 0000000000..992d326997 --- /dev/null +++ b/EmbeddedPkg/Include/Library/EfiFileLib.h @@ -0,0 +1,315 @@ +/** @file + Library functions that perform file IO. Memory buffer, file system, and + fimrware volume operations are supproted. + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 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 insensative 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; + + 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#: + + 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 seperated 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 + secitons 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 locaiton 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 doe 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 locaiton 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 flie 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 + ); + +#endif diff --git a/EmbeddedPkg/Include/Library/EfiResetSystemLib.h b/EmbeddedPkg/Include/Library/EfiResetSystemLib.h new file mode 100644 index 0000000000..162857660f --- /dev/null +++ b/EmbeddedPkg/Include/Library/EfiResetSystemLib.h @@ -0,0 +1,58 @@ +/** @file + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#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/EmbeddedPkg/Include/Library/GdbSerialLib.h b/EmbeddedPkg/Include/Library/GdbSerialLib.h new file mode 100644 index 0000000000..3d72005c91 --- /dev/null +++ b/EmbeddedPkg/Include/Library/GdbSerialLib.h @@ -0,0 +1,107 @@ +/** @file + Basic serial IO abstaction for GDB + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __GDB_SERIAL_LIB_H__ +#define __GDB_SERIAL_LIB_H__ + + + +/** + Sets the baud rate, receive FIFO depth, transmit/receice 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 + vaule 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 coonfigured. + +**/ +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 availible + @return FALSE - Character not availible + +**/ +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/EmbeddedPkg/Include/Library/HalRuntimeServicesLib.h b/EmbeddedPkg/Include/Library/HalRuntimeServicesLib.h new file mode 100644 index 0000000000..d77edfa437 --- /dev/null +++ b/EmbeddedPkg/Include/Library/HalRuntimeServicesLib.h @@ -0,0 +1,165 @@ +/** @file + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#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/EmbeddedPkg/Include/Library/PrePiLib.h b/EmbeddedPkg/Include/Library/PrePiLib.h new file mode 100644 index 0000000000..61c7e4d7ac --- /dev/null +++ b/EmbeddedPkg/Include/Library/PrePiLib.h @@ -0,0 +1,766 @@ +/** @file + Library that helps implement monolithic PEI. (SEC goes to DXE) + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PRE_PI_LIB_H__ +#define __PRE_PI_LIB_H__ + +/** + 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 +FfsFindByName ( + 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 succes 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 + ); + + +/** + Retrieves the magic value from the PE/COFF header. + + @param Hdr The buffer in which to return the PE32, PE32+, or TE header. + + @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32 + @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+ + +**/ +VOID +CreateHobList ( + IN VOID *MemoryBegin, + IN UINTN MemoryLength, + IN VOID *HobBase, + IN VOID *StackBase + ); + + +/** + 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 resrouce 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 + ); + + +/** + 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 + ); + +VOID +EFIAPI +AddDxeCoreReportStatusCodeCallback ( + VOID + ); + + +#endif diff --git a/EmbeddedPkg/Include/Library/RealTimeClockLib.h b/EmbeddedPkg/Include/Library/RealTimeClockLib.h new file mode 100644 index 0000000000..6fdc34d8b9 --- /dev/null +++ b/EmbeddedPkg/Include/Library/RealTimeClockLib.h @@ -0,0 +1,138 @@ +/** @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.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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/EmbeddedPkg/Include/Protocol/DebugSupportPeriodicCallback.h b/EmbeddedPkg/Include/Protocol/DebugSupportPeriodicCallback.h new file mode 100644 index 0000000000..d780cbd4cb --- /dev/null +++ b/EmbeddedPkg/Include/Protocol/DebugSupportPeriodicCallback.h @@ -0,0 +1,42 @@ +/** @file + Protocol is used to help implement DebugSupport.RegisterPeriodicCallback() functionality. + This enables the DXE timer driver to support the periodic callback function so the + DebugSupport driver does not need to contain platform specific information about how a timer + works. + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#ifndef __DEBUG_SUPPORT_PERIODIC_CALLBACK_H__ +#define __DEBUG_SUPPORT_PERIODIC_CALLBACK_H__ + +#include + +typedef struct _EFI_DEBUG_SUPPORT_PERIODIC_CALLBACK_PROTOCOL EFI_DEBUG_SUPPORT_PERIODIC_CALLBACK_PROTOCOL; + + +// {9546E07C-2CBB-4c88-986C-CD341086F044} +#define EFI_DEBUG_SUPPORT_PERIODIC_CALLBACK_PROTOCOL_GUID \ + { 0x9546e07c, 0x2cbb, 0x4c88, { 0x98, 0x6c, 0xcd, 0x34, 0x10, 0x86, 0xf0, 0x44 } } + + +// +// DebugSupport protocol definition +// +struct _EFI_DEBUG_SUPPORT_PERIODIC_CALLBACK_PROTOCOL { + EFI_PERIODIC_CALLBACK PeriodicCallback; +}; + +extern EFI_GUID gEfiDebugSupportPeriodicCallbackProtocolGuid; + +#endif diff --git a/EmbeddedPkg/Include/Protocol/EblAddCommand.h b/EmbeddedPkg/Include/Protocol/EblAddCommand.h new file mode 100644 index 0000000000..2c11e7fe58 --- /dev/null +++ b/EmbeddedPkg/Include/Protocol/EblAddCommand.h @@ -0,0 +1,156 @@ +/** @file + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +/** @file + Abstraction for hardware based interrupt routine + + Copyright (c) 2009 Apple Inc. + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#ifndef __EBL_ADD_COMMAND_H__ +#define __EBL_ADD_COMMAND_H__ + + + +// +// Protocol GUID +// +// AEDA2428-9A22-4637-9B21-545E28FBB829 + +#define EBL_ADD_COMMAND_PROTOCOL_GUID \ + { 0xaeda2428, 0x9a22, 0x4637, { 0x9b, 0x21, 0x54, 0x5e, 0x28, 0xfb, 0xb8, 0x29 } } + + +typedef struct _EBL_ADD_COMMAND_PROTOCOL EBL_ADD_COMMAND_PROTOCOL; + +typedef +EFI_STATUS +(EFIAPI *EBL_COMMMAND) ( + IN UINTN Argc, + IN CHAR8 **Argv + ); + +typedef struct { + CHAR8 *Name; + CHAR8 *HelpSummary; + CHAR8 *Help; + EBL_COMMMAND Command; +} EBL_COMMAND_TABLE; + + +/** + Add a single command table entry. + + @param EntryArray Pointer EBL_COMMAND_TABLE of the command that is being added + +**/ +typedef +VOID +(EFIAPI *EBL_ADD_COMMAND) ( + IN const EBL_COMMAND_TABLE *Entry + ); + + +/** + Add a multiple command table entry. + + @param EntryArray Pointer EBL_COMMAND_TABLE of the commands that are being added + + @param ArrayCount Nuber of commands in the EntryArray. + +**/ +typedef +VOID +(EFIAPI *EBL_ADD_COMMANDS) ( + IN const EBL_COMMAND_TABLE *EntryArray, + IN UINTN ArrayCount + ); + + +typedef +VOID +(EFIAPI *EBL_GET_CHAR_CALL_BACK) ( + IN UINTN ElapsedTime + ); + +/** + Return a keypress or optionally timeout if a timeout value was passed in. + An optional callback funciton is called evey second when waiting for a + timeout. + + @param Key EFI Key information returned + @param TimeoutInSec Number of seconds to wait to timeout + @param CallBack Callback called every second during the timeout wait + + @return EFI_SUCCESS Key was returned + @return EFI_TIMEOUT If the TimoutInSec expired + +**/ +typedef +EFI_STATUS +(EFIAPI *EBL_GET_CHAR_KEY) ( + IN OUT EFI_INPUT_KEY *Key, + IN UINTN TimeoutInSec, + IN EBL_GET_CHAR_CALL_BACK CallBack OPTIONAL + ); + + +/** + This routine is used prevent command output data from scrolling off the end + of the screen. The global gPageBreak is used to turn on or off this feature. + If the CurrentRow is near the end of the screen pause and print out a prompt + If the use hits Q to quit return TRUE else for any other key return FALSE. + PrefixNewline is used to figure out if a newline is needed before the prompt + string. This depends on the last print done before calling this function. + CurrentRow is updated by one on a call or set back to zero if a prompt is + needed. + + @param CurrentRow Used to figure out if its the end of the page and updated + @param PrefixNewline Did previous print issue a newline + + @return TRUE if Q was hit to quit, FALSE in all other cases. + +**/ +typedef +BOOLEAN +(EFIAPI *EBL_ANY_KEY_CONTINUE_Q_QUIT) ( + IN UINTN *CurrentRow, + IN BOOLEAN PrefixNewline + ); + + + +struct _EBL_ADD_COMMAND_PROTOCOL { + EBL_ADD_COMMAND AddCommand; + EBL_ADD_COMMANDS AddCommands; + + // Commands to reuse EBL infrastructure + EBL_GET_CHAR_KEY EblGetCharKey; + EBL_ANY_KEY_CONTINUE_Q_QUIT EblAnyKeyToContinueQtoQuit; +}; + +extern EFI_GUID gEfiEblAddCommandProtocolGuid; + +#endif + + diff --git a/EmbeddedPkg/Include/Protocol/EmbeddedDevice.h b/EmbeddedPkg/Include/Protocol/EmbeddedDevice.h new file mode 100644 index 0000000000..4be6c11a28 --- /dev/null +++ b/EmbeddedPkg/Include/Protocol/EmbeddedDevice.h @@ -0,0 +1,58 @@ +/** @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.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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/EmbeddedPkg/Include/Protocol/EmbeddedExternalDevice.h b/EmbeddedPkg/Include/Protocol/EmbeddedExternalDevice.h new file mode 100644 index 0000000000..1131399a60 --- /dev/null +++ b/EmbeddedPkg/Include/Protocol/EmbeddedExternalDevice.h @@ -0,0 +1,94 @@ +/** @file + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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/EmbeddedPkg/Include/Protocol/EmbeddedGpio.h b/EmbeddedPkg/Include/Protocol/EmbeddedGpio.h new file mode 100644 index 0000000000..fd3d3bd9bc --- /dev/null +++ b/EmbeddedPkg/Include/Protocol/EmbeddedGpio.h @@ -0,0 +1,167 @@ +/** @file + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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; + +#endif diff --git a/EmbeddedPkg/Include/Protocol/HardwareInterrupt.h b/EmbeddedPkg/Include/Protocol/HardwareInterrupt.h new file mode 100644 index 0000000000..a4825832c4 --- /dev/null +++ b/EmbeddedPkg/Include/Protocol/HardwareInterrupt.h @@ -0,0 +1,151 @@ +/** @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.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 + ); + + +struct _EFI_HARDWARE_INTERRUPT_PROTOCOL { + HARDWARE_INTERRUPT_REGISTER RegisterInterruptSource; + HARDWARE_INTERRUPT_ENABLE EnableInterruptSource; + HARDWARE_INTERRUPT_DISABLE DisableInterruptSource; + HARDWARE_INTERRUPT_INTERRUPT_STATE GetInterruptSourceState; +}; + +extern EFI_GUID gHardwareInterruptProtocolGuid; + +#endif + + diff --git a/EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.c b/EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.c new file mode 100644 index 0000000000..fcb533c8b7 --- /dev/null +++ b/EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.c @@ -0,0 +1,156 @@ +/** @file + Add external EblCmd Lib + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +#include +#include +#include +#include +#include + + +STATIC BOOLEAN gInstalledCommand = FALSE; +STATIC EFI_EVENT mEblCommandRegistration = NULL; + +STATIC const EBL_COMMAND_TABLE *mAddExternalCmdLibTemplate = NULL; +STATIC UINTN mAddExternalCmdLibTemplateSize = 0; +EBL_ADD_COMMAND_PROTOCOL *gEblExternalCommand = NULL; + + +/** + Return a keypress or optionally timeout if a timeout value was passed in. + An optional callback funciton is called evey second when waiting for a + timeout. + + @param Key EFI Key information returned + @param TimeoutInSec Number of seconds to wait to timeout + @param CallBack Callback called every second during the timeout wait + + @return EFI_SUCCESS Key was returned + @return EFI_TIMEOUT If the TimoutInSec expired + +**/ +EFI_STATUS +EFIAPI +EblGetCharKey ( + IN OUT EFI_INPUT_KEY *Key, + IN UINTN TimeoutInSec, + IN EBL_GET_CHAR_CALL_BACK CallBack OPTIONAL + ) +{ + if (gEblExternalCommand != NULL) { + return gEblExternalCommand->EblGetCharKey (Key, TimeoutInSec, CallBack); + } + return EFI_TIMEOUT; +} + + +/** + This routine is used prevent command output data from scrolling off the end + of the screen. The global gPageBreak is used to turn on or off this feature. + If the CurrentRow is near the end of the screen pause and print out a prompt + If the use hits Q to quit return TRUE else for any other key return FALSE. + PrefixNewline is used to figure out if a newline is needed before the prompt + string. This depends on the last print done before calling this function. + CurrentRow is updated by one on a call or set back to zero if a prompt is + needed. + + @param CurrentRow Used to figure out if its the end of the page and updated + @param PrefixNewline Did previous print issue a newline + + @return TRUE if Q was hit to quit, FALSE in all other cases. + +**/ +BOOLEAN +EFIAPI +EblAnyKeyToContinueQtoQuit ( + IN UINTN *CurrentRow, + IN BOOLEAN PrefixNewline + ) +{ + if (gEblExternalCommand != NULL) { + return gEblExternalCommand->EblAnyKeyToContinueQtoQuit (CurrentRow, PrefixNewline); + } + return FALSE; +} + + + +/** + Update mFvbEntry. Add new entry, or update existing entry if Fvb protocol is + reinstalled. + + @param Event The Event that is being processed + @param Context Event Context + +**/ +VOID +EFIAPI +EblAddCommandNotificationEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + if (!gInstalledCommand) { + Status = gBS->LocateProtocol (&gEfiEblAddCommandProtocolGuid, NULL, (VOID **)&gEblExternalCommand); + if (!EFI_ERROR (Status)) { + gEblExternalCommand->AddCommands (mAddExternalCmdLibTemplate, mAddExternalCmdLibTemplateSize); + gInstalledCommand = TRUE; + } + } +} + + + +/** + The user Entry Point for the driver. 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 +EblAddExternalCommands ( + IN const EBL_COMMAND_TABLE *EntryArray, + IN UINTN ArrayCount + ) +{ + if (mAddExternalCmdLibTemplate != NULL) { + return EFI_ALREADY_STARTED; + } + + mAddExternalCmdLibTemplate = EntryArray; + mAddExternalCmdLibTemplateSize = ArrayCount; + + EfiCreateProtocolNotifyEvent ( + &gEfiEblAddCommandProtocolGuid, + TPL_CALLBACK, + EblAddCommandNotificationEvent, + NULL, + &mEblCommandRegistration + ); + + return EFI_SUCCESS; +} + diff --git a/EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.inf b/EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.inf new file mode 100644 index 0000000000..5b0af6e75a --- /dev/null +++ b/EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.inf @@ -0,0 +1,47 @@ +#%HEADER% +#/** @file +# Component description file for the entry point to a EFIDXE Drivers +# +# Library to abstract Framework extensions that conflict with UEFI 2.0 Specification +# Copyright (c) 2007 - 2007, Intel Corporation +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = EblAddExternalCommandLib + FILE_GUID = 9195D970-C6F7-484E-8013-5B03C89C3B81 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = EblAddExternalCommandLib|DXE_DRIVER UEFI_APPLICATION UEFI_DRIVER + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + EblAddExternalCommandLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiLib + +[Protocols] + +[Guids] + \ No newline at end of file diff --git a/EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.c b/EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.c new file mode 100644 index 0000000000..5cbdfdb15a --- /dev/null +++ b/EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.c @@ -0,0 +1,28 @@ +/** @file + Null EblCmdLib + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +#include +#include + + +VOID +EblInitializeExternalCmd ( + VOID + ) +{ + return; +} diff --git a/EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.inf b/EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.inf new file mode 100644 index 0000000000..b40935b838 --- /dev/null +++ b/EmbeddedPkg/Library/EblCmdLibNull/EblCmdLibNull.inf @@ -0,0 +1,45 @@ +#%HEADER% +#/** @file +# Component description file for the entry point to a EFIDXE Drivers +# +# Library to abstract Framework extensions that conflict with UEFI 2.0 Specification +# Copyright (c) 2007 - 2007, Intel Corporation +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = EblCmdLibNull + FILE_GUID = 3513C4E2-06D6-4921-9C2B-E938777BA79E + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = EfiCmdLib|DXE_DRIVER UEFI_APPLICATION UEFI_DRIVER + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + EblCmdLibNull.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + +[Protocols] + +[Guids] + \ No newline at end of file diff --git a/EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.c b/EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.c new file mode 100644 index 0000000000..13766c88b2 --- /dev/null +++ b/EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.c @@ -0,0 +1,173 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include + +#include +#include + + +BOOLEAN gUseIpv6 = FALSE; + +EFI_STATUS +EFIAPI +EblGetCurrentIpAddress ( + IN OUT EFI_IP_ADDRESS *Ip + ) +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *Pxe; + + Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Pxe->Start (Pxe, gUseIpv6); + if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { + return Status; + } + + CopyMem (Ip, &Pxe->Mode->StationIp, sizeof (EFI_IP_ADDRESS)); + + return Status; +} + + +EFI_STATUS +EFIAPI +EblGetCurrentMacAddress ( + IN OUT EFI_MAC_ADDRESS *Mac + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNet; + + Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet); + if (EFI_ERROR(Status)) { + return Status; + } + + CopyMem (SimpleNet->Mode->CurrentAddress.Addr, Mac, sizeof (EFI_MAC_ADDRESS)); + return Status; +} + + +CHAR8 * +EFIAPI +EblLoadFileBootTypeString ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + VOID *NullPtr; + + Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, &NullPtr); + if (!EFI_ERROR (Status)) { + return "EFI PXE Network Boot"; + } + + return ""; +} + +EFI_STATUS +EFIAPI +EblPerformDHCP ( + IN BOOLEAN SortOffers + ) +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *Pxe; + + Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Pxe->Start (Pxe, gUseIpv6); + if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { + return Status; + } + + Status = Pxe->Dhcp(Pxe, TRUE); + return Status; +} + + +EFI_STATUS +EFIAPI +EblSetStationIp ( + IN EFI_IP_ADDRESS *NewStationIp, OPTIONAL + IN EFI_IP_ADDRESS *NewSubnetMask OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *Pxe; + + Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Pxe->Start (Pxe, gUseIpv6); + if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { + return Status; + } + + Status = Pxe->SetStationIp (Pxe, NewStationIp, NewSubnetMask); + return Status; +} + + +EFI_STATUS +EFIAPI +EblMtftp ( + IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation, + IN OUT VOID *BufferPtr OPTIONAL, + IN BOOLEAN Overwrite, + IN OUT UINT64 *BufferSize, + IN UINTN *BlockSize OPTIONAL, + IN EFI_IP_ADDRESS *ServerIp, + IN UINT8 *Filename OPTIONAL, + IN EFI_PXE_BASE_CODE_MTFTP_INFO *Info OPTIONAL, + IN BOOLEAN DontUseBuffer + ) +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *Pxe; + + Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Pxe->Mtftp ( + Pxe, + Operation, + BufferPtr, + Overwrite, + BufferSize, + BlockSize, + ServerIp, + Filename, + Info, + DontUseBuffer + ); + return Status; +} + diff --git a/EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.inf b/EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.inf new file mode 100644 index 0000000000..f46242fc62 --- /dev/null +++ b/EmbeddedPkg/Library/EblNetworkLib/EblNetworkLib.inf @@ -0,0 +1,28 @@ +#%HEADER% +# +# Copyright (c) 2005 - 2009 Apple Computer, Inc. All rights reserved. +# +# +# + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = EblNetworkLib + FILE_GUID = D885869A-7869-47DB-9429-DE03C318BCFD + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = EblNetworkLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER + +[sources.common] + EblNetworkLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[Protocols] + gEfiSimpleNetworkProtocolGuid + gEfiPxeBaseCodeProtocolGuid + +[Depex] + TRUE \ No newline at end of file diff --git a/EmbeddedPkg/Library/EfiFileLib/EfiFileLib.c b/EmbeddedPkg/Library/EfiFileLib/EfiFileLib.c new file mode 100644 index 0000000000..e98651b14d --- /dev/null +++ b/EmbeddedPkg/Library/EfiFileLib/EfiFileLib.c @@ -0,0 +1,1483 @@ +/** @file + File IO routines inspired by Streams with an EFI flavor + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + 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 insensative 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 + 10.0.1.102: - TFTP service IP followed by the file name +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define EFI_OPEN_FILE_GUARD_HEADER 0x4B4D4641 +#define EFI_OPEN_FILE_GUARD_FOOTER 0x444D5A56 + +// Need to defend against this overflowing +#define MAX_CMD_LINE 0x200 + +typedef struct { + UINT32 Header; + EFI_OPEN_FILE File; + UINT32 Footer; +} EFI_OPEN_FILE_GUARD; + + +// globals to store current open device info +EFI_HANDLE *mBlkIo = NULL; +UINTN mBlkIoCount = 0; + +EFI_HANDLE *mFs = NULL; +UINTN mFsCount = 0; +// mFsInfo[] array entries must match mFs[] handles +EFI_FILE_SYSTEM_INFO **mFsInfo = NULL; + +EFI_HANDLE *mFv = NULL; +UINTN mFvCount = 0; +EFI_HANDLE *mLoadFile = NULL; +UINTN mLoadFileCount = 0; + + + +/** + Internal worker function to validate a File handle. + + @param File Open File Handle + + @return TRUE File is valid + @return FALSE File is not valid + + +**/ +BOOLEAN +FileHandleValid ( + IN EFI_OPEN_FILE *File + ) +{ + EFI_OPEN_FILE_GUARD *GuardFile; + + // Look right before and after file structure for the correct signatures + GuardFile = BASE_CR (File, EFI_OPEN_FILE_GUARD, File); + if ((GuardFile->Header != EFI_OPEN_FILE_GUARD_HEADER) || + (GuardFile->Footer != EFI_OPEN_FILE_GUARD_FOOTER) ) { + return FALSE; + } + + return TRUE; +} + +/** + Internal worker function. If Buffer is not NULL free it. + + @param Buffer Buffer to FreePool() + +**/ +VOID +EblFreePool ( + IN VOID *Buffer + ) +{ + if (Buffer != NULL) { + FreePool (Buffer); + } +} + +/** + Update Device List Global Variables + +**/ +VOID +EblUpdateDeviceLists ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Size; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs; + EFI_FILE_HANDLE Root; + UINTN Index; + + if (mBlkIo != NULL) { + FreePool (mBlkIo); + } + gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &mBlkIoCount, &mBlkIo); + + if (mFv != NULL) { + FreePool (mFv); + } + gBS->LocateHandleBuffer (ByProtocol, &gEfiFirmwareVolume2ProtocolGuid, NULL, &mFvCount, &mFv); + + if (mLoadFile != NULL) { + FreePool (mLoadFile); + } + gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &mLoadFileCount, &mLoadFile); + + if (mFs != NULL) { + FreePool (mFs); + } + + if (&mFsInfo[0] != NULL) { + // Need to Free the mFsInfo prior to reclaculating mFsCount so don't move this code + for (Index = 0; Index < mFsCount; Index++) { + if (mFsInfo[Index] != NULL) { + FreePool (mFsInfo[Index]); + } + } + FreePool (mFsInfo); + } + + gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &mFsCount, &mFs); + + + mFsInfo = AllocateZeroPool (mFsCount * sizeof (EFI_FILE_SYSTEM_INFO *)); + if (mFsInfo == NULL) { + // If we can't do this then we can't support file system entries + mFsCount = 0; + } else { + // Loop through all the file system structures and cache the file system info data + for (Index =0; Index < mFsCount; Index++) { + Status = gBS->HandleProtocol (mFs[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs); + if (!EFI_ERROR (Status)) { + Status = Fs->OpenVolume (Fs, &Root); + if (!EFI_ERROR (Status)) { + // Get information about the volume + Size = 0; + Status = Root->GetInfo (Root, &gEfiFileSystemInfoGuid, &Size, mFsInfo[Index]); + if (Status == EFI_BUFFER_TOO_SMALL) { + mFsInfo[Index] = AllocatePool (Size); + Status = Root->GetInfo (Root, &gEfiFileSystemInfoGuid, &Size, mFsInfo[Index]); + } + + Root->Close (Root); + } + } + } + } +} + + +/** + PathName is in the form : for example fs1:\ or ROOT:\. + Return TRUE if the prefix of PathName matches a file system + Volume Name. MatchIndex is the array index in mFsInfo[] of the match, + and it can be used with mFs[] to find the handle that needs to be opened + + @param PathName PathName to check + @param FileStart Index of the first character of the + @param MatchIndex Index in mFsInfo[] that matches + + @return TRUE PathName matches a Volume Label and MatchIndex is valid + @return FALSE PathName does not match a Volume Label MatchIndex undefined + +**/ +BOOLEAN +EblMatchVolumeName ( + IN CHAR8 *PathName, + IN UINTN FileStart, + OUT UINTN *MatchIndex + ) +{ + UINTN Index; + UINTN Compare; + UINTN VolStrLen; + BOOLEAN Match; + + for (Index =0; Index < mFsCount; Index++) { + if (mFsInfo[Index] == NULL) { + // FsInfo is not valid so skip it + continue; + } + VolStrLen = StrLen (mFsInfo[Index]->VolumeLabel); + for (Compare = 0, Match = TRUE; Compare < (FileStart - 1); Compare++) { + if (Compare > VolStrLen) { + Match = FALSE; + break; + } + if (PathName[Compare] != (CHAR8)mFsInfo[Index]->VolumeLabel[Compare]) { + // If the VolumeLabel has a space allow a _ to match with it in addition to ' ' + if (!((PathName[Compare] == '_') && (mFsInfo[Index]->VolumeLabel[Compare] == L' '))) { + Match = FALSE; + break; + } + } + } + if (Match) { + *MatchIndex = Index; + return TRUE; + } + } + + return FALSE; +} + + +/** + 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 DeviceType + ) +{ + switch (DeviceType) { + case EfiOpenLoadFile: + return mLoadFileCount; + case EfiOpenFirmwareVolume: + return mFvCount; + case EfiOpenFileSystem: + return mFsCount; + case EfiOpenBlockIo: + return mBlkIoCount; + default: + return 0; + } +} + +EFI_STATUS +ConvertIpStringToEfiIp ( + IN CHAR8 *PathName, + OUT EFI_IP_ADDRESS *ServerIp + ) +{ + CHAR8 *Str; + + Str = PathName; + ServerIp->v4.Addr[0] = (UINT8)AsciiStrDecimalToUintn (Str); + + Str = AsciiStrStr (Str, "."); + if (Str == NULL) { + return EFI_DEVICE_ERROR; + } + + ServerIp->v4.Addr[1] = (UINT8)AsciiStrDecimalToUintn (++Str); + + Str = AsciiStrStr (Str, "."); + if (Str == NULL) { + return EFI_DEVICE_ERROR; + } + + ServerIp->v4.Addr[2] = (UINT8)AsciiStrDecimalToUintn (++Str); + + Str = AsciiStrStr (Str, "."); + if (Str == NULL) { + return EFI_DEVICE_ERROR; + } + + ServerIp->v4.Addr[3] = (UINT8)AsciiStrDecimalToUintn (++Str); + + return EFI_SUCCESS; +} + + +/** + Internal work function to extract a device number from a string skipping + text. Easy way to extract numbers from strings like blk7:. + + @param Str String to extract device number form + + @return -1 Device string is not valid + @return Device # + +**/ +UINTN +EblConvertDevStringToNumber ( + IN CHAR8 *Str + ) +{ + UINTN Max; + UINTN Index; + + + // Find the first digit + Max = AsciiStrLen (Str); + for (Index = 0; !((*Str >= '0') && (*Str <= '9')) && (Index < Max); Index++) { + Str++; + } + if (Index == Max) { + return (UINTN)-1; + } + + return AsciiStrDecimalToUintn (Str); +} + + +/** + Internal work function to fill in EFI_OPEN_FILE information for the Fs and BlkIo + + @param File Open file handle + @param FileName Name of file after device stripped off + + +**/ +EFI_STATUS +EblFileDevicePath ( + IN OUT EFI_OPEN_FILE *File, + IN CHAR8 *FileName, + IN CONST UINT64 OpenMode + ) +{ + EFI_STATUS Status; + UINTN Size; + FILEPATH_DEVICE_PATH *FilePath; + EFI_DEVICE_PATH_PROTOCOL *FileDevicePath; + CHAR16 UnicodeFileName[MAX_PATHNAME]; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs; + EFI_FILE_HANDLE Root; + + + if ( *FileName != 0 ) { + AsciiStrToUnicodeStr (FileName, UnicodeFileName); + } else { + AsciiStrToUnicodeStr ("\\", UnicodeFileName); + } + + Size = StrSize (UnicodeFileName); + FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + sizeof (EFI_DEVICE_PATH_PROTOCOL)); + if (FileDevicePath != NULL) { + FilePath = (FILEPATH_DEVICE_PATH *) FileDevicePath; + FilePath->Header.Type = MEDIA_DEVICE_PATH; + FilePath->Header.SubType = MEDIA_FILEPATH_DP; + CopyMem (&FilePath->PathName, UnicodeFileName, Size); + SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH); + SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header)); + + if (File->EfiHandle != NULL) { + File->DevicePath = DevicePathFromHandle (File->EfiHandle); + } + + File->DevicePath = AppendDevicePath (File->DevicePath, FileDevicePath); + FreePool (FileDevicePath); + } + + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiBlockIoProtocolGuid, (VOID **)&BlkIo); + if (!EFI_ERROR (Status)) { + CopyMem (&File->FsBlockIoMedia, BlkIo->Media, sizeof (EFI_BLOCK_IO_MEDIA)); + + // If we are not opening the device this will get over written with file info + File->MaxPosition = MultU64x32 (BlkIo->Media->LastBlock + 1, BlkIo->Media->BlockSize); + } + + if (File->Type == EfiOpenFileSystem) { + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs); + if (!EFI_ERROR (Status)) { + Status = Fs->OpenVolume (Fs, &Root); + if (!EFI_ERROR (Status)) { + // Get information about the volume + Size = 0; + Status = Root->GetInfo (Root, &gEfiFileSystemInfoGuid, &Size, File->FsInfo); + if (Status == EFI_BUFFER_TOO_SMALL) { + File->FsInfo = AllocatePool (Size); + Status = Root->GetInfo (Root, &gEfiFileSystemInfoGuid, &Size, File->FsInfo); + } + + // Get information about the file + Status = Root->Open (Root, &File->FsFileHandle, UnicodeFileName, OpenMode, 0); + if (!EFI_ERROR (Status)) { + Size = 0; + Status = File->FsFileHandle->GetInfo (File->FsFileHandle, &gEfiFileInfoGuid, &Size, NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { + File->FsFileInfo = AllocatePool (Size); + Status = File->FsFileHandle->GetInfo (File->FsFileHandle, &gEfiFileInfoGuid, &Size, File->FsFileInfo); + if (!EFI_ERROR (Status)) { + File->Size = (UINTN)File->FsFileInfo->FileSize; + File->MaxPosition = (UINT64)File->Size; + } + } + } + + Root->Close (Root); + } + } + } else if (File->Type == EfiOpenBlockIo) { + File->Size = (UINTN)File->MaxPosition; + } + + return Status; +} + +#define ToUpper(a) ((((a) >= 'a') && ((a) <= 'z')) ? ((a) - 'a' + 'A') : (a)) + +EFI_STATUS +CompareGuidToString ( + IN EFI_GUID *Guid, + IN CHAR8 *String + ) +{ + CHAR8 AsciiGuid[64]; + CHAR8 *StringPtr; + CHAR8 *GuidPtr; + + AsciiSPrint (AsciiGuid, sizeof(AsciiGuid), "%g", Guid); + + StringPtr = String; + GuidPtr = AsciiGuid; + + while ((*StringPtr != '\0') && (*GuidPtr != '\0')) { + // Skip dashes + if (*StringPtr == '-') { + StringPtr++; + continue; + } + + if (*GuidPtr == '-') { + GuidPtr++; + continue; + } + + if (ToUpper(*StringPtr) != ToUpper(*GuidPtr)) { + return EFI_NOT_FOUND; + } + + StringPtr++; + GuidPtr++; + } + + return EFI_SUCCESS; +} + + +/** + Internal work function to fill in EFI_OPEN_FILE information for the FV + + @param File Open file handle + @param FileName Name of file after device stripped off + + +**/ +EFI_STATUS +EblFvFileDevicePath ( + IN OUT EFI_OPEN_FILE *File, + IN CHAR8 *FileName, + IN CONST UINT64 OpenMode + ) +{ + EFI_STATUS Status; + EFI_STATUS GetNextFileStatus; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH DevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN Key; + UINT32 AuthenticationStatus; + CHAR8 AsciiSection[MAX_PATHNAME]; + VOID *Section; + UINTN SectionSize; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_LBA Lba; + UINTN BlockSize; + UINTN NumberOfBlocks; + + + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&File->Fv); + if (EFI_ERROR (Status)) { + return Status; + } + + DevicePath = DevicePathFromHandle (File->EfiHandle); + + if (*FileName == '\0') { + File->DevicePath = DuplicateDevicePath (DevicePath); + } else { + Key = 0; + do { + File->FvType = EFI_FV_FILETYPE_ALL; + GetNextFileStatus = File->Fv->GetNextFile ( + File->Fv, + &Key, + &File->FvType, + &File->FvNameGuid, + &File->FvAttributes, + &File->Size + ); + if (!EFI_ERROR (GetNextFileStatus)) { + Section = NULL; + + // Compare GUID first + Status = CompareGuidToString (&File->FvNameGuid, FileName); + if (!EFI_ERROR(Status)) { + break; + } + + Status = File->Fv->ReadSection ( + File->Fv, + &File->FvNameGuid, + EFI_SECTION_USER_INTERFACE, + 0, + &Section, + &SectionSize, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + UnicodeStrToAsciiStr (Section, AsciiSection); + if (AsciiStriCmp (FileName, AsciiSection) == 0) { + FreePool (Section); + break; + } + FreePool (Section); + } + } + } while (!EFI_ERROR (GetNextFileStatus)); + + if (EFI_ERROR (GetNextFileStatus)) { + return GetNextFileStatus; + } + + File->MaxPosition = File->Size; + EfiInitializeFwVolDevicepathNode (&DevicePathNode, &File->FvNameGuid); + File->DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&DevicePathNode); + } + + + // Get FVB Info about the handle + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb); + if (!EFI_ERROR (Status)) { + Status = Fvb->GetPhysicalAddress (Fvb, &File->FvStart); + if (!EFI_ERROR (Status)) { + for (Lba = 0, File->FvSize = 0; ; File->FvSize += (BlockSize * NumberOfBlocks), Lba += NumberOfBlocks) { + Status = Fvb->GetBlockSize (Fvb, Lba, &BlockSize, &NumberOfBlocks); + if (EFI_ERROR (Status)) { + break; + } + } + } + } + + // FVB not required if FV was soft loaded... + return EFI_SUCCESS; +} + + + + +/** + Open a device named by PathName. The PathName includes a device name and + path seperated 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 + secitons 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 Status; + EFI_OPEN_FILE *File; + EFI_OPEN_FILE FileData; + UINTN StrLen; + UINTN FileStart; + UINTN DevNumber = 0; + EFI_OPEN_FILE_GUARD *GuardFile; + BOOLEAN VolumeNameMatch; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN Size; + EFI_IP_ADDRESS Ip; + + EblUpdateDeviceLists (); + + File = &FileData; + ZeroMem (File, sizeof (EFI_OPEN_FILE)); + File->FvSectionType = SectionType; + + StrLen = AsciiStrSize (PathName); + if (StrLen <= 2) { + // Smallest valid path is 1 char and a null + return NULL; + } + + for (FileStart = 0; FileStart < StrLen; FileStart++) { + if (PathName[FileStart] == ':') { + FileStart++; + break; + } + } + + if (FileStart == 0) { + // We could add a current working diretory concept + return NULL; + } + + // + // Matching volume name has precedence over handle based names + // + VolumeNameMatch = EblMatchVolumeName (PathName, FileStart, &DevNumber); + if (!VolumeNameMatch) { + DevNumber = EblConvertDevStringToNumber ((CHAR8 *)PathName); + } + + File->DeviceName = AllocatePool (StrLen); + AsciiStrCpy (File->DeviceName, PathName); + File->DeviceName[FileStart - 1] = '\0'; + File->FileName = &File->DeviceName[FileStart]; + + // + // Use best match algorithm on the dev names so we only need to look at the + // first few charters to match the full device name. Short name forms are + // legal from the caller. + // + Status = EFI_SUCCESS; + if (*PathName == 'f' || *PathName == 'F' || VolumeNameMatch) { + if (PathName[1] == 's' || PathName[1] == 'S' || VolumeNameMatch) { + if (DevNumber >= mFsCount) { + goto ErrorExit; + } + File->Type = EfiOpenFileSystem; + File->EfiHandle = mFs[DevNumber]; + Status = EblFileDevicePath (File, &PathName[FileStart], OpenMode); + + } else if (PathName[1] == 'v' || PathName[1] == 'V') { + if (DevNumber >= mFvCount) { + goto ErrorExit; + } + File->Type = EfiOpenFirmwareVolume; + File->EfiHandle = mFv[DevNumber]; + + if ((PathName[FileStart] == '/') || (PathName[FileStart] == '\\')) { + // Skip leading / as its not really needed for the FV since no directories are supported + FileStart++; + } + Status = EblFvFileDevicePath (File, &PathName[FileStart], OpenMode); + } + } else if ((*PathName == 'A') || (*PathName == 'a')) { + // Handle a:0x10000000:0x1234 address form a:ADDRESS:SIZE + File->Type = EfiOpenMemoryBuffer; + // 1st colon is at PathName[FileStart - 1] + File->Buffer = (VOID *)AsciiStrHexToUintn (&PathName[FileStart]); + + // Find 2nd colon + while ((PathName[FileStart] != ':') && (PathName[FileStart] != '\0')) { + FileStart++; + } + + // If we ran out of string, there's no extra data + if (PathName[FileStart] == '\0') { + File->Size = 0; + } else { + File->Size = AsciiStrHexToUintn (&PathName[FileStart + 1]); + } + + // if there's no number after the second colon, default + // the end of memory + if (File->Size == 0) { + File->Size = (UINTN)(0 - (UINTN)File->Buffer); + } + + File->MaxPosition = File->Size; + File->BaseOffset = (UINTN)File->Buffer; + + } else if (*PathName== 'l' || *PathName == 'L') { + if (DevNumber >= mLoadFileCount) { + goto ErrorExit; + } + File->Type = EfiOpenLoadFile; + File->EfiHandle = mLoadFile[DevNumber]; + + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiLoadFileProtocolGuid, (VOID **)&File->LoadFile); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + File->DevicePath = DuplicateDevicePath (DevicePath); + + } else if (*PathName == 'b' || *PathName == 'B') { + // Handle b#:0x10000000:0x1234 address form b#:ADDRESS:SIZE + if (DevNumber >= mBlkIoCount) { + goto ErrorExit; + } + File->Type = EfiOpenBlockIo; + File->EfiHandle = mBlkIo[DevNumber]; + EblFileDevicePath (File, "", OpenMode); + + // 1st colon is at PathName[FileStart - 1] + File->DiskOffset = AsciiStrHexToUintn (&PathName[FileStart]); + + // Find 2nd colon + while ((PathName[FileStart] != ':') && (PathName[FileStart] != '\0')) { + FileStart++; + } + + // If we ran out of string, there's no extra data + if (PathName[FileStart] == '\0') { + Size = 0; + } else { + Size = AsciiStrHexToUintn (&PathName[FileStart + 1]); + } + + // if a zero size is passed in (or the size is left out entirely), + // go to the end of the device. + if (Size == 0) { + File->Size = File->Size - File->DiskOffset; + } else { + File->Size = Size; + } + + File->MaxPosition = File->Size; + File->BaseOffset = File->DiskOffset; + } else if ((*PathName) >= '0' && (*PathName <= '9')) { + + // Get current IP address + Status = EblGetCurrentIpAddress (&Ip); + if (EFI_ERROR(Status)) { + AsciiPrint("Device IP Address is not configured.\n"); + goto ErrorExit; + } + + + // Parse X.X.X.X:Filename, only support IPv4 TFTP for now... + File->Type = EfiOpenTftp; + File->IsDirty = FALSE; + File->IsBufferValid = FALSE; + + Status = ConvertIpStringToEfiIp (PathName, &File->ServerIp); + } + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + GuardFile = (EFI_OPEN_FILE_GUARD *)AllocateZeroPool (sizeof (EFI_OPEN_FILE_GUARD)); + if (GuardFile == NULL) { + goto ErrorExit; + } + + GuardFile->Header = EFI_OPEN_FILE_GUARD_HEADER; + CopyMem (&(GuardFile->File), &FileData, sizeof (EFI_OPEN_FILE)); + GuardFile->Footer = EFI_OPEN_FILE_GUARD_FOOTER; + + return &(GuardFile->File); + +ErrorExit: + FreePool (File->DeviceName); + return NULL; +} + +#define FILE_COPY_CHUNK 0x01000000 + +EFI_STATUS +EfiCopyFile ( + IN CHAR8 *DestinationFile, + IN CHAR8 *SourceFile + ) +{ + EFI_OPEN_FILE *Source = NULL; + EFI_OPEN_FILE *Destination = NULL; + EFI_STATUS Status = EFI_SUCCESS; + VOID *Buffer = NULL; + UINTN Size; + UINTN Offset; + UINTN Chunk = FILE_COPY_CHUNK; + + Source = EfiOpen(SourceFile, EFI_FILE_MODE_READ, 0); + if (Source == NULL) { + AsciiPrint("Source file open error.\n"); + Status = EFI_NOT_FOUND; + goto Exit; + } + + Destination = EfiOpen(DestinationFile, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); + if (Destination == NULL) { + AsciiPrint("Destination file open error.\n"); + Status = EFI_NOT_FOUND; + goto Exit; + } + + Buffer = AllocatePool(FILE_COPY_CHUNK); + if (Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + Size = EfiTell(Source, NULL); + + for (Offset = 0; Offset + FILE_COPY_CHUNK <= Size; Offset += Chunk) { + Chunk = FILE_COPY_CHUNK; + + Status = EfiRead(Source, Buffer, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("Read file error\n"); + goto Exit; + } + + Status = EfiWrite(Destination, Buffer, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("Write file error\n"); + goto Exit; + } + } + + // Any left over? + if (Offset < Size) { + Chunk = Size - Offset; + + Status = EfiRead(Source, Buffer, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("Read file error\n"); + goto Exit; + } + + Status = EfiWrite(Destination, Buffer, &Chunk); + if (EFI_ERROR(Status)) { + AsciiPrint("Write file error\n"); + goto Exit; + } + } + +Exit: + if (Source != NULL) { + Status = EfiClose(Source); + if (EFI_ERROR(Status)) { + AsciiPrint("Source close error"); + } + } + + if (Destination != NULL) { + Status = EfiClose(Destination); + if (EFI_ERROR(Status)) { + AsciiPrint("Destination close error"); + } + } + + if (Buffer != NULL) { + FreePool(Buffer); + } + + return Status; +} + +/** + 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 + ) +{ + CHAR8 *DevStr; + CHAR8 Path[MAX_CMD_LINE]; + + switch (DeviceType) { + case EfiOpenLoadFile: + DevStr = "loadfile%d:"; + break; + case EfiOpenFirmwareVolume: + DevStr = "fv%d:"; + break; + case EfiOpenFileSystem: + DevStr = "fs%d:"; + break; + case EfiOpenBlockIo: + DevStr = "blk%d:"; + break; + case EfiOpenMemoryBuffer: + DevStr = "a%d:"; + break; + default: + return NULL; + } + + AsciiSPrint (Path, MAX_PATHNAME, DevStr, Index); + + return EfiOpen (Path, EFI_FILE_MODE_READ, 0); +} + + +/** + 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 *File + ) +{ + EFI_STATUS Status; + UINT64 TftpBufferSize; + + if (!FileHandleValid (File)) { + return EFI_INVALID_PARAMETER; + } + + //Write the buffer contents to TFTP file. + if ((File->Type == EfiOpenTftp) && (File->IsDirty)) { + + TftpBufferSize = File->Size; + Status = EblMtftp ( + EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, + File->Buffer, + TRUE, + &TftpBufferSize, + NULL, + &File->ServerIp, + (UINT8 *)File->FileName, + NULL, + FALSE + ); + if (EFI_ERROR(Status)) { + AsciiPrint("TFTP error during APPLE_NSP_TFTP_WRITE_FILE: %r\n", Status); + return Status; + } + } + + if ((File->Type == EfiOpenLoadFile) || + ((File->Type == EfiOpenTftp) && (File->IsBufferValid == TRUE))) { + EblFreePool(File->Buffer); + } + + EblFreePool (File->DevicePath); + EblFreePool (File->DeviceName); + EblFreePool (File->FsFileInfo); + EblFreePool (File->FsInfo); + + if (File->FsFileHandle != NULL) { + File->FsFileHandle->Close (File->FsFileHandle); + } + + // Need to free File and it's Guard structures + EblFreePool (BASE_CR (File, EFI_OPEN_FILE_GUARD, File)); + return EFI_SUCCESS; +} + + +/** + 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 *File, + OUT EFI_LBA *CurrentPosition OPTIONAL + ) +{ + EFI_STATUS Status; + UINT64 BufferSize = 0; + + if (!FileHandleValid (File)) { + return 0; + } + + if (CurrentPosition != NULL) { + *CurrentPosition = File->CurrentPosition; + } + + if (File->Type == EfiOpenLoadFile) { + // Figure out the File->Size + File->Buffer = NULL; + File->Size = 0; + Status = File->LoadFile->LoadFile (File->LoadFile, File->DevicePath, FALSE, &File->Size, File->Buffer); + if (Status != EFI_BUFFER_TOO_SMALL) { + return 0; + } + + File->MaxPosition = (UINT64)File->Size; + } else if (File->Type == EfiOpenTftp) { + + Status = EblMtftp ( + EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, + NULL, + FALSE, + &BufferSize, + NULL, + &File->ServerIp, + (UINT8 *)File->FileName, + NULL, + TRUE + ); + if (EFI_ERROR(Status)) { + AsciiPrint("TFTP error during APPLE_NSP_TFTP_GET_FILE_SIZE: %r\n", Status); + return 0; + } + + File->Size = BufferSize; + File->MaxPosition = File->Size; + } + + return File->Size; +} + + +/** + Seek to the Offset locaiton 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 doe 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 *File, + IN EFI_LBA Offset, + IN EFI_SEEK_TYPE SeekType + ) +{ + EFI_STATUS Status; + UINT64 CurrentPosition; + + if (!FileHandleValid (File)) { + return EFI_INVALID_PARAMETER; + } + + if (File->Type == EfiOpenLoadFile || File->Type == EfiOpenFirmwareVolume) { + // LoadFile and FV do not support Seek + return EFI_UNSUPPORTED; + } + + CurrentPosition = File->CurrentPosition; + switch (SeekType) { + case EfiSeekStart: + if (Offset > File->MaxPosition) { + return EFI_NOT_FOUND; + } + CurrentPosition = Offset; + break; + + case EfiSeekCurrent: + if ((File->CurrentPosition + Offset) > File->MaxPosition) { + return EFI_NOT_FOUND; + } + CurrentPosition += Offset; + break; + + case EfiSeekEnd: + if (Offset != 0) { + // We don't support growing file size via seeking past end of file + return EFI_UNSUPPORTED; + } + CurrentPosition = File->MaxPosition; + break; + + default: + return EFI_NOT_FOUND; + } + + Status = EFI_SUCCESS; + if (File->FsFileHandle != NULL) { + Status = File->FsFileHandle->SetPosition (File->FsFileHandle, CurrentPosition); + } + + if (!EFI_ERROR (Status)) { + File->CurrentPosition = CurrentPosition; + } + + return Status; +} + +EFI_STATUS +CacheTftpFile ( + IN OUT EFI_OPEN_FILE *File + ) +{ + EFI_STATUS Status; + UINT64 TftpBufferSize; + + if (File->IsBufferValid) { + return EFI_SUCCESS; + } + + // Make sure the file size is set. + EfiTell (File, NULL); + + //Allocate a buffer to hold the whole file. + File->Buffer = AllocatePool(File->Size); + if (File->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TftpBufferSize = File->Size; + + Status = EblMtftp ( + EFI_PXE_BASE_CODE_TFTP_READ_FILE, + File->Buffer, + FALSE, + &TftpBufferSize, + NULL, + &File->ServerIp, + (UINT8 *)File->FileName, + NULL, + FALSE); + if (EFI_ERROR(Status)) { + AsciiPrint("TFTP error during APPLE_NSP_TFTP_READ_FILE: %r\n", Status); + FreePool(File->Buffer); + return Status; + } + + // Set the buffer valid flag. + File->IsBufferValid = TRUE; + + return Status; +} + +/** + Read BufferSize bytes from the current locaiton in the file. For load file, + FV, and TFTP 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 *File, + OUT VOID *Buffer, + OUT UINTN *BufferSize + ) +{ + EFI_STATUS Status; + UINT32 AuthenticationStatus; + EFI_DISK_IO_PROTOCOL *DiskIo; + + if (!FileHandleValid (File)) { + return EFI_INVALID_PARAMETER; + } + + // Don't read past the end of the file. + if ((File->CurrentPosition + *BufferSize) > File->MaxPosition) { + return EFI_END_OF_FILE; + } + + switch (File->Type) { + case EfiOpenMemoryBuffer: + CopyMem (Buffer, File->Buffer + File->CurrentPosition, *BufferSize); + File->CurrentPosition += *BufferSize; + Status = EFI_SUCCESS; + break; + + case EfiOpenLoadFile: + // Figure out the File->Size + EfiTell (File, NULL); + + Status = File->LoadFile->LoadFile (File->LoadFile, File->DevicePath, FALSE, BufferSize, Buffer); + break; + + case EfiOpenFirmwareVolume: + if (File->FvSectionType == EFI_SECTION_ALL) { + Status = File->Fv->ReadFile ( + File->Fv, + &File->FvNameGuid, + &Buffer, + BufferSize, + &File->FvType, + &File->FvAttributes, + &AuthenticationStatus + ); + } else { + Status = File->Fv->ReadSection ( + File->Fv, + &File->FvNameGuid, + File->FvSectionType, + 0, + &Buffer, + BufferSize, + &AuthenticationStatus + ); + } + break; + + case EfiOpenFileSystem: + Status = File->FsFileHandle->Read (File->FsFileHandle, BufferSize, Buffer); + File->CurrentPosition += *BufferSize; + break; + + case EfiOpenBlockIo: + Status = gBS->HandleProtocol(File->EfiHandle, &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo); + if (!EFI_ERROR(Status)) { + Status = DiskIo->ReadDisk(DiskIo, File->FsBlockIoMedia.MediaId, File->DiskOffset + File->CurrentPosition, *BufferSize, Buffer); + } + File->CurrentPosition += *BufferSize; + break; + + case EfiOpenTftp: + // Cache the file if it hasn't been cached yet. + if (File->IsBufferValid == FALSE) { + Status = CacheTftpFile (File); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // Copy out the requested data + CopyMem (Buffer, File->Buffer + File->CurrentPosition, *BufferSize); + File->CurrentPosition += *BufferSize; + + Status = EFI_SUCCESS; + break; + + default: + return EFI_INVALID_PARAMETER; + }; + + return Status; +} + + +/** + 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 flie 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 *File, + OUT VOID **Buffer, + OUT UINTN *BufferSize + ) +{ + if (!FileHandleValid (File)) { + return EFI_INVALID_PARAMETER; + } + + // Loadfile defers file size determination on Open so use tell to find it + EfiTell (File, NULL); + + *BufferSize = File->Size; + *Buffer = AllocatePool (*BufferSize); + if (*Buffer == NULL) { + return EFI_NOT_FOUND; + } + + return EfiRead (File, *Buffer, BufferSize); +} + + +/** + Write data back to the file. For TFTP case you must write the entire 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 *File, + OUT VOID *Buffer, + OUT UINTN *BufferSize + ) +{ + EFI_STATUS Status; + EFI_FV_WRITE_FILE_DATA FileData; + EFI_DISK_IO_PROTOCOL *DiskIo; + + if (!FileHandleValid (File)) { + return EFI_INVALID_PARAMETER; + } + + switch (File->Type) { + case EfiOpenMemoryBuffer: + if ((File->CurrentPosition + *BufferSize) > File->MaxPosition) { + return EFI_END_OF_FILE; + } + + CopyMem (File->Buffer + File->CurrentPosition, Buffer, *BufferSize); + File->CurrentPosition += *BufferSize; + Status = EFI_SUCCESS; + + case EfiOpenLoadFile: + // LoadFile device is read only be definition + Status = EFI_UNSUPPORTED; + + case EfiOpenFirmwareVolume: + if (File->FvSectionType != EFI_SECTION_ALL) { + // Writes not support to a specific section. You have to update entire file + return EFI_UNSUPPORTED; + } + + FileData.NameGuid = &(File->FvNameGuid); + FileData.Type = File->FvType; + FileData.FileAttributes = File->FvAttributes; + FileData.Buffer = Buffer; + FileData.BufferSize = (UINT32)*BufferSize; + Status = File->Fv->WriteFile (File->Fv, 1, EFI_FV_UNRELIABLE_WRITE, &FileData); + break; + + case EfiOpenFileSystem: + Status = File->FsFileHandle->Write (File->FsFileHandle, BufferSize, Buffer); + File->CurrentPosition += *BufferSize; + break; + + case EfiOpenBlockIo: + if ((File->CurrentPosition + *BufferSize) > File->MaxPosition) { + return EFI_END_OF_FILE; + } + + Status = gBS->HandleProtocol (File->EfiHandle, &gEfiDiskIoProtocolGuid, (VOID **)&DiskIo); + if (!EFI_ERROR(Status)) { + Status = DiskIo->WriteDisk (DiskIo, File->FsBlockIoMedia.MediaId, File->DiskOffset + File->CurrentPosition, *BufferSize, Buffer); + } + File->CurrentPosition += *BufferSize; + break; + + case EfiOpenTftp: + // Cache the file if it hasn't been cached yet. + if (File->IsBufferValid == FALSE) { + Status = CacheTftpFile(File); + if (EFI_ERROR(Status)) { + return Status; + } + } + + // Don't overwrite the buffer + if ((File->CurrentPosition + *BufferSize) > File->MaxPosition) { + UINT8 *TempBuffer; + + TempBuffer = File->Buffer; + + File->Buffer = AllocatePool (File->CurrentPosition + *BufferSize); + if (File->Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (File->Buffer, TempBuffer, File->Size); + + FreePool (TempBuffer); + + File->Size = File->CurrentPosition + *BufferSize; + File->MaxPosition = File->Size; + } + + // Copy in the requested data + CopyMem (File->Buffer + File->CurrentPosition, Buffer, *BufferSize); + File->CurrentPosition += *BufferSize; + + // Mark the file dirty + File->IsDirty = TRUE; + + Status = EFI_SUCCESS; + break; + + default: + Status = EFI_INVALID_PARAMETER; + }; + + return Status; +} + diff --git a/EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf b/EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf new file mode 100644 index 0000000000..a69fb0c423 --- /dev/null +++ b/EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf @@ -0,0 +1,64 @@ +#%HEADER% +#/** @file +# Component description file for the entry point to a EFIDXE Drivers +# +# Library to abstract Framework extensions that conflict with UEFI 2.0 Specification +# Copyright (c) 2007 - 2007, Intel Corporation +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = EfiFileLib + FILE_GUID = d8c640db-73ba-48f5-a7ed-8e93c6012491 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = EfiFileLib|DXE_DRIVER UEFI_APPLICATION UEFI_DRIVER + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + EfiFileLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + BaseLib + MemoryAllocationLib + DevicePathLib + PrintLib + BaseMemoryLib + UefiLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DebugLib + EblNetworkLib + +[Protocols] + gEfiBlockIoProtocolGuid # PROTOCOL SOMETIMES_CONSUMED + gEfiDiskIoProtocolGuid # PROTOCOL SOMETIMES_CONSUMED + gEfiSimpleFileSystemProtocolGuid # PROTOCOL SOMETIMES_CONSUMED + gEfiFirmwareVolume2ProtocolGuid # PROTOCOL SOMETIMES_CONSUMED + gEfiLoadFileProtocolGuid # PROTOCOL SOMETIMES_CONSUMED + gEfiFirmwareVolumeBlockProtocolGuid # PROTOCOL SOMETIMES_CONSUMED + +[Guids] + gEfiFileInfoGuid + gEfiFileSystemInfoGuid diff --git a/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c b/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c new file mode 100644 index 0000000000..ef5a2f2a7f --- /dev/null +++ b/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c @@ -0,0 +1,187 @@ +/** @file + Basic serial IO abstaction for GDB + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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/receice 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 + vaule 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 coonfigured. + +**/ +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 availible + @return FALSE - Character not availible + +**/ +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/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf b/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf new file mode 100644 index 0000000000..42a7caaa91 --- /dev/null +++ b/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf @@ -0,0 +1,50 @@ +#%HEADER% +#/** @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. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[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/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c b/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c new file mode 100644 index 0000000000..62d8636456 --- /dev/null +++ b/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c @@ -0,0 +1,262 @@ +/** @file + Basic serial IO abstaction for GDB + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 0x20 +#define LSR_RXDA 0x01 +#define DLAB 0x01 +#define ENABLE_FIFO 0x01 +#define CLEAR_FIFOS 0x06 + + + +// 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/receice 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 + vaule 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 coonfigured. + +**/ +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 availible + @return FALSE - Character not availible + +**/ +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/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf b/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf new file mode 100644 index 0000000000..0c8d0e6a69 --- /dev/null +++ b/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf @@ -0,0 +1,47 @@ +#%HEADER% +#/** @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. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[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/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Capsule.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Capsule.c new file mode 100644 index 0000000000..cbc48b2b0c --- /dev/null +++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Capsule.c @@ -0,0 +1,288 @@ +/** @file + Generic Capsule services + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + + +// +//Max size capsule services support are platform policy,to populate capsules we just need +//memory to maintain them across reset,it is not a problem. And to special capsules ,for +//example,update flash,it is mostly decided by the platform. Here is a sample size for +//different type capsules. +// +#define MAX_SIZE_POPULATE (0) +#define MAX_SIZE_NON_POPULATE (0) +#define MAX_SUPPORT_CAPSULE_NUM 0x10 + + +BOOLEAN +EFIAPI +SupportUpdateCapsuleRest ( + VOID + ) +{ + // + //If the platform has a way to guarantee the memory integrity across a system reset, return + //TRUE, else FALSE. + // + return FALSE; +} + + + +VOID +EFIAPI +SupportCapsuleSize ( + IN OUT UINT32 *MaxSizePopulate, + IN OUT UINT32 *MaxSizeNonPopulate + ) +{ + // + //Here is a sample size, different platforms have different sizes. + // + *MaxSizePopulate = MAX_SIZE_POPULATE; + *MaxSizeNonPopulate = MAX_SIZE_NON_POPULATE; + return; +} + + + + +EFI_STATUS +LibUpdateCapsule ( + IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL + ) +/*++ + +Routine Description: + + This code finds if the capsule needs reset to update, if no, update immediately. + +Arguments: + + CapsuleHeaderArray A array of pointers to capsule headers passed in + CapsuleCount The number of capsule + ScatterGatherList Physical address of datablock list points to capsule + +Returns: + + EFI STATUS + EFI_SUCCESS Valid capsule was passed.If CAPSULE_FLAG_PERSIT_ACROSS_RESET is + not set, the capsule has been successfully processed by the firmware. + If it set, the ScattlerGatherList is successfully to be set. + EFI_INVALID_PARAMETER CapsuleCount is less than 1,CapsuleGuid is not supported. + EFI_DEVICE_ERROR Failed to SetVariable or AllocatePool or ProcessFirmwareVolume. + +--*/ +{ + UINTN CapsuleSize; + UINTN ArrayNumber; + VOID *BufferPtr; + EFI_STATUS Status; + EFI_HANDLE FvHandle; + UEFI_CAPSULE_HEADER *CapsuleHeader; + + if ((CapsuleCount < 1) || (CapsuleCount > MAX_SUPPORT_CAPSULE_NUM)){ + return EFI_INVALID_PARAMETER; + } + + BufferPtr = NULL; + CapsuleHeader = NULL; + + // + //Compare GUIDs with EFI_CAPSULE_GUID, if capsule header contains CAPSULE_FLAGS_PERSIST_ACROSS_RESET + //and CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flags,whatever the GUID is ,the service supports. + // + for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) { + CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; + if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) { + return EFI_INVALID_PARAMETER; + } + if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiCapsuleGuid)) { + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) { + return EFI_UNSUPPORTED; + } + } + } + + // + //Assume that capsules have the same flags on reseting or not. + // + CapsuleHeader = CapsuleHeaderArray[0]; + + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) { + // + //Check if the platform supports update capsule across a system reset + // + if (!SupportUpdateCapsuleRest()) { + return EFI_UNSUPPORTED; + } + + if (ScatterGatherList == 0) { + return EFI_INVALID_PARAMETER; + } else { + Status = EfiSetVariable ( + EFI_CAPSULE_VARIABLE_NAME, + &gEfiCapsuleVendorGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (UINTN), + (VOID *) &ScatterGatherList + ); + if (Status != EFI_SUCCESS) { + return EFI_DEVICE_ERROR; + } + } + return EFI_SUCCESS; + } + + // + //The rest occurs in the condition of non-reset mode + // + if (EfiAtRuntime ()) { + return EFI_INVALID_PARAMETER; + } + + // + //Here should be in the boot-time + // + for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) { + CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; + CapsuleSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize; + Status = gBS->AllocatePool (EfiBootServicesData, CapsuleSize, &BufferPtr); + if (Status != EFI_SUCCESS) { + goto Done; + } + gBS->CopyMem (BufferPtr, (UINT8*)CapsuleHeader+ CapsuleHeader->HeaderSize, CapsuleSize); + + // + //Call DXE service ProcessFirmwareVolume to process immediatelly + // + Status = gDS->ProcessFirmwareVolume (BufferPtr, CapsuleSize, &FvHandle); + if (Status != EFI_SUCCESS) { + gBS->FreePool (BufferPtr); + return EFI_DEVICE_ERROR; + } + gDS->Dispatch (); + gBS->FreePool (BufferPtr); + } + return EFI_SUCCESS; + +Done: + if (BufferPtr != NULL) { + gBS->FreePool (BufferPtr); + } + return EFI_DEVICE_ERROR; +} + + +EFI_STATUS +QueryCapsuleCapabilities ( + IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray, + IN UINTN CapsuleCount, + OUT UINT64 *MaxiumCapsuleSize, + OUT EFI_RESET_TYPE *ResetType + ) +/*++ + +Routine Description: + + This code is query about capsule capability. + +Arguments: + + CapsuleHeaderArray A array of pointers to capsule headers passed in + CapsuleCount The number of capsule + MaxiumCapsuleSize Max capsule size is supported + ResetType Reset type the capsule indicates, if reset is not needed,return EfiResetCold. + If reset is needed, return EfiResetWarm. + +Returns: + + EFI STATUS + EFI_SUCCESS Valid answer returned + EFI_INVALID_PARAMETER MaxiumCapsuleSize is NULL,ResetType is NULL.CapsuleCount is less than 1,CapsuleGuid is not supported. + EFI_UNSUPPORTED The capsule type is not supported. + +--*/ +{ + UINTN ArrayNumber; + UEFI_CAPSULE_HEADER *CapsuleHeader; + UINT32 MaxSizePopulate; + UINT32 MaxSizeNonPopulate; + + + if ((CapsuleCount < 1) || (CapsuleCount > MAX_SUPPORT_CAPSULE_NUM)){ + return EFI_INVALID_PARAMETER; + } + + if ((MaxiumCapsuleSize == NULL) ||(ResetType == NULL)) { + return EFI_INVALID_PARAMETER; + } + + CapsuleHeader = NULL; + + // + //Compare GUIDs with EFI_CAPSULE_GUID, if capsule header contains CAPSULE_FLAGS_PERSIST_ACROSS_RESET + //and CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flags,whatever the GUID is ,the service supports. + // + for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) { + CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; + if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) { + return EFI_INVALID_PARAMETER; + } + if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiCapsuleGuid)) { + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) { + return EFI_UNSUPPORTED; + } + } + } + + SupportCapsuleSize(&MaxSizePopulate,&MaxSizeNonPopulate); + // + //Assume that capsules have the same flags on reseting or not. + // + CapsuleHeader = CapsuleHeaderArray[0]; + if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) { + // + //Check if the platform supports update capsule across a system reset + // + if (!SupportUpdateCapsuleRest()) { + return EFI_UNSUPPORTED; + } + *ResetType = EfiResetWarm; + *MaxiumCapsuleSize = MaxSizePopulate; + } else { + *ResetType = EfiResetCold; + *MaxiumCapsuleSize = MaxSizeNonPopulate; + } + return EFI_SUCCESS; +} + + +VOID +LibCapsuleVirtualAddressChangeEvent ( + VOID + ) +{ +} + +VOID +LibCapsuleInitialize ( + VOID + ) +{ +} diff --git a/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Mtc.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Mtc.c new file mode 100644 index 0000000000..8e8f2dbf24 --- /dev/null +++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Mtc.c @@ -0,0 +1,226 @@ +/** @file + Generic Monotonic Counter services + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + + +// +// The current Monotonic count value +// +UINT64 mEfiMtc = 0; + + +// +// Event to use to update the Mtc's high part when wrapping +// +EFI_EVENT mEfiMtcEvent; + +// +// EfiMtcName - Variable name of the MTC value +// +CHAR16 *mEfiMtcName = L"MTC"; + +// +// EfiMtcGuid - Guid of the MTC value +// +EFI_GUID mEfiMtcGuid = { 0xeb704011, 0x1402, 0x11d3, { 0x8e, 0x77, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } }; + + + +// +// Worker functions +// + + +VOID +EFIAPI +EfiMtcEventHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Monotonic count event handler. This handler updates the high monotonic count. + +Arguments: + + Event The event to handle + Context The event context + +Returns: + + EFI_SUCCESS The event has been handled properly + EFI_NOT_FOUND An error occurred updating the variable. + +--*/ +{ + UINT32 HighCount; + + EfiGetNextHighMonotonicCount (&HighCount); + return; +} + + + +VOID +LibMtcVirtualAddressChangeEvent (VOID) +{ +} + + +EFI_STATUS +EFIAPI +LibMtcGetNextHighMonotonicCount ( + OUT UINT32 *HighCount + ) +{ + EFI_STATUS Status; + EFI_TPL OldTpl; + + // + // Check input parameters + // + if (HighCount == NULL) { + return EFI_INVALID_PARAMETER; + } + + + if (!EfiAtRuntime ()) { + // Use a lock if called before ExitBootServices() + OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); + } + + *HighCount = (UINT32) RShiftU64 (mEfiMtc, 32) + 1; + mEfiMtc = LShiftU64 (*HighCount, 32); + + if (!EfiAtRuntime ()) { + gBS->RestoreTPL (OldTpl); + } + + // + // Update the NvRam store to match the new high part + // + Status = EfiSetVariable ( + mEfiMtcName, + &mEfiMtcGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (UINT32), + HighCount + ); + + return Status; +} + + +EFI_STATUS +LibMtcGetNextMonotonicCount ( + OUT UINT64 *Count + ) +{ + EFI_STATUS Status; + EFI_TPL OldTpl; + UINT32 HighCount; + UINTN BufferSize; + + // + // Can not be called after ExitBootServices() + // + if (EfiAtRuntime ()) { + return EFI_UNSUPPORTED; + } + + // + // Check input parameters + // + if (Count == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (mEfiMtc == 0) { + // + // If the MTC has not been initialized read the variable + // + + // + // Read the last high part + // + BufferSize = sizeof (UINT32); + Status = EfiGetVariable ( + mEfiMtcName, + &mEfiMtcGuid, + NULL, + &BufferSize, + &HighCount + ); + if (EFI_ERROR (Status)) { + HighCount = 0; + } + + // + // Set the current value + // + mEfiMtc = LShiftU64 (HighCount, 32); + // + // Increment the upper 32 bits for this boot + // Continue even if it fails. It will only fail if the variable services are + // not functional. + // + Status = EfiGetNextHighMonotonicCount (&HighCount); + } + + + // + // Update the monotonic counter with a lock + // + OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); + *Count = mEfiMtc; + mEfiMtc++; + gBS->RestoreTPL (OldTpl); + + // + // If the MSB bit of the low part toggled, then signal that the high + // part needs updated now + // + if ((((UINT32) mEfiMtc) ^ ((UINT32) *Count)) & 0x80000000) { + gBS->SignalEvent (mEfiMtcEvent); + } + + return EFI_SUCCESS; +} + + + +VOID +LibMtcInitialize ( + VOID + ) +{ + EFI_STATUS Status; + + // + // Initialize event to handle overflows + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + EfiMtcEventHandler, + NULL, + &mEfiMtcEvent + ); + ASSERT_EFI_ERROR (Status); +} + diff --git a/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/ReportStatusCode.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/ReportStatusCode.c new file mode 100644 index 0000000000..f1953a89d8 --- /dev/null +++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/ReportStatusCode.c @@ -0,0 +1,198 @@ +/** @file + Report status code lib on top of either SerialLib and/or EFI Serial Protocol. + Based on PcdStatusCodeUseEfiSerial & PcdStatusCodeUseHardSerial settings + + There is just a single runtime memory buffer that contans all the data. + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +//////////#include "DxeStatusCode.h" + + +EFI_SERIAL_IO_PROTOCOL *mSerialIoProtocol = NULL; + + +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 + ) +{ + CHAR8 *Filename; + CHAR8 *Description; + CHAR8 *Format; + CHAR8 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE]; + UINT32 ErrorLevel; + UINT32 LineNumber; + UINTN CharCount; + VA_LIST Marker; + EFI_DEBUG_INFO *DebugInfo; + EFI_TPL CurrentTpl; + + + if (FeaturePcdGet (PcdStatusCodeUseEfiSerial)) { + if (EfiAtRuntime ()) { + return EFI_DEVICE_ERROR; + } + CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); + gBS->RestoreTPL (CurrentTpl); + + if (CurrentTpl > EFI_TPL_CALLBACK ) { + return EFI_DEVICE_ERROR; + } + } + + Buffer[0] = '\0'; + + if (Data != NULL && + ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) { + // + // Print ASSERT() information into output buffer. + // + CharCount = AsciiSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + "\n\rDXE_ASSERT!: %a (%d): %a\n\r", + Filename, + LineNumber, + Description + ); + } else if (Data != NULL && + ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) { + // + // Print DEBUG() information into output buffer. + // + CharCount = AsciiVSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + Format, + Marker + ); + } else if (Data != NULL && + CompareGuid (&Data->Type, &gEfiStatusCodeSpecificDataGuid) && + (CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) { + // + // Print specific data into output buffer. + // + DebugInfo = (EFI_DEBUG_INFO *) (Data + 1); + Marker = (VA_LIST) (DebugInfo + 1); + Format = (CHAR8 *) (((UINT64 *) (DebugInfo + 1)) + 12); + + CharCount = AsciiVSPrint (Buffer, EFI_STATUS_CODE_DATA_MAX_SIZE, Format, Marker); + } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) { + // + // Print ERROR information into output buffer. + // + CharCount = AsciiSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + "ERROR: C%x:V%x I%x", + CodeType, + Value, + Instance + ); + + // + // Make sure we don't try to print values that weren't + // intended to be printed, especially NULL GUID pointers. + // + + if (CallerId != NULL) { + CharCount += AsciiSPrint ( + &Buffer[CharCount - 1], + (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)), + " %g", + CallerId + ); + } + + if (Data != NULL) { + CharCount += AsciiSPrint ( + &Buffer[CharCount - 1], + (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)), + " %x", + Data + ); + } + + CharCount += AsciiSPrint ( + &Buffer[CharCount - 1], + (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)), + "\n\r" + ); + } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) { + CharCount = AsciiSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + "PROGRESS CODE: V%x I%x\n\r", + Value, + Instance + ); + } else { + CharCount = AsciiSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + "Undefined: C%x:V%x I%x\n\r", + CodeType, + Value, + Instance + ); + } + + + if (FeaturePcdGet (PcdStatusCodeUseHardSerial)) { + // + // Callout to SerialPort Lib function to do print. + // + SerialPortWrite ((UINT8 *) Buffer, CharCount); + } + if (FeaturePcdGet (PcdStatusCodeUseEfiSerial)) { + if (mSerialIoProtocol == NULL) { + gBS->LocateProtocol (&gEfiSerialIoProtocolGuid, NULL, (VOID **) &mSerialIoProtocol); + } + + if (mSerialIoProtocol == NULL) { + mSerialIoProtocol->Write ( + mSerialIoProtocol, + &CharCount, + Buffer + ); + } + } + + return EFI_SUCCESS; +} + + +VOID +LibReportStatusCodeVirtualAddressChangeEvent ( + VOID + ) +{ + return; +} + +VOID +LibReportStatusCodeInitialize ( + VOID + ) +{ + return; +} + + + diff --git a/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Reset.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Reset.c new file mode 100644 index 0000000000..8671971a22 --- /dev/null +++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Reset.c @@ -0,0 +1,63 @@ +/** @file + Simple PC Port 0x92 reset driver + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + + + +VOID +LibResetInitializeReset ( + VOID + ) +{ +} + +VOID +LibResetVirtualAddressChangeEvent ( + VOID + ) +{ +} + + +VOID +LibResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ) +{ + UINT8 Data; + + switch (ResetType) { + case EfiResetWarm: + case EfiResetCold: + case EfiResetShutdown: + Data = IoRead8 (0x92); + Data |= 1; + IoWrite8 (0x92, Data); + break; + + default: + return ; + } + + // + // Given we should have reset getting here would be bad + // + ASSERT (FALSE); +} + diff --git a/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c new file mode 100644 index 0000000000..bb87ba82be --- /dev/null +++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Rtc.c @@ -0,0 +1,861 @@ +/** @file + Simple PC RTC + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + + + +typedef struct { + EFI_LOCK RtcLock; + UINT16 SavedTimeZone; + UINT8 Daylight; +} PC_RTC_GLOBALS; + +#define PCAT_RTC_ADDRESS_REGISTER 0x70 +#define PCAT_RTC_DATA_REGISTER 0x71 + +// +// Dallas DS12C887 Real Time Clock +// +#define RTC_ADDRESS_SECONDS 0 // R/W Range 0..59 +#define RTC_ADDRESS_SECONDS_ALARM 1 // R/W Range 0..59 +#define RTC_ADDRESS_MINUTES 2 // R/W Range 0..59 +#define RTC_ADDRESS_MINUTES_ALARM 3 // R/W Range 0..59 +#define RTC_ADDRESS_HOURS 4 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM +#define RTC_ADDRESS_HOURS_ALARM 5 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM +#define RTC_ADDRESS_DAY_OF_THE_WEEK 6 // R/W Range 1..7 +#define RTC_ADDRESS_DAY_OF_THE_MONTH 7 // R/W Range 1..31 +#define RTC_ADDRESS_MONTH 8 // R/W Range 1..12 +#define RTC_ADDRESS_YEAR 9 // R/W Range 0..99 +#define RTC_ADDRESS_REGISTER_A 10 // R/W[0..6] R0[7] +#define RTC_ADDRESS_REGISTER_B 11 // R/W +#define RTC_ADDRESS_REGISTER_C 12 // RO +#define RTC_ADDRESS_REGISTER_D 13 // RO +#define RTC_ADDRESS_CENTURY 50 // R/W Range 19..20 Bit 8 is R/W +// +// Date and time initial values. +// They are used if the RTC values are invalid during driver initialization +// +#define RTC_INIT_SECOND 0 +#define RTC_INIT_MINUTE 0 +#define RTC_INIT_HOUR 0 +#define RTC_INIT_DAY 1 +#define RTC_INIT_MONTH 1 +#define RTC_INIT_YEAR 2001 + +// +// Register initial values +// +#define RTC_INIT_REGISTER_A 0x26 +#define RTC_INIT_REGISTER_B 0x02 +#define RTC_INIT_REGISTER_D 0x0 + +#pragma pack(1) +// +// Register A +// +typedef struct { + UINT8 RS : 4; // Rate Selection Bits + UINT8 DV : 3; // Divisor + UINT8 UIP : 1; // Update in progress +} RTC_REGISTER_A_BITS; + +typedef union { + RTC_REGISTER_A_BITS Bits; + UINT8 Data; +} RTC_REGISTER_A; + +// +// Register B +// +typedef struct { + UINT8 DSE : 1; // 0 - Daylight saving disabled 1 - Daylight savings enabled + UINT8 MIL : 1; // 0 - 12 hour mode 1 - 24 hour mode + UINT8 DM : 1; // 0 - BCD Format 1 - Binary Format + UINT8 SQWE : 1; // 0 - Disable SQWE output 1 - Enable SQWE output + UINT8 UIE : 1; // 0 - Update INT disabled 1 - Update INT enabled + UINT8 AIE : 1; // 0 - Alarm INT disabled 1 - Alarm INT Enabled + UINT8 PIE : 1; // 0 - Periodic INT disabled 1 - Periodic INT Enabled + UINT8 SET : 1; // 0 - Normal operation. 1 - Updates inhibited +} RTC_REGISTER_B_BITS; + +typedef union { + RTC_REGISTER_B_BITS Bits; + UINT8 Data; +} RTC_REGISTER_B; + +// +// Register C +// +typedef struct { + UINT8 Reserved : 4; // Read as zero. Can not be written. + UINT8 UF : 1; // Update End Interrupt Flag + UINT8 AF : 1; // Alarm Interrupt Flag + UINT8 PF : 1; // Periodic Interrupt Flag + UINT8 IRQF : 1; // Iterrupt Request Flag = PF & PIE | AF & AIE | UF & UIE +} RTC_REGISTER_C_BITS; + +typedef union { + RTC_REGISTER_C_BITS Bits; + UINT8 Data; +} RTC_REGISTER_C; + +// +// Register D +// +typedef struct { + UINT8 Reserved : 7; // Read as zero. Can not be written. + UINT8 VRT : 1; // Valid RAM and Time +} RTC_REGISTER_D_BITS; + +typedef union { + RTC_REGISTER_D_BITS Bits; + UINT8 Data; +} RTC_REGISTER_D; + +#pragma pack() + +PC_RTC_GLOBALS mRtc; + +BOOLEAN +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; + } +} + + +const INTN mDayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +BOOLEAN +DayValid ( + IN EFI_TIME *Time + ) +{ + if (Time->Day < 1 || + Time->Day > mDayOfMonth[Time->Month - 1] || + (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28)) + ) { + return FALSE; + } + + return TRUE; +} + + +UINT8 +DecimaltoBcd ( + IN UINT8 DecValue + ) +{ + UINTN High; + UINTN Low; + + High = DecValue / 10; + Low = DecValue - (High * 10); + + return (UINT8) (Low + (High << 4)); +} + +UINT8 +BcdToDecimal ( + IN UINT8 BcdValue + ) +{ + UINTN High; + UINTN Low; + + High = BcdValue >> 4; + Low = BcdValue - (High << 4); + + return (UINT8) (Low + (High * 10)); +} + + + + +VOID +ConvertEfiTimeToRtcTime ( + IN EFI_TIME *Time, + IN RTC_REGISTER_B RegisterB, + IN UINT8 *Century + ) +{ + BOOLEAN PM; + + PM = TRUE; + // + // Adjust hour field if RTC in in 12 hour mode + // + if (RegisterB.Bits.MIL == 0) { + if (Time->Hour < 12) { + PM = FALSE; + } + + if (Time->Hour >= 13) { + Time->Hour = (UINT8) (Time->Hour - 12); + } else if (Time->Hour == 0) { + Time->Hour = 12; + } + } + // + // Set the Time/Date/Daylight Savings values. + // + *Century = DecimaltoBcd ((UINT8) (Time->Year / 100)); + + Time->Year = (UINT16) (Time->Year % 100); + + if (RegisterB.Bits.DM == 0) { + Time->Year = DecimaltoBcd ((UINT8) Time->Year); + Time->Month = DecimaltoBcd (Time->Month); + Time->Day = DecimaltoBcd (Time->Day); + Time->Hour = DecimaltoBcd (Time->Hour); + Time->Minute = DecimaltoBcd (Time->Minute); + Time->Second = DecimaltoBcd (Time->Second); + } + // + // If we are in 12 hour mode and PM is set, then set bit 7 of the Hour field. + // + if (RegisterB.Bits.MIL == 0 && PM) { + Time->Hour = (UINT8) (Time->Hour | 0x80); + } +} + +EFI_STATUS +RtcTimeFieldsValid ( + IN EFI_TIME *Time + ) +/*++ + +Routine Description: + + Arguments: + + Returns: +--*/ +// TODO: Time - add argument and description to function comment +// TODO: EFI_INVALID_PARAMETER - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + if (Time->Year < 1998 || + Time->Year > 2099 || + Time->Month < 1 || + Time->Month > 12 || + (!DayValid (Time)) || + Time->Hour > 23 || + Time->Minute > 59 || + Time->Second > 59 || + Time->Nanosecond > 999999999 || + (!(Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE || (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) || + (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT))) + ) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +UINT8 +RtcRead ( + IN UINT8 Address + ) +{ + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80))); + return IoRead8 (PCAT_RTC_DATA_REGISTER); +} + +VOID +RtcWrite ( + IN UINT8 Address, + IN UINT8 Data + ) +{ + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80))); + IoWrite8 (PCAT_RTC_DATA_REGISTER, Data); +} + + +EFI_STATUS +RtcTestCenturyRegister ( + VOID + ) +{ + UINT8 Century; + UINT8 Temp; + + Century = RtcRead (RTC_ADDRESS_CENTURY); + // + // RtcWrite (RTC_ADDRESS_CENTURY, 0x00); + // + Temp = (UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f); + RtcWrite (RTC_ADDRESS_CENTURY, Century); + if (Temp == 0x19 || Temp == 0x20) { + return EFI_SUCCESS; + } + + return EFI_DEVICE_ERROR; +} + +VOID +ConvertRtcTimeToEfiTime ( + IN EFI_TIME *Time, + IN RTC_REGISTER_B RegisterB + ) +{ + BOOLEAN PM; + + if ((Time->Hour) & 0x80) { + PM = TRUE; + } else { + PM = FALSE; + } + + Time->Hour = (UINT8) (Time->Hour & 0x7f); + + if (RegisterB.Bits.DM == 0) { + Time->Year = BcdToDecimal ((UINT8) Time->Year); + Time->Month = BcdToDecimal (Time->Month); + Time->Day = BcdToDecimal (Time->Day); + Time->Hour = BcdToDecimal (Time->Hour); + Time->Minute = BcdToDecimal (Time->Minute); + Time->Second = BcdToDecimal (Time->Second); + } + // + // If time is in 12 hour format, convert it to 24 hour format + // + if (RegisterB.Bits.MIL == 0) { + if (PM && Time->Hour < 12) { + Time->Hour = (UINT8) (Time->Hour + 12); + } + + if (!PM && Time->Hour == 12) { + Time->Hour = 0; + } + } + + Time->Nanosecond = 0; + Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE; + Time->Daylight = 0; +} + +EFI_STATUS +RtcWaitToUpdate ( + UINTN Timeout + ) +{ + RTC_REGISTER_A RegisterA; + RTC_REGISTER_D RegisterD; + + // + // See if the RTC is functioning correctly + // + RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D); + + if (RegisterD.Bits.VRT == 0) { + return EFI_DEVICE_ERROR; + } + // + // Wait for up to 0.1 seconds for the RTC to be ready. + // + Timeout = (Timeout / 10) + 1; + RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A); + while (RegisterA.Bits.UIP == 1 && Timeout > 0) { + MicroSecondDelay (10); + RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A); + Timeout--; + } + + RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D); + if (Timeout == 0 || RegisterD.Bits.VRT == 0) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +LibGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +{ + EFI_STATUS Status; + RTC_REGISTER_B RegisterB; + UINT8 Century; + UINTN BufferSize; + + // + // Check parameters for null pointer + // + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + + } + // + // Acquire RTC Lock to make access to RTC atomic + // + EfiAcquireLock (&mRtc.RtcLock); + + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (100000); + if (EFI_ERROR (Status)) { + EfiReleaseLock (&mRtc.RtcLock); + return Status; + } + // + // Read Register B + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + + // + // Get the Time/Date/Daylight Savings values. + // + Time->Second = RtcRead (RTC_ADDRESS_SECONDS); + Time->Minute = RtcRead (RTC_ADDRESS_MINUTES); + Time->Hour = RtcRead (RTC_ADDRESS_HOURS); + Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); + Time->Month = RtcRead (RTC_ADDRESS_MONTH); + Time->Year = RtcRead (RTC_ADDRESS_YEAR); + + ConvertRtcTimeToEfiTime (Time, RegisterB); + + if (RtcTestCenturyRegister () == EFI_SUCCESS) { + Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f)); + } else { + Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY)); + } + + Time->Year = (UINT16) (Century * 100 + Time->Year); + + // + // Release RTC Lock. + // + EfiReleaseLock (&mRtc.RtcLock); + + // + // Get the variable that containts the TimeZone and Daylight fields + // + Time->TimeZone = mRtc.SavedTimeZone; + Time->Daylight = mRtc.Daylight; + + BufferSize = sizeof (INT16) + sizeof (UINT8); + + // + // Make sure all field values are in correct range + // + Status = RtcTimeFieldsValid (Time); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Fill in Capabilities if it was passed in + // + if (Capabilities) { + Capabilities->Resolution = 1; + // + // 1 hertz + // + Capabilities->Accuracy = 50000000; + // + // 50 ppm + // + Capabilities->SetsToZero = FALSE; + } + + return EFI_SUCCESS; +} + + + +EFI_STATUS +LibSetTime ( + IN EFI_TIME *Time + ) +{ + EFI_STATUS Status; + EFI_TIME RtcTime; + RTC_REGISTER_B RegisterB; + UINT8 Century; + + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure that the time fields are valid + // + Status = RtcTimeFieldsValid (Time); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (&RtcTime, Time, sizeof (EFI_TIME)); + + // + // Acquire RTC Lock to make access to RTC atomic + // + EfiAcquireLock (&mRtc.RtcLock); + + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (100000); + if (EFI_ERROR (Status)) { + EfiReleaseLock (&mRtc.RtcLock); + return Status; + } + // + // Read Register B, and inhibit updates of the RTC + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + RegisterB.Bits.SET = 1; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century); + + RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second); + RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute); + RtcWrite (RTC_ADDRESS_HOURS, RtcTime.Hour); + RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day); + RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month); + RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year); + if (RtcTestCenturyRegister () == EFI_SUCCESS) { + Century = (UINT8) ((Century & 0x7f) | (RtcRead (RTC_ADDRESS_CENTURY) & 0x80)); + } + + RtcWrite (RTC_ADDRESS_CENTURY, Century); + + // + // Allow updates of the RTC registers + // + RegisterB.Bits.SET = 0; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + // + // Release RTC Lock. + // + EfiReleaseLock (&mRtc.RtcLock); + + // + // Set the variable that containts the TimeZone and Daylight fields + // + mRtc.SavedTimeZone = Time->TimeZone; + mRtc.Daylight = Time->Daylight; + return Status; +} + +EFI_STATUS +libGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +{ + EFI_STATUS Status; + RTC_REGISTER_B RegisterB; + RTC_REGISTER_C RegisterC; + UINT8 Century; + + // + // Check paramters for null pointers + // + if ((Enabled == NULL) || (Pending == NULL) || (Time == NULL)) { + return EFI_INVALID_PARAMETER; + + } + // + // Acquire RTC Lock to make access to RTC atomic + // + EfiAcquireLock (&mRtc.RtcLock); + + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (100000); + if (EFI_ERROR (Status)) { + EfiReleaseLock (&mRtc.RtcLock); + return EFI_DEVICE_ERROR; + } + // + // Read Register B and Register C + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C); + + // + // Get the Time/Date/Daylight Savings values. + // + *Enabled = RegisterB.Bits.AIE; + if (*Enabled) { + Time->Second = RtcRead (RTC_ADDRESS_SECONDS_ALARM); + Time->Minute = RtcRead (RTC_ADDRESS_MINUTES_ALARM); + Time->Hour = RtcRead (RTC_ADDRESS_HOURS_ALARM); + Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); + Time->Month = RtcRead (RTC_ADDRESS_MONTH); + Time->Year = RtcRead (RTC_ADDRESS_YEAR); + } else { + Time->Second = 0; + Time->Minute = 0; + Time->Hour = 0; + Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); + Time->Month = RtcRead (RTC_ADDRESS_MONTH); + Time->Year = RtcRead (RTC_ADDRESS_YEAR); + } + + ConvertRtcTimeToEfiTime (Time, RegisterB); + + if (RtcTestCenturyRegister () == EFI_SUCCESS) { + Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f)); + } else { + Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY)); + } + + Time->Year = (UINT16) (Century * 100 + Time->Year); + + // + // Release RTC Lock. + // + EfiReleaseLock (&mRtc.RtcLock); + + // + // Make sure all field values are in correct range + // + Status = RtcTimeFieldsValid (Time); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + *Pending = RegisterC.Bits.AF; + + return EFI_SUCCESS; +} + +EFI_STATUS +LibSetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ) +{ + EFI_STATUS Status; + EFI_TIME RtcTime; + RTC_REGISTER_B RegisterB; + UINT8 Century; + EFI_TIME_CAPABILITIES Capabilities; + + if (Enabled) { + + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Make sure that the time fields are valid + // + Status = RtcTimeFieldsValid (Time); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + // + // Just support set alarm time within 24 hours + // + LibGetTime (&RtcTime, &Capabilities); + if (Time->Year != RtcTime.Year || + Time->Month != RtcTime.Month || + (Time->Day != RtcTime.Day && Time->Day != (RtcTime.Day + 1)) + ) { + return EFI_UNSUPPORTED; + } + // + // Make a local copy of the time and date + // + CopyMem (&RtcTime, Time, sizeof (EFI_TIME)); + + } + // + // Acquire RTC Lock to make access to RTC atomic + // + EfiAcquireLock (&mRtc.RtcLock); + + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (100000); + if (EFI_ERROR (Status)) { + EfiReleaseLock (&mRtc.RtcLock); + return EFI_DEVICE_ERROR; + } + // + // Read Register B, and inhibit updates of the RTC + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + + RegisterB.Bits.SET = 1; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + if (Enabled) { + ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century); + + // + // Set RTC alarm time + // + RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second); + RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute); + RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour); + + RegisterB.Bits.AIE = 1; + + } else { + RegisterB.Bits.AIE = 0; + } + // + // Allow updates of the RTC registers + // + RegisterB.Bits.SET = 0; + RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data); + + // + // Release RTC Lock. + // + EfiReleaseLock (&mRtc.RtcLock); + + return EFI_SUCCESS; +} + + + +VOID +LibRtcVirtualAddressChangeEvent ( + VOID + ) +{ +} + + +VOID +LibRtcInitialize ( + VOID + ) +{ + EFI_STATUS Status; + RTC_REGISTER_A RegisterA; + RTC_REGISTER_B RegisterB; + RTC_REGISTER_C RegisterC; + RTC_REGISTER_D RegisterD; + UINT8 Century; + EFI_TIME Time; + + // + // Acquire RTC Lock to make access to RTC atomic + // + EfiAcquireLock (&mRtc.RtcLock); + + // + // Initialize RTC Register + // + // Make sure Division Chain is properly configured, + // or RTC clock won't "tick" -- time won't increment + // + RegisterA.Data = RTC_INIT_REGISTER_A; + RtcWrite (RTC_ADDRESS_REGISTER_A, RegisterA.Data); + + // + // Read Register B + // + RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B); + + // + // Clear RTC flag register + // + RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C); + + // + // Clear RTC register D + // + RegisterD.Data = RTC_INIT_REGISTER_D; + RtcWrite (RTC_ADDRESS_REGISTER_D, RegisterD.Data); + + // + // Wait for up to 0.1 seconds for the RTC to be updated + // + Status = RtcWaitToUpdate (100000); + if (EFI_ERROR (Status)) { + EfiReleaseLock (&mRtc.RtcLock); + return; + } + + // + // Get the Time/Date/Daylight Savings values. + // + Time.Second = RtcRead (RTC_ADDRESS_SECONDS); + Time.Minute = RtcRead (RTC_ADDRESS_MINUTES); + Time.Hour = RtcRead (RTC_ADDRESS_HOURS); + Time.Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH); + Time.Month = RtcRead (RTC_ADDRESS_MONTH); + Time.Year = RtcRead (RTC_ADDRESS_YEAR); + + ConvertRtcTimeToEfiTime (&Time, RegisterB); + + if (RtcTestCenturyRegister () == EFI_SUCCESS) { + Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f)); + } else { + Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY)); + } + + Time.Year = (UINT16) (Century * 100 + Time.Year); + + // + // Set RTC configuration after get original time + // + RtcWrite (RTC_ADDRESS_REGISTER_B, RTC_INIT_REGISTER_B); + + // + // Release RTC Lock. + // + EfiReleaseLock (&mRtc.RtcLock); + + // + // Validate time fields + // + Status = RtcTimeFieldsValid (&Time); + if (EFI_ERROR (Status)) { + Time.Second = RTC_INIT_SECOND; + Time.Minute = RTC_INIT_MINUTE; + Time.Hour = RTC_INIT_HOUR; + Time.Day = RTC_INIT_DAY; + Time.Month = RTC_INIT_MONTH; + Time.Year = RTC_INIT_YEAR; + } + // + // Reset time value according to new RTC configuration + // + LibSetTime (&Time); + + return; +} + + diff --git a/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Variable.c b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Variable.c new file mode 100644 index 0000000000..d96a44304a --- /dev/null +++ b/EmbeddedPkg/Library/HalRuntimeServicesExampleLib/Variable.c @@ -0,0 +1,306 @@ +/** @file + Variable services implemented from system memory + + There is just a single runtime memory buffer that contans all the data. + + Copyright (c) 2007, Intel Corporation
+ Portions copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + + +UINT64 mMaximumVariableStorageSize; +UINT64 mRemainingVariableStorageSize; +UINT64 mMaximumVariableSize; + +typedef struct { + EFI_GUID VendorGuid; + UINT32 Attribute; + UINTN DataSize; +} VARIABLE_ARRAY_ENTRY; +// CHAR16 VariableName[] +// UINT8 Data[] + +VARIABLE_ARRAY_ENTRY *mVariableArray = NULL; +VARIABLE_ARRAY_ENTRY *mVariableArrayNextFree = NULL; +VARIABLE_ARRAY_ENTRY *mVariableArrayEnd = NULL; + + +VARIABLE_ARRAY_ENTRY * +AddEntry ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + UINTN Size; + UINTN SizeOfString; + VARIABLE_ARRAY_ENTRY *Entry; + EFI_TPL CurrentTpl; + + + SizeOfString = StrSize (VariableName); + Size = SizeOfString + sizeof (VARIABLE_ARRAY_ENTRY) + DataSize; + if ((VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArrayNextFree) + Size) > mVariableArrayEnd) { + // ran out of space + return NULL; + } + + if (!EfiAtRuntime ()) { + // Enter critical section + CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); + } + + Entry = mVariableArrayNextFree; + CopyGuid (&Entry->VendorGuid, VendorGuid); + Entry->Attribute = Attributes; + Entry->DataSize = DataSize; + StrCpy ((CHAR16 *)++mVariableArrayNextFree, VariableName); + mVariableArrayNextFree = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArrayNextFree) + SizeOfString); + CopyMem (mVariableArrayNextFree, Data, DataSize); + mVariableArrayNextFree = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArrayNextFree) + DataSize); + + if (!EfiAtRuntime ()) { + // Exit Critical section + gBS->RestoreTPL (CurrentTpl); + } + + return Entry; +} + +VOID +DeleteEntry ( + IN VARIABLE_ARRAY_ENTRY *Entry + ) +{ + UINTN Size; + UINT8 *Data; + EFI_TPL CurrentTpl; + + Size = StrSize ((CHAR16 *)(Entry + 1)) + sizeof (VARIABLE_ARRAY_ENTRY) + Entry->DataSize; + Data = ((UINT8 *)Entry) + Size; + + CopyMem (Entry, Data, (UINTN)mVariableArrayNextFree - (UINTN)Data); + + if (!EfiAtRuntime ()) { + // Enter critical section + CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); + } + + mVariableArrayNextFree = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArrayNextFree) - Size); + + if (!EfiAtRuntime ()) { + // Exit Critical section + gBS->RestoreTPL (CurrentTpl); + } +} + + +VARIABLE_ARRAY_ENTRY * +GetVariableArrayEntry ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VOID **Data OPTIONAL + ) +{ + VARIABLE_ARRAY_ENTRY *Entry; + UINTN Size; + + if (*VariableName == L'\0') { + // by definition first entry is null-terminated string + if (mVariableArray == mVariableArrayNextFree) { + return NULL; + } + return mVariableArray; + } + + for (Entry = mVariableArray; Entry < mVariableArrayEnd;) { + if (CompareGuid (VendorGuid, &Entry->VendorGuid)) { + if (StrCmp (VariableName, (CHAR16 *)(Entry + 1))) { + Size = StrSize ((CHAR16 *)(Entry + 1)); + if (Data != NULL) { + *Data = (VOID *)(((UINT8 *)Entry) + (Size + sizeof (VARIABLE_ARRAY_ENTRY))); + } + return Entry; + } + } + + Size = StrSize ((CHAR16 *)(Entry + 1)) + sizeof (VARIABLE_ARRAY_ENTRY) + Entry->DataSize; + Entry = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)Entry) + Size); + } + + return NULL; +} + + +EFI_STATUS +LibGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + VARIABLE_ARRAY_ENTRY *Entry; + VOID *InternalData; + + if (EfiAtRuntime () && (Attributes != NULL)) { + if ((*Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) { + return EFI_NOT_FOUND; + } + } + + Entry = GetVariableArrayEntry (VariableName, VendorGuid, &InternalData); + if (Entry == NULL) { + return EFI_NOT_FOUND; + } + + if (*DataSize < Entry->DataSize) { + *DataSize = Entry->DataSize; + return EFI_BUFFER_TOO_SMALL; + } + + *DataSize = Entry->DataSize; + if (Attributes != NULL) { + *Attributes = Entry->Attribute; + } + + CopyMem (Data, InternalData, *DataSize); + return EFI_SUCCESS; +} + + +EFI_STATUS +LibGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +{ + VARIABLE_ARRAY_ENTRY *Entry; + VOID *InternalData; + UINTN StringSize; + BOOLEAN Done; + + for (Done = FALSE; !Done; ) { + Entry = GetVariableArrayEntry (VariableName, VendorGuid, &InternalData); + if (Entry == NULL) { + return EFI_NOT_FOUND; + } + + // If we are at runtime skip variables that do not have the Runitme attribute set. + Done = (EfiAtRuntime () && ((Entry->Attribute & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) ? FALSE : TRUE; + } + + StringSize = StrSize ((CHAR16 *)(Entry + 1)); + Entry = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)Entry) + (StringSize + sizeof (VARIABLE_ARRAY_ENTRY) + Entry->DataSize)); + if (Entry >= mVariableArrayEnd) { + return EFI_NOT_FOUND; + } + + if (*VariableNameSize < StringSize) { + *VariableNameSize = StringSize; + return EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = StringSize; + CopyMem (VariableName, (CHAR16 *)(Entry + 1), StringSize); + CopyMem (VendorGuid, &Entry->VendorGuid, sizeof (EFI_GUID)); + return EFI_SUCCESS; +} + + + +EFI_STATUS +LibSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + VARIABLE_ARRAY_ENTRY *Entry; + VOID *InternalData; + + if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) { + return EFI_NOT_FOUND; + } + + Entry = GetVariableArrayEntry (VariableName, VendorGuid, &InternalData); + if (Entry == NULL) { + if (DataSize == 0) { + return EFI_NOT_FOUND; + } + Entry = AddEntry (VariableName, VendorGuid, Attributes, DataSize, Data); + return (Entry == NULL) ? EFI_OUT_OF_RESOURCES : EFI_SUCCESS; + + } else if (DataSize == 0) { + // DataSize is zero so delete + DeleteEntry (Entry); + } else if (DataSize == Entry->DataSize) { + // No change is size so just update the store + Entry->Attribute |= Attributes; + CopyMem (InternalData, Data, DataSize); + } else { + // Grow the entry by deleting and adding back. Don't lose previous Attributes + Attributes |= Entry->Attribute; + DeleteEntry (Entry); + Entry = AddEntry (VariableName, VendorGuid, Attributes, DataSize, Data); + return (Entry == NULL) ? EFI_OUT_OF_RESOURCES : EFI_SUCCESS; + } +} + + +EFI_STATUS +LibQueryVariableInfo ( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize + ) +{ + *MaximumVariableStorageSize = mMaximumVariableStorageSize; + *RemainingVariableStorageSize = mRemainingVariableStorageSize; + *MaximumVariableStorageSize = mRemainingVariableStorageSize; + return EFI_SUCCESS; +} + + +VOID +LibVariableVirtualAddressChangeEvent (VOID) +{ + EfiConvertPointer (0, (VOID **)&mVariableArray); + EfiConvertPointer (0, (VOID **)&mVariableArrayNextFree); + EfiConvertPointer (0, (VOID **)&mVariableArrayEnd); +} + + +VOID +LibVariableInitialize (VOID) +{ + UINTN Size; + + Size = PcdGet32 (PcdEmbeddedMemVariableStoreSize); + mVariableArray = mVariableArrayNextFree = (VARIABLE_ARRAY_ENTRY *)AllocateRuntimePool (Size); + ASSERT (mVariableArray != NULL); + + mVariableArrayEnd = (VARIABLE_ARRAY_ENTRY *)(((UINT8 *)mVariableArray) + Size); + + mMaximumVariableStorageSize = Size - sizeof (VARIABLE_ARRAY_ENTRY); + mRemainingVariableStorageSize = mMaximumVariableStorageSize; + mMaximumVariableSize = mMaximumVariableStorageSize; +} + diff --git a/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c b/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c new file mode 100644 index 0000000000..b635fa0d9e --- /dev/null +++ b/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c @@ -0,0 +1,247 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 paramter. + // + 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; + + if (InputSection == NULL) { + return RETURN_INVALID_PARAMETER; + } + + ASSERT (OutputBufferSize != NULL); + ASSERT (ScratchBufferSize != NULL); + ASSERT (SectionAttribute != NULL); + + 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], &(((EFI_GUID_DEFINED_SECTION *) InputSection)->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; + + if (InputSection == NULL) { + return RETURN_INVALID_PARAMETER; + } + + ASSERT (OutputBuffer != NULL); + ASSERT (AuthenticationStatus != NULL); + + 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], &(((EFI_GUID_DEFINED_SECTION *) InputSection)->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/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf b/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf new file mode 100644 index 0000000000..bffe5b250a --- /dev/null +++ b/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf @@ -0,0 +1,24 @@ +#%HEADER% +[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/EmbeddedPkg/Library/PrePiLib/FwVol.c b/EmbeddedPkg/Library/PrePiLib/FwVol.c new file mode 100644 index 0000000000..4a9e24683f --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/FwVol.c @@ -0,0 +1,841 @@ +/** @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. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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); + } + + 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; + UINTN DstBufferSize; + VOID *ScratchBuffer; + UINT32 ScratchBufferSize; + VOID *DstBuffer; + UINT16 SectionAttribute; + UINT32 AuthenticationStatus; + + + *OutputBuffer = NULL; + ParsedLength = 0; + Status = EFI_NOT_FOUND; + while (ParsedLength < SectionSize) { + if (Section->Type == SectionType) { + *OutputBuffer = (VOID *)(Section + 1); + + return EFI_SUCCESS; + } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) { + + if (Section->Type == EFI_SECTION_COMPRESSION) { + CompressionSection = (EFI_COMPRESSION_SECTION *) Section; + SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; + + if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) { + return EFI_UNSUPPORTED; + } + + Status = UefiDecompressGetInfo ( + (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), + (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION), + (UINT32 *) &DstBufferSize, + &ScratchBufferSize + ); + } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { + Status = ExtractGuidedSectionGetInfo ( + Section, + (UINT32 *) &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. + // + DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); + // + // Call decompress function + // + if (Section->Type == EFI_SECTION_COMPRESSION) { + Status = UefiDecompress ( + (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), + 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 + ); + } + } + + // + // Size is 24 bits wide so mask upper 8 bits. + // SectionLength is adjusted it is 4 byte aligned. + // Go to the next section + // + SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; + 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 succes 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. + // + 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 existance 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/EmbeddedPkg/Library/PrePiLib/Hob.c b/EmbeddedPkg/Library/PrePiLib/Hob.c new file mode 100644 index 0000000000..3c6574282c --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/Hob.c @@ -0,0 +1,808 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include + +// +// Have to use build system to set the original value in case we are running +// from FLASH and globals don't work. So if you do a GetHobList() and gHobList +// and gHobList is NULL the PCD default values are used. +// +VOID *gHobList = NULL; + + + + +// May want to put this into a library so you only need the PCD setings 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)); +} + +/** + + +**/ +VOID +CreateHobList ( + IN VOID *MemoryBegin, + IN UINTN MemoryLength, + IN VOID *HobBase, + IN VOID *StackBase + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *Hob; + EFI_HOB_GENERIC_HEADER *HobEnd; + EFI_RESOURCE_ATTRIBUTE_TYPE Attributes; + + + Hob = HobBase; + 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)MemoryBegin + MemoryLength; + Hob->EfiMemoryBottom = (UINTN)MemoryBegin; + Hob->EfiFreeMemoryTop = (UINTN)StackBase; + Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS)(UINTN)(HobEnd+1); + Hob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS)(UINTN)HobEnd; + + SetHobList (Hob); + + BuildCpuHob (PcdGet8 (PcdPrePiCpuMemorySize), PcdGet8 (PcdPrePiCpuIoSize)); + + Attributes =( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_TESTED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + ); + + BuildResourceDescriptorHob (EFI_RESOURCE_SYSTEM_MEMORY, Attributes, (UINTN)MemoryBegin, MemoryLength); + + + BuildStackHob ((UINTN)StackBase, Hob->EfiMemoryTop - (UINTN)StackBase); + + if (FeaturePcdGet (PcdPrePiProduceMemoryTypeInformationHob)) { + // Optional feature that helps prevent EFI memory map fragmentation. + BuildMemoryTypeInformationHob (); + } + +} + + +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 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 + ) +{ + if (gHobList == NULL) { + return (VOID *)(UINTN)PcdGet32 (PcdPrePiHobBase); + } else { + return gHobList; + } +} + + + +/** + Updates the pointer to the HOB list. + + @param HobList Hob list pointer to store + +**/ +EFI_STATUS +EFIAPI +SetHobList ( + IN VOID *HobList + ) +{ + gHobList = HobList; + + // + // If this code is running from ROM this could fail + // + return (gHobList == HobList) ? EFI_SUCCESS: EFI_UNSUPPORTED; +} + + + +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; +} + + +/** + 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 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)); + + Hob->ResourceType = ResourceType; + Hob->ResourceAttribute = ResourceAttribute; + Hob->PhysicalStart = PhysicalStart; + Hob->ResourceLength = 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 + ) +{ + 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 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)); +} + + diff --git a/EmbeddedPkg/Library/PrePiLib/Memory.c b/EmbeddedPkg/Library/PrePiLib/Memory.c new file mode 100644 index 0000000000..209c71b42f --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/Memory.c @@ -0,0 +1,160 @@ +/** @file + Implementation of the 6 PEI Ffs (FV) APIs in library form. + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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. + + 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); +} + + + + +/** + 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 AllcoatePages for big allocations + return 0; + } else { + + Hob = (EFI_HOB_MEMORY_POOL *)CreateHob (EFI_HOB_TYPE_MEMORY_POOL, (UINT16)(sizeof (EFI_HOB_TYPE_MEMORY_POOL) + AllocationSize)); + return (VOID *)(Hob + 1); + } +} + + + diff --git a/EmbeddedPkg/Library/PrePiLib/PrePi.h b/EmbeddedPkg/Library/PrePiLib/PrePi.h new file mode 100644 index 0000000000..dc3ef48614 --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/PrePi.h @@ -0,0 +1,44 @@ +/** @file + Library that helps implement monolithic PEI (i.e. PEI part of SEC) + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PI_PEI_H_ +#define _PI_PEI_H_ + +#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/EmbeddedPkg/Library/PrePiLib/PrePiLib.c b/EmbeddedPkg/Library/PrePiLib/PrePiLib.c new file mode 100644 index 0000000000..f92be0fea3 --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/PrePiLib.c @@ -0,0 +1,231 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 + + ); + + +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 = AllocatePages (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/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf b/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf new file mode 100644 index 0000000000..278ee44722 --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf @@ -0,0 +1,90 @@ +#%HEADER% +#/** @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) 2008, Apple, Inc. +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[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 IPF EBC +# + +[Sources.common] + FwVol.c + Hob.c + Memory.c + PrePiLib.c + ReportStatusCode.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec # needed to support StatusCodes + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec # needed to support StatusCodes + + +[LibraryClasses] + BaseLib + DebugLib + BaseMemoryLib + UefiDecompressLib + PeCoffLib + CacheMaintenanceLib + PrintLib + SerialPortLib + ExtractGuidedSectionLib + +[Guids] + gEfiHobMemoryAllocModuleGuid + gEfiHobMemoryAllocStackGuid + gEfiStatusCodeSpecificDataGuid + gEfiMemoryTypeInformationGuid + gEfiStatusCodeDataTypeDebugGuid + +[Protocols] + gEfiStatusCodeRuntimeProtocolGuid + + +[FixedPcd.common] + gEmbeddedTokenSpaceGuid.PcdPrePiHobBase + gEmbeddedTokenSpaceGuid.PcdPrePiTempMemorySize + gEmbeddedTokenSpaceGuid.PcdPrePiBfvBaseAddress + gEmbeddedTokenSpaceGuid.PcdPrePiBfvSize + gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize + 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/EmbeddedPkg/Library/PrePiLib/ReportStatusCode.c b/EmbeddedPkg/Library/PrePiLib/ReportStatusCode.c new file mode 100644 index 0000000000..8833567fe5 --- /dev/null +++ b/EmbeddedPkg/Library/PrePiLib/ReportStatusCode.c @@ -0,0 +1,327 @@ +/** @file + Library that helps implement monolithic PEI + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define EFI_STATUS_CODE_DATA_MAX_SIZE 200 + +EFI_STATUS +EFIAPI +SerialReportStatusCode ( + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value, + IN UINT32 Instance, + IN CONST EFI_GUID *CallerId, + IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL + ); + + +EFI_STATUS_CODE_PROTOCOL gStatusCode = { + (EFI_REPORT_STATUS_CODE)SerialReportStatusCode +}; + +/** + Extracts ASSERT() information from a status code structure. + + Converts the status code specified by CodeType, Value, and Data to the ASSERT() + arguments specified by Filename, Description, and LineNumber. If CodeType is + an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and + Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract + Filename, Description, and LineNumber from the optional data area of the + status code buffer specified by Data. The optional data area of Data contains + a Null-terminated ASCII string for the FileName, followed by a Null-terminated + ASCII string for the Description, followed by a 32-bit LineNumber. If the + ASSERT() information could be extracted from Data, then return TRUE. + Otherwise, FALSE is returned. + + If Data is NULL, then ASSERT(). + If Filename is NULL, then ASSERT(). + If Description is NULL, then ASSERT(). + If LineNumber is NULL, then ASSERT(). + + @param CodeType The type of status code being converted. + @param Value The status code value being converted. + @param Data Pointer to status code data buffer. + @param Filename Pointer to the source file name that generated the ASSERT(). + @param Description Pointer to the description of the ASSERT(). + @param LineNumber Pointer to source line number that generated the ASSERT(). + + @retval TRUE The status code specified by CodeType, Value, and Data was + converted ASSERT() arguments specified by Filename, Description, + and LineNumber. + @retval FALSE The status code specified by CodeType, Value, and Data could + not be converted to ASSERT() arguments. + +**/ +BOOLEAN +EFIAPI +ReportStatusCodeExtractAssertInfo ( + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value, + IN CONST EFI_STATUS_CODE_DATA *Data, + OUT CHAR8 **Filename, + OUT CHAR8 **Description, + OUT UINT32 *LineNumber + ) +{ + EFI_DEBUG_ASSERT_DATA *AssertData; + + ASSERT (Data != NULL); + ASSERT (Filename != NULL); + ASSERT (Description != NULL); + ASSERT (LineNumber != NULL); + + if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) && + ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED) && + ((Value & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) { + AssertData = (EFI_DEBUG_ASSERT_DATA *)(Data + 1); + *Filename = (CHAR8 *)(AssertData + 1); + *Description = *Filename + AsciiStrLen (*Filename) + 1; + *LineNumber = AssertData->LineNumber; + return TRUE; + } + return FALSE; +} + + +/** + Extracts DEBUG() information from a status code structure. + + Converts the status code specified by Data to the DEBUG() arguments specified + by ErrorLevel, Marker, and Format. If type GUID in Data is + EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID, then extract ErrorLevel, Marker, and + Format from the optional data area of the status code buffer specified by Data. + The optional data area of Data contains a 32-bit ErrorLevel followed by Marker + which is 12 UINTN parameters, followed by a Null-terminated ASCII string for + the Format. If the DEBUG() information could be extracted from Data, then + return TRUE. Otherwise, FALSE is returned. + + If Data is NULL, then ASSERT(). + If ErrorLevel is NULL, then ASSERT(). + If Marker is NULL, then ASSERT(). + If Format is NULL, then ASSERT(). + + @param Data Pointer to status code data buffer. + @param ErrorLevel Pointer to error level mask for a debug message. + @param Marker Pointer to the variable argument list associated with Format. + @param Format Pointer to a Null-terminated ASCII format string of a + debug message. + + @retval TRUE The status code specified by Data was converted DEBUG() arguments + specified by ErrorLevel, Marker, and Format. + @retval FALSE The status code specified by Data could not be converted to + DEBUG() arguments. + +**/ +BOOLEAN +EFIAPI +ReportStatusCodeExtractDebugInfo ( + IN CONST EFI_STATUS_CODE_DATA *Data, + OUT UINT32 *ErrorLevel, + OUT BASE_LIST *Marker, + OUT CHAR8 **Format + ) +{ + EFI_DEBUG_INFO *DebugInfo; + + ASSERT (Data != NULL); + ASSERT (ErrorLevel != NULL); + ASSERT (Marker != NULL); + ASSERT (Format != NULL); + + // + // If the GUID type is not EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID then return FALSE + // + if (!CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid)) { + return FALSE; + } + + // + // Retrieve the debug information from the status code record + // + DebugInfo = (EFI_DEBUG_INFO *)(Data + 1); + + *ErrorLevel = DebugInfo->ErrorLevel; + + // + // The first 12 * UINTN bytes of the string are really an + // argument stack to support varargs on the Format string. + // + *Marker = (BASE_LIST) (DebugInfo + 1); + *Format = (CHAR8 *)(((UINT64 *)*Marker) + 12); + + return TRUE; +} + + + + +EFI_STATUS +EFIAPI +SerialReportStatusCode ( + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value, + IN UINT32 Instance, + IN CONST EFI_GUID *CallerId, + IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL + ) +{ + CHAR8 *Filename; + CHAR8 *Description; + CHAR8 *Format; + CHAR8 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE]; + UINT32 ErrorLevel; + UINT32 LineNumber; + UINTN CharCount; + BASE_LIST Marker; + EFI_DEBUG_INFO *DebugInfo; + + Buffer[0] = '\0'; + + + if (Data != NULL && + ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) { + + // + // Print ASSERT() information into output buffer. + // + CharCount = AsciiSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + "\n\rASSERT!: %a (%d): %a\n\r", + Filename, + LineNumber, + Description + ); + + + // + // Callout to standard output. + // + SerialPortWrite ((UINT8 *)Buffer, CharCount); + return EFI_SUCCESS; + + } else if (Data != NULL && + ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) { + + // + // Print DEBUG() information into output buffer. + // + CharCount = AsciiBSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + Format, + Marker + ); + + } else if (Data != NULL && + CompareGuid (&Data->Type, &gEfiStatusCodeSpecificDataGuid) && + (CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) { + + // + // Print specific data into output buffer. + // + DebugInfo = (EFI_DEBUG_INFO *) (Data + 1); + Marker = (BASE_LIST) (DebugInfo + 1); + Format = (CHAR8 *) (((UINT64 *) (DebugInfo + 1)) + 12); + + CharCount = AsciiBSPrint (Buffer, EFI_STATUS_CODE_DATA_MAX_SIZE, Format, Marker); + + } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) { + // + // Print ERROR information into output buffer. + // + + CharCount = AsciiSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + "ERROR: C%x:V%x I%x", + CodeType, + Value, + Instance + ); + + // + // Make sure we don't try to print values that weren't intended to be printed, especially NULL GUID pointers. + // + if (CallerId != NULL) { + CharCount += AsciiSPrint ( + &Buffer[CharCount - 1], + (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)), + " %g", + CallerId + ); + } + + if (Data != NULL) { + CharCount += AsciiSPrint ( + &Buffer[CharCount - 1], + (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)), + " %x", + Data + ); + + } + + + CharCount += AsciiSPrint ( + &Buffer[CharCount - 1], + (EFI_STATUS_CODE_DATA_MAX_SIZE - (sizeof (Buffer[0]) * CharCount)), + "\n\r" + ); + + } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) { + CharCount = AsciiSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + "PROGRESS CODE: V%x I%x\n\r", + Value, + Instance + ); + } else { + CharCount = AsciiSPrint ( + Buffer, + EFI_STATUS_CODE_DATA_MAX_SIZE, + "Undefined: C%x:V%x I%x\n\r", + CodeType, + Value, + Instance + ); + + } + + SerialPortWrite ((UINT8 *)Buffer, CharCount); + return EFI_SUCCESS; + +} + + +VOID +EFIAPI +AddDxeCoreReportStatusCodeCallback ( + VOID + ) +{ + BuildGuidDataHob (&gEfiStatusCodeRuntimeProtocolGuid, &gStatusCode, sizeof(VOID *)); +} + diff --git a/EmbeddedPkg/Library/SemiHostingDebugLib/DebugLib.c b/EmbeddedPkg/Library/SemiHostingDebugLib/DebugLib.c new file mode 100644 index 0000000000..61e3aac3c2 --- /dev/null +++ b/EmbeddedPkg/Library/SemiHostingDebugLib/DebugLib.c @@ -0,0 +1,258 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +/** @file + UEFI Debug Library that uses PrintLib to send messages to STDERR. + + Copyright (c) 2006 - 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include +#include +#include +#include +#include +#include +#include + +// +// Define the maximum debug and assert message length that this library supports +// +#define MAX_DEBUG_MESSAGE_LENGTH 0x100 + +/** + + Prints a debug message to the debug output device if the specified error level is enabled. + + If any bit in ErrorLevel is also set in PcdDebugPrintErrorLevel, then print + the message specified by Format and the associated variable argument list to + the debug output device. + + If Format is NULL, then ASSERT(). + + @param ErrorLevel The error level of the debug message. + @param Format Format string for the debug message to print. + +**/ +VOID +EFIAPI +DebugPrint ( + IN UINTN ErrorLevel, + IN CONST CHAR8 *Format, + ... + ) +{ + CHAR8 AsciiBuffer[MAX_DEBUG_MESSAGE_LENGTH]; + VA_LIST Marker; + + // + // If Format is NULL, then ASSERT(). + // + ASSERT (Format != NULL); + + // + // Check driver debug mask value and global mask + // + if ((ErrorLevel & PcdGet32(PcdDebugPrintErrorLevel)) == 0) { + return; + } + + // + // Convert the DEBUG() message to a Unicode String + // + VA_START (Marker, Format); + AsciiVSPrint (AsciiBuffer, sizeof (AsciiBuffer), Format, Marker); + VA_END (Marker); + + SemihostWriteString (AsciiBuffer); +} + + +/** + + Prints an assert message containing a filename, line number, and description. + This may be followed by a breakpoint or a dead loop. + + Print a message of the form "ASSERT (): \n" + to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of + PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if + DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then + CpuDeadLoop() is called. If neither of these bits are set, then this function + returns immediately after the message is printed to the debug output device. + DebugAssert() must actively prevent recusrsion. If DebugAssert() is called while + processing another DebugAssert(), then DebugAssert() must return immediately. + + If FileName is NULL, then a string of "(NULL) Filename" is printed. + + If Description is NULL, then a string of "(NULL) Description" is printed. + + @param FileName Pointer to the name of the source file that generated the assert condition. + @param LineNumber The line number in the source file that generated the assert condition + @param Description Pointer to the description of the assert condition. + +**/ +VOID +EFIAPI +DebugAssert ( + IN CONST CHAR8 *FileName, + IN UINTN LineNumber, + IN CONST CHAR8 *Description + ) +{ + CHAR8 AsciiBuffer[MAX_DEBUG_MESSAGE_LENGTH]; + + // + // Generate the ASSERT() message in Unicode format + // + AsciiSPrint (AsciiBuffer, sizeof (AsciiBuffer), "ASSERT %a(%d): %a\n", FileName, LineNumber, Description); + + SemihostWriteString (AsciiBuffer); + + // + // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings + // + if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) { + CpuBreakpoint (); + } else if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) { + CpuDeadLoop (); + } +} + + +/** + + Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer. + + This function fills Length bytes of Buffer with the value specified by + PcdDebugClearMemoryValue, and returns Buffer. + + If Buffer is NULL, then ASSERT(). + + If Length is greater than (MAX_ADDRESS ? Buffer + 1), then ASSERT(). + + @param Buffer Pointer to the target buffer to fill with PcdDebugClearMemoryValue. + @param Length Number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue. + + @return Buffer + +**/ +VOID * +EFIAPI +DebugClearMemory ( + OUT VOID *Buffer, + IN UINTN Length + ) +{ + // + // If Buffer is NULL, then ASSERT(). + // + ASSERT (Buffer != NULL); + + // + // SetMem() checks for the the ASSERT() condition on Length and returns Buffer + // + return SetMem (Buffer, Length, PcdGet8(PcdDebugClearMemoryValue)); +} + + +/** + + Returns TRUE if ASSERT() macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of + PcdDebugProperyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugAssertEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0); +} + + +/** + + Returns TRUE if DEBUG()macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of + PcdDebugProperyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugPrintEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0); +} + + +/** + + Returns TRUE if DEBUG_CODE()macros are enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of + PcdDebugProperyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugCodeEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0); +} + + +/** + + Returns TRUE if DEBUG_CLEAR_MEMORY()macro is enabled. + + This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CLEAR_MEMORY_ENABLED bit of + PcdDebugProperyMask is set. Otherwise FALSE is returned. + + @retval TRUE The DEBUG_PROPERTY_DEBUG_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is set. + @retval FALSE The DEBUG_PROPERTY_DEBUG_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is clear. + +**/ +BOOLEAN +EFIAPI +DebugClearMemoryEnabled ( + VOID + ) +{ + return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0); +} diff --git a/EmbeddedPkg/Library/SemiHostingDebugLib/SemiHostingDebugLib.inf b/EmbeddedPkg/Library/SemiHostingDebugLib/SemiHostingDebugLib.inf new file mode 100644 index 0000000000..683f03f2f3 --- /dev/null +++ b/EmbeddedPkg/Library/SemiHostingDebugLib/SemiHostingDebugLib.inf @@ -0,0 +1,46 @@ +#%HEADER% +#/** @file +# Debug Library for UEFI drivers +# +# Library to abstract Framework extensions that conflict with UEFI 2.0 Specification +# Copyright (c) 2007, Intel Corporation. +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SemiHostingDebugLib + FILE_GUID = 2A8D3FC4-8DB1-4D27-A3F3-780AF03CF848 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DebugLib|BASE SEC DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + + +[Sources.common] + DebugLib.c + + +[Packages] + MdePkg/MdePkg.dec + ArmPkg/ArmPkg.dec + +[LibraryClasses] + BaseMemoryLib + BaseLib + PcdLib + PrintLib + SemihostLib + +[Pcd.common] + gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel + gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask + diff --git a/EmbeddedPkg/Library/SemiHostingSerialPortLib/SemiHostingSerialPortLib.inf b/EmbeddedPkg/Library/SemiHostingSerialPortLib/SemiHostingSerialPortLib.inf new file mode 100644 index 0000000000..c0a540342a --- /dev/null +++ b/EmbeddedPkg/Library/SemiHostingSerialPortLib/SemiHostingSerialPortLib.inf @@ -0,0 +1,35 @@ +#%HEADER% +#/** @file +# Semihosting serail port lib +# +# Copyright (c) 2008, Apple Inc. +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SemiHostingSerialPortLib + FILE_GUID = E9FB2D1E-05D9-421C-8C35-6100BB0093B7 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = SerialPortLib + + +[Sources.common] + SerialPortLib.c + + +[Packages] + MdePkg/MdePkg.dec + ArmPkg/ArmPkg.dec + +[LibraryClasses] + SemihostLib diff --git a/EmbeddedPkg/Library/SemiHostingSerialPortLib/SerialPortLib.c b/EmbeddedPkg/Library/SemiHostingSerialPortLib/SerialPortLib.c new file mode 100644 index 0000000000..cadeb73731 --- /dev/null +++ b/EmbeddedPkg/Library/SemiHostingSerialPortLib/SerialPortLib.c @@ -0,0 +1,145 @@ +/** @file + Serial I/O Port library functions with no library constructor/destructor + + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + + +/* + + Programmed hardware of Serial port. + + @return Always return EFI_UNSUPPORTED. + +**/ +RETURN_STATUS +EFIAPI +SerialPortInitialize ( + VOID + ) +{ + if (SemihostConnectionSupported ()) { + return RETURN_SUCCESS; + } else { + return RETURN_UNSUPPORTED; + } +} + +/** + Write data to serial device. + + @param Buffer Point of data buffer which need to be writed. + @param NumberOfBytes Number of output bytes which are cached in Buffer. + + @retval 0 Write data failed. + @retval !0 Actual number of bytes writed to serial device. + +**/ + +#define PRINT_BUFFER_SIZE 512 +#define PRINT_BUFFER_THRESHOLD (PRINT_BUFFER_SIZE - 4) + +UINTN +EFIAPI +SerialPortWrite ( + IN UINT8 *Buffer, + IN UINTN NumberOfBytes +) +{ + UINT8 PrintBuffer[PRINT_BUFFER_SIZE]; + UINTN SourceIndex = 0; + UINTN DestinationIndex = 0; + UINT8 CurrentCharacter; + + while (SourceIndex < NumberOfBytes) + { + CurrentCharacter = Buffer[SourceIndex++]; + + switch (CurrentCharacter) + { + case '\r': + continue; + + case '\n': + PrintBuffer[DestinationIndex++] = ' '; + // fall through + + default: + PrintBuffer[DestinationIndex++] = CurrentCharacter; + break; + } + + if (DestinationIndex > PRINT_BUFFER_THRESHOLD) + { + PrintBuffer[DestinationIndex] = '\0'; + SemihostWriteString ((CHAR8 *) PrintBuffer); + + DestinationIndex = 0; + } + } + + if (DestinationIndex > 0) + { + PrintBuffer[DestinationIndex] = '\0'; + SemihostWriteString ((CHAR8 *) PrintBuffer); + } + + return 0; +} + + +/** + Read data from serial device and save the datas in buffer. + + @param Buffer Point of data buffer which need to be writed. + @param NumberOfBytes Number of output bytes which are cached in Buffer. + + @retval 0 Read data failed. + @retval !0 Aactual number of bytes read from serial device. + +**/ +UINTN +EFIAPI +SerialPortRead ( + OUT UINT8 *Buffer, + IN UINTN NumberOfBytes +) +{ + *Buffer = SemihostReadCharacter (); + return 1; +} + + + +/** + Check to see if any data is avaiable to be read from the debug device. + + @retval TRUE At least one byte of data is avaiable to be read + @retval FALS No data is avaiable to be read + +**/ +BOOLEAN +EFIAPI +SerialPortPoll ( + VOID + ) +{ + // Since SemiHosting read character is blocking always say we have a char ready? + return SemihostConnectionSupported (); +} + diff --git a/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c b/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c new file mode 100644 index 0000000000..6a5acad376 --- /dev/null +++ b/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c @@ -0,0 +1,175 @@ +/** @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. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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 reqruied 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 transistions to calling in virtual mode, all future + // runtime calls will be made in virtual mode. + // + return; +} + + + diff --git a/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf b/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf new file mode 100644 index 0000000000..b9f39dd380 --- /dev/null +++ b/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf @@ -0,0 +1,38 @@ +#%HEADER% +#/** @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. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[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 + \ No newline at end of file diff --git a/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c b/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c new file mode 100644 index 0000000000..fe02f9863f --- /dev/null +++ b/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c @@ -0,0 +1,103 @@ +/** @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. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#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/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf b/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf new file mode 100644 index 0000000000..4b6fa5bb1a --- /dev/null +++ b/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf @@ -0,0 +1,36 @@ +#%HEADER% +#/** @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. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[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 \ No newline at end of file diff --git a/EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.c b/EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.c new file mode 100644 index 0000000000..98087f9dc0 --- /dev/null +++ b/EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.c @@ -0,0 +1,99 @@ +/** @file + Serial I/O Port library functions with no library constructor/destructor + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + + +#include + +/* + + Programmed hardware of Serial port. + + @return Always return EFI_UNSUPPORTED. + +**/ +RETURN_STATUS +EFIAPI +SerialPortInitialize ( + VOID + ) +{ + return RETURN_UNSUPPORTED; +} + +/** + Write data to serial device. + + @param Buffer Point of data buffer which need to be writed. + @param NumberOfBytes Number of output bytes which are cached in Buffer. + + @retval 0 Write data failed. + @retval !0 Actual number of bytes writed to serial device. + +**/ +UINTN +EFIAPI +SerialPortWrite ( + IN UINT8 *Buffer, + IN UINTN NumberOfBytes +) +{ + return 0; +} + + +/** + Read data from serial device and save the datas in buffer. + + @param Buffer Point of data buffer which need to be writed. + @param NumberOfBytes Number of output bytes which are cached in Buffer. + + @retval 0 Read data failed. + @retval !0 Aactual number of bytes read from serial device. + +**/ +UINTN +EFIAPI +SerialPortRead ( + OUT UINT8 *Buffer, + IN UINTN NumberOfBytes +) +{ + return 0; +} + + + +/** + Poll the serial device to see if there is any data waiting. + + If there is data waiting to be read from the serial port, then return + TRUE. If there is no data waiting to be read from the serial port, then + return FALSE. + + @retval TRUE Data is waiting to be read. + @retval FALSE There is no data waiting to be read. + +**/ +BOOLEAN +EFIAPI +SerialPortPoll ( + VOID + ) +{ + return 0; +} + diff --git a/EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.inf b/EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.inf new file mode 100644 index 0000000000..e2a994b63e --- /dev/null +++ b/EmbeddedPkg/Library/TemplateSerialPortLib/TemplateSerialPortLib.inf @@ -0,0 +1,37 @@ +#%HEADER% +#/** @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. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TemplateSerialPortLib + FILE_GUID = A9133571-AD4B-4457-94A8-A9CC2CE7574F + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = SerialPortLib + + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + TemplateSerialPortLib.c + + +[Packages] + MdePkg/MdePkg.dec + diff --git a/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClock.c b/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClock.c new file mode 100644 index 0000000000..b93626a6fb --- /dev/null +++ b/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClock.c @@ -0,0 +1,158 @@ +/** @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. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include + +EFI_HANDLE mHandle = NULL; + + + +/** + 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 + ) +{ + 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 + ) +{ + return LibSetTime (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 +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; + + LibRtcInitialize (ImageHandle, SystemTable); + + 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/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf b/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf new file mode 100644 index 0000000000..f0afceeb65 --- /dev/null +++ b/EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf @@ -0,0 +1,45 @@ +#%HEADER% +#/** @file +# NT Emulation Reset Architectural Protocol Driver as defined in TIANO +# +# This Reset module simulates system reset by process exit on NT. +# Copyright (c) 2006 - 2007, Intel Corporation +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = RealTimeClock + FILE_GUID = B336F62D-4135-4A55-AE4E-4971BBF0885D + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeRealTimeClock + +[Sources.common] + RealTimeClock.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + RealTimeClockLib + +[Protocols] + gEfiRealTimeClockArchProtocolGuid + +[Depex] + TRUE + diff --git a/EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf b/EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf new file mode 100644 index 0000000000..956aab709a --- /dev/null +++ b/EmbeddedPkg/ResetRuntimeDxe/ResetRuntimeDxe.inf @@ -0,0 +1,51 @@ +#%HEADER% +#/** @file +# NT Emulation Reset Architectural Protocol Driver as defined in TIANO +# +# This Reset module simulates system reset by process exit on NT. +# Copyright (c) 2006 - 2007, Intel Corporation +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Reset + FILE_GUID = 16036A73-E8EF-46D0-953C-9B8E96527D13 + MODULE_TYPE = DXE_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/EmbeddedPkg/ResetRuntimeDxe/reset.c b/EmbeddedPkg/ResetRuntimeDxe/reset.c new file mode 100644 index 0000000000..3327b8d1ec --- /dev/null +++ b/EmbeddedPkg/ResetRuntimeDxe/reset.c @@ -0,0 +1,74 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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/EmbeddedPkg/SerialDxe/SerialDxe.inf b/EmbeddedPkg/SerialDxe/SerialDxe.inf new file mode 100644 index 0000000000..29c0aa8c2a --- /dev/null +++ b/EmbeddedPkg/SerialDxe/SerialDxe.inf @@ -0,0 +1,54 @@ +#%HEADER% +#/** @file +# +# Component discription file for Bds module +# +# Copyright (c) 2008, Intel Corporation.
+# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SerialDxe + FILE_GUID = D3987D4B-971A-435F-8CAF-4967EB627241 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = SerialDxeInitialize + + +[Sources.common] + SerialIo.c + + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + ReportStatusCodeLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + UefiDriverEntryPoint + SerialPortLib + +[Guids] + + +[Protocols] + gEfiSerialIoProtocolGuid + gEfiDevicePathProtocolGuid + + +[Depex] + TRUE diff --git a/EmbeddedPkg/SerialDxe/SerialIo.c b/EmbeddedPkg/SerialDxe/SerialIo.c new file mode 100644 index 0000000000..aa9653bcf3 --- /dev/null +++ b/EmbeddedPkg/SerialDxe/SerialIo.c @@ -0,0 +1,258 @@ +/** @file + Serial IO Abstraction for GDB stub. This allows an EFI consoles that shows up on the system + running GDB. One consle for error information and another console for user input/output. + + Basic packet format is $packet-data#checksum. So every comand 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. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include + +#include + +/** + 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 +SerialReset ( + IN EFI_SERIAL_IO_PROTOCOL *This + ) +{ + SerialPortInitialize (); + return EFI_SUCCESS; +} + + +/** + Sets the baud rate, receive FIFO depth, transmit/receice 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 ReveiveFifoDepth The requested depth of the FIFO on the receive side of the + serial interface. A ReceiveFifoDepth value of 0 will use + the device's dfault 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 + vaule 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 +SerialSetAttributes ( + 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 +SerialSetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN UINT32 Control + ) +{ + return EFI_UNSUPPORTED; +} + + +/** + Retrieves the status of thecontrol 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 +SerialGetControl ( + IN EFI_SERIAL_IO_PROTOCOL *This, + OUT UINT32 *Control + ) +{ + if (SerialPortPoll ()) { + // If a character is pending don't set EFI_SERIAL_INPUT_BUFFER_EMPTY + *Control = EFI_SERIAL_OUTPUT_BUFFER_EMPTY; + } else { + *Control = EFI_SERIAL_INPUT_BUFFER_EMPTY | EFI_SERIAL_OUTPUT_BUFFER_EMPTY; + } + 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 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 +SerialWrite ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + UINTN Count; + + Count = SerialPortWrite (Buffer, *BufferSize); + *BufferSize = Count; + return (Count == 0) ? EFI_DEVICE_ERROR : 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 +SerialRead ( + IN EFI_SERIAL_IO_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + UINTN Count; + + Count = SerialPortWrite (Buffer, *BufferSize); + *BufferSize = Count; + return (Count == 0) ? EFI_DEVICE_ERROR : EFI_SUCCESS; +} + + +EFI_HANDLE gHandle = NULL; + +// +// Template used to initailize the GDB Serial IO protocols +// +EFI_SERIAL_IO_MODE gSerialIoMode = { + 0, // ControlMask + 0, // Timeout + 0, // BaudRate + 1, // RceiveFifoDepth + 0, // DataBits + 0, // Parity + 0 // StopBits +}; + + +EFI_SERIAL_IO_PROTOCOL gSerialIoTemplate = { + SERIAL_IO_INTERFACE_REVISION, + SerialReset, + SerialSetAttributes, + SerialSetControl, + SerialGetControl, + SerialWrite, + SerialRead, + &gSerialIoMode +}; + + +/** + Initialize the state information for the Serial Io 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 +SerialDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + + // Make a new handle with Serial IO protocol and its device path on it. + Status = gBS->InstallMultipleProtocolInterfaces ( + &gHandle, + &gEfiSerialIoProtocolGuid, &gSerialIoTemplate, + &gEfiDevicePathProtocolGuid, NULL, // BugBug: Need a device path + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + diff --git a/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOut.c b/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOut.c new file mode 100644 index 0000000000..f491de6e95 --- /dev/null +++ b/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOut.c @@ -0,0 +1,671 @@ +/** @file + Simple Console that sits on a SerialLib. + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +/* + 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 + + +#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; + + + +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; + + SerialPortRead ((UINT8 *)&Char, 1); + + // + // Check for ESC sequence. This code is not techincally 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 = StrLen(String) + 1; + CHAR8 *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); + + 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, + NULL + ); + if (!EFI_ERROR (Status)) { + gST->ConOut = &mSimpleTextOut; + gST->ConIn = &mSimpleTextIn; + } + + return Status; +} diff --git a/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOutSerial.inf b/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOutSerial.inf new file mode 100644 index 0000000000..17821d62f7 --- /dev/null +++ b/EmbeddedPkg/SimpleTextInOutSerial/SimpleTextInOutSerial.inf @@ -0,0 +1,56 @@ +#%HEADER% +#/** @file +# +# Component discription file for Bds module +# +# Copyright (c) 2008, Intel Corporation.
+# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[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 + +[depex] + TRUE diff --git a/EmbeddedPkg/TemplateBds/BdsEntry.c b/EmbeddedPkg/TemplateBds/BdsEntry.c new file mode 100644 index 0000000000..dcdf499d20 --- /dev/null +++ b/EmbeddedPkg/TemplateBds/BdsEntry.c @@ -0,0 +1,183 @@ +/** @file + The entry of the embedded BDS. This BDS does not follow the Boot Manager requirements + of the UEFI specification as it is designed to implement an embedded systmes + propriatary boot scheme. + + This template assume a DXE driver produces a SerialIo protocol not using the EFI + driver module and it will attempt to connect a console on top of this. + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "BdsEntry.h" + + +BOOLEAN gConsolePresent = FALSE; + + +EFI_HANDLE mBdsImageHandle = NULL; +EFI_BDS_ARCH_PROTOCOL gBdsProtocol = { + BdsEntry, +}; + + + + +/** + This function uses policy data from the platform to determine what operating + system or system utility should be loaded and invoked. This function call + also optionally make the use of user input to determine the operating system + or system utility to be loaded and invoked. When the DXE Core has dispatched + all the drivers on the dispatch queue, this function is called. This + function will attempt to connect the boot devices required to load and invoke + the selected operating system or system utility. During this process, + additional firmware volumes may be discovered that may contain addition DXE + drivers that can be dispatched by the DXE Core. If a boot device cannot be + fully connected, this function calls the DXE Service Dispatch() to allow the + DXE drivers from any newly discovered firmware volumes to be dispatched. + Then the boot device connection can be attempted again. If the same boot + device connection operation fails twice in a row, then that boot device has + failed, and should be skipped. This function should never return. + + @param This The EFI_BDS_ARCH_PROTOCOL instance. + + @return None. + +**/ +VOID +EFIAPI +BdsEntry ( + IN EFI_BDS_ARCH_PROTOCOL *This + ) +{ + EFI_STATUS Status; + UINTN NoHandles; + EFI_HANDLE *Buffer; + UINTN Index; + EFI_HANDLE FvHandle; + EFI_GUID *NameGuid; + + // + // This code assumes that a DXE driver produces a SerialIo protocol not following the EFI + // driver model. At a minimum we need to connect an EFI driver model terminal driver on top + // of the serial driver. + // + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSerialIoProtocolGuid, NULL, &NoHandles, &Buffer); + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < NoHandles; Index++) { + // For every Serial IO protocol in the system connect EFI drivers to it. + // This should cause the terminal driver to bind to the Serial IO protocol and produce a + // child handle that produces SimpleTextOut & SImpleTextIn protocols + gBS->ConnectController (Buffer[Index], NULL, NULL, TRUE); + } + + FreePool (Buffer); + } + + // + // Now we need to setup the EFI System Table with information about the console devices. + // This code is normally in the console spliter driver on platforms that support multiple + // consoles at the same time + // + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextOutProtocolGuid, NULL, &NoHandles, &Buffer); + if (!EFI_ERROR (Status)) { + // Use the first SimpleTextOut we find and update the EFI System Table + gST->ConsoleOutHandle = Buffer[0]; + gST->StandardErrorHandle = Buffer[0]; + Status = gBS->HandleProtocol (Buffer[0], &gEfiSimpleTextOutProtocolGuid, (VOID **)&gST->ConOut); + ASSERT_EFI_ERROR (Status); + + gST->StdErr = gST->ConOut; + + FreePool (Buffer); + + gConsolePresent = TRUE; + } + + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleTextInProtocolGuid, NULL, &NoHandles, &Buffer); + if (!EFI_ERROR (Status)) { + // Use the first SimpleTextIn we find and update the EFI System Table + gST->ConsoleInHandle = Buffer[0]; + Status = gBS->HandleProtocol (Buffer[0], &gEfiSimpleTextInProtocolGuid, (VOID **)&gST->ConIn); + ASSERT_EFI_ERROR (Status); + + FreePool (Buffer); + } + + // + // We now have EFI Consoles up and running. Print () will work now. DEBUG () and ASSERT () worked + // prior to this point as they were configured to use a more primative output scheme. + // + + + // + // Platform specific stuff goes here + // + + + // + // Normal UEFI behavior is to process Globally Defined Variables as defined in Chapter 3 + // (Boot Manager) of the UEFI specification. For this embedded system we don't do this. + // + + // + // Search all the FVs for an application with a UI Section of Ebl. A .FDF file can be used + // to control the names of UI sections in an FV. + // + Status = FindApplicationMatchingUiSection (L"Ebl", &FvHandle, &NameGuid); + if (EFI_ERROR (Status)) { + // + // Just load the first application we find reguardless of name. + // This is the fallback path. + // + Status = FindApplicationMatchingUiSection (NULL, &FvHandle, &NameGuid); + // Nothing to boot + ASSERT_EFI_ERROR (Status); + } + + Status = LoadPeCoffSectionFromFv (FvHandle, NameGuid); + + // + // EFI does not define the bavior if all boot attemps fail and the last one returns. + // So we make a policy choice to reset the system since this BDS does not have a UI. + // + gRT->ResetSystem (EfiResetCold, Status, 0, NULL); + + return ; +} + + +EFI_STATUS +EFIAPI +BdsInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + mBdsImageHandle = ImageHandle; + + // + // Install protocol interface + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mBdsImageHandle, + &gEfiBdsArchProtocolGuid, &gBdsProtocol, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + + diff --git a/EmbeddedPkg/TemplateBds/BdsEntry.h b/EmbeddedPkg/TemplateBds/BdsEntry.h new file mode 100644 index 0000000000..31eb6d7d4e --- /dev/null +++ b/EmbeddedPkg/TemplateBds/BdsEntry.h @@ -0,0 +1,62 @@ +/** @file + + Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#ifndef __BDS_ENTRY_H__ +#define __BDS_ENTRY_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + + + +EFI_STATUS +LoadPeCoffSectionFromFv ( + IN EFI_HANDLE FvHandle, + IN EFI_GUID *NameGuid + ); + +EFI_STATUS +FindApplicationMatchingUiSection ( + IN CHAR16 *UiString, + OUT EFI_HANDLE *FvHandle, + OUT EFI_GUID **NameGuid + ); + +VOID +EFIAPI +BdsEntry ( + IN EFI_BDS_ARCH_PROTOCOL *This + ); + +#endif + diff --git a/EmbeddedPkg/TemplateBds/FirmwareVolume.c b/EmbeddedPkg/TemplateBds/FirmwareVolume.c new file mode 100644 index 0000000000..b6a2206a86 --- /dev/null +++ b/EmbeddedPkg/TemplateBds/FirmwareVolume.c @@ -0,0 +1,160 @@ +/** @file + The entry of the embedded BDS. This BDS does not follow the Boot Manager requirements + of the UEFI specification as it is designed to implement an embedded systmes + propriatary boot scheme. + + This template assume a DXE driver produces a SerialIo protocol not using the EFI + driver module and it will attempt to connect a console on top of this. + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "BdsEntry.h" + + +EFI_STATUS +FindApplicationMatchingUiSection ( + IN CHAR16 *UiString, + OUT EFI_HANDLE *FvHandle, + OUT EFI_GUID **NameGuid + ) +{ + EFI_STATUS Status; + EFI_STATUS NextStatus; + UINTN NoHandles; + EFI_HANDLE *Buffer; + UINTN Index; + EFI_FV_FILETYPE FileType; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; + VOID *Key; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINTN Size; + UINTN UiStringLen; + CHAR16 *UiSection; + UINT32 Authentication; + + + UiStringLen = 0; + if (UiString != NULL) { + UiStringLen = StrLen (UiString); + } + + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiFirmwareVolume2ProtocolGuid, NULL, &NoHandles, &Buffer); + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < NoHandles; Index++) { + Status = gBS->HandleProtocol (Buffer[Index], &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv); + if (!EFI_ERROR (Status)) { + Key = AllocatePool (Fv->KeySize); + FileType = EFI_FV_FILETYPE_APPLICATION; + + do { + NextStatus = Fv->GetNextFile (Fv, Key, &FileType, *NameGuid, &Attributes, &Size); + if (!EFI_ERROR (NextStatus)) { + if (UiString == NULL) { + // + // If UiString is NULL match first application we find. + // + *FvHandle = Buffer[Index]; + FreePool (Key); + return Status; + } + + UiSection = NULL; + Status = Fv->ReadSection ( + Fv, + *NameGuid, + EFI_SECTION_USER_INTERFACE, + 0, + (VOID **)&UiSection, + &Size, + &Authentication + ); + if (!EFI_ERROR (Status)) { + if (StrnCmp (UiString, UiSection, UiStringLen)) { + // + // We found a UiString match. + // + *FvHandle = Buffer[Index]; + FreePool (Key); + FreePool (UiSection); + return Status; + } + FreePool (UiSection); + } + } + } while (!EFI_ERROR (NextStatus)); + + FreePool (Key); + } + } + + FreePool (Buffer); + } + + return EFI_NOT_FOUND; +} + + +EFI_DEVICE_PATH * +FvFileDevicePath ( + IN EFI_HANDLE FvHandle, + IN EFI_GUID *NameGuid + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH NewNode; + + DevicePath = DevicePathFromHandle (FvHandle); + + EfiInitializeFwVolDevicepathNode (&NewNode, NameGuid); + + return AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&NewNode); +} + + + +EFI_STATUS +LoadPeCoffSectionFromFv ( + IN EFI_HANDLE FvHandle, + IN EFI_GUID *NameGuid + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; + VOID *Buffer; + UINTN BufferSize; + UINT32 Authentication; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_HANDLE ImageHandle; + + Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = Fv->ReadSection (Fv, NameGuid, EFI_SECTION_PE32, 0, &Buffer, &BufferSize, &Authentication); + if (!EFI_ERROR (Status)) { + DevicePath = FvFileDevicePath (FvHandle, NameGuid); + Status = gBS->LoadImage (TRUE, gImageHandle, DevicePath, Buffer, BufferSize, &ImageHandle); + if (!EFI_ERROR (Status)) { + // ExitData is NULL so we need to pass in a size of zero + BufferSize = 0; + Status = gBS->StartImage (ImageHandle, &BufferSize, NULL); + } + + FreePool (Buffer); + } + + + return Status; +} + diff --git a/EmbeddedPkg/TemplateBds/TemplateBds.inf b/EmbeddedPkg/TemplateBds/TemplateBds.inf new file mode 100644 index 0000000000..5a3c1b9801 --- /dev/null +++ b/EmbeddedPkg/TemplateBds/TemplateBds.inf @@ -0,0 +1,68 @@ +#%HEADER% +#/** @file +# +# Component discription file for Bds module +# +# Copyright (c) 2008, Intel Corporation.
+# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TemplateBds + FILE_GUID = 3C85595C-70FD-447D-B0CB-7F6BBA9C9BEB + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = BdsInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + BdsEntry.c + FirmwareVolume.c + + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + DevicePathLib + BaseLib + HobLib + UefiRuntimeServicesTableLib + ReportStatusCodeLib + PerformanceLib + DxeServicesTableLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + PrintLib + UefiDriverEntryPoint + +[Guids] + + +[Protocols] + gEfiBdsArchProtocolGuid + gEfiSimpleTextInProtocolGuid + gEfiSimpleTextOutProtocolGuid + gEfiSerialIoProtocolGuid + gEfiDevicePathProtocolGuid + gEfiFirmwareVolume2ProtocolGuid + +[depex] + TRUE diff --git a/EmbeddedPkg/TemplateCpuDxe/Arm/Exception.c b/EmbeddedPkg/TemplateCpuDxe/Arm/Exception.c new file mode 100644 index 0000000000..e32d47e123 --- /dev/null +++ b/EmbeddedPkg/TemplateCpuDxe/Arm/Exception.c @@ -0,0 +1,250 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include + +VOID +ExceptionHandlersStart ( + VOID + ); + +VOID +ExceptionHandlersEnd ( + VOID + ); + +VOID +CommonExceptionEntry ( + VOID + ); + +VOID +AsmCommonExceptionEntry ( + VOID + ); + + +EFI_EXCEPTION_CALLBACK gExceptionHandlers[MAX_ARM_EXCEPTION + 1]; + + +/** + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + + @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disabled. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +EFI_STATUS +RegisterInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + if (InterruptType > MAX_ARM_EXCEPTION) { + return EFI_UNSUPPORTED; + } + + if ((InterruptHandler == NULL) && (gExceptionHandlers[InterruptType] == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) { + return EFI_ALREADY_STARTED; + } + + gExceptionHandlers[InterruptType] = InterruptHandler; + + return EFI_SUCCESS; +} + + + + +VOID +EFIAPI +DefaultSWIExceptionHandler( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + return; +} + + +VOID +EFIAPI +DefaultExceptionHandler( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + DEBUG ((EFI_D_ERROR, "Exception %d from %x\n", ExceptionType, SystemContext.SystemContextArm->PC)); + ASSERT (FALSE); + + return; +} + + + +EFI_STATUS +InitializeExceptions ( + IN EFI_CPU_ARCH_PROTOCOL *Cpu + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINTN Offset; + UINTN Length; + UINTN Index; + BOOLEAN Enabled; + + // + // Disable interrupts + // + Cpu->GetInterruptState (Cpu, &Enabled); + Cpu->DisableInterrupt (Cpu); + + // + // Initialize the C entry points for interrupts + // + for (Index = 0; Index <= MAX_ARM_EXCEPTION; Index++) { + if (Index == EXCEPT_ARM_SOFTWARE_INTERRUPT) { + Status = Cpu->RegisterInterruptHandler (Cpu, Index, DefaultSWIExceptionHandler); + } else { + Status = Cpu->RegisterInterruptHandler (Cpu, Index, DefaultExceptionHandler); + } + ASSERT_EFI_ERROR (Status); + } + + // + // Copy an implementation of the ARM exception vectors to 0x0. + // + Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart; + + CopyMem ((VOID *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress), (VOID *)ExceptionHandlersStart, Length); + + // + // Patch in the common Assembly exception handler + // + Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart; + *(UINTN *) ((UINT8 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress) + Offset) = (UINTN)AsmCommonExceptionEntry; + + // + // Flush Caches since we updated executable stuff + // + InvalidateInstructionCache (); + + if (Enabled) { + // + // Restore interrupt state + // + Status = Cpu->EnableInterrupt (Cpu); + } + + return Status; +} + + + +/** + This function reads the processor timer specified by TimerIndex and returns it in TimerValue. + + @param TimerIndex Specifies which processor timer is to be returned in TimerValue. This parameter + must be between 0 and NumberOfTimers-1. + @param TimerValue Pointer to the returned timer value. + @param TimerPeriod A pointer to the amount of time that passes in femtoseconds for each increment + of TimerValue. + + @retval EFI_SUCCESS The processor timer value specified by TimerIndex was returned in TimerValue. + @retval EFI_DEVICE_ERROR An error occurred attempting to read one of the processor's timers. + @retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid. + @retval EFI_UNSUPPORTED The processor does not have any readable timers. + +**/ +EFI_STATUS +EFIAPI +GetTimerValue ( + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ) +{ + return EFI_UNSUPPORTED; +} + + +/** + This function flushes the range of addresses from Start to Start+Length + from the processor's data cache. If Start is not aligned to a cache line + boundary, then the bytes before Start to the preceding cache line boundary + are also flushed. If Start+Length is not aligned to a cache line boundary, + then the bytes past Start+Length to the end of the next cache line boundary + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be + supported. If the data cache is fully coherent with all DMA operations, then + this function can just return EFI_SUCCESS. If the processor does not support + flushing a range of the data cache, then the entire data cache can be flushed. + + @param Start The beginning physical address to flush from the processor's data + cache. + @param Length The number of bytes to flush from the processor's data cache. This + function may flush more bytes than Length specifies depending upon + the granularity of the flush operation that the processor supports. + @param FlushType Specifies the type of flush operation to perform. + + @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from + the processor's data cache. + @retval EFI_UNSUPPORTED The processor does not support the cache flush type specified + by FlushType. + @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed + from the processor's data cache. + +**/ +EFI_STATUS +EFIAPI +FlushCpuDataCache ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ) +{ + if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) { + WriteBackInvalidateDataCacheRange((VOID *)(UINTN)Start, (UINTN)Length); + return EFI_SUCCESS; + } else if (FlushType == EfiCpuFlushTypeInvalidate) { + InvalidateDataCacheRange((VOID *)(UINTN)Start, (UINTN)Length); + return EFI_SUCCESS; + } else if (FlushType == EfiCpuFlushTypeWriteBack) { + WriteBackDataCacheRange((VOID *)(UINTN)Start, (UINTN)Length); + return EFI_SUCCESS; + } else { + return EFI_UNSUPPORTED; + } +} + + + + diff --git a/EmbeddedPkg/TemplateCpuDxe/Arm/Exceptions.S b/EmbeddedPkg/TemplateCpuDxe/Arm/Exceptions.S new file mode 100755 index 0000000000..d864759afd --- /dev/null +++ b/EmbeddedPkg/TemplateCpuDxe/Arm/Exceptions.S @@ -0,0 +1,158 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2008-2009 Apple Inc. All rights reserved. +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#------------------------------------------------------------------------------ + +.text +.align 2 + +.globl _ExceptionHandlersStart +.globl _ExceptionHandlersEnd +.globl _CommonExceptionEntry +.globl _AsmCommonExceptionEntry +.globl _gExceptionHandlers + +_ExceptionHandlersStart: + +_Reset: + b _ResetEntry + +_UndefinedInstruction: + b _UndefinedInstructionEntry + +_SoftwareInterrupt: + b _SoftwareInterruptEntry + +_PrefetchAbort: + b _PrefetchAbortEntry + +_DataAbort: + b _DataAbortEntry + +_ReservedException: + b _ReservedExceptionEntry + +_Irq: + b _IrqEntry + +_Fiq: + b _FiqEntry + +_ResetEntry: + stmfd sp!,{r0-r1} + mov r0,#0 + ldr r1,_CommonExceptionEntry + bx r1 + +_UndefinedInstructionEntry: + stmfd sp!,{r0-r1} + mov r0,#1 + ldr r1,_CommonExceptionEntry + bx r1 + +_SoftwareInterruptEntry: + stmfd sp!,{r0-r1} + mov r0,#2 + ldr r1,_CommonExceptionEntry + bx r1 + +_PrefetchAbortEntry: + stmfd sp!,{r0-r1} + mov r0,#3 + sub lr,lr,#4 + ldr r1,_CommonExceptionEntry + bx r1 + +_DataAbortEntry: + stmfd sp!,{r0-r1} + mov r0,#4 + sub lr,lr,#8 + ldr r1,_CommonExceptionEntry + bx r1 + +_ReservedExceptionEntry: + stmfd sp!,{r0-r1} + mov r0,#5 + ldr r1,_CommonExceptionEntry + bx r1 + +_IrqEntry: + stmfd sp!,{r0-r1} + mov r0,#6 + sub lr,lr,#4 + ldr r1,_CommonExceptionEntry + bx r1 + +_FiqEntry: + stmfd sp!,{r0-r1} + mov r0,#7 + sub lr,lr,#4 + ldr r1,_CommonExceptionEntry + bx r1 + +_CommonExceptionEntry: + .byte 0x12 + .byte 0x34 + .byte 0x56 + .byte 0x78 + +_ExceptionHandlersEnd: + +LIndirectgExceptionHandlers: + .long _gExceptionHandlers + +_AsmCommonExceptionEntry: + mrc p15, 0, r1, c6, c0, 2 @ Read IFAR + stmfd sp!,{r1} @ Store the IFAR + + mrc p15, 0, r1, c5, c0, 1 @ Read IFSR + stmfd sp!,{r1} @ Store the IFSR + + mrc p15, 0, r1, c6, c0, 0 @ Read DFAR + stmfd sp!,{r1} @ Store the DFAR + + mrc p15, 0, r1, c5, c0, 0 @ Read DFSR + stmfd sp!,{r1} @ Store the DFSR + + mrs r1,spsr @ Read SPSR (which is the pre-exception CPSR) + stmfd sp!,{r1} @ Store the SPSR + + stmfd sp!,{lr} @ Store the link register (which is the pre-exception PC) + stmfd sp,{sp,lr}^ @ Store user/system mode stack pointer and link register + nop @ Required by ARM architecture + sub sp,sp,#0x08 @ Adjust stack pointer + stmfd sp!,{r2-r12} @ Store general purpose registers + + ldr r3,[sp,#0x40] @ Read saved R1 from the stack (it was saved by the exception entry routine) + ldr r2,[sp,#0x3C] @ Read saved R0 from the stack (it was saved by the exception entry routine) + stmfd sp!,{r2-r3} @ Store general purpose registers R0 and R1 + + mov r1,sp @ Prepare System Context pointer as an argument for the exception handler + + ldr r2,LIndirectgExceptionHandlers @ Offset to 32-bit address of exception handler + ldr r2,[r2] @ Load exception handler table + ldr r3,[r2,r0,lsl #2] @ Index to find the handler for this exception + +// blx r3 @ Call exception handler + bx r3 @ Call exception handler + + ldr r2,[sp,#0x40] @ Load CPSR from context, in case it has changed + msr SPSR_cxsf,r2 @ Store it back to the SPSR to be restored when exiting this handler + + ldmfd sp!,{r0-r12} @ Restore general purpose registers + ldmia sp,{sp,lr}^ @ Restore user/system mode stack pointer and link register + nop @ Required by ARM architecture + add sp,sp,#0x08 @ Adjust stack pointer + ldmfd sp!,{lr} @ Restore the link register (which is the pre-exception PC) + add sp,sp,#0x1C @ Clear out the remaining stack space + movs pc,lr @ Return from exception + diff --git a/EmbeddedPkg/TemplateCpuDxe/Arm/Exceptions.asm b/EmbeddedPkg/TemplateCpuDxe/Arm/Exceptions.asm new file mode 100755 index 0000000000..b91639d149 --- /dev/null +++ b/EmbeddedPkg/TemplateCpuDxe/Arm/Exceptions.asm @@ -0,0 +1,152 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) 2008-2009 Apple Inc. All rights reserved. +// +// All rights reserved. This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +//------------------------------------------------------------------------------ + + EXPORT ExceptionHandlersStart + EXPORT ExceptionHandlersEnd + EXPORT CommonExceptionEntry + EXPORT AsmCommonExceptionEntry + IMPORT gExceptionHandlers + + AREA DxeExceptionHandlers, CODE, READONLY + +ExceptionHandlersStart + +Reset + B ResetEntry + +UndefinedInstruction + B UndefinedInstructionEntry + +SoftwareInterrupt + B SoftwareInterruptEntry + +PrefetchAbort + B PrefetchAbortEntry + +DataAbort + B DataAbortEntry + +ReservedException + B ReservedExceptionEntry + +Irq + B IrqEntry + +Fiq + B FiqEntry + +ResetEntry + STMFD SP!,{R0-R1} + MOV R0,#0 + LDR R1,CommonExceptionEntry + BX R1 + +UndefinedInstructionEntry + STMFD SP!,{R0-R1} + MOV R0,#1 + LDR R1,CommonExceptionEntry + BX R1 + +SoftwareInterruptEntry + STMFD SP!,{R0-R1} + MOV R0,#2 + LDR R1,CommonExceptionEntry + BX R1 + +PrefetchAbortEntry + STMFD SP!,{R0-R1} + MOV R0,#3 + SUB LR,LR,#4 + LDR R1,CommonExceptionEntry + BX R1 + +DataAbortEntry + STMFD SP!,{R0-R1} + MOV R0,#4 + SUB LR,LR,#8 + LDR R1,CommonExceptionEntry + BX R1 + +ReservedExceptionEntry + STMFD SP!,{R0-R1} + MOV R0,#5 + LDR R1,CommonExceptionEntry + BX R1 + +IrqEntry + STMFD SP!,{R0-R1} + MOV R0,#6 + SUB LR,LR,#4 + LDR R1,CommonExceptionEntry + BX R1 + +FiqEntry + STMFD SP!,{R0-R1} + MOV R0,#7 + SUB LR,LR,#4 + LDR R1,CommonExceptionEntry + BX R1 + +CommonExceptionEntry + DCD 0x12345678 + +ExceptionHandlersEnd + +AsmCommonExceptionEntry + MRC p15, 0, r1, c6, c0, 2 ; Read IFAR + STMFD SP!,{R1} ; Store the IFAR + + MRC p15, 0, r1, c5, c0, 1 ; Read IFSR + STMFD SP!,{R1} ; Store the IFSR + + MRC p15, 0, r1, c6, c0, 0 ; Read DFAR + STMFD SP!,{R1} ; Store the DFAR + + MRC p15, 0, r1, c5, c0, 0 ; Read DFSR + STMFD SP!,{R1} ; Store the DFSR + + MRS R1,SPSR ; Read SPSR (which is the pre-exception CPSR) + STMFD SP!,{R1} ; Store the SPSR + + STMFD SP!,{LR} ; Store the link register (which is the pre-exception PC) + STMFD SP,{SP,LR}^ ; Store user/system mode stack pointer and link register + NOP ; Required by ARM architecture + SUB SP,SP,#0x08 ; Adjust stack pointer + STMFD SP!,{R2-R12} ; Store general purpose registers + + LDR R3,[SP,#0x40] ; Read saved R1 from the stack (it was saved by the exception entry routine) + LDR R2,[SP,#0x3C] ; Read saved R0 from the stack (it was saved by the exception entry routine) + STMFD SP!,{R2-R3} ; Store general purpose registers R0 and R1 + + MOV R1,SP ; Prepare System Context pointer as an argument for the exception handler + + LDR R2,=gExceptionHandlers ; Load exception handler table + LDR R3,[R2,R0,LSL #2] ; Index to find the handler for this exception + + BLX R3 ; Call exception handler + + LDR R2,[SP,#0x40] ; Load CPSR from context, in case it has changed + MSR SPSR_cxsf,R2 ; Store it back to the SPSR to be restored when exiting this handler + + LDMFD SP!,{R0-R12} ; Restore general purpose registers + LDM SP,{SP,LR}^ ; Restore user/system mode stack pointer and link register + NOP ; Required by ARM architecture + ADD SP,SP,#0x08 ; Adjust stack pointer + LDMFD SP!,{LR} ; Restore the link register (which is the pre-exception PC) + ADD SP,SP,#0x1C ; Clear out the remaining stack space + MOVS PC,LR ; Return from exception + + END + + diff --git a/EmbeddedPkg/TemplateCpuDxe/CpuDxe.c b/EmbeddedPkg/TemplateCpuDxe/CpuDxe.c new file mode 100644 index 0000000000..90bf8a9af8 --- /dev/null +++ b/EmbeddedPkg/TemplateCpuDxe/CpuDxe.c @@ -0,0 +1,323 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuDxe.h" + + + +/** + This function flushes the range of addresses from Start to Start+Length + from the processor's data cache. If Start is not aligned to a cache line + boundary, then the bytes before Start to the preceding cache line boundary + are also flushed. If Start+Length is not aligned to a cache line boundary, + then the bytes past Start+Length to the end of the next cache line boundary + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be + supported. If the data cache is fully coherent with all DMA operations, then + this function can just return EFI_SUCCESS. If the processor does not support + flushing a range of the data cache, then the entire data cache can be flushed. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param Start The beginning physical address to flush from the processor's data + cache. + @param Length The number of bytes to flush from the processor's data cache. This + function may flush more bytes than Length specifies depending upon + the granularity of the flush operation that the processor supports. + @param FlushType Specifies the type of flush operation to perform. + + @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from + the processor's data cache. + @retval EFI_UNSUPPORTED The processor does not support the cache flush type specified + by FlushType. + @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed + from the processor's data cache. + +**/ +EFI_STATUS +EFIAPI +CpuFlushCpuDataCache ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ) +{ + return FlushCpuDataCache (Start, Length, FlushType); +} + + +/** + This function enables interrupt processing by the processor. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + + @retval EFI_SUCCESS Interrupts are enabled on the processor. + @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor. + +**/ +EFI_STATUS +EFIAPI +CpuEnableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ) +{ + EnableInterrupts (); + return EFI_SUCCESS; +} + + +/** + This function disables interrupt processing by the processor. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + + @retval EFI_SUCCESS Interrupts are disabled on the processor. + @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor. + +**/ +EFI_STATUS +EFIAPI +CpuDisableInterrupt ( + IN EFI_CPU_ARCH_PROTOCOL *This + ) +/*++ + +Routine Description: + Disables CPU interrupts. + +Arguments: + This - Protocol instance structure + +Returns: + EFI_SUCCESS - If interrupts were disabled in the CPU. + EFI_DEVICE_ERROR - If interrupts could not be disabled on the CPU. + +--*/ +{ + DisableInterrupts (); + return EFI_SUCCESS; +} + + +/** + This function retrieves the processor's current interrupt state a returns it in + State. If interrupts are currently enabled, then TRUE is returned. If interrupts + are currently disabled, then FALSE is returned. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param State A pointer to the processor's current interrupt state. Set to TRUE if + interrupts are enabled and FALSE if interrupts are disabled. + + @retval EFI_SUCCESS The processor's current interrupt state was returned in State. + @retval EFI_INVALID_PARAMETER State is NULL. + +**/ +EFI_STATUS +EFIAPI +CpuGetInterruptState ( + IN EFI_CPU_ARCH_PROTOCOL *This, + OUT BOOLEAN *State + ) +{ + if (State == NULL) { + return EFI_INVALID_PARAMETER; + } + + *State = GetInterruptState (); + return EFI_SUCCESS; +} + + +/** + This function generates an INIT on the processor. If this function succeeds, then the + processor will be reset, and control will not be returned to the caller. If InitType is + not supported by this processor, or the processor cannot programmatically generate an + INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error + occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param InitType The type of processor INIT to perform. + + @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen. + @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported + by this processor. + @retval EFI_DEVICE_ERROR The processor INIT failed. + +**/ +EFI_STATUS +EFIAPI +CpuInit ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_CPU_INIT_TYPE InitType + ) +{ + return EFI_UNSUPPORTED; +} + + +/** + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disabled. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +EFI_STATUS +EFIAPI +CpuRegisterInterruptHandler ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + return RegisterInterruptHandler (InterruptType, InterruptHandler); +} + + +/** + This function reads the processor timer specified by TimerIndex and returns it in TimerValue. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param TimerIndex Specifies which processor timer is to be returned in TimerValue. This parameter + must be between 0 and NumberOfTimers-1. + @param TimerValue Pointer to the returned timer value. + @param TimerPeriod A pointer to the amount of time that passes in femtoseconds for each increment + of TimerValue. + + @retval EFI_SUCCESS The processor timer value specified by TimerIndex was returned in TimerValue. + @retval EFI_DEVICE_ERROR An error occurred attempting to read one of the processor's timers. + @retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid. + @retval EFI_UNSUPPORTED The processor does not have any readable timers. + +**/ +EFI_STATUS +EFIAPI +CpuGetTimerValue ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ) +{ + return GetTimerValue (TimerIndex, TimerValue, TimerPeriod); +} + + +/** + This function modifies the attributes for the memory region specified by BaseAddress and + Length from their current attributes to the attributes specified by Attributes. + + @param This The EFI_CPU_ARCH_PROTOCOL instance. + @param BaseAddress The physical address that is the start address of a memory region. + @param Length The size in bytes of the memory region. + @param Attributes The bit mask of attributes to set for the memory region. + + @retval EFI_SUCCESS The attributes were set for the memory region. + @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by + BaseAddress and Length cannot be modified. + @retval EFI_INVALID_PARAMETER Length is zero. + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of + the memory resource range. + @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory + resource range specified by BaseAddress and Length. + The bit mask of attributes is not support for the memory resource + range specified by BaseAddress and Length. + +**/ +EFI_STATUS +EFIAPI +CpuSetMemoryAttributes ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ) +{ + // + // This is used to set cachability via the MMU on ARM + // + // This more about optimization and we can usually run fine if the default + // settings for cachability are good. + // + return EFI_UNSUPPORTED; +} + + + + +// +// Globals used to initialize the protocol +// +EFI_HANDLE mCpuHandle = NULL; +EFI_CPU_ARCH_PROTOCOL mCpu = { + CpuFlushCpuDataCache, + CpuEnableInterrupt, + CpuDisableInterrupt, + CpuGetInterruptState, + CpuInit, + CpuRegisterInterruptHandler, + CpuGetTimerValue, + CpuSetMemoryAttributes, + 0, // NumberOfTimers + 4, // DmaBufferAlignment +}; + + +/** + 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 +CpuDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + InitializeExceptions (&mCpu); + + // + // Install CPU Architectural Protocol and the thunk protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mCpuHandle, + &gEfiCpuArchProtocolGuid, &mCpu, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + diff --git a/EmbeddedPkg/TemplateCpuDxe/CpuDxe.h b/EmbeddedPkg/TemplateCpuDxe/CpuDxe.h new file mode 100644 index 0000000000..c81d8012f8 --- /dev/null +++ b/EmbeddedPkg/TemplateCpuDxe/CpuDxe.h @@ -0,0 +1,124 @@ +/** @file + + Copyright (c) 2006 - 2008, Intel Corporation
+ Portions copyright (c) 2008-2009 Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +/** + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + + @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disabled. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +EFI_STATUS +RegisterInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ); + + +EFI_STATUS +InitializeExceptions ( + IN EFI_CPU_ARCH_PROTOCOL *Cpu + ); + + +/** + This function reads the processor timer specified by TimerIndex and returns it in TimerValue. + + @param TimerIndex Specifies which processor timer is to be returned in TimerValue. This parameter + must be between 0 and NumberOfTimers-1. + @param TimerValue Pointer to the returned timer value. + @param TimerPeriod A pointer to the amount of time that passes in femtoseconds for each increment + of TimerValue. + + @retval EFI_SUCCESS The processor timer value specified by TimerIndex was returned in TimerValue. + @retval EFI_DEVICE_ERROR An error occurred attempting to read one of the processor's timers. + @retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid. + @retval EFI_UNSUPPORTED The processor does not have any readable timers. + +**/ +EFI_STATUS +GetTimerValue ( + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ); + + +/** + This function flushes the range of addresses from Start to Start+Length + from the processor's data cache. If Start is not aligned to a cache line + boundary, then the bytes before Start to the preceding cache line boundary + are also flushed. If Start+Length is not aligned to a cache line boundary, + then the bytes past Start+Length to the end of the next cache line boundary + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be + supported. If the data cache is fully coherent with all DMA operations, then + this function can just return EFI_SUCCESS. If the processor does not support + flushing a range of the data cache, then the entire data cache can be flushed. + + @param Start The beginning physical address to flush from the processor's data + cache. + @param Length The number of bytes to flush from the processor's data cache. This + function may flush more bytes than Length specifies depending upon + the granularity of the flush operation that the processor supports. + @param FlushType Specifies the type of flush operation to perform. + + @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from + the processor's data cache. + @retval EFI_UNSUPPORTED The processor does not support the cache flush type specified + by FlushType. + @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed + from the processor's data cache. + +**/ +EFI_STATUS +EFIAPI +FlushCpuDataCache ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ); + + diff --git a/EmbeddedPkg/TemplateCpuDxe/IA32/Exception.c b/EmbeddedPkg/TemplateCpuDxe/IA32/Exception.c new file mode 100644 index 0000000000..5ba38e1623 --- /dev/null +++ b/EmbeddedPkg/TemplateCpuDxe/IA32/Exception.c @@ -0,0 +1,183 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + + +EFI_EXCEPTION_CALLBACK gExceptionHandlers[0x100]; + + +/** + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + + @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disabled. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +EFI_STATUS +RegisterInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + if (InterruptType > 0xFF) { + return EFI_UNSUPPORTED; + } + + if ((InterruptHandler == NULL) && (gExceptionHandlers[InterruptType] == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) { + return EFI_ALREADY_STARTED; + } + + gExceptionHandlers[InterruptType] = InterruptHandler; + + return EFI_SUCCESS; +} + + + + +VOID +EFIAPI +DefaultExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + DEBUG ((EFI_D_ERROR, "Exception %d from %x\n", ExceptionType, SystemContext.SystemContextIa32->Eip)); + ASSERT (FALSE); + + return; +} + + + +EFI_STATUS +InitializeExceptions ( + IN EFI_CPU_ARCH_PROTOCOL *Cpu + ) +{ + // You need to initialize gExceptionHandlers[] to point to DefaultExceptionHandler() + // and write all the assembly to handle the interrupts. + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + + + +/** + This function reads the processor timer specified by TimerIndex and returns it in TimerValue. + + @param TimerIndex Specifies which processor timer is to be returned in TimerValue. This parameter + must be between 0 and NumberOfTimers-1. + @param TimerValue Pointer to the returned timer value. + @param TimerPeriod A pointer to the amount of time that passes in femtoseconds for each increment + of TimerValue. + + @retval EFI_SUCCESS The processor timer value specified by TimerIndex was returned in TimerValue. + @retval EFI_DEVICE_ERROR An error occurred attempting to read one of the processor's timers. + @retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid. + @retval EFI_UNSUPPORTED The processor does not have any readable timers. + +**/ +EFI_STATUS +EFIAPI +GetTimerValue ( + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ) +{ + if (TimerValue == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (TimerIndex == 0) { + *TimerValue = AsmReadTsc (); + if (TimerPeriod != NULL) { + // + // BugBug: Hard coded. Don't know how to do this generically + // + *TimerPeriod = 1000000000; + } + return EFI_SUCCESS; + } + return EFI_INVALID_PARAMETER; +} + + +/** + This function flushes the range of addresses from Start to Start+Length + from the processor's data cache. If Start is not aligned to a cache line + boundary, then the bytes before Start to the preceding cache line boundary + are also flushed. If Start+Length is not aligned to a cache line boundary, + then the bytes past Start+Length to the end of the next cache line boundary + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be + supported. If the data cache is fully coherent with all DMA operations, then + this function can just return EFI_SUCCESS. If the processor does not support + flushing a range of the data cache, then the entire data cache can be flushed. + + @param Start The beginning physical address to flush from the processor's data + cache. + @param Length The number of bytes to flush from the processor's data cache. This + function may flush more bytes than Length specifies depending upon + the granularity of the flush operation that the processor supports. + @param FlushType Specifies the type of flush operation to perform. + + @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from + the processor's data cache. + @retval EFI_UNSUPPORTED The processor does not support the cache flush type specified + by FlushType. + @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed + from the processor's data cache. + +**/ +EFI_STATUS +EFIAPI +FlushCpuDataCache ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ) +{ + if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) { + AsmWbinvd (); + return EFI_SUCCESS; + } else if (FlushType == EfiCpuFlushTypeInvalidate) { + AsmInvd (); + return EFI_SUCCESS; + } else { + return EFI_UNSUPPORTED; + } +} + + + + diff --git a/EmbeddedPkg/TemplateCpuDxe/TemplateCpuDxe.inf b/EmbeddedPkg/TemplateCpuDxe/TemplateCpuDxe.inf new file mode 100644 index 0000000000..67d3edc7c4 --- /dev/null +++ b/EmbeddedPkg/TemplateCpuDxe/TemplateCpuDxe.inf @@ -0,0 +1,71 @@ +#%HEADER% +#/** @file +# +# Component discription file for Bds module +# +# Copyright (c) 2008, Intel Corporation.
+# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TemplateCpuDxe + FILE_GUID = CB6DC1E4-5B27-41E8-BC27-9AA50B62081E + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = CpuDxeInitialize + + +[Sources.common] + CpuDxe.c + +[Sources.ARM] + Arm/Exception.c + Arm/Exceptions.asm + Arm/Exceptions.S + +[Sources.IA32] + IA32/Exception.c + +[Sources.X64] + X64/Exception.c + + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[Packages.ARM] + ArmPkg/ArmPkg.dec + +[LibraryClasses] + BaseLib + UefiRuntimeServicesTableLib + ReportStatusCodeLib + PerformanceLib + DxeServicesTableLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + UefiDriverEntryPoint + CacheMaintenanceLib + +[Protocols] + gEfiCpuArchProtocolGuid + +[Pcd.ARM] + gArmTokenSpaceGuid.PcdCpuVectorBaseAddress + + +[depex] + TRUE diff --git a/EmbeddedPkg/TemplateCpuDxe/X64/Exception.c b/EmbeddedPkg/TemplateCpuDxe/X64/Exception.c new file mode 100644 index 0000000000..f86eda077a --- /dev/null +++ b/EmbeddedPkg/TemplateCpuDxe/X64/Exception.c @@ -0,0 +1,183 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + + +EFI_EXCEPTION_CALLBACK gExceptionHandlers[0x100]; + + +/** + This function registers and enables the handler specified by InterruptHandler for a processor + interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the + handler for the processor interrupt or exception type specified by InterruptType is uninstalled. + The installed handler is called once for each processor interrupt or exception. + + @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disabled. + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. If this parameter is NULL, then the handler + will be uninstalled. + + @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was + previously installed. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not + previously installed. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +EFI_STATUS +RegisterInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + if (InterruptType > 0xFF) { + return EFI_UNSUPPORTED; + } + + if ((InterruptHandler == NULL) && (gExceptionHandlers[InterruptType] == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) { + return EFI_ALREADY_STARTED; + } + + gExceptionHandlers[InterruptType] = InterruptHandler; + + return EFI_SUCCESS; +} + + + + +VOID +EFIAPI +DefaultExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + DEBUG ((EFI_D_ERROR, "Exception %d from %x\n", ExceptionType, SystemContext.SystemContextX64->Rip)); + ASSERT (FALSE); + + return; +} + + + +EFI_STATUS +InitializeExceptions ( + IN EFI_CPU_ARCH_PROTOCOL *Cpu + ) +{ + // You need to initialize gExceptionHandlers[] to point to DefaultExceptionHandler() + // and write all the assembly to handle the interrupts. + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + + + +/** + This function reads the processor timer specified by TimerIndex and returns it in TimerValue. + + @param TimerIndex Specifies which processor timer is to be returned in TimerValue. This parameter + must be between 0 and NumberOfTimers-1. + @param TimerValue Pointer to the returned timer value. + @param TimerPeriod A pointer to the amount of time that passes in femtoseconds for each increment + of TimerValue. + + @retval EFI_SUCCESS The processor timer value specified by TimerIndex was returned in TimerValue. + @retval EFI_DEVICE_ERROR An error occurred attempting to read one of the processor's timers. + @retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid. + @retval EFI_UNSUPPORTED The processor does not have any readable timers. + +**/ +EFI_STATUS +EFIAPI +GetTimerValue ( + IN UINT32 TimerIndex, + OUT UINT64 *TimerValue, + OUT UINT64 *TimerPeriod OPTIONAL + ) +{ + if (TimerValue == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (TimerIndex == 0) { + *TimerValue = AsmReadTsc (); + if (TimerPeriod != NULL) { + // + // BugBug: Hard coded. Don't know how to do this generically + // + *TimerPeriod = 1000000000; + } + return EFI_SUCCESS; + } + return EFI_INVALID_PARAMETER; +} + + +/** + This function flushes the range of addresses from Start to Start+Length + from the processor's data cache. If Start is not aligned to a cache line + boundary, then the bytes before Start to the preceding cache line boundary + are also flushed. If Start+Length is not aligned to a cache line boundary, + then the bytes past Start+Length to the end of the next cache line boundary + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be + supported. If the data cache is fully coherent with all DMA operations, then + this function can just return EFI_SUCCESS. If the processor does not support + flushing a range of the data cache, then the entire data cache can be flushed. + + @param Start The beginning physical address to flush from the processor's data + cache. + @param Length The number of bytes to flush from the processor's data cache. This + function may flush more bytes than Length specifies depending upon + the granularity of the flush operation that the processor supports. + @param FlushType Specifies the type of flush operation to perform. + + @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from + the processor's data cache. + @retval EFI_UNSUPPORTED The processor does not support the cache flush type specified + by FlushType. + @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed + from the processor's data cache. + +**/ +EFI_STATUS +EFIAPI +FlushCpuDataCache ( + IN EFI_PHYSICAL_ADDRESS Start, + IN UINT64 Length, + IN EFI_CPU_FLUSH_TYPE FlushType + ) +{ + if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) { + AsmWbinvd (); + return EFI_SUCCESS; + } else if (FlushType == EfiCpuFlushTypeInvalidate) { + AsmInvd (); + return EFI_SUCCESS; + } else { + return EFI_UNSUPPORTED; + } +} + + + + diff --git a/EmbeddedPkg/TemplateMetronomeDxe/Metronome.c b/EmbeddedPkg/TemplateMetronomeDxe/Metronome.c new file mode 100644 index 0000000000..861bf249cd --- /dev/null +++ b/EmbeddedPkg/TemplateMetronomeDxe/Metronome.c @@ -0,0 +1,132 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + + + +/** + 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 + ) +{ + // + // Fill me in + // + MicroSecondDelay (10 * TickNumber); + return EFI_UNSUPPORTED; +} + + + +/** + Interface stucture 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, + 100 +}; + + +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 +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/EmbeddedPkg/TemplateMetronomeDxe/TemplateMetronomeDxe.inf b/EmbeddedPkg/TemplateMetronomeDxe/TemplateMetronomeDxe.inf new file mode 100644 index 0000000000..9a4e53a703 --- /dev/null +++ b/EmbeddedPkg/TemplateMetronomeDxe/TemplateMetronomeDxe.inf @@ -0,0 +1,50 @@ +#%HEADER% +#/** @file +# +# Component discription file for Bds module +# +# Copyright (c) 2008, Apple, Inc
+# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TemplateMetronomeDxe + 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 + +[LibraryClasses] + BaseLib + UefiLib + UefiBootServicesTableLib + DebugLib + PrintLib + UefiDriverEntryPoint + TimerLib + +[Guids] + + +[Protocols] + gEfiMetronomeArchProtocolGuid + +[depex] + TRUE diff --git a/EmbeddedPkg/TemplateSec/TemplateSec.c b/EmbeddedPkg/TemplateSec/TemplateSec.c new file mode 100644 index 0000000000..dbbf3cb815 --- /dev/null +++ b/EmbeddedPkg/TemplateSec/TemplateSec.c @@ -0,0 +1,76 @@ +/** @file + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include + +#include + +VOID +_ModuleEntryPoint ( + VOID + ) +{ +} + +VOID +CEntryPoint ( + VOID *MemoryBase, + UINTN MemorySize, + VOID *StackBase, + UINTN StackSize + ) +{ + EFI_PHYSICAL_ADDRESS MemoryBegin; + UINT64 MemoryLength; + VOID *HobBase; + + // + // Boot strap the C environment so the other library services will work properly. + // + MemoryBegin = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryBase; + MemoryLength = (UINT64)MemorySize; + HobBase = (VOID *)(UINTN)(FixedPcdGet32(PcdEmbeddedFdBaseAddress) + FixedPcdGet32(PcdEmbeddedFdSize)); + CreateHobList (MemoryBase, MemorySize, HobBase, StackBase); + + MemoryBegin = (EFI_PHYSICAL_ADDRESS)(UINTN)StackBase; + MemoryLength = (UINT64)StackSize; + UpdateStackHob (MemoryBegin, MemoryLength); + + DEBUG ((DEBUG_ERROR, "CEntryPoint (%x,%x,%x,%x)\n", MemoryBase, MemorySize, StackBase, StackSize)); + + // + // Add your C code stuff here.... + // + + + // + // Load the DXE Core and transfer control to it + // + + // Give the DXE Core access to our DEBUG and ASSERT infrastructure so this will work prior + // to the DXE version being loaded. Thus we close the debugging gap between phases. + AddDxeCoreReportStatusCodeCallback (); + + //BuildFvHobs (PcdBfvBase, PcdBfvSize, NULL); + + LoadDxeCoreFromFv (NULL, 0); + + // DXE Core should always load and never return + ASSERT (FALSE); +} + diff --git a/EmbeddedPkg/TemplateSec/TemplateSec.inf b/EmbeddedPkg/TemplateSec/TemplateSec.inf new file mode 100644 index 0000000000..5c62b7520e --- /dev/null +++ b/EmbeddedPkg/TemplateSec/TemplateSec.inf @@ -0,0 +1,66 @@ +#%HEADER% +#/** @file +# +# Component description file for DxeIpl module +# +# The responsibility of this module is to load the DXE Core from a Firmware Volume. This implementation i used to load a 32-bit DXE Core. +# +# Copyright (c) 2006 - 2008, Intel Corporation.
+# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TemplateSec + FILE_GUID = 1D6F730F-5A55-4078-869B-E0A18324BDC8 + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 ARM +# + +[Sources.common] + TemplateSec.c + +[Sources.Ia32] +# Ia32/ResetVector.asm | MSFT +# Ia32/ResetVector.S | GCC + +[Sources.X64] +# X64/ResetVector.asm | MSFT +# X64/ResetVector.S | GCC + +[Sources.ARM] +# Arm/ResetVector.asm | RVCT +# Arm/ResetVector.S | GCC + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + + +[LibraryClasses] + BaseLib + DebugLib + BaseMemoryLib + UefiDecompressLib + PeCoffLib + CacheMaintenanceLib + PrePiLib + +[Pcd] + gEmbeddedTokenSpaceGuid.PcdEmbeddedFdBaseAddress + gEmbeddedTokenSpaceGuid.PcdEmbeddedFdSize + diff --git a/EmbeddedPkg/TemplateTimerDxe/TemplateTimerDxe.inf b/EmbeddedPkg/TemplateTimerDxe/TemplateTimerDxe.inf new file mode 100644 index 0000000000..d7c1f05674 --- /dev/null +++ b/EmbeddedPkg/TemplateTimerDxe/TemplateTimerDxe.inf @@ -0,0 +1,56 @@ +#%HEADER% +#/** @file +# +# Component discription file for Bds module +# +# Copyright (c) 2008, Apple Inc.
+# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TemplateTimerDxe + FILE_GUID = E697928E-7C98-4501-8406-21F5509549CC + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = TimerInitialize + +[Sources.common] + Timer.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + BaseLib + UefiRuntimeServicesTableLib + PerformanceLib + UefiLib + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + UefiDriverEntryPoint + IoLib + +[Guids] + +[Protocols] + gEfiTimerArchProtocolGuid + gHardwareInterruptProtocolGuid + +[Pcd.common] + gEmbeddedTokenSpaceGuid.PcdTimerBaseAddress + gEmbeddedTokenSpaceGuid.PcdTimerVector + gEmbeddedTokenSpaceGuid.PcdTimerPeriod + +[Depex] + gHardwareInterruptProtocolGuid \ No newline at end of file diff --git a/EmbeddedPkg/TemplateTimerDxe/Timer.c b/EmbeddedPkg/TemplateTimerDxe/Timer.c new file mode 100644 index 0000000000..4bfa3e8622 --- /dev/null +++ b/EmbeddedPkg/TemplateTimerDxe/Timer.c @@ -0,0 +1,373 @@ +/** @file + Template for Timer Architecture Protocol driver of the ARM flavor + + Copyright (c) 2008-2009, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// +// Get Base Address of timer block from platform .DSC file +// +#define TIMER_BASE ((UINTN)FixedPcdGet32 (PcdTimerBaseAddress) + 0x00c0) + + +#define TIMER_CMD ((UINTN)FixedPcdGet32 (PcdTimerBaseAddress) + 0x00000004) +#define TIMER_DATA ((UINTN)FixedPcdGet32 (PcdTimerBaseAddress) + 0x00000008) + +// +// The notification function to call on every timer interrupt. +// A bug in the compiler prevents us from initializing this here. +// +volatile EFI_TIMER_NOTIFY mTimerNotifyFunction; + +// +// The current period of the timer interrupt +// +volatile UINT64 mTimerPeriod = 0; + +// +// Cached copy of the Hardware Interrupt protocol instance +// +EFI_HARDWARE_INTERRUPT_PROTOCOL *gInterrupt = NULL; + + +/** + 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 + +**/ +VOID +EFIAPI +TimerInterruptHandler ( + IN HARDWARE_INTERRUPT_SOURCE Source, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + EFI_TPL OriginalTPL; + + // Mask all interrupts + OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); + + MmioWrite32 (TIMER_CMD, 0); + + if (mTimerNotifyFunction) { + mTimerNotifyFunction (mTimerPeriod); + } + + // restore state + gBS->RestoreTPL (OriginalTPL); +} + + + +/** + This function registers the handler NotifyFunction so it is called every time + the timer interrupt fires. It also passes the amount of time since the last + handler call to the NotifyFunction. If NotifyFunction is NULL, then the + handler is unregistered. If the handler is registered, then EFI_SUCCESS is + returned. If the CPU does not support registering a timer interrupt handler, + then EFI_UNSUPPORTED is returned. If an attempt is made to register a handler + when a handler is already registered, then EFI_ALREADY_STARTED is returned. + If an attempt is made to unregister a handler when a handler is not registered, + then EFI_INVALID_PARAMETER is returned. If an error occurs attempting to + register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR + is returned. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param NotifyFunction The function to call when a timer interrupt fires. This + function executes at TPL_HIGH_LEVEL. The DXE Core will + register a handler for the timer interrupt, so it can know + how much time has passed. This information is used to + signal timer based events. NULL will unregister the handler. + + @retval EFI_SUCCESS The timer handler was registered. + @retval EFI_UNSUPPORTED The platform does not support timer interrupts. + @retval EFI_ALREADY_STARTED NotifyFunction is not NULL, and a handler is already + registered. + @retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler was not + previously registered. + @retval EFI_DEVICE_ERROR The timer handler could not be registered. + +**/ +EFI_STATUS +EFIAPI +TimerDriverRegisterHandler ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN EFI_TIMER_NOTIFY NotifyFunction + ) +{ + // + // Check for invalid parameters + // + if (NotifyFunction == NULL && mTimerNotifyFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (NotifyFunction != NULL && mTimerNotifyFunction != NULL) { + return EFI_ALREADY_STARTED; + } + + mTimerNotifyFunction = NotifyFunction; + + return EFI_SUCCESS; +} + + + +/** + This function adjusts the period of timer interrupts to the value specified + by TimerPeriod. If the timer period is updated, then the selected timer + period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If + the timer hardware is not programmable, then EFI_UNSUPPORTED is returned. + If an error occurs while attempting to update the timer period, then the + timer hardware will be put back in its state prior to this call, and + EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt + is disabled. This is not the same as disabling the CPU's interrupts. + Instead, it must either turn off the timer hardware, or it must adjust the + interrupt controller so that a CPU interrupt is not generated when the timer + interrupt fires. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param TimerPeriod The rate to program the timer interrupt in 100 nS units. If + the timer hardware is not programmable, then EFI_UNSUPPORTED is + returned. If the timer is programmable, then the timer period + will be rounded up to the nearest timer period that is supported + by the timer hardware. If TimerPeriod is set to 0, then the + timer interrupts will be disabled. + + @retval EFI_SUCCESS The timer period was changed. + @retval EFI_UNSUPPORTED The platform cannot change the period of the timer interrupt. + @retval EFI_DEVICE_ERROR The timer period could not be changed due to a device error. + +**/ +EFI_STATUS +EFIAPI +TimerDriverSetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + IN UINT64 TimerPeriod + ) +{ + EFI_STATUS Status; + UINT64 TimerCount; + + if (TimerPeriod == 0) { + // + // Disable interrupt 0 and timer + // + MmioAnd32 (TIMER_DATA, 0); + + Status = gInterrupt->DisableInterruptSource (gInterrupt, FixedPcdGet32 (PcdTimerVector)); + } else { + // + // Convert TimerPeriod into Timer F counts + // + TimerCount = DivU64x32 (TimerPeriod + 5, 10); + + // + // Program Timer F with the new count value + // + MmioWrite32 (TIMER_DATA, (UINT32)TimerCount); + + // + // Enable interrupt and initialize and enable timer. + // + MmioOr32 (TIMER_CMD, 0x11); + + Status = gInterrupt->EnableInterruptSource (gInterrupt, FixedPcdGet32 (PcdTimerVector)); + } + + // + // Save the new timer period + // + mTimerPeriod = TimerPeriod; + return Status; +} + + +/** + This function retrieves the period of timer interrupts in 100 ns units, + returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod + is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is + returned, then the timer is currently disabled. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + @param TimerPeriod A pointer to the timer period to retrieve in 100 ns units. If + 0 is returned, then the timer is currently disabled. + + @retval EFI_SUCCESS The timer period was returned in TimerPeriod. + @retval EFI_INVALID_PARAMETER TimerPeriod is NULL. + +**/ +EFI_STATUS +EFIAPI +TimerDriverGetTimerPeriod ( + IN EFI_TIMER_ARCH_PROTOCOL *This, + OUT UINT64 *TimerPeriod + ) +{ + if (TimerPeriod == NULL) { + return EFI_INVALID_PARAMETER; + } + + *TimerPeriod = mTimerPeriod; + return EFI_SUCCESS; +} + + + +/** + This function generates a soft timer interrupt. If the platform does not support soft + timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned. + If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler() + service, then a soft timer interrupt will be generated. If the timer interrupt is + enabled when this service is called, then the registered handler will be invoked. The + registered handler should not be able to distinguish a hardware-generated timer + interrupt from a software-generated timer interrupt. + + @param This The EFI_TIMER_ARCH_PROTOCOL instance. + + @retval EFI_SUCCESS The soft timer interrupt was generated. + @retval EFI_UNSUPPORTED The platform does not support the generation of soft timer interrupts. + +**/ +EFI_STATUS +EFIAPI +TimerDriverGenerateSoftInterrupt ( + IN EFI_TIMER_ARCH_PROTOCOL *This + ) +{ + return EFI_UNSUPPORTED; +} + + +/** + Interface stucture for the Timer Architectural Protocol. + + @par Protocol Description: + This protocol provides the services to initialize a periodic timer + interrupt, and to register a handler that is called each time the timer + interrupt fires. It may also provide a service to adjust the rate of the + periodic timer interrupt. When a timer interrupt occurs, the handler is + passed the amount of time that has passed since the previous timer + interrupt. + + @param RegisterHandler + Registers a handler that will be called each time the + timer interrupt fires. TimerPeriod defines the minimum + time between timer interrupts, so TimerPeriod will also + be the minimum time between calls to the registered + handler. + + @param SetTimerPeriod + Sets the period of the timer interrupt in 100 nS units. + This function is optional, and may return EFI_UNSUPPORTED. + If this function is supported, then the timer period will + be rounded up to the nearest supported timer period. + + @param GetTimerPeriod + Retrieves the period of the timer interrupt in 100 nS units. + + @param GenerateSoftInterrupt + Generates a soft timer interrupt that simulates the firing of + the timer interrupt. This service can be used to invoke the + registered handler if the timer interrupt has been masked for + a period of time. + +**/ +EFI_TIMER_ARCH_PROTOCOL gTimer = { + TimerDriverRegisterHandler, + TimerDriverSetTimerPeriod, + TimerDriverGetTimerPeriod, + TimerDriverGenerateSoftInterrupt +}; + +EFI_HANDLE gTimerHandle = NULL; + + +/** + Initialize the state information for the Timer 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 +TimerInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Find the interrupt controller protocol. ASSERT if not found. + // + Status = gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, ( VOID ** )&gInterrupt); + ASSERT_EFI_ERROR (Status); + + MmioWrite32 (TIMER_CMD, 0x01); + + // + // Force the timer to be disabled + // + Status = TimerDriverSetTimerPeriod (&gTimer, 0); + ASSERT_EFI_ERROR (Status); + + // + // Install interrupt handler + // + Status = gInterrupt->RegisterInterruptSource (gInterrupt, FixedPcdGet32 (PcdTimerVector), TimerInterruptHandler); + ASSERT_EFI_ERROR (Status); + + // + // Force the timer to be enabled at its default period + // + Status = TimerDriverSetTimerPeriod (&gTimer, FixedPcdGet32 (PcdTimerPeriod)); + ASSERT_EFI_ERROR (Status); + + + // + // Install the Timer Architectural Protocol onto a new handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &gTimerHandle, + &gEfiTimerArchProtocolGuid, &gTimer, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + -- cgit v1.2.3