VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/ArmPkg/Drivers/CpuDxe/CpuDxe.c@ 101297

Last change on this file since 101297 was 101291, checked in by vboxsync, 16 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

  • Property svn:eol-style set to native
File size: 10.5 KB
Line 
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#include <Library/MemoryAllocationLib.h>
15
16BOOLEAN mIsFlushingGCD;
17
18/**
19 This function flushes the range of addresses from Start to Start+Length
20 from the processor's data cache. If Start is not aligned to a cache line
21 boundary, then the bytes before Start to the preceding cache line boundary
22 are also flushed. If Start+Length is not aligned to a cache line boundary,
23 then the bytes past Start+Length to the end of the next cache line boundary
24 are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
25 supported. If the data cache is fully coherent with all DMA operations, then
26 this function can just return EFI_SUCCESS. If the processor does not support
27 flushing a range of the data cache, then the entire data cache can be flushed.
28
29 @param This The EFI_CPU_ARCH_PROTOCOL instance.
30 @param Start The beginning physical address to flush from the processor's data
31 cache.
32 @param Length The number of bytes to flush from the processor's data cache. This
33 function may flush more bytes than Length specifies depending upon
34 the granularity of the flush operation that the processor supports.
35 @param FlushType Specifies the type of flush operation to perform.
36
37 @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from
38 the processor's data cache.
39 @retval EFI_UNSUPPORTED The processor does not support the cache flush type specified
40 by FlushType.
41 @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed
42 from the processor's data cache.
43
44**/
45EFI_STATUS
46EFIAPI
47CpuFlushCpuDataCache (
48 IN EFI_CPU_ARCH_PROTOCOL *This,
49 IN EFI_PHYSICAL_ADDRESS Start,
50 IN UINT64 Length,
51 IN EFI_CPU_FLUSH_TYPE FlushType
52 )
53{
54 switch (FlushType) {
55 case EfiCpuFlushTypeWriteBack:
56 WriteBackDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
57 break;
58 case EfiCpuFlushTypeInvalidate:
59 InvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
60 break;
61 case EfiCpuFlushTypeWriteBackInvalidate:
62 WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
63 break;
64 default:
65 return EFI_INVALID_PARAMETER;
66 }
67
68 return EFI_SUCCESS;
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**/
80EFI_STATUS
81EFIAPI
82CpuEnableInterrupt (
83 IN EFI_CPU_ARCH_PROTOCOL *This
84 )
85{
86 ArmEnableInterrupts ();
87
88 return EFI_SUCCESS;
89}
90
91/**
92 This function disables interrupt processing by the processor.
93
94 @param This The EFI_CPU_ARCH_PROTOCOL instance.
95
96 @retval EFI_SUCCESS Interrupts are disabled on the processor.
97 @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor.
98
99**/
100EFI_STATUS
101EFIAPI
102CpuDisableInterrupt (
103 IN EFI_CPU_ARCH_PROTOCOL *This
104 )
105{
106 ArmDisableInterrupts ();
107
108 return EFI_SUCCESS;
109}
110
111/**
112 This function retrieves the processor's current interrupt state a returns it in
113 State. If interrupts are currently enabled, then TRUE is returned. If interrupts
114 are currently disabled, then FALSE is returned.
115
116 @param This The EFI_CPU_ARCH_PROTOCOL instance.
117 @param State A pointer to the processor's current interrupt state. Set to TRUE if
118 interrupts are enabled and FALSE if interrupts are disabled.
119
120 @retval EFI_SUCCESS The processor's current interrupt state was returned in State.
121 @retval EFI_INVALID_PARAMETER State is NULL.
122
123**/
124EFI_STATUS
125EFIAPI
126CpuGetInterruptState (
127 IN EFI_CPU_ARCH_PROTOCOL *This,
128 OUT BOOLEAN *State
129 )
130{
131 if (State == NULL) {
132 return EFI_INVALID_PARAMETER;
133 }
134
135 *State = ArmGetInterruptState ();
136 return EFI_SUCCESS;
137}
138
139/**
140 This function generates an INIT on the processor. If this function succeeds, then the
141 processor will be reset, and control will not be returned to the caller. If InitType is
142 not supported by this processor, or the processor cannot programmatically generate an
143 INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
144 occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
145
146 @param This The EFI_CPU_ARCH_PROTOCOL instance.
147 @param InitType The type of processor INIT to perform.
148
149 @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen.
150 @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported
151 by this processor.
152 @retval EFI_DEVICE_ERROR The processor INIT failed.
153
154**/
155EFI_STATUS
156EFIAPI
157CpuInit (
158 IN EFI_CPU_ARCH_PROTOCOL *This,
159 IN EFI_CPU_INIT_TYPE InitType
160 )
161{
162 return EFI_UNSUPPORTED;
163}
164
165EFI_STATUS
166EFIAPI
167CpuRegisterInterruptHandler (
168 IN EFI_CPU_ARCH_PROTOCOL *This,
169 IN EFI_EXCEPTION_TYPE InterruptType,
170 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
171 )
172{
173 return RegisterInterruptHandler (InterruptType, InterruptHandler);
174}
175
176EFI_STATUS
177EFIAPI
178CpuGetTimerValue (
179 IN EFI_CPU_ARCH_PROTOCOL *This,
180 IN UINT32 TimerIndex,
181 OUT UINT64 *TimerValue,
182 OUT UINT64 *TimerPeriod OPTIONAL
183 )
184{
185 return EFI_UNSUPPORTED;
186}
187
188/**
189 Callback function for idle events.
190
191 @param Event Event whose notification function is being invoked.
192 @param Context The pointer to the notification function's context,
193 which is implementation-dependent.
194
195**/
196VOID
197EFIAPI
198IdleLoopEventCallback (
199 IN EFI_EVENT Event,
200 IN VOID *Context
201 )
202{
203 CpuSleep ();
204}
205
206//
207// Globals used to initialize the protocol
208//
209EFI_HANDLE mCpuHandle = NULL;
210EFI_CPU_ARCH_PROTOCOL mCpu = {
211 CpuFlushCpuDataCache,
212 CpuEnableInterrupt,
213 CpuDisableInterrupt,
214 CpuGetInterruptState,
215 CpuInit,
216 CpuRegisterInterruptHandler,
217 CpuGetTimerValue,
218 CpuSetMemoryAttributes,
219 0, // NumberOfTimers
220 2048, // DmaBufferAlignment
221};
222
223STATIC
224VOID
225InitializeDma (
226 IN OUT EFI_CPU_ARCH_PROTOCOL *CpuArchProtocol
227 )
228{
229 CpuArchProtocol->DmaBufferAlignment = ArmCacheWritebackGranule ();
230}
231
232/**
233 Map all EfiConventionalMemory regions in the memory map with NX
234 attributes so that allocating or freeing EfiBootServicesData regions
235 does not result in changes to memory permission attributes.
236
237**/
238STATIC
239VOID
240RemapUnusedMemoryNx (
241 VOID
242 )
243{
244 UINT64 TestBit;
245 UINTN MemoryMapSize;
246 UINTN MapKey;
247 UINTN DescriptorSize;
248 UINT32 DescriptorVersion;
249 EFI_MEMORY_DESCRIPTOR *MemoryMap;
250 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
251 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
252 EFI_STATUS Status;
253
254 TestBit = LShiftU64 (1, EfiBootServicesData);
255 if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) == 0) {
256 return;
257 }
258
259 MemoryMapSize = 0;
260 MemoryMap = NULL;
261
262 Status = gBS->GetMemoryMap (
263 &MemoryMapSize,
264 MemoryMap,
265 &MapKey,
266 &DescriptorSize,
267 &DescriptorVersion
268 );
269 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
270 do {
271 MemoryMap = (EFI_MEMORY_DESCRIPTOR *)AllocatePool (MemoryMapSize);
272 ASSERT (MemoryMap != NULL);
273 Status = gBS->GetMemoryMap (
274 &MemoryMapSize,
275 MemoryMap,
276 &MapKey,
277 &DescriptorSize,
278 &DescriptorVersion
279 );
280 if (EFI_ERROR (Status)) {
281 FreePool (MemoryMap);
282 }
283 } while (Status == EFI_BUFFER_TOO_SMALL);
284
285 ASSERT_EFI_ERROR (Status);
286
287 MemoryMapEntry = MemoryMap;
288 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
289 while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
290 if (MemoryMapEntry->Type == EfiConventionalMemory) {
291 ArmSetMemoryAttributes (
292 MemoryMapEntry->PhysicalStart,
293 EFI_PAGES_TO_SIZE (MemoryMapEntry->NumberOfPages),
294 EFI_MEMORY_XP,
295 EFI_MEMORY_XP
296 );
297 }
298
299 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
300 }
301}
302
303EFI_STATUS
304CpuDxeInitialize (
305 IN EFI_HANDLE ImageHandle,
306 IN EFI_SYSTEM_TABLE *SystemTable
307 )
308{
309 EFI_STATUS Status;
310 EFI_EVENT IdleLoopEvent;
311
312 InitializeExceptions (&mCpu);
313
314 InitializeDma (&mCpu);
315
316 //
317 // Once we install the CPU arch protocol, the DXE core's memory
318 // protection routines will invoke them to manage the permissions of page
319 // allocations as they are created. Given that this includes pages
320 // allocated for page tables by this driver, we must ensure that unused
321 // memory is mapped with the same permissions as boot services data
322 // regions. Otherwise, we may end up with unbounded recursion, due to the
323 // fact that updating permissions on a newly allocated page table may trigger
324 // a block entry split, which triggers a page table allocation, etc etc
325 //
326 if (FeaturePcdGet (PcdRemapUnusedMemoryNx)) {
327 RemapUnusedMemoryNx ();
328 }
329
330 Status = gBS->InstallMultipleProtocolInterfaces (
331 &mCpuHandle,
332 &gEfiCpuArchProtocolGuid,
333 &mCpu,
334 &gEfiMemoryAttributeProtocolGuid,
335 &mMemoryAttribute,
336 NULL
337 );
338
339 //
340 // Make sure GCD and MMU settings match. This API calls gDS->SetMemorySpaceAttributes ()
341 // and that calls EFI_CPU_ARCH_PROTOCOL.SetMemoryAttributes, so this code needs to go
342 // after the protocol is installed
343 //
344 mIsFlushingGCD = TRUE;
345 SyncCacheConfig (&mCpu);
346 mIsFlushingGCD = FALSE;
347
348 //
349 // Setup a callback for idle events
350 //
351 Status = gBS->CreateEventEx (
352 EVT_NOTIFY_SIGNAL,
353 TPL_NOTIFY,
354 IdleLoopEventCallback,
355 NULL,
356 &gIdleLoopEventGuid,
357 &IdleLoopEvent
358 );
359 ASSERT_EFI_ERROR (Status);
360
361 return Status;
362}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette