…Show last 359 lines
61 }
62 }
63
64 if (GENERALSEGMENT_P(LOADEDDESCRIPTOR.desc)==0) //Not present loaded into non-data segment register?
65 {
66 if (segment==CPU_SEGMENT_SS) //Stack fault?
67 {
68 THROWDESCSP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Stack fault!
69 }
70 else
71 {
72 THROWDESCNP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
73 }
74 return NULL; //We're an invalid TSS to execute!
75 }
76
77 if (isGateDescriptor(&LOADEDDESCRIPTOR)==0) //Invalid descriptor?
78 {
79 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error!
80 return NULL; //We're an invalid descriptor to use!
81 }
82
83 if ((isGateDescriptor(&LOADEDDESCRIPTOR)==1) && (segment == CPU_SEGMENT_CS) && isJMPorCALL) //Handling of gate descriptors?
84 {
85 is_gated = 1; //We're gated!
86 memcpy(&GATEDESCRIPTOR, &LOADEDDESCRIPTOR, sizeof(GATEDESCRIPTOR)); //Copy the loaded descriptor to the GATE!
87 //Check for invalid loads!
88 switch (GENERALSEGMENT_TYPE(GATEDESCRIPTOR.desc))
89 {
90 default: //Unknown type?
91 case AVL_SYSTEM_INTERRUPTGATE16BIT:
92 case AVL_SYSTEM_TRAPGATE16BIT:
93 case AVL_SYSTEM_INTERRUPTGATE32BIT:
94 case AVL_SYSTEM_TRAPGATE32BIT:
95 //We're an invalid gate!
96 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error!
97 return NULL; //Not present: invalid descriptor type loaded!
98 break;
99 case AVL_SYSTEM_TASKGATE: //Task gate?
100 case AVL_SYSTEM_CALLGATE16BIT:
101 case AVL_SYSTEM_CALLGATE32BIT:
102 //Valid gate! Allow!
103 break;
104 }
105 if ((MAX(getCPL(), getRPL(*segmentval)) > GENERALSEGMENT_DPL(GATEDESCRIPTOR.desc)) && (isJMPorCALL!=3)) //Gate has too high a privilege level? Only when not an IRET(always allowed)!
106 {
107 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
108 return NULL; //We are a lower privilege level, so don't load!
109 }
110 *segmentval = (GATEDESCRIPTOR.desc.selector & ~3) | (*segmentval & 3); //We're loading this segment now, with requesting privilege!
111 if ((loadresult = LOADDESCRIPTOR(segment, *segmentval, &LOADEDDESCRIPTOR,isJMPorCALL))<=0) //Error loading current descriptor?
112 {
113 if (loadresult == 0) //Not faulted already?
114 {
115 THROWDESCGP(*segmentval, 1, (*segmentval & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //Throw error!
116 }
117 return NULL; //Error, by specified reason!
118 }
119 if (isGateDescriptor(&LOADEDDESCRIPTOR)==0) //Invalid descriptor?
120 {
121 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error!
122 return NULL; //We're an invalid descriptor to use!
123 }
124 privilegedone = 1; //Privilege has been precalculated!
125 if (GENERALSEGMENT_TYPE(GATEDESCRIPTOR.desc) == AVL_SYSTEM_TASKGATE) //Task gate?
126 {
127 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)!
128 {
129 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
130 return NULL; //Don't load!
131 }
132 }
133 else //Normal descriptor?
134 {
135 if ((isJMPorCALL == 1) && !EXECSEGMENT_C(LOADEDDESCRIPTOR.desc)) //JMP to a nonconforming segment?
136 {
137 if (GENERALSEGMENT_DPL(LOADEDDESCRIPTOR.desc) != getCPL()) //Different CPL?
138 {
139 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
140 return NULL; //We are a different privilege level, so don't load!
141 }
142 }
143 else if (isJMPorCALL) //Call instruction (or JMP instruction to a conforming segment)
144 {
145 if (GENERALSEGMENT_DPL(LOADEDDESCRIPTOR.desc) > getCPL()) //We have a lower CPL?
146 {
147 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
148 return NULL; //We are a different privilege level, so don't load!
149 }
150 }
151 }
152 }
153 else if ((isGateDescriptor(&LOADEDDESCRIPTOR)==-1) && (segment==CPU_SEGMENT_CS) && isJMPorCALL) //JMP/CALL to non-gate descriptor(and not a system segment)?
154 {
155 equalprivilege = 1; //Enforce equal privilege!
156 }
157
158 //Final descriptor safety check!
159 if (isGateDescriptor(&LOADEDDESCRIPTOR)==0) //Invalid descriptor?
160 {
161 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error!
162 return NULL; //We're an invalid descriptor to use!
163 }
164
165 if (
166 (
167 (segment==CPU_SEGMENT_SS) ||
168 (segment==CPU_SEGMENT_DS) ||
169 (segment==CPU_SEGMENT_ES) ||
170 (segment==CPU_SEGMENT_FS) ||
171 (segment==CPU_SEGMENT_GS) //SS,DS,ES,FS,GS are ...
172 ) &&
173 (
174 (getLoadedTYPE(&LOADEDDESCRIPTOR)==2) || //A System segment? OR ...
175 ((getLoadedTYPE(&LOADEDDESCRIPTOR)==1) && (EXECSEGMENT_R(LOADEDDESCRIPTOR.desc)==0)) //An execute-only code segment?
176 )
177 )
178 {
179 THROWDESCGP(originalval,1,(originalval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
180 return NULL; //Not present: limit exceeded!
181 }
182
183 switch (GENERALSEGMENT_TYPE(LOADEDDESCRIPTOR.desc)) //We're a TSS? We're to perform a task switch!
184 {
185 case AVL_SYSTEM_BUSY_TSS16BIT:
186 case AVL_SYSTEM_TSS16BIT: //TSS?
187 case AVL_SYSTEM_BUSY_TSS32BIT:
188 case AVL_SYSTEM_TSS32BIT: //TSS?
189 is_TSS = (getLoadedTYPE(&LOADEDDESCRIPTOR)==2); //We're a TSS when a system segment!
190 break;
191 default:
192 is_TSS = 0; //We're no TSS!
193 break;
194 }
195
196 if (is_TSS && (segment==CPU_SEGMENT_CS) && (isJMPorCALL==3)) //IRET allowed regardless of privilege?
197 {
198 privilegedone = 1; //Allow us always!
199 }
200
201 //Now check for CPL,DPL&RPL! (chapter 6.3.2)
202 if (
203 (
204 (!privilegedone && !equalprivilege && (MAX(getCPL(),getRPL(*segmentval))>GENERALSEGMENT_DPL(LOADEDDESCRIPTOR.desc)) && ((!(EXECSEGMENT_ISEXEC(LOADEDDESCRIPTOR.desc) && EXECSEGMENT_C(LOADEDDESCRIPTOR.desc) && getLoadedTYPE(&LOADEDDESCRIPTOR)==1)))) || //We are a lower privilege level with either non-conforming or a data/system segment descriptor?
205 ((!privilegedone && equalprivilege && MAX(getCPL(),getRPL(*segmentval))!=GENERALSEGMENT_DPL(LOADEDDESCRIPTOR.desc)) && //We must be at the same privilege level?
206 !(EXECSEGMENT_C(LOADEDDESCRIPTOR.desc)) //Not conforming checking further ahead makes sure that we don't double check things?
207 )
208 )
209 && (!((isJMPorCALL==3) && is_TSS)) //No privilege checking is done on IRET through TSS!
210 )
211 {
212 THROWDESCGP(originalval,1,(originalval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
213 return NULL; //We are a lower privilege level, so don't load!
214 }
215
216 if (is_TSS && (segment==CPU_SEGMENT_TR)) //We're a TSS loading into TR? We're to perform a task switch!
217 {
218 if (*segmentval & 2) //LDT lookup set?
219 {
220 THROWDESCGP(originalval,1,(originalval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
221 return NULL; //We're an invalid TSS to call!
222 }
223 //Handle the task switch normally! We're allowed to use the TSS!
224 }
225
226 if ((GENERALSEGMENT_P(LOADEDDESCRIPTOR.desc)==0) && ((segment==CPU_SEGMENT_CS) || (segment==CPU_SEGMENT_SS) || (segment==CPU_SEGMENT_TR) || (*segmentval&~3))) //Not present loaded into non-data register?
227 {
228 if (segment==CPU_SEGMENT_SS) //Stack fault?
229 {
230 THROWDESCSP(originalval,1,(originalval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
231 }
232 else
233 {
234 THROWDESCNP(originalval,1,(originalval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
235 }
236 return NULL; //We're an invalid TSS to execute!
237 }
238
239 if ((segment==CPU_SEGMENT_CS) && is_TSS) //Special stuff on CS, CPL, Task switch.
240 {
241 //Execute a normal task switch!
242 if (CPU_executionphase_starttaskswitch(segment,&LOADEDDESCRIPTOR,segmentval,*segmentval,isJMPorCALL,is_gated,-1)) //Switching to a certain task?
243 {
244 return NULL; //Error changing priviledges or anything else!
245 }
246
247 //We've properly switched to the destination task! Continue execution normally!
248 return NULL; //Don't actually load CS with the descriptor: we've caused a task switch after all!
249 }
250
251 if ((segment == CPU_SEGMENT_CS) && (is_gated==0)) //Special stuff on normal CS register (conforming?), CPL.
252 {
253 if (EXECSEGMENT_C(LOADEDDESCRIPTOR.desc)) //Conforming segment?
254 {
255 if ((!privilegedone) && (GENERALSEGMENT_DPL(LOADEDDESCRIPTOR.desc)<MAX(getCPL(),getRPL(*segmentval)))) //Target DPL must be less-or-equal to the CPL.
256 {
257 THROWDESCGP(originalval,1,(originalval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
258 return NULL; //We are a lower privilege level, so don't load!
259 }
260 }
261 else //Non-conforming segment?
262 {
263 if ((!privilegedone) && (GENERALSEGMENT_DPL(LOADEDDESCRIPTOR.desc)!=MAX(getCPL(),getRPL(*segmentval)))) //Check for equal only when using Gate Descriptors?
264 {
265 THROWDESCGP(originalval,1,(originalval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
266 return NULL; //We are a lower privilege level, so don't load!
267 }
268 }
269 }
270
271 if ((segment == CPU_SEGMENT_CS) && (isGateDescriptor(&GATEDESCRIPTOR) == 1) && (is_gated)) //Gated CS?
272 {
273 switch (GENERALSEGMENT_TYPE(GATEDESCRIPTOR.desc)) //What type of gate are we using?
274 {
275 case AVL_SYSTEM_CALLGATE16BIT: //16-bit call gate?
276 callgatetype = 1; //16-bit call gate!
277 break;
278 case AVL_SYSTEM_CALLGATE32BIT: //32-bit call gate?
279 callgatetype = 2; //32-bit call gate!
280 break;
281 default:
282 callgatetype = 0; //No call gate!
283 break;
284 }
285 if (callgatetype) //To process a call gate's parameters and offsets?
286 {
287 destEIP = GATEDESCRIPTOR.desc.callgate_base_low; //16-bit EIP!
288 if (callgatetype == 2) //32-bit destination?
289 {
290 destEIP |= (GATEDESCRIPTOR.desc.callgate_base_mid<<16); //Mid EIP!
291 destEIP |= (GATEDESCRIPTOR.desc.callgate_base_high<<24); //High EIP!
292 }
293 uint_32 argument; //Current argument to copy to the destination stack!
294 word arguments;
295 CPU[activeCPU].CallGateParamCount = 0; //Clear our stack to transfer!
296 CPU[activeCPU].CallGateSize = (callgatetype==2)?1:0; //32-bit vs 16-bit call gate!
297
298 if ((GENERALSEGMENT_DPL(LOADEDDESCRIPTOR.desc)!=getCPL()) && (isJMPorCALL==2)) //Stack switch required (with CALL only)?
299 {
300 //Backup the old stack data!
301 /*
302 CPU[activeCPU].have_oldESP = 1;
303 CPU[activeCPU].have_oldSS = 1;
304 CPU[activeCPU].oldESP = REG_ESP; //Backup!
305 CPU[activeCPU].oldSS = REG_SS; //Backup!
306 */ //Dont automatically at the start of the instruction!
307 //Now, copy the stack arguments!
308
309 *isdifferentCPL = 1; //We're a different level!
310 arguments = CALLGATE_NUMARGUMENTS = (GATEDESCRIPTOR.desc.ParamCnt&0x1F); //Amount of parameters!
311 CPU[activeCPU].CallGateParamCount = 0; //Initialize the amount of arguments that we're storing!
312 if (checkStackAccess(arguments,0,(callgatetype==2)?1:0)) return NULL; //Abort on stack fault!
313 for (;arguments--;) //Copy as many arguments as needed!
314 {
315 if (callgatetype==2) //32-bit source?
316 {
317 argument = MMU_rdw(CPU_SEGMENT_SS, CPU[activeCPU].registers->SS, CPU[activeCPU].registers->ESP&getstackaddrsizelimiter(), 0,!STACK_SEGMENT_DESCRIPTOR_B_BIT()); //POP 32-bit argument!
318 if (STACK_SEGMENT_DESCRIPTOR_B_BIT()) //32-bits?
319 {
320 CPU[activeCPU].registers->ESP += 4; //Increase!
321 }
322 else //16-bits?
323 {
324 CPU[activeCPU].registers->SP += 4; //Increase!
325 }
326 }
327 else //16-bit source?
328 {
329 argument = MMU_rw(CPU_SEGMENT_SS, CPU[activeCPU].registers->SS, (CPU[activeCPU].registers->ESP&getstackaddrsizelimiter()), 0,!STACK_SEGMENT_DESCRIPTOR_B_BIT()); //POP 16-bit argument!
330 if (STACK_SEGMENT_DESCRIPTOR_B_BIT()) //32-bits?
331 {
332 CPU[activeCPU].registers->ESP += 2; //Increase!
333 }
334 else //16-bits?
335 {
336 CPU[activeCPU].registers->SP += 2; //Increase!
337 }
338 }
339 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!
340 }
341
342 CPU[activeCPU].CPL = GENERALSEGMENT_DPL(LOADEDDESCRIPTOR.desc); //Changing privilege to this!
343 }
344 else
345 {
346 *isdifferentCPL = 2; //Indicate call gate determines operand size!
347 }
348 }
349 }
350
351 //Handle invalid types now!
352 if ((segment==CPU_SEGMENT_CS) &&
353 (getLoadedTYPE(&LOADEDDESCRIPTOR)!=1) //Data or System in CS (non-exec)?
354 )
355 {
356 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error!
357 return NULL; //Not present: invalid descriptor type loaded!
358 }
359 else if ((getLoadedTYPE(&LOADEDDESCRIPTOR)==1) && (segment!=CPU_SEGMENT_CS) && (EXECSEGMENT_R(LOADEDDESCRIPTOR.desc)==0)) //Executable non-readable in non-executable segment?
360 {
361 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error!
362 return NULL; //Not present: invalid descriptor type loaded!
363 }
364 else if ((getLoadedTYPE(&LOADEDDESCRIPTOR)==1) && ((segment==CPU_SEGMENT_LDTR) || (segment==CPU_SEGMENT_TR))) //Executable segment loaded invalid?
365 {
366 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error!
367 return NULL; //Not present: invalid descriptor type loaded!
368 }
369 else if (getLoadedTYPE(&LOADEDDESCRIPTOR)==0) //Data descriptor loaded?
370 {
371 if (((segment!=CPU_SEGMENT_DS) && (segment!=CPU_SEGMENT_ES) && (segment!=CPU_SEGMENT_FS) && (segment!=CPU_SEGMENT_GS) && (segment!=CPU_SEGMENT_SS))) //Data descriptor in invalid type?
372 {
373 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error!
374 return NULL; //Not present: invalid descriptor type loaded!
375 }
376 if ((DATASEGMENT_W(LOADEDDESCRIPTOR.desc)==0) && (segment==CPU_SEGMENT_SS)) //Non-writable SS segment?
377 {
378 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error!
379 return NULL; //Not present: invalid descriptor type loaded!
380 }
381 }
382 else if (getLoadedTYPE(&LOADEDDESCRIPTOR)==2) //System descriptor loaded?
383 {
384 if ((segment==CPU_SEGMENT_CS) || (segment==CPU_SEGMENT_DS) || (segment==CPU_SEGMENT_ES) || (segment==CPU_SEGMENT_FS) || (segment==CPU_SEGMENT_GS) || (segment==CPU_SEGMENT_SS)) //System descriptor in invalid register?
385 {
386 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error!
387 return NULL; //Not present: invalid descriptor type loaded!
388 }
389 if ((segment==CPU_SEGMENT_LDTR) && (GENERALSEGMENT_TYPE(LOADEDDESCRIPTOR.desc)!=AVL_SYSTEM_LDT)) //Invalid LDT load?
390 {
391 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error!
392 return NULL; //Not present: invalid descriptor type loaded!
393 }
394 if ((segment==CPU_SEGMENT_TR) && (is_TSS==0)) //Non-TSS into task register?
395 {
396 THROWDESCGP(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw #GP error!
397 return NULL; //Not present: invalid descriptor type loaded!
398 }
399 }
400
401 if (segment==CPU_SEGMENT_CS) //We need to reload a new CPL?
402 {
403 //Non-gates doesn't change RPL(CPL) of CS! (IRET?&)RETF does change CPL here(already done beforehand)!
404 if ((is_gated==0) && (isJMPorCALL==4)) //RETF changes privilege level?
405 {
406 if (getRPL(*segmentval)>getCPL()) //Lowered?
407 {
408 CPU[activeCPU].CPL = getRPL(*segmentval); //New CPL, lowered!
409 setRPL(*segmentval,CPU[activeCPU].CPL); //Only gated loads(CALL gates) can change RPL(active lowest CPL in CS). Otherwise, it keeps the old RPL.
410 setRPL(originalval,CPU[activeCPU].CPL); //Only gated loads(CALL gates) can change RPL(active lowest CPL in CS). Otherwise, it keeps the old RPL.
411 }
412 }
413 }
414
415 validLDTR:
416 memcpy(dest,&LOADEDDESCRIPTOR,sizeof(LOADEDDESCRIPTOR)); //Give the loaded descriptor!
417
418 return dest; //Give the segment descriptor read from memory!
419}