NMI Support Patch 1:
[reactos.git] / reactos / hal / halx86 / generic / bios.c
1 /*
2 * PROJECT: ReactOS Hardware Abstraction Layer (HAL)
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: halx86/generic/bios.c
5 * PURPOSE: BIOS Access Routines
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 ULONG HalpSavedPfn;
18 HARDWARE_PTE HalpSavedPte;
19 ULONG HalpGpfHandler;
20 ULONG HalpBopHandler;
21 ULONG HalpSavedEsp0;
22 USHORT HalpSavedIopmBase;
23 PUSHORT HalpSavedIoMap;
24 USHORT HalpSavedIoMapData[32][2];
25 ULONG HalpSavedIoMapEntries;
26
27 #define GetPdeAddress(x) (PHARDWARE_PTE)(((((ULONG_PTR)(x)) >> 22) << 2) + 0xC0300000)
28 #define GetPteAddress(x) (PHARDWARE_PTE)(((((ULONG_PTR)(x)) >> 12) << 2) + 0xC0000000)
29
30 /* FUNCTIONS ******************************************************************/
31
32 VOID
33 NTAPI
34 HalpStoreAndClearIopm(VOID)
35 {
36 ULONG i, j;
37 PUSHORT Entry = HalpSavedIoMap;
38
39 //
40 // Loop the I/O Map
41 //
42 for (i = j = 0; i < (IOPM_SIZE) / 2; i++)
43 {
44 //
45 // Check for non-FFFF entry
46 //
47 if (*Entry != 0xFFFF)
48 {
49 //
50 // Save it
51 //
52 ASSERT(j < 32);
53 HalpSavedIoMapData[j][0] = i;
54 HalpSavedIoMapData[j][1] = *Entry;
55 }
56
57 //
58 // Clear it
59 //
60 *Entry++ = 0;
61 }
62
63 //
64 // Terminate it
65 //
66 while (i++ < (IOPM_FULL_SIZE / 2)) *Entry++ = 0xFFFF;
67
68 //
69 // Return the entries we saved
70 //
71 HalpSavedIoMapEntries = j;
72 }
73
74 VOID
75 NTAPI
76 HalpRestoreIopm(VOID)
77 {
78 ULONG i = HalpSavedIoMapEntries;
79
80 //
81 // Set default state
82 //
83 RtlFillMemory(HalpSavedIoMap, 0xFF, IOPM_FULL_SIZE);
84
85 //
86 // Restore the backed up copy, and initialize it
87 //
88 while (i--) HalpSavedIoMap[HalpSavedIoMapData[i][0]] = HalpSavedIoMapData[i][1];
89 }
90
91 VOID
92 NTAPI
93 HalpMapRealModeMemory(VOID)
94 {
95 PHARDWARE_PTE Pte, V86Pte;
96 ULONG i;
97
98 /* Get the page table directory for the lowest meg of memory */
99 Pte = GetPdeAddress(0);
100 HalpSavedPfn = Pte->PageFrameNumber;
101 HalpSavedPte = *Pte;
102
103 /* Map it to the HAL reserved region and make it valid */
104 Pte->Valid = 1;
105 Pte->Write = 1;
106 Pte->Owner = 1;
107 Pte->PageFrameNumber = (GetPdeAddress(0xFFC00000))->PageFrameNumber;
108
109 /* Flush the TLB by resetting CR3 */
110 __writecr3(__readcr3());
111
112 /* Now loop the first meg of memory */
113 for (i = 0; i < 0x100000; i += PAGE_SIZE)
114 {
115 /* Identity map it */
116 Pte = GetPteAddress((PVOID)i);
117 Pte->PageFrameNumber = i >> PAGE_SHIFT;
118 Pte->Valid = 1;
119 Pte->Write = 1;
120 Pte->Owner = 1;
121 }
122
123 /* Now get the entry for our real mode V86 code and the target */
124 Pte = GetPteAddress(0x20000);
125 V86Pte = GetPteAddress(&HalpRealModeStart);
126 do
127 {
128 /* Map the physical address into our real-mode region */
129 Pte->PageFrameNumber = V86Pte->PageFrameNumber;
130
131 /* Keep going until we've reached the end of our region */
132 Pte++;
133 V86Pte++;
134 } while (V86Pte <= GetPteAddress(&HalpRealModeEnd));
135
136 /* Flush the TLB by resetting CR3 */
137 __writecr3(__readcr3());
138 }
139
140 VOID
141 NTAPI
142 HalpSwitchToRealModeTrapHandlers(VOID)
143 {
144 ULONG Handler;
145
146 /* Save the current Invalid Opcode and General Protection Fault Handlers */
147 HalpGpfHandler = ((((PKIPCR)KeGetPcr())->IDT[13].ExtendedOffset << 16) &
148 0xFFFF0000) |
149 (((PKIPCR)KeGetPcr())->IDT[13].Offset & 0xFFFF);
150 HalpBopHandler = ((((PKIPCR)KeGetPcr())->IDT[6].ExtendedOffset << 16) &
151 0xFFFF0000) |
152 (((PKIPCR)KeGetPcr())->IDT[6].Offset & 0xFFFF);
153
154 /* Now set our own GPF handler to handle exceptions while in real mode */
155 Handler = (ULONG_PTR)HalpTrap0D;
156 ((PKIPCR)KeGetPcr())->IDT[13].ExtendedOffset =
157 (USHORT)((Handler >> 16) & 0xFFFF);
158 ((PKIPCR)KeGetPcr())->IDT[13].Offset = (USHORT)Handler;
159
160 /* And our own invalid opcode handler to detect the BOP to get us out */
161 Handler = (ULONG_PTR)HalpTrap06;
162 ((PKIPCR)KeGetPcr())->IDT[6].ExtendedOffset =
163 (USHORT)((Handler >> 16) & 0xFFFF);
164 ((PKIPCR)KeGetPcr())->IDT[6].Offset = (USHORT)Handler;
165 }
166
167 VOID
168 NTAPI
169 HalpSetupRealModeIoPermissionsAndTask(VOID)
170 {
171 /* Save a copy of the I/O Map and delete it */
172 HalpSavedIoMap = (PUSHORT)&(KeGetPcr()->TSS->IoMaps[0]);
173 HalpStoreAndClearIopm();
174
175 /* Save the IOPM and switch to the real-mode one */
176 HalpSavedIopmBase = KeGetPcr()->TSS->IoMapBase;
177 KeGetPcr()->TSS->IoMapBase = KiComputeIopmOffset(1);
178
179 /* Save our stack pointer */
180 HalpSavedEsp0 = KeGetPcr()->TSS->Esp0;
181 }
182
183 VOID
184 NTAPI
185 HalpRestoreTrapHandlers(VOID)
186 {
187 /* We're back, restore the handlers we over-wrote */
188 ((PKIPCR)KeGetPcr())->IDT[13].ExtendedOffset =
189 (USHORT)((HalpGpfHandler >> 16) & 0xFFFF);
190 ((PKIPCR)KeGetPcr())->IDT[13].Offset = (USHORT)HalpGpfHandler;
191 ((PKIPCR)KeGetPcr())->IDT[6].ExtendedOffset =
192 (USHORT)((HalpBopHandler >> 16) & 0xFFFF);
193 ((PKIPCR)KeGetPcr())->IDT[6].Offset = (USHORT)HalpBopHandler;
194 }
195
196 VOID
197 NTAPI
198 HalpRestoreIoPermissionsAndTask(VOID)
199 {
200 /* Restore the stack pointer */
201 KeGetPcr()->TSS->Esp0 = HalpSavedEsp0;
202
203 /* Restore the I/O Map */
204 HalpRestoreIopm();
205
206 /* Restore the IOPM */
207 KeGetPcr()->TSS->IoMapBase = HalpSavedIopmBase;
208 }
209
210 VOID
211 NTAPI
212 HalpUnmapRealModeMemory(VOID)
213 {
214 ULONG i;
215 PHARDWARE_PTE Pte;
216
217 /* Loop the first meg of memory */
218 for (i = 0; i < 0x100000; i += PAGE_SIZE)
219 {
220 /* Invalidate each PTE */
221 Pte = GetPteAddress((PVOID)i);
222 Pte->Valid = 0;
223 Pte->Write = 0;
224 Pte->Owner = 0;
225 Pte->PageFrameNumber = 0;
226 }
227
228 /* Restore the PDE for the lowest megabyte of memory */
229 Pte = GetPdeAddress(0);
230 *Pte = HalpSavedPte;
231 Pte->PageFrameNumber = HalpSavedPfn;
232
233 /* Flush the TLB by resetting CR3 */
234 __writecr3(__readcr3());
235 }
236
237 BOOLEAN
238 NTAPI
239 HalpBiosDisplayReset(VOID)
240 {
241 ULONG Flags;
242 PHARDWARE_PTE IdtPte;
243 BOOLEAN RestoreWriteProtection = FALSE;
244
245 /* Disable interrupts */
246 Flags = __readeflags();
247 _disable();
248
249 /* Map memory available to the V8086 real-mode code */
250 HalpMapRealModeMemory();
251
252 /*
253 * On P5, the first 7 entries of the IDT are write protected to work around
254 * the cmpxchg8b lock errata. Unprotect them here so we can set our custom
255 * invalid op-code handler.
256 */
257 if (KeGetCurrentPrcb()->CpuType == 5)
258 {
259 /* Get the PTE and check if it is has been write protected yet */
260 IdtPte = GetPteAddress(((PKIPCR)KeGetPcr())->IDT);
261 if (IdtPte->Write == 0)
262 {
263 /* Remove the protection and flush the TLB */
264 IdtPte->Write = 1;
265 __writecr3(__readcr3());
266 RestoreWriteProtection = TRUE;
267 }
268 }
269
270 /* Use special invalid opcode and GPF trap handlers */
271 HalpSwitchToRealModeTrapHandlers();
272
273 /* Configure the IOPM and TSS */
274 HalpSetupRealModeIoPermissionsAndTask();
275
276 /* Now jump to real mode */
277 HalpBiosCall();
278
279 /* Restore kernel trap handlers */
280 HalpRestoreTrapHandlers();
281
282 /* Check if we removed the write protection before */
283 if (RestoreWriteProtection)
284 {
285 /* Get the PTE, restore the write protection and flush the TLB */
286 IdtPte = GetPteAddress(((PKIPCR)KeGetPcr())->IDT);
287 IdtPte->Write = 0;
288 __writecr3(__readcr3());
289 }
290
291 /* Restore TSS and IOPM */
292 HalpRestoreIoPermissionsAndTask();
293
294 /* Restore low memory mapping */
295 HalpUnmapRealModeMemory();
296
297 /* Restore interrupts if they were previously enabled */
298 __writeeflags(Flags);
299 return TRUE;
300 }
301
302 /* EOF */