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