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 "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
40 /* FUNCTIONS *****************************************************************/
42 .globl _HalpBiosCall@0
46 /* Set up stack pointer */
50 /* Build a trap frame */
59 push offset _HalpRealModeEnd
62 mov _HalpSavedEsp, esp
64 /* Turn off alignment faults */
69 /* Setup a new stack */
72 sub eax, NPX_FRAME_LENGTH
73 mov [esi+KTSS_ESP0], eax
75 /* Save V86 registers */
82 /* Get linear delta between stack and code */
83 mov eax, offset _HalpRealModeEnd-4
84 sub eax, offset _HalpRealModeStart
86 /* Get offset of code */
87 mov edx, offset _HalpRealModeStart
90 /* Add offset to linear address and save the new V86 SP */
94 /* Start building interrupt frame. Setup V86 EFLAGS and IOPL 3 */
96 or dword ptr [esp], EFLAGS_V86_MASK
97 or dword ptr [esp], 0x3000
99 /* Push the CS and IP */
103 /* Do the interrupt return (jump to V86 mode) */
106 .globl _HalpRealModeStart
114 /* Do the interrupt */
117 /* BOP to exit V86 mode */
121 /* The stack lives here */
124 .globl _HalpRealModeEnd
127 /* We're back, clean up the trap frame */
137 /* Return to caller */
142 .globl _HalpOpcodeInvalid@0
143 .func HalpOpcodeInvalid@0
144 _HalpOpcodeInvalid@0:
149 /* Nothing to return */
154 .globl _HalpPushInt@0
161 /* Get SS offset and base */
162 mov edx, [esi+HALP_BIOS_FRAME_ESP]
163 mov ebx, [esi+HALP_BIOS_FRAME_SS_BASE]
165 /* Convert to 16-bits */
169 /* Get EFLAGS and write them into the linear address of SP */
170 mov ax, word ptr [esi+HALP_BIOS_FRAME_EFLAGS]
174 /* Get CS segment and write it into SP */
175 mov ax, word ptr [esi+HALP_BIOS_FRAME_CS]
179 /* Get IP and write it into SP */
180 mov ax, word ptr [esi+HALP_BIOS_FRAME_EIP]
183 /* Get new IP value (the interrupt ID is in ECX, so this is in the IVT) */
187 /* Now save the new IP */
189 mov [esi+HALP_BIOS_FRAME_EIP], eax
191 /* Save the new CS of this IP */
194 mov [esi+HALP_BIOS_FRAME_CS], eax
196 /* Update the stack pointer after our manual interrupt frame construction */
197 mov word ptr [esi+HALP_BIOS_FRAME_ESP], dx
199 /* Get CS and convert it to linear format */
200 mov eax, [esi+HALP_BIOS_FRAME_CS]
202 mov [esi+HALP_BIOS_FRAME_CS_BASE], eax
203 mov dword ptr [esi+HALP_BIOS_FRAME_CS_LIMIT], 0xFFFF
204 mov dword ptr [esi+HALP_BIOS_FRAME_CS_FLAGS], 0
206 /* Return success and restore EBX */
212 .globl _HalpOpcodeINTnn@0
213 .func HalpOpcodeINTnn@0
216 /* Save non-volatiles and stack */
221 /* Get SS and convert it to linear format */
222 mov eax, [esi+HALP_BIOS_FRAME_SS]
224 mov [esi+HALP_BIOS_FRAME_SS_BASE], eax
225 mov dword ptr [esi+HALP_BIOS_FRAME_SS_LIMIT], 0xFFFF
226 mov dword ptr [esi+HALP_BIOS_FRAME_SS_FLAGS], 0
228 /* Increase IP and check if we're past the CS limit */
229 inc dword ptr [esi+HALP_BIOS_FRAME_EIP]
230 mov edi, [esi+HALP_BIOS_FRAME_EIP]
231 cmp edi, [esi+HALP_BIOS_FRAME_CS_LIMIT]
234 /* Convert IP to linear address and read the interrupt number */
235 add edi, [esi+HALP_BIOS_FRAME_CS_BASE]
236 movzx ecx, byte ptr [edi]
238 /* Increase EIP and do the interrupt, check for status */
239 inc dword ptr [esi+HALP_BIOS_FRAME_EIP]
244 /* Update the trap frame */
245 mov ebp, [esi+HALP_BIOS_FRAME_TRAP_FRAME]
246 mov eax, [esi+HALP_BIOS_FRAME_SS]
247 mov [ebp+KTRAP_FRAME_SS], eax
248 mov eax, [esi+HALP_BIOS_FRAME_ESP]
249 mov [ebp+KTRAP_FRAME_ESP], eax
250 mov eax, [esi+HALP_BIOS_FRAME_CS]
251 mov [ebp+KTRAP_FRAME_CS], eax
252 mov eax, [esi+HALP_BIOS_FRAME_EFLAGS]
253 mov [ebp+KTRAP_FRAME_EFLAGS], eax
255 /* Set success code */
259 /* Restore volatiles */
266 /* Set failure code */
271 .globl _HalpDispatchV86Opcode@0
272 .func HalpDispatchV86Opcode@0
273 _HalpDispatchV86Opcode@0:
275 /* Make space for the HAL BIOS Frame on the stack */
278 sub esp, HALP_BIOS_FRAME_LENGTH
280 /* Save non-volatiles */
284 /* Save pointer to the trap frame */
286 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_TRAP_FRAME], esi
289 movzx eax, word ptr [esi+KTRAP_FRAME_SS]
290 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_SS], eax
293 mov eax, [esi+KTRAP_FRAME_ESP]
294 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_ESP], eax
297 mov eax, [esi+KTRAP_FRAME_EFLAGS]
298 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_EFLAGS], eax
301 movzx eax, word ptr [esi+KTRAP_FRAME_CS]
302 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_CS], eax
305 mov eax, [esi+KTRAP_FRAME_EIP]
306 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_EIP], eax
310 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_PREFIX], eax
312 /* Set pointer to HAL BIOS Frame */
313 lea esi, [ebp-HALP_BIOS_FRAME_LENGTH]
315 /* Convert CS to linear format */
316 mov eax, [esi+HALP_BIOS_FRAME_CS]
318 mov [esi+HALP_BIOS_FRAME_CS_BASE], eax
319 mov dword ptr [esi+HALP_BIOS_FRAME_CS_LIMIT], 0xFFFF
320 mov dword ptr [esi+HALP_BIOS_FRAME_CS_FLAGS], 0
322 /* Make sure IP is within the CS Limit */
323 mov edi, [esi+HALP_BIOS_FRAME_EIP]
324 cmp edi, [esi+HALP_BIOS_FRAME_CS_LIMIT]
327 /* Convert IP to linear address and read the opcode */
328 add edi, [esi+HALP_BIOS_FRAME_CS_BASE]
331 /* We only deal with interrupts */
335 /* Anything else is invalid */
336 call _HalpOpcodeInvalid@0
340 /* Handle dispatching the interrupt */
341 call _HalpOpcodeINTnn@0
345 /* Update the trap frame EIP */
348 mov [edi+KTRAP_FRAME_EIP], eax
350 /* Set success code */
354 /* Restore registers and return */
362 /* Set failure code and return */
367 .func Ki16BitStackException
368 _Ki16BitStackException:
374 /* Go to kernel mode thread stack */
375 mov eax, PCR[KPCR_CURRENT_THREAD]
376 add esp, [eax+KTHREAD_INITIAL_STACK]
378 /* Switch to good stack segment */
384 TRAP_FIXUPS htd_a, htd_t, DoFixupV86, DoFixupAbios
388 TRAP_PROLOG htd_a, htd_t
390 /* Check if this is a V86 trap */
391 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
398 /* Handle the opcode */
399 call _HalpDispatchV86Opcode@0
401 /* Exit the interrupt */
402 jmp _Kei386EoiHelper@0
409 /* Restore DS/ES segments */
410 mov eax, KGDT_R3_DATA | RPL_MASK
414 /* Restore ESP and return */
415 mov esp, _HalpSavedEsp