VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UefiCpuPkg/CpuDxe/CpuDxe.c@ 109019

Last change on this file since 109019 was 108794, checked in by vboxsync, 4 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 30.4 KB
Line 
1/** @file
2 CPU DXE Module to produce CPU ARCH Protocol.
3
4 Copyright (c) 2008 - 2023, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7**/
8
9#include "CpuDxe.h"
10#include "CpuMp.h"
11#include "CpuPageTable.h"
12
13#define CPU_INTERRUPT_NUM 256
14
15//
16// Global Variables
17//
18BOOLEAN InterruptState = FALSE;
19EFI_HANDLE mCpuHandle = NULL;
20BOOLEAN mIsFlushingGCD;
21BOOLEAN mIsAllocatingPageTable = FALSE;
22UINT64 mTimerPeriod = 0;
23
24EFI_CPU_ARCH_PROTOCOL gCpu = {
25 CpuFlushCpuDataCache,
26 CpuEnableInterrupt,
27 CpuDisableInterrupt,
28 CpuGetInterruptState,
29 CpuInit,
30 CpuRegisterInterruptHandler,
31 CpuGetTimerValue,
32 CpuSetMemoryAttributes,
33 1, // NumberOfTimers
34 4 // DmaBufferAlignment
35};
36
37//
38// CPU Arch Protocol Functions
39//
40
41/**
42 Flush CPU data cache. If the instruction cache is fully coherent
43 with all DMA operations then function can just return EFI_SUCCESS.
44
45 @param This Protocol instance structure
46 @param Start Physical address to start flushing from.
47 @param Length Number of bytes to flush. Round up to chipset
48 granularity.
49 @param FlushType Specifies the type of flush operation to perform.
50
51 @retval EFI_SUCCESS If cache was flushed
52 @retval EFI_UNSUPPORTED If flush type is not supported.
53 @retval EFI_DEVICE_ERROR If requested range could not be flushed.
54
55**/
56EFI_STATUS
57EFIAPI
58CpuFlushCpuDataCache (
59 IN EFI_CPU_ARCH_PROTOCOL *This,
60 IN EFI_PHYSICAL_ADDRESS Start,
61 IN UINT64 Length,
62 IN EFI_CPU_FLUSH_TYPE FlushType
63 )
64{
65 if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
66 AsmWbinvd ();
67 return EFI_SUCCESS;
68 } else if (FlushType == EfiCpuFlushTypeInvalidate) {
69 AsmInvd ();
70 return EFI_SUCCESS;
71 } else {
72 return EFI_UNSUPPORTED;
73 }
74}
75
76/**
77 Enables CPU interrupts.
78
79 @param This Protocol instance structure
80
81 @retval EFI_SUCCESS If interrupts were enabled in the CPU
82 @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU.
83
84**/
85EFI_STATUS
86EFIAPI
87CpuEnableInterrupt (
88 IN EFI_CPU_ARCH_PROTOCOL *This
89 )
90{
91 EnableInterrupts ();
92
93 InterruptState = TRUE;
94 return EFI_SUCCESS;
95}
96
97/**
98 Disables CPU interrupts.
99
100 @param This Protocol instance structure
101
102 @retval EFI_SUCCESS If interrupts were disabled in the CPU.
103 @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU.
104
105**/
106EFI_STATUS
107EFIAPI
108CpuDisableInterrupt (
109 IN EFI_CPU_ARCH_PROTOCOL *This
110 )
111{
112 DisableInterrupts ();
113
114 InterruptState = FALSE;
115 return EFI_SUCCESS;
116}
117
118/**
119 Return the state of interrupts.
120
121 @param This Protocol instance structure
122 @param State Pointer to the CPU's current interrupt state
123
124 @retval EFI_SUCCESS If interrupts were disabled in the CPU.
125 @retval EFI_INVALID_PARAMETER State is NULL.
126
127**/
128EFI_STATUS
129EFIAPI
130CpuGetInterruptState (
131 IN EFI_CPU_ARCH_PROTOCOL *This,
132 OUT BOOLEAN *State
133 )
134{
135 if (State == NULL) {
136 return EFI_INVALID_PARAMETER;
137 }
138
139 *State = InterruptState;
140 return EFI_SUCCESS;
141}
142
143/**
144 Generates an INIT to the CPU.
145
146 @param This Protocol instance structure
147 @param InitType Type of CPU INIT to perform
148
149 @retval EFI_SUCCESS If CPU INIT occurred. This value should never be
150 seen.
151 @retval EFI_DEVICE_ERROR If CPU INIT failed.
152 @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported.
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
165/**
166 Registers a function to be called from the CPU interrupt handler.
167
168 @param This Protocol instance structure
169 @param InterruptType Defines which interrupt to hook. IA-32
170 valid range is 0x00 through 0xFF
171 @param InterruptHandler A pointer to a function of type
172 EFI_CPU_INTERRUPT_HANDLER that is called
173 when a processor interrupt occurs. A null
174 pointer is an error condition.
175
176 @retval EFI_SUCCESS If handler installed or uninstalled.
177 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler
178 for InterruptType was previously installed.
179 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for
180 InterruptType was not previously installed.
181 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType
182 is not supported.
183
184**/
185EFI_STATUS
186EFIAPI
187CpuRegisterInterruptHandler (
188 IN EFI_CPU_ARCH_PROTOCOL *This,
189 IN EFI_EXCEPTION_TYPE InterruptType,
190 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
191 )
192{
193 return RegisterCpuInterruptHandler (InterruptType, InterruptHandler);
194}
195
196/**
197 Returns a timer value from one of the CPU's internal timers. There is no
198 inherent time interval between ticks but is a function of the CPU frequency.
199
200 @param This - Protocol instance structure.
201 @param TimerIndex - Specifies which CPU timer is requested.
202 @param TimerValue - Pointer to the returned timer value.
203 @param TimerPeriod - A pointer to the amount of time that passes
204 in femtoseconds (10-15) for each increment
205 of TimerValue. If TimerValue does not
206 increment at a predictable rate, then 0 is
207 returned. The amount of time that has
208 passed between two calls to GetTimerValue()
209 can be calculated with the formula
210 (TimerValue2 - TimerValue1) * TimerPeriod.
211 This parameter is optional and may be NULL.
212
213 @retval EFI_SUCCESS - If the CPU timer count was returned.
214 @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.
215 @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.
216 @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
217
218**/
219EFI_STATUS
220EFIAPI
221CpuGetTimerValue (
222 IN EFI_CPU_ARCH_PROTOCOL *This,
223 IN UINT32 TimerIndex,
224 OUT UINT64 *TimerValue,
225 OUT UINT64 *TimerPeriod OPTIONAL
226 )
227{
228 UINT64 BeginValue;
229 UINT64 EndValue;
230
231 if (TimerValue == NULL) {
232 return EFI_INVALID_PARAMETER;
233 }
234
235 if (TimerIndex != 0) {
236 return EFI_INVALID_PARAMETER;
237 }
238
239 *TimerValue = AsmReadTsc ();
240
241 if (TimerPeriod != NULL) {
242 if (mTimerPeriod == 0) {
243 //
244 // Read time stamp counter before and after delay of 100 microseconds
245 //
246 BeginValue = AsmReadTsc ();
247 MicroSecondDelay (100);
248 EndValue = AsmReadTsc ();
249 //
250 // Calculate the actual frequency
251 //
252 mTimerPeriod = DivU64x64Remainder (
253 MultU64x32 (
254 1000 * 1000 * 1000,
255 100
256 ),
257 EndValue - BeginValue,
258 NULL
259 );
260 }
261
262 *TimerPeriod = mTimerPeriod;
263 }
264
265 return EFI_SUCCESS;
266}
267
268/**
269 A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed to
270 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure.
271
272 @param[in] Buffer Pointer to an MTRR_SETTINGS object, to be passed to
273 MtrrSetAllMtrrs().
274**/
275VOID
276EFIAPI
277SetMtrrsFromBuffer (
278 IN VOID *Buffer
279 )
280{
281 MtrrSetAllMtrrs (Buffer);
282}
283
284/**
285 Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.
286
287 This function modifies the attributes for the memory region specified by BaseAddress and
288 Length from their current attributes to the attributes specified by Attributes.
289
290 @param This The EFI_CPU_ARCH_PROTOCOL instance.
291 @param BaseAddress The physical address that is the start address of a memory region.
292 @param Length The size in bytes of the memory region.
293 @param Attributes The bit mask of attributes to set for the memory region.
294
295 @retval EFI_SUCCESS The attributes were set for the memory region.
296 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
297 BaseAddress and Length cannot be modified.
298 @retval EFI_INVALID_PARAMETER Length is zero.
299 Attributes specified an illegal combination of attributes that
300 cannot be set together.
301 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
302 the memory resource range.
303 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
304 resource range specified by BaseAddress and Length.
305 The bit mask of attributes is not support for the memory resource
306 range specified by BaseAddress and Length.
307
308**/
309EFI_STATUS
310EFIAPI
311CpuSetMemoryAttributes (
312 IN EFI_CPU_ARCH_PROTOCOL *This,
313 IN EFI_PHYSICAL_ADDRESS BaseAddress,
314 IN UINT64 Length,
315 IN UINT64 Attributes
316 )
317{
318 RETURN_STATUS Status;
319 MTRR_MEMORY_CACHE_TYPE CacheType;
320 EFI_STATUS MpStatus;
321 EFI_MP_SERVICES_PROTOCOL *MpService;
322 MTRR_SETTINGS MtrrSettings;
323 UINT64 CacheAttributes;
324 UINT64 MemoryAttributes;
325 MTRR_MEMORY_CACHE_TYPE CurrentCacheType;
326
327 //
328 // If this function is called because GCD SetMemorySpaceAttributes () is called
329 // by RefreshGcdMemoryAttributes (), then we are just synchronizing GCD memory
330 // map with MTRR values. So there is no need to modify MTRRs, just return immediately
331 // to avoid unnecessary computing.
332 //
333 if (mIsFlushingGCD) {
334 DEBUG ((DEBUG_VERBOSE, " Flushing GCD\n"));
335 return EFI_SUCCESS;
336 }
337
338 //
339 // During memory attributes updating, new pages may be allocated to setup
340 // smaller granularity of page table. Page allocation action might then cause
341 // another calling of CpuSetMemoryAttributes() recursively, due to memory
342 // protection policy configured (such as PcdDxeNxMemoryProtectionPolicy).
343 // Since this driver will always protect memory used as page table by itself,
344 // there's no need to apply protection policy requested from memory service.
345 // So it's safe to just return EFI_SUCCESS if this time of calling is caused
346 // by page table memory allocation.
347 //
348 if (mIsAllocatingPageTable) {
349 DEBUG ((DEBUG_VERBOSE, " Allocating page table memory\n"));
350 return EFI_SUCCESS;
351 }
352
353 CacheAttributes = Attributes & EFI_CACHE_ATTRIBUTE_MASK;
354 MemoryAttributes = Attributes & EFI_MEMORY_ATTRIBUTE_MASK;
355
356 if (Attributes != (CacheAttributes | MemoryAttributes)) {
357 return EFI_INVALID_PARAMETER;
358 }
359
360 if (CacheAttributes != 0) {
361 if (!IsMtrrSupported ()) {
362 return EFI_UNSUPPORTED;
363 }
364
365 switch (CacheAttributes) {
366 case EFI_MEMORY_UC:
367 CacheType = CacheUncacheable;
368 break;
369
370 case EFI_MEMORY_WC:
371 CacheType = CacheWriteCombining;
372 break;
373
374 case EFI_MEMORY_WT:
375 CacheType = CacheWriteThrough;
376 break;
377
378 case EFI_MEMORY_WP:
379 CacheType = CacheWriteProtected;
380 break;
381
382 case EFI_MEMORY_WB:
383 CacheType = CacheWriteBack;
384 break;
385
386 default:
387 return EFI_INVALID_PARAMETER;
388 }
389
390 CurrentCacheType = MtrrGetMemoryAttribute (BaseAddress);
391 if (CurrentCacheType != CacheType) {
392 //
393 // call MTRR library function
394 //
395 Status = MtrrSetMemoryAttribute (
396 BaseAddress,
397 Length,
398 CacheType
399 );
400
401 if (!RETURN_ERROR (Status)) {
402 MpStatus = gBS->LocateProtocol (
403 &gEfiMpServiceProtocolGuid,
404 NULL,
405 (VOID **)&MpService
406 );
407 //
408 // Synchronize the update with all APs
409 //
410 if (!EFI_ERROR (MpStatus)) {
411 MtrrGetAllMtrrs (&MtrrSettings);
412 MpStatus = MpService->StartupAllAPs (
413 MpService, // This
414 SetMtrrsFromBuffer, // Procedure
415 FALSE, // SingleThread
416 NULL, // WaitEvent
417 0, // TimeoutInMicrosecsond
418 &MtrrSettings, // ProcedureArgument
419 NULL // FailedCpuList
420 );
421 ASSERT (MpStatus == EFI_SUCCESS || MpStatus == EFI_NOT_STARTED);
422 }
423 }
424
425 if (EFI_ERROR (Status)) {
426 return Status;
427 }
428 }
429 }
430
431 //
432 // Set memory attribute by page table
433 //
434 return AssignMemoryPageAttributes (NULL, BaseAddress, Length, MemoryAttributes, NULL);
435}
436
437/**
438 Gets GCD Mem Space type from MTRR Type.
439
440 This function gets GCD Mem Space type from MTRR Type.
441
442 @param Type MTRR memory type
443
444 @return GCD Mem Space type
445
446**/
447UINT64
448GetMemorySpaceAttributeFromMtrrType (
449 IN MTRR_MEMORY_CACHE_TYPE Type
450 )
451{
452 switch (Type) {
453 case CacheUncacheable:
454 return EFI_MEMORY_UC;
455 case CacheWriteCombining:
456 return EFI_MEMORY_WC;
457 case CacheWriteThrough:
458 return EFI_MEMORY_WT;
459 case CacheWriteProtected:
460 return EFI_MEMORY_WP;
461 case CacheWriteBack:
462 return EFI_MEMORY_WB;
463 default:
464 return 0;
465 }
466}
467
468/**
469 Searches memory descriptors covered by given memory range.
470
471 This function searches into the Gcd Memory Space for descriptors
472 (from StartIndex to EndIndex) that contains the memory range
473 specified by BaseAddress and Length.
474
475 @param MemorySpaceMap Gcd Memory Space Map as array.
476 @param NumberOfDescriptors Number of descriptors in map.
477 @param BaseAddress BaseAddress for the requested range.
478 @param Length Length for the requested range.
479 @param StartIndex Start index into the Gcd Memory Space Map.
480 @param EndIndex End index into the Gcd Memory Space Map.
481
482 @retval EFI_SUCCESS Search successfully.
483 @retval EFI_NOT_FOUND The requested descriptors does not exist.
484
485**/
486EFI_STATUS
487SearchGcdMemorySpaces (
488 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
489 IN UINTN NumberOfDescriptors,
490 IN EFI_PHYSICAL_ADDRESS BaseAddress,
491 IN UINT64 Length,
492 OUT UINTN *StartIndex,
493 OUT UINTN *EndIndex
494 )
495{
496 UINTN Index;
497
498 *StartIndex = 0;
499 *EndIndex = 0;
500 for (Index = 0; Index < NumberOfDescriptors; Index++) {
501 if ((BaseAddress >= MemorySpaceMap[Index].BaseAddress) &&
502 (BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length))
503 {
504 *StartIndex = Index;
505 }
506
507 if ((BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress) &&
508 (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length))
509 {
510 *EndIndex = Index;
511 return EFI_SUCCESS;
512 }
513 }
514
515 return EFI_NOT_FOUND;
516}
517
518/**
519 Sets the attributes for a specified range in Gcd Memory Space Map.
520
521 This function sets the attributes for a specified range in
522 Gcd Memory Space Map.
523
524 @param MemorySpaceMap Gcd Memory Space Map as array
525 @param NumberOfDescriptors Number of descriptors in map
526 @param BaseAddress BaseAddress for the range
527 @param Length Length for the range
528 @param Attributes Attributes to set
529
530 @retval EFI_SUCCESS Memory attributes set successfully
531 @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space
532
533**/
534EFI_STATUS
535SetGcdMemorySpaceAttributes (
536 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
537 IN UINTN NumberOfDescriptors,
538 IN EFI_PHYSICAL_ADDRESS BaseAddress,
539 IN UINT64 Length,
540 IN UINT64 Attributes
541 )
542{
543 EFI_STATUS Status;
544 UINTN Index;
545 UINTN StartIndex;
546 UINTN EndIndex;
547 EFI_PHYSICAL_ADDRESS RegionStart;
548 UINT64 RegionLength;
549
550 //
551 // Get all memory descriptors covered by the memory range
552 //
553 Status = SearchGcdMemorySpaces (
554 MemorySpaceMap,
555 NumberOfDescriptors,
556 BaseAddress,
557 Length,
558 &StartIndex,
559 &EndIndex
560 );
561 if (EFI_ERROR (Status)) {
562 return Status;
563 }
564
565 //
566 // Go through all related descriptors and set attributes accordingly
567 //
568 for (Index = StartIndex; Index <= EndIndex; Index++) {
569 if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
570 continue;
571 }
572
573 //
574 // Calculate the start and end address of the overlapping range
575 //
576 if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
577 RegionStart = BaseAddress;
578 } else {
579 RegionStart = MemorySpaceMap[Index].BaseAddress;
580 }
581
582 if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
583 RegionLength = BaseAddress + Length - RegionStart;
584 } else {
585 RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;
586 }
587
588 //
589 // Set memory attributes according to MTRR attribute and the original attribute of descriptor
590 //
591 gDS->SetMemorySpaceAttributes (
592 RegionStart,
593 RegionLength,
594 (MemorySpaceMap[Index].Attributes & ~EFI_CACHE_ATTRIBUTE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)
595 );
596 }
597
598 return EFI_SUCCESS;
599}
600
601/**
602 Refreshes the GCD Memory Space attributes according to MTRRs.
603
604 This function refreshes the GCD Memory Space attributes according to MTRRs.
605
606**/
607VOID
608RefreshMemoryAttributesFromMtrr (
609 VOID
610 )
611{
612 EFI_STATUS Status;
613 RETURN_STATUS ReturnStatus;
614 UINTN Index;
615 UINTN NumberOfDescriptors;
616 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
617 MTRR_MEMORY_RANGE *Ranges;
618 UINTN RangeCount;
619
620 MemorySpaceMap = NULL;
621
622 //
623 // Get the memory space map from GCD
624 //
625 Status = gDS->GetMemorySpaceMap (
626 &NumberOfDescriptors,
627 &MemorySpaceMap
628 );
629 ASSERT_EFI_ERROR (Status);
630
631 RangeCount = 0;
632 ReturnStatus = MtrrGetMemoryAttributesInMtrrSettings (NULL, NULL, &RangeCount);
633 ASSERT (ReturnStatus == RETURN_BUFFER_TOO_SMALL);
634 Ranges = AllocatePool (sizeof (*Ranges) * RangeCount);
635 ASSERT (Ranges != NULL);
636 ReturnStatus = MtrrGetMemoryAttributesInMtrrSettings (NULL, Ranges, &RangeCount);
637 ASSERT_RETURN_ERROR (ReturnStatus);
638
639 for (Index = 0; Index < RangeCount; Index++) {
640 SetGcdMemorySpaceAttributes (
641 MemorySpaceMap,
642 NumberOfDescriptors,
643 Ranges[Index].BaseAddress,
644 Ranges[Index].Length,
645 GetMemorySpaceAttributeFromMtrrType (Ranges[Index].Type)
646 );
647 }
648
649 //
650 // Free memory space map allocated by GCD service GetMemorySpaceMap ()
651 //
652 if (MemorySpaceMap != NULL) {
653 FreePool (MemorySpaceMap);
654 }
655}
656
657/**
658 Check if paging is enabled or not.
659**/
660BOOLEAN
661IsPagingAndPageAddressExtensionsEnabled (
662 VOID
663 )
664{
665 IA32_CR0 Cr0;
666 IA32_CR4 Cr4;
667
668 Cr0.UintN = AsmReadCr0 ();
669 Cr4.UintN = AsmReadCr4 ();
670
671 return ((Cr0.Bits.PG != 0) && (Cr4.Bits.PAE != 0));
672}
673
674/**
675 Refreshes the GCD Memory Space attributes according to MTRRs and Paging.
676
677 This function refreshes the GCD Memory Space attributes according to MTRRs
678 and page tables.
679
680**/
681VOID
682RefreshGcdMemoryAttributes (
683 VOID
684 )
685{
686 mIsFlushingGCD = TRUE;
687
688 if (IsMtrrSupported ()) {
689 RefreshMemoryAttributesFromMtrr ();
690 }
691
692 if (IsPagingAndPageAddressExtensionsEnabled ()) {
693 RefreshGcdMemoryAttributesFromPaging ();
694 }
695
696 mIsFlushingGCD = FALSE;
697}
698
699/**
700 Initialize Interrupt Descriptor Table for interrupt handling.
701
702**/
703VOID
704InitInterruptDescriptorTable (
705 VOID
706 )
707{
708 EFI_STATUS Status;
709 EFI_VECTOR_HANDOFF_INFO *VectorInfoList;
710 EFI_VECTOR_HANDOFF_INFO *VectorInfo;
711 IA32_IDT_GATE_DESCRIPTOR *IdtTable;
712 IA32_DESCRIPTOR IdtDescriptor;
713 UINTN IdtEntryCount;
714
715 VectorInfo = NULL;
716 Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList);
717 if ((Status == EFI_SUCCESS) && (VectorInfoList != NULL)) {
718 VectorInfo = VectorInfoList;
719 }
720
721 AsmReadIdtr (&IdtDescriptor);
722 IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
723 if (IdtEntryCount < CPU_INTERRUPT_NUM) {
724 //
725 // Increase Interrupt Descriptor Table and Copy the old IDT table in
726 //
727 IdtTable = AllocateZeroPool (sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM);
728 ASSERT (IdtTable != NULL);
729 CopyMem (IdtTable, (VOID *)IdtDescriptor.Base, sizeof (IA32_IDT_GATE_DESCRIPTOR) * IdtEntryCount);
730
731 //
732 // Load Interrupt Descriptor Table
733 //
734 IdtDescriptor.Base = (UINTN)IdtTable;
735 IdtDescriptor.Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM - 1);
736 AsmWriteIdtr (&IdtDescriptor);
737 }
738
739 Status = InitializeCpuExceptionHandlers (VectorInfo);
740 ASSERT_EFI_ERROR (Status);
741}
742
743/**
744 Callback function for idle events.
745
746 @param Event Event whose notification function is being invoked.
747 @param Context The pointer to the notification function's context,
748 which is implementation-dependent.
749
750**/
751VOID
752EFIAPI
753IdleLoopEventCallback (
754 IN EFI_EVENT Event,
755 IN VOID *Context
756 )
757{
758 CpuSleep ();
759}
760
761/**
762 Ensure the compatibility of a memory space descriptor with the MMIO aperture.
763
764 The memory space descriptor can come from the GCD memory space map, or it can
765 represent a gap between two neighboring memory space descriptors. In the
766 latter case, the GcdMemoryType field is expected to be
767 EfiGcdMemoryTypeNonExistent.
768
769 If the memory space descriptor already has type
770 EfiGcdMemoryTypeMemoryMappedIo, and its capabilities are a superset of the
771 required capabilities, then no action is taken -- it is by definition
772 compatible with the aperture.
773
774 Otherwise, the intersection of the memory space descriptor is calculated with
775 the aperture. If the intersection is the empty set (no overlap), no action is
776 taken; the memory space descriptor is compatible with the aperture.
777
778 Otherwise, the type of the descriptor is investigated again. If the type is
779 EfiGcdMemoryTypeNonExistent (representing a gap, or a genuine descriptor with
780 such a type), then an attempt is made to add the intersection as MMIO space
781 to the GCD memory space map, with the specified capabilities. This ensures
782 continuity for the aperture, and the descriptor is deemed compatible with the
783 aperture.
784
785 Otherwise, the memory space descriptor is incompatible with the MMIO
786 aperture.
787
788 @param[in] Base Base address of the aperture.
789 @param[in] Length Length of the aperture.
790 @param[in] Capabilities Capabilities required by the aperture.
791 @param[in] Descriptor The descriptor to ensure compatibility with the
792 aperture for.
793
794 @retval EFI_SUCCESS The descriptor is compatible. The GCD memory
795 space map may have been updated, for
796 continuity within the aperture.
797 @retval EFI_INVALID_PARAMETER The descriptor is incompatible.
798 @return Error codes from gDS->AddMemorySpace().
799**/
800EFI_STATUS
801IntersectMemoryDescriptor (
802 IN UINT64 Base,
803 IN UINT64 Length,
804 IN UINT64 Capabilities,
805 IN CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
806 )
807{
808 UINT64 IntersectionBase;
809 UINT64 IntersectionEnd;
810 EFI_STATUS Status;
811
812 if ((Descriptor->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
813 ((Descriptor->Capabilities & Capabilities) == Capabilities))
814 {
815 return EFI_SUCCESS;
816 }
817
818 IntersectionBase = MAX (Base, Descriptor->BaseAddress);
819 IntersectionEnd = MIN (
820 Base + Length,
821 Descriptor->BaseAddress + Descriptor->Length
822 );
823 if (IntersectionBase >= IntersectionEnd) {
824 //
825 // The descriptor and the aperture don't overlap.
826 //
827 return EFI_SUCCESS;
828 }
829
830 if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
831 Status = gDS->AddMemorySpace (
832 EfiGcdMemoryTypeMemoryMappedIo,
833 IntersectionBase,
834 IntersectionEnd - IntersectionBase,
835 Capabilities
836 );
837
838 DEBUG ((
839 EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
840 "%a: %a: add [%Lx, %Lx): %r\n",
841 gEfiCallerBaseName,
842 __func__,
843 IntersectionBase,
844 IntersectionEnd,
845 Status
846 ));
847 return Status;
848 }
849
850 DEBUG ((
851 DEBUG_ERROR,
852 "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts "
853 "with aperture [%Lx, %Lx) cap %Lx\n",
854 gEfiCallerBaseName,
855 __func__,
856 Descriptor->BaseAddress,
857 Descriptor->BaseAddress + Descriptor->Length,
858 (UINT32)Descriptor->GcdMemoryType,
859 Descriptor->Capabilities,
860 Base,
861 Base + Length,
862 Capabilities
863 ));
864 return EFI_INVALID_PARAMETER;
865}
866
867/**
868 Add MMIO space to GCD.
869 The routine checks the GCD database and only adds those which are
870 not added in the specified range to GCD.
871
872 @param Base Base address of the MMIO space.
873 @param Length Length of the MMIO space.
874 @param Capabilities Capabilities of the MMIO space.
875
876 @retval EFI_SUCCESS The MMIO space was added successfully.
877**/
878EFI_STATUS
879AddMemoryMappedIoSpace (
880 IN UINT64 Base,
881 IN UINT64 Length,
882 IN UINT64 Capabilities
883 )
884{
885 EFI_STATUS Status;
886 UINTN Index;
887 UINTN NumberOfDescriptors;
888 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
889
890 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
891 if (EFI_ERROR (Status)) {
892 DEBUG ((
893 DEBUG_ERROR,
894 "%a: %a: GetMemorySpaceMap(): %r\n",
895 gEfiCallerBaseName,
896 __func__,
897 Status
898 ));
899 return Status;
900 }
901
902 for (Index = 0; Index < NumberOfDescriptors; Index++) {
903 Status = IntersectMemoryDescriptor (
904 Base,
905 Length,
906 Capabilities,
907 &MemorySpaceMap[Index]
908 );
909 if (EFI_ERROR (Status)) {
910 goto FreeMemorySpaceMap;
911 }
912 }
913
914 DEBUG_CODE_BEGIN ();
915 //
916 // Make sure there are adjacent descriptors covering [Base, Base + Length).
917 // It is possible that they have not been merged; merging can be prevented
918 // by allocation and different capabilities.
919 //
920 UINT64 CheckBase;
921 EFI_STATUS CheckStatus;
922 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
923
924 for (CheckBase = Base;
925 CheckBase < Base + Length;
926 CheckBase = Descriptor.BaseAddress + Descriptor.Length)
927 {
928 CheckStatus = gDS->GetMemorySpaceDescriptor (CheckBase, &Descriptor);
929 ASSERT_EFI_ERROR (CheckStatus);
930 ASSERT (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo);
931 ASSERT ((Descriptor.Capabilities & Capabilities) == Capabilities);
932 }
933
934 DEBUG_CODE_END ();
935
936FreeMemorySpaceMap:
937 FreePool (MemorySpaceMap);
938
939 return Status;
940}
941
942/**
943 Add and allocate CPU local APIC memory mapped space.
944
945 @param[in]ImageHandle Image handle this driver.
946
947**/
948VOID
949AddLocalApicMemorySpace (
950 IN EFI_HANDLE ImageHandle
951 )
952{
953 EFI_STATUS Status;
954 EFI_PHYSICAL_ADDRESS BaseAddress;
955
956 BaseAddress = (EFI_PHYSICAL_ADDRESS)GetLocalApicBaseAddress ();
957 Status = AddMemoryMappedIoSpace (BaseAddress, SIZE_4KB, EFI_MEMORY_UC);
958 ASSERT_EFI_ERROR (Status);
959
960 //
961 // Try to allocate APIC memory mapped space, does not check return
962 // status because it may be allocated by other driver, or DXE Core if
963 // this range is built into Memory Allocation HOB.
964 //
965 Status = gDS->AllocateMemorySpace (
966 EfiGcdAllocateAddress,
967 EfiGcdMemoryTypeMemoryMappedIo,
968 0,
969 SIZE_4KB,
970 &BaseAddress,
971 ImageHandle,
972 NULL
973 );
974 if (EFI_ERROR (Status)) {
975 DEBUG ((
976 DEBUG_INFO,
977 "%a: %a: AllocateMemorySpace() Status - %r\n",
978 gEfiCallerBaseName,
979 __func__,
980 Status
981 ));
982 }
983}
984
985/**
986 Initialize the state information for the CPU Architectural Protocol.
987
988 @param ImageHandle Image handle this driver.
989 @param SystemTable Pointer to the System Table.
990
991 @retval EFI_SUCCESS Thread can be successfully created
992 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
993 @retval EFI_DEVICE_ERROR Cannot create the thread
994
995**/
996EFI_STATUS
997EFIAPI
998InitializeCpu (
999 IN EFI_HANDLE ImageHandle,
1000 IN EFI_SYSTEM_TABLE *SystemTable
1001 )
1002{
1003 EFI_STATUS Status;
1004 EFI_EVENT IdleLoopEvent;
1005
1006 InitializePageTableLib ();
1007
1008 InitializeFloatingPointUnits ();
1009
1010 //
1011 // Make sure interrupts are disabled
1012 //
1013 DisableInterrupts ();
1014
1015 //
1016 // Init GDT for DXE
1017 //
1018 InitGlobalDescriptorTable ();
1019
1020 //
1021 // Setup IDT pointer, IDT and interrupt entry points
1022 //
1023 InitInterruptDescriptorTable ();
1024
1025 //
1026 // Install CPU Architectural Protocol
1027 //
1028 Status = gBS->InstallMultipleProtocolInterfaces (
1029 &mCpuHandle,
1030 &gEfiCpuArchProtocolGuid,
1031 &gCpu,
1032 NULL
1033 );
1034 ASSERT_EFI_ERROR (Status);
1035
1036 //
1037 // Install EFI memory attribute Protocol
1038 //
1039 InstallEfiMemoryAttributeProtocol (mCpuHandle);
1040
1041 //
1042 // Refresh GCD memory space map according to MTRR value.
1043 //
1044 RefreshGcdMemoryAttributes ();
1045
1046 //
1047 // Add and allocate local APIC memory mapped space
1048 //
1049 AddLocalApicMemorySpace (ImageHandle);
1050
1051 //
1052 // Setup a callback for idle events
1053 //
1054 Status = gBS->CreateEventEx (
1055 EVT_NOTIFY_SIGNAL,
1056 TPL_NOTIFY,
1057 IdleLoopEventCallback,
1058 NULL,
1059 &gIdleLoopEventGuid,
1060 &IdleLoopEvent
1061 );
1062 ASSERT_EFI_ERROR (Status);
1063
1064 InitializeMpSupport ();
1065
1066 return Status;
1067}
Note: See TracBrowser for help on using the repository browser.

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