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