1 /** @file
2 
3   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
4   Copyright (c) 2011, ARM Limited. All rights reserved.
5 
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "CpuDxe.h"
11 
12 #include <Guid/IdleLoopEvent.h>
13 
14 BOOLEAN                   mIsFlushingGCD;
15 
16 /**
17   This function flushes the range of addresses from Start to Start+Length
18   from the processor's data cache. If Start is not aligned to a cache line
19   boundary, then the bytes before Start to the preceding cache line boundary
20   are also flushed. If Start+Length is not aligned to a cache line boundary,
21   then the bytes past Start+Length to the end of the next cache line boundary
22   are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
23   supported. If the data cache is fully coherent with all DMA operations, then
24   this function can just return EFI_SUCCESS. If the processor does not support
25   flushing a range of the data cache, then the entire data cache can be flushed.
26 
27   @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
28   @param  Start            The beginning physical address to flush from the processor's data
29                            cache.
30   @param  Length           The number of bytes to flush from the processor's data cache. This
31                            function may flush more bytes than Length specifies depending upon
32                            the granularity of the flush operation that the processor supports.
33   @param  FlushType        Specifies the type of flush operation to perform.
34 
35   @retval EFI_SUCCESS           The address range from Start to Start+Length was flushed from
36                                 the processor's data cache.
37   @retval EFI_UNSUPPORTED       The processor does not support the cache flush type specified
38                                 by FlushType.
39   @retval EFI_DEVICE_ERROR      The address range from Start to Start+Length could not be flushed
40                                 from the processor's data cache.
41 
42 **/
43 EFI_STATUS
44 EFIAPI
CpuFlushCpuDataCache(IN EFI_CPU_ARCH_PROTOCOL * This,IN EFI_PHYSICAL_ADDRESS Start,IN UINT64 Length,IN EFI_CPU_FLUSH_TYPE FlushType)45 CpuFlushCpuDataCache (
46   IN EFI_CPU_ARCH_PROTOCOL           *This,
47   IN EFI_PHYSICAL_ADDRESS            Start,
48   IN UINT64                          Length,
49   IN EFI_CPU_FLUSH_TYPE              FlushType
50   )
51 {
52 
53   switch (FlushType) {
54     case EfiCpuFlushTypeWriteBack:
55       WriteBackDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
56       break;
57     case EfiCpuFlushTypeInvalidate:
58       InvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
59       break;
60     case EfiCpuFlushTypeWriteBackInvalidate:
61       WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
62       break;
63     default:
64       return EFI_INVALID_PARAMETER;
65   }
66 
67   return EFI_SUCCESS;
68 }
69 
70 
71 /**
72   This function enables interrupt processing by the processor.
73 
74   @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
75 
76   @retval EFI_SUCCESS           Interrupts are enabled on the processor.
77   @retval EFI_DEVICE_ERROR      Interrupts could not be enabled on the processor.
78 
79 **/
80 EFI_STATUS
81 EFIAPI
CpuEnableInterrupt(IN EFI_CPU_ARCH_PROTOCOL * This)82 CpuEnableInterrupt (
83   IN EFI_CPU_ARCH_PROTOCOL          *This
84   )
85 {
86   ArmEnableInterrupts ();
87 
88   return EFI_SUCCESS;
89 }
90 
91 
92 /**
93   This function disables interrupt processing by the processor.
94 
95   @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
96 
97   @retval EFI_SUCCESS           Interrupts are disabled on the processor.
98   @retval EFI_DEVICE_ERROR      Interrupts could not be disabled on the processor.
99 
100 **/
101 EFI_STATUS
102 EFIAPI
CpuDisableInterrupt(IN EFI_CPU_ARCH_PROTOCOL * This)103 CpuDisableInterrupt (
104   IN EFI_CPU_ARCH_PROTOCOL          *This
105   )
106 {
107   ArmDisableInterrupts ();
108 
109   return EFI_SUCCESS;
110 }
111 
112 
113 /**
114   This function retrieves the processor's current interrupt state a returns it in
115   State. If interrupts are currently enabled, then TRUE is returned. If interrupts
116   are currently disabled, then FALSE is returned.
117 
118   @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
119   @param  State            A pointer to the processor's current interrupt state. Set to TRUE if
120                            interrupts are enabled and FALSE if interrupts are disabled.
121 
122   @retval EFI_SUCCESS           The processor's current interrupt state was returned in State.
123   @retval EFI_INVALID_PARAMETER State is NULL.
124 
125 **/
126 EFI_STATUS
127 EFIAPI
CpuGetInterruptState(IN EFI_CPU_ARCH_PROTOCOL * This,OUT BOOLEAN * State)128 CpuGetInterruptState (
129   IN  EFI_CPU_ARCH_PROTOCOL         *This,
130   OUT BOOLEAN                       *State
131   )
132 {
133   if (State == NULL) {
134     return EFI_INVALID_PARAMETER;
135   }
136 
137   *State = ArmGetInterruptState();
138   return EFI_SUCCESS;
139 }
140 
141 
142 /**
143   This function generates an INIT on the processor. If this function succeeds, then the
144   processor will be reset, and control will not be returned to the caller. If InitType is
145   not supported by this processor, or the processor cannot programmatically generate an
146   INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
147   occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
148 
149   @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
150   @param  InitType         The type of processor INIT to perform.
151 
152   @retval EFI_SUCCESS           The processor INIT was performed. This return code should never be seen.
153   @retval EFI_UNSUPPORTED       The processor INIT operation specified by InitType is not supported
154                                 by this processor.
155   @retval EFI_DEVICE_ERROR      The processor INIT failed.
156 
157 **/
158 EFI_STATUS
159 EFIAPI
CpuInit(IN EFI_CPU_ARCH_PROTOCOL * This,IN EFI_CPU_INIT_TYPE InitType)160 CpuInit (
161   IN EFI_CPU_ARCH_PROTOCOL           *This,
162   IN EFI_CPU_INIT_TYPE               InitType
163   )
164 {
165   return EFI_UNSUPPORTED;
166 }
167 
168 EFI_STATUS
169 EFIAPI
CpuRegisterInterruptHandler(IN EFI_CPU_ARCH_PROTOCOL * This,IN EFI_EXCEPTION_TYPE InterruptType,IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler)170 CpuRegisterInterruptHandler (
171   IN EFI_CPU_ARCH_PROTOCOL          *This,
172   IN EFI_EXCEPTION_TYPE             InterruptType,
173   IN EFI_CPU_INTERRUPT_HANDLER      InterruptHandler
174   )
175 {
176   return RegisterInterruptHandler (InterruptType, InterruptHandler);
177 }
178 
179 EFI_STATUS
180 EFIAPI
CpuGetTimerValue(IN EFI_CPU_ARCH_PROTOCOL * This,IN UINT32 TimerIndex,OUT UINT64 * TimerValue,OUT UINT64 * TimerPeriod OPTIONAL)181 CpuGetTimerValue (
182   IN  EFI_CPU_ARCH_PROTOCOL          *This,
183   IN  UINT32                         TimerIndex,
184   OUT UINT64                         *TimerValue,
185   OUT UINT64                         *TimerPeriod   OPTIONAL
186   )
187 {
188   return EFI_UNSUPPORTED;
189 }
190 
191 /**
192   Callback function for idle events.
193 
194   @param  Event                 Event whose notification function is being invoked.
195   @param  Context               The pointer to the notification function's context,
196                                 which is implementation-dependent.
197 
198 **/
199 VOID
200 EFIAPI
IdleLoopEventCallback(IN EFI_EVENT Event,IN VOID * Context)201 IdleLoopEventCallback (
202   IN EFI_EVENT                Event,
203   IN VOID                     *Context
204   )
205 {
206   CpuSleep ();
207 }
208 
209 //
210 // Globals used to initialize the protocol
211 //
212 EFI_HANDLE            mCpuHandle = NULL;
213 EFI_CPU_ARCH_PROTOCOL mCpu = {
214   CpuFlushCpuDataCache,
215   CpuEnableInterrupt,
216   CpuDisableInterrupt,
217   CpuGetInterruptState,
218   CpuInit,
219   CpuRegisterInterruptHandler,
220   CpuGetTimerValue,
221   CpuSetMemoryAttributes,
222   0,          // NumberOfTimers
223   2048,       // DmaBufferAlignment
224 };
225 
226 STATIC
227 VOID
InitializeDma(IN OUT EFI_CPU_ARCH_PROTOCOL * CpuArchProtocol)228 InitializeDma (
229   IN OUT  EFI_CPU_ARCH_PROTOCOL   *CpuArchProtocol
230   )
231 {
232   CpuArchProtocol->DmaBufferAlignment = ArmCacheWritebackGranule ();
233 }
234 
235 EFI_STATUS
CpuDxeInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)236 CpuDxeInitialize (
237   IN EFI_HANDLE         ImageHandle,
238   IN EFI_SYSTEM_TABLE   *SystemTable
239   )
240 {
241   EFI_STATUS  Status;
242   EFI_EVENT    IdleLoopEvent;
243 
244   InitializeExceptions (&mCpu);
245 
246   InitializeDma (&mCpu);
247 
248   Status = gBS->InstallMultipleProtocolInterfaces (
249                 &mCpuHandle,
250                 &gEfiCpuArchProtocolGuid,           &mCpu,
251                 NULL
252                 );
253 
254   //
255   // Make sure GCD and MMU settings match. This API calls gDS->SetMemorySpaceAttributes ()
256   // and that calls EFI_CPU_ARCH_PROTOCOL.SetMemoryAttributes, so this code needs to go
257   // after the protocol is installed
258   //
259   mIsFlushingGCD = TRUE;
260   SyncCacheConfig (&mCpu);
261   mIsFlushingGCD = FALSE;
262 
263   // If the platform is a MPCore system then install the Configuration Table describing the
264   // secondary core states
265   if (ArmIsMpCore()) {
266     PublishArmProcessorTable();
267   }
268 
269   //
270   // Setup a callback for idle events
271   //
272   Status = gBS->CreateEventEx (
273                   EVT_NOTIFY_SIGNAL,
274                   TPL_NOTIFY,
275                   IdleLoopEventCallback,
276                   NULL,
277                   &gIdleLoopEventGuid,
278                   &IdleLoopEvent
279                   );
280   ASSERT_EFI_ERROR (Status);
281 
282   return Status;
283 }
284