]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/X64/SetIdtEntry.c
2d15f5b5d122ab72dfa4e3f4b2cabd16ecbc7988
[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 BOOLEAN mPage1GSupport;
25 VOID *mOriginalHandler;
26 UINTN mS3NvsPageTableAddress;
27
28 /**
29 Page fault handler.
30
31 **/
32 VOID
33 EFIAPI
34 PageFaultHandlerHook (
35 VOID
36 );
37
38 /**
39 Hook IDT with our page fault handler so that the on-demand paging works on page fault.
40
41 @param IdtEntry a pointer to IDT entry
42
43 **/
44 VOID
45 HookPageFaultHandler (
46 IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
47 )
48 {
49 UINT32 RegEax;
50 UINT32 RegEdx;
51 UINTN PageFaultHandlerHookAddress;
52
53 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
54 mPhyMask = LShiftU64 (1, (UINT8)RegEax) - 1;
55 mPhyMask &= (1ull << 48) - SIZE_4KB;
56
57 mPage1GSupport = FALSE;
58 if (PcdGetBool(PcdUse1GPageTable)) {
59 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
60 if (RegEax >= 0x80000001) {
61 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
62 if ((RegEdx & BIT26) != 0) {
63 mPage1GSupport = TRUE;
64 }
65 }
66 }
67
68 //
69 // Set Page Fault entry to catch >4G access
70 //
71 PageFaultHandlerHookAddress = (UINTN)PageFaultHandlerHook;
72 mOriginalHandler = (VOID *)(UINTN)(LShiftU64 (IdtEntry->Bits.OffsetUpper, 32) + IdtEntry->Bits.OffsetLow + (IdtEntry->Bits.OffsetHigh << 16));
73 IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;
74 IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
75 IdtEntry->Bits.Reserved_0 = 0;
76 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
77 IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);
78 IdtEntry->Bits.OffsetUpper = (UINT32)(PageFaultHandlerHookAddress >> 32);
79 IdtEntry->Bits.Reserved_1 = 0;
80
81 if (mPage1GSupport) {
82 mS3NvsPageTableAddress = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(2);
83 }else {
84 mS3NvsPageTableAddress = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(6);
85 }
86 }
87
88 /**
89 Set a IDT entry for interrupt vector 3 for debug purpose.
90
91 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
92
93 **/
94 VOID
95 SetIdtEntry (
96 IN ACPI_S3_CONTEXT *AcpiS3Context
97 )
98 {
99 IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
100 IA32_DESCRIPTOR *IdtDescriptor;
101 UINTN S3DebugBuffer;
102 EFI_STATUS Status;
103
104 //
105 // Restore IDT for debug
106 //
107 IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile);
108 AsmWriteIdtr (IdtDescriptor);
109
110 //
111 // Setup the default CPU exception handlers
112 //
113 Status = InitializeCpuExceptionHandlers (NULL);
114 ASSERT_EFI_ERROR (Status);
115
116 DEBUG_CODE (
117 //
118 // Update IDT entry INT3 if the instruction is valid in it
119 //
120 S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress);
121 if (*(UINTN *)S3DebugBuffer != (UINTN) -1) {
122 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (3 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
123 IdtEntry->Bits.OffsetLow = (UINT16)S3DebugBuffer;
124 IdtEntry->Bits.Selector = (UINT16)AsmReadCs ();
125 IdtEntry->Bits.Reserved_0 = 0;
126 IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
127 IdtEntry->Bits.OffsetHigh = (UINT16)(S3DebugBuffer >> 16);
128 IdtEntry->Bits.OffsetUpper = (UINT32)(S3DebugBuffer >> 32);
129 IdtEntry->Bits.Reserved_1 = 0;
130 }
131 );
132
133 IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (14 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
134 HookPageFaultHandler (IdtEntry);
135 }
136
137 /**
138 Get new page address.
139
140 @param PageNum new page number needed
141
142 @return new page address
143 **/
144 UINTN
145 GetNewPage (
146 IN UINTN PageNum
147 )
148 {
149 UINTN NewPage;
150 NewPage = mS3NvsPageTableAddress;
151 ZeroMem ((VOID *)NewPage, EFI_PAGES_TO_SIZE(PageNum));
152 mS3NvsPageTableAddress += EFI_PAGES_TO_SIZE(PageNum);
153 return NewPage;
154 }
155
156 /**
157 The page fault handler that on-demand read >4G memory/MMIO.
158
159 @retval TRUE The page fault is correctly handled.
160 @retval FALSE The page fault is not handled and is passed through to original handler.
161
162 **/
163 BOOLEAN
164 EFIAPI
165 PageFaultHandler (
166 VOID
167 )
168 {
169 UINT64 *PageTable;
170 UINT64 PFAddress;
171 UINTN PTIndex;
172
173 PFAddress = AsmReadCr2 ();
174 DEBUG ((EFI_D_ERROR, "BootScript - PageFaultHandler: Cr2 - %lx\n", PFAddress));
175
176 if (PFAddress >= mPhyMask + SIZE_4KB) {
177 return FALSE;
178 }
179 PFAddress &= mPhyMask;
180
181 PageTable = (UINT64*)(UINTN)(AsmReadCr3 () & mPhyMask);
182
183 PTIndex = BitFieldRead64 (PFAddress, 39, 47);
184 // PML4E
185 if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
186 PageTable[PTIndex] = GetNewPage (1) | IA32_PG_P | IA32_PG_RW;
187 }
188 PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & mPhyMask);
189 PTIndex = BitFieldRead64 (PFAddress, 30, 38);
190 // PDPTE
191 if (mPage1GSupport) {
192 PageTable[PTIndex] = PFAddress | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
193 } else {
194 if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
195 PageTable[PTIndex] = GetNewPage (1) | IA32_PG_P | IA32_PG_RW;
196 }
197 PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & mPhyMask);
198 PTIndex = BitFieldRead64 (PFAddress, 21, 29);
199 // PD
200 PageTable[PTIndex] = PFAddress | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
201 }
202
203 return TRUE;
204 }