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