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