2 * FILE: hal/halx86/generic/bios.S
3 * COPYRIGHT: See COPYING in the top level directory
4 * PURPOSE: V8086 Real-Mode BIOS Thunking
5 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
8 /* INCLUDES ******************************************************************/
11 #include <internal/i386/asmmacro.S>
12 .intel_syntax noprefix
17 #define HALP_BIOS_FRAME_SS 0x00
18 #define HALP_BIOS_FRAME_ESP 0x04
19 #define HALP_BIOS_FRAME_EFLAGS 0x08
20 #define HALP_BIOS_FRAME_CS 0x0C
21 #define HALP_BIOS_FRAME_EIP 0x10
22 #define HALP_BIOS_FRAME_TRAP_FRAME 0x14
23 #define HALP_BIOS_FRAME_CS_LIMIT 0x18
24 #define HALP_BIOS_FRAME_CS_BASE 0x1C
25 #define HALP_BIOS_FRAME_CS_FLAGS 0x20
26 #define HALP_BIOS_FRAME_SS_LIMIT 0x24
27 #define HALP_BIOS_FRAME_SS_BASE 0x28
28 #define HALP_BIOS_FRAME_SS_FLAGS 0x2C
29 #define HALP_BIOS_FRAME_PREFIX 0x30
30 #define HALP_BIOS_FRAME_LENGTH 0x34
32 /* GLOBALS *******************************************************************/
38 .asciz "HAL: An invalid V86 opcode was encountered at address %x:%x\n"
41 .asciz "HAL: Trap0D while not in V86 mode\n"
44 .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx [%s]!!!\n"
46 /* FUNCTIONS *****************************************************************/
48 .globl _HalpBiosCall@0
52 /* Set up stack pointer */
56 /* Build a trap frame */
65 push offset _HalpRealModeEnd
68 mov _HalpSavedEsp, esp
70 /* Turn off alignment faults */
75 /* Setup a new stack */
78 sub eax, NPX_FRAME_LENGTH
79 mov [esi+KTSS_ESP0], eax
81 /* Save V86 registers */
88 /* Get linear delta between stack and code */
89 mov eax, offset _HalpRealModeEnd-4
90 sub eax, offset _HalpRealModeStart
92 /* Get offset of code */
93 mov edx, offset _HalpRealModeStart
96 /* Add offset to linear address and save the new V86 SP */
100 /* Start building interrupt frame. Setup V86 EFLAGS and IOPL 3 */
102 or dword ptr [esp], EFLAGS_V86_MASK
103 or dword ptr [esp], 0x3000
105 /* Push the CS and IP */
109 /* Do the interrupt return (jump to V86 mode) */
112 .globl _HalpRealModeStart
120 /* Do the interrupt */
123 /* BOP to exit V86 mode */
127 /* The stack lives here */
130 .globl _HalpRealModeEnd
133 /* We're back, clean up the trap frame */
143 /* Return to caller */
148 .globl _HalpOpcodeInvalid@0
149 .func HalpOpcodeInvalid@0
150 _HalpOpcodeInvalid@0:
152 /* This should never happen -- is the IOPM damaged? */
153 push [esi+HALP_BIOS_FRAME_EIP]
154 push [esi+HALP_BIOS_FRAME_CS]
155 push offset _InvalidMsg
162 /* Nothing to return */
167 .globl _HalpPushInt@0
174 /* Get SS offset and base */
175 mov edx, [esi+HALP_BIOS_FRAME_ESP]
176 mov ebx, [esi+HALP_BIOS_FRAME_SS_BASE]
178 /* Convert to 16-bits */
182 /* Get EFLAGS and write them into the linear address of SP */
183 mov ax, word ptr [esi+HALP_BIOS_FRAME_EFLAGS]
187 /* Get CS segment and write it into SP */
188 mov ax, word ptr [esi+HALP_BIOS_FRAME_CS]
192 /* Get IP and write it into SP */
193 mov ax, word ptr [esi+HALP_BIOS_FRAME_EIP]
196 /* Get new IP value (the interrupt ID is in ECX, so this is in the IVT) */
200 /* Now save the new IP */
202 mov [esi+HALP_BIOS_FRAME_EIP], eax
204 /* Save the new CS of this IP */
207 mov [esi+HALP_BIOS_FRAME_CS], eax
209 /* Update the stack pointer after our manual interrupt frame construction */
210 mov word ptr [esi+HALP_BIOS_FRAME_ESP], dx
212 /* Get CS and convert it to linear format */
213 mov eax, [esi+HALP_BIOS_FRAME_CS]
215 mov [esi+HALP_BIOS_FRAME_CS_BASE], eax
216 mov dword ptr [esi+HALP_BIOS_FRAME_CS_LIMIT], 0xFFFF
217 mov dword ptr [esi+HALP_BIOS_FRAME_CS_FLAGS], 0
219 /* Return success and restore EBX */
225 .globl _HalpOpcodeINTnn@0
226 .func HalpOpcodeINTnn@0
229 /* Save non-volatiles and stack */
234 /* Get SS and convert it to linear format */
235 mov eax, [esi+HALP_BIOS_FRAME_SS]
237 mov [esi+HALP_BIOS_FRAME_SS_BASE], eax
238 mov dword ptr [esi+HALP_BIOS_FRAME_SS_LIMIT], 0xFFFF
239 mov dword ptr [esi+HALP_BIOS_FRAME_SS_FLAGS], 0
241 /* Increase IP and check if we're past the CS limit */
242 inc dword ptr [esi+HALP_BIOS_FRAME_EIP]
243 mov edi, [esi+HALP_BIOS_FRAME_EIP]
244 cmp edi, [esi+HALP_BIOS_FRAME_CS_LIMIT]
247 /* Convert IP to linear address and read the interrupt number */
248 add edi, [esi+HALP_BIOS_FRAME_CS_BASE]
249 movzx ecx, byte ptr [edi]
251 /* Increase EIP and do the interrupt, check for status */
252 inc dword ptr [esi+HALP_BIOS_FRAME_EIP]
257 /* Update the trap frame */
258 mov ebp, [esi+HALP_BIOS_FRAME_TRAP_FRAME]
259 mov eax, [esi+HALP_BIOS_FRAME_SS]
260 mov [ebp+KTRAP_FRAME_SS], eax
261 mov eax, [esi+HALP_BIOS_FRAME_ESP]
262 mov [ebp+KTRAP_FRAME_ESP], eax
263 mov eax, [esi+HALP_BIOS_FRAME_CS]
264 mov [ebp+KTRAP_FRAME_CS], eax
265 mov eax, [esi+HALP_BIOS_FRAME_EFLAGS]
266 mov [ebp+KTRAP_FRAME_EFLAGS], eax
268 /* Set success code */
272 /* Restore volatiles */
279 /* Set failure code */
284 .globl _HalpDispatchV86Opcode@0
285 .func HalpDispatchV86Opcode@0
286 _HalpDispatchV86Opcode@0:
288 /* Make space for the HAL BIOS Frame on the stack */
291 sub esp, HALP_BIOS_FRAME_LENGTH
293 /* Save non-volatiles */
297 /* Save pointer to the trap frame */
299 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_TRAP_FRAME], esi
302 movzx eax, word ptr [esi+KTRAP_FRAME_SS]
303 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_SS], eax
306 mov eax, [esi+KTRAP_FRAME_ESP]
307 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_ESP], eax
310 mov eax, [esi+KTRAP_FRAME_EFLAGS]
311 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_EFLAGS], eax
314 movzx eax, word ptr [esi+KTRAP_FRAME_CS]
315 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_CS], eax
318 mov eax, [esi+KTRAP_FRAME_EIP]
319 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_EIP], eax
323 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_PREFIX], eax
325 /* Set pointer to HAL BIOS Frame */
326 lea esi, [ebp-HALP_BIOS_FRAME_LENGTH]
328 /* Convert CS to linear format */
329 mov eax, [esi+HALP_BIOS_FRAME_CS]
331 mov [esi+HALP_BIOS_FRAME_CS_BASE], eax
332 mov dword ptr [esi+HALP_BIOS_FRAME_CS_LIMIT], 0xFFFF
333 mov dword ptr [esi+HALP_BIOS_FRAME_CS_FLAGS], 0
335 /* Make sure IP is within the CS Limit */
336 mov edi, [esi+HALP_BIOS_FRAME_EIP]
337 cmp edi, [esi+HALP_BIOS_FRAME_CS_LIMIT]
340 /* Convert IP to linear address and read the opcode */
341 add edi, [esi+HALP_BIOS_FRAME_CS_BASE]
344 /* We only deal with interrupts */
348 /* Anything else is invalid */
349 call _HalpOpcodeInvalid@0
353 /* Handle dispatching the interrupt */
354 call _HalpOpcodeINTnn@0
358 /* Update the trap frame EIP */
361 mov [edi+KTRAP_FRAME_EIP], eax
363 /* Set success code */
367 /* Restore registers and return */
375 /* Set failure code and return */
380 .func Ki16BitStackException
381 _Ki16BitStackException:
387 /* Go to kernel mode thread stack */
388 mov eax, PCR[KPCR_CURRENT_THREAD]
389 add esp, [eax+KTHREAD_INITIAL_STACK]
391 /* Switch to good stack segment */
392 UNHANDLED_PATH "16-Bit Stack"
397 TRAP_FIXUPS htd_a, htd_t, DoFixupV86, DoFixupAbios
401 TRAP_PROLOG htd_a, htd_t
403 /* Check if this is a V86 trap */
404 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
407 /* This is weird -- but might happen during an NMI */
408 push offset _InvalidGpfMsg
416 /* Handle the opcode */
417 call _HalpDispatchV86Opcode@0
419 /* Exit the interrupt */
420 jmp _Kei386EoiHelper@0
427 /* Restore DS/ES segments */
428 mov eax, KGDT_R3_DATA | RPL_MASK
432 /* Restore ESP and return */
433 mov esp, _HalpSavedEsp