Trap handlers in C patch 7 of X:
[reactos.git] / reactos / ntoskrnl / ke / i386 / v86vdm.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ke/i386/v86vdm.c
5 * PURPOSE: V8086 and VDM Trap Emulation
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 * Alex Ionescu (alex.ionescu@reactos.org)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS ********************************************************************/
17
18 ULONG KeI386EFlagsAndMaskV86 = EFLAGS_USER_SANITIZE;
19 ULONG KeI386EFlagsOrMaskV86 = EFLAGS_INTERRUPT_MASK;
20 PVOID Ki386IopmSaveArea;
21 BOOLEAN KeI386VirtualIntExtensions = FALSE;
22 const PULONG KiNtVdmState = (PULONG)FIXED_NTVDMSTATE_LINEAR_PC_AT;
23
24 /* UNHANDLED OPCODES **********************************************************/
25
26 KiVdmUnhandledOpcode(F);
27 KiVdmUnhandledOpcode(OUTSW);
28 KiVdmUnhandledOpcode(OUTSB);
29 KiVdmUnhandledOpcode(INSB);
30 KiVdmUnhandledOpcode(INSW);
31 KiVdmUnhandledOpcode(NPX);
32 KiVdmUnhandledOpcode(INBimm);
33 KiVdmUnhandledOpcode(INWimm);
34 KiVdmUnhandledOpcode(OUTBimm);
35 KiVdmUnhandledOpcode(OUTWimm);
36 KiVdmUnhandledOpcode(INB);
37 KiVdmUnhandledOpcode(INW);
38 KiVdmUnhandledOpcode(OUTB);
39 KiVdmUnhandledOpcode(OUTW);
40 KiVdmUnhandledOpcode(HLT);
41 KiVdmUnhandledOpcode(INTO);
42 KiVdmUnhandledOpcode(INV);
43
44 /* OPCODE HANDLERS ************************************************************/
45
46 BOOLEAN
47 FASTCALL
48 KiVdmOpcodePUSHF(IN PKTRAP_FRAME TrapFrame,
49 IN ULONG Flags)
50 {
51 ULONG Esp, V86EFlags, TrapEFlags;
52
53 /* Get current V8086 flags and mask out interrupt flag */
54 V86EFlags = *KiNtVdmState;
55 V86EFlags &= ~EFLAGS_INTERRUPT_MASK;
56
57 /* Get trap frame EFLags and leave only align, nested task and interrupt */
58 TrapEFlags = TrapFrame->EFlags;
59 TrapEFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
60
61 /* Add in those flags if they exist, and add in the IOPL flag */
62 V86EFlags |= TrapEFlags;
63 V86EFlags |= EFLAGS_IOPL;
64
65 /* Build flat ESP */
66 Esp = (TrapFrame->HardwareSegSs << 4) + (USHORT)TrapFrame->HardwareEsp;
67 Esp -= 2;
68
69 /* Check for OPER32 */
70 if (Flags & PFX_FLAG_OPER32)
71 {
72 /* Save EFlags */
73 Esp -= 2;
74 *(PULONG)(Esp - 2) = V86EFlags;
75 }
76 else
77 {
78 /* Save EFLags */
79 *(PUSHORT)Esp = (USHORT)V86EFlags;
80 }
81
82 /* Set new ESP and EIP */
83 TrapFrame->HardwareEsp = (USHORT)Esp;
84 TrapFrame->Eip += (Flags & 0xFF);
85
86 /* We're done */
87 return TRUE;
88 }
89
90 BOOLEAN
91 FASTCALL
92 KiVdmOpcodePOPF(IN PKTRAP_FRAME TrapFrame,
93 IN ULONG Flags)
94 {
95 ULONG Esp, V86EFlags, EFlags, TrapEFlags;
96
97 /* Build flat ESP */
98 Esp = (TrapFrame->HardwareSegSs << 4) + (USHORT)TrapFrame->HardwareEsp;
99
100 /* Read EFlags */
101 EFlags = *(PULONG)Esp;
102 Esp += 4;
103
104 /* Check for OPER32 */
105 if (!(Flags & PFX_FLAG_OPER32))
106 {
107 /* Read correct flags and use correct stack address */
108 Esp -= 2;
109 EFlags &= 0xFFFF;
110 }
111
112 /* Set new ESP */
113 TrapFrame->HardwareEsp = Esp;
114
115 /* Mask out IOPL from the flags */
116 EFlags &= ~EFLAGS_IOPL;
117
118 /* Save the V86 flags, but mask out the nested task flag */
119 V86EFlags = EFlags & ~EFLAGS_NESTED_TASK;
120
121 /* Now leave only alignment, nested task and interrupt flag */
122 EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
123
124 /* FIXME: Check for VME support */
125
126 /* Add V86 and Interrupt flag */
127 V86EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK;
128
129 /* Update EFlags in trap frame */
130 TrapEFlags = TrapFrame->EFlags;
131 TrapFrame->EFlags = (TrapFrame->EFlags & EFLAGS_VIP) | V86EFlags;
132
133 /* Check if ESP0 needs to be fixed up */
134 if (TrapEFlags & EFLAGS_V86_MASK) Ki386AdjustEsp0(TrapFrame);
135
136 /* Update the V8086 EFlags state */
137 KiVdmClearVdmEFlags(EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
138 KiVdmSetVdmEFlags(EFlags);
139
140 /* FIXME: Check for VDM interrupts */
141
142 /* Update EIP */
143 TrapFrame->Eip += (Flags & 0xFF);
144
145 /* We're done */
146 return TRUE;
147 }
148
149 BOOLEAN
150 FASTCALL
151 KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame,
152 IN ULONG Flags)
153 {
154 ULONG Esp, V86EFlags, TrapEFlags, Eip, Interrupt;
155
156 /* Read trap frame EFlags */
157 TrapEFlags = TrapFrame->EFlags;
158
159 /* Remove interrupt flag from V8086 EFlags */
160 V86EFlags = *KiNtVdmState;
161 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
162
163 /* Keep only alignment and interrupt flag from the V8086 state */
164 V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_INTERRUPT_MASK);
165
166 /* FIXME: Support VME */
167
168 /* Mask in the relevant V86 EFlags into the trap flags */
169 V86EFlags |= (TrapEFlags & ~EFLAGS_INTERRUPT_MASK);
170
171 /* And mask out the VIF, nested task and TF flag from the trap flags */
172 TrapFrame->EFlags = TrapEFlags &~ (EFLAGS_VIF | EFLAGS_NESTED_TASK | EFLAGS_TF);
173
174 /* Add the IOPL flag to the local trap flags */
175 V86EFlags |= EFLAGS_IOPL;
176
177 /* Build flat ESP */
178 Esp = (TrapFrame->HardwareSegSs << 4) + TrapFrame->HardwareEsp;
179
180 /* Push EFlags */
181 Esp -= 2;
182 *(PUSHORT)(Esp) = (USHORT)V86EFlags;
183
184 /* Push CS */
185 Esp -= 2;
186 *(PUSHORT)(Esp) = (USHORT)TrapFrame->SegCs;
187
188 /* Push IP */
189 Esp -= 2;
190 *(PUSHORT)(Esp) = (USHORT)TrapFrame->Eip + (Flags & 0xFF) + 1;
191
192 /* Update ESP */
193 TrapFrame->HardwareEsp = (USHORT)Esp;
194
195 /* Get flat EIP */
196 Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip;
197
198 /* Now get the *next* EIP address (current is original + the count - 1) */
199 Eip += (Flags & 0xFF);
200
201 /* Now read the interrupt number */
202 Interrupt = *(PUCHAR)Eip;
203
204 /* Read the EIP from its IVT entry */
205 Interrupt = *(PULONG)(Interrupt * 4);
206 TrapFrame->Eip = (USHORT)Interrupt;
207
208 /* Now get the CS segment */
209 Interrupt = (USHORT)(Interrupt >> 16);
210
211 /* Check if the trap was not V8086 trap */
212 if (!(TrapFrame->EFlags & EFLAGS_V86_MASK))
213 {
214 /* Was it a kernel CS? */
215 Interrupt |= RPL_MASK;
216 if (TrapFrame->SegCs == KGDT_R0_CODE)
217 {
218 /* Add the RPL mask */
219 TrapFrame->SegCs = Interrupt;
220 }
221 else
222 {
223 /* Set user CS */
224 TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
225 }
226 }
227 else
228 {
229 /* Set IVT CS */
230 TrapFrame->SegCs = Interrupt;
231 }
232
233 /* We're done */
234 return TRUE;
235 }
236
237 BOOLEAN
238 FASTCALL
239 KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame,
240 IN ULONG Flags)
241 {
242 ULONG Esp, V86EFlags, EFlags, TrapEFlags, Eip;
243
244 /* Build flat ESP */
245 Esp = (TrapFrame->HardwareSegSs << 4) + TrapFrame->HardwareEsp;
246
247 /* Check for OPER32 */
248 if (Flags & PFX_FLAG_OPER32)
249 {
250 /* Build segmented EIP */
251 TrapFrame->Eip = *(PULONG)Esp;
252 TrapFrame->SegCs = *(PUSHORT)(Esp + 4);
253
254 /* Set new ESP */
255 TrapFrame->HardwareEsp += 12;
256
257 /* Get EFLAGS */
258 EFlags = *(PULONG)(Esp + 8);
259 }
260 else
261 {
262 /* Build segmented EIP */
263 TrapFrame->Eip = *(PUSHORT)Esp;
264 TrapFrame->SegCs = *(PUSHORT)(Esp + 2);
265
266 /* Set new ESP */
267 TrapFrame->HardwareEsp += 6;
268
269 /* Get EFLAGS */
270 EFlags = *(PUSHORT)(Esp + 4);
271 }
272
273 /* Mask out EFlags */
274 EFlags &= ~(EFLAGS_IOPL + EFLAGS_VIF + EFLAGS_NESTED_TASK + EFLAGS_VIP);
275 V86EFlags = EFlags;
276
277 /* FIXME: Check for VME support */
278
279 /* Add V86 and Interrupt flag */
280 EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK;
281
282 /* Update EFlags in trap frame */
283 TrapEFlags = TrapFrame->EFlags;
284 TrapFrame->EFlags = (TrapFrame->EFlags & EFLAGS_VIP) | EFlags;
285
286 /* Check if ESP0 needs to be fixed up */
287 if (!(TrapEFlags & EFLAGS_V86_MASK)) Ki386AdjustEsp0(TrapFrame);
288
289 /* Update the V8086 EFlags state */
290 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
291 KiVdmSetVdmEFlags(V86EFlags);
292
293 /* Build flat EIP and check if this is the BOP instruction */
294 Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip;
295 if (*(PUSHORT)Eip == 0xC4C4)
296 {
297 /* Dispatch the BOP */
298 VdmDispatchBop(TrapFrame);
299 }
300 else
301 {
302 /* FIXME: Check for VDM interrupts */
303 }
304
305 /* We're done */
306 return TRUE;
307 }
308
309 BOOLEAN
310 FASTCALL
311 KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame,
312 IN ULONG Flags)
313 {
314 /* FIXME: Support VME */
315
316 /* disable interrupts */
317 KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
318
319 /* Skip instruction */
320 TrapFrame->Eip += (Flags & 0xFF);
321
322 /* Done */
323 return TRUE;
324 }
325
326 BOOLEAN
327 FASTCALL
328 KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame,
329 IN ULONG Flags)
330 {
331 /* FIXME: Support VME */
332
333 /* Enable interrupts */
334 KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK);
335
336 /* Skip instruction */
337 TrapFrame->Eip += (Flags & 0xFF);
338
339 /* Done */
340 return TRUE;
341 }
342
343 /* MASTER OPCODE HANDLER ******************************************************/
344
345 BOOLEAN
346 FASTCALL
347 KiVdmHandleOpcode(IN PKTRAP_FRAME TrapFrame,
348 IN ULONG Flags)
349 {
350 ULONG Eip;
351
352 /* Get flat EIP of the *current* instruction (not the original EIP) */
353 Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip;
354 Eip += (Flags & 0xFF) - 1;
355
356 /* Read the opcode entry */
357 switch (*(PUCHAR)Eip)
358 {
359 case 0xF: return KiCallVdmHandler(F);
360 case 0x26: return KiCallVdmPrefixHandler(PFX_FLAG_ES);
361 case 0x2E: return KiCallVdmPrefixHandler(PFX_FLAG_CS);
362 case 0x36: return KiCallVdmPrefixHandler(PFX_FLAG_SS);
363 case 0x3E: return KiCallVdmPrefixHandler(PFX_FLAG_DS);
364 case 0x64: return KiCallVdmPrefixHandler(PFX_FLAG_FS);
365 case 0x65: return KiCallVdmPrefixHandler(PFX_FLAG_GS);
366 case 0x66: return KiCallVdmPrefixHandler(PFX_FLAG_OPER32);
367 case 0x67: return KiCallVdmPrefixHandler(PFX_FLAG_ADDR32);
368 case 0xF0: return KiCallVdmPrefixHandler(PFX_FLAG_LOCK);
369 case 0xF2: return KiCallVdmPrefixHandler(PFX_FLAG_REPNE);
370 case 0xF3: return KiCallVdmPrefixHandler(PFX_FLAG_REP);
371 case 0x6C: return KiCallVdmHandler(INSB);
372 case 0x6D: return KiCallVdmHandler(INSW);
373 case 0x6E: return KiCallVdmHandler(OUTSB);
374 case 0x6F: return KiCallVdmHandler(OUTSW);
375 case 0x98: return KiCallVdmHandler(NPX);
376 case 0xD8: return KiCallVdmHandler(NPX);
377 case 0xD9: return KiCallVdmHandler(NPX);
378 case 0xDA: return KiCallVdmHandler(NPX);
379 case 0xDB: return KiCallVdmHandler(NPX);
380 case 0xDC: return KiCallVdmHandler(NPX);
381 case 0xDD: return KiCallVdmHandler(NPX);
382 case 0xDE: return KiCallVdmHandler(NPX);
383 case 0xDF: return KiCallVdmHandler(NPX);
384 case 0x9C: return KiCallVdmHandler(PUSHF);
385 case 0x9D: return KiCallVdmHandler(POPF);
386 case 0xCD: return KiCallVdmHandler(INTnn);
387 case 0xCE: return KiCallVdmHandler(INTO);
388 case 0xCF: return KiCallVdmHandler(IRET);
389 case 0xE4: return KiCallVdmHandler(INBimm);
390 case 0xE5: return KiCallVdmHandler(INWimm);
391 case 0xE6: return KiCallVdmHandler(OUTBimm);
392 case 0xE7: return KiCallVdmHandler(OUTWimm);
393 case 0xEC: return KiCallVdmHandler(INB);
394 case 0xED: return KiCallVdmHandler(INW);
395 case 0xEE: return KiCallVdmHandler(OUTB);
396 case 0xEF: return KiCallVdmHandler(OUTW);
397 case 0xF4: return KiCallVdmHandler(HLT);
398 case 0xFA: return KiCallVdmHandler(CLI);
399 case 0xFB: return KiCallVdmHandler(STI);
400 default: return KiCallVdmHandler(INV);
401 }
402 }
403
404 /* PREFIX HANDLER *************************************************************/
405
406 BOOLEAN
407 FASTCALL
408 KiVdmOpcodePrefix(IN PKTRAP_FRAME TrapFrame,
409 IN ULONG Flags)
410 {
411 /* Increase instruction size */
412 Flags++;
413
414 /* Handle the next opcode */
415 return KiVdmHandleOpcode(TrapFrame, Flags);
416 }
417
418 /* TRAP HANDLER ***************************************************************/
419
420 BOOLEAN
421 FASTCALL
422 Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame)
423 {
424 /* Clean up */
425 TrapFrame->Eip &= 0xFFFF;
426 TrapFrame->HardwareEsp &= 0xFFFF;
427
428 /* We start with only 1 byte per instruction */
429 return KiVdmHandleOpcode(TrapFrame, 1);
430 }
431
432 VOID
433 FASTCALL
434 KiExitV86Mode(IN PKTRAP_FRAME TrapFrame)
435 {
436 PKV8086_STACK_FRAME StackFrame;
437 PKGDTENTRY GdtEntry;
438 PKTHREAD Thread;
439 PKTRAP_FRAME PmTrapFrame;
440 PKV86_FRAME V86Frame;
441 PFX_SAVE_AREA NpxFrame;
442
443 /* Get the stack frame back */
444 StackFrame = CONTAINING_RECORD(TrapFrame->Esi, KV8086_STACK_FRAME, V86Frame);
445 PmTrapFrame = &StackFrame->TrapFrame;
446 V86Frame = &StackFrame->V86Frame;
447 NpxFrame = &StackFrame->NpxArea;
448
449 /* Copy the FPU frame back */
450 Thread = KeGetCurrentThread();
451 RtlCopyMemory(KiGetThreadNpxArea(Thread), NpxFrame, sizeof(FX_SAVE_AREA));
452
453 /* Set initial stack back */
454 Thread->InitialStack = (PVOID)((ULONG_PTR)V86Frame->ThreadStack + sizeof(FX_SAVE_AREA));
455
456 /* Set ESP0 back in the KTSS */
457 KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&PmTrapFrame->V86Es;
458
459 /* Restore TEB addresses */
460 Thread->Teb = V86Frame->ThreadTeb;
461 KeGetPcr()->Tib.Self = V86Frame->PcrTeb;
462
463 /* Setup real TEB descriptor */
464 GdtEntry = &((PKIPCR)KeGetPcr())->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)];
465 GdtEntry->BaseLow = (USHORT)((ULONG_PTR)Thread->Teb & 0xFFFF);
466 GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Thread->Teb >> 16);
467 GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Thread->Teb >> 24);
468
469 /* Enable interrupts and get back to protected mode */
470 _enable();
471 KiV86TrapReturn(TrapFrame->Edi);
472 }
473
474 VOID
475 FASTCALL
476 KiEnterV86Mode(VOID)
477 {
478 PKTHREAD Thread;
479 PKGDTENTRY GdtEntry;
480 KV8086_STACK_FRAME StackFrameBuffer;
481 PKV8086_STACK_FRAME StackFrame = &StackFrameBuffer;
482 PKTRAP_FRAME TrapFrame = &StackFrame->TrapFrame;
483 PKV86_FRAME V86Frame = &StackFrame->V86Frame;
484 PFX_SAVE_AREA NpxFrame = &StackFrame->NpxArea;
485
486 /* Build fake user-mode trap frame */
487 TrapFrame->SegCs = KGDT_R0_CODE | RPL_MASK;
488 TrapFrame->SegEs = TrapFrame->SegDs = TrapFrame->SegFs = TrapFrame->SegGs = 0;
489 TrapFrame->ErrCode = 0;
490
491 /* Get the current thread's initial stack */
492 Thread = KeGetCurrentThread();
493 V86Frame->ThreadStack = KiGetThreadNpxArea(Thread);
494
495 /* Save TEB addresses */
496 V86Frame->ThreadTeb = Thread->Teb;
497 V86Frame->PcrTeb = KeGetPcr()->Tib.Self;
498
499 /* Save return EIP */
500 TrapFrame->Eip = (ULONG_PTR)KiExitV86Mode;
501
502 /* Save our stack (after the frames) */
503 TrapFrame->Esi = (ULONG_PTR)V86Frame;
504 TrapFrame->Edi = (ULONG_PTR)_AddressOfReturnAddress() + 4;
505
506 /* Sanitize EFlags and enable interrupts */
507 TrapFrame->EFlags = __readeflags() & 0x60DD7;
508 TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
509
510 /* Fill out the rest of the frame */
511 TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK;
512 TrapFrame->HardwareEsp = 0x11FFE;
513 TrapFrame->ExceptionList = EXCEPTION_CHAIN_END;
514 TrapFrame->Dr7 = 0;
515 //TrapFrame->DbgArgMark = 0xBADB0D00;
516 TrapFrame->PreviousPreviousMode = -1;
517
518 /* Disable interrupts */
519 _disable();
520
521 /* Copy the thread's NPX frame */
522 RtlCopyMemory(NpxFrame, V86Frame->ThreadStack, sizeof(FX_SAVE_AREA));
523
524 /* Clear exception list */
525 KeGetPcr()->Tib.ExceptionList = EXCEPTION_CHAIN_END;
526
527 /* Set new ESP0 */
528 KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&TrapFrame->V86Es;
529
530 /* Set new initial stack */
531 Thread->InitialStack = V86Frame;
532
533 /* Set VDM TEB */
534 Thread->Teb = (PTEB)TRAMPOLINE_TEB;
535 KeGetPcr()->Tib.Self = (PVOID)TRAMPOLINE_TEB;
536
537 /* Setup VDM TEB descriptor */
538 GdtEntry = &((PKIPCR)KeGetPcr())->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)];
539 GdtEntry->BaseLow = (USHORT)((ULONG_PTR)TRAMPOLINE_TEB & 0xFFFF);
540 GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)TRAMPOLINE_TEB >> 16);
541 GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)TRAMPOLINE_TEB >> 24);
542
543 /* Enable interrupts */
544 _enable();
545
546 /* Start VDM execution */
547 NtVdmControl(VdmStartExecution, NULL);
548
549 /* Exit to V86 mode */
550 KiEoiHelper(TrapFrame);
551 }
552
553 /* PUBLIC FUNCTIONS ***********************************************************/
554
555 /*
556 * @implemented
557 */
558 NTSTATUS
559 NTAPI
560 Ke386CallBios(IN ULONG Int,
561 OUT PCONTEXT Context)
562 {
563 PUCHAR Trampoline = (PUCHAR)TRAMPOLINE_BASE;
564 PTEB VdmTeb = (PTEB)TRAMPOLINE_TEB;
565 PVDM_TIB VdmTib = (PVDM_TIB)TRAMPOLINE_TIB;
566 ULONG ContextSize = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
567 PKTHREAD Thread = KeGetCurrentThread();
568 PKTSS Tss = KeGetPcr()->TSS;
569 PKPROCESS Process = Thread->ApcState.Process;
570 PVDM_PROCESS_OBJECTS VdmProcessObjects;
571 USHORT OldOffset, OldBase;
572
573 /* Start with a clean TEB */
574 RtlZeroMemory(VdmTeb, sizeof(TEB));
575
576 /* Write the interrupt and bop */
577 *Trampoline++ = 0xCD;
578 *Trampoline++ = (UCHAR)Int;
579 *(PULONG)Trampoline = TRAMPOLINE_BOP;
580
581 /* Setup the VDM TEB and TIB */
582 VdmTeb->Vdm = (PVOID)TRAMPOLINE_TIB;
583 RtlZeroMemory(VdmTib, sizeof(VDM_TIB));
584 VdmTib->Size = sizeof(VDM_TIB);
585
586 /* Set a blank VDM state */
587 *VdmState = 0;
588
589 /* Copy the context */
590 RtlCopyMemory(&VdmTib->VdmContext, Context, ContextSize);
591 VdmTib->VdmContext.SegCs = (ULONG_PTR)Trampoline >> 4;
592 VdmTib->VdmContext.SegSs = (ULONG_PTR)Trampoline >> 4;
593 VdmTib->VdmContext.Eip = 0;
594 VdmTib->VdmContext.Esp = 2 * PAGE_SIZE - sizeof(ULONG_PTR);
595 VdmTib->VdmContext.EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK;
596 VdmTib->VdmContext.ContextFlags = CONTEXT_FULL;
597
598 /* This can't be a real VDM process */
599 ASSERT(PsGetCurrentProcess()->VdmObjects == NULL);
600
601 /* Allocate VDM structure */
602 VdmProcessObjects = ExAllocatePoolWithTag(NonPagedPool,
603 sizeof(VDM_PROCESS_OBJECTS),
604 ' eK');
605 if (!VdmProcessObjects) return STATUS_NO_MEMORY;
606
607 /* Set it up */
608 RtlZeroMemory(VdmProcessObjects, sizeof(VDM_PROCESS_OBJECTS));
609 VdmProcessObjects->VdmTib = VdmTib;
610 PsGetCurrentProcess()->VdmObjects = VdmProcessObjects;
611
612 /* Set the system affinity for the current thread */
613 KeSetSystemAffinityThread(1);
614
615 /* Make sure there's space for two IOPMs, then copy & clear the current */
616 ASSERT(((PKIPCR)KeGetPcr())->GDT[KGDT_TSS / 8].LimitLow >=
617 (0x2000 + IOPM_OFFSET - 1));
618 RtlCopyMemory(Ki386IopmSaveArea, &Tss->IoMaps[0].IoMap, PAGE_SIZE * 2);
619 RtlZeroMemory(&Tss->IoMaps[0].IoMap, PAGE_SIZE * 2);
620
621 /* Save the old offset and base, and set the new ones */
622 OldOffset = Process->IopmOffset;
623 OldBase = Tss->IoMapBase;
624 Process->IopmOffset = (USHORT)IOPM_OFFSET;
625 Tss->IoMapBase = (USHORT)IOPM_OFFSET;
626
627 /* Switch stacks and work the magic */
628 Ki386SetupAndExitToV86Mode(VdmTeb);
629
630 /* Restore IOPM */
631 RtlCopyMemory(&Tss->IoMaps[0].IoMap, Ki386IopmSaveArea, PAGE_SIZE * 2);
632 Process->IopmOffset = OldOffset;
633 Tss->IoMapBase = OldBase;
634
635 /* Restore affinity */
636 KeRevertToUserAffinityThread();
637
638 /* Restore context */
639 RtlCopyMemory(Context, &VdmTib->VdmContext, ContextSize);
640 Context->ContextFlags = CONTEXT_FULL;
641
642 /* Free VDM objects */
643 ExFreePool(PsGetCurrentProcess()->VdmObjects);
644 PsGetCurrentProcess()->VdmObjects = NULL;
645
646 /* Return status */
647 return STATUS_SUCCESS;
648 }
649
650 /*
651 * @unimplemented
652 */
653 BOOLEAN
654 NTAPI
655 Ke386IoSetAccessProcess(IN PKPROCESS Process,
656 IN ULONG Flag)
657 {
658 UNIMPLEMENTED;
659 return FALSE;
660 }
661
662 /*
663 * @unimplemented
664 */
665 BOOLEAN
666 NTAPI
667 Ke386SetIoAccessMap(IN ULONG Flag,
668 IN PVOID IopmBuffer)
669 {
670 UNIMPLEMENTED;
671 return FALSE;
672 }
673
674 /*
675 * @unimplemented
676 */
677 BOOLEAN
678 NTAPI
679 Ke386QueryIoAccessMap(IN ULONG Flag,
680 IN PVOID IopmBuffer)
681 {
682 UNIMPLEMENTED;
683 return FALSE;
684 }