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)
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 UCHAR HalpIopmSaveBuffer
[0x2000];
19 HARDWARE_PTE HalpSavedPte
;
22 USHORT HalpSavedIopmBase
;
23 PUCHAR HalpSavedIoMap
;
26 #define GetPdeAddress(x) (PHARDWARE_PTE)(((((ULONG_PTR)(x)) >> 22) << 2) + 0xC0300000)
27 #define GetPteAddress(x) (PHARDWARE_PTE)(((((ULONG_PTR)(x)) >> 12) << 2) + 0xC0000000)
29 /* FUNCTIONS ******************************************************************/
33 HalpStoreAndClearIopm(IN PUCHAR IoMap
)
37 /* Backup the old I/O Map */
38 RtlCopyMemory(HalpIopmSaveBuffer
, IoMap
, 0x2000);
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;
47 HalpRestoreIopm(IN PUCHAR IoMap
)
51 /* Restore the backed up copy, and initialize it */
52 RtlCopyMemory(IoMap
, HalpIopmSaveBuffer
, 0x2000);
53 for (i
= 0x2000; i
< 0x2004; i
++) IoMap
[i
] = 0xFF;
58 HalpMapRealModeMemory(VOID
)
60 PHARDWARE_PTE Pte
, V86Pte
;
63 /* Get the page table directory for the lowest meg of memory */
64 Pte
= GetPdeAddress(0);
65 HalpSavedPfn
= Pte
->PageFrameNumber
;
68 /* Map it to the HAL reserved region and make it valid */
72 Pte
->PageFrameNumber
= (GetPdeAddress(0xFFC00000))->PageFrameNumber
;
74 /* Flush the TLB by resetting CR3 */
75 __writecr3(__readcr3());
77 /* Now loop the first meg of memory */
78 for (i
= 0; i
< 0x100000; i
+= PAGE_SIZE
)
81 Pte
= GetPteAddress((PVOID
)i
);
82 Pte
->PageFrameNumber
= i
>> PAGE_SHIFT
;
88 /* Now get the entry for our real mode V86 code and the target */
89 Pte
= GetPteAddress(0x20000);
90 V86Pte
= GetPteAddress(&HalpRealModeStart
);
93 /* Map the physical address into our real-mode region */
94 Pte
->PageFrameNumber
= V86Pte
->PageFrameNumber
;
96 /* Keep going until we've reached the end of our region */
99 } while (V86Pte
<= GetPteAddress(&HalpRealModeEnd
));
101 /* Flush the TLB by resetting CR3 */
102 __writecr3(__readcr3());
107 HalpSwitchToRealModeTrapHandlers(VOID
)
110 PHARDWARE_PTE IdtPte
;
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.
117 if (KeGetCurrentPrcb()->CpuType
== 5)
119 IdtPte
= GetPteAddress(((PKIPCR
)KeGetPcr())->IDT
);
122 /* Flush the TLB by resetting CR3 */
123 __writecr3(__readcr3());
126 /* Save the current Invalid Opcode and General Protection Fault Handlers */
127 HalpGpfHandler
= ((((PKIPCR
)KeGetPcr())->IDT
[13].ExtendedOffset
<< 16) &
129 (((PKIPCR
)KeGetPcr())->IDT
[13].Offset
& 0xFFFF);
130 HalpBopHandler
= ((((PKIPCR
)KeGetPcr())->IDT
[6].ExtendedOffset
<< 16) &
132 (((PKIPCR
)KeGetPcr())->IDT
[6].Offset
& 0xFFFF);
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
;
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
;
149 HalpSetupRealModeIoPermissionsAndTask(VOID
)
151 /* Save a copy of the I/O Map and delete it */
152 HalpSavedIoMap
= (PUCHAR
)&(KeGetPcr()->TSS
->IoMaps
[0]);
153 HalpStoreAndClearIopm(HalpSavedIoMap
);
155 /* Save the IOPM and switch to the real-mode one */
156 HalpSavedIopmBase
= KeGetPcr()->TSS
->IoMapBase
;
157 KeGetPcr()->TSS
->IoMapBase
= KiComputeIopmOffset(1);
159 /* Save our stack pointer */
160 HalpSavedEsp0
= KeGetPcr()->TSS
->Esp0
;
165 HalpRestoreTrapHandlers(VOID
)
167 PHARDWARE_PTE IdtPte
;
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
;
177 /* On P5, restore the write protection for the first 7 IDT entries */
178 if (KeGetCurrentPrcb()->CpuType
== 5)
180 IdtPte
= GetPteAddress(((PKIPCR
)KeGetPcr())->IDT
);
183 /* Flush the TLB by resetting CR3 */
184 __writecr3(__readcr3());
190 HalpRestoreIoPermissionsAndTask(VOID
)
192 /* Restore the stack pointer */
193 KeGetPcr()->TSS
->Esp0
= HalpSavedEsp0
;
195 /* Restore the I/O Map */
196 HalpRestoreIopm(HalpSavedIoMap
);
198 /* Restore the IOPM */
199 KeGetPcr()->TSS
->IoMapBase
= HalpSavedIopmBase
;
204 HalpUnmapRealModeMemory(VOID
)
209 /* Loop the first meg of memory */
210 for (i
= 0; i
< 0x100000; i
+= PAGE_SIZE
)
212 /* Invalidate each PTE */
213 Pte
= GetPteAddress((PVOID
)i
);
217 Pte
->PageFrameNumber
= 0;
220 /* Restore the PDE for the lowest megabyte of memory */
221 Pte
= GetPdeAddress(0);
223 Pte
->PageFrameNumber
= HalpSavedPfn
;
225 /* Flush the TLB by resetting CR3 */
226 __writecr3(__readcr3());
231 HalpBiosDisplayReset(VOID
)
235 /* Disable interrupts */
236 Flags
= __readeflags();
239 /* Map memory available to the V8086 real-mode code */
240 HalpMapRealModeMemory();
242 /* Use special invalid opcode and GPF trap handlers */
243 HalpSwitchToRealModeTrapHandlers();
245 /* Configure the IOPM and TSS */
246 HalpSetupRealModeIoPermissionsAndTask();
248 /* Now jump to real mode */
251 /* Restore kernel trap handlers */
252 HalpRestoreTrapHandlers();
254 /* Restore TSS and IOPM */
255 HalpRestoreIoPermissionsAndTask();
257 /* Restore low memory mapping */
258 HalpUnmapRealModeMemory();
260 /* Restore interrupts if they were previously enabled */
261 __writeeflags(Flags
);