- NtUserWaitForInputIdle: Call EngGetTickCount, removing duplicated code
[reactos.git] / reactos / ntoskrnl / ke / i386 / v86m_sup.S
1 /*
2 * FILE: ntoskrnl/ke/i386/v86m_sup.S
3 * COPYRIGHT: See COPYING in the top level directory
4 * PURPOSE: Virtual 8086 (V86) Mode Support
5 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
6 * NOTE: See asmmacro.S for the V86 trap code.
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <asm.h>
12 #include <internal/i386/asmmacro.S>
13 #undef LOCK
14 .intel_syntax noprefix
15
16 /* FIXME: Can we make a nice macro to generate V86 Opcode handlers? */
17
18 /* GLOBALS *******************************************************************/
19
20 //
21 // This table contains indexes into the OpcodeDispatchV86 Table for opcodes in
22 // Virtual-8086 Mode.
23 // There are 256 entries.
24 //
25 OpcodeIndex:
26 INVALID_V86_OPCODE 15 /* OP 00-14: UNHANDLED */
27 .byte 1 /* OP 0F: 0F */
28 INVALID_V86_OPCODE 22 /* OP 10-25: UNHANDLED */
29 .byte 2 /* OP 26: ES Prefix */
30 INVALID_V86_OPCODE 7 /* OP 27-2D: UNHANDLED */
31 .byte 3 /* OP 2E: CS Prefix */
32 INVALID_V86_OPCODE 7 /* OP 2F-35: UNHANDLED */
33 .byte 4 /* OP 36: SS Prefix */
34 INVALID_V86_OPCODE 7 /* OP 37-3D: UNHANDLED */
35 .byte 5 /* OP 3E: DS Prefix */
36 INVALID_V86_OPCODE 37 /* OP 3F-63: UNHANDLED */
37 .byte 6 /* OP 64: FS Prefix */
38 .byte 7 /* OP 65: GS Prefix */
39 .byte 8 /* OP 66: OPER32 Prefix */
40 .byte 9 /* OP 67: ADDR32 Prefix */
41 INVALID_V86_OPCODE 4 /* OP 68-6B: UNHANDLED */
42 .byte 10 /* OP 6C: INSB */
43 .byte 11 /* OP 6D: INSW */
44 .byte 12 /* OP 6E: OUTSB */
45 .byte 13 /* OP 6F: OUTSW */
46 INVALID_V86_OPCODE 43 /* OP 70-9A: UNHANDLED */
47 .byte 19 /* OP 9B: NPX */
48 .byte 14 /* OP 9C: PUSHF */
49 .byte 15 /* OP 9D: POPF */
50 INVALID_V86_OPCODE 47 /* OP 9E-CC: UNHANDLED */
51 .byte 16 /* OP CD: INTnn */
52 .byte 17 /* OP CE: INTO */
53 .byte 18 /* OP CF: IRETD */
54 INVALID_V86_OPCODE 8 /* OP D0-D7: UNHANDLED */
55 .byte 19 /* OP D8: NPX */
56 .byte 19 /* OP D9: NPX */
57 .byte 19 /* OP DA: NPX */
58 .byte 19 /* OP DB: NPX */
59 .byte 19 /* OP DC: NPX */
60 .byte 19 /* OP DD: NPX */
61 .byte 19 /* OP DE: NPX */
62 .byte 19 /* OP DF: NPX */
63 INVALID_V86_OPCODE 4 /* OP DE-E3: UNHANDLED */
64 .byte 20 /* OP E4: INBimm */
65 .byte 21 /* OP E5: INWimm */
66 .byte 22 /* OP E6: OUTBimm */
67 .byte 23 /* OP E7: OUTWimm */
68 INVALID_V86_OPCODE 4 /* OP E8-EB: UNHANDLED */
69 .byte 24 /* OP EC: INB */
70 .byte 25 /* OP EF: INW */
71 .byte 26 /* OP EE: OUTB */
72 .byte 27 /* OP EF: OUTW */
73 .byte 28 /* OP F0: LOCK Prefix */
74 .byte 0 /* OP F1: UNHANDLED */
75 .byte 29 /* OP F2: REPNE Prefix */
76 .byte 30 /* OP F3: REP Prefix */
77 .byte 33 /* OP F4: HLT */
78 INVALID_V86_OPCODE 5 /* OP F5-F9: UNHANDLED */
79 .byte 31 /* OP FA: CLI */
80 .byte 32 /* OP FB: STI */
81 INVALID_V86_OPCODE 4 /* OP FC-FF: UNHANDLED */
82
83 //
84 // This table contains the emulation routines for
85 // Virtual-8086 Mode. There are 34 entries.
86 //
87 OpcodeDispatchV86:
88 .long _OpcodeInvalidV86
89 .long _Opcode0FV86
90 .long _OpcodeESPrefixV86
91 .long _OpcodeCSPrefixV86
92 .long _OpcodeSSPrefixV86
93 .long _OpcodeDSPrefixV86
94 .long _OpcodeFSPrefixV86
95 .long _OpcodeGSPrefixV86
96 .long _OpcodeOPER32PrefixV86
97 .long _OpcodeADDR32PrefixV86
98 .long _OpcodeINSBV86
99 .long _OpcodeINSWV86
100 .long _OpcodeOUTSBV86
101 .long _OpcodeOUTSWV86
102 .long _OpcodePUSHFV86
103 .long _OpcodePOPFV86
104 .long _OpcodeINTnnV86
105 .long _OpcodeINTOV86
106 .long _OpcodeIRETV86
107 .long _OpcodeNPXV86
108 .long _OpcodeINBimmV86
109 .long _OpcodeINWimmV86
110 .long _OpcodeOUTBimmV86
111 .long _OpcodeOUTWimmV86
112 .long _OpcodeINBV86
113 .long _OpcodeINWV86
114 .long _OpcodeOUTBV86
115 .long _OpcodeOUTWV86
116 .long _OpcodeLOCKPrefixV86
117 .long _OpcodeREPNEPrefixV86
118 .long _OpcodeREPPrefixV86
119 .long _OpcodeCLIV86
120 .long _OpcodeSTIV86
121 .long _OpcodeHLTV86
122
123 _ExVdmOpcodeDispatchCounts:
124 .rept 34
125 .long 0
126 .endr
127
128 V86DebugMsg:
129 .asciz "Received V86 Emulation Opcode: %lx\n"
130
131 /* VIRTUAL-8086 MODE OPCODER HANDLERS ****************************************/
132
133 .func OpcodeInvalidV86
134 _OpcodeInvalidV86:
135 UNHANDLED_V86_OPCODE
136 .endfunc
137
138 .func Opcode0FV86
139 _Opcode0FV86:
140 UNHANDLED_V86_OPCODE
141 .endfunc
142
143 GENERATE_PREFIX_HANDLER ES
144 GENERATE_PREFIX_HANDLER CS
145 GENERATE_PREFIX_HANDLER DS
146 GENERATE_PREFIX_HANDLER FS
147 GENERATE_PREFIX_HANDLER GS
148 GENERATE_PREFIX_HANDLER SS
149 GENERATE_PREFIX_HANDLER OPER32
150 GENERATE_PREFIX_HANDLER ADDR32
151 GENERATE_PREFIX_HANDLER LOCK
152 GENERATE_PREFIX_HANDLER REP
153 GENERATE_PREFIX_HANDLER REPNE
154
155 .func OpcodeINSBV86
156 _OpcodeINSBV86:
157 UNHANDLED_V86_OPCODE
158 .endfunc
159
160 .func OpcodeINSWV86
161 _OpcodeINSWV86:
162 UNHANDLED_V86_OPCODE
163 .endfunc
164
165 .func OpcodeOUTSBV86
166 _OpcodeOUTSBV86:
167 UNHANDLED_V86_OPCODE
168 .endfunc
169
170 .func OpcodeOUTSWV86
171 _OpcodeOUTSWV86:
172 UNHANDLED_V86_OPCODE
173 .endfunc
174
175 .func OpcodePUSHFV86
176 _OpcodePUSHFV86:
177
178 /* Get VDM state */
179 mov eax, FIXED_NTVDMSTATE_LINEAR_PC_AT
180 mov eax, [eax]
181
182 /* Get EFLAGS and mask out IF */
183 mov edx, [ebp+KTRAP_FRAME_EFLAGS]
184 and eax, ~EFLAGS_INTERRUPT_MASK
185
186 /* Mask align check and interrupt mask */
187 and eax, EFLAGS_ALIGN_CHECK + EFLAGS_NESTED_TASK + EFLAGS_INTERRUPT_MASK
188 or eax, edx
189
190 /* Add IOPL Mask */
191 or eax, EFLAGS_IOPL
192
193 /* Get flat ESP */
194 movzx ecx, word ptr [ebp+KTRAP_FRAME_SS]
195 shl ecx, 4
196 movzx edx, word ptr [ebp+KTRAP_FRAME_ESP]
197 sub dx, 2
198
199 /* Check if there is an OPER32 prefix */
200 test ebx, PREFIX_FLAG_OPER32
201 jnz SkipPrefix
202
203 /* Push EFLAGS */
204 mov [ecx+edx], ax
205
206 UpdateFrame:
207
208 /* Update ESP and EIP */
209 mov [ebp+KTRAP_FRAME_ESP], dx
210 add [ebp+KTRAP_FRAME_EIP], edi
211
212 /* Return success */
213 mov eax, 1
214 ret
215
216 SkipPrefix:
217
218 /* Skip the prefix, push EFLAGS and jump back */
219 sub dx, 2
220 mov [edx+ecx], eax
221 jmp UpdateFrame
222 .endfunc
223
224 .func OpcodePOPFV86
225 _OpcodePOPFV86:
226
227 /* Get VDM state */
228 mov eax, FIXED_NTVDMSTATE_LINEAR_PC_AT
229
230 /* Get flat ESP */
231 mov ecx, [ebp+KTRAP_FRAME_SS]
232 shl ecx, 4
233 movzx edx, word ptr [ebp+KTRAP_FRAME_ESP]
234
235 /* Pop EFLAGS */
236 mov ecx, [ecx+edx]
237 add edx, 4
238
239 /* Check for OPER32 prefix */
240 test ebx, PREFIX_FLAG_OPER32
241 jnz NoPrefix
242
243 /* Skip 2 bytes */
244 and ecx, 0xFFFF
245 sub edx, 2
246
247 NoPrefix:
248
249 /* Set new ESP */
250 mov [ebp+KTRAP_FRAME_ESP], edx
251
252 /* Mask out EFLAGS */
253 and eax, ~EFLAGS_IOPL
254 mov ebx, ebx
255 and ebx, ~EFLAGS_NESTED_TASK
256 and ecx, EFLAGS_ALIGN_CHECK + EFLAGS_NESTED_TASK + EFLAGS_INTERRUPT_MASK
257
258 /* FIXME: Support VME */
259
260 /* Save VDM State pointer */
261 push eax
262
263 /* Set new EFLAGS, make sure to add IF and V86 */
264 or ebx, EFLAGS_INTERRUPT_MASK + EFLAGS_V86_MASK
265 push [ebp+KTRAP_FRAME_EFLAGS]
266 mov [ebp+KTRAP_FRAME_EFLAGS], ebx
267
268 /* Make sure we were in V86 mode */
269 test ebx, EFLAGS_V86_MASK
270 jnz CheckEspAdjust
271 int 3
272
273 CheckEspAdjust:
274
275 /* Check if we have to update ESP0 and fixup the stack from our push */
276 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
277 lea esp, [esp+4]
278 jnz NoAdjustEsp0
279
280 /* Adjust it */
281 push ebp
282 call _Ki386AdjustEsp0@4
283
284 NoAdjustEsp0:
285
286 /* Restore VDM state */
287 pop eax
288
289 /* Update the flags in the VDM State */
290 LOCK and dword ptr [eax], ~(EFLAGS_ALIGN_CHECK + EFLAGS_NESTED_TASK + EFLAGS_INTERRUPT_MASK)
291 LOCK or [eax], ecx
292
293 /* Update EIP */
294 add [ebp+KTRAP_FRAME_EIP], edi
295
296 /* FIXME: Check for VDM Pending interrupts */
297
298 /* Return success */
299 mov eax, 1
300 ret
301 .endfunc
302
303 .func OpcodeINTnnV86
304 _OpcodeINTnnV86:
305
306 /* Get EFlags */
307 mov edx, [ebp+KTRAP_FRAME_EFLAGS]
308
309 /* Remove the flag in the VDM State */
310 mov eax, FIXED_NTVDMSTATE_LINEAR_PC_AT
311 mov ecx, [eax]
312 LOCK and dword ptr [eax], ~EFLAGS_INTERRUPT_MASK
313
314 /* Mask it out from EFLAGS too */
315 mov eax, edx
316 and eax, ~EFLAGS_INTERRUPT_MASK
317
318 /* Mask out the alignment check and IF flag from the VDM state */
319 and ecx, EFLAGS_ALIGN_CHECK + EFLAGS_INTERRUPT_MASK
320
321 /* FIXME: Support VME */
322
323 /* Now mask out VIF and TF */
324 or eax, ecx
325 and edx, ~(EFLAGS_VIF + EFLAGS_NESTED_TASK + EFLAGS_TF)
326 mov [ebp+KTRAP_FRAME_EFLAGS], edx
327
328 /* Set the IOPL Mask */
329 or eax, EFLAGS_IOPL
330
331 /* Get stack flat address */
332 movzx ecx, word ptr [ebp+KTRAP_FRAME_SS]
333 shl ecx, 4
334 movzx edx, word ptr [ebp+KTRAP_FRAME_ESP]
335
336 /* Push EFLAGS */
337 sub dx, 2
338 mov word ptr [ecx+edx], ax
339
340 /* Push CS */
341 mov ax, word ptr [ebp+KTRAP_FRAME_CS]
342 sub dx, 2
343 mov word ptr [ecx+edx], ax
344
345 /* Push IP */
346 movzx eax, word ptr [ebp+KTRAP_FRAME_EIP]
347 add eax, edi
348 inc eax
349 sub dx, 2
350 mov word ptr [ecx+edx], ax
351
352 /* Update ESP */
353 mov [ebp+KTRAP_FRAME_ESP], dx
354
355 /* Get the interrupt */
356 inc esi
357 movzx ecx, byte ptr [esi]
358 /* FIXME: Analyze and see if this is a hooked VDM (PM) Interrupt */
359
360 /* Get the entry in the IVT */
361 mov ebx, [ecx*4]
362 mov eax, ebx
363 shr eax, 16
364
365 /* Update EIP */
366 mov word ptr [ebp+KTRAP_FRAME_EIP], bx
367
368 /* Check if this was V86 mode */
369 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
370 jnz SetCs
371
372 /* Check if it was a kernel CS */
373 or ax, RPL_MASK
374 cmp ax, KGDT_R0_CODE
375 jnb SetCs
376
377 /* Set user-mode CS */
378 mov ax, KGDT_R3_CODE + RPL_MASK
379
380 SetCs:
381 /* Set new CS */
382 mov [ebp+KTRAP_FRAME_CS], ax
383
384 /* Return success */
385 mov eax, 1
386 ret
387 .endfunc
388
389 .func OpcodeINTOV86
390 _OpcodeINTOV86:
391 UNHANDLED_V86_OPCODE
392 .endfunc
393
394 .func OpcodeIRETV86
395 _OpcodeIRETV86:
396
397 /* Get the VDM State */
398 mov eax, FIXED_NTVDMSTATE_LINEAR_PC_AT
399
400 /* Get flat ESP */
401 movzx ecx, word ptr [ebp+KTRAP_FRAME_SS]
402 shl ecx, 4
403 movzx edx, word ptr [ebp+KTRAP_FRAME_ESP]
404 add ecx, edx
405
406 /* Check for OPER32 prefix */
407 test ebx, PREFIX_FLAG_OPER32
408 jnz Iret32
409
410 /* Get flat IP */
411 movzx edi, word ptr [ecx]
412 mov [ebp+KTRAP_FRAME_EIP], edi
413 movzx esi, word ptr [ecx+2]
414 mov [ebp+KTRAP_FRAME_CS], esi
415
416 /* Update ESP */
417 add edx, 6
418 mov [ebp+KTRAP_FRAME_ESP], edx
419
420 /* Get EFLAGS */
421 movzx ebx, word ptr [ecx+4]
422
423 MaskEFlags:
424
425 /* Mask out EFLAGS */
426 and ebx, ~(EFLAGS_IOPL + EFLAGS_VIF + EFLAGS_NESTED_TASK + EFLAGS_VIP)
427 mov ecx, ebx
428
429 /* FIXME: Check for VME support */
430
431 /* Save VDM state */
432 push eax
433
434 /* Enable V86 and Interrupts */
435 or ebx, EFLAGS_V86_MASK + EFLAGS_INTERRUPT_MASK
436
437 /* Save old flags */
438 mov eax, [ebp+KTRAP_FRAME_EFLAGS]
439 push eax
440
441 /* Mask out VIP and set new eflags */
442 and eax, EFLAGS_VIP
443 or eax, ebx
444 mov [ebp+KTRAP_FRAME_EFLAGS], eax
445
446 /* Check if we have to update ESP0 */
447 pop ebx
448 test ebx, EFLAGS_V86_MASK
449 jnz NoEsp0Update
450
451 /* Save ECX and ECX */
452 push ecx
453 push edx
454
455 /* Update esp0 and restore registers */
456 push ebp
457 call _Ki386AdjustEsp0@4
458 pop edx
459 pop ecx
460
461 NoEsp0Update:
462
463 /* Put VDM state in EAX and update VDM EFlags */
464 pop eax
465 and ecx, EFLAGS_INTERRUPT_MASK
466 LOCK and dword ptr [eax], ~EFLAGS_INTERRUPT_MASK
467 LOCK or [eax], ecx
468
469 /* Get flat EIP and check if this is the BOP */
470 shl esi, 4
471 add esi, edi
472 mov ax, [esi]
473 cmp ax, 0xC4C4
474 jz IsBop
475
476 /* FIXME: Check for VDM interrupts */
477
478 /* Return success */
479 RetIret:
480 mov eax, 1
481 ret
482
483 IsBop:
484
485 /* Call the BOP handler */
486 push ebp
487 call _VdmDispatchBop@4
488 jmp RetIret
489
490 Iret32:
491
492 /* Get 32-bit flat EIP */
493 mov edi, [ecx]
494 mov [ebp+KTRAP_FRAME_EIP], edi
495 movzx esi, word ptr [ecx+4]
496 mov [ebp+KTRAP_FRAME_CS], esi
497
498 /* Set new ESP */
499 add edx, 12
500 mov [ebp+KTRAP_FRAME_ESP], edx
501
502 /* Get EFLAGS and continue */
503 mov ebx, [ecx+8]
504 jmp MaskEFlags
505 .endfunc
506
507 .func OpcodeNPXV86
508 _OpcodeNPXV86:
509 UNHANDLED_V86_OPCODE
510 .endfunc
511
512 .func OpcodeINBimmV86
513 _OpcodeINBimmV86:
514 UNHANDLED_V86_OPCODE
515 .endfunc
516
517 .func OpcodeINWimmV86
518 _OpcodeINWimmV86:
519 UNHANDLED_V86_OPCODE
520 .endfunc
521
522 .func OpcodeOUTBimmV86
523 _OpcodeOUTBimmV86:
524 UNHANDLED_V86_OPCODE
525 .endfunc
526
527 .func OpcodeOUTWimmV86
528 _OpcodeOUTWimmV86:
529 UNHANDLED_V86_OPCODE
530 .endfunc
531
532 .func OpcodeINBV86
533 _OpcodeINBV86:
534 UNHANDLED_V86_OPCODE
535 .endfunc
536
537 .func OpcodeINWV86
538 _OpcodeINWV86:
539 UNHANDLED_V86_OPCODE
540 .endfunc
541
542 .func OpcodeOUTBV86
543 _OpcodeOUTBV86:
544 UNHANDLED_V86_OPCODE
545 .endfunc
546
547 .func OpcodeOUTWV86
548 _OpcodeOUTWV86:
549 UNHANDLED_V86_OPCODE
550 .endfunc
551
552 .func OpcodeCLIV86
553 _OpcodeCLIV86:
554
555 /* Get VDM State */
556 mov eax, FIXED_NTVDMSTATE_LINEAR_PC_AT
557
558 /* FIXME: Support VME */
559
560 /* FIXME: Support VDM Interrupts */
561
562 /* Disable interrupts */
563 LOCK and dword ptr [eax], ~EFLAGS_INTERRUPT_MASK
564
565 /* Update EIP (remember EDI == instruction size) */
566 add [ebp+KTRAP_FRAME_EIP], edi
567
568 /* Return success */
569 mov eax, 1
570 ret
571 .endfunc
572
573 .func OpcodeSTIV86
574 _OpcodeSTIV86:
575
576 /* Get VDM State */
577 mov eax, FIXED_NTVDMSTATE_LINEAR_PC_AT
578
579 /* FIXME: Support VME */
580
581 /* Enable interrupts */
582 LOCK or dword ptr [eax], EFLAGS_INTERRUPT_MASK
583
584 /* Update EIP (remember EDI == instruction size) */
585 add [ebp+KTRAP_FRAME_EIP], edi
586
587 /* FIXME: Support VDM Interrupts */
588
589 /* Return success */
590 mov eax, 1
591 ret
592 .endfunc
593
594 .func OpcodeGenericPrefixV86
595 _OpcodeGenericPrefixV86:
596
597 /* Skip instruction */
598 inc esi
599 inc edi
600
601 /* Get the instruction */
602 movzx ecx, byte ptr [esi]
603
604 /* Get the opcode index */
605 movzx edx, byte ptr OpcodeIndex[ecx]
606
607 /* Dispatch it */
608 jmp OpcodeDispatchV86[edx*4]
609 .endfunc
610
611 .func OpcodeHLTV86
612 _OpcodeHLTV86:
613 UNHANDLED_V86_OPCODE
614 .endfunc
615
616 /* FUNCTIONS *****************************************************************/
617
618 .globl _Ki386SetupAndExitToV86Mode@4
619 .func Ki386SetupAndExitToV86Mode@4
620 _Ki386SetupAndExitToV86Mode@4:
621
622 /* Save nonvolatiles */
623 push ebp
624 push ebx
625 push esi
626 push edi
627
628 /* Give us a little stack */
629 sub esp, 12
630 mov ecx, esp
631
632 /* Go past the KTRAP_FRAME and NPX Frame and set a new frame in EAX */
633 sub esp, NPX_FRAME_LENGTH
634 and esp, ~15
635 sub esp, KTRAP_FRAME_LENGTH
636 mov eax, esp
637
638 /* Create a fake user-mode frame */
639 mov dword ptr [eax+KTRAP_FRAME_CS], KGDT_R0_CODE + RPL_MASK
640 mov dword ptr [eax+KTRAP_FRAME_ES], 0
641 mov dword ptr [eax+KTRAP_FRAME_DS], 0
642 mov dword ptr [eax+KTRAP_FRAME_FS], 0
643 mov dword ptr [eax+KTRAP_FRAME_GS], 0
644 mov dword ptr [eax+KTRAP_FRAME_ERROR_CODE], 0
645
646 /* Get the current thread's initial stack */
647 mov ebx, [fs:KPCR_SELF]
648 mov edi, [ebx+KPCR_CURRENT_THREAD]
649 mov edx, [edi+KTHREAD_INITIAL_STACK]
650 sub edx, NPX_FRAME_LENGTH
651
652 /* Save it on our stack, as well as the real TEB addresses */
653 mov [ecx], edx
654 mov edx, [edi+KTHREAD_TEB]
655 mov [ecx+4], edx
656 mov edx, [fs:KPCR_TEB]
657 mov [ecx+8] , edx
658
659 /* Set our ESP in ESI, and the return function in EIP */
660 mov edi, offset _Ki386BiosCallReturnAddress
661 mov [eax+KTRAP_FRAME_ESI], ecx
662 mov [eax+KTRAP_FRAME_EIP], edi
663
664 /* Push the flags and sanitize them */
665 pushfd
666 pop edi
667 and edi, 0x60DD7
668 or edi, EFLAGS_INTERRUPT_MASK
669
670 /* Set SS and ESP, and fill out the rest of the frame */
671 mov dword ptr [eax+KTRAP_FRAME_SS], KGDT_R3_DATA + RPL_MASK;
672 mov dword ptr [eax+KTRAP_FRAME_ESP], 0x11FFE;
673 mov dword ptr [eax+KTRAP_FRAME_EFLAGS], edi
674 mov dword ptr [eax+KTRAP_FRAME_EXCEPTION_LIST], -1
675 mov dword ptr [eax+KTRAP_FRAME_PREVIOUS_MODE], -1
676 mov dword ptr [eax+KTRAP_FRAME_DR7], 0
677 mov dword ptr [eax+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
678
679 /* Jump past the frame now */
680 add eax, KTRAP_FRAME_LENGTH
681 cli
682
683 /* Save the current stack */
684 push ecx
685
686 /* Get the current thread's intial stack again */
687 mov edi, [ebx+KPCR_CURRENT_THREAD]
688 mov esi, [edi+KTHREAD_INITIAL_STACK]
689 sub esi, NPX_FRAME_LENGTH
690
691 /* Set the size of the copy, and the destination, and copy the NPX frame */
692 mov ecx, NPX_FRAME_LENGTH / 4
693 mov edi, eax
694 rep movsd
695
696 /* Restore stack */
697 pop ecx
698
699 /* Get the current thread and TSS */
700 mov edi, [ebx+KPCR_CURRENT_THREAD]
701 mov esi, [ebx+KPCR_TSS]
702
703 /* Bias the V86 vrame */
704 sub eax, KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS
705
706 /* Set exception list and new ESP */
707 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
708 mov [esi+KTSS_ESP0], eax
709
710 /* Now skip past the NPX frame and V86 fields and set this as the intial stack */
711 add eax, NPX_FRAME_LENGTH + (KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS)
712 mov [edi+KTHREAD_INITIAL_STACK], eax
713
714 /* Setup our fake TEB pointer */
715 mov eax, [ecx+0x20]
716 mov [fs:KPCR_TEB], eax
717 mov [edi+KTHREAD_TEB], eax
718
719 /* Setup the descriptors for the fake TEB */
720 mov ebx, [fs:KPCR_GDT]
721 mov [ebx+0x3A], ax
722 shr eax, 16
723 mov [ebx+0x3C], al
724 mov [ebx+0x3F], ah
725 sti
726
727 /*
728 * Start VDM execution. This will save this fake 32-bit KTRAP_FRAME and
729 * initialize a real 16-bit VDM context frame
730 */
731 push 0
732 push 0 // VdmStartExecution
733 call _NtVdmControl@8
734
735 /* Exit to V86 mode */
736 mov ebp, esp
737 jmp _Kei386EoiHelper@0
738 .endfunc
739
740 .globl _Ki386BiosCallReturnAddress
741 .func Ki386BiosCallReturnAddress
742 _Ki386BiosCallReturnAddress:
743
744 /* Get the PCR */
745 mov eax, [fs:KPCR_SELF]
746
747 /* Get NPX destination */
748 mov edi, [ebp+KTRAP_FRAME_ESI]
749 mov edi, [edi]
750
751 /* Get initial stack */
752 mov ecx, [eax+KPCR_CURRENT_THREAD]
753 mov esi, [ecx+KTHREAD_INITIAL_STACK]
754 sub esi, NPX_FRAME_LENGTH
755
756 /* Set length and copy the NPX frame */
757 mov ecx, NPX_FRAME_LENGTH / 4
758 rep movsd
759
760 /* Restore stack */
761 mov esp, [ebp+KTRAP_FRAME_ESI]
762 add esp, 4
763
764 /* Set initial stack */
765 mov ecx, [eax+KPCR_CURRENT_THREAD]
766 mov [ecx+KTHREAD_INITIAL_STACK], edi
767
768 /* Get TSS and set the ESP 0 */
769 mov eax, [eax+KPCR_TSS]
770 sub edi, NPX_FRAME_LENGTH + (KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS)
771 mov [eax+KTSS_ESP0], edi
772
773 /* Restore KTHREAD TEB in EDX */
774 pop edx
775 mov [ecx+KTHREAD_TEB], edx
776
777 /* Restore PCR TEB in EDX */
778 pop edx
779 mov [fs:KPCR_TEB], edx
780
781 /* Setup the descriptors for the real TEB */
782 mov ebx, [fs:KPCR_GDT]
783 mov [ebx+0x3A], dx
784 shr edx, 16
785 mov [ebx+0x3C], dl
786 mov [ebx+0x3F], dh
787
788 /* Enable interrupts and pop back non-volatiles */
789 sti
790 pop edi
791 pop esi
792 pop ebx
793 pop ebp
794 ret 4
795 .endfunc
796
797 .globl _Ki386HandleOpcodeV86@0
798 .func Ki386HandleOpcodeV86@0
799 _Ki386HandleOpcodeV86@0:
800
801 /* Get flat EIP */
802 mov esi, [ebp+KTRAP_FRAME_CS]
803 shl esi, 4
804 add esi, [ebp+KTRAP_FRAME_EIP]
805
806 /* Get the opcode entry in the table */
807 movzx ecx, byte ptr [esi]
808 movzx edx, byte ptr OpcodeIndex[ecx]
809
810 /* Set instruction length and prefix flags */
811 mov edi, 1
812 xor ebx, ebx
813
814 /* Accounting statistics */
815 // inc dword ptr _ExVdmOpcodeDispatchCounts[edx*4] // FIXME: Generates protection fault
816
817 /* Handle the opcode */
818 jmp OpcodeDispatchV86[edx*4]
819 .endfunc