1 | /** @file
|
---|
2 |
|
---|
3 | Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
|
---|
4 | Copyright (c) 2011, ARM Limited. All rights reserved.
|
---|
5 |
|
---|
6 | SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
7 |
|
---|
8 | **/
|
---|
9 |
|
---|
10 | #include "CpuDxe.h"
|
---|
11 |
|
---|
12 | #include <Guid/IdleLoopEvent.h>
|
---|
13 |
|
---|
14 | #include <Library/MemoryAllocationLib.h>
|
---|
15 |
|
---|
16 | BOOLEAN mIsFlushingGCD;
|
---|
17 |
|
---|
18 | /**
|
---|
19 | This function flushes the range of addresses from Start to Start+Length
|
---|
20 | from the processor's data cache. If Start is not aligned to a cache line
|
---|
21 | boundary, then the bytes before Start to the preceding cache line boundary
|
---|
22 | are also flushed. If Start+Length is not aligned to a cache line boundary,
|
---|
23 | then the bytes past Start+Length to the end of the next cache line boundary
|
---|
24 | are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
|
---|
25 | supported. If the data cache is fully coherent with all DMA operations, then
|
---|
26 | this function can just return EFI_SUCCESS. If the processor does not support
|
---|
27 | flushing a range of the data cache, then the entire data cache can be flushed.
|
---|
28 |
|
---|
29 | @param This The EFI_CPU_ARCH_PROTOCOL instance.
|
---|
30 | @param Start The beginning physical address to flush from the processor's data
|
---|
31 | cache.
|
---|
32 | @param Length The number of bytes to flush from the processor's data cache. This
|
---|
33 | function may flush more bytes than Length specifies depending upon
|
---|
34 | the granularity of the flush operation that the processor supports.
|
---|
35 | @param FlushType Specifies the type of flush operation to perform.
|
---|
36 |
|
---|
37 | @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from
|
---|
38 | the processor's data cache.
|
---|
39 | @retval EFI_UNSUPPORTED The processor does not support the cache flush type specified
|
---|
40 | by FlushType.
|
---|
41 | @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed
|
---|
42 | from the processor's data cache.
|
---|
43 |
|
---|
44 | **/
|
---|
45 | EFI_STATUS
|
---|
46 | EFIAPI
|
---|
47 | CpuFlushCpuDataCache (
|
---|
48 | IN EFI_CPU_ARCH_PROTOCOL *This,
|
---|
49 | IN EFI_PHYSICAL_ADDRESS Start,
|
---|
50 | IN UINT64 Length,
|
---|
51 | IN EFI_CPU_FLUSH_TYPE FlushType
|
---|
52 | )
|
---|
53 | {
|
---|
54 | switch (FlushType) {
|
---|
55 | case EfiCpuFlushTypeWriteBack:
|
---|
56 | WriteBackDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
|
---|
57 | break;
|
---|
58 | case EfiCpuFlushTypeInvalidate:
|
---|
59 | InvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
|
---|
60 | break;
|
---|
61 | case EfiCpuFlushTypeWriteBackInvalidate:
|
---|
62 | WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
|
---|
63 | break;
|
---|
64 | default:
|
---|
65 | return EFI_INVALID_PARAMETER;
|
---|
66 | }
|
---|
67 |
|
---|
68 | return EFI_SUCCESS;
|
---|
69 | }
|
---|
70 |
|
---|
71 | /**
|
---|
72 | This function enables interrupt processing by the processor.
|
---|
73 |
|
---|
74 | @param This The EFI_CPU_ARCH_PROTOCOL instance.
|
---|
75 |
|
---|
76 | @retval EFI_SUCCESS Interrupts are enabled on the processor.
|
---|
77 | @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor.
|
---|
78 |
|
---|
79 | **/
|
---|
80 | EFI_STATUS
|
---|
81 | EFIAPI
|
---|
82 | CpuEnableInterrupt (
|
---|
83 | IN EFI_CPU_ARCH_PROTOCOL *This
|
---|
84 | )
|
---|
85 | {
|
---|
86 | ArmEnableInterrupts ();
|
---|
87 |
|
---|
88 | return EFI_SUCCESS;
|
---|
89 | }
|
---|
90 |
|
---|
91 | /**
|
---|
92 | This function disables interrupt processing by the processor.
|
---|
93 |
|
---|
94 | @param This The EFI_CPU_ARCH_PROTOCOL instance.
|
---|
95 |
|
---|
96 | @retval EFI_SUCCESS Interrupts are disabled on the processor.
|
---|
97 | @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor.
|
---|
98 |
|
---|
99 | **/
|
---|
100 | EFI_STATUS
|
---|
101 | EFIAPI
|
---|
102 | CpuDisableInterrupt (
|
---|
103 | IN EFI_CPU_ARCH_PROTOCOL *This
|
---|
104 | )
|
---|
105 | {
|
---|
106 | ArmDisableInterrupts ();
|
---|
107 |
|
---|
108 | return EFI_SUCCESS;
|
---|
109 | }
|
---|
110 |
|
---|
111 | /**
|
---|
112 | This function retrieves the processor's current interrupt state a returns it in
|
---|
113 | State. If interrupts are currently enabled, then TRUE is returned. If interrupts
|
---|
114 | are currently disabled, then FALSE is returned.
|
---|
115 |
|
---|
116 | @param This The EFI_CPU_ARCH_PROTOCOL instance.
|
---|
117 | @param State A pointer to the processor's current interrupt state. Set to TRUE if
|
---|
118 | interrupts are enabled and FALSE if interrupts are disabled.
|
---|
119 |
|
---|
120 | @retval EFI_SUCCESS The processor's current interrupt state was returned in State.
|
---|
121 | @retval EFI_INVALID_PARAMETER State is NULL.
|
---|
122 |
|
---|
123 | **/
|
---|
124 | EFI_STATUS
|
---|
125 | EFIAPI
|
---|
126 | CpuGetInterruptState (
|
---|
127 | IN EFI_CPU_ARCH_PROTOCOL *This,
|
---|
128 | OUT BOOLEAN *State
|
---|
129 | )
|
---|
130 | {
|
---|
131 | if (State == NULL) {
|
---|
132 | return EFI_INVALID_PARAMETER;
|
---|
133 | }
|
---|
134 |
|
---|
135 | *State = ArmGetInterruptState ();
|
---|
136 | return EFI_SUCCESS;
|
---|
137 | }
|
---|
138 |
|
---|
139 | /**
|
---|
140 | This function generates an INIT on the processor. If this function succeeds, then the
|
---|
141 | processor will be reset, and control will not be returned to the caller. If InitType is
|
---|
142 | not supported by this processor, or the processor cannot programmatically generate an
|
---|
143 | INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
|
---|
144 | occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
|
---|
145 |
|
---|
146 | @param This The EFI_CPU_ARCH_PROTOCOL instance.
|
---|
147 | @param InitType The type of processor INIT to perform.
|
---|
148 |
|
---|
149 | @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen.
|
---|
150 | @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported
|
---|
151 | by this processor.
|
---|
152 | @retval EFI_DEVICE_ERROR The processor INIT failed.
|
---|
153 |
|
---|
154 | **/
|
---|
155 | EFI_STATUS
|
---|
156 | EFIAPI
|
---|
157 | CpuInit (
|
---|
158 | IN EFI_CPU_ARCH_PROTOCOL *This,
|
---|
159 | IN EFI_CPU_INIT_TYPE InitType
|
---|
160 | )
|
---|
161 | {
|
---|
162 | return EFI_UNSUPPORTED;
|
---|
163 | }
|
---|
164 |
|
---|
165 | EFI_STATUS
|
---|
166 | EFIAPI
|
---|
167 | CpuRegisterInterruptHandler (
|
---|
168 | IN EFI_CPU_ARCH_PROTOCOL *This,
|
---|
169 | IN EFI_EXCEPTION_TYPE InterruptType,
|
---|
170 | IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
|
---|
171 | )
|
---|
172 | {
|
---|
173 | return RegisterInterruptHandler (InterruptType, InterruptHandler);
|
---|
174 | }
|
---|
175 |
|
---|
176 | EFI_STATUS
|
---|
177 | EFIAPI
|
---|
178 | CpuGetTimerValue (
|
---|
179 | IN EFI_CPU_ARCH_PROTOCOL *This,
|
---|
180 | IN UINT32 TimerIndex,
|
---|
181 | OUT UINT64 *TimerValue,
|
---|
182 | OUT UINT64 *TimerPeriod OPTIONAL
|
---|
183 | )
|
---|
184 | {
|
---|
185 | return EFI_UNSUPPORTED;
|
---|
186 | }
|
---|
187 |
|
---|
188 | /**
|
---|
189 | Callback function for idle events.
|
---|
190 |
|
---|
191 | @param Event Event whose notification function is being invoked.
|
---|
192 | @param Context The pointer to the notification function's context,
|
---|
193 | which is implementation-dependent.
|
---|
194 |
|
---|
195 | **/
|
---|
196 | VOID
|
---|
197 | EFIAPI
|
---|
198 | IdleLoopEventCallback (
|
---|
199 | IN EFI_EVENT Event,
|
---|
200 | IN VOID *Context
|
---|
201 | )
|
---|
202 | {
|
---|
203 | CpuSleep ();
|
---|
204 | }
|
---|
205 |
|
---|
206 | //
|
---|
207 | // Globals used to initialize the protocol
|
---|
208 | //
|
---|
209 | EFI_HANDLE mCpuHandle = NULL;
|
---|
210 | EFI_CPU_ARCH_PROTOCOL mCpu = {
|
---|
211 | CpuFlushCpuDataCache,
|
---|
212 | CpuEnableInterrupt,
|
---|
213 | CpuDisableInterrupt,
|
---|
214 | CpuGetInterruptState,
|
---|
215 | CpuInit,
|
---|
216 | CpuRegisterInterruptHandler,
|
---|
217 | CpuGetTimerValue,
|
---|
218 | CpuSetMemoryAttributes,
|
---|
219 | 0, // NumberOfTimers
|
---|
220 | 2048, // DmaBufferAlignment
|
---|
221 | };
|
---|
222 |
|
---|
223 | STATIC
|
---|
224 | VOID
|
---|
225 | InitializeDma (
|
---|
226 | IN OUT EFI_CPU_ARCH_PROTOCOL *CpuArchProtocol
|
---|
227 | )
|
---|
228 | {
|
---|
229 | CpuArchProtocol->DmaBufferAlignment = ArmCacheWritebackGranule ();
|
---|
230 | }
|
---|
231 |
|
---|
232 | #ifndef VBOX
|
---|
233 | /**
|
---|
234 | Map all EfiConventionalMemory regions in the memory map with NX
|
---|
235 | attributes so that allocating or freeing EfiBootServicesData regions
|
---|
236 | does not result in changes to memory permission attributes.
|
---|
237 |
|
---|
238 | **/
|
---|
239 | STATIC
|
---|
240 | VOID
|
---|
241 | RemapUnusedMemoryNx (
|
---|
242 | VOID
|
---|
243 | )
|
---|
244 | {
|
---|
245 | UINT64 TestBit;
|
---|
246 | UINTN MemoryMapSize;
|
---|
247 | UINTN MapKey;
|
---|
248 | UINTN DescriptorSize;
|
---|
249 | UINT32 DescriptorVersion;
|
---|
250 | EFI_MEMORY_DESCRIPTOR *MemoryMap;
|
---|
251 | EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
|
---|
252 | EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
|
---|
253 | EFI_STATUS Status;
|
---|
254 |
|
---|
255 | TestBit = LShiftU64 (1, EfiBootServicesData);
|
---|
256 | if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) == 0) {
|
---|
257 | return;
|
---|
258 | }
|
---|
259 |
|
---|
260 | MemoryMapSize = 0;
|
---|
261 | MemoryMap = NULL;
|
---|
262 |
|
---|
263 | Status = gBS->GetMemoryMap (
|
---|
264 | &MemoryMapSize,
|
---|
265 | MemoryMap,
|
---|
266 | &MapKey,
|
---|
267 | &DescriptorSize,
|
---|
268 | &DescriptorVersion
|
---|
269 | );
|
---|
270 | ASSERT (Status == EFI_BUFFER_TOO_SMALL);
|
---|
271 | do {
|
---|
272 | MemoryMap = (EFI_MEMORY_DESCRIPTOR *)AllocatePool (MemoryMapSize);
|
---|
273 | ASSERT (MemoryMap != NULL);
|
---|
274 | Status = gBS->GetMemoryMap (
|
---|
275 | &MemoryMapSize,
|
---|
276 | MemoryMap,
|
---|
277 | &MapKey,
|
---|
278 | &DescriptorSize,
|
---|
279 | &DescriptorVersion
|
---|
280 | );
|
---|
281 | if (EFI_ERROR (Status)) {
|
---|
282 | FreePool (MemoryMap);
|
---|
283 | }
|
---|
284 | } while (Status == EFI_BUFFER_TOO_SMALL);
|
---|
285 |
|
---|
286 | ASSERT_EFI_ERROR (Status);
|
---|
287 |
|
---|
288 | MemoryMapEntry = MemoryMap;
|
---|
289 | MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
|
---|
290 | while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
|
---|
291 | if (MemoryMapEntry->Type == EfiConventionalMemory) {
|
---|
292 | ArmSetMemoryAttributes (
|
---|
293 | MemoryMapEntry->PhysicalStart,
|
---|
294 | EFI_PAGES_TO_SIZE (MemoryMapEntry->NumberOfPages),
|
---|
295 | EFI_MEMORY_XP,
|
---|
296 | EFI_MEMORY_XP
|
---|
297 | );
|
---|
298 | }
|
---|
299 |
|
---|
300 | MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
|
---|
301 | }
|
---|
302 | }
|
---|
303 | #endif
|
---|
304 |
|
---|
305 | EFI_STATUS
|
---|
306 | CpuDxeInitialize (
|
---|
307 | IN EFI_HANDLE ImageHandle,
|
---|
308 | IN EFI_SYSTEM_TABLE *SystemTable
|
---|
309 | )
|
---|
310 | {
|
---|
311 | EFI_STATUS Status;
|
---|
312 | EFI_EVENT IdleLoopEvent;
|
---|
313 |
|
---|
314 | InitializeExceptions (&mCpu);
|
---|
315 |
|
---|
316 | InitializeDma (&mCpu);
|
---|
317 |
|
---|
318 | #ifdef VBOX
|
---|
319 | /** @todo r=aeichner
|
---|
320 | * Exposing the EFI_MEMORY_ATTRIBUTE protocol (added with edk2-stable202308) breaks OL9 and
|
---|
321 | * Ubuntu 23.04 server guests at least. They use a shima64.efi and grubaa64.efi version where
|
---|
322 | * the SHIM sets a memory region in the grub binary to readonly when the EFI_MEMORY_ATTRIBUTE protocol is present
|
---|
323 | * but grub tries to write to that region for whatever reason (this seems to be fixed with more recent
|
---|
324 | * guests like ArchLinux or Debian 12 because these still boot with the protocol exposed).
|
---|
325 | * Disabling the protocol also requires disabling mapping the unused memory as NX as the DXE core has
|
---|
326 | * no means to disable the NX when it loads drivers during the discovery phase if the protocol is not exposed.
|
---|
327 | * Not setting the PcdRemapUnusedMemoryNx to FALSE here as I would have to replicate this comment in the DSC file.
|
---|
328 | *
|
---|
329 | * I'd really like to leave them enabled alas OL9 and Ubuntu 23.04 are pretty important ARM guests, sigh...
|
---|
330 | *
|
---|
331 | * The following is an excerpt from the exception with a debug firmware build (for the sake of completeness):
|
---|
332 | * BdsDxe: starting Boot0004 "Oracle Linux" from HD(1,GPT,13CF6614-34C0-46C2-A049-DF0B6B8E67C1,0x800,0x12C000)/\EFI\redhat\shimaa64.efi
|
---|
333 | * InstallProtocolInterface: 605DAB50-E046-4300-ABB6-3DD810DD8B23 F7DC31E8
|
---|
334 | * FSOpen: Open '\EFI\redhat\grubaa64.efi' Success
|
---|
335 | * SetMemoryAttributes: BaseAddress == 0xF77C7000, Length == 0x29F000, Attributes == 0x4000
|
---|
336 | * ClearMemoryAttributes: BaseAddress == 0xF77C7000, Length == 0x29F000, Attributes == 0x22000
|
---|
337 | * SetMemoryAttributes: BaseAddress == 0xF77C8000, Length == 0x1C000, Attributes == 0x20000
|
---|
338 | * ClearMemoryAttributes: BaseAddress == 0xF77C8000, Length == 0x1C000, Attributes == 0x6000
|
---|
339 | * SetMemoryAttributes: BaseAddress == 0xF77E4000, Length == 0x11000, Attributes == 0x4000
|
---|
340 | * ClearMemoryAttributes: BaseAddress == 0xF77E4000, Length == 0x11000, Attributes == 0x22000
|
---|
341 | * SetMemoryAttributes: BaseAddress == 0xF77F5000, Length == 0x26E000, Attributes == 0x4000
|
---|
342 | * ClearMemoryAttributes: BaseAddress == 0xF77F5000, Length == 0x26E000, Attributes == 0x22000
|
---|
343 | * SetMemoryAttributes: BaseAddress == 0xF7A63000, Length == 0x1000, Attributes == 0x24000
|
---|
344 | * ClearMemoryAttributes: BaseAddress == 0xF7A63000, Length == 0x1000, Attributes == 0x2000
|
---|
345 | * SetMemoryAttributes: BaseAddress == 0xF7A64000, Length == 0x1000, Attributes == 0x24000
|
---|
346 | * ClearMemoryAttributes: BaseAddress == 0xF7A64000, Length == 0x1000, Attributes == 0x2000
|
---|
347 | * SetMemoryAttributes: BaseAddress == 0xF77AE000, Length == 0xA000, Attributes == 0x20000
|
---|
348 | * ClearMemoryAttributes: BaseAddress == 0xF77AE000, Length == 0xA000, Attributes == 0x6000
|
---|
349 | * SetMemoryAttributes: BaseAddress == 0xF77B8000, Length == 0x1000, Attributes == 0x24000
|
---|
350 | * ClearMemoryAttributes: BaseAddress == 0xF77B8000, Length == 0x1000, Attributes == 0x2000
|
---|
351 | * SetMemoryAttributes: BaseAddress == 0xF77B9000, Length == 0x1000, Attributes == 0x24000
|
---|
352 | * ClearMemoryAttributes: BaseAddress == 0xF77B9000, Length == 0x1000, Attributes == 0x2000
|
---|
353 | * SetMemoryAttributes: BaseAddress == 0xF77BA000, Length == 0x1000, Attributes == 0x4000
|
---|
354 | * ClearMemoryAttributes: BaseAddress == 0xF77BA000, Length ==== 0x22000
|
---|
355 | * SetMemoryAttributes: BaseAddress == 0xF77BB000, Length == 0x1000, Attributes == 0x4000
|
---|
356 | * ClearMemoryAttributes: BaseAddress == 0xF77BB000, Length == 0x1000, Attributes == 0x22000
|
---|
357 | * SetMemoryAttributes: BaseAddress == 0xF77BC000, Length == 0x1000, Attributes == 0x20000 <= This is where the region is marked as readonly
|
---|
358 | * ClearMemoryAttributes: BaseAddress == 0xF77BC000, Length == 0x1000, Attributes == 0x6000
|
---|
359 | *
|
---|
360 | *
|
---|
361 | * Synchronous Exception at 0x00000000F77D889C
|
---|
362 | * PC 0x0000F77D889C
|
---|
363 | * PC 0x0000F77DAD90
|
---|
364 | * PC 0x0000F77DD240
|
---|
365 | * PC 0x0000F77DDD2C
|
---|
366 | * PC 0x0000F7D2F8D4
|
---|
367 | * PC 0x0000F7D2F984
|
---|
368 | * PC 0x0000F7D2D4F0
|
---|
369 | * PC 0x0000F7D2D030
|
---|
370 | * PC 0x0000FF174DDC (0x0000FF16D000+0x00007DDC) [ 1] DxeCore.dll
|
---|
371 | * PC 0x0000FB72F8AC (0x0000FB71C000+0x000138AC) [ 2] BdsDxe.dll
|
---|
372 | * PC 0x0000FB71E234 (0x0000FB71C000+0x00002234) [ 2] BdsDxe.dll
|
---|
373 | * PC 0x0000FB71FAB8 (0x0000FB71C000+0x00003AB8) [ 2] BdsDxe.dll
|
---|
374 | * PC 0x0000FF16FB78 (0x0000FF16D000+0x00002B78) [ 3] DxeCore.dll
|
---|
375 | * PC 0x0000FF16E9DC (0x0000FF16D000+0x000019DC) [ 3] DxeCore.dll
|
---|
376 | * PC 0x0000FF16E028 (0x0000FF16D000+0x00001028) [ 3] DxeCore.dll
|
---|
377 | * [...]
|
---|
378 | * X0 0x00000000F77BC8A0 X1 0x0000000000000000 X2 0x000000000000000D X3 0x00000000F77E60D8
|
---|
379 | * X4 0x00000000F77BC860 X5 0x00000000F77AE000 X6 0x00000000F77BA000 X7 0x00000000F77E5110
|
---|
380 | * X8 0x00000000F77E5108 X9 0x00000000F77E5110 X10 0x00000000F77E5120 X11 0x00000000F77E5110
|
---|
381 | * X12 0x00000000F77BCFFF X13 0x0000000000000008 X14 0x0000000000000000 X15 0x0000000000000000
|
---|
382 | * X16 0x0000000088660397 X17 0x0000000031550F3D X18 0x0000000000000011 X19 0x00000000F7DAF000
|
---|
383 | * X20 0x0000000000000000 X21 0x00000000F7DC3000 X22 0x00000000F9E3CA98 X3 0x00000000FF16CB40
|
---|
384 | * X24 0x00000000F9E3CA98 X25 0x00000000F7DC3210 X26 0x00000000F7DC3218 X27 0x00000000F7DC3208
|
---|
385 | * X28 0x00000000F7DC3220 FP 0x00000000FF16C990 LR 0x00000000F77DAD90
|
---|
386 | * [...]
|
---|
387 | * SP 0x00000000FF16C990 ELR 0x00000000F77D889C SPSR 0x60000205 FPSR 0x00000000
|
---|
388 | * ESR 0x9600004F FAR 0x00000000F77BC910 <= FAR holds the faulting virtual address
|
---|
389 | *
|
---|
390 | * ESR : EC 0x25 IL 0x1 ISS 0x0000004F
|
---|
391 | *
|
---|
392 | * Data abort: Permission fault, third level
|
---|
393 | */
|
---|
394 | #endif
|
---|
395 | #ifndef VBOX
|
---|
396 | //
|
---|
397 | // Once we install the CPU arch protocol, the DXE core's memory
|
---|
398 | // protection routines will invoke them to manage the permissions of page
|
---|
399 | // allocations as they are created. Given that this includes pages
|
---|
400 | // allocated for page tables by this driver, we must ensure that unused
|
---|
401 | // memory is mapped with the same permissions as boot services data
|
---|
402 | // regions. Otherwise, we may end up with unbounded recursion, due to the
|
---|
403 | // fact that updating permissions on a newly allocated page table may trigger
|
---|
404 | // a block entry split, which triggers a page table allocation, etc etc
|
---|
405 | //
|
---|
406 | if (FeaturePcdGet (PcdRemapUnusedMemoryNx)) {
|
---|
407 | RemapUnusedMemoryNx ();
|
---|
408 | }
|
---|
409 | #endif
|
---|
410 |
|
---|
411 | Status = gBS->InstallMultipleProtocolInterfaces (
|
---|
412 | &mCpuHandle,
|
---|
413 | &gEfiCpuArchProtocolGuid,
|
---|
414 | &mCpu,
|
---|
415 | #ifndef VBOX
|
---|
416 | &gEfiMemoryAttributeProtocolGuid,
|
---|
417 | &mMemoryAttribute,
|
---|
418 | #endif
|
---|
419 | NULL
|
---|
420 | );
|
---|
421 |
|
---|
422 | //
|
---|
423 | // Make sure GCD and MMU settings match. This API calls gDS->SetMemorySpaceAttributes ()
|
---|
424 | // and that calls EFI_CPU_ARCH_PROTOCOL.SetMemoryAttributes, so this code needs to go
|
---|
425 | // after the protocol is installed
|
---|
426 | //
|
---|
427 | mIsFlushingGCD = TRUE;
|
---|
428 | SyncCacheConfig (&mCpu);
|
---|
429 | mIsFlushingGCD = FALSE;
|
---|
430 |
|
---|
431 | //
|
---|
432 | // Setup a callback for idle events
|
---|
433 | //
|
---|
434 | Status = gBS->CreateEventEx (
|
---|
435 | EVT_NOTIFY_SIGNAL,
|
---|
436 | TPL_NOTIFY,
|
---|
437 | IdleLoopEventCallback,
|
---|
438 | NULL,
|
---|
439 | &gIdleLoopEventGuid,
|
---|
440 | &IdleLoopEvent
|
---|
441 | );
|
---|
442 | ASSERT_EFI_ERROR (Status);
|
---|
443 |
|
---|
444 | return Status;
|
---|
445 | }
|
---|