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