1 /* descriptor table format in memory
2    UINT16 limit
3    UINT24 addr
4    0..3 type
5     system segment
6      3 execute:
7 	  0 data segment: readable,
8        1: write
9        2: expand down
10 	  1 code segment
11        1: readable
12        2: conforming (can be used with higher privilege level)
13      0: access (set when processor accesses segment)
14 
15    4 dt 0 system segment, 1 application segment (code, data)
16    5,6 dpl descriptor privileg level
17    7 p present 0 gives trap when accessed
18    UINT16 reserved (should be zero)
19 */
20 #define WRITEABLE(a) ((a&0xa)==2)
21 #define READABLE(a) ( ((a&0xa)==0xa)|| ((a&8)==0) )
22 
i286_trap2(int number)23 static void i286_trap2(int number)
24 {
25 	i286_interrupt(number);
26 }
27 
i286_selector_okay(UINT16 selector)28 static int i286_selector_okay(UINT16 selector)
29 {
30 	if (selector&4) {
31 		return (selector&~7)<I.ldtr.limit;
32 	} else {
33 		return (selector&~7)<I.gdtr.limit;
34 	}
35 }
36 
i286_selector_to_address(UINT16 selector)37 static offs_t i286_selector_to_address(UINT16 selector)
38 {
39 	if (selector&4) {
40 		return I.ldtr.base+(selector&~7);
41 	} else {
42 		return I.gdtr.base+(selector&~7);
43 	}
44 }
45 
i286_data_descriptor(int reg,UINT16 selector)46 static void i286_data_descriptor(int reg, UINT16 selector)
47 {
48 	if (PM) {
49 		UINT16 help;
50 		/* selector format
51 		   15..3 number/address in descriptor table
52 		   2: 0 global, 1 local descriptor table
53 		   1,0: requested privileg level
54 		   must be higher or same as current privileg level in code selector */
55 		if (selector&4) { /* local descriptor table */
56 			if (selector>I.ldtr.limit) i286_trap2(GENERAL_PROTECTION_FAULT);
57 			I.sregs[reg]=selector;
58 			I.limit[reg]=ReadWord(I.ldtr.base+(selector&~7));
59 			I.base[reg]=ReadWord(I.ldtr.base+(selector&~7)+2)
60 				|(ReadWord(I.ldtr.base+(selector&~7)+4)<<16);
61 			I.rights[reg]=I.base[reg]>>24;
62 			I.base[reg]&=0xffffff;
63 		} else { /* global descriptor table */
64 			if (!(selector&~7)||(selector>I.gdtr.limit)) i286_trap2(GENERAL_PROTECTION_FAULT);
65 			I.sregs[reg]=selector;
66 			I.limit[reg]=ReadWord(I.gdtr.base+(selector&~7));
67 			I.base[reg]=ReadWord(I.gdtr.base+(selector&~7)+2);
68 			help=ReadWord(I.gdtr.base+(selector&~7)+4);
69 			I.rights[reg]=help>>8;
70 			I.base[reg]|=(help&0xff)<<16;
71 		}
72 	} else {
73 		I.sregs[reg]=selector;
74 		I.base[reg]=selector<<4;
75 	}
76 }
77 
i286_code_descriptor(UINT16 selector,UINT16 offset)78 static void i286_code_descriptor(UINT16 selector, UINT16 offset)
79 {
80 	UINT16 word1, word2, word3;
81 	if (PM) {
82 		/* selector format
83 		   15..3 number/address in descriptor table
84 		   2: 0 global, 1 local descriptor table
85 		   1,0: requested privileg level
86 		   must be higher or same as current privileg level in code selector */
87 		if (selector&4) { /* local descriptor table */
88 			if (selector>I.ldtr.limit) i286_trap2(GENERAL_PROTECTION_FAULT);
89 			word1=ReadWord(I.ldtr.base+(selector&~7));
90 			word2=ReadWord(I.ldtr.base+(selector&~7)+2);
91 			word3=ReadWord(I.ldtr.base+(selector&~7)+4);
92 		} else { /* global descriptor table */
93 			if (!(selector&~7)||(selector>I.gdtr.limit)) i286_trap2(GENERAL_PROTECTION_FAULT);
94 			word1=ReadWord(I.gdtr.base+(selector&~7));
95 			word2=ReadWord(I.gdtr.base+(selector&~7)+2);
96 			word3=ReadWord(I.gdtr.base+(selector&~7)+4);
97 		}
98 		if (word3&0x1000) {
99 			I.sregs[CS]=selector;
100 			I.limit[CS]=word1;
101 			I.base[CS]=word2|((word3&0xff)<<16);
102 			I.rights[CS]=word3>>8;
103 			I.pc=I.base[CS]+offset;
104 		} else { // systemdescriptor
105 			switch (word3&0xf00) {
106 			case 0x400: // call gate
107 				// word3&0x1f words to be copied from stack to stack
108 				i286_data_descriptor(CS, word2);
109 				I.pc=I.base[CS]+word1;
110 				break;
111 			case 0x500: // task gate
112 				i286_data_descriptor(CS, word2);
113 				I.pc=I.base[CS]+word1;
114 				break;
115 			case 0x600: // interrupt gate
116 				I.TF = I.IF = 0;
117 				i286_data_descriptor(CS, word2);
118 				I.pc=I.base[CS]+word1;
119 				break;
120 			case 0x700: // trap gate
121 				i286_data_descriptor(CS, word2);
122 				I.pc=I.base[CS]+word1;
123 				break;
124 			}
125 		}
126 	} else {
127 		I.sregs[CS]=selector;
128 		I.base[CS]=selector<<4;
129 		I.pc=I.base[CS]+offset;
130 	}
131 }
132 
i286_interrupt_descriptor(UINT16 number)133 static void i286_interrupt_descriptor(UINT16 number)
134 {
135 	UINT16 word1,word2,word3;
136 	if ((number<<3)>=I.idtr.limit) {
137 		;// go into shutdown mode
138 		return;
139 	}
140 	PREFIX(_pushf());
141 	PUSH(I.sregs[CS]);
142 	PUSH(I.pc - I.base[CS]);
143 	word1=ReadWord(I.idtr.base+(number<<3));
144 	word2=ReadWord(I.idtr.base+(number<<3)+2);
145 	word3=ReadWord(I.idtr.base+(number<<3)+4);
146 	switch (word3&0xf00) {
147 	case 0x500: // task gate
148 		i286_data_descriptor(CS, word2);
149 		I.pc=I.base[CS]+word1;
150 		break;
151 	case 0x600: // interrupt gate
152 		I.TF = I.IF = 0;
153 		i286_data_descriptor(CS, word2);
154 		I.pc=I.base[CS]+word1;
155 		break;
156 	case 0x700: // trap gate
157 		i286_data_descriptor(CS, word2);
158 		I.pc=I.base[CS]+word1;
159 		break;
160 	}
161 }
162 
PREFIX286(_0fpre)163 static void PREFIX286(_0fpre)(void)
164 {
165 	unsigned next = FETCHOP;
166 	UINT16 ModRM;
167 	UINT16 tmp;
168 	offs_t addr;
169 
170 	switch (next) {
171 	case 0:
172 		ModRM=FETCHOP;
173 		switch (ModRM&0x38) {
174 		case 0: /* sldt */
175 			if (!PM) i286_trap2(ILLEGAL_INSTRUCTION);
176 			PutRMWord(ModRM, I.ldtr.sel);
177 			break;
178 		case 8: /* str */
179 			if (!PM) i286_trap2(ILLEGAL_INSTRUCTION);
180 			PutRMWord(ModRM, I.tr.sel);
181 			break;
182 		case 0x10: /* lldt */
183 			if (!PM) i286_trap2(ILLEGAL_INSTRUCTION);
184 			if (PM&&(CPL!=0)) i286_trap2(GENERAL_PROTECTION_FAULT);
185 			I.ldtr.sel=GetRMWord(ModRM);
186 			if ((I.ldtr.sel&~7)>=I.gdtr.limit) i286_trap2(GENERAL_PROTECTION_FAULT);
187 			I.ldtr.limit=ReadWord(I.gdtr.base+(I.ldtr.sel&~7));
188 			I.ldtr.base=ReadWord(I.gdtr.base+(I.ldtr.sel&~7)+2)
189 				|(ReadWord(I.gdtr.base+(I.ldtr.sel&~7)+4)<<16);
190 			I.ldtr.rights=I.ldtr.base>>24;
191 			I.ldtr.base&=0xffffff;
192 			break;
193 		case 0x18: /* ltr */
194 			if (!PM) i286_trap2(ILLEGAL_INSTRUCTION);
195 			if (CPL!=0) i286_trap2(GENERAL_PROTECTION_FAULT);
196 			I.tr.sel=GetRMWord(ModRM);
197 			if ((I.tr.sel&~7)>=I.gdtr.limit) i286_trap2(GENERAL_PROTECTION_FAULT);
198 			I.tr.limit=ReadWord(I.gdtr.base+(I.tr.sel&~7));
199 			I.tr.base=ReadWord(I.gdtr.base+(I.tr.sel&~7)+2)
200 				|(ReadWord(I.gdtr.base+(I.tr.sel&~7)+4)<<16);
201 			I.tr.rights=I.tr.base>>24;
202 			I.tr.base&=0xffffff;
203 			break;
204 		case 0x20: /* verr */
205 			if (!PM) i286_trap2(ILLEGAL_INSTRUCTION);
206 			tmp=GetRMWord(ModRM);
207 			if (tmp&4) {
208 				I.ZeroVal=( ((tmp&~7)<I.ldtr.limit)
209 							&& READABLE( ReadByte(I.ldtr.base+(tmp&~7)+5)) );
210 			} else {
211 				I.ZeroVal=( ((tmp&~7)<I.gdtr.limit)
212 							&& READABLE( ReadByte(I.gdtr.base+(tmp&~7)+5)) );
213 			}
214 			break;
215 		case 0x28: /* verw */
216 			if (!PM) i286_trap2(ILLEGAL_INSTRUCTION);
217 			tmp=GetRMWord(ModRM);
218 			if (tmp&4) {
219 				I.ZeroVal=( ((tmp&~7)<I.ldtr.limit)
220 							&& WRITEABLE( ReadByte(I.ldtr.base+(tmp&~7)+5)) );
221 			} else {
222 				I.ZeroVal=( ((tmp&~7)<I.gdtr.limit)
223 							&& WRITEABLE( ReadByte(I.gdtr.base+(tmp&~7)+5)) );
224 			}
225 			break;
226 		default:
227 			i286_trap2(ILLEGAL_INSTRUCTION);
228 			break;
229 		}
230 		break;
231 	case 1:
232 		/* lgdt, lldt in protected mode privilege level 0 required else common protection
233 		   failure 0xd */
234 		ModRM = FETCHOP;
235 		switch (ModRM&0x38) {
236 		case 0: /* sgdt */
237 			PutRMWord(ModRM,I.gdtr.limit);
238 			PutRMWordOffset(2,I.gdtr.base&0xffff);
239 			PutRMByteOffset(4,I.gdtr.base>>16);
240 			break;
241 		case 8: /* sidt */
242 			PutRMWord(ModRM,I.idtr.limit);
243 			PutRMWordOffset(2,I.idtr.base&0xffff);
244 			PutRMByteOffset(4,I.idtr.base>>16);
245 			break;
246 		case 0x10: /* lgdt */
247 			if (PM&&(CPL!=0)) i286_trap2(GENERAL_PROTECTION_FAULT);
248 			I.gdtr.limit=GetRMWord(ModRM);
249 			I.gdtr.base=GetRMWordOffset(2)|(GetRMByteOffset(4)<<16);
250 			break;
251 		case 0x18: /* lidt */
252 			if (PM&&(CPL!=0)) i286_trap2(GENERAL_PROTECTION_FAULT);
253 			I.idtr.limit=GetRMWord(ModRM);
254 			I.idtr.base=GetRMWordOffset(2)|(GetRMByteOffset(4)<<16);
255 			break;
256 		case 0x20: /* smsw */
257 			PutRMWord(ModRM, I.msw);
258 			break;
259 		case 0x30: /* lmsw */
260 			if (PM&&(CPL!=0)) i286_trap2(GENERAL_PROTECTION_FAULT);
261 			I.msw=(I.msw&1)|GetRMWord(ModRM);
262 			break;
263 		default:
264 			i286_trap2(ILLEGAL_INSTRUCTION);
265 			break;
266 		}
267 		break;
268 	case 2: /* LAR */
269 		ModRM = FETCHOP;
270 		tmp=GetRMWord(ModRM);
271 		I.ZeroVal=i286_selector_okay(tmp);
272 		if (I.ZeroVal) {
273 			RegWord(ModRM)=tmp;
274 		}
275 		break;
276 	case 3: /* LSL */
277 		if (!PM) i286_trap2(ILLEGAL_INSTRUCTION);
278 		ModRM = FETCHOP;
279 		tmp=GetRMWord(ModRM);
280 		I.ZeroVal=i286_selector_okay(tmp);
281 		if (I.ZeroVal) {
282 			addr=i286_selector_to_address(tmp);
283 			RegWord(ModRM)=ReadWord(addr);
284 		}
285 		break;
286 	case 6: /* clts */
287 		if (PM&&(CPL!=0)) i286_trap2(GENERAL_PROTECTION_FAULT);
288 		I.msw=~8;
289 		break;
290 	default:
291 		i286_trap2(ILLEGAL_INSTRUCTION);
292 		break;
293 	}
294 }
295 
PREFIX286(_arpl)296 static void PREFIX286(_arpl)(void) /* 0x63 */
297 {
298 	if (PM) {
299 		UINT16 ModRM=FETCHOP, tmp=GetRMWord(ModRM);
300 
301 		I.ZeroVal=i286_selector_okay(RegWord(ModRM))
302 			  &&i286_selector_okay(RegWord(ModRM))
303 			  &&((tmp&3)<(RegWord(ModRM)&3));
304 		if (I.ZeroVal) PutbackRMWord(ModRM, (tmp&~3)|(RegWord(ModRM)&3));
305 	} else {
306 		i286_trap2(ILLEGAL_INSTRUCTION);
307 	}
308 }
309