[HAL]
[reactos.git] / reactos / hal / halx86 / generic / i386 / v86.s
1 /*
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)
6 */
7
8 /* INCLUDES ******************************************************************/
9
10 #include <asm.h>
11 #include <internal/i386/asmmacro.S>
12 .intel_syntax noprefix
13
14 //
15 // HAL BIOS Frame
16 //
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
31
32 /* GLOBALS *******************************************************************/
33
34 _HalpSavedEsp:
35 .long 0
36
37 _UnhandledMsg:
38 .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
39
40 /* FUNCTIONS *****************************************************************/
41
42 .globl _HalpBiosCall@0
43 .func HalpBiosCall@0
44 _HalpBiosCall@0:
45
46 /* Set up stack pointer */
47 push ebp
48 mov ebp, esp
49
50 /* Build a trap frame */
51 pushfd
52 push edi
53 push esi
54 push ebx
55 push ds
56 push es
57 push fs
58 push gs
59 push offset _HalpRealModeEnd
60
61 /* Save the stack */
62 mov _HalpSavedEsp, esp
63
64 /* Turn off alignment faults */
65 mov eax, cr0
66 and eax, ~CR0_AM
67 mov cr0, eax
68
69 /* Setup a new stack */
70 mov esi, fs:KPCR_TSS
71 mov eax, esp
72 sub eax, NPX_FRAME_LENGTH
73 mov [esi+KTSS_ESP0], eax
74
75 /* Save V86 registers */
76 push 0
77 push 0
78 push 0
79 push 0
80 push 0x2000
81
82 /* Get linear delta between stack and code */
83 mov eax, offset _HalpRealModeEnd-4
84 sub eax, offset _HalpRealModeStart
85
86 /* Get offset of code */
87 mov edx, offset _HalpRealModeStart
88 and edx, 0xFFF
89
90 /* Add offset to linear address and save the new V86 SP */
91 add eax, edx
92 push eax
93
94 /* Start building interrupt frame. Setup V86 EFLAGS and IOPL 3 */
95 pushfd
96 or dword ptr [esp], EFLAGS_V86_MASK
97 or dword ptr [esp], 0x3000
98
99 /* Push the CS and IP */
100 push 0x2000
101 push edx
102
103 /* Do the interrupt return (jump to V86 mode) */
104 iretd
105
106 .globl _HalpRealModeStart
107 _HalpRealModeStart:
108
109 /* Set mode 13 */
110 mov ax, 0x12
111 .byte 0
112 .byte 0
113
114 /* Do the interrupt */
115 int 0x10
116
117 /* BOP to exit V86 mode */
118 .byte 0xC4
119 .byte 0xC4
120
121 /* The stack lives here */
122 .align 4
123 .space 2048
124 .globl _HalpRealModeEnd
125 _HalpRealModeEnd:
126
127 /* We're back, clean up the trap frame */
128 pop gs
129 pop fs
130 pop es
131 pop ds
132 pop ebx
133 pop esi
134 pop edi
135 popfd
136
137 /* Return to caller */
138 pop ebp
139 ret 0
140 .endfunc
141
142 .globl _HalpOpcodeInvalid@0
143 .func HalpOpcodeInvalid@0
144 _HalpOpcodeInvalid@0:
145
146 /* Unhandled */
147 UNHANDLED_PATH
148
149 /* Nothing to return */
150 xor eax, eax
151 ret 0
152 .endfunc
153
154 .globl _HalpPushInt@0
155 .func HalpPushInt@0
156 _HalpPushInt@0:
157
158 /* Save EBX */
159 push ebx
160
161 /* Get SS offset and base */
162 mov edx, [esi+HALP_BIOS_FRAME_ESP]
163 mov ebx, [esi+HALP_BIOS_FRAME_SS_BASE]
164
165 /* Convert to 16-bits */
166 and edx, 0xFFFF
167 sub dx, 2
168
169 /* Get EFLAGS and write them into the linear address of SP */
170 mov ax, word ptr [esi+HALP_BIOS_FRAME_EFLAGS]
171 mov [ebx+edx], ax
172 sub dx, 2
173
174 /* Get CS segment and write it into SP */
175 mov ax, word ptr [esi+HALP_BIOS_FRAME_CS]
176 mov [ebx+edx], ax
177 sub dx, 2
178
179 /* Get IP and write it into SP */
180 mov ax, word ptr [esi+HALP_BIOS_FRAME_EIP]
181 mov [ebx+edx], ax
182
183 /* Get new IP value (the interrupt ID is in ECX, so this is in the IVT) */
184 mov eax, [ecx*4]
185 push eax
186
187 /* Now save the new IP */
188 movzx eax, ax
189 mov [esi+HALP_BIOS_FRAME_EIP], eax
190
191 /* Save the new CS of this IP */
192 pop eax
193 shr eax, 16
194 mov [esi+HALP_BIOS_FRAME_CS], eax
195
196 /* Update the stack pointer after our manual interrupt frame construction */
197 mov word ptr [esi+HALP_BIOS_FRAME_ESP], dx
198
199 /* Get CS and convert it to linear format */
200 mov eax, [esi+HALP_BIOS_FRAME_CS]
201 shl eax, 4
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
205
206 /* Return success and restore EBX */
207 mov eax, 1
208 pop ebx
209 ret 0
210 .endfunc
211
212 .globl _HalpOpcodeINTnn@0
213 .func HalpOpcodeINTnn@0
214 _HalpOpcodeINTnn@0:
215
216 /* Save non-volatiles and stack */
217 push ebp
218 push esi
219 push ebx
220
221 /* Get SS and convert it to linear format */
222 mov eax, [esi+HALP_BIOS_FRAME_SS]
223 shl eax, 4
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
227
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]
232 ja EipLimitReached
233
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]
237
238 /* Increase EIP and do the interrupt, check for status */
239 inc dword ptr [esi+HALP_BIOS_FRAME_EIP]
240 call _HalpPushInt@0
241 test eax, 0xFFFF
242 jz Done
243
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
254
255 /* Set success code */
256 mov eax, 1
257
258 Done:
259 /* Restore volatiles */
260 pop ebx
261 pop edi
262 pop ebp
263 ret 0
264
265 EipLimitReached:
266 /* Set failure code */
267 xor eax, eax
268 jmp Done
269 .endfunc
270
271 .globl _HalpDispatchV86Opcode@0
272 .func HalpDispatchV86Opcode@0
273 _HalpDispatchV86Opcode@0:
274
275 /* Make space for the HAL BIOS Frame on the stack */
276 push ebp
277 mov ebp, esp
278 sub esp, HALP_BIOS_FRAME_LENGTH
279
280 /* Save non-volatiles */
281 push esi
282 push edi
283
284 /* Save pointer to the trap frame */
285 mov esi, [ebp]
286 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_TRAP_FRAME], esi
287
288 /* Save SS */
289 movzx eax, word ptr [esi+KTRAP_FRAME_SS]
290 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_SS], eax
291
292 /* Save ESP */
293 mov eax, [esi+KTRAP_FRAME_ESP]
294 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_ESP], eax
295
296 /* Save EFLAGS */
297 mov eax, [esi+KTRAP_FRAME_EFLAGS]
298 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_EFLAGS], eax
299
300 /* Save CS */
301 movzx eax, word ptr [esi+KTRAP_FRAME_CS]
302 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_CS], eax
303
304 /* Save EIP */
305 mov eax, [esi+KTRAP_FRAME_EIP]
306 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_EIP], eax
307
308 /* No prefix */
309 xor eax, eax
310 mov [ebp-HALP_BIOS_FRAME_LENGTH+HALP_BIOS_FRAME_PREFIX], eax
311
312 /* Set pointer to HAL BIOS Frame */
313 lea esi, [ebp-HALP_BIOS_FRAME_LENGTH]
314
315 /* Convert CS to linear format */
316 mov eax, [esi+HALP_BIOS_FRAME_CS]
317 shl eax, 4
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
321
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]
325 ja DispatchError
326
327 /* Convert IP to linear address and read the opcode */
328 add edi, [esi+HALP_BIOS_FRAME_CS_BASE]
329 mov dl, [edi]
330
331 /* We only deal with interrupts */
332 cmp dl, 0xCD
333 je DispatchInt
334
335 /* Anything else is invalid */
336 call _HalpOpcodeInvalid@0
337 jmp DispatchError
338
339 DispatchInt:
340 /* Handle dispatching the interrupt */
341 call _HalpOpcodeINTnn@0
342 test eax, 0xFFFF
343 jz DispatchReturn
344
345 /* Update the trap frame EIP */
346 mov edi, [ebp-0x20]
347 mov eax, [ebp-0x24]
348 mov [edi+KTRAP_FRAME_EIP], eax
349
350 /* Set success code */
351 mov eax, 1
352
353 DispatchReturn:
354 /* Restore registers and return */
355 pop edi
356 pop esi
357 mov esp, ebp
358 pop ebp
359 ret 0
360
361 DispatchError:
362 /* Set failure code and return */
363 xor eax, eax
364 jmp DispatchReturn
365 .endfunc
366
367 .func Ki16BitStackException
368 _Ki16BitStackException:
369
370 /* Save stack */
371 push ss
372 push esp
373
374 /* Go to kernel mode thread stack */
375 mov eax, PCR[KPCR_CURRENT_THREAD]
376 add esp, [eax+KTHREAD_INITIAL_STACK]
377
378 /* Switch to good stack segment */
379 UNHANDLED_PATH
380 .endfunc
381
382 .globl _HalpTrap0D@0
383 .func HalpTrap0D@0
384 TRAP_FIXUPS htd_a, htd_t, DoFixupV86, DoFixupAbios
385 _HalpTrap0D@0:
386
387 /* Enter trap */
388 TRAP_PROLOG htd_a, htd_t
389
390 /* Check if this is a V86 trap */
391 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
392 jnz DoDispatch
393
394 /* Unhandled */
395 UNHANDLED_PATH
396
397 DoDispatch:
398 /* Handle the opcode */
399 call _HalpDispatchV86Opcode@0
400
401 /* Exit the interrupt */
402 jmp _Kei386EoiHelper@0
403 .endfunc
404
405 .globl _HalpTrap06@0
406 .func HalpTrap06@0
407 _HalpTrap06@0:
408
409 /* Restore DS/ES segments */
410 mov eax, KGDT_R3_DATA | RPL_MASK
411 mov ds, ax
412 mov es, ax
413
414 /* Restore ESP and return */
415 mov esp, _HalpSavedEsp
416 ret 0
417 .endfunc