[NTVDM]
[reactos.git] / reactos / subsystems / ntvdm / cpu / callback.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: callback.c
5 * PURPOSE: 16 and 32-bit Callbacks Support
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /******************************************************************************\
11 | WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
12 |
13 | Callbacks support supposes implicitely that the callbacks are used
14 | in the SAME thread as the CPU thread, otherwise messing in parallel
15 | with the CPU registers is 100% prone to bugs!!
16 \******************************************************************************/
17
18 /* INCLUDES *******************************************************************/
19
20 #define NDEBUG
21
22 #include "cpu.h"
23 #include "callback.h"
24 #include "emulator.h"
25
26 #include "bop.h"
27 #include <isvbop.h>
28
29 /* PRIVATE VARIABLES **********************************************************/
30
31 #define TRAMPOLINE_SIZE sizeof(ULONGLONG)
32
33 static BYTE Yield[] =
34 {
35 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
36 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // 13x nop
37 BOP(BOP_UNSIMULATE), // UnSimulate16 BOP
38 };
39 C_ASSERT(sizeof(Yield) == 16 * sizeof(BYTE));
40
41 /* PUBLIC FUNCTIONS ***********************************************************/
42
43 VOID
44 InitializeContextEx(IN PCALLBACK16 Context,
45 IN ULONG TrampolineSize,
46 IN USHORT Segment,
47 IN USHORT Offset)
48 {
49 Context->TrampolineFarPtr = MAKELONG(Offset, Segment);
50 Context->TrampolineSize = max(TRAMPOLINE_SIZE, TrampolineSize);
51 Context->Segment = Segment;
52 Context->NextOffset = Offset + Context->TrampolineSize;
53 }
54
55 VOID
56 InitializeContext(IN PCALLBACK16 Context,
57 IN USHORT Segment,
58 IN USHORT Offset)
59 {
60 InitializeContextEx(Context,
61 TRAMPOLINE_SIZE,
62 Segment,
63 Offset);
64 }
65
66 VOID
67 Call16(IN USHORT Segment,
68 IN USHORT Offset)
69 {
70 /* Save CS:IP */
71 USHORT OrgCS = getCS();
72 USHORT OrgIP = getIP();
73
74 /* Set the new CS:IP */
75 setCS(Segment);
76 setIP(Offset);
77
78 DPRINT("Call16(%04X:%04X)\n", Segment, Offset);
79
80 /* Start CPU simulation */
81 CpuSimulate();
82
83 /* Restore CS:IP */
84 setCS(OrgCS);
85 setIP(OrgIP);
86 }
87
88 VOID
89 RunCallback16(IN PCALLBACK16 Context,
90 IN ULONG FarPtr)
91 {
92 PUCHAR TrampolineBase = (PUCHAR)FAR_POINTER(Context->TrampolineFarPtr);
93 PUCHAR Trampoline = TrampolineBase;
94 UCHAR OldTrampoline[TRAMPOLINE_SIZE];
95
96 /* Save the old trampoline */
97 ((PULONGLONG)&OldTrampoline)[0] = ((PULONGLONG)TrampolineBase)[0];
98
99 DPRINT("RunCallback16(0x%p)\n", FarPtr);
100
101 /* Build the generic entry-point for 16-bit far calls */
102 *Trampoline++ = 0x9A; // Call far seg:off
103 *(PULONG)Trampoline = FarPtr;
104 Trampoline += sizeof(ULONG);
105 UnSimulate16(Trampoline);
106
107 /* Perform the call */
108 Call16(HIWORD(Context->TrampolineFarPtr),
109 LOWORD(Context->TrampolineFarPtr));
110
111 /* Restore the old trampoline */
112 ((PULONGLONG)TrampolineBase)[0] = ((PULONGLONG)&OldTrampoline)[0];
113 }
114
115 ULONG
116 RegisterCallback16(IN ULONG FarPtr,
117 IN LPBYTE CallbackCode,
118 IN SIZE_T CallbackSize,
119 OUT PSIZE_T CodeSize OPTIONAL)
120 {
121 LPBYTE CodeStart = (LPBYTE)FAR_POINTER(FarPtr);
122 LPBYTE Code = CodeStart;
123
124 SIZE_T OurCodeSize = CallbackSize;
125
126 if (CallbackCode == NULL) CallbackSize = 0;
127
128 if (CallbackCode)
129 {
130 /* 16-bit interrupt code */
131 RtlCopyMemory(Code, CallbackCode, CallbackSize);
132 Code += CallbackSize;
133 }
134
135 /* Return the real size of the code if needed */
136 if (CodeSize) *CodeSize = OurCodeSize; // == (ULONG_PTR)Code - (ULONG_PTR)CodeStart;
137
138 // /* Return the entry-point address for 32-bit calls */
139 // return (ULONG_PTR)(CodeStart + CallbackSize);
140 return OurCodeSize;
141 }
142
143 /* EOF */