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