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