]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuDxeRiscV64/CpuDxe.c
UefiCpuPkg: Add CpuDxeRiscV64 module
[mirror_edk2.git] / UefiCpuPkg / CpuDxeRiscV64 / CpuDxe.c
CommitLineData
c27cdc94
S
1/** @file\r
2 RISC-V CPU DXE driver.\r
3\r
4 Copyright (c) 2016 - 2022, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>\r
5 Copyright (c) 2022, Ventana Micro Systems Inc. All rights reserved.<BR>\r
6\r
7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
8\r
9**/\r
10\r
11#include "CpuDxe.h"\r
12\r
13//\r
14// Global Variables\r
15//\r
16STATIC BOOLEAN mInterruptState = FALSE;\r
17STATIC EFI_HANDLE mCpuHandle = NULL;\r
18STATIC UINTN mBootHartId;\r
19RISCV_EFI_BOOT_PROTOCOL gRiscvBootProtocol;\r
20\r
21/**\r
22 Get the boot hartid\r
23\r
24 @param This Protocol instance structure\r
25 @param BootHartId Pointer to the Boot Hart ID variable\r
26\r
27 @retval EFI_SUCCESS If BootHartId is returned\r
28 @retval EFI_INVALID_PARAMETER Either "BootHartId" is NULL or "This" is not\r
29 a valid RISCV_EFI_BOOT_PROTOCOL instance.\r
30\r
31**/\r
32EFI_STATUS\r
33EFIAPI\r
34RiscvGetBootHartId (\r
35 IN RISCV_EFI_BOOT_PROTOCOL *This,\r
36 OUT UINTN *BootHartId\r
37 )\r
38{\r
39 if ((This != &gRiscvBootProtocol) || (BootHartId == NULL)) {\r
40 return EFI_INVALID_PARAMETER;\r
41 }\r
42\r
43 *BootHartId = mBootHartId;\r
44 return EFI_SUCCESS;\r
45}\r
46\r
47RISCV_EFI_BOOT_PROTOCOL gRiscvBootProtocol = {\r
48 RISCV_EFI_BOOT_PROTOCOL_LATEST_VERSION,\r
49 RiscvGetBootHartId\r
50};\r
51\r
52EFI_CPU_ARCH_PROTOCOL gCpu = {\r
53 CpuFlushCpuDataCache,\r
54 CpuEnableInterrupt,\r
55 CpuDisableInterrupt,\r
56 CpuGetInterruptState,\r
57 CpuInit,\r
58 CpuRegisterInterruptHandler,\r
59 CpuGetTimerValue,\r
60 CpuSetMemoryAttributes,\r
61 1, // NumberOfTimers\r
62 4 // DmaBufferAlignment\r
63};\r
64\r
65//\r
66// CPU Arch Protocol Functions\r
67//\r
68\r
69/**\r
70 Flush CPU data cache. If the instruction cache is fully coherent\r
71 with all DMA operations then function can just return EFI_SUCCESS.\r
72\r
73 @param This Protocol instance structure\r
74 @param Start Physical address to start flushing from.\r
75 @param Length Number of bytes to flush. Round up to chipset\r
76 granularity.\r
77 @param FlushType Specifies the type of flush operation to perform.\r
78\r
79 @retval EFI_SUCCESS If cache was flushed\r
80 @retval EFI_UNSUPPORTED If flush type is not supported.\r
81 @retval EFI_DEVICE_ERROR If requested range could not be flushed.\r
82\r
83**/\r
84EFI_STATUS\r
85EFIAPI\r
86CpuFlushCpuDataCache (\r
87 IN EFI_CPU_ARCH_PROTOCOL *This,\r
88 IN EFI_PHYSICAL_ADDRESS Start,\r
89 IN UINT64 Length,\r
90 IN EFI_CPU_FLUSH_TYPE FlushType\r
91 )\r
92{\r
93 return EFI_SUCCESS;\r
94}\r
95\r
96/**\r
97 Enables CPU interrupts.\r
98\r
99 @param This Protocol instance structure\r
100\r
101 @retval EFI_SUCCESS If interrupts were enabled in the CPU\r
102 @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU.\r
103\r
104**/\r
105EFI_STATUS\r
106EFIAPI\r
107CpuEnableInterrupt (\r
108 IN EFI_CPU_ARCH_PROTOCOL *This\r
109 )\r
110{\r
111 EnableInterrupts ();\r
112 mInterruptState = TRUE;\r
113 return EFI_SUCCESS;\r
114}\r
115\r
116/**\r
117 Disables CPU interrupts.\r
118\r
119 @param This Protocol instance structure\r
120\r
121 @retval EFI_SUCCESS If interrupts were disabled in the CPU.\r
122 @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU.\r
123\r
124**/\r
125EFI_STATUS\r
126EFIAPI\r
127CpuDisableInterrupt (\r
128 IN EFI_CPU_ARCH_PROTOCOL *This\r
129 )\r
130{\r
131 DisableInterrupts ();\r
132 mInterruptState = FALSE;\r
133 return EFI_SUCCESS;\r
134}\r
135\r
136/**\r
137 Return the state of interrupts.\r
138\r
139 @param This Protocol instance structure\r
140 @param State Pointer to the CPU's current interrupt state\r
141\r
142 @retval EFI_SUCCESS If interrupts were disabled in the CPU.\r
143 @retval EFI_INVALID_PARAMETER State is NULL.\r
144\r
145**/\r
146EFI_STATUS\r
147EFIAPI\r
148CpuGetInterruptState (\r
149 IN EFI_CPU_ARCH_PROTOCOL *This,\r
150 OUT BOOLEAN *State\r
151 )\r
152{\r
153 if (State == NULL) {\r
154 return EFI_INVALID_PARAMETER;\r
155 }\r
156\r
157 *State = mInterruptState;\r
158 return EFI_SUCCESS;\r
159}\r
160\r
161/**\r
162 Generates an INIT to the CPU.\r
163\r
164 @param This Protocol instance structure\r
165 @param InitType Type of CPU INIT to perform\r
166\r
167 @retval EFI_SUCCESS If CPU INIT occurred. This value should never be\r
168 seen.\r
169 @retval EFI_DEVICE_ERROR If CPU INIT failed.\r
170 @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported.\r
171\r
172**/\r
173EFI_STATUS\r
174EFIAPI\r
175CpuInit (\r
176 IN EFI_CPU_ARCH_PROTOCOL *This,\r
177 IN EFI_CPU_INIT_TYPE InitType\r
178 )\r
179{\r
180 return EFI_UNSUPPORTED;\r
181}\r
182\r
183/**\r
184 Registers a function to be called from the CPU interrupt handler.\r
185\r
186 @param This Protocol instance structure\r
187 @param InterruptType Defines which interrupt to hook. IA-32\r
188 valid range is 0x00 through 0xFF\r
189 @param InterruptHandler A pointer to a function of type\r
190 EFI_CPU_INTERRUPT_HANDLER that is called\r
191 when a processor interrupt occurs. A null\r
192 pointer is an error condition.\r
193\r
194 @retval EFI_SUCCESS If handler installed or uninstalled.\r
195 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler\r
196 for InterruptType was previously installed.\r
197 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for\r
198 InterruptType was not previously installed.\r
199 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType\r
200 is not supported.\r
201\r
202**/\r
203EFI_STATUS\r
204EFIAPI\r
205CpuRegisterInterruptHandler (\r
206 IN EFI_CPU_ARCH_PROTOCOL *This,\r
207 IN EFI_EXCEPTION_TYPE InterruptType,\r
208 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
209 )\r
210{\r
211 return RegisterCpuInterruptHandler (InterruptType, InterruptHandler);\r
212}\r
213\r
214/**\r
215 Returns a timer value from one of the CPU's internal timers. There is no\r
216 inherent time interval between ticks but is a function of the CPU frequency.\r
217\r
218 @param This - Protocol instance structure.\r
219 @param TimerIndex - Specifies which CPU timer is requested.\r
220 @param TimerValue - Pointer to the returned timer value.\r
221 @param TimerPeriod - A pointer to the amount of time that passes\r
222 in femtoseconds (10-15) for each increment\r
223 of TimerValue. If TimerValue does not\r
224 increment at a predictable rate, then 0 is\r
225 returned. The amount of time that has\r
226 passed between two calls to GetTimerValue()\r
227 can be calculated with the formula\r
228 (TimerValue2 - TimerValue1) * TimerPeriod.\r
229 This parameter is optional and may be NULL.\r
230\r
231 @retval EFI_SUCCESS - If the CPU timer count was returned.\r
232 @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.\r
233 @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.\r
234 @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.\r
235\r
236**/\r
237EFI_STATUS\r
238EFIAPI\r
239CpuGetTimerValue (\r
240 IN EFI_CPU_ARCH_PROTOCOL *This,\r
241 IN UINT32 TimerIndex,\r
242 OUT UINT64 *TimerValue,\r
243 OUT UINT64 *TimerPeriod OPTIONAL\r
244 )\r
245{\r
246 if (TimerValue == NULL) {\r
247 return EFI_INVALID_PARAMETER;\r
248 }\r
249\r
250 if (TimerIndex != 0) {\r
251 return EFI_INVALID_PARAMETER;\r
252 }\r
253\r
254 *TimerValue = (UINT64)RiscVReadTimer ();\r
255 if (TimerPeriod != NULL) {\r
256 *TimerPeriod = DivU64x32 (\r
257 1000000000000000u,\r
258 PcdGet64 (PcdCpuCoreCrystalClockFrequency)\r
259 );\r
260 }\r
261\r
262 return EFI_SUCCESS;\r
263}\r
264\r
265/**\r
266 Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.\r
267\r
268 This function modifies the attributes for the memory region specified by BaseAddress and\r
269 Length from their current attributes to the attributes specified by Attributes.\r
270\r
271 @param This The EFI_CPU_ARCH_PROTOCOL instance.\r
272 @param BaseAddress The physical address that is the start address of a memory region.\r
273 @param Length The size in bytes of the memory region.\r
274 @param Attributes The bit mask of attributes to set for the memory region.\r
275\r
276 @retval EFI_SUCCESS The attributes were set for the memory region.\r
277 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by\r
278 BaseAddress and Length cannot be modified.\r
279 @retval EFI_INVALID_PARAMETER Length is zero.\r
280 Attributes specified an illegal combination of attributes that\r
281 cannot be set together.\r
282 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
283 the memory resource range.\r
284 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory\r
285 resource range specified by BaseAddress and Length.\r
286 The bit mask of attributes is not support for the memory resource\r
287 range specified by BaseAddress and Length.\r
288\r
289**/\r
290EFI_STATUS\r
291EFIAPI\r
292CpuSetMemoryAttributes (\r
293 IN EFI_CPU_ARCH_PROTOCOL *This,\r
294 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
295 IN UINT64 Length,\r
296 IN UINT64 Attributes\r
297 )\r
298{\r
299 DEBUG ((DEBUG_INFO, "%a: Set memory attributes not supported yet\n", __FUNCTION__));\r
300 return EFI_SUCCESS;\r
301}\r
302\r
303/**\r
304 Initialize the state information for the CPU Architectural Protocol.\r
305\r
306 @param ImageHandle Image handle this driver.\r
307 @param SystemTable Pointer to the System Table.\r
308\r
309 @retval EFI_SUCCESS Thread can be successfully created\r
310 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
311 @retval EFI_DEVICE_ERROR Cannot create the thread\r
312\r
313**/\r
314EFI_STATUS\r
315EFIAPI\r
316InitializeCpu (\r
317 IN EFI_HANDLE ImageHandle,\r
318 IN EFI_SYSTEM_TABLE *SystemTable\r
319 )\r
320{\r
321 EFI_STATUS Status;\r
322 EFI_RISCV_FIRMWARE_CONTEXT *FirmwareContext;\r
323\r
324 GetFirmwareContextPointer (&FirmwareContext);\r
325 ASSERT (FirmwareContext != NULL);\r
326 if (FirmwareContext == NULL) {\r
327 DEBUG ((DEBUG_ERROR, "Failed to get the pointer of EFI_RISCV_FIRMWARE_CONTEXT\n"));\r
328 return EFI_NOT_FOUND;\r
329 }\r
330\r
331 DEBUG ((DEBUG_INFO, " %a: Firmware Context is at 0x%x.\n", __FUNCTION__, FirmwareContext));\r
332\r
333 mBootHartId = FirmwareContext->BootHartId;\r
334 DEBUG ((DEBUG_INFO, " %a: mBootHartId = 0x%x.\n", __FUNCTION__, mBootHartId));\r
335\r
336 InitializeCpuExceptionHandlers (NULL);\r
337\r
338 //\r
339 // Make sure interrupts are disabled\r
340 //\r
341 DisableInterrupts ();\r
342\r
343 //\r
344 // Install Boot protocol\r
345 //\r
346 Status = gBS->InstallProtocolInterface (\r
347 &ImageHandle,\r
348 &gRiscVEfiBootProtocolGuid,\r
349 EFI_NATIVE_INTERFACE,\r
350 &gRiscvBootProtocol\r
351 );\r
352 ASSERT_EFI_ERROR (Status);\r
353\r
354 //\r
355 // Install CPU Architectural Protocol\r
356 //\r
357 Status = gBS->InstallMultipleProtocolInterfaces (\r
358 &mCpuHandle,\r
359 &gEfiCpuArchProtocolGuid,\r
360 &gCpu,\r
361 NULL\r
362 );\r
363 ASSERT_EFI_ERROR (Status);\r
364 return Status;\r
365}\r