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
;
112 /* On i586, the first 7 entries of IDT are write-protected, unprotect them. */
113 if (KeGetCurrentPrcb()->CpuType
== 5)
115 IdtPte
= GetPteAddress(((PKIPCR
)KeGetPcr())->IDT
);
118 /* Flush the TLB by resetting CR3 */
119 __writecr3(__readcr3());
122 /* Save the current Invalid Opcode and General Protection Fault Handlers */
123 HalpGpfHandler
= ((((PKIPCR
)KeGetPcr())->IDT
[13].ExtendedOffset
<< 16) &
125 (((PKIPCR
)KeGetPcr())->IDT
[13].Offset
& 0xFFFF);
126 HalpBopHandler
= ((((PKIPCR
)KeGetPcr())->IDT
[6].ExtendedOffset
<< 16) &
128 (((PKIPCR
)KeGetPcr())->IDT
[6].Offset
& 0xFFFF);
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
;
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
;
145 HalpSetupRealModeIoPermissionsAndTask(VOID
)
147 /* Save a copy of the I/O Map and delete it */
148 HalpSavedIoMap
= (PUCHAR
)&(KeGetPcr()->TSS
->IoMaps
[0]);
149 HalpStoreAndClearIopm(HalpSavedIoMap
);
151 /* Save the IOPM and switch to the real-mode one */
152 HalpSavedIopmBase
= KeGetPcr()->TSS
->IoMapBase
;
153 KeGetPcr()->TSS
->IoMapBase
= KiComputeIopmOffset(1);
155 /* Save our stack pointer */
156 HalpSavedEsp0
= KeGetPcr()->TSS
->Esp0
;
161 HalpRestoreTrapHandlers(VOID
)
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
;
174 HalpRestoreIoPermissionsAndTask(VOID
)
176 /* Restore the stack pointer */
177 KeGetPcr()->TSS
->Esp0
= HalpSavedEsp0
;
179 /* Restore the I/O Map */
180 HalpRestoreIopm(HalpSavedIoMap
);
182 /* Restore the IOPM */
183 KeGetPcr()->TSS
->IoMapBase
= HalpSavedIopmBase
;
188 HalpUnmapRealModeMemory(VOID
)
193 /* Loop the first meg of memory */
194 for (i
= 0; i
< 0x100000; i
+= PAGE_SIZE
)
196 /* Invalidate each PTE */
197 Pte
= GetPteAddress((PVOID
)i
);
200 Pte
->PageFrameNumber
= 0;
203 /* Restore the PDE for the lowest megabyte of memory */
204 Pte
= GetPdeAddress(0);
206 Pte
->PageFrameNumber
= HalpSavedPfn
;
208 /* Flush the TLB by resetting CR3 */
209 __writecr3(__readcr3());
214 HalpBiosDisplayReset(VOID
)
218 /* Disable interrupts */
219 Ke386SaveFlags(Flags
);
222 /* Map memory available to the V8086 real-mode code */
223 HalpMapRealModeMemory();
225 /* Use special invalid opcode and GPF trap handlers */
226 HalpSwitchToRealModeTrapHandlers();
228 /* Configure the IOPM and TSS */
229 HalpSetupRealModeIoPermissionsAndTask();
231 /* Now jump to real mode */
234 /* Restore kernel trap handlers */
235 HalpRestoreTrapHandlers();
237 /* Restore TSS and IOPM */
238 HalpRestoreIoPermissionsAndTask();
240 /* Restore low memory mapping */
241 HalpUnmapRealModeMemory();
243 /* Restore interrupts if they were previously enabled */
244 Ke386RestoreFlags(Flags
);