TianoCore EDK2 master
Loading...
Searching...
No Matches
CpuDxe.c
Go to the documentation of this file.
1
10#include "CpuDxe.h"
11
12#include <Guid/IdleLoopEvent.h>
13
15
16BOOLEAN mIsFlushingGCD;
17
18// Shadow state for the CPU interrupt en/disabled bit
19STATIC BOOLEAN mInterruptsEnabled;
20STATIC VOID *mHardwareInterruptProtocolNotifyEventRegistration;
21
27EFIAPI
30 )
31{
32 mInterruptsEnabled = TRUE;
33
34 return EFI_SUCCESS;
35}
36
42EFIAPI
45 )
46{
47 mInterruptsEnabled = FALSE;
48
49 return EFI_SUCCESS;
50}
51
57EFIAPI
60 OUT BOOLEAN *State
61 )
62{
63 if (State == NULL) {
64 return EFI_INVALID_PARAMETER;
65 }
66
67 *State = mInterruptsEnabled;
68 return EFI_SUCCESS;
69}
70
100EFIAPI
104 IN UINT64 Length,
105 IN EFI_CPU_FLUSH_TYPE FlushType
106 )
107{
108 switch (FlushType) {
109 case EfiCpuFlushTypeWriteBack:
110 WriteBackDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
111 break;
112 case EfiCpuFlushTypeInvalidate:
113 InvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
114 break;
115 case EfiCpuFlushTypeWriteBackInvalidate:
117 break;
118 default:
119 return EFI_INVALID_PARAMETER;
120 }
121
122 return EFI_SUCCESS;
123}
124
134STATIC
136EFIAPI
139 )
140{
141 ArmEnableInterrupts ();
142
143 return EFI_SUCCESS;
144}
145
155STATIC
157EFIAPI
160 )
161{
162 ArmDisableInterrupts ();
163
164 return EFI_SUCCESS;
165}
166
180STATIC
182EFIAPI
185 OUT BOOLEAN *State
186 )
187{
188 if (State == NULL) {
189 return EFI_INVALID_PARAMETER;
190 }
191
192 *State = ArmGetInterruptState ();
193 return EFI_SUCCESS;
194}
195
212STATIC
214EFIAPI
217 IN EFI_CPU_INIT_TYPE InitType
218 )
219{
220 return EFI_UNSUPPORTED;
221}
222
223STATIC
225EFIAPI
228 IN EFI_EXCEPTION_TYPE InterruptType,
229 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
230 )
231{
232 return RegisterInterruptHandler (InterruptType, InterruptHandler);
233}
234
235STATIC
237EFIAPI
240 IN UINT32 TimerIndex,
241 OUT UINT64 *TimerValue,
242 OUT UINT64 *TimerPeriod OPTIONAL
243 )
244{
245 return EFI_UNSUPPORTED;
246}
247
256STATIC
257VOID
258EFIAPI
260 IN EFI_EVENT Event,
261 IN VOID *Context
262 )
263{
264 CpuSleep ();
265}
266
267//
268// Globals used to initialize the protocol
269//
275 CpuInit,
279 0, // NumberOfTimers
280 2048, // DmaBufferAlignment
281};
282
283STATIC
284VOID
285InitializeDma (
286 IN OUT EFI_CPU_ARCH_PROTOCOL *CpuArchProtocol
287 )
288{
289 CpuArchProtocol->DmaBufferAlignment = ArmCacheWritebackGranule ();
290}
291
298STATIC
299VOID
301 VOID
302 )
303{
304 UINT64 TestBit;
305 UINTN MemoryMapSize;
306 UINTN MapKey;
307 UINTN DescriptorSize;
308 UINT32 DescriptorVersion;
309 EFI_MEMORY_DESCRIPTOR *MemoryMap;
310 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
311 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
312 EFI_STATUS Status;
313
314 TestBit = LShiftU64 (1, EfiBootServicesData);
315 if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) == 0) {
316 return;
317 }
318
319 MemoryMapSize = 0;
320 MemoryMap = NULL;
321
322 Status = gBS->GetMemoryMap (
323 &MemoryMapSize,
324 MemoryMap,
325 &MapKey,
326 &DescriptorSize,
327 &DescriptorVersion
328 );
329 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
330 do {
331 MemoryMap = (EFI_MEMORY_DESCRIPTOR *)AllocatePool (MemoryMapSize);
332 ASSERT (MemoryMap != NULL);
333 Status = gBS->GetMemoryMap (
334 &MemoryMapSize,
335 MemoryMap,
336 &MapKey,
337 &DescriptorSize,
338 &DescriptorVersion
339 );
340 if (EFI_ERROR (Status)) {
341 FreePool (MemoryMap);
342 }
343 } while (Status == EFI_BUFFER_TOO_SMALL);
344
345 ASSERT_EFI_ERROR (Status);
346
347 MemoryMapEntry = MemoryMap;
348 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
349 while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
350 if (MemoryMapEntry->Type == EfiConventionalMemory) {
352 MemoryMapEntry->PhysicalStart,
353 EFI_PAGES_TO_SIZE (MemoryMapEntry->NumberOfPages),
354 EFI_MEMORY_XP,
355 EFI_MEMORY_XP
356 );
357 }
358
359 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
360 }
361}
362
363STATIC
364VOID
365EFIAPI
366HardwareInterruptProtocolNotify (
367 IN EFI_EVENT Event,
368 IN VOID *Context
369 )
370{
371 VOID *Protocol;
372 EFI_STATUS Status;
373
374 Status = gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, &Protocol);
375 if (EFI_ERROR (Status)) {
376 return;
377 }
378
379 //
380 // Now that the dedicated driver has taken control of the interrupt
381 // controller, we can allow interrupts to be enabled on the CPU side. So swap
382 // out the function stubs that manipulate the shadow state with the real
383 // ones. Interrupts are still disabled at the CPU so these fields can be set
384 // in any order.
385 //
386 mCpu.EnableInterrupt = CpuEnableInterrupt;
387 mCpu.DisableInterrupt = CpuDisableInterrupt;
388 mCpu.GetInterruptState = CpuGetInterruptState;
389
390 if (mInterruptsEnabled) {
391 ArmEnableInterrupts ();
392 }
393
394 gBS->CloseEvent (Event);
395}
396
398CpuDxeInitialize (
399 IN EFI_HANDLE ImageHandle,
400 IN EFI_SYSTEM_TABLE *SystemTable
401 )
402{
403 EFI_STATUS Status;
404 EFI_EVENT IdleLoopEvent;
405 EFI_HANDLE CpuHandle;
406
407 ArmDisableInterrupts ();
408 InitializeExceptions ();
409
410 InitializeDma (&mCpu);
411
412 //
413 // Once we install the CPU arch protocol, the DXE core's memory
414 // protection routines will invoke them to manage the permissions of page
415 // allocations as they are created. Given that this includes pages
416 // allocated for page tables by this driver, we must ensure that unused
417 // memory is mapped with the same permissions as boot services data
418 // regions. Otherwise, we may end up with unbounded recursion, due to the
419 // fact that updating permissions on a newly allocated page table may trigger
420 // a block entry split, which triggers a page table allocation, etc etc
421 //
422 if (FeaturePcdGet (PcdRemapUnusedMemoryNx)) {
424 }
425
426 CpuHandle = NULL;
427
428 Status = gBS->InstallMultipleProtocolInterfaces (
429 &CpuHandle,
430 &gEfiCpuArchProtocolGuid,
431 &mCpu,
432 &gEfiMemoryAttributeProtocolGuid,
433 &mMemoryAttribute,
434 NULL
435 );
436 if (EFI_ERROR (Status)) {
437 ASSERT_EFI_ERROR (Status);
438 return Status;
439 }
440
441 //
442 // Make sure GCD and MMU settings match. This API calls gDS->SetMemorySpaceAttributes ()
443 // and that calls EFI_CPU_ARCH_PROTOCOL.SetMemoryAttributes, so this code needs to go
444 // after the protocol is installed
445 //
446 mIsFlushingGCD = TRUE;
447 SyncCacheConfig (&mCpu);
448 mIsFlushingGCD = FALSE;
449
450 //
451 // Setup a callback for idle events
452 //
453 Status = gBS->CreateEventEx (
454 EVT_NOTIFY_SIGNAL,
455 TPL_NOTIFY,
457 NULL,
458 &gIdleLoopEventGuid,
459 &IdleLoopEvent
460 );
461 ASSERT_EFI_ERROR (Status);
462
463 //
464 // Interrupts should only be enabled on the CPU side after the GIC driver has
465 // configured and deasserted all incoming interrupt lines. So keep interrupts
466 // masked until the gHardwareInterruptProtocolGuid protocol appears.
467 //
469 &gHardwareInterruptProtocolGuid,
470 TPL_CALLBACK,
471 HardwareInterruptProtocolNotify,
472 NULL,
473 &mHardwareInterruptProtocolNotifyEventRegistration
474 );
475
476 return EFI_SUCCESS;
477}
UINT64 UINTN
VOID *EFIAPI WriteBackDataCacheRange(IN VOID *Address, IN UINTN Length)
VOID *EFIAPI InvalidateDataCacheRange(IN VOID *Address, IN UINTN Length)
VOID *EFIAPI WriteBackInvalidateDataCacheRange(IN VOID *Address, IN UINTN Length)
EFI_STATUS ArmSetMemoryAttributes(IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN UINT64 Attributes, IN UINT64 AttributeMask)
STATIC EFI_STATUS EFIAPI CpuDisableInterrupt(IN EFI_CPU_ARCH_PROTOCOL *This)
Definition: CpuDxe.c:158
STATIC EFI_STATUS EFIAPI CpuFlushCpuDataCache(IN EFI_CPU_ARCH_PROTOCOL *This, IN EFI_PHYSICAL_ADDRESS Start, IN UINT64 Length, IN EFI_CPU_FLUSH_TYPE FlushType)
Definition: CpuDxe.c:101
STATIC EFI_STATUS EFIAPI CpuRegisterInterruptHandler(IN EFI_CPU_ARCH_PROTOCOL *This, IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler)
Definition: CpuDxe.c:226
STATIC EFI_STATUS EFIAPI CpuShadowDisableInterrupt(IN EFI_CPU_ARCH_PROTOCOL *This)
Definition: CpuDxe.c:43
STATIC VOID EFIAPI IdleLoopEventCallback(IN EFI_EVENT Event, IN VOID *Context)
Definition: CpuDxe.c:259
STATIC EFI_STATUS EFIAPI CpuEnableInterrupt(IN EFI_CPU_ARCH_PROTOCOL *This)
Definition: CpuDxe.c:137
STATIC EFI_STATUS EFIAPI CpuGetInterruptState(IN EFI_CPU_ARCH_PROTOCOL *This, OUT BOOLEAN *State)
Definition: CpuDxe.c:183
STATIC VOID RemapUnusedMemoryNx(VOID)
Definition: CpuDxe.c:300
STATIC EFI_STATUS EFIAPI CpuShadowGetInterruptState(IN EFI_CPU_ARCH_PROTOCOL *This, OUT BOOLEAN *State)
Definition: CpuDxe.c:58
STATIC EFI_STATUS EFIAPI CpuShadowEnableInterrupt(IN EFI_CPU_ARCH_PROTOCOL *This)
Definition: CpuDxe.c:28
STATIC EFI_STATUS EFIAPI CpuInit(IN EFI_CPU_ARCH_PROTOCOL *This, IN EFI_CPU_INIT_TYPE InitType)
Definition: CpuDxe.c:215
STATIC EFI_STATUS EFIAPI CpuGetTimerValue(IN EFI_CPU_ARCH_PROTOCOL *This, IN UINT32 TimerIndex, OUT UINT64 *TimerValue, OUT UINT64 *TimerPeriod OPTIONAL)
Definition: CpuDxe.c:238
EFI_STATUS EFIAPI CpuSetMemoryAttributes(IN EFI_CPU_ARCH_PROTOCOL *This, IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN UINT64 Attributes)
Definition: CpuMmuCommon.c:229
EFI_STATUS RegisterInterruptHandler(IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler)
Definition: Exception.c:55
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
EFI_CPU_FLUSH_TYPE
Definition: Cpu.h:24
EFI_CPU_INIT_TYPE
Definition: Cpu.h:34
VOID(EFIAPI * EFI_CPU_INTERRUPT_HANDLER)(IN CONST EFI_EXCEPTION_TYPE InterruptType, IN CONST EFI_SYSTEM_CONTEXT SystemContext)
Definition: Cpu.h:52
VOID EFIAPI CpuSleep(VOID)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define VOID
Definition: Base.h:269
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:463
INTN EFI_EXCEPTION_TYPE
Definition: DebugSupport.h:35
#define PcdGet64(TokenName)
Definition: PcdLib.h:375
#define FeaturePcdGet(TokenName)
Definition: PcdLib.h:50
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_EVENT EFIAPI EfiCreateProtocolNotifyEvent(IN EFI_GUID *ProtocolGuid, IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction, IN VOID *NotifyContext OPTIONAL, OUT VOID **Registration)
Definition: UefiLib.c:130
@ EfiBootServicesData
@ EfiConventionalMemory
EFI_PHYSICAL_ADDRESS PhysicalStart
Definition: UefiSpec.h:165