6ce335e44c3d4a189cc15a2f2bafcf2fb7558d68
[reactos.git] / lib / soft386 / common.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: 386/486 CPU Emulation Library
4 * FILE: common.c
5 * PURPOSE: Common functions used internally by Soft386.
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "common.h"
12
13 /* PUBLIC FUNCTIONS ***********************************************************/
14
15 inline
16 BOOLEAN
17 Soft386ReadMemory(PSOFT386_STATE State,
18 INT SegmentReg,
19 ULONG Offset,
20 BOOLEAN InstFetch,
21 PVOID Buffer,
22 ULONG Size)
23 {
24 ULONG LinearAddress;
25 PSOFT386_SEG_REG CachedDescriptor;
26
27 ASSERT(SegmentReg < SOFT386_NUM_SEG_REGS);
28
29 /* Get the cached descriptor */
30 CachedDescriptor = &State->SegmentRegs[SegmentReg];
31
32 if ((Offset + Size) >= CachedDescriptor->Limit)
33 {
34 /* Read beyond limit */
35 // TODO: Generate exception #GP
36
37 return FALSE;
38 }
39
40 /* Check for protected mode */
41 if (State->ControlRegisters[0] & SOFT386_CR0_PE)
42 {
43 /* Privilege checks */
44
45 if (!CachedDescriptor->Present)
46 {
47 // TODO: Generate exception #NP
48 return FALSE;
49 }
50
51 if (GET_SEGMENT_DPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl)
52 {
53 // TODO: Generate exception #GP
54 return FALSE;
55 }
56
57 if (InstFetch)
58 {
59 if (!CachedDescriptor->Executable)
60 {
61 /* Data segment not executable */
62
63 // TODO: Generate exception #GP
64 return FALSE;
65 }
66 }
67 else
68 {
69 if (CachedDescriptor->Executable && (!CachedDescriptor->ReadWrite))
70 {
71 /* Code segment not readable */
72
73 // TODO: Generate exception #GP
74 return FALSE;
75 }
76 }
77 }
78
79 /* Find the linear address */
80 LinearAddress = CachedDescriptor->Base + Offset;
81
82 // TODO: Paging support!
83
84 /* Did the host provide a memory hook? */
85 if (State->MemReadCallback)
86 {
87 /* Yes, call the host */
88 State->MemReadCallback(State, LinearAddress, Buffer, Size);
89 }
90 else
91 {
92 /* Read the memory directly */
93 RtlMoveMemory(Buffer, (LPVOID)LinearAddress, Size);
94 }
95
96 return TRUE;
97 }
98
99 inline
100 BOOLEAN
101 Soft386WriteMemory(PSOFT386_STATE State,
102 INT SegmentReg,
103 ULONG Offset,
104 PVOID Buffer,
105 ULONG Size)
106 {
107 ULONG LinearAddress;
108 PSOFT386_SEG_REG CachedDescriptor;
109
110 ASSERT(SegmentReg < SOFT386_NUM_SEG_REGS);
111
112 /* Get the cached descriptor */
113 CachedDescriptor = &State->SegmentRegs[SegmentReg];
114
115 if ((Offset + Size) >= CachedDescriptor->Limit)
116 {
117 /* Write beyond limit */
118 // TODO: Generate exception #GP
119
120 return FALSE;
121 }
122
123 /* Check for protected mode */
124 if (State->ControlRegisters[0] & SOFT386_CR0_PE)
125 {
126 /* Privilege checks */
127
128 if (!CachedDescriptor->Present)
129 {
130 // TODO: Generate exception #NP
131 return FALSE;
132 }
133
134 if (GET_SEGMENT_DPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl)
135 {
136 // TODO: Generate exception #GP
137 return FALSE;
138 }
139
140 if (CachedDescriptor->Executable)
141 {
142 /* Code segment not writable */
143
144 // TODO: Generate exception #GP
145 return FALSE;
146 }
147 else if (!CachedDescriptor->ReadWrite)
148 {
149 /* Data segment not writeable */
150
151 // TODO: Generate exception #GP
152 return FALSE;
153 }
154 }
155
156 /* Find the linear address */
157 LinearAddress = CachedDescriptor->Base + Offset;
158
159 // TODO: Paging support!
160
161 /* Did the host provide a memory hook? */
162 if (State->MemWriteCallback)
163 {
164 /* Yes, call the host */
165 State->MemWriteCallback(State, LinearAddress, Buffer, Size);
166 }
167 else
168 {
169 /* Write the memory directly */
170 RtlMoveMemory((LPVOID)LinearAddress, Buffer, Size);
171 }
172
173 return TRUE;
174 }
175
176 inline
177 BOOLEAN
178 Soft386StackPush(PSOFT386_STATE State, ULONG Value)
179 {
180 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_SS].Size;
181
182 // TODO: Handle OPSIZE prefix.
183
184 if (Size)
185 {
186 /* 32-bit size */
187
188 /* Check if ESP is between 1 and 3 */
189 if (State->GeneralRegs[SOFT386_REG_ESP].Long >= 1
190 && State->GeneralRegs[SOFT386_REG_ESP].Long <= 3)
191 {
192 // TODO: Exception #SS
193 return FALSE;
194 }
195
196 /* Subtract ESP by 4 */
197 State->GeneralRegs[SOFT386_REG_ESP].Long -= 4;
198
199 /* Store the value in SS:ESP */
200 return Soft386WriteMemory(State,
201 SOFT386_REG_SS,
202 State->GeneralRegs[SOFT386_REG_ESP].Long,
203 &Value,
204 sizeof(ULONG));
205 }
206 else
207 {
208 /* 16-bit size */
209 USHORT ShortValue = LOWORD(Value);
210
211 /* Check if SP is 1 */
212 if (State->GeneralRegs[SOFT386_REG_ESP].Long == 1)
213 {
214 // TODO: Exception #SS
215 return FALSE;
216 }
217
218 /* Subtract SP by 2 */
219 State->GeneralRegs[SOFT386_REG_ESP].LowWord -= 2;
220
221 /* Store the value in SS:SP */
222 return Soft386WriteMemory(State,
223 SOFT386_REG_SS,
224 State->GeneralRegs[SOFT386_REG_ESP].LowWord,
225 &ShortValue,
226 sizeof(USHORT));
227 }
228 }
229
230 inline
231 BOOLEAN
232 Soft386StackPop(PSOFT386_STATE State, PULONG Value)
233 {
234 ULONG LongValue;
235 USHORT ShortValue;
236 BOOLEAN Size = State->SegmentRegs[SOFT386_REG_SS].Size;
237
238 // TODO: Handle OPSIZE prefix.
239
240 if (Size)
241 {
242 /* 32-bit size */
243
244 /* Check if ESP is 0xFFFFFFFF */
245 if (State->GeneralRegs[SOFT386_REG_ESP].Long == 0xFFFFFFFF)
246 {
247 // TODO: Exception #SS
248 return FALSE;
249 }
250
251 /* Read the value from SS:ESP */
252 if (!Soft386ReadMemory(State,
253 SOFT386_REG_SS,
254 State->GeneralRegs[SOFT386_REG_ESP].Long,
255 FALSE,
256 &LongValue,
257 sizeof(LongValue)))
258 {
259 /* An exception occurred */
260 return FALSE;
261 }
262
263 /* Increment ESP by 4 */
264 State->GeneralRegs[SOFT386_REG_ESP].Long += 4;
265
266 /* Store the value in the result */
267 *Value = LongValue;
268 }
269 else
270 {
271 /* 16-bit size */
272
273 /* Check if SP is 0xFFFF */
274 if (State->GeneralRegs[SOFT386_REG_ESP].LowWord == 0xFFFF)
275 {
276 // TODO: Exception #SS
277 return FALSE;
278 }
279
280 /* Read the value from SS:SP */
281 if (!Soft386ReadMemory(State,
282 SOFT386_REG_SS,
283 State->GeneralRegs[SOFT386_REG_ESP].LowWord,
284 FALSE,
285 &ShortValue,
286 sizeof(ShortValue)))
287 {
288 /* An exception occurred */
289 return FALSE;
290 }
291
292 /* Increment SP by 2 */
293 State->GeneralRegs[SOFT386_REG_ESP].Long += 2;
294
295 /* Store the value in the result */
296 *Value = ShortValue;
297 }
298
299 return TRUE;
300 }
301
302 /* EOF */