…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}