…Show last 788 lines
61 if ((loadresult = LOADDESCRIPTOR(segment,*segmentval,&LOADEDDESCRIPTOR,isJMPorCALL))<=0) //Error loading current descriptor?
62 {
63 if (loadresult == 0) //Not already faulted?
64 {
65 //if ((segment == CPU_SEGMENT_SS) && (isJMPorCALL & 0x200) && ((isJMPorCALL & 0x8000) == 0)) goto throwSSsegmentval;
66 goto throwdescsegmentval;
67 }
68 return NULL; //Error, by specified reason!
69 }
70 allowNP = ((segment==CPU_SEGMENT_DS) || (segment==CPU_SEGMENT_ES) || (segment==CPU_SEGMENT_FS) || (segment==CPU_SEGMENT_GS)); //Allow segment to be marked non-present(exception: values 0-3 with data segments)?
71
72 if (((*segmentval&~3)==0)) //NULL GDT segment when not allowed?
73 {
74 if (segment==CPU_SEGMENT_LDTR) //in LDTR? We're valid!
75 {
76 goto validLDTR; //Skip all checks, and check out as valid! We're allowed on the LDTR only!
77 }
78 else //Skip checks: we're invalid to check any further!
79 {
80 if ((segment==CPU_SEGMENT_CS) || (segment==CPU_SEGMENT_TR) || (segment==CPU_SEGMENT_SS)) //Not allowed?
81 {
82 //if ((segment == CPU_SEGMENT_SS) && (isJMPorCALL & 0x200) && ((isJMPorCALL & 0x8000) == 0)) goto throwSSsegmentval;
83 goto throwdescsegmentval; //Throw #GP error!
84 return NULL; //Error, by specified reason!
85 }
86 else if (allowNP)
87 {
88 goto validLDTR; //Load NULL descriptor!
89 }
90 }
91 }
92
93 if ((isGateDescriptor(&LOADEDDESCRIPTOR)==1) && (segment == CPU_SEGMENT_CS) && (((isJMPorCALL&0x1FF)==1) || ((isJMPorCALL&0x1FF)==2)) && ((isJMPorCALL&0x200)==0)) //Handling of gate descriptors? Disable on task code/data segment loading!
94 {
95 is_gated = 1; //We're gated!
96 memcpy(&GATEDESCRIPTOR, &LOADEDDESCRIPTOR, sizeof(GATEDESCRIPTOR)); //Copy the loaded descriptor to the GATE!
97 //Check for invalid loads!
98 switch (GENERALSEGMENT_TYPE(GATEDESCRIPTOR))
99 {
100 default: //Unknown type?
101 case AVL_SYSTEM_INTERRUPTGATE16BIT:
102 case AVL_SYSTEM_TRAPGATE16BIT:
103 case AVL_SYSTEM_INTERRUPTGATE32BIT:
104 case AVL_SYSTEM_TRAPGATE32BIT:
105 /*
106 if ((isJMPorCALL & 0x1FF) == 2) //CALL? It's an programmed interrupt call!
107 {
108 CPU_handleInterruptGate(((isJMPorCALL&0x400)>>10),(*segmentval & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT, (*segmentval & 0xFFF8), &LOADEDDESCRIPTOR.desc, REG_CS, REG_EIP, -2, 1); //Raise an interrupt instead!
109 return NULL; //Abort: we're handled by the interrupt handler!
110 }
111 */ //80386 user manual CALL instruction reference says that interrupt and other gates being loaded end up with a General Protection fault.
112 //JMP isn't valid for interrupt gates?
113 //We're an invalid gate!
114 goto throwdescsegmentval; //Throw #GP error!
115 return NULL; //Not present: invalid descriptor type loaded!
116 break;
117 case AVL_SYSTEM_TASKGATE: //Task gate?
118 case AVL_SYSTEM_CALLGATE16BIT:
119 case AVL_SYSTEM_CALLGATE32BIT:
120 //Valid gate! Allow!
121 break;
122 }
123 if ((MAX(effectiveCPL(), getRPL(*segmentval)) > GENERALSEGMENT_DPL(GATEDESCRIPTOR)) && ((isJMPorCALL&0x1FF)!=3)) //Gate has too high a privilege level? Only when not an IRET(always allowed)!
124 {
125 goto throwdescsegmentval; //Throw error!
126 return NULL; //We are a lower privilege level, so don't load!
127 }
128 if (GENERALSEGMENT_P(GATEDESCRIPTOR)==0) //Not present loaded into non-data segment register?
129 {
130 if (segment==CPU_SEGMENT_SS) //Stack fault?
131 {
132 THROWDESCSS(*segmentval,(isJMPorCALL&0x200)?1:(((isJMPorCALL&0x400)>>10)),(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Stack fault!
133 }
134 else
135 {
136 THROWDESCNP(*segmentval, (isJMPorCALL&0x200)?1:(((isJMPorCALL&0x400)>>10)),(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
137 }
138 return NULL; //We're an invalid TSS to execute!
139 }
140
141 *segmentval = GATEDESCRIPTOR.desc.selector; //We're loading this segment now, with requesting privilege!
142
143 if (((*segmentval&~3)==0)) //NULL GDT segment when not allowed?
144 {
145 goto throwdescsegmentval; //Throw #GP(0) error!
146 return NULL; //Abort!
147 }
148
149 if ((loadresult = LOADDESCRIPTOR(segment, *segmentval, &LOADEDDESCRIPTOR,isJMPorCALL))<=0) //Error loading current descriptor?
150 {
151 if (loadresult == 0) //Not faulted already?
152 {
153 goto throwdescsegmentval; //Throw error!
154 }
155 return NULL; //Error, by specified reason!
156 }
157 privilegedone = 1; //Privilege has been precalculated!
158 if (GENERALSEGMENT_TYPE(GATEDESCRIPTOR) == AVL_SYSTEM_TASKGATE) //Task gate?
159 {
160 if (segment != CPU_SEGMENT_CS) //Not code? We're not a task switch! We're trying to load the task segment into a data register. This is illegal! TR doesn't support Task Gates directly(hardware only)!
161 {
162 goto throwdescsegmentval; //Throw error!
163 return NULL; //Don't load!
164 }
165 }
166 else //Normal descriptor?
167 {
168 if (GENERALSEGMENT_S(LOADEDDESCRIPTOR)==0) goto throwdescsegmentval;
169 if (((isJMPorCALL&0x1FF) == 1) && (!EXECSEGMENT_C(LOADEDDESCRIPTOR))) //JMP to a nonconforming segment?
170 {
171 if (GENERALSEGMENT_DPL(LOADEDDESCRIPTOR) != effectiveCPL()) //Different CPL?
172 {
173 goto throwdescsegmentval; //Throw error!
174 return NULL; //We are a different privilege level, so don't load!
175 }
176 }
177 else if (isJMPorCALL&0x1FF) //Call instruction (or JMP instruction to a conforming segment)
178 {
179 if (GENERALSEGMENT_DPL(LOADEDDESCRIPTOR) > effectiveCPL()) //We have a lower CPL?
180 {
181 goto throwdescsegmentval; //Throw error!
182 return NULL; //We are a different privilege level, so don't load!
183 }
184 }
185 }
186 }
187
188 switch (GENERALSEGMENT_TYPE(LOADEDDESCRIPTOR)) //We're a TSS? We're to perform a task switch!
189 {
190 case AVL_SYSTEM_BUSY_TSS16BIT:
191 case AVL_SYSTEM_TSS16BIT: //TSS?
192 case AVL_SYSTEM_BUSY_TSS32BIT:
193 case AVL_SYSTEM_TSS32BIT: //TSS?
194 is_TSS = (isGateDescriptor(&LOADEDDESCRIPTOR)==-1); //We're a TSS when a system segment!
195 break;
196 default:
197 is_TSS = 0; //We're no TSS!
198 break;
199 }
200
201 byte isnonconformingcode;
202 isnonconformingcode = EXECSEGMENT_ISEXEC(LOADEDDESCRIPTOR) && (!EXECSEGMENT_C(LOADEDDESCRIPTOR)) && (getLoadedTYPE(&LOADEDDESCRIPTOR) == 1); //non-conforming code?
203 //Now check for CPL,DPL&RPL! (chapter 6.3.2)
204 if (
205 (
206 (!privilegedone && (getRPL(*segmentval)<effectiveCPL()) && (((isJMPorCALL&0x1FF)==4)||(isJMPorCALL&0x1FF)==3)) || //IRET/RETF to higher privilege level?
207 ((GENERALSEGMENT_DPL(LOADEDDESCRIPTOR)>effectiveCPL()) && (EXECSEGMENT_ISEXEC(LOADEDDESCRIPTOR) && (getLoadedTYPE(&LOADEDDESCRIPTOR) == 1)) && (((isJMPorCALL&0x1FF)==2) || ((isJMPorCALL&0x1FF)==1))) || //CALL/JMP to a lower privilege?
208 (!privilegedone && (MAX(effectiveCPL(),getRPL(*segmentval))>GENERALSEGMENT_DPL(LOADEDDESCRIPTOR)) && (((getLoadedTYPE(&LOADEDDESCRIPTOR)!=1) && (segment!=CPU_SEGMENT_SS)) || (isnonconformingcode && (segment!=CPU_SEGMENT_CS))) && ((isJMPorCALL&0x1FF)!=4) && ((isJMPorCALL&0x1FF)!=3)) || //We are a lower privilege level with either a data/system segment descriptor? Non-conforming code segments have different check for code segments only, but the same rule for data segments:
209 (!privilegedone && (MAX((((isJMPorCALL&0x1FF)==4)||((isJMPorCALL&0x1FF)==3))?getRPL(*segmentval):effectiveCPL(),getRPL(*segmentval))<GENERALSEGMENT_DPL(LOADEDDESCRIPTOR)) && (EXECSEGMENT_ISEXEC(LOADEDDESCRIPTOR) && (EXECSEGMENT_C(LOADEDDESCRIPTOR)) && (getLoadedTYPE(&LOADEDDESCRIPTOR) == 1))) || //We must be at the same privilege level or higher compared to MAX(CPL,RPL) (or just RPL for RETF) for conforming code segment descriptors?
210 (!privilegedone && ((((((isJMPorCALL&0x1FF)==4)||((isJMPorCALL&0x1FF)==3))?getRPL(*segmentval):effectiveCPL())!=GENERALSEGMENT_DPL(LOADEDDESCRIPTOR))) && isnonconformingcode && (segment==CPU_SEGMENT_CS)) || //We must be at the same privilege level compared to CPL (or RPL for RETF) for non-conforming code segment descriptors? Not for data segment selectors(the same as data segment descriptors).
211 (!privilegedone && ((effectiveCPL()!=getRPL(*segmentval)) || (effectiveCPL()!=GENERALSEGMENT_DPL(LOADEDDESCRIPTOR))) && (segment==CPU_SEGMENT_SS)) //SS DPL must match CPL and RPL!
212 )
213 && (!(((isJMPorCALL&0x1FF)==3) && is_TSS)) //No privilege checking is done on IRET through TSS!
214 && (!((isJMPorCALL&0x80)==0x80)) //Don't ignore privilege?
215 )
216 {
217 //if ((segment == CPU_SEGMENT_SS) && (isJMPorCALL & 0x200) && ((isJMPorCALL & 0x8000) == 0)) goto throwSSoriginalval;
218 //if ((segment == CPU_SEGMENT_SS) && (isJMPorCALL & 0x200) && ((isJMPorCALL & 0x8000) == 0)) goto throwSSoriginalval;
219 throwdescoriginalval:
220 if (isJMPorCALL & 0x200) //TSS is the cause?
221 {
222 THROWDESCTS(originalval, 1, (originalval & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //Throw error!
223 }
224 else //Plain #GP?
225 {
226 THROWDESCGP(originalval, ((isJMPorCALL & 0x400) >> 10), (originalval & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //Throw error!
227 }
228 return NULL; //Not present: limit exceeded!
229 /*
230 throwSSoriginalval:
231 THROWDESCSS(originalval,((isJMPorCALL&0x400)>>10),(originalval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
232 return NULL; //Not present: limit exceeded!
233 */
234 }
235
236 if (is_TSS && (*segmentval & 4)) //TSS in LDT detected? That's not allowed!
237 {
238 goto throwdescoriginalval; //Throw error!
239 return NULL; //Error out!
240 }
241
242 if ((segment==CPU_SEGMENT_CS) && is_TSS && ((isJMPorCALL&0x200)==0)) //Special stuff on CS, CPL, Task switch.
243 {
244 //Present is handled by the task switch mechanism, so don't check it here!
245
246 //Execute a normal task switch!
247 if (CPU_executionphase_starttaskswitch(segment,&LOADEDDESCRIPTOR,segmentval,*segmentval,isJMPorCALL,is_gated,-1)) //Switching to a certain task?
248 {
249 return NULL; //Error changing priviledges or anything else!
250 }
251
252 //We've properly switched to the destination task! Continue execution normally!
253 return NULL; //Don't actually load CS with the descriptor: we've caused a task switch after all!
254 }
255
256 if ((segment == CPU_SEGMENT_CS) && (is_gated == 0) && (getLoadedTYPE(&LOADEDDESCRIPTOR)==1) && (((isJMPorCALL & 0x1FF) == 2)||((isJMPorCALL & 0x1FF) == 1))) //CALL/JMP to lower or different privilege?
257 {
258 if ((GENERALSEGMENT_DPL(LOADEDDESCRIPTOR) > effectiveCPL()) && EXECSEGMENT_C(LOADEDDESCRIPTOR)) //Conforming and lower privilege?
259 {
260 goto throwdescoriginalval; //Throw #GP error!
261 }
262 if (((getRPL(*segmentval) > effectiveCPL()) || (GENERALSEGMENT_DPL(LOADEDDESCRIPTOR) != effectiveCPL())) && !EXECSEGMENT_C(LOADEDDESCRIPTOR)) //Non-conforming and different privilege or lowering privilege?
263 {
264 goto throwdescoriginalval; //Throw #GP error!
265 }
266 //Non-conforming always must match CPL, so we don't handle it here(it's in the generic check)!
267 }
268
269 //Handle invalid types to load now!
270 switch (getLoadedTYPE(&LOADEDDESCRIPTOR))
271 {
272 case 0: //Data descriptor?
273 if ((segment==CPU_SEGMENT_CS) || (segment==CPU_SEGMENT_LDTR) || (segment==CPU_SEGMENT_TR)) //Data descriptor in invalid type?
274 {
275 goto throwdescsegmentval; //Throw #GP error!
276 return NULL; //Not present: invalid descriptor type loaded!
277 }
278 if ((DATASEGMENT_W(LOADEDDESCRIPTOR) == 0) && (segment == CPU_SEGMENT_SS)) //Non-writable SS segment?
279 {
280 goto throwdescsegmentval; //Throw #GP error!
281 return NULL; //Not present: invalid descriptor type loaded!
282 }
283 break;
284 case 1: //Executable descriptor?
285 if ((segment != CPU_SEGMENT_CS) && (EXECSEGMENT_R(LOADEDDESCRIPTOR) == 0)) //Executable non-readable in non-executable segment?
286 {
287 goto throwdescsegmentval; //Throw #GP error!
288 return NULL; //Not present: invalid descriptor type loaded!
289 }
290 if (((segment == CPU_SEGMENT_LDTR) || (segment == CPU_SEGMENT_TR) || (segment == CPU_SEGMENT_SS))) //Executable segment in invalid register?
291 {
292 goto throwdescsegmentval; //Throw #GP error!
293 return NULL; //Not present: invalid descriptor type loaded!
294 }
295 break;
296 case 2: //System descriptor?
297 if ((segment!=CPU_SEGMENT_LDTR) && (segment!=CPU_SEGMENT_TR)) //System descriptor in invalid register?
298 {
299 goto throwdescsegmentval; //Throw #GP error!
300 return NULL; //Not present: invalid descriptor type loaded!
301 }
302 if ((segment == CPU_SEGMENT_LDTR) && (GENERALSEGMENT_TYPE(LOADEDDESCRIPTOR) != AVL_SYSTEM_LDT)) //Invalid LDT load?
303 {
304 goto throwdescsegmentval; //Throw #GP error!
305 return NULL; //Not present: invalid descriptor type loaded!
306 }
307 if ((segment == CPU_SEGMENT_TR) && (is_TSS == 0)) //Non-TSS into task register?
308 {
309 goto throwdescsegmentval; //Throw #GP error!
310 return NULL; //Not present: invalid descriptor type loaded!
311 }
312 break;
313 default: //Unknown descriptor type? Count as invalid!
314 goto throwdescsegmentval; //Throw #GP error!
315 return NULL; //Not present: invalid descriptor type loaded!
316 break;
317 }
318
319 //Make sure we're present last!
320 if (GENERALSEGMENT_P(LOADEDDESCRIPTOR)==0) //Not present loaded into non-data NULL register?
321 {
322 if (segment==CPU_SEGMENT_SS) //Stack fault?
323 {
324 goto throwSSsegmentval;
325 }
326 else
327 {
328 THROWDESCNP(*segmentval,(isJMPorCALL&0x200)?1:((isJMPorCALL&0x400)>>10),(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
329 }
330 return NULL; //We're an invalid TSS to execute!
331 }
332
333
334 if ((segment == CPU_SEGMENT_CS) && (isGateDescriptor(&GATEDESCRIPTOR) == 1) && (is_gated)) //Gated CS?
335 {
336 switch (GENERALSEGMENT_TYPE(GATEDESCRIPTOR)) //What type of gate are we using?
337 {
338 case AVL_SYSTEM_CALLGATE16BIT: //16-bit call gate?
339 callgatetype = 1; //16-bit call gate!
340 break;
341 case AVL_SYSTEM_CALLGATE32BIT: //32-bit call gate?
342 callgatetype = 2; //32-bit call gate!
343 break;
344 default:
345 callgatetype = 0; //No call gate!
346 break;
347 }
348 if (callgatetype) //To process a call gate's parameters and offsets?
349 {
350 destEIP = (uint_32)GATEDESCRIPTOR.desc.callgate_base_low; //16-bit EIP!
351 if (callgatetype == 2) //32-bit destination?
352 {
353 destEIP |= (((uint_32)GATEDESCRIPTOR.desc.callgate_base_mid)<<16); //Mid EIP!
354 destEIP |= (((uint_32)GATEDESCRIPTOR.desc.callgate_base_high)<<24); //High EIP!
355 }
356 uint_32 argument; //Current argument to copy to the destination stack!
357 word arguments;
358 CPU[activeCPU].CallGateParamCount = 0; //Clear our stack to transfer!
359 CPU[activeCPU].CallGateSize = (callgatetype==2)?1:0; //32-bit vs 16-bit call gate!
360
361 if ((GENERALSEGMENT_DPL(LOADEDDESCRIPTOR)<effectiveCPL()) && (EXECSEGMENT_C(LOADEDDESCRIPTOR)==0) && ((isJMPorCALL&0x1FF)==2)) //Stack switch required (with CALL only)?
362 {
363 //Now, copy the stack arguments!
364
365 *isdifferentCPL = 1; //We're a different level!
366 arguments = CALLGATE_NUMARGUMENTS = (GATEDESCRIPTOR.desc.ParamCnt&0x1F); //Amount of parameters!
367 CPU[activeCPU].CallGateParamCount = 0; //Initialize the amount of arguments that we're storing!
368 if (checkStackAccess(arguments,0,(callgatetype==2)?1:0)) return NULL; //Abort on stack fault!
369 for (;arguments--;) //Copy as many arguments as needed!
370 {
371 if (callgatetype==2) //32-bit source?
372 {
373 argument = MMU_rdw(CPU_SEGMENT_SS, REG_SS, REG_ESP&getstackaddrsizelimiter(), 0,!STACK_SEGMENT_DESCRIPTOR_B_BIT()); //POP 32-bit argument!
374 if (STACK_SEGMENT_DESCRIPTOR_B_BIT()) //32-bits?
375 {
376 REG_ESP += 4; //Increase!
377 }
378 else //16-bits?
379 {
380 REG_SP += 4; //Increase!
381 }
382 }
383 else //16-bit source?
384 {
385 argument = MMU_rw(CPU_SEGMENT_SS, REG_SS, (REG_ESP&getstackaddrsizelimiter()), 0,!STACK_SEGMENT_DESCRIPTOR_B_BIT()); //POP 16-bit argument!
386 if (STACK_SEGMENT_DESCRIPTOR_B_BIT()) //32-bits?
387 {
388 REG_ESP += 2; //Increase!
389 }
390 else //16-bits?
391 {
392 REG_SP += 2; //Increase!
393 }
394 }
395 CPU[activeCPU].CallGateStack[CPU[activeCPU].CallGateParamCount++] = argument; //Add the argument to the call gate buffer to transfer to the new stack! Implement us as a LIFO for transfers!
396 }
397 }
398 else
399 {
400 *isdifferentCPL = 2; //Indicate call gate determines operand size!
401 }
402 }
403 }
404
405 validLDTR:
406 memcpy(dest,&LOADEDDESCRIPTOR,sizeof(LOADEDDESCRIPTOR)); //Give the loaded descriptor!
407
408 return dest; //Give the segment descriptor read from memory!
409}
410
411word segmentWritten_tempSS;
412uint_32 segmentWritten_tempESP;
413word segmentWritten_tempSP;
414extern word RETF_popbytes; //How many to pop?
415byte is_stackswitching=0; //Are we busy stack switching?
416
417byte RETF_checkSegmentRegisters[4] = {CPU_SEGMENT_ES,CPU_SEGMENT_FS,CPU_SEGMENT_GS,CPU_SEGMENT_DS}; //All segment registers to check for when returning to a lower privilege level!
418
419word segmentWrittenVal, isJMPorCALLval;
420
421byte segmentWritten(int segment, word value, word isJMPorCALL) //A segment register has been written to!
422{
423 byte RETF_segmentregister=0,RETF_whatsegment; //A segment register we're checking during a RETF instruction!
424 byte oldCPL= getCPL();
425 byte isDifferentCPL;
426 byte isnonconformingcodeordata;
427 sbyte loadresult;
428 uint_32 tempesp;
429 segmentWrittenVal = value; //What value is written!
430 isJMPorCALLval = isJMPorCALL; //What type of write are we?
431 if (getcpumode()==CPU_MODE_PROTECTED) //Protected mode, must not be real or V8086 mode, so update the segment descriptor cache!
432 {
433 isDifferentCPL = 0; //Default: same CPL!
434 SEGMENT_DESCRIPTOR tempdescriptor;
435 SEGMENT_DESCRIPTOR *descriptor = getsegment_seg(segment,&tempdescriptor,&value,isJMPorCALL,&isDifferentCPL); //Read the segment!
436 uint_32 stackval;
437 word stackval16; //16-bit stack value truncated!
438 if (descriptor) //Loaded&valid?
439 {
440 if ((segment == CPU_SEGMENT_CS) && (((isJMPorCALL&0x1FF) == 2) || ((isJMPorCALL&0x1FF)==1))) //JMP(with call gate)/CALL needs pushed data on the stack?
441 {
442 if ((isDifferentCPL==1) && ((isJMPorCALL&0x1FF) == 2)) //Stack switch is required with CALL only?
443 {
444 //TSSSize = 0; //Default to 16-bit TSS!
445 switch (GENERALSEGMENT_TYPE(CPU[activeCPU].SEG_DESCRIPTOR[CPU_SEGMENT_TR])) //What kind of TSS?
446 {
447 case AVL_SYSTEM_BUSY_TSS32BIT:
448 case AVL_SYSTEM_TSS32BIT:
449 //TSSSize = 1; //32-bit TSS!
450 case AVL_SYSTEM_BUSY_TSS16BIT:
451 case AVL_SYSTEM_TSS16BIT:
452 if (switchStacks(GENERALSEGMENTPTR_DPL(descriptor)|((isJMPorCALL&0x400)>>8))) return 1; //Abort failing switching stacks!
453
454 if (checkStackAccess(2,1,CPU[activeCPU].CallGateSize)) return 1; //Abort on error!
455
456 CPU_PUSH16(&CPU[activeCPU].oldSS,CPU[activeCPU].CallGateSize); //SS to return!
457
458 if (CPU[activeCPU].CallGateSize)
459 {
460 CPU_PUSH32(&CPU[activeCPU].oldESP);
461 }
462 else
463 {
464 word temp=(word)(CPU[activeCPU].oldESP&0xFFFF);
465 CPU_PUSH16(&temp,0);
466 }
467
468 //Now, we've switched to the destination stack! Load all parameters onto the new stack!
469 if (checkStackAccess(CPU[activeCPU].CallGateParamCount,1,CPU[activeCPU].CallGateSize)) return 1; //Abort on error!
470 for (;CPU[activeCPU].CallGateParamCount;) //Process the CALL Gate Stack!
471 {
472 stackval = CPU[activeCPU].CallGateStack[--CPU[activeCPU].CallGateParamCount]; //Read the next value to store!
473 if (CPU[activeCPU].CallGateSize) //32-bit stack to push to?
474 {
475 CPU_PUSH32(&stackval); //Push the 32-bit stack value to the new stack!
476 }
477 else //16-bit?
478 {
479 stackval16 = (word)(stackval&0xFFFF); //Reduced data if needed!
480 CPU_PUSH16(&stackval16,0); //Push the 16-bit stack value to the new stack!
481 }
482 }
483 break;
484 default:
485 break;
486 }
487 }
488 else if (isDifferentCPL==0) //Unchanging CPL? Take call size from operand size!
489 {
490 CPU[activeCPU].CallGateSize = CPU_Operand_size[activeCPU]; //Use the call instruction size!
491 }
492 //Else, call by call gate size!
493
494 if ((isJMPorCALL&0x1FF)==2) //CALL pushes return address!
495 {
496 if (checkStackAccess(2,1,CPU[activeCPU].CallGateSize)) return 1; //Abort on error!
497
498 //Push the old address to the new stack!
499 if (CPU[activeCPU].CallGateSize) //32-bit?
500 {
501 CPU_PUSH16(®_CS,1);
502 CPU_PUSH32(®_EIP);
503 }
504 else //16-bit?
505 {
506 CPU_PUSH16(®_CS,0);
507 CPU_PUSH16(®_IP,0);
508 }
509 }
510
511 /*if ((EXECSEGMENTPTR_C(descriptor)==0) && (isDifferentCPL==1)) //Non-Conforming segment, call gate and more privilege?
512 {
513 CPU[activeCPU].CPL = GENERALSEGMENTPTR_DPL(descriptor); //CPL = DPL!
514 }*/
515 setRPL(value,getCPL()); //RPL of CS always becomes CPL!
516
517 if (isDifferentCPL==1) //Different CPL?
518 {
519 hascallinterrupttaken_type = CALLGATE_NUMARGUMENTS?CALLGATE_DIFFERENTLEVEL_XPARAMETERS:CALLGATE_DIFFERENTLEVEL_NOPARAMETERS; //INT gate type taken. Low 4 bits are the type. High 2 bits are privilege level/task gate flag. Left at 0xFF when nothing is used(unknown case?)
520 }
521 else //Same CPL call gate?
522 {
523 hascallinterrupttaken_type = CALLGATE_SAMELEVEL; //Same level call gate!
524 }
525 }
526 else if ((segment == CPU_SEGMENT_CS) && ((isJMPorCALL&0x1FF) == 4)) //RETF needs popped data on the stack?
527 {
528 if (is_stackswitching == 0) //We're ready to process?
529 {
530 if (STACK_SEGMENT_DESCRIPTOR_B_BIT())
531 {
532 REG_ESP += RETF_popbytes; //Process ESP!
533 }
534 else
535 {
536 REG_SP += RETF_popbytes; //Process SP!
537 }
538 if (oldCPL < getRPL(value)) //Lowering privilege?
539 {
540 if (checkStackAccess(2, 0, CPU_Operand_size[activeCPU])) return 1; //Stack fault?
541 }
542 }
543
544 if (oldCPL<getRPL(value)) //CPL changed or still busy for this stage?
545 {
546 //Now, return to the old prvilege level!
547 hascallinterrupttaken_type = RET_DIFFERENTLEVEL; //INT gate type taken. Low 4 bits are the type. High 2 bits are privilege level/task
548 if (CPU_Operand_size[activeCPU])
549 {
550 if (CPU80386_internal_POPdw(6, &segmentWritten_tempESP))
551 {
552 //CPU[activeCPU].CPL = oldCPL; //Restore CPL for continuing!
553 is_stackswitching = 1; //We're stack switching!
554 return 1; //POP ESP!
555 }
556 }
557 else
558 {
559 if (CPU8086_internal_POPw(6, &segmentWritten_tempSP, 0))
560 {
561 //CPU[activeCPU].CPL = oldCPL; //Restore CPL for continuing!
562 is_stackswitching = 1; //We're stack switching!
563 return 1; //POP SP!
564 }
565 }
566 if (CPU8086_internal_POPw(8, &segmentWritten_tempSS, CPU_Operand_size[activeCPU]))
567 {
568 //CPU[activeCPU].CPL = oldCPL; //Restore CPL for continuing!
569 is_stackswitching = 1; //We're stack switching!
570 return 1; //POPped?
571 }
572 is_stackswitching = 0; //We've finished stack switching!
573 //Privilege change!
574 if (segmentWritten(CPU_SEGMENT_SS,segmentWritten_tempSS,(getRPL(value)<<13)|0x1000)) return 1; //Back to our calling stack!
575 if (CPU_Operand_size[activeCPU])
576 {
577 REG_ESP = segmentWritten_tempESP; //POP ESP!
578 }
579 else
580 {
581 REG_ESP = (uint_32)segmentWritten_tempSP; //POP SP!
582 }
583 RETF_segmentregister = 1; //We're checking the segments for privilege changes to be invalidated!
584 }
585 else if (oldCPL > getRPL(value)) //CPL raised during RETF?
586 {
587 THROWDESCGP(value, (isJMPorCALL&0x200)?1:(((isJMPorCALL&0x400)>>10)), (value & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //Raising CPL using RETF isn't allowed!
588 return 1; //Abort on fault!
589 }
590 else //Same privilege? (E)SP on the destination stack is already processed, don't process again!
591 {
592 RETF_popbytes = 0; //Nothing to pop anymore!
593 }
594 }
595 else if ((segment==CPU_SEGMENT_CS) && ((isJMPorCALL&0x1FF)==3)) //IRET might need extra data popped?
596 {
597 if (getRPL(value)>oldCPL) //Stack needs to be restored when returning to outer privilege level!
598 {
599 if (checkStackAccess(2,0,CPU_Operand_size[activeCPU])) return 1; //First level IRET data?
600 if (CPU_Operand_size[activeCPU])
601 {
602 tempesp = CPU_POP32();
603 }
604 else
605 {
606 tempesp = CPU_POP16(CPU_Operand_size[activeCPU]);
607 }
608
609 segmentWritten_tempSS = CPU_POP16(CPU_Operand_size[activeCPU]);
610
611 if (segmentWritten(CPU_SEGMENT_SS,segmentWritten_tempSS,(getRPL(value)<<13)|0x1000)) return 1; //Back to our calling stack!
612 REG_ESP = tempesp;
613
614 RETF_segmentregister = 1; //We're checking the segments for privilege changes to be invalidated!
615 }
616 else if (oldCPL > getRPL(value)) //CPL raised during IRET?
617 {
618 THROWDESCGP(value, (isJMPorCALL&0x200)?1:((isJMPorCALL&0x400)>>10), (value & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //Raising CPL using RETF isn't allowed!
619 return 1; //Abort!
620 }
621 }
622
623 if (segment==CPU_SEGMENT_TR) //Loading the Task Register? We're to mask us as busy!
624 {
625 if ((isJMPorCALL&0x1FF)==0) //Not a JMP or CALL itself, or a task switch, so just a plain load using LTR?
626 {
627 SEGMENT_DESCRIPTOR savedescriptor;
628 switch (GENERALSEGMENT_TYPE(tempdescriptor)) //What kind of TSS?
629 {
630 case AVL_SYSTEM_BUSY_TSS32BIT:
631 case AVL_SYSTEM_BUSY_TSS16BIT:
632 if ((isJMPorCALL & 0x800) == 0) //Needs to be non-busy?
633 {
634 THROWDESCGP(value, (isJMPorCALL & 0x200) ? 1 : (((isJMPorCALL & 0x400) >> 10)), (value & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //We cannot load a busy TSS!
635 return 1; //Abort on fault!
636 }
637 break;
638 case AVL_SYSTEM_TSS32BIT:
639 case AVL_SYSTEM_TSS16BIT:
640 if ((isJMPorCALL & 0x800)) //Needs to be busy?
641 {
642 THROWDESCGP(value, (isJMPorCALL & 0x200) ? 1 : (((isJMPorCALL & 0x400) >> 10)), (value & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //We cannot load a busy TSS!
643 return 1; //Abort on fault!
644 }
645
646 tempdescriptor.desc.AccessRights |= 2; //Mark not idle in the RAM descriptor!
647 savedescriptor.desc.DATA64 = tempdescriptor.desc.DATA64; //Copy the resulting descriptor contents to our buffer for writing to RAM!
648 if (SAVEDESCRIPTOR(segment,value,&savedescriptor,isJMPorCALL)<=0) //Save it back to RAM failed?
649 {
650 return 1; //Abort on fault!
651 }
652 break;
653 default: //Invalid segment descriptor to load into the TR register?
654 THROWDESCGP(value,(isJMPorCALL&0x200)?1:((isJMPorCALL&0x400)>>10),(value&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //We cannot load a busy TSS!
655 return 1; //Abort on fault!
656 break; //Ignore!
657 }
658 }
659 }
660 //Now, load the new descriptor and address for CS if needed(with secondary effects)!
661 if ((CPU[activeCPU].have_oldSegReg&(1 << segment)) == 0) //Backup not loaded yet?
662 {
663 memcpy(&CPU[activeCPU].SEG_DESCRIPTORbackup[segment], &CPU[activeCPU].SEG_DESCRIPTOR[segment], sizeof(CPU[activeCPU].SEG_DESCRIPTORbackup[0])); //Restore the descriptor!
664 CPU[activeCPU].oldSegReg[segment] = *CPU[activeCPU].SEGMENT_REGISTERS[segment]; //Backup the register too!
665 CPU[activeCPU].have_oldSegReg |= (1 << segment); //Loaded!
666 }
667 memcpy(&CPU[activeCPU].SEG_DESCRIPTOR[segment],descriptor,sizeof(CPU[activeCPU].SEG_DESCRIPTOR[segment])); //Load the segment descriptor into the cache!
668 //if (memprotect(CPU[activeCPU].SEGMENT_REGISTERS[segment],2,"CPU_REGISTERS")) //Valid segment register?
669 {
670 *CPU[activeCPU].SEGMENT_REGISTERS[segment] = value; //Set the segment register to the allowed value!
671 }
672
673 if ((loadresult = touchSegment(segment,value,descriptor,isJMPorCALL))<=0) //Errored out during touching?
674 {
675 if (loadresult == 0) //Not already faulted?
676 {
677 if (isJMPorCALL&0x200) //TSS is the cause?
678 {
679 THROWDESCTS(value,1,(value&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
680 }
681 else //Plain #GP?
682 {
683 THROWDESCGP(value,((isJMPorCALL&0x400)>>10),(value&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
684 }
685 }
686 return 1; //Abort on fault!
687 }
688
689 if (segment == CPU_SEGMENT_CS) //CS register?
690 {
691 REG_EIP = destEIP; //The current OPCode: just jump to the address specified by the descriptor OR command!
692 if (((isJMPorCALL & 0x1FF) == 4) || ((isJMPorCALL & 0x1FF) == 3)) //IRET/RETF required limit check!
693 {
694 if (CPU_MMU_checkrights(CPU_SEGMENT_CS, REG_CS, REG_EIP, 3, &CPU[activeCPU].SEG_DESCRIPTOR[CPU_SEGMENT_CS], 2, CPU_Operand_size[activeCPU])) //Limit broken or protection fault?
695 {
696 THROWDESCGP(0, 0, 0); //#GP(0) when out of limit range!
697 return 1; //Abort on fault!
698 }
699 }
700 }
701 else if (segment == CPU_SEGMENT_SS) //SS? We're also updating the CPL!
702 {
703 updateCPL(); //Update the CPL according to the mode!
704 }
705
706 if (RETF_segmentregister) //Are we to check the segment registers for validity during a RETF?
707 {
708 for (RETF_segmentregister = 0; RETF_segmentregister < NUMITEMS(RETF_checkSegmentRegisters); ++RETF_segmentregister) //Process all we need to check!
709 {
710 RETF_whatsegment = RETF_checkSegmentRegisters[RETF_segmentregister]; //What register to check?
711 word descriptor_index;
712 descriptor_index = getDescriptorIndex(*CPU[activeCPU].SEGMENT_REGISTERS[RETF_whatsegment]); //What descriptor index?
713 if (descriptor_index) //Valid index(Non-NULL)?
714 {
715 if ((word)(descriptor_index | 0x7) > ((*CPU[activeCPU].SEGMENT_REGISTERS[RETF_whatsegment] & 4) ? CPU[activeCPU].SEG_DESCRIPTOR[CPU_SEGMENT_LDTR].PRECALCS.limit : CPU[activeCPU].registers->GDTR.limit)) //LDT/GDT limit exceeded?
716 {
717 invalidRETFsegment:
718 if ((CPU[activeCPU].have_oldSegReg&(1 << RETF_whatsegment)) == 0) //Backup not loaded yet?
719 {
720 memcpy(&CPU[activeCPU].SEG_DESCRIPTORbackup[RETF_whatsegment], &CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment], sizeof(CPU[activeCPU].SEG_DESCRIPTORbackup[0])); //Restore the descriptor!
721 CPU[activeCPU].oldSegReg[RETF_whatsegment] = *CPU[activeCPU].SEGMENT_REGISTERS[RETF_whatsegment]; //Backup the register too!
722 CPU[activeCPU].have_oldSegReg |= (1 << RETF_whatsegment); //Loaded!
723 }
724 //Selector and Access rights are zeroed!
725 *CPU[activeCPU].SEGMENT_REGISTERS[RETF_whatsegment] = 0; //Zero the register!
726 if ((isJMPorCALL&0x1FF) == 3) //IRET?
727 {
728 CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment].desc.AccessRights &= 0x7F; //Clear the valid flag only with IRET!
729 }
730 else //RETF?
731 {
732 CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment].desc.AccessRights = 0; //Invalid!
733 }
734 CPU_calcSegmentPrecalcs(&CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment]); //Update the precalcs for said access rights!
735 continue; //Next register!
736 }
737 }
738 if (GENERALSEGMENT_P(CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment])==0) //Not present?
739 {
740 goto invalidRETFsegment; //Next register!
741 }
742 if (GENERALSEGMENT_S(CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment])==0) //Not data/readable code segment?
743 {
744 goto invalidRETFsegment; //Next register!
745 }
746 //We're either data or code!
747 isnonconformingcodeordata = 0; //Default: neither!
748 if (EXECSEGMENT_ISEXEC(CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment])) //Code?
749 {
750 if (!EXECSEGMENT_C(CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment])) //Nonconforming? Invalid!
751 {
752 isnonconformingcodeordata = 1; //Next register!
753 }
754 if (!EXECSEGMENT_R(CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment])) //Not readable? Invalid!
755 {
756 goto invalidRETFsegment; //Next register!
757 }
758 }
759 else isnonconformingcodeordata = 1; //Data!
760 //We're either data or readable code!
761 if (isnonconformingcodeordata && (GENERALSEGMENT_DPL(CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment])<MAX(getCPL(),getRPL(*CPU[activeCPU].SEGMENT_REGISTERS[RETF_whatsegment])))) //Not privileged enough to handle said segment descriptor?
762 {
763 goto invalidRETFsegment; //Next register!
764 }
765 }
766 }
767 if (segment == CPU_SEGMENT_CS)
768 {
769 if (CPU_condflushPIQ(-1)) return 1; //We're jumping to another address!
770 }
771 }
772 else //A fault has been raised? Abort!
773 {
774 if (segment == CPU_SEGMENT_CS)
775 {
776 CPU_flushPIQ(-1); //We're jumping to another address!
777 }
778 return 1; //Abort on fault!
779 }
780 }
781 else //Real mode has no protection?
782 {
783 if ((isJMPorCALL&0x1FF) == 2) //CALL needs pushed data?
784 {
785 if ((CPU_Operand_size[activeCPU]) && (EMULATED_CPU>=CPU_80386)) //32-bit?
786 {
787 if (CPU[activeCPU].internalinstructionstep==0) if (checkStackAccess(2, 1, 1)) return 1; //We're trying to push on the stack!
788 uint_32 pushingval;
789 pushingval = REG_CS; //What to push!
790 if (CPU80386_internal_PUSHdw(0,&pushingval)) return 1;
791 if (CPU80386_internal_PUSHdw(2,®_EIP)) return 1;
792 }
793 else //16-bit?
794 {
795 if (CPU[activeCPU].internalinstructionstep==0) if(checkStackAccess(2, 1, 0)) return 1; //We're trying to push on the stack!
796 if (CPU8086_internal_PUSHw(0,®_CS,0)) return 1;
797 if (CPU8086_internal_PUSHw(2,®_IP,0)) return 1;
798 }
799 }
800
801 if ((CPU[activeCPU].have_oldSegReg&(1 << segment)) == 0) //Backup not loaded yet?
802 {
803 memcpy(&CPU[activeCPU].SEG_DESCRIPTORbackup[segment], &CPU[activeCPU].SEG_DESCRIPTOR[segment], sizeof(CPU[activeCPU].SEG_DESCRIPTORbackup[0])); //Restore the descriptor!
804 CPU[activeCPU].oldSegReg[segment] = *CPU[activeCPU].SEGMENT_REGISTERS[segment]; //Backup the register too!
805 CPU[activeCPU].have_oldSegReg |= (1 << segment); //Loaded!
806 }
807
808 //if (memprotect(CPU[activeCPU].SEGMENT_REGISTERS[segment],2,"CPU_REGISTERS")) //Valid segment register?
809 {
810 *CPU[activeCPU].SEGMENT_REGISTERS[segment] = value; //Just set the segment, don't load descriptor!
811 //Load the correct base data for our loading!
812 CPU[activeCPU].SEG_DESCRIPTOR[segment].desc.base_low = (word)(((uint_32)value<<4)&0xFFFF); //Low base!
813 CPU[activeCPU].SEG_DESCRIPTOR[segment].desc.base_mid = ((((uint_32)value << 4) & 0xFF0000)>>16); //Mid base!
814 CPU[activeCPU].SEG_DESCRIPTOR[segment].desc.base_high = ((((uint_32)value << 4) & 0xFF000000)>>24); //High base!
815 //This also maps the resulting segment in low memory (20-bit address space) in real mode, thus CS is pulled low as well!
816 //Real mode affects only CS like Virtual 8086 mode(reloading all base/limit values). Other segments are unmodified.
817 //Virtual 8086 mode also loads the rights etc.? This is to prevent Virtual 8086 tasks having leftover data in their descriptors, causing faults!
818 if ((segment==CPU_SEGMENT_CS) || (getcpumode()==CPU_MODE_8086)) //Only done for the CS segment in real mode as well as all registers in 8086 mode?
819 {
820 CPU[activeCPU].SEG_DESCRIPTOR[segment].desc.AccessRights = 0x93; //Compatible rights!
821 CPU[activeCPU].SEG_DESCRIPTOR[segment].desc.limit_low = 0xFFFF;
822 CPU[activeCPU].SEG_DESCRIPTOR[segment].desc.noncallgate_info = 0x00; //Not used!
823 }
824 }
825 if (segment==CPU_SEGMENT_CS) //CS segment? Reload access rights in real mode on first write access!
826 {
827 CPU[activeCPU].SEG_DESCRIPTOR[CPU_SEGMENT_CS].desc.AccessRights = 0x93; //Load default access rights!
828 CPU_calcSegmentPrecalcs(&CPU[activeCPU].SEG_DESCRIPTOR[segment]); //Calculate any precalcs for the segment descriptor(do it here since we don't load descriptors externally)!
829 REG_EIP = destEIP; //... The current OPCode: just jump to the address!
830 }
831 else if (segment == CPU_SEGMENT_SS) //SS? We're also updating the CPL!
832 {
833 updateCPL(); //Update the CPL according to the mode!
834 CPU_calcSegmentPrecalcs(&CPU[activeCPU].SEG_DESCRIPTOR[segment]); //Calculate any precalcs for the segment descriptor(do it here since we don't load descriptors externally)!
835 }
836 else
837 {
838 CPU_calcSegmentPrecalcs(&CPU[activeCPU].SEG_DESCRIPTOR[segment]); //Calculate any precalcs for the segment descriptor(do it here since we don't load descriptors externally)!
839 }
840 }
841 //Real mode doesn't use the descriptors?
842 if (segment == CPU_SEGMENT_CS)
843 {
844 if (CPU_condflushPIQ(-1)) return 1; //We're jumping to another address!
845 }
846 return 0; //No fault raised&continue!
847}