]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
UefiCpuPkg/PiSmmCpuDxeSmm: Add support for PCD PcdPteMemoryEncryptionAddressOrMask
[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 Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
6
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
11
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.
14
15 **/
16
17 #include "PiSmmCpuDxeSmm.h"
18
19 /**
20 Create PageTable for SMM use.
21
22 @return PageTable Address
23
24 **/
25 UINT32
26 SmmInitPageTable (
27 VOID
28 )
29 {
30 UINTN PageFaultHandlerHookAddress;
31 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
32 EFI_STATUS Status;
33
34 //
35 // Initialize spin lock
36 //
37 InitializeSpinLock (mPFLock);
38
39 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
40 //
41 // Set own Page Fault entry instead of the default one, because SMM Profile
42 // feature depends on IRET instruction to do Single Step
43 //
44 PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile;
45 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) gcSmiIdtr.Base;
46 IdtEntry += EXCEPT_IA32_PAGE_FAULT;
47 IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;
48 IdtEntry->Bits.Reserved_0 = 0;
49 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
50 IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);
51 } else {
52 //
53 // Register SMM Page Fault Handler
54 //
55 Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);
56 ASSERT_EFI_ERROR (Status);
57 }
58
59 //
60 // Additional SMM IDT initialization for SMM stack guard
61 //
62 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
63 InitializeIDTSmmStackGuard ();
64 }
65 return Gen4GPageTable (TRUE);
66 }
67
68 /**
69 Page Fault handler for SMM use.
70
71 **/
72 VOID
73 SmiDefaultPFHandler (
74 VOID
75 )
76 {
77 CpuDeadLoop ();
78 }
79
80 /**
81 ThePage Fault handler wrapper for SMM use.
82
83 @param InterruptType Defines the type of interrupt or exception that
84 occurred on the processor.This parameter is processor architecture specific.
85 @param SystemContext A pointer to the processor context when
86 the interrupt occurred on the processor.
87 **/
88 VOID
89 EFIAPI
90 SmiPFHandler (
91 IN EFI_EXCEPTION_TYPE InterruptType,
92 IN EFI_SYSTEM_CONTEXT SystemContext
93 )
94 {
95 UINTN PFAddress;
96 UINTN GuardPageAddress;
97 UINTN CpuIndex;
98
99 ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);
100
101 AcquireSpinLock (mPFLock);
102
103 PFAddress = AsmReadCr2 ();
104
105 //
106 // If a page fault occurs in SMRAM range, it might be in a SMM stack guard page,
107 // or SMM page protection violation.
108 //
109 if ((PFAddress >= mCpuHotPlugData.SmrrBase) &&
110 (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {
111 CpuIndex = GetCpuIndex ();
112 GuardPageAddress = (mSmmStackArrayBase + EFI_PAGE_SIZE + CpuIndex * mSmmStackSize);
113 if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&
114 (PFAddress >= GuardPageAddress) &&
115 (PFAddress < (GuardPageAddress + EFI_PAGE_SIZE))) {
116 DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n"));
117 } else {
118 DEBUG ((DEBUG_ERROR, "SMM exception data - 0x%x(", SystemContext.SystemContextIa32->ExceptionData));
119 DEBUG ((DEBUG_ERROR, "I:%x, R:%x, U:%x, W:%x, P:%x",
120 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0,
121 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_RSVD) != 0,
122 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_US) != 0,
123 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_WR) != 0,
124 (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_P) != 0
125 ));
126 DEBUG ((DEBUG_ERROR, ")\n"));
127 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {
128 DEBUG ((DEBUG_ERROR, "SMM exception at execution (0x%x)\n", PFAddress));
129 DEBUG_CODE (
130 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
131 );
132 } else {
133 DEBUG ((DEBUG_ERROR, "SMM exception at access (0x%x)\n", PFAddress));
134 DEBUG_CODE (
135 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
136 );
137 }
138 }
139 CpuDeadLoop ();
140 }
141
142 //
143 // If a page fault occurs in SMM range
144 //
145 if ((PFAddress < mCpuHotPlugData.SmrrBase) ||
146 (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {
147 if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {
148 DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));
149 DEBUG_CODE (
150 DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
151 );
152 CpuDeadLoop ();
153 }
154 if (IsSmmCommBufferForbiddenAddress (PFAddress)) {
155 DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%x)!\n", PFAddress));
156 DEBUG_CODE (
157 DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
158 );
159 CpuDeadLoop ();
160 }
161 }
162
163 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
164 SmmProfilePFHandler (
165 SystemContext.SystemContextIa32->Eip,
166 SystemContext.SystemContextIa32->ExceptionData
167 );
168 } else {
169 SmiDefaultPFHandler ();
170 }
171
172 ReleaseSpinLock (mPFLock);
173 }
174
175 /**
176 This function sets memory attribute for page table.
177 **/
178 VOID
179 SetPageTableAttributes (
180 VOID
181 )
182 {
183 UINTN Index2;
184 UINTN Index3;
185 UINT64 *L1PageTable;
186 UINT64 *L2PageTable;
187 UINT64 *L3PageTable;
188 BOOLEAN IsSplitted;
189 BOOLEAN PageTableSplitted;
190
191 DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n"));
192
193 //
194 // Disable write protection, because we need mark page table to be write protected.
195 // We need *write* page table memory, to mark itself to be *read only*.
196 //
197 AsmWriteCr0 (AsmReadCr0() & ~CR0_WP);
198
199 do {
200 DEBUG ((DEBUG_INFO, "Start...\n"));
201 PageTableSplitted = FALSE;
202
203 L3PageTable = (UINT64 *)GetPageTableBase ();
204
205 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
206 PageTableSplitted = (PageTableSplitted || IsSplitted);
207
208 for (Index3 = 0; Index3 < 4; Index3++) {
209 L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
210 if (L2PageTable == NULL) {
211 continue;
212 }
213
214 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
215 PageTableSplitted = (PageTableSplitted || IsSplitted);
216
217 for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) {
218 if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
219 // 2M
220 continue;
221 }
222 L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
223 if (L1PageTable == NULL) {
224 continue;
225 }
226 SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted);
227 PageTableSplitted = (PageTableSplitted || IsSplitted);
228 }
229 }
230 } while (PageTableSplitted);
231
232 //
233 // Enable write protection, after page table updated.
234 //
235 AsmWriteCr0 (AsmReadCr0() | CR0_WP);
236
237 return ;
238 }