2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/i386/v86vdm.c
5 * PURPOSE: Manages the Kernel's support for Virtual-8086 Mode (V86)
6 * used by Video Drivers to access ROM BIOS functions, as well
7 * as the kernel architecture part of generic VDM support.
8 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
11 /* INCLUDES ******************************************************************/
17 /* GLOBALS *******************************************************************/
19 ULONG KeI386EFlagsAndMaskV86
= EFLAGS_USER_SANITIZE
;
20 ULONG KeI386EFlagsOrMaskV86
= EFLAGS_INTERRUPT_MASK
;
21 PVOID Ki386IopmSaveArea
;
22 BOOLEAN KeI386VirtualIntExtensions
= FALSE
;
24 /* PRIVATE FUNCTIONS *********************************************************/
26 /* PUBLIC FUNCTIONS **********************************************************/
33 Ke386CallBios(IN ULONG Int
,
36 PUCHAR Trampoline
= (PUCHAR
)TRAMPOLINE_BASE
;
37 PTEB VdmTeb
= (PTEB
)TRAMPOLINE_TEB
;
38 PVDM_TIB VdmTib
= (PVDM_TIB
)TRAMPOLINE_TIB
;
39 ULONG ContextSize
= FIELD_OFFSET(CONTEXT
, ExtendedRegisters
);
40 PKTHREAD Thread
= KeGetCurrentThread();
41 PKTSS Tss
= KeGetPcr()->TSS
;
42 PKPROCESS Process
= Thread
->ApcState
.Process
;
43 PVDM_PROCESS_OBJECTS VdmProcessObjects
;
44 USHORT OldOffset
, OldBase
;
46 /* Start with a clean TEB */
47 RtlZeroMemory(VdmTeb
, sizeof(TEB
));
49 /* Write the interrupt and bop */
51 *Trampoline
++ = (UCHAR
)Int
;
52 *(PULONG
)Trampoline
= TRAMPOLINE_BOP
;
54 /* Setup the VDM TEB and TIB */
55 VdmTeb
->Vdm
= (PVOID
)TRAMPOLINE_TIB
;
56 RtlZeroMemory(VdmTib
, sizeof(VDM_TIB
));
57 VdmTib
->Size
= sizeof(VDM_TIB
);
59 /* Set a blank VDM state */
62 /* Copy the context */
63 RtlCopyMemory(&VdmTib
->VdmContext
, Context
, ContextSize
);
64 VdmTib
->VdmContext
.SegCs
= (ULONG_PTR
)Trampoline
>> 4;
65 VdmTib
->VdmContext
.SegSs
= (ULONG_PTR
)Trampoline
>> 4;
66 VdmTib
->VdmContext
.Eip
= 0;
67 VdmTib
->VdmContext
.Esp
= 2 * PAGE_SIZE
- sizeof(ULONG_PTR
);
68 VdmTib
->VdmContext
.EFlags
|= EFLAGS_V86_MASK
| EFLAGS_INTERRUPT_MASK
;
69 VdmTib
->VdmContext
.ContextFlags
= CONTEXT_FULL
;
71 /* This can't be a real VDM process */
72 ASSERT(PsGetCurrentProcess()->VdmObjects
== NULL
);
74 /* Allocate VDM structure */
75 VdmProcessObjects
= ExAllocatePoolWithTag(NonPagedPool
,
76 sizeof(VDM_PROCESS_OBJECTS
),
77 TAG('K', 'e', ' ', ' '));
78 if (!VdmProcessObjects
) return STATUS_NO_MEMORY
;
81 RtlZeroMemory(VdmProcessObjects
, sizeof(VDM_PROCESS_OBJECTS
));
82 VdmProcessObjects
->VdmTib
= VdmTib
;
83 PsGetCurrentProcess()->VdmObjects
= VdmProcessObjects
;
85 /* Set the system affinity for the current thread */
86 KeSetSystemAffinityThread(1);
88 /* Make sure there's space for two IOPMs, then copy & clear the current */
89 //ASSERT(((PKGDTENTRY)&KeGetPcr()->GDT[KGDT_TSS / 8])->LimitLow >=
90 // (0x2000 + IOPM_OFFSET - 1));
91 RtlCopyMemory(Ki386IopmSaveArea
, &Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
92 RtlZeroMemory(&Tss
->IoMaps
[0].IoMap
, PAGE_SIZE
* 2);
94 /* Save the old offset and base, and set the new ones */
95 OldOffset
= Process
->IopmOffset
;
96 OldBase
= Tss
->IoMapBase
;
97 Process
->IopmOffset
= (USHORT
)IOPM_OFFSET
;
98 Tss
->IoMapBase
= (USHORT
)IOPM_OFFSET
;
100 /* Switch stacks and work the magic */
101 Ki386SetupAndExitToV86Mode(VdmTeb
);
104 RtlCopyMemory(&Tss
->IoMaps
[0].IoMap
, Ki386IopmSaveArea
, PAGE_SIZE
* 2);
105 Process
->IopmOffset
= OldOffset
;
106 Tss
->IoMapBase
= OldBase
;
108 /* Restore affinity */
109 KeRevertToUserAffinityThread();
111 /* Restore context */
112 RtlCopyMemory(Context
, &VdmTib
->VdmContext
, ContextSize
);
113 Context
->ContextFlags
= CONTEXT_FULL
;
115 /* Free VDM objects */
116 ExFreePool(PsGetCurrentProcess()->VdmObjects
);
117 PsGetCurrentProcess()->VdmObjects
= NULL
;
120 return STATUS_SUCCESS
;