94d0250f13d5e84e070cfadc1be768f4d14d2fc8
[reactos.git] / reactos / ntoskrnl / ke / i386 / v86m_sup.S
1 /*
2 * FILE: ntoskrnl/ke/i386/vm86_sup.S
3 * PURPOSE: V86 mode support
4 * PROGRAMMER: David Welch (welch@cwcom.net)
5 * UPDATE HISTORY:
6 * Created 09/10/00
7 */
8
9 #include <internal/asm.h>
10
11 .globl _Ki386RetToV86Mode
12 .globl _KiV86Complete
13
14 /*
15 * VOID Ki386RetToV86Mode(KV86M_REGISTERS* InRegs,
16 * KV86M_REGISTERS* OutRegs);
17 *
18 * Starts in v86 mode with the registers set to the
19 * specified values.
20 */
21 _Ki386RetToV86Mode:
22 /*
23 * Setup a stack frame
24 */
25 pushl %ebp
26 movl %esp, %ebp
27
28 /*
29 * Save registers
30 */
31 pusha
32
33 /*
34 * Get a pointer to IN_REGS
35 */
36 movl 8(%ebp), %ebx
37
38 /*
39 * Save ebp
40 */
41 pushl %ebp
42
43 /*
44 * Save a pointer to IN_REGS which the v86m exception handler will
45 * use to handle exceptions
46 */
47 pushl %ebx
48
49 /*
50 * Since we are going to fiddle with the stack pointer this must be
51 * a critical section for this processor
52 */
53 cli
54
55 /*
56 * Save the exception handler stack from the TSS
57 */
58 movl %fs:KPCR_TSS, %esi
59 pushl KTSS_ESP0(%esi)
60
61 /*
62 * The stack used for handling exceptions from v86 mode in this thread
63 * will be the current stack adjusted so we don't overwrite the
64 * existing stack frames
65 */
66 movl %esp, KTSS_ESP0(%esi)
67
68 /*
69 * Create the stack frame for an iret to v86 mode
70 */
71 pushl KV86M_REGISTERS_GS(%ebx)
72 pushl KV86M_REGISTERS_FS(%ebx)
73 pushl KV86M_REGISTERS_DS(%ebx)
74 pushl KV86M_REGISTERS_ES(%ebx)
75 pushl KV86M_REGISTERS_SS(%ebx)
76 pushl KV86M_REGISTERS_ESP(%ebx)
77 pushl KV86M_REGISTERS_EFLAGS(%ebx)
78 pushl KV86M_REGISTERS_CS(%ebx)
79 pushl KV86M_REGISTERS_EIP(%ebx)
80
81 /*
82 * Setup the CPU registers
83 */
84 movl KV86M_REGISTERS_EAX(%ebx), %eax
85 movl KV86M_REGISTERS_ECX(%ebx), %ecx
86 movl KV86M_REGISTERS_EDX(%ebx), %edx
87 movl KV86M_REGISTERS_ESI(%ebx), %esi
88 movl KV86M_REGISTERS_EDI(%ebx), %edi
89 movl KV86M_REGISTERS_EBP(%ebx), %ebp
90 movl KV86M_REGISTERS_EBX(%ebx), %ebx
91
92 /*
93 * Go to v86 mode
94 */
95 iret
96
97 /*
98 * Handle the completion of a vm86 routine. We are called from
99 * an exception handler with the registers at the point of the
100 * exception on the stack.
101 */
102 _KiV86Complete:
103 /* Restore the original ebp */
104 movl TF_ORIG_EBP(%esp), %ebp
105
106 /* Get a pointer to the OUT_REGS structure */
107 movl 12(%ebp), %ebx
108
109 /* Skip debug information and unsaved registers */
110 addl $0x30, %esp
111
112 /* Ignore 32-bit segment registers */
113 addl $12, %esp
114
115 /* Save the vm86 registers into the OUT_REGS structure */
116 popl KV86M_REGISTERS_EDX(%ebx)
117 popl KV86M_REGISTERS_ECX(%ebx)
118 popl KV86M_REGISTERS_EAX(%ebx)
119
120 /* Restore the old previous mode */
121 popl %eax
122 movb %al, %ss:KTHREAD_PREVIOUS_MODE(%esi)
123
124 /* Restore the old exception handler list */
125 popl %eax
126 movl %eax, %fs:KPCR_EXCEPTION_LIST
127
128 /* Ignore the 32-bit fs register */
129 addl $4, %esp
130
131 popl KV86M_REGISTERS_EDI(%ebx)
132 popl KV86M_REGISTERS_ESI(%ebx)
133 popl KV86M_REGISTERS_EBX(%ebx)
134 popl KV86M_REGISTERS_EBP(%ebx)
135
136 /* Ignore error code */
137 addl $4, %esp
138
139 popl KV86M_REGISTERS_EIP(%ebx)
140 popl KV86M_REGISTERS_CS(%ebx)
141 popl KV86M_REGISTERS_EFLAGS(%ebx)
142 popl KV86M_REGISTERS_ESP(%ebx)
143 popl KV86M_REGISTERS_SS(%ebx)
144 popl KV86M_REGISTERS_ES(%ebx)
145 popl KV86M_REGISTERS_DS(%ebx)
146 popl KV86M_REGISTERS_FS(%ebx)
147 popl KV86M_REGISTERS_GS(%ebx)
148
149 /*
150 * We are going to fiddle with the stack so this must be a critical
151 * section for this process
152 */
153 cli
154
155 /*
156 * Restore the exception handler stack in the TSS
157 */
158 movl %fs:KPCR_TSS, %esi
159 popl KTSS_ESP0(%esi)
160
161 /* Exit the critical section */
162 sti
163
164 /* Ignore IN_REGS pointer */
165 addl $4, %esp
166
167 /* Ignore ebp restored above */
168 addl $4, %esp
169
170 /* Return to caller */
171 popa
172 movl %ebp, %esp
173 popl %ebp
174 ret
175