- Finish the work around for the Pentium cmpxchg8b lock errata: We detected the errat...
[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 PHARDWARE_PTE IdtPte;
111
112 /*
113 * On P5, the first 7 entries of the IDT are write protected to work around
114 * the cmpxchg8b lock errata. Unprotect them here so we can set our custom
115 * invalid op-code handler.
116 */
117 if (KeGetCurrentPrcb()->CpuType == 5)
118 {
119 IdtPte = GetPteAddress(((PKIPCR)KeGetPcr())->IDT);
120 IdtPte->Write = 1;
121
122 /* Flush the TLB by resetting CR3 */
123 __writecr3(__readcr3());
124 }
125
126 /* Save the current Invalid Opcode and General Protection Fault Handlers */
127 HalpGpfHandler = ((((PKIPCR)KeGetPcr())->IDT[13].ExtendedOffset << 16) &
128 0xFFFF0000) |
129 (((PKIPCR)KeGetPcr())->IDT[13].Offset & 0xFFFF);
130 HalpBopHandler = ((((PKIPCR)KeGetPcr())->IDT[6].ExtendedOffset << 16) &
131 0xFFFF0000) |
132 (((PKIPCR)KeGetPcr())->IDT[6].Offset & 0xFFFF);
133
134 /* Now set our own GPF handler to handle exceptions while in real mode */
135 Handler = (ULONG_PTR)HalpTrap0D;
136 ((PKIPCR)KeGetPcr())->IDT[13].ExtendedOffset =
137 (USHORT)((Handler >> 16) & 0xFFFF);
138 ((PKIPCR)KeGetPcr())->IDT[13].Offset = (USHORT)Handler;
139
140 /* And our own invalid opcode handler to detect the BOP to get us out */
141 Handler = (ULONG_PTR)HalpTrap06;
142 ((PKIPCR)KeGetPcr())->IDT[6].ExtendedOffset =
143 (USHORT)((Handler >> 16) & 0xFFFF);
144 ((PKIPCR)KeGetPcr())->IDT[6].Offset = (USHORT)Handler;
145 }
146
147 VOID
148 NTAPI
149 HalpSetupRealModeIoPermissionsAndTask(VOID)
150 {
151 /* Save a copy of the I/O Map and delete it */
152 HalpSavedIoMap = (PUCHAR)&(KeGetPcr()->TSS->IoMaps[0]);
153 HalpStoreAndClearIopm(HalpSavedIoMap);
154
155 /* Save the IOPM and switch to the real-mode one */
156 HalpSavedIopmBase = KeGetPcr()->TSS->IoMapBase;
157 KeGetPcr()->TSS->IoMapBase = KiComputeIopmOffset(1);
158
159 /* Save our stack pointer */
160 HalpSavedEsp0 = KeGetPcr()->TSS->Esp0;
161 }
162
163 VOID
164 NTAPI
165 HalpRestoreTrapHandlers(VOID)
166 {
167 PHARDWARE_PTE IdtPte;
168
169 /* We're back, restore the handlers we over-wrote */
170 ((PKIPCR)KeGetPcr())->IDT[13].ExtendedOffset =
171 (USHORT)((HalpGpfHandler >> 16) & 0xFFFF);
172 ((PKIPCR)KeGetPcr())->IDT[13].Offset = (USHORT)HalpGpfHandler;
173 ((PKIPCR)KeGetPcr())->IDT[6].ExtendedOffset =
174 (USHORT)((HalpBopHandler >> 16) & 0xFFFF);
175 ((PKIPCR)KeGetPcr())->IDT[6].Offset = (USHORT)HalpBopHandler;
176
177 /* On P5, restore the write protection for the first 7 IDT entries */
178 if (KeGetCurrentPrcb()->CpuType == 5)
179 {
180 IdtPte = GetPteAddress(((PKIPCR)KeGetPcr())->IDT);
181 IdtPte->Write = 0;
182
183 /* Flush the TLB by resetting CR3 */
184 __writecr3(__readcr3());
185 }
186 }
187
188 VOID
189 NTAPI
190 HalpRestoreIoPermissionsAndTask(VOID)
191 {
192 /* Restore the stack pointer */
193 KeGetPcr()->TSS->Esp0 = HalpSavedEsp0;
194
195 /* Restore the I/O Map */
196 HalpRestoreIopm(HalpSavedIoMap);
197
198 /* Restore the IOPM */
199 KeGetPcr()->TSS->IoMapBase = HalpSavedIopmBase;
200 }
201
202 VOID
203 NTAPI
204 HalpUnmapRealModeMemory(VOID)
205 {
206 ULONG i;
207 PHARDWARE_PTE Pte;
208
209 /* Loop the first meg of memory */
210 for (i = 0; i < 0x100000; i += PAGE_SIZE)
211 {
212 /* Invalidate each PTE */
213 Pte = GetPteAddress((PVOID)i);
214 Pte->Valid = 0;
215 Pte->Write = 0;
216 Pte->Owner = 0;
217 Pte->PageFrameNumber = 0;
218 }
219
220 /* Restore the PDE for the lowest megabyte of memory */
221 Pte = GetPdeAddress(0);
222 *Pte = HalpSavedPte;
223 Pte->PageFrameNumber = HalpSavedPfn;
224
225 /* Flush the TLB by resetting CR3 */
226 __writecr3(__readcr3());
227 }
228
229 BOOLEAN
230 NTAPI
231 HalpBiosDisplayReset(VOID)
232 {
233 ULONG Flags;
234
235 /* Disable interrupts */
236 Flags = __readeflags();
237 _disable();
238
239 /* Map memory available to the V8086 real-mode code */
240 HalpMapRealModeMemory();
241
242 /* Use special invalid opcode and GPF trap handlers */
243 HalpSwitchToRealModeTrapHandlers();
244
245 /* Configure the IOPM and TSS */
246 HalpSetupRealModeIoPermissionsAndTask();
247
248 /* Now jump to real mode */
249 HalpBiosCall();
250
251 /* Restore kernel trap handlers */
252 HalpRestoreTrapHandlers();
253
254 /* Restore TSS and IOPM */
255 HalpRestoreIoPermissionsAndTask();
256
257 /* Restore low memory mapping */
258 HalpUnmapRealModeMemory();
259
260 /* Restore interrupts if they were previously enabled */
261 __writeeflags(Flags);
262 return TRUE;
263 }
264
265 /* EOF */