]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/CpuDxe/CpuDxe.c
Roll back the change on GetMemorySpaceAttributeFromMtrrType()'s parameter type, from...
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / CpuDxe.c
1 /** @file
2 CPU DXE Module.
3
4 Copyright (c) 2008 - 2011, 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
17 //
18 // Global Variables
19 //
20 IA32_IDT_GATE_DESCRIPTOR gIdtTable[INTERRUPT_VECTOR_NUMBER] = { 0 };
21
22 EFI_CPU_INTERRUPT_HANDLER ExternalVectorTable[0x100];
23 BOOLEAN InterruptState = FALSE;
24 EFI_HANDLE mCpuHandle = NULL;
25 BOOLEAN mIsFlushingGCD;
26 UINT64 mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;
27 UINT64 mValidMtrrBitsMask = MTRR_LIB_MSR_VALID_MASK;
28
29 FIXED_MTRR mFixedMtrrTable[] = {
30 {
31 MTRR_LIB_IA32_MTRR_FIX64K_00000,
32 0,
33 0x10000
34 },
35 {
36 MTRR_LIB_IA32_MTRR_FIX16K_80000,
37 0x80000,
38 0x4000
39 },
40 {
41 MTRR_LIB_IA32_MTRR_FIX16K_A0000,
42 0xA0000,
43 0x4000
44 },
45 {
46 MTRR_LIB_IA32_MTRR_FIX4K_C0000,
47 0xC0000,
48 0x1000
49 },
50 {
51 MTRR_LIB_IA32_MTRR_FIX4K_C8000,
52 0xC8000,
53 0x1000
54 },
55 {
56 MTRR_LIB_IA32_MTRR_FIX4K_D0000,
57 0xD0000,
58 0x1000
59 },
60 {
61 MTRR_LIB_IA32_MTRR_FIX4K_D8000,
62 0xD8000,
63 0x1000
64 },
65 {
66 MTRR_LIB_IA32_MTRR_FIX4K_E0000,
67 0xE0000,
68 0x1000
69 },
70 {
71 MTRR_LIB_IA32_MTRR_FIX4K_E8000,
72 0xE8000,
73 0x1000
74 },
75 {
76 MTRR_LIB_IA32_MTRR_FIX4K_F0000,
77 0xF0000,
78 0x1000
79 },
80 {
81 MTRR_LIB_IA32_MTRR_FIX4K_F8000,
82 0xF8000,
83 0x1000
84 },
85 };
86
87
88 EFI_CPU_ARCH_PROTOCOL gCpu = {
89 CpuFlushCpuDataCache,
90 CpuEnableInterrupt,
91 CpuDisableInterrupt,
92 CpuGetInterruptState,
93 CpuInit,
94 CpuRegisterInterruptHandler,
95 CpuGetTimerValue,
96 CpuSetMemoryAttributes,
97 1, // NumberOfTimers
98 4 // DmaBufferAlignment
99 };
100
101 //
102 // Error code flag indicating whether or not an error code will be
103 // pushed on the stack if an exception occurs.
104 //
105 // 1 means an error code will be pushed, otherwise 0
106 //
107 // bit 0 - exception 0
108 // bit 1 - exception 1
109 // etc.
110 //
111 UINT32 mErrorCodeFlag = 0x00027d00;
112
113 //
114 // Local function prototypes
115 //
116
117 /**
118 Set Interrupt Descriptor Table Handler Address.
119
120 @param Index The Index of the interrupt descriptor table handle.
121 @param Handler Handler address.
122
123 **/
124 VOID
125 SetInterruptDescriptorTableHandlerAddress (
126 IN UINTN Index,
127 IN VOID *Handler OPTIONAL
128 );
129
130 //
131 // CPU Arch Protocol Functions
132 //
133
134
135 /**
136 Common exception handler.
137
138 @param InterruptType Exception type
139 @param SystemContext EFI_SYSTEM_CONTEXT
140
141 **/
142 VOID
143 EFIAPI
144 CommonExceptionHandler (
145 IN EFI_EXCEPTION_TYPE InterruptType,
146 IN EFI_SYSTEM_CONTEXT SystemContext
147 )
148 {
149 #if defined (MDE_CPU_IA32)
150 DEBUG ((
151 EFI_D_ERROR,
152 "!!!! IA32 Exception Type - %08x !!!!\n",
153 InterruptType
154 ));
155 if ((mErrorCodeFlag & (1 << InterruptType)) != 0) {
156 DEBUG ((
157 EFI_D_ERROR,
158 "ExceptionData - %08x\n",
159 SystemContext.SystemContextIa32->ExceptionData
160 ));
161 }
162 DEBUG ((
163 EFI_D_ERROR,
164 "CS - %04x, EIP - %08x, EFL - %08x, SS - %04x\n",
165 SystemContext.SystemContextIa32->Cs,
166 SystemContext.SystemContextIa32->Eip,
167 SystemContext.SystemContextIa32->Eflags,
168 SystemContext.SystemContextIa32->Ss
169 ));
170 DEBUG ((
171 EFI_D_ERROR,
172 "DS - %04x, ES - %04x, FS - %04x, GS - %04x\n",
173 SystemContext.SystemContextIa32->Ds,
174 SystemContext.SystemContextIa32->Es,
175 SystemContext.SystemContextIa32->Fs,
176 SystemContext.SystemContextIa32->Gs
177 ));
178 DEBUG ((
179 EFI_D_ERROR,
180 "EAX - %08x, EBX - %08x, ECX - %08x, EDX - %08x\n",
181 SystemContext.SystemContextIa32->Eax,
182 SystemContext.SystemContextIa32->Ebx,
183 SystemContext.SystemContextIa32->Ecx,
184 SystemContext.SystemContextIa32->Edx
185 ));
186 DEBUG ((
187 EFI_D_ERROR,
188 "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n",
189 SystemContext.SystemContextIa32->Esp,
190 SystemContext.SystemContextIa32->Ebp,
191 SystemContext.SystemContextIa32->Esi,
192 SystemContext.SystemContextIa32->Edi
193 ));
194 DEBUG ((
195 EFI_D_ERROR,
196 "GDT - %08x LIM - %04x, IDT - %08x LIM - %04x\n",
197 SystemContext.SystemContextIa32->Gdtr[0],
198 SystemContext.SystemContextIa32->Gdtr[1],
199 SystemContext.SystemContextIa32->Idtr[0],
200 SystemContext.SystemContextIa32->Idtr[1]
201 ));
202 DEBUG ((
203 EFI_D_ERROR,
204 "LDT - %08x, TR - %08x\n",
205 SystemContext.SystemContextIa32->Ldtr,
206 SystemContext.SystemContextIa32->Tr
207 ));
208 DEBUG ((
209 EFI_D_ERROR,
210 "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n",
211 SystemContext.SystemContextIa32->Cr0,
212 SystemContext.SystemContextIa32->Cr2,
213 SystemContext.SystemContextIa32->Cr3,
214 SystemContext.SystemContextIa32->Cr4
215 ));
216 DEBUG ((
217 EFI_D_ERROR,
218 "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n",
219 SystemContext.SystemContextIa32->Dr0,
220 SystemContext.SystemContextIa32->Dr1,
221 SystemContext.SystemContextIa32->Dr2,
222 SystemContext.SystemContextIa32->Dr3
223 ));
224 DEBUG ((
225 EFI_D_ERROR,
226 "DR6 - %08x, DR7 - %08x\n",
227 SystemContext.SystemContextIa32->Dr6,
228 SystemContext.SystemContextIa32->Dr7
229 ));
230 #elif defined (MDE_CPU_X64)
231 DEBUG ((
232 EFI_D_ERROR,
233 "!!!! X64 Exception Type - %016lx !!!!\n",
234 (UINT64)InterruptType
235 ));
236 if ((mErrorCodeFlag & (1 << InterruptType)) != 0) {
237 DEBUG ((
238 EFI_D_ERROR,
239 "ExceptionData - %016lx\n",
240 SystemContext.SystemContextX64->ExceptionData
241 ));
242 }
243 DEBUG ((
244 EFI_D_ERROR,
245 "RIP - %016lx, RFL - %016lx\n",
246 SystemContext.SystemContextX64->Rip,
247 SystemContext.SystemContextX64->Rflags
248 ));
249 DEBUG ((
250 EFI_D_ERROR,
251 "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",
252 SystemContext.SystemContextX64->Rax,
253 SystemContext.SystemContextX64->Rcx,
254 SystemContext.SystemContextX64->Rdx
255 ));
256 DEBUG ((
257 EFI_D_ERROR,
258 "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",
259 SystemContext.SystemContextX64->Rbx,
260 SystemContext.SystemContextX64->Rsp,
261 SystemContext.SystemContextX64->Rbp
262 ));
263 DEBUG ((
264 EFI_D_ERROR,
265 "RSI - %016lx, RDI - %016lx\n",
266 SystemContext.SystemContextX64->Rsi,
267 SystemContext.SystemContextX64->Rdi
268 ));
269 DEBUG ((
270 EFI_D_ERROR,
271 "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",
272 SystemContext.SystemContextX64->R8,
273 SystemContext.SystemContextX64->R9,
274 SystemContext.SystemContextX64->R10
275 ));
276 DEBUG ((
277 EFI_D_ERROR,
278 "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",
279 SystemContext.SystemContextX64->R11,
280 SystemContext.SystemContextX64->R12,
281 SystemContext.SystemContextX64->R13
282 ));
283 DEBUG ((
284 EFI_D_ERROR,
285 "R14 - %016lx, R15 - %016lx\n",
286 SystemContext.SystemContextX64->R14,
287 SystemContext.SystemContextX64->R15
288 ));
289 DEBUG ((
290 EFI_D_ERROR,
291 "CS - %04lx, DS - %04lx, ES - %04lx, FS - %04lx, GS - %04lx, SS - %04lx\n",
292 SystemContext.SystemContextX64->Cs,
293 SystemContext.SystemContextX64->Ds,
294 SystemContext.SystemContextX64->Es,
295 SystemContext.SystemContextX64->Fs,
296 SystemContext.SystemContextX64->Gs,
297 SystemContext.SystemContextX64->Ss
298 ));
299 DEBUG ((
300 EFI_D_ERROR,
301 "GDT - %016lx; %04lx, IDT - %016lx; %04lx\n",
302 SystemContext.SystemContextX64->Gdtr[0],
303 SystemContext.SystemContextX64->Gdtr[1],
304 SystemContext.SystemContextX64->Idtr[0],
305 SystemContext.SystemContextX64->Idtr[1]
306 ));
307 DEBUG ((
308 EFI_D_ERROR,
309 "LDT - %016lx, TR - %016lx\n",
310 SystemContext.SystemContextX64->Ldtr,
311 SystemContext.SystemContextX64->Tr
312 ));
313 DEBUG ((
314 EFI_D_ERROR,
315 "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",
316 SystemContext.SystemContextX64->Cr0,
317 SystemContext.SystemContextX64->Cr2,
318 SystemContext.SystemContextX64->Cr3
319 ));
320 DEBUG ((
321 EFI_D_ERROR,
322 "CR4 - %016lx, CR8 - %016lx\n",
323 SystemContext.SystemContextX64->Cr4,
324 SystemContext.SystemContextX64->Cr8
325 ));
326 DEBUG ((
327 EFI_D_ERROR,
328 "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",
329 SystemContext.SystemContextX64->Dr0,
330 SystemContext.SystemContextX64->Dr1,
331 SystemContext.SystemContextX64->Dr2
332 ));
333 DEBUG ((
334 EFI_D_ERROR,
335 "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",
336 SystemContext.SystemContextX64->Dr3,
337 SystemContext.SystemContextX64->Dr6,
338 SystemContext.SystemContextX64->Dr7
339 ));
340 #else
341 #error CPU type not supported for exception information dump!
342 #endif
343
344 //
345 // Hang the system with CpuSleep so the processor will enter a lower power
346 // state.
347 //
348 while (TRUE) {
349 CpuSleep ();
350 };
351 }
352
353
354 /**
355 Flush CPU data cache. If the instruction cache is fully coherent
356 with all DMA operations then function can just return EFI_SUCCESS.
357
358 @param This Protocol instance structure
359 @param Start Physical address to start flushing from.
360 @param Length Number of bytes to flush. Round up to chipset
361 granularity.
362 @param FlushType Specifies the type of flush operation to perform.
363
364 @retval EFI_SUCCESS If cache was flushed
365 @retval EFI_UNSUPPORTED If flush type is not supported.
366 @retval EFI_DEVICE_ERROR If requested range could not be flushed.
367
368 **/
369 EFI_STATUS
370 EFIAPI
371 CpuFlushCpuDataCache (
372 IN EFI_CPU_ARCH_PROTOCOL *This,
373 IN EFI_PHYSICAL_ADDRESS Start,
374 IN UINT64 Length,
375 IN EFI_CPU_FLUSH_TYPE FlushType
376 )
377 {
378 if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
379 AsmWbinvd ();
380 return EFI_SUCCESS;
381 } else if (FlushType == EfiCpuFlushTypeInvalidate) {
382 AsmInvd ();
383 return EFI_SUCCESS;
384 } else {
385 return EFI_UNSUPPORTED;
386 }
387 }
388
389
390 /**
391 Enables CPU interrupts.
392
393 @param This Protocol instance structure
394
395 @retval EFI_SUCCESS If interrupts were enabled in the CPU
396 @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU.
397
398 **/
399 EFI_STATUS
400 EFIAPI
401 CpuEnableInterrupt (
402 IN EFI_CPU_ARCH_PROTOCOL *This
403 )
404 {
405 EnableInterrupts ();
406
407 InterruptState = TRUE;
408 return EFI_SUCCESS;
409 }
410
411
412 /**
413 Disables CPU interrupts.
414
415 @param This Protocol instance structure
416
417 @retval EFI_SUCCESS If interrupts were disabled in the CPU.
418 @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU.
419
420 **/
421 EFI_STATUS
422 EFIAPI
423 CpuDisableInterrupt (
424 IN EFI_CPU_ARCH_PROTOCOL *This
425 )
426 {
427 DisableInterrupts ();
428
429 InterruptState = FALSE;
430 return EFI_SUCCESS;
431 }
432
433
434 /**
435 Return the state of interrupts.
436
437 @param This Protocol instance structure
438 @param State Pointer to the CPU's current interrupt state
439
440 @retval EFI_SUCCESS If interrupts were disabled in the CPU.
441 @retval EFI_INVALID_PARAMETER State is NULL.
442
443 **/
444 EFI_STATUS
445 EFIAPI
446 CpuGetInterruptState (
447 IN EFI_CPU_ARCH_PROTOCOL *This,
448 OUT BOOLEAN *State
449 )
450 {
451 if (State == NULL) {
452 return EFI_INVALID_PARAMETER;
453 }
454
455 *State = InterruptState;
456 return EFI_SUCCESS;
457 }
458
459
460 /**
461 Generates an INIT to the CPU.
462
463 @param This Protocol instance structure
464 @param InitType Type of CPU INIT to perform
465
466 @retval EFI_SUCCESS If CPU INIT occurred. This value should never be
467 seen.
468 @retval EFI_DEVICE_ERROR If CPU INIT failed.
469 @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported.
470
471 **/
472 EFI_STATUS
473 EFIAPI
474 CpuInit (
475 IN EFI_CPU_ARCH_PROTOCOL *This,
476 IN EFI_CPU_INIT_TYPE InitType
477 )
478 {
479 return EFI_UNSUPPORTED;
480 }
481
482
483 /**
484 Registers a function to be called from the CPU interrupt handler.
485
486 @param This Protocol instance structure
487 @param InterruptType Defines which interrupt to hook. IA-32
488 valid range is 0x00 through 0xFF
489 @param InterruptHandler A pointer to a function of type
490 EFI_CPU_INTERRUPT_HANDLER that is called
491 when a processor interrupt occurs. A null
492 pointer is an error condition.
493
494 @retval EFI_SUCCESS If handler installed or uninstalled.
495 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler
496 for InterruptType was previously installed.
497 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for
498 InterruptType was not previously installed.
499 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType
500 is not supported.
501
502 **/
503 EFI_STATUS
504 EFIAPI
505 CpuRegisterInterruptHandler (
506 IN EFI_CPU_ARCH_PROTOCOL *This,
507 IN EFI_EXCEPTION_TYPE InterruptType,
508 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
509 )
510 {
511 if (InterruptType < 0 || InterruptType > 0xff) {
512 return EFI_UNSUPPORTED;
513 }
514
515 if (InterruptHandler == NULL && ExternalVectorTable[InterruptType] == NULL) {
516 return EFI_INVALID_PARAMETER;
517 }
518
519 if (InterruptHandler != NULL && ExternalVectorTable[InterruptType] != NULL) {
520 return EFI_ALREADY_STARTED;
521 }
522
523 SetInterruptDescriptorTableHandlerAddress ((UINTN)InterruptType, NULL);
524 ExternalVectorTable[InterruptType] = InterruptHandler;
525 return EFI_SUCCESS;
526 }
527
528
529 /**
530 Returns a timer value from one of the CPU's internal timers. There is no
531 inherent time interval between ticks but is a function of the CPU frequency.
532
533 @param This - Protocol instance structure.
534 @param TimerIndex - Specifies which CPU timer is requested.
535 @param TimerValue - Pointer to the returned timer value.
536 @param TimerPeriod - A pointer to the amount of time that passes
537 in femtoseconds (10-15) for each increment
538 of TimerValue. If TimerValue does not
539 increment at a predictable rate, then 0 is
540 returned. The amount of time that has
541 passed between two calls to GetTimerValue()
542 can be calculated with the formula
543 (TimerValue2 - TimerValue1) * TimerPeriod.
544 This parameter is optional and may be NULL.
545
546 @retval EFI_SUCCESS - If the CPU timer count was returned.
547 @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.
548 @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.
549 @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
550
551 **/
552 EFI_STATUS
553 EFIAPI
554 CpuGetTimerValue (
555 IN EFI_CPU_ARCH_PROTOCOL *This,
556 IN UINT32 TimerIndex,
557 OUT UINT64 *TimerValue,
558 OUT UINT64 *TimerPeriod OPTIONAL
559 )
560 {
561 if (TimerValue == NULL) {
562 return EFI_INVALID_PARAMETER;
563 }
564
565 if (TimerIndex != 0) {
566 return EFI_INVALID_PARAMETER;
567 }
568
569 *TimerValue = AsmReadTsc ();
570
571 if (TimerPeriod != NULL) {
572 //
573 // BugBug: Hard coded. Don't know how to do this generically
574 //
575 *TimerPeriod = 1000000000;
576 }
577
578 return EFI_SUCCESS;
579 }
580
581
582 /**
583 Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.
584
585 This function modifies the attributes for the memory region specified by BaseAddress and
586 Length from their current attributes to the attributes specified by Attributes.
587
588 @param This The EFI_CPU_ARCH_PROTOCOL instance.
589 @param BaseAddress The physical address that is the start address of a memory region.
590 @param Length The size in bytes of the memory region.
591 @param Attributes The bit mask of attributes to set for the memory region.
592
593 @retval EFI_SUCCESS The attributes were set for the memory region.
594 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
595 BaseAddress and Length cannot be modified.
596 @retval EFI_INVALID_PARAMETER Length is zero.
597 Attributes specified an illegal combination of attributes that
598 cannot be set together.
599 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
600 the memory resource range.
601 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
602 resource range specified by BaseAddress and Length.
603 The bit mask of attributes is not support for the memory resource
604 range specified by BaseAddress and Length.
605
606 **/
607 EFI_STATUS
608 EFIAPI
609 CpuSetMemoryAttributes (
610 IN EFI_CPU_ARCH_PROTOCOL *This,
611 IN EFI_PHYSICAL_ADDRESS BaseAddress,
612 IN UINT64 Length,
613 IN UINT64 Attributes
614 )
615 {
616 RETURN_STATUS Status;
617 MTRR_MEMORY_CACHE_TYPE CacheType;
618
619 if (!IsMtrrSupported ()) {
620 return EFI_UNSUPPORTED;
621 }
622
623 //
624 // If this function is called because GCD SetMemorySpaceAttributes () is called
625 // by RefreshGcdMemoryAttributes (), then we are just synchronzing GCD memory
626 // map with MTRR values. So there is no need to modify MTRRs, just return immediately
627 // to avoid unnecessary computing.
628 //
629 if (mIsFlushingGCD) {
630 DEBUG((EFI_D_ERROR, " Flushing GCD\n"));
631 return EFI_SUCCESS;
632 }
633
634 switch (Attributes) {
635 case EFI_MEMORY_UC:
636 CacheType = CacheUncacheable;
637 break;
638
639 case EFI_MEMORY_WC:
640 CacheType = CacheWriteCombining;
641 break;
642
643 case EFI_MEMORY_WT:
644 CacheType = CacheWriteThrough;
645 break;
646
647 case EFI_MEMORY_WP:
648 CacheType = CacheWriteProtected;
649 break;
650
651 case EFI_MEMORY_WB:
652 CacheType = CacheWriteBack;
653 break;
654
655 case EFI_MEMORY_UCE:
656 case EFI_MEMORY_RP:
657 case EFI_MEMORY_XP:
658 case EFI_MEMORY_RUNTIME:
659 return EFI_UNSUPPORTED;
660
661 default:
662 return EFI_INVALID_PARAMETER;
663 }
664 //
665 // call MTRR libary function
666 //
667 Status = MtrrSetMemoryAttribute (
668 BaseAddress,
669 Length,
670 CacheType
671 );
672
673 return (EFI_STATUS) Status;
674 }
675
676 /**
677 Initializes the valid bits mask and valid address mask for MTRRs.
678
679 This function initializes the valid bits mask and valid address mask for MTRRs.
680
681 **/
682 VOID
683 InitializeMtrrMask (
684 VOID
685 )
686 {
687 UINT32 RegEax;
688 UINT8 PhysicalAddressBits;
689
690 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
691
692 if (RegEax >= 0x80000008) {
693 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
694
695 PhysicalAddressBits = (UINT8) RegEax;
696
697 mValidMtrrBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;
698 mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000ULL;
699 } else {
700 mValidMtrrBitsMask = MTRR_LIB_MSR_VALID_MASK;
701 mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;
702 }
703 }
704
705 /**
706 Gets GCD Mem Space type from MTRR Type.
707
708 This function gets GCD Mem Space type from MTRR Type.
709
710 @param MtrrAttributes MTRR memory type
711
712 @return GCD Mem Space type
713
714 **/
715 UINT64
716 GetMemorySpaceAttributeFromMtrrType (
717 IN UINT8 MtrrAttributes
718 )
719 {
720 switch (MtrrAttributes) {
721 case MTRR_CACHE_UNCACHEABLE:
722 return EFI_MEMORY_UC;
723 case MTRR_CACHE_WRITE_COMBINING:
724 return EFI_MEMORY_WC;
725 case MTRR_CACHE_WRITE_THROUGH:
726 return EFI_MEMORY_WT;
727 case MTRR_CACHE_WRITE_PROTECTED:
728 return EFI_MEMORY_WP;
729 case MTRR_CACHE_WRITE_BACK:
730 return EFI_MEMORY_WB;
731 default:
732 return 0;
733 }
734 }
735
736 /**
737 Searches memory descriptors covered by given memory range.
738
739 This function searches into the Gcd Memory Space for descriptors
740 (from StartIndex to EndIndex) that contains the memory range
741 specified by BaseAddress and Length.
742
743 @param MemorySpaceMap Gcd Memory Space Map as array.
744 @param NumberOfDescriptors Number of descriptors in map.
745 @param BaseAddress BaseAddress for the requested range.
746 @param Length Length for the requested range.
747 @param StartIndex Start index into the Gcd Memory Space Map.
748 @param EndIndex End index into the Gcd Memory Space Map.
749
750 @retval EFI_SUCCESS Search successfully.
751 @retval EFI_NOT_FOUND The requested descriptors does not exist.
752
753 **/
754 EFI_STATUS
755 SearchGcdMemorySpaces (
756 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
757 IN UINTN NumberOfDescriptors,
758 IN EFI_PHYSICAL_ADDRESS BaseAddress,
759 IN UINT64 Length,
760 OUT UINTN *StartIndex,
761 OUT UINTN *EndIndex
762 )
763 {
764 UINTN Index;
765
766 *StartIndex = 0;
767 *EndIndex = 0;
768 for (Index = 0; Index < NumberOfDescriptors; Index++) {
769 if (BaseAddress >= MemorySpaceMap[Index].BaseAddress &&
770 BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
771 *StartIndex = Index;
772 }
773 if (BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress &&
774 BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
775 *EndIndex = Index;
776 return EFI_SUCCESS;
777 }
778 }
779 return EFI_NOT_FOUND;
780 }
781
782 /**
783 Sets the attributes for a specified range in Gcd Memory Space Map.
784
785 This function sets the attributes for a specified range in
786 Gcd Memory Space Map.
787
788 @param MemorySpaceMap Gcd Memory Space Map as array
789 @param NumberOfDescriptors Number of descriptors in map
790 @param BaseAddress BaseAddress for the range
791 @param Length Length for the range
792 @param Attributes Attributes to set
793
794 @retval EFI_SUCCESS Memory attributes set successfully
795 @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space
796
797 **/
798 EFI_STATUS
799 SetGcdMemorySpaceAttributes (
800 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
801 IN UINTN NumberOfDescriptors,
802 IN EFI_PHYSICAL_ADDRESS BaseAddress,
803 IN UINT64 Length,
804 IN UINT64 Attributes
805 )
806 {
807 EFI_STATUS Status;
808 UINTN Index;
809 UINTN StartIndex;
810 UINTN EndIndex;
811 EFI_PHYSICAL_ADDRESS RegionStart;
812 UINT64 RegionLength;
813
814 //
815 // Get all memory descriptors covered by the memory range
816 //
817 Status = SearchGcdMemorySpaces (
818 MemorySpaceMap,
819 NumberOfDescriptors,
820 BaseAddress,
821 Length,
822 &StartIndex,
823 &EndIndex
824 );
825 if (EFI_ERROR (Status)) {
826 return Status;
827 }
828
829 //
830 // Go through all related descriptors and set attributes accordingly
831 //
832 for (Index = StartIndex; Index <= EndIndex; Index++) {
833 if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
834 continue;
835 }
836 //
837 // Calculate the start and end address of the overlapping range
838 //
839 if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
840 RegionStart = BaseAddress;
841 } else {
842 RegionStart = MemorySpaceMap[Index].BaseAddress;
843 }
844 if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
845 RegionLength = BaseAddress + Length - RegionStart;
846 } else {
847 RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;
848 }
849 //
850 // Set memory attributes according to MTRR attribute and the original attribute of descriptor
851 //
852 gDS->SetMemorySpaceAttributes (
853 RegionStart,
854 RegionLength,
855 (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)
856 );
857 }
858
859 return EFI_SUCCESS;
860 }
861
862
863 /**
864 Refreshes the GCD Memory Space attributes according to MTRRs.
865
866 This function refreshes the GCD Memory Space attributes according to MTRRs.
867
868 **/
869 VOID
870 RefreshGcdMemoryAttributes (
871 VOID
872 )
873 {
874 EFI_STATUS Status;
875 UINTN Index;
876 UINTN SubIndex;
877 UINT64 RegValue;
878 EFI_PHYSICAL_ADDRESS BaseAddress;
879 UINT64 Length;
880 UINT64 Attributes;
881 UINT64 CurrentAttributes;
882 UINT8 MtrrType;
883 UINTN NumberOfDescriptors;
884 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
885 UINT64 DefaultAttributes;
886 VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
887 MTRR_FIXED_SETTINGS MtrrFixedSettings;
888 UINT32 FirmwareVariableMtrrCount;
889 UINT8 DefaultMemoryType;
890
891 if (!IsMtrrSupported ()) {
892 return;
893 }
894
895 FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
896 ASSERT (FirmwareVariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
897
898 mIsFlushingGCD = TRUE;
899 MemorySpaceMap = NULL;
900
901 //
902 // Initialize the valid bits mask and valid address mask for MTRRs
903 //
904 InitializeMtrrMask ();
905
906 //
907 // Get the memory attribute of variable MTRRs
908 //
909 MtrrGetMemoryAttributeInVariableMtrr (
910 mValidMtrrBitsMask,
911 mValidMtrrAddressMask,
912 VariableMtrr
913 );
914
915 //
916 // Get the memory space map from GCD
917 //
918 Status = gDS->GetMemorySpaceMap (
919 &NumberOfDescriptors,
920 &MemorySpaceMap
921 );
922 ASSERT_EFI_ERROR (Status);
923
924 DefaultMemoryType = (UINT8) MtrrGetDefaultMemoryType ();
925 DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (DefaultMemoryType);
926
927 //
928 // Set default attributes to all spaces.
929 //
930 for (Index = 0; Index < NumberOfDescriptors; Index++) {
931 if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
932 continue;
933 }
934 gDS->SetMemorySpaceAttributes (
935 MemorySpaceMap[Index].BaseAddress,
936 MemorySpaceMap[Index].Length,
937 (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) |
938 (MemorySpaceMap[Index].Capabilities & DefaultAttributes)
939 );
940 }
941
942 //
943 // Go for variable MTRRs with WB attribute
944 //
945 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
946 if (VariableMtrr[Index].Valid &&
947 VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) {
948 SetGcdMemorySpaceAttributes (
949 MemorySpaceMap,
950 NumberOfDescriptors,
951 VariableMtrr[Index].BaseAddress,
952 VariableMtrr[Index].Length,
953 EFI_MEMORY_WB
954 );
955 }
956 }
957
958 //
959 // Go for variable MTRRs with the attribute except for WB and UC attributes
960 //
961 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
962 if (VariableMtrr[Index].Valid &&
963 VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK &&
964 VariableMtrr[Index].Type != MTRR_CACHE_UNCACHEABLE) {
965 Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8) VariableMtrr[Index].Type);
966 SetGcdMemorySpaceAttributes (
967 MemorySpaceMap,
968 NumberOfDescriptors,
969 VariableMtrr[Index].BaseAddress,
970 VariableMtrr[Index].Length,
971 Attributes
972 );
973 }
974 }
975
976 //
977 // Go for variable MTRRs with UC attribute
978 //
979 for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
980 if (VariableMtrr[Index].Valid &&
981 VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE) {
982 SetGcdMemorySpaceAttributes (
983 MemorySpaceMap,
984 NumberOfDescriptors,
985 VariableMtrr[Index].BaseAddress,
986 VariableMtrr[Index].Length,
987 EFI_MEMORY_UC
988 );
989 }
990 }
991
992 //
993 // Go for fixed MTRRs
994 //
995 Attributes = 0;
996 BaseAddress = 0;
997 Length = 0;
998 MtrrGetFixedMtrr (&MtrrFixedSettings);
999 for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
1000 RegValue = MtrrFixedSettings.Mtrr[Index];
1001 //
1002 // Check for continuous fixed MTRR sections
1003 //
1004 for (SubIndex = 0; SubIndex < 8; SubIndex++) {
1005 MtrrType = (UINT8) RShiftU64 (RegValue, SubIndex * 8);
1006 CurrentAttributes = GetMemorySpaceAttributeFromMtrrType (MtrrType);
1007 if (Length == 0) {
1008 //
1009 // A new MTRR attribute begins
1010 //
1011 Attributes = CurrentAttributes;
1012 } else {
1013 //
1014 // If fixed MTRR attribute changed, then set memory attribute for previous atrribute
1015 //
1016 if (CurrentAttributes != Attributes) {
1017 SetGcdMemorySpaceAttributes (
1018 MemorySpaceMap,
1019 NumberOfDescriptors,
1020 BaseAddress,
1021 Length,
1022 Attributes
1023 );
1024 BaseAddress = mFixedMtrrTable[Index].BaseAddress + mFixedMtrrTable[Index].Length * SubIndex;
1025 Length = 0;
1026 Attributes = CurrentAttributes;
1027 }
1028 }
1029 Length += mFixedMtrrTable[Index].Length;
1030 }
1031 }
1032 //
1033 // Handle the last fixed MTRR region
1034 //
1035 SetGcdMemorySpaceAttributes (
1036 MemorySpaceMap,
1037 NumberOfDescriptors,
1038 BaseAddress,
1039 Length,
1040 Attributes
1041 );
1042
1043 //
1044 // Free memory space map allocated by GCD service GetMemorySpaceMap ()
1045 //
1046 if (MemorySpaceMap != NULL) {
1047 FreePool (MemorySpaceMap);
1048 }
1049
1050 mIsFlushingGCD = FALSE;
1051 }
1052
1053 /**
1054 Set Interrupt Descriptor Table Handler Address.
1055
1056 @param Index The Index of the interrupt descriptor table handle.
1057 @param Handler Handler address.
1058
1059 **/
1060 VOID
1061 SetInterruptDescriptorTableHandlerAddress (
1062 IN UINTN Index,
1063 IN VOID *Handler OPTIONAL
1064 )
1065 {
1066 UINTN UintnHandler;
1067
1068 if (Handler != NULL) {
1069 UintnHandler = (UINTN) Handler;
1070 } else {
1071 UintnHandler = ((UINTN) AsmIdtVector00) + (8 * Index);
1072 }
1073
1074 gIdtTable[Index].Bits.OffsetLow = (UINT16)UintnHandler;
1075 gIdtTable[Index].Bits.Reserved_0 = 0;
1076 gIdtTable[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
1077 gIdtTable[Index].Bits.OffsetHigh = (UINT16)(UintnHandler >> 16);
1078 #if defined (MDE_CPU_X64)
1079 gIdtTable[Index].Bits.OffsetUpper = (UINT32)(UintnHandler >> 32);
1080 gIdtTable[Index].Bits.Reserved_1 = 0;
1081 #endif
1082 }
1083
1084
1085 /**
1086 Initialize Interrupt Descriptor Table for interrupt handling.
1087
1088 **/
1089 VOID
1090 InitInterruptDescriptorTable (
1091 VOID
1092 )
1093 {
1094 EFI_STATUS Status;
1095 IA32_DESCRIPTOR OldIdtPtr;
1096 IA32_IDT_GATE_DESCRIPTOR *OldIdt;
1097 UINTN OldIdtSize;
1098 VOID *IdtPtrAlignmentBuffer;
1099 IA32_DESCRIPTOR *IdtPtr;
1100 UINTN Index;
1101 UINT16 CurrentCs;
1102 VOID *IntHandler;
1103
1104 SetMem (ExternalVectorTable, sizeof(ExternalVectorTable), 0);
1105
1106 //
1107 // Get original IDT address and size.
1108 //
1109 AsmReadIdtr ((IA32_DESCRIPTOR *) &OldIdtPtr);
1110
1111 if ((OldIdtPtr.Base != 0) && ((OldIdtPtr.Limit & 7) == 7)) {
1112 OldIdt = (IA32_IDT_GATE_DESCRIPTOR*) OldIdtPtr.Base;
1113 OldIdtSize = (OldIdtPtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
1114 } else {
1115 OldIdt = NULL;
1116 OldIdtSize = 0;
1117 }
1118
1119 //
1120 // Intialize IDT
1121 //
1122 CurrentCs = AsmReadCs();
1123 for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++) {
1124 //
1125 // If the old IDT had a handler for this interrupt, then
1126 // preserve it.
1127 //
1128 if (Index < OldIdtSize) {
1129 IntHandler =
1130 (VOID*) (
1131 OldIdt[Index].Bits.OffsetLow +
1132 (OldIdt[Index].Bits.OffsetHigh << 16)
1133 #if defined (MDE_CPU_X64)
1134 + (((UINTN) OldIdt[Index].Bits.OffsetUpper) << 32)
1135 #endif
1136 );
1137 } else {
1138 IntHandler = NULL;
1139 }
1140
1141 gIdtTable[Index].Bits.Selector = CurrentCs;
1142 gIdtTable[Index].Bits.Reserved_0 = 0;
1143 gIdtTable[Index].Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
1144 SetInterruptDescriptorTableHandlerAddress (Index, IntHandler);
1145 }
1146
1147 //
1148 // Load IDT Pointer
1149 //
1150 IdtPtrAlignmentBuffer = AllocatePool (sizeof (*IdtPtr) + 16);
1151 IdtPtr = ALIGN_POINTER (IdtPtrAlignmentBuffer, 16);
1152 IdtPtr->Base = (UINT32)(((UINTN)(VOID*) gIdtTable) & (BASE_4GB-1));
1153 IdtPtr->Limit = (UINT16) (sizeof (gIdtTable) - 1);
1154
1155 AsmWriteIdtr (IdtPtr);
1156
1157 FreePool (IdtPtrAlignmentBuffer);
1158
1159 //
1160 // Initialize Exception Handlers
1161 //
1162 for (Index = OldIdtSize; Index < 32; Index++) {
1163 Status = CpuRegisterInterruptHandler (&gCpu, Index, CommonExceptionHandler);
1164 ASSERT_EFI_ERROR (Status);
1165 }
1166
1167 //
1168 // Set the pointer to the array of C based exception handling routines.
1169 //
1170 InitializeExternalVectorTablePtr (ExternalVectorTable);
1171
1172 }
1173
1174
1175 /**
1176 Callback function for idle events.
1177
1178 @param Event Event whose notification function is being invoked.
1179 @param Context The pointer to the notification function's context,
1180 which is implementation-dependent.
1181
1182 **/
1183 VOID
1184 EFIAPI
1185 IdleLoopEventCallback (
1186 IN EFI_EVENT Event,
1187 IN VOID *Context
1188 )
1189 {
1190 CpuSleep ();
1191 }
1192
1193
1194 /**
1195 Initialize the state information for the CPU Architectural Protocol.
1196
1197 @param ImageHandle Image handle this driver.
1198 @param SystemTable Pointer to the System Table.
1199
1200 @retval EFI_SUCCESS Thread can be successfully created
1201 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
1202 @retval EFI_DEVICE_ERROR Cannot create the thread
1203
1204 **/
1205 EFI_STATUS
1206 EFIAPI
1207 InitializeCpu (
1208 IN EFI_HANDLE ImageHandle,
1209 IN EFI_SYSTEM_TABLE *SystemTable
1210 )
1211 {
1212 EFI_STATUS Status;
1213 EFI_EVENT IdleLoopEvent;
1214
1215 //
1216 // Make sure interrupts are disabled
1217 //
1218 DisableInterrupts ();
1219
1220 //
1221 // Init GDT for DXE
1222 //
1223 InitGlobalDescriptorTable ();
1224
1225 //
1226 // Setup IDT pointer, IDT and interrupt entry points
1227 //
1228 InitInterruptDescriptorTable ();
1229
1230 //
1231 // Install CPU Architectural Protocol
1232 //
1233 Status = gBS->InstallMultipleProtocolInterfaces (
1234 &mCpuHandle,
1235 &gEfiCpuArchProtocolGuid, &gCpu,
1236 NULL
1237 );
1238 ASSERT_EFI_ERROR (Status);
1239
1240 //
1241 // Refresh GCD memory space map according to MTRR value.
1242 //
1243 RefreshGcdMemoryAttributes ();
1244
1245 //
1246 // Setup a callback for idle events
1247 //
1248 Status = gBS->CreateEventEx (
1249 EVT_NOTIFY_SIGNAL,
1250 TPL_NOTIFY,
1251 IdleLoopEventCallback,
1252 NULL,
1253 &gIdleLoopEventGuid,
1254 &IdleLoopEvent
1255 );
1256 ASSERT_EFI_ERROR (Status);
1257
1258 return Status;
1259 }
1260