]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
UefiCpuPkg/SmmCpuFeaturesLibStm: Add STM library instance
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / Ia32 / PageTbl.c
1 /** @file
2 Page table manipulation functions for IA-32 processors
3
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
9
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.
12
13 **/
14
15 #include "PiSmmCpuDxeSmm.h"
16
17 /**
18 Create PageTable for SMM use.
19
20 @return PageTable Address
21
22 **/
23 UINT32
24 SmmInitPageTable (
25 VOID
26 )
27 {
28 UINTN PageFaultHandlerHookAddress;
29 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
30 EFI_STATUS Status;
31
32 //
33 // Initialize spin lock
34 //
35 InitializeSpinLock (mPFLock);
36
37 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
38 //
39 // Set own Page Fault entry instead of the default one, because SMM Profile
40 // feature depends on IRET instruction to do Single Step
41 //
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);
49 } else {
50 //
51 // Register SMM Page Fault Handler
52 //
53 Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);
54 ASSERT_EFI_ERROR (Status);
55 }
56
57 //
58 // Additional SMM IDT initialization for SMM stack guard
59 //
60 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
61 InitializeIDTSmmStackGuard ();
62 }
63 return Gen4GPageTable (TRUE);
64 }
65
66 /**
67 Page Fault handler for SMM use.
68
69 **/
70 VOID
71 SmiDefaultPFHandler (
72 VOID
73 )
74 {
75 CpuDeadLoop ();
76 }
77
78 /**
79 ThePage Fault handler wrapper for SMM use.
80
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.
85 **/
86 VOID
87 EFIAPI
88 SmiPFHandler (
89 IN EFI_EXCEPTION_TYPE InterruptType,
90 IN EFI_SYSTEM_CONTEXT SystemContext
91 )
92 {
93 UINTN PFAddress;
94 UINTN GuardPageAddress;
95 UINTN CpuIndex;
96
97 ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);
98
99 AcquireSpinLock (mPFLock);
100
101 PFAddress = AsmReadCr2 ();
102
103 //
104 // If a page fault occurs in SMRAM range, it might be in a SMM stack guard page,
105 // or SMM page protection violation.
106 //
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"));
115 } else {
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
123 ));
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));
127 DEBUG_CODE (
128 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
129 );
130 } else {
131 DEBUG ((DEBUG_ERROR, "SMM exception at access (0x%x)\n", PFAddress));
132 DEBUG_CODE (
133 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
134 );
135 }
136 }
137 CpuDeadLoop ();
138 }
139
140 //
141 // If a page fault occurs in SMM range
142 //
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));
147 DEBUG_CODE (
148 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
149 );
150 CpuDeadLoop ();
151 }
152 }
153
154 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
155 SmmProfilePFHandler (
156 SystemContext.SystemContextIa32->Eip,
157 SystemContext.SystemContextIa32->ExceptionData
158 );
159 } else {
160 SmiDefaultPFHandler ();
161 }
162
163 ReleaseSpinLock (mPFLock);
164 }
165
166 /**
167 This function sets memory attribute for page table.
168 **/
169 VOID
170 SetPageTableAttributes (
171 VOID
172 )
173 {
174 UINTN Index2;
175 UINTN Index3;
176 UINT64 *L1PageTable;
177 UINT64 *L2PageTable;
178 UINT64 *L3PageTable;
179 BOOLEAN IsSplitted;
180 BOOLEAN PageTableSplitted;
181
182 DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));
183
184 //
185 // Disable write protection, because we need mark page table to be write protected.
186 // We need *write* page table memory, to mark itself to be *read only*.
187 //
188 AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);
189
190 do {
191 DEBUG ((DEBUG_INFO, "Start...\n"));
192 PageTableSplitted = FALSE;
193
194 L3PageTable = (UINT64 *)GetPageTableBase ();
195
196 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
197 PageTableSplitted = (PageTableSplitted || IsSplitted);
198
199 for (Index3 = 0; Index3 < 4; Index3++) {
200 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);
201 if (L2PageTable == NULL) {
202 continue;
203 }
204
205 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
206 PageTableSplitted = (PageTableSplitted || IsSplitted);
207
208 for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {
209 if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
210 // 2M
211 continue;
212 }
213 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);
214 if (L1PageTable == NULL) {
215 continue;
216 }
217 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
218 PageTableSplitted = (PageTableSplitted || IsSplitted);
219 }
220 }
221 } while (PageTableSplitted);
222
223 //
224 // Enable write protection, after page table updated.
225 //
226 AsmWriteCr0 (AsmReadCr0() | CR0_WP);
227
228 return ;
229 }