--- /dev/null
+/** @file\r
+ RISC-V CPU DXE driver.\r
+\r
+ Copyright (c) 2016 - 2022, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>\r
+ Copyright (c) 2022, Ventana Micro Systems Inc. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "CpuDxe.h"\r
+\r
+//\r
+// Global Variables\r
+//\r
+STATIC BOOLEAN mInterruptState = FALSE;\r
+STATIC EFI_HANDLE mCpuHandle = NULL;\r
+STATIC UINTN mBootHartId;\r
+RISCV_EFI_BOOT_PROTOCOL gRiscvBootProtocol;\r
+\r
+/**\r
+ Get the boot hartid\r
+\r
+ @param This Protocol instance structure\r
+ @param BootHartId Pointer to the Boot Hart ID variable\r
+\r
+ @retval EFI_SUCCESS If BootHartId is returned\r
+ @retval EFI_INVALID_PARAMETER Either "BootHartId" is NULL or "This" is not\r
+ a valid RISCV_EFI_BOOT_PROTOCOL instance.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RiscvGetBootHartId (\r
+ IN RISCV_EFI_BOOT_PROTOCOL *This,\r
+ OUT UINTN *BootHartId\r
+ )\r
+{\r
+ if ((This != &gRiscvBootProtocol) || (BootHartId == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *BootHartId = mBootHartId;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+RISCV_EFI_BOOT_PROTOCOL gRiscvBootProtocol = {\r
+ RISCV_EFI_BOOT_PROTOCOL_LATEST_VERSION,\r
+ RiscvGetBootHartId\r
+};\r
+\r
+EFI_CPU_ARCH_PROTOCOL gCpu = {\r
+ CpuFlushCpuDataCache,\r
+ CpuEnableInterrupt,\r
+ CpuDisableInterrupt,\r
+ CpuGetInterruptState,\r
+ CpuInit,\r
+ CpuRegisterInterruptHandler,\r
+ CpuGetTimerValue,\r
+ CpuSetMemoryAttributes,\r
+ 1, // NumberOfTimers\r
+ 4 // DmaBufferAlignment\r
+};\r
+\r
+//\r
+// CPU Arch Protocol Functions\r
+//\r
+\r
+/**\r
+ Flush CPU data cache. If the instruction cache is fully coherent\r
+ with all DMA operations then function can just return EFI_SUCCESS.\r
+\r
+ @param This Protocol instance structure\r
+ @param Start Physical address to start flushing from.\r
+ @param Length Number of bytes to flush. Round up to chipset\r
+ granularity.\r
+ @param FlushType Specifies the type of flush operation to perform.\r
+\r
+ @retval EFI_SUCCESS If cache was flushed\r
+ @retval EFI_UNSUPPORTED If flush type is not supported.\r
+ @retval EFI_DEVICE_ERROR If requested range could not be flushed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuFlushCpuDataCache (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_PHYSICAL_ADDRESS Start,\r
+ IN UINT64 Length,\r
+ IN EFI_CPU_FLUSH_TYPE FlushType\r
+ )\r
+{\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Enables CPU interrupts.\r
+\r
+ @param This Protocol instance structure\r
+\r
+ @retval EFI_SUCCESS If interrupts were enabled in the CPU\r
+ @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuEnableInterrupt (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This\r
+ )\r
+{\r
+ EnableInterrupts ();\r
+ mInterruptState = TRUE;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Disables CPU interrupts.\r
+\r
+ @param This Protocol instance structure\r
+\r
+ @retval EFI_SUCCESS If interrupts were disabled in the CPU.\r
+ @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuDisableInterrupt (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This\r
+ )\r
+{\r
+ DisableInterrupts ();\r
+ mInterruptState = FALSE;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Return the state of interrupts.\r
+\r
+ @param This Protocol instance structure\r
+ @param State Pointer to the CPU's current interrupt state\r
+\r
+ @retval EFI_SUCCESS If interrupts were disabled in the CPU.\r
+ @retval EFI_INVALID_PARAMETER State is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuGetInterruptState (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ OUT BOOLEAN *State\r
+ )\r
+{\r
+ if (State == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *State = mInterruptState;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Generates an INIT to the CPU.\r
+\r
+ @param This Protocol instance structure\r
+ @param InitType Type of CPU INIT to perform\r
+\r
+ @retval EFI_SUCCESS If CPU INIT occurred. This value should never be\r
+ seen.\r
+ @retval EFI_DEVICE_ERROR If CPU INIT failed.\r
+ @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuInit (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_CPU_INIT_TYPE InitType\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Registers a function to be called from the CPU interrupt handler.\r
+\r
+ @param This Protocol instance structure\r
+ @param InterruptType Defines which interrupt to hook. IA-32\r
+ valid range is 0x00 through 0xFF\r
+ @param InterruptHandler A pointer to a function of type\r
+ EFI_CPU_INTERRUPT_HANDLER that is called\r
+ when a processor interrupt occurs. A null\r
+ pointer is an error condition.\r
+\r
+ @retval EFI_SUCCESS If handler installed or uninstalled.\r
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler\r
+ for InterruptType was previously installed.\r
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for\r
+ InterruptType was not previously installed.\r
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType\r
+ is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuRegisterInterruptHandler (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_EXCEPTION_TYPE InterruptType,\r
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
+ )\r
+{\r
+ return RegisterCpuInterruptHandler (InterruptType, InterruptHandler);\r
+}\r
+\r
+/**\r
+ Returns a timer value from one of the CPU's internal timers. There is no\r
+ inherent time interval between ticks but is a function of the CPU frequency.\r
+\r
+ @param This - Protocol instance structure.\r
+ @param TimerIndex - Specifies which CPU timer is requested.\r
+ @param TimerValue - Pointer to the returned timer value.\r
+ @param TimerPeriod - A pointer to the amount of time that passes\r
+ in femtoseconds (10-15) for each increment\r
+ of TimerValue. If TimerValue does not\r
+ increment at a predictable rate, then 0 is\r
+ returned. The amount of time that has\r
+ passed between two calls to GetTimerValue()\r
+ can be calculated with the formula\r
+ (TimerValue2 - TimerValue1) * TimerPeriod.\r
+ This parameter is optional and may be NULL.\r
+\r
+ @retval EFI_SUCCESS - If the CPU timer count was returned.\r
+ @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.\r
+ @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.\r
+ @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuGetTimerValue (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN UINT32 TimerIndex,\r
+ OUT UINT64 *TimerValue,\r
+ OUT UINT64 *TimerPeriod OPTIONAL\r
+ )\r
+{\r
+ if (TimerValue == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (TimerIndex != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *TimerValue = (UINT64)RiscVReadTimer ();\r
+ if (TimerPeriod != NULL) {\r
+ *TimerPeriod = DivU64x32 (\r
+ 1000000000000000u,\r
+ PcdGet64 (PcdCpuCoreCrystalClockFrequency)\r
+ );\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.\r
+\r
+ This function modifies the attributes for the memory region specified by BaseAddress and\r
+ Length from their current attributes to the attributes specified by Attributes.\r
+\r
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.\r
+ @param BaseAddress The physical address that is the start address of a memory region.\r
+ @param Length The size in bytes of the memory region.\r
+ @param Attributes The bit mask of attributes to set for the memory region.\r
+\r
+ @retval EFI_SUCCESS The attributes were set for the memory region.\r
+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
+ BaseAddress and Length cannot be modified.\r
+ @retval EFI_INVALID_PARAMETER Length is zero.\r
+ Attributes specified an illegal combination of attributes that\r
+ cannot be set together.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
+ the memory resource range.\r
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
+ resource range specified by BaseAddress and Length.\r
+ The bit mask of attributes is not support for the memory resource\r
+ range specified by BaseAddress and Length.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuSetMemoryAttributes (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINT64 Attributes\r
+ )\r
+{\r
+ DEBUG ((DEBUG_INFO, "%a: Set memory attributes not supported yet\n", __FUNCTION__));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Initialize the state information for the CPU Architectural Protocol.\r
+\r
+ @param ImageHandle Image handle this driver.\r
+ @param SystemTable Pointer to the System Table.\r
+\r
+ @retval EFI_SUCCESS Thread can be successfully created\r
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
+ @retval EFI_DEVICE_ERROR Cannot create the thread\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeCpu (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_RISCV_FIRMWARE_CONTEXT *FirmwareContext;\r
+\r
+ GetFirmwareContextPointer (&FirmwareContext);\r
+ ASSERT (FirmwareContext != NULL);\r
+ if (FirmwareContext == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "Failed to get the pointer of EFI_RISCV_FIRMWARE_CONTEXT\n"));\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, " %a: Firmware Context is at 0x%x.\n", __FUNCTION__, FirmwareContext));\r
+\r
+ mBootHartId = FirmwareContext->BootHartId;\r
+ DEBUG ((DEBUG_INFO, " %a: mBootHartId = 0x%x.\n", __FUNCTION__, mBootHartId));\r
+\r
+ InitializeCpuExceptionHandlers (NULL);\r
+\r
+ //\r
+ // Make sure interrupts are disabled\r
+ //\r
+ DisableInterrupts ();\r
+\r
+ //\r
+ // Install Boot protocol\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &ImageHandle,\r
+ &gRiscVEfiBootProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &gRiscvBootProtocol\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Install CPU Architectural Protocol\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mCpuHandle,\r
+ &gEfiCpuArchProtocolGuid,\r
+ &gCpu,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ RISC-V CPU DXE module header file.\r
+\r
+ Copyright (c) 2016 - 2022, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef CPU_DXE_H_\r
+#define CPU_DXE_H_\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/Cpu.h>\r
+#include <Protocol/RiscVBootProtocol.h>\r
+#include <Library/BaseRiscVSbiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/CpuExceptionHandlerLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+\r
+/**\r
+ Flush CPU data cache. If the instruction cache is fully coherent\r
+ with all DMA operations then function can just return EFI_SUCCESS.\r
+\r
+ @param This Protocol instance structure\r
+ @param Start Physical address to start flushing from.\r
+ @param Length Number of bytes to flush. Round up to chipset\r
+ granularity.\r
+ @param FlushType Specifies the type of flush operation to perform.\r
+\r
+ @retval EFI_SUCCESS If cache was flushed\r
+ @retval EFI_UNSUPPORTED If flush type is not supported.\r
+ @retval EFI_DEVICE_ERROR If requested range could not be flushed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuFlushCpuDataCache (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_PHYSICAL_ADDRESS Start,\r
+ IN UINT64 Length,\r
+ IN EFI_CPU_FLUSH_TYPE FlushType\r
+ );\r
+\r
+/**\r
+ Enables CPU interrupts.\r
+\r
+ @param This Protocol instance structure\r
+\r
+ @retval EFI_SUCCESS If interrupts were enabled in the CPU\r
+ @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuEnableInterrupt (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This\r
+ );\r
+\r
+/**\r
+ Disables CPU interrupts.\r
+\r
+ @param This Protocol instance structure\r
+\r
+ @retval EFI_SUCCESS If interrupts were disabled in the CPU.\r
+ @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuDisableInterrupt (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This\r
+ );\r
+\r
+/**\r
+ Return the state of interrupts.\r
+\r
+ @param This Protocol instance structure\r
+ @param State Pointer to the CPU's current interrupt state\r
+\r
+ @retval EFI_SUCCESS If interrupts were disabled in the CPU.\r
+ @retval EFI_INVALID_PARAMETER State is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuGetInterruptState (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ OUT BOOLEAN *State\r
+ );\r
+\r
+/**\r
+ Generates an INIT to the CPU.\r
+\r
+ @param This Protocol instance structure\r
+ @param InitType Type of CPU INIT to perform\r
+\r
+ @retval EFI_SUCCESS If CPU INIT occurred. This value should never be\r
+ seen.\r
+ @retval EFI_DEVICE_ERROR If CPU INIT failed.\r
+ @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuInit (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_CPU_INIT_TYPE InitType\r
+ );\r
+\r
+/**\r
+ Registers a function to be called from the CPU interrupt handler.\r
+\r
+ @param This Protocol instance structure\r
+ @param InterruptType Defines which interrupt to hook. IA-32\r
+ valid range is 0x00 through 0xFF\r
+ @param InterruptHandler A pointer to a function of type\r
+ EFI_CPU_INTERRUPT_HANDLER that is called\r
+ when a processor interrupt occurs. A null\r
+ pointer is an error condition.\r
+\r
+ @retval EFI_SUCCESS If handler installed or uninstalled.\r
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler\r
+ for InterruptType was previously installed.\r
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for\r
+ InterruptType was not previously installed.\r
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType\r
+ is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuRegisterInterruptHandler (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_EXCEPTION_TYPE InterruptType,\r
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
+ );\r
+\r
+/**\r
+ Returns a timer value from one of the CPU's internal timers. There is no\r
+ inherent time interval between ticks but is a function of the CPU frequency.\r
+\r
+ @param This - Protocol instance structure.\r
+ @param TimerIndex - Specifies which CPU timer is requested.\r
+ @param TimerValue - Pointer to the returned timer value.\r
+ @param TimerPeriod - A pointer to the amount of time that passes\r
+ in femtoseconds (10-15) for each increment\r
+ of TimerValue. If TimerValue does not\r
+ increment at a predictable rate, then 0 is\r
+ returned. The amount of time that has\r
+ passed between two calls to GetTimerValue()\r
+ can be calculated with the formula\r
+ (TimerValue2 - TimerValue1) * TimerPeriod.\r
+ This parameter is optional and may be NULL.\r
+\r
+ @retval EFI_SUCCESS - If the CPU timer count was returned.\r
+ @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.\r
+ @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.\r
+ @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuGetTimerValue (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN UINT32 TimerIndex,\r
+ OUT UINT64 *TimerValue,\r
+ OUT UINT64 *TimerPeriod OPTIONAL\r
+ );\r
+\r
+/**\r
+ Set memory cacheability attributes for given range of memeory.\r
+\r
+ @param This Protocol instance structure\r
+ @param BaseAddress Specifies the start address of the\r
+ memory range\r
+ @param Length Specifies the length of the memory range\r
+ @param Attributes The memory cacheability for the memory range\r
+\r
+ @retval EFI_SUCCESS If the cacheability of that memory range is\r
+ set successfully\r
+ @retval EFI_UNSUPPORTED If the desired operation cannot be done\r
+ @retval EFI_INVALID_PARAMETER The input parameter is not correct,\r
+ such as Length = 0\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuSetMemoryAttributes (\r
+ IN EFI_CPU_ARCH_PROTOCOL *This,\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINT64 Attributes\r
+ );\r
+\r
+#endif\r