]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c
MdeModulePkg BootScriptExecutorDxe: Fix S3 failure When PcdUse1GPageTable defined...
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / BootScriptExecutorDxe / X64 / SetIdtEntry.c
1 /** @file
2 Set a IDT entry for debug purpose
3
4 Set a IDT entry for interrupt vector 3 for debug purpose for x64 platform
5
6 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
7
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17 #include "ScriptExecute.h"
18
19 #define IA32_PG_P BIT0
20 #define IA32_PG_RW BIT1
21 #define IA32_PG_PS BIT7
22
23 UINT64 mPhyMask;
24 VOID *mOriginalHandler;
25 UINTN mS3NvsPageTableAddress;
26
27 /**
28 Page fault handler.
29
30 **/
31 VOID
32 EFIAPI
33 PageFaultHandlerHook (
34 VOID
35 );
36
37 /**
38 Hook IDT with our page fault handler so that the on-demand paging works on page fault.
39
40 @param IdtEntry a pointer to IDT entry
41
42 **/
43 VOID
44 HookPageFaultHandler (
45 IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
46 )
47 {
48 UINT32 RegEax;
49 UINT8 PhysicalAddressBits;
50 UINTN PageFaultHandlerHookAddress;
51
52 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
53 if (RegEax >= 0x80000008) {
54 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
55 PhysicalAddressBits = (UINT8) RegEax;
56 } else {
57 PhysicalAddressBits = 36;
58 }
59 mPhyMask = LShiftU64 (1, PhysicalAddressBits) - 1;
60 mPhyMask &= (1ull << 48) - SIZE_4KB;
61
62 //
63 // Set Page Fault entry to catch >4G access
64 //
65 PageFaultHandlerHookAddress = (UINTN)PageFaultHandlerHook;
66 mOriginalHandler = (VOID *)(UINTN)(LShiftU64 (IdtEntry->Bits.OffsetUpper, 32) + IdtEntry->Bits.OffsetLow + (IdtEntry->Bits.OffsetHigh << 16));
67 IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;
68 IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
69 IdtEntry->Bits.Reserved_0 = 0;
70 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
71 IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);
72 IdtEntry->Bits.OffsetUpper = (UINT32)(PageFaultHandlerHookAddress >> 32);
73 IdtEntry->Bits.Reserved_1 = 0;
74
75 if (mPage1GSupport) {
76 mS3NvsPageTableAddress = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(2);
77 }else {
78 mS3NvsPageTableAddress = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(6);
79 }
80 }
81
82 /**
83 Set a IDT entry for interrupt vector 3 for debug purpose.
84
85 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
86
87 **/
88 VOID
89 SetIdtEntry (
90 IN ACPI_S3_CONTEXT *AcpiS3Context
91 )
92 {
93 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
94 IA32_DESCRIPTOR *IdtDescriptor;
95 UINTN S3DebugBuffer;
96 EFI_STATUS Status;
97
98 //
99 // Restore IDT for debug
100 //
101 IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile);
102 AsmWriteIdtr (IdtDescriptor);
103
104 //
105 // Setup the default CPU exception handlers
106 //
107 Status = InitializeCpuExceptionHandlers (NULL);
108 ASSERT_EFI_ERROR (Status);
109
110 DEBUG_CODE (
111 //
112 // Update IDT entry INT3 if the instruction is valid in it
113 //
114 S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress);
115 if (*(UINTN *)S3DebugBuffer != (UINTN) -1) {
116 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (3 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
117 IdtEntry->Bits.OffsetLow = (UINT16)S3DebugBuffer;
118 IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
119 IdtEntry->Bits.Reserved_0 = 0;
120 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
121 IdtEntry->Bits.OffsetHigh = (UINT16)(S3DebugBuffer >> 16);
122 IdtEntry->Bits.OffsetUpper = (UINT32)(S3DebugBuffer >> 32);
123 IdtEntry->Bits.Reserved_1 = 0;
124 }
125 );
126
127 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (14 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
128 HookPageFaultHandler (IdtEntry);
129 }
130
131 /**
132 Get new page address.
133
134 @param PageNum new page number needed
135
136 @return new page address
137 **/
138 UINTN
139 GetNewPage (
140 IN UINTN PageNum
141 )
142 {
143 UINTN NewPage;
144 NewPage = mS3NvsPageTableAddress;
145 ZeroMem ((VOID *)NewPage, EFI_PAGES_TO_SIZE(PageNum));
146 mS3NvsPageTableAddress += EFI_PAGES_TO_SIZE(PageNum);
147 return NewPage;
148 }
149
150 /**
151 The page fault handler that on-demand read >4G memory/MMIO.
152
153 @retval TRUE The page fault is correctly handled.
154 @retval FALSE The page fault is not handled and is passed through to original handler.
155
156 **/
157 BOOLEAN
158 EFIAPI
159 PageFaultHandler (
160 VOID
161 )
162 {
163 UINT64 *PageTable;
164 UINT64 PFAddress;
165 UINTN PTIndex;
166
167 PFAddress = AsmReadCr2 ();
168 DEBUG ((EFI_D_ERROR, "BootScript - PageFaultHandler: Cr2 - %lx\n", PFAddress));
169
170 if (PFAddress >= mPhyMask + SIZE_4KB) {
171 return FALSE;
172 }
173 PFAddress &= mPhyMask;
174
175 PageTable = (UINT64*)(UINTN)(AsmReadCr3 () & mPhyMask);
176
177 PTIndex = BitFieldRead64 (PFAddress, 39, 47);
178 // PML4E
179 if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
180 PageTable[PTIndex] = GetNewPage (1) | IA32_PG_P | IA32_PG_RW;
181 }
182 PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & mPhyMask);
183 PTIndex = BitFieldRead64 (PFAddress, 30, 38);
184 // PDPTE
185 if (mPage1GSupport) {
186 PageTable[PTIndex] = PFAddress | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
187 } else {
188 if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
189 PageTable[PTIndex] = GetNewPage (1) | IA32_PG_P | IA32_PG_RW;
190 }
191 PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & mPhyMask);
192 PTIndex = BitFieldRead64 (PFAddress, 21, 29);
193 // PD
194 PageTable[PTIndex] = PFAddress | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
195 }
196
197 return TRUE;
198 }