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