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