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