2 Page table manipulation functions for IA-32 processors
4 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "PiSmmCpuDxeSmm.h"
18 Create PageTable for SMM use.
20 @return PageTable Address
28 UINTN PageFaultHandlerHookAddress
;
29 IA32_IDT_GATE_DESCRIPTOR
*IdtEntry
;
33 // Initialize spin lock
35 InitializeSpinLock (mPFLock
);
37 if (FeaturePcdGet (PcdCpuSmmProfileEnable
)) {
39 // Set own Page Fault entry instead of the default one, because SMM Profile
40 // feature depends on IRET instruction to do Single Step
42 PageFaultHandlerHookAddress
= (UINTN
)PageFaultIdtHandlerSmmProfile
;
43 IdtEntry
= (IA32_IDT_GATE_DESCRIPTOR
*) gcSmiIdtr
.Base
;
44 IdtEntry
+= EXCEPT_IA32_PAGE_FAULT
;
45 IdtEntry
->Bits
.OffsetLow
= (UINT16
)PageFaultHandlerHookAddress
;
46 IdtEntry
->Bits
.Reserved_0
= 0;
47 IdtEntry
->Bits
.GateType
= IA32_IDT_GATE_TYPE_INTERRUPT_32
;
48 IdtEntry
->Bits
.OffsetHigh
= (UINT16
)(PageFaultHandlerHookAddress
>> 16);
51 // Register SMM Page Fault Handler
53 Status
= SmmRegisterExceptionHandler (&mSmmCpuService
, EXCEPT_IA32_PAGE_FAULT
, SmiPFHandler
);
54 ASSERT_EFI_ERROR (Status
);
58 // Additional SMM IDT initialization for SMM stack guard
60 if (FeaturePcdGet (PcdCpuSmmStackGuard
)) {
61 InitializeIDTSmmStackGuard ();
63 return Gen4GPageTable (TRUE
);
67 Page Fault handler for SMM use.
79 ThePage Fault handler wrapper for SMM use.
81 @param InterruptType Defines the type of interrupt or exception that
82 occurred on the processor.This parameter is processor architecture specific.
83 @param SystemContext A pointer to the processor context when
84 the interrupt occurred on the processor.
89 IN EFI_EXCEPTION_TYPE InterruptType
,
90 IN EFI_SYSTEM_CONTEXT SystemContext
94 UINTN GuardPageAddress
;
97 ASSERT (InterruptType
== EXCEPT_IA32_PAGE_FAULT
);
99 AcquireSpinLock (mPFLock
);
101 PFAddress
= AsmReadCr2 ();
104 // If a page fault occurs in SMRAM range, it might be in a SMM stack guard page,
105 // or SMM page protection violation.
107 if ((PFAddress
>= mCpuHotPlugData
.SmrrBase
) &&
108 (PFAddress
< (mCpuHotPlugData
.SmrrBase
+ mCpuHotPlugData
.SmrrSize
))) {
109 CpuIndex
= GetCpuIndex ();
110 GuardPageAddress
= (mSmmStackArrayBase
+ EFI_PAGE_SIZE
+ CpuIndex
* mSmmStackSize
);
111 if ((FeaturePcdGet (PcdCpuSmmStackGuard
)) &&
112 (PFAddress
>= GuardPageAddress
) &&
113 (PFAddress
< (GuardPageAddress
+ EFI_PAGE_SIZE
))) {
114 DEBUG ((DEBUG_ERROR
, "SMM stack overflow!\n"));
116 DEBUG ((DEBUG_ERROR
, "SMM exception data - 0x%x(", SystemContext
.SystemContextIa32
->ExceptionData
));
117 DEBUG ((DEBUG_ERROR
, "I:%x, R:%x, U:%x, W:%x, P:%x",
118 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_ID
) != 0,
119 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_RSVD
) != 0,
120 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_US
) != 0,
121 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_WR
) != 0,
122 (SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_P
) != 0
124 DEBUG ((DEBUG_ERROR
, ")\n"));
125 if ((SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_ID
) != 0) {
126 DEBUG ((DEBUG_ERROR
, "SMM exception at execution (0x%x)\n", PFAddress
));
128 DumpModuleInfoByIp (*(UINTN
*)(UINTN
)SystemContext
.SystemContextIa32
->Esp
);
131 DEBUG ((DEBUG_ERROR
, "SMM exception at access (0x%x)\n", PFAddress
));
133 DumpModuleInfoByIp ((UINTN
)SystemContext
.SystemContextIa32
->Eip
);
141 // If a page fault occurs in SMM range
143 if ((PFAddress
< mCpuHotPlugData
.SmrrBase
) ||
144 (PFAddress
>= mCpuHotPlugData
.SmrrBase
+ mCpuHotPlugData
.SmrrSize
)) {
145 if ((SystemContext
.SystemContextIa32
->ExceptionData
& IA32_PF_EC_ID
) != 0) {
146 DEBUG ((DEBUG_ERROR
, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress
));
148 DumpModuleInfoByIp (*(UINTN
*)(UINTN
)SystemContext
.SystemContextIa32
->Esp
);
152 if (IsSmmCommBufferForbiddenAddress (PFAddress
)) {
153 DEBUG ((DEBUG_ERROR
, "Access SMM communication forbidden address (0x%x)!\n", PFAddress
));
155 DumpModuleInfoByIp ((UINTN
)SystemContext
.SystemContextIa32
->Eip
);
161 if (FeaturePcdGet (PcdCpuSmmProfileEnable
)) {
162 SmmProfilePFHandler (
163 SystemContext
.SystemContextIa32
->Eip
,
164 SystemContext
.SystemContextIa32
->ExceptionData
167 SmiDefaultPFHandler ();
170 ReleaseSpinLock (mPFLock
);
174 This function sets memory attribute for page table.
177 SetPageTableAttributes (
187 BOOLEAN PageTableSplitted
;
189 DEBUG ((DEBUG_INFO
, "SetPageTableAttributes\n"));
192 // Disable write protection, because we need mark page table to be write protected.
193 // We need *write* page table memory, to mark itself to be *read only*.
195 AsmWriteCr0 (AsmReadCr0() & ~CR0_WP
);
198 DEBUG ((DEBUG_INFO
, "Start...\n"));
199 PageTableSplitted
= FALSE
;
201 L3PageTable
= (UINT64
*)GetPageTableBase ();
203 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS
)(UINTN
)L3PageTable
, SIZE_4KB
, EFI_MEMORY_RO
, &IsSplitted
);
204 PageTableSplitted
= (PageTableSplitted
|| IsSplitted
);
206 for (Index3
= 0; Index3
< 4; Index3
++) {
207 L2PageTable
= (UINT64
*)(UINTN
)(L3PageTable
[Index3
] & PAGING_4K_ADDRESS_MASK_64
);
208 if (L2PageTable
== NULL
) {
212 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS
)(UINTN
)L2PageTable
, SIZE_4KB
, EFI_MEMORY_RO
, &IsSplitted
);
213 PageTableSplitted
= (PageTableSplitted
|| IsSplitted
);
215 for (Index2
= 0; Index2
< SIZE_4KB
/sizeof(UINT64
); Index2
++) {
216 if ((L2PageTable
[Index2
] & IA32_PG_PS
) != 0) {
220 L1PageTable
= (UINT64
*)(UINTN
)(L2PageTable
[Index2
] & PAGING_4K_ADDRESS_MASK_64
);
221 if (L1PageTable
== NULL
) {
224 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS
)(UINTN
)L1PageTable
, SIZE_4KB
, EFI_MEMORY_RO
, &IsSplitted
);
225 PageTableSplitted
= (PageTableSplitted
|| IsSplitted
);
228 } while (PageTableSplitted
);
231 // Enable write protection, after page table updated.
233 AsmWriteCr0 (AsmReadCr0() | CR0_WP
);