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