2 Page table manipulation functions for IA-32 processors
4 Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "PiSmmCpuDxeSmm.h"
20 Create PageTable for SMM use.
22 @return PageTable Address
30 UINTN PageFaultHandlerHookAddress
;
31 IA32_IDT_GATE_DESCRIPTOR
*IdtEntry
;
35 // Initialize spin lock
37 InitializeSpinLock (mPFLock
);
39 mPhysicalAddressBits
= 32;
41 if (FeaturePcdGet (PcdCpuSmmProfileEnable
)) {
43 // Set own Page Fault entry instead of the default one, because SMM Profile
44 // feature depends on IRET instruction to do Single Step
46 PageFaultHandlerHookAddress
= (UINTN
)PageFaultIdtHandlerSmmProfile
;
47 IdtEntry
= (IA32_IDT_GATE_DESCRIPTOR
*) gcSmiIdtr
.Base
;
48 IdtEntry
+= EXCEPT_IA32_PAGE_FAULT
;
49 IdtEntry
->Bits
.OffsetLow
= (UINT16
)PageFaultHandlerHookAddress
;
50 IdtEntry
->Bits
.Reserved_0
= 0;
51 IdtEntry
->Bits
.GateType
= IA32_IDT_GATE_TYPE_INTERRUPT_32
;
52 IdtEntry
->Bits
.OffsetHigh
= (UINT16
)(PageFaultHandlerHookAddress
>> 16);
55 // Register SMM Page Fault Handler
57 Status
= SmmRegisterExceptionHandler (&mSmmCpuService
, EXCEPT_IA32_PAGE_FAULT
, SmiPFHandler
);
58 ASSERT_EFI_ERROR (Status
);
62 // Additional SMM IDT initialization for SMM stack guard
64 if (FeaturePcdGet (PcdCpuSmmStackGuard
)) {
65 InitializeIDTSmmStackGuard ();
67 return Gen4GPageTable (TRUE
);
71 Page Fault handler for SMM use.
83 ThePage Fault handler wrapper for SMM use.
85 @param InterruptType Defines the type of interrupt or exception that
86 occurred on the processor.This parameter is processor architecture specific.
87 @param SystemContext A pointer to the processor context when
88 the interrupt occurred on the processor.
93 IN EFI_EXCEPTION_TYPE InterruptType
,
94 IN EFI_SYSTEM_CONTEXT SystemContext
98 UINTN GuardPageAddress
;
101 ASSERT (InterruptType
== EXCEPT_IA32_PAGE_FAULT
);
103 AcquireSpinLock (mPFLock
);
105 PFAddress
= AsmReadCr2 ();
108 // If a page fault occurs in SMRAM range, it might be in a SMM stack guard page,
109 // or SMM page protection violation.
111 if ((PFAddress
>= mCpuHotPlugData
.SmrrBase
) &&
112 (PFAddress
< (mCpuHotPlugData
.SmrrBase
+ mCpuHotPlugData
.SmrrSize
))) {
113 DumpCpuContext (InterruptType
, SystemContext
);
114 CpuIndex
= GetCpuIndex ();
115 GuardPageAddress
= (mSmmStackArrayBase
+ EFI_PAGE_SIZE
+ CpuIndex
* mSmmStackSize
);
116 if ((FeaturePcdGet (PcdCpuSmmStackGuard
)) &&
117 (PFAddress
>= GuardPageAddress
) &&
118 (PFAddress
< (GuardPageAddress
+ EFI_PAGE_SIZE
))) {
119 DEBUG ((DEBUG_ERROR
, "SMM stack overflow!\n"));
121 if ((SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_ID
) != 0) {
122 DEBUG ((DEBUG_ERROR
, "SMM exception at execution (0x%x)\n", PFAddress
));
124 DumpModuleInfoByIp (*(UINTN
*)(UINTN
)SystemContext
.SystemContextIa32
->Esp
);
127 DEBUG ((DEBUG_ERROR
, "SMM exception at access (0x%x)\n", PFAddress
));
129 DumpModuleInfoByIp ((UINTN
)SystemContext
.SystemContextIa32
->Eip
);
137 // If a page fault occurs in non-SMRAM range.
139 if ((PFAddress
< mCpuHotPlugData
.SmrrBase
) ||
140 (PFAddress
>= mCpuHotPlugData
.SmrrBase
+ mCpuHotPlugData
.SmrrSize
)) {
141 if ((SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_ID
) != 0) {
142 DumpCpuContext (InterruptType
, SystemContext
);
143 DEBUG ((DEBUG_ERROR
, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress
));
145 DumpModuleInfoByIp (*(UINTN
*)(UINTN
)SystemContext
.SystemContextIa32
->Esp
);
149 if (IsSmmCommBufferForbiddenAddress (PFAddress
)) {
150 DumpCpuContext (InterruptType
, SystemContext
);
151 DEBUG ((DEBUG_ERROR
, "Access SMM communication forbidden address (0x%x)!\n", PFAddress
));
153 DumpModuleInfoByIp ((UINTN
)SystemContext
.SystemContextIa32
->Eip
);
160 // If NULL pointer was just accessed
162 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask
) & BIT1
) != 0 &&
163 (PFAddress
< EFI_PAGE_SIZE
)) {
164 DumpCpuContext (InterruptType
, SystemContext
);
165 DEBUG ((DEBUG_ERROR
, "!!! NULL pointer access !!!\n"));
167 DumpModuleInfoByIp ((UINTN
)SystemContext
.SystemContextIa32
->Eip
);
172 if (FeaturePcdGet (PcdCpuSmmProfileEnable
)) {
173 SmmProfilePFHandler (
174 SystemContext
.SystemContextIa32
->Eip
,
175 SystemContext
.SystemContextIa32
->ExceptionData
178 DumpCpuContext (InterruptType
, SystemContext
);
179 SmiDefaultPFHandler ();
182 ReleaseSpinLock (mPFLock
);
186 This function sets memory attribute for page table.
189 SetPageTableAttributes (
199 BOOLEAN PageTableSplitted
;
202 // Don't mark page table to read-only if heap guard is enabled.
204 // BIT2: SMM page guard enabled
205 // BIT3: SMM pool guard enabled
207 if ((PcdGet8 (PcdHeapGuardPropertyMask
) & (BIT3
| BIT2
)) != 0) {
208 DEBUG ((DEBUG_INFO
, "Don't mark page table to read-only as heap guard is enabled\n"));
213 // Don't mark page table to read-only if SMM profile is enabled.
215 if (FeaturePcdGet (PcdCpuSmmProfileEnable
)) {
216 DEBUG ((DEBUG_INFO
, "Don't mark page table to read-only as SMM profile is enabled\n"));
220 DEBUG ((DEBUG_INFO
, "SetPageTableAttributes\n"));
223 // Disable write protection, because we need mark page table to be write protected.
224 // We need *write* page table memory, to mark itself to be *read only*.
226 AsmWriteCr0 (AsmReadCr0() & ~CR0_WP
);
229 DEBUG ((DEBUG_INFO
, "Start...\n"));
230 PageTableSplitted
= FALSE
;
232 L3PageTable
= (UINT64
*)GetPageTableBase ();
234 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS
)(UINTN
)L3PageTable
, SIZE_4KB
, EFI_MEMORY_RO
, &IsSplitted
);
235 PageTableSplitted
= (PageTableSplitted
|| IsSplitted
);
237 for (Index3
= 0; Index3
< 4; Index3
++) {
238 L2PageTable
= (UINT64
*)(UINTN
)(L3PageTable
[Index3
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
239 if (L2PageTable
== NULL
) {
243 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS
)(UINTN
)L2PageTable
, SIZE_4KB
, EFI_MEMORY_RO
, &IsSplitted
);
244 PageTableSplitted
= (PageTableSplitted
|| IsSplitted
);
246 for (Index2
= 0; Index2
< SIZE_4KB
/sizeof(UINT64
); Index2
++) {
247 if ((L2PageTable
[Index2
] & IA32_PG_PS
) != 0) {
251 L1PageTable
= (UINT64
*)(UINTN
)(L2PageTable
[Index2
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
252 if (L1PageTable
== NULL
) {
255 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS
)(UINTN
)L1PageTable
, SIZE_4KB
, EFI_MEMORY_RO
, &IsSplitted
);
256 PageTableSplitted
= (PageTableSplitted
|| IsSplitted
);
259 } while (PageTableSplitted
);
262 // Enable write protection, after page table updated.
264 AsmWriteCr0 (AsmReadCr0() | CR0_WP
);