Commit 90a9fdae1f1acc791abc2c20731eddf01ba73ae6
1 parent
3fb2ded1
more ring 0 operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@261 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
478 additions
and
87 deletions
exec-i386.h
@@ -124,12 +124,22 @@ extern CCTable cc_table[]; | @@ -124,12 +124,22 @@ extern CCTable cc_table[]; | ||
124 | 124 | ||
125 | void load_seg(int seg_reg, int selector, unsigned cur_eip); | 125 | void load_seg(int seg_reg, int selector, unsigned cur_eip); |
126 | void jmp_seg(int selector, unsigned int new_eip); | 126 | void jmp_seg(int selector, unsigned int new_eip); |
127 | +void helper_iret_protected(int shift); | ||
127 | void helper_lldt_T0(void); | 128 | void helper_lldt_T0(void); |
128 | void helper_ltr_T0(void); | 129 | void helper_ltr_T0(void); |
129 | void helper_movl_crN_T0(int reg); | 130 | void helper_movl_crN_T0(int reg); |
130 | void helper_movl_drN_T0(int reg); | 131 | void helper_movl_drN_T0(int reg); |
132 | +void helper_invlpg(unsigned int addr); | ||
133 | +void cpu_x86_update_cr0(CPUX86State *env); | ||
134 | +void cpu_x86_update_cr3(CPUX86State *env); | ||
135 | +void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); | ||
136 | +int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write); | ||
131 | void __hidden cpu_lock(void); | 137 | void __hidden cpu_lock(void); |
132 | void __hidden cpu_unlock(void); | 138 | void __hidden cpu_unlock(void); |
139 | +void do_interrupt(int intno, int is_int, int error_code, | ||
140 | + unsigned int next_eip); | ||
141 | +void do_interrupt_user(int intno, int is_int, int error_code, | ||
142 | + unsigned int next_eip); | ||
133 | void raise_interrupt(int intno, int is_int, int error_code, | 143 | void raise_interrupt(int intno, int is_int, int error_code, |
134 | unsigned int next_eip); | 144 | unsigned int next_eip); |
135 | void raise_exception_err(int exception_index, int error_code); | 145 | void raise_exception_err(int exception_index, int error_code); |
@@ -329,3 +339,22 @@ void helper_frstor(uint8_t *ptr, int data32); | @@ -329,3 +339,22 @@ void helper_frstor(uint8_t *ptr, int data32); | ||
329 | const uint8_t parity_table[256]; | 339 | const uint8_t parity_table[256]; |
330 | const uint8_t rclw_table[32]; | 340 | const uint8_t rclw_table[32]; |
331 | const uint8_t rclb_table[32]; | 341 | const uint8_t rclb_table[32]; |
342 | + | ||
343 | +static inline uint32_t compute_eflags(void) | ||
344 | +{ | ||
345 | + return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); | ||
346 | +} | ||
347 | + | ||
348 | +#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK) | ||
349 | + | ||
350 | +#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \ | ||
351 | + RF_MASK | AC_MASK | ID_MASK) | ||
352 | + | ||
353 | +/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */ | ||
354 | +static inline void load_eflags(int eflags, int update_mask) | ||
355 | +{ | ||
356 | + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); | ||
357 | + DF = 1 - (2 * ((eflags >> 10) & 1)); | ||
358 | + env->eflags = (env->eflags & ~update_mask) | | ||
359 | + (eflags & update_mask); | ||
360 | +} |
helper-i386.c
@@ -126,17 +126,74 @@ void cpu_loop_exit(void) | @@ -126,17 +126,74 @@ void cpu_loop_exit(void) | ||
126 | longjmp(env->jmp_env, 1); | 126 | longjmp(env->jmp_env, 1); |
127 | } | 127 | } |
128 | 128 | ||
129 | +static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, | ||
130 | + uint32_t *esp_ptr, int dpl) | ||
131 | +{ | ||
132 | + int type, index, shift; | ||
133 | + | ||
129 | #if 0 | 134 | #if 0 |
130 | -/* full interrupt support (only useful for real CPU emulation, not | ||
131 | - finished) - I won't do it any time soon, finish it if you want ! */ | ||
132 | -void raise_interrupt(int intno, int is_int, int error_code, | ||
133 | - unsigned int next_eip) | 135 | + { |
136 | + int i; | ||
137 | + printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); | ||
138 | + for(i=0;i<env->tr.limit;i++) { | ||
139 | + printf("%02x ", env->tr.base[i]); | ||
140 | + if ((i & 7) == 7) printf("\n"); | ||
141 | + } | ||
142 | + printf("\n"); | ||
143 | + } | ||
144 | +#endif | ||
145 | + | ||
146 | + if (!(env->tr.flags & DESC_P_MASK)) | ||
147 | + cpu_abort(env, "invalid tss"); | ||
148 | + type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; | ||
149 | + if ((type & 7) != 1) | ||
150 | + cpu_abort(env, "invalid tss type"); | ||
151 | + shift = type >> 3; | ||
152 | + index = (dpl * 4 + 2) << shift; | ||
153 | + if (index + (4 << shift) - 1 > env->tr.limit) | ||
154 | + raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); | ||
155 | + if (shift == 0) { | ||
156 | + *esp_ptr = lduw(env->tr.base + index); | ||
157 | + *ss_ptr = lduw(env->tr.base + index + 2); | ||
158 | + } else { | ||
159 | + *esp_ptr = ldl(env->tr.base + index); | ||
160 | + *ss_ptr = lduw(env->tr.base + index + 4); | ||
161 | + } | ||
162 | +} | ||
163 | + | ||
164 | +/* return non zero if error */ | ||
165 | +static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, | ||
166 | + int selector) | ||
134 | { | 167 | { |
135 | - SegmentDescriptorTable *dt; | 168 | + SegmentCache *dt; |
169 | + int index; | ||
136 | uint8_t *ptr; | 170 | uint8_t *ptr; |
137 | - int type, dpl, cpl; | ||
138 | - uint32_t e1, e2; | ||
139 | - | 171 | + |
172 | + if (selector & 0x4) | ||
173 | + dt = &env->ldt; | ||
174 | + else | ||
175 | + dt = &env->gdt; | ||
176 | + index = selector & ~7; | ||
177 | + if ((index + 7) > dt->limit) | ||
178 | + return -1; | ||
179 | + ptr = dt->base + index; | ||
180 | + *e1_ptr = ldl(ptr); | ||
181 | + *e2_ptr = ldl(ptr + 4); | ||
182 | + return 0; | ||
183 | +} | ||
184 | + | ||
185 | + | ||
186 | +/* protected mode interrupt */ | ||
187 | +static void do_interrupt_protected(int intno, int is_int, int error_code, | ||
188 | + unsigned int next_eip) | ||
189 | +{ | ||
190 | + SegmentCache *dt; | ||
191 | + uint8_t *ptr, *ssp; | ||
192 | + int type, dpl, cpl, selector, ss_dpl; | ||
193 | + int has_error_code, new_stack, shift; | ||
194 | + uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; | ||
195 | + uint32_t old_cs, old_ss, old_esp, old_eip; | ||
196 | + | ||
140 | dt = &env->idt; | 197 | dt = &env->idt; |
141 | if (intno * 8 + 7 > dt->limit) | 198 | if (intno * 8 + 7 > dt->limit) |
142 | raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | 199 | raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
@@ -147,6 +204,8 @@ void raise_interrupt(int intno, int is_int, int error_code, | @@ -147,6 +204,8 @@ void raise_interrupt(int intno, int is_int, int error_code, | ||
147 | type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; | 204 | type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; |
148 | switch(type) { | 205 | switch(type) { |
149 | case 5: /* task gate */ | 206 | case 5: /* task gate */ |
207 | + cpu_abort(env, "task gate not supported"); | ||
208 | + break; | ||
150 | case 6: /* 286 interrupt gate */ | 209 | case 6: /* 286 interrupt gate */ |
151 | case 7: /* 286 trap gate */ | 210 | case 7: /* 286 trap gate */ |
152 | case 14: /* 386 interrupt gate */ | 211 | case 14: /* 386 interrupt gate */ |
@@ -164,17 +223,184 @@ void raise_interrupt(int intno, int is_int, int error_code, | @@ -164,17 +223,184 @@ void raise_interrupt(int intno, int is_int, int error_code, | ||
164 | /* check valid bit */ | 223 | /* check valid bit */ |
165 | if (!(e2 & DESC_P_MASK)) | 224 | if (!(e2 & DESC_P_MASK)) |
166 | raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); | 225 | raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); |
226 | + selector = e1 >> 16; | ||
227 | + offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); | ||
228 | + if ((selector & 0xfffc) == 0) | ||
229 | + raise_exception_err(EXCP0D_GPF, 0); | ||
230 | + | ||
231 | + if (load_segment(&e1, &e2, selector) != 0) | ||
232 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | ||
233 | + if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) | ||
234 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | ||
235 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | ||
236 | + if (dpl > cpl) | ||
237 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | ||
238 | + if (!(e2 & DESC_P_MASK)) | ||
239 | + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | ||
240 | + if (!(e2 & DESC_C_MASK) && dpl < cpl) { | ||
241 | + /* to inner priviledge */ | ||
242 | + get_ss_esp_from_tss(&ss, &esp, dpl); | ||
243 | + if ((ss & 0xfffc) == 0) | ||
244 | + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | ||
245 | + if ((ss & 3) != dpl) | ||
246 | + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | ||
247 | + if (load_segment(&ss_e1, &ss_e2, ss) != 0) | ||
248 | + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | ||
249 | + ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; | ||
250 | + if (ss_dpl != dpl) | ||
251 | + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | ||
252 | + if (!(ss_e2 & DESC_S_MASK) || | ||
253 | + (ss_e2 & DESC_CS_MASK) || | ||
254 | + !(ss_e2 & DESC_W_MASK)) | ||
255 | + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | ||
256 | + if (!(ss_e2 & DESC_P_MASK)) | ||
257 | + raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | ||
258 | + new_stack = 1; | ||
259 | + } else if ((e2 & DESC_C_MASK) || dpl == cpl) { | ||
260 | + /* to same priviledge */ | ||
261 | + new_stack = 0; | ||
262 | + } else { | ||
263 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | ||
264 | + new_stack = 0; /* avoid warning */ | ||
265 | + } | ||
266 | + | ||
267 | + shift = type >> 3; | ||
268 | + has_error_code = 0; | ||
269 | + if (!is_int) { | ||
270 | + switch(intno) { | ||
271 | + case 8: | ||
272 | + case 10: | ||
273 | + case 11: | ||
274 | + case 12: | ||
275 | + case 13: | ||
276 | + case 14: | ||
277 | + case 17: | ||
278 | + has_error_code = 1; | ||
279 | + break; | ||
280 | + } | ||
281 | + } | ||
282 | + push_size = 6 + (new_stack << 2) + (has_error_code << 1); | ||
283 | + if (env->eflags & VM_MASK) | ||
284 | + push_size += 8; | ||
285 | + push_size <<= shift; | ||
286 | + | ||
287 | + /* XXX: check that enough room is available */ | ||
288 | + if (new_stack) { | ||
289 | + old_esp = env->regs[R_ESP]; | ||
290 | + old_ss = env->segs[R_SS].selector; | ||
291 | + load_seg(R_SS, ss, env->eip); | ||
292 | + } else { | ||
293 | + old_esp = 0; | ||
294 | + old_ss = 0; | ||
295 | + esp = env->regs[R_ESP]; | ||
296 | + } | ||
297 | + if (is_int) | ||
298 | + old_eip = next_eip; | ||
299 | + else | ||
300 | + old_eip = env->eip; | ||
301 | + old_cs = env->segs[R_CS].selector; | ||
302 | + load_seg(R_CS, selector, env->eip); | ||
303 | + env->eip = offset; | ||
304 | + env->regs[R_ESP] = esp - push_size; | ||
305 | + ssp = env->segs[R_SS].base + esp; | ||
306 | + if (shift == 1) { | ||
307 | + int old_eflags; | ||
308 | + if (env->eflags & VM_MASK) { | ||
309 | + ssp -= 4; | ||
310 | + stl(ssp, env->segs[R_GS].selector); | ||
311 | + ssp -= 4; | ||
312 | + stl(ssp, env->segs[R_FS].selector); | ||
313 | + ssp -= 4; | ||
314 | + stl(ssp, env->segs[R_DS].selector); | ||
315 | + ssp -= 4; | ||
316 | + stl(ssp, env->segs[R_ES].selector); | ||
317 | + } | ||
318 | + if (new_stack) { | ||
319 | + ssp -= 4; | ||
320 | + stl(ssp, old_ss); | ||
321 | + ssp -= 4; | ||
322 | + stl(ssp, old_esp); | ||
323 | + } | ||
324 | + ssp -= 4; | ||
325 | + old_eflags = compute_eflags(); | ||
326 | + stl(ssp, old_eflags); | ||
327 | + ssp -= 4; | ||
328 | + stl(ssp, old_cs); | ||
329 | + ssp -= 4; | ||
330 | + stl(ssp, old_eip); | ||
331 | + if (has_error_code) { | ||
332 | + ssp -= 4; | ||
333 | + stl(ssp, error_code); | ||
334 | + } | ||
335 | + } else { | ||
336 | + if (new_stack) { | ||
337 | + ssp -= 2; | ||
338 | + stw(ssp, old_ss); | ||
339 | + ssp -= 2; | ||
340 | + stw(ssp, old_esp); | ||
341 | + } | ||
342 | + ssp -= 2; | ||
343 | + stw(ssp, compute_eflags()); | ||
344 | + ssp -= 2; | ||
345 | + stw(ssp, old_cs); | ||
346 | + ssp -= 2; | ||
347 | + stw(ssp, old_eip); | ||
348 | + if (has_error_code) { | ||
349 | + ssp -= 2; | ||
350 | + stw(ssp, error_code); | ||
351 | + } | ||
352 | + } | ||
353 | + | ||
354 | + /* interrupt gate clear IF mask */ | ||
355 | + if ((type & 1) == 0) { | ||
356 | + env->eflags &= ~IF_MASK; | ||
357 | + } | ||
358 | + env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); | ||
167 | } | 359 | } |
168 | 360 | ||
169 | -#else | 361 | +/* real mode interrupt */ |
362 | +static void do_interrupt_real(int intno, int is_int, int error_code, | ||
363 | + unsigned int next_eip) | ||
364 | +{ | ||
365 | + SegmentCache *dt; | ||
366 | + uint8_t *ptr, *ssp; | ||
367 | + int selector; | ||
368 | + uint32_t offset, esp; | ||
369 | + uint32_t old_cs, old_eip; | ||
170 | 370 | ||
171 | -/* | ||
172 | - * is_int is TRUE if coming from the int instruction. next_eip is the | ||
173 | - * EIP value AFTER the interrupt instruction. It is only relevant if | ||
174 | - * is_int is TRUE. | ||
175 | - */ | ||
176 | -void raise_interrupt(int intno, int is_int, int error_code, | ||
177 | - unsigned int next_eip) | 371 | + /* real mode (simpler !) */ |
372 | + dt = &env->idt; | ||
373 | + if (intno * 4 + 3 > dt->limit) | ||
374 | + raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | ||
375 | + ptr = dt->base + intno * 4; | ||
376 | + offset = lduw(ptr); | ||
377 | + selector = lduw(ptr + 2); | ||
378 | + esp = env->regs[R_ESP] & 0xffff; | ||
379 | + ssp = env->segs[R_SS].base + esp; | ||
380 | + if (is_int) | ||
381 | + old_eip = next_eip; | ||
382 | + else | ||
383 | + old_eip = env->eip; | ||
384 | + old_cs = env->segs[R_CS].selector; | ||
385 | + ssp -= 2; | ||
386 | + stw(ssp, compute_eflags()); | ||
387 | + ssp -= 2; | ||
388 | + stw(ssp, old_cs); | ||
389 | + ssp -= 2; | ||
390 | + stw(ssp, old_eip); | ||
391 | + esp -= 6; | ||
392 | + | ||
393 | + /* update processor state */ | ||
394 | + env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff); | ||
395 | + env->eip = offset; | ||
396 | + env->segs[R_CS].selector = selector; | ||
397 | + env->segs[R_CS].base = (uint8_t *)(selector << 4); | ||
398 | + env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); | ||
399 | +} | ||
400 | + | ||
401 | +/* fake user mode interrupt */ | ||
402 | +void do_interrupt_user(int intno, int is_int, int error_code, | ||
403 | + unsigned int next_eip) | ||
178 | { | 404 | { |
179 | SegmentCache *dt; | 405 | SegmentCache *dt; |
180 | uint8_t *ptr; | 406 | uint8_t *ptr; |
@@ -196,14 +422,39 @@ void raise_interrupt(int intno, int is_int, int error_code, | @@ -196,14 +422,39 @@ void raise_interrupt(int intno, int is_int, int error_code, | ||
196 | code */ | 422 | code */ |
197 | if (is_int) | 423 | if (is_int) |
198 | EIP = next_eip; | 424 | EIP = next_eip; |
425 | +} | ||
426 | + | ||
427 | +/* | ||
428 | + * Begin excution of an interruption. is_int is TRUE if coming from | ||
429 | + * the int instruction. next_eip is the EIP value AFTER the interrupt | ||
430 | + * instruction. It is only relevant if is_int is TRUE. | ||
431 | + */ | ||
432 | +void do_interrupt(int intno, int is_int, int error_code, | ||
433 | + unsigned int next_eip) | ||
434 | +{ | ||
435 | + if (env->cr[0] & CR0_PE_MASK) { | ||
436 | + do_interrupt_protected(intno, is_int, error_code, next_eip); | ||
437 | + } else { | ||
438 | + do_interrupt_real(intno, is_int, error_code, next_eip); | ||
439 | + } | ||
440 | +} | ||
441 | + | ||
442 | +/* | ||
443 | + * Signal an interruption. It is executed in the main CPU loop. | ||
444 | + * is_int is TRUE if coming from the int instruction. next_eip is the | ||
445 | + * EIP value AFTER the interrupt instruction. It is only relevant if | ||
446 | + * is_int is TRUE. | ||
447 | + */ | ||
448 | +void raise_interrupt(int intno, int is_int, int error_code, | ||
449 | + unsigned int next_eip) | ||
450 | +{ | ||
199 | env->exception_index = intno; | 451 | env->exception_index = intno; |
200 | env->error_code = error_code; | 452 | env->error_code = error_code; |
201 | - | 453 | + env->exception_is_int = is_int; |
454 | + env->exception_next_eip = next_eip; | ||
202 | cpu_loop_exit(); | 455 | cpu_loop_exit(); |
203 | } | 456 | } |
204 | 457 | ||
205 | -#endif | ||
206 | - | ||
207 | /* shortcuts to generate exceptions */ | 458 | /* shortcuts to generate exceptions */ |
208 | void raise_exception_err(int exception_index, int error_code) | 459 | void raise_exception_err(int exception_index, int error_code) |
209 | { | 460 | { |
@@ -335,9 +586,9 @@ static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2) | @@ -335,9 +586,9 @@ static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2) | ||
335 | { | 586 | { |
336 | sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); | 587 | sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); |
337 | sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); | 588 | sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
338 | - if (e2 & (1 << 23)) | 589 | + if (e2 & DESC_G_MASK) |
339 | sc->limit = (sc->limit << 12) | 0xfff; | 590 | sc->limit = (sc->limit << 12) | 0xfff; |
340 | - sc->seg_32bit = (e2 >> 22) & 1; | 591 | + sc->flags = e2; |
341 | } | 592 | } |
342 | 593 | ||
343 | void helper_lldt_T0(void) | 594 | void helper_lldt_T0(void) |
@@ -382,9 +633,10 @@ void helper_ltr_T0(void) | @@ -382,9 +633,10 @@ void helper_ltr_T0(void) | ||
382 | 633 | ||
383 | selector = T0 & 0xffff; | 634 | selector = T0 & 0xffff; |
384 | if ((selector & 0xfffc) == 0) { | 635 | if ((selector & 0xfffc) == 0) { |
385 | - /* XXX: NULL selector case: invalid LDT */ | 636 | + /* NULL selector case: invalid LDT */ |
386 | env->tr.base = NULL; | 637 | env->tr.base = NULL; |
387 | env->tr.limit = 0; | 638 | env->tr.limit = 0; |
639 | + env->tr.flags = 0; | ||
388 | } else { | 640 | } else { |
389 | if (selector & 0x4) | 641 | if (selector & 0x4) |
390 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 642 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
@@ -412,10 +664,7 @@ void helper_ltr_T0(void) | @@ -412,10 +664,7 @@ void helper_ltr_T0(void) | ||
412 | void load_seg(int seg_reg, int selector, unsigned int cur_eip) | 664 | void load_seg(int seg_reg, int selector, unsigned int cur_eip) |
413 | { | 665 | { |
414 | SegmentCache *sc; | 666 | SegmentCache *sc; |
415 | - SegmentCache *dt; | ||
416 | - int index; | ||
417 | uint32_t e1, e2; | 667 | uint32_t e1, e2; |
418 | - uint8_t *ptr; | ||
419 | 668 | ||
420 | sc = &env->segs[seg_reg]; | 669 | sc = &env->segs[seg_reg]; |
421 | if ((selector & 0xfffc) == 0) { | 670 | if ((selector & 0xfffc) == 0) { |
@@ -427,21 +676,13 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | @@ -427,21 +676,13 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | ||
427 | /* XXX: each access should trigger an exception */ | 676 | /* XXX: each access should trigger an exception */ |
428 | sc->base = NULL; | 677 | sc->base = NULL; |
429 | sc->limit = 0; | 678 | sc->limit = 0; |
430 | - sc->seg_32bit = 1; | 679 | + sc->flags = 0; |
431 | } | 680 | } |
432 | } else { | 681 | } else { |
433 | - if (selector & 0x4) | ||
434 | - dt = &env->ldt; | ||
435 | - else | ||
436 | - dt = &env->gdt; | ||
437 | - index = selector & ~7; | ||
438 | - if ((index + 7) > dt->limit) { | 682 | + if (load_segment(&e1, &e2, selector) != 0) { |
439 | EIP = cur_eip; | 683 | EIP = cur_eip; |
440 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 684 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
441 | } | 685 | } |
442 | - ptr = dt->base + index; | ||
443 | - e1 = ldl(ptr); | ||
444 | - e2 = ldl(ptr + 4); | ||
445 | if (!(e2 & DESC_S_MASK) || | 686 | if (!(e2 & DESC_S_MASK) || |
446 | (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { | 687 | (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { |
447 | EIP = cur_eip; | 688 | EIP = cur_eip; |
@@ -469,8 +710,8 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | @@ -469,8 +710,8 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | ||
469 | } | 710 | } |
470 | load_seg_cache(sc, e1, e2); | 711 | load_seg_cache(sc, e1, e2); |
471 | #if 0 | 712 | #if 0 |
472 | - fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", | ||
473 | - selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); | 713 | + fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", |
714 | + selector, (unsigned long)sc->base, sc->limit, sc->flags); | ||
474 | #endif | 715 | #endif |
475 | } | 716 | } |
476 | sc->selector = selector; | 717 | sc->selector = selector; |
@@ -480,25 +721,14 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | @@ -480,25 +721,14 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) | ||
480 | void jmp_seg(int selector, unsigned int new_eip) | 721 | void jmp_seg(int selector, unsigned int new_eip) |
481 | { | 722 | { |
482 | SegmentCache sc1; | 723 | SegmentCache sc1; |
483 | - SegmentCache *dt; | ||
484 | - int index; | ||
485 | uint32_t e1, e2, cpl, dpl, rpl; | 724 | uint32_t e1, e2, cpl, dpl, rpl; |
486 | - uint8_t *ptr; | ||
487 | 725 | ||
488 | if ((selector & 0xfffc) == 0) { | 726 | if ((selector & 0xfffc) == 0) { |
489 | raise_exception_err(EXCP0D_GPF, 0); | 727 | raise_exception_err(EXCP0D_GPF, 0); |
490 | } | 728 | } |
491 | 729 | ||
492 | - if (selector & 0x4) | ||
493 | - dt = &env->ldt; | ||
494 | - else | ||
495 | - dt = &env->gdt; | ||
496 | - index = selector & ~7; | ||
497 | - if ((index + 7) > dt->limit) | 730 | + if (load_segment(&e1, &e2, selector) != 0) |
498 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | 731 | raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
499 | - ptr = dt->base + index; | ||
500 | - e1 = ldl(ptr); | ||
501 | - e2 = ldl(ptr + 4); | ||
502 | cpl = env->segs[R_CS].selector & 3; | 732 | cpl = env->segs[R_CS].selector & 3; |
503 | if (e2 & DESC_S_MASK) { | 733 | if (e2 & DESC_S_MASK) { |
504 | if (!(e2 & DESC_CS_MASK)) | 734 | if (!(e2 & DESC_CS_MASK)) |
@@ -530,22 +760,143 @@ void jmp_seg(int selector, unsigned int new_eip) | @@ -530,22 +760,143 @@ void jmp_seg(int selector, unsigned int new_eip) | ||
530 | } | 760 | } |
531 | } | 761 | } |
532 | 762 | ||
533 | -/* XXX: do more */ | 763 | +/* init the segment cache in vm86 mode */ |
764 | +static inline void load_seg_vm(int seg, int selector) | ||
765 | +{ | ||
766 | + SegmentCache *sc = &env->segs[seg]; | ||
767 | + selector &= 0xffff; | ||
768 | + sc->base = (uint8_t *)(selector << 4); | ||
769 | + sc->selector = selector; | ||
770 | + sc->flags = 0; | ||
771 | + sc->limit = 0xffff; | ||
772 | +} | ||
773 | + | ||
774 | +/* protected mode iret */ | ||
775 | +void helper_iret_protected(int shift) | ||
776 | +{ | ||
777 | + uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; | ||
778 | + uint32_t new_es, new_ds, new_fs, new_gs; | ||
779 | + uint32_t e1, e2; | ||
780 | + int cpl, dpl, rpl, eflags_mask; | ||
781 | + uint8_t *ssp; | ||
782 | + | ||
783 | + sp = env->regs[R_ESP]; | ||
784 | + if (!(env->segs[R_SS].flags & DESC_B_MASK)) | ||
785 | + sp &= 0xffff; | ||
786 | + ssp = env->segs[R_SS].base + sp; | ||
787 | + if (shift == 1) { | ||
788 | + /* 32 bits */ | ||
789 | + new_eflags = ldl(ssp + 8); | ||
790 | + new_cs = ldl(ssp + 4) & 0xffff; | ||
791 | + new_eip = ldl(ssp); | ||
792 | + if (new_eflags & VM_MASK) | ||
793 | + goto return_to_vm86; | ||
794 | + } else { | ||
795 | + /* 16 bits */ | ||
796 | + new_eflags = lduw(ssp + 4); | ||
797 | + new_cs = lduw(ssp + 2); | ||
798 | + new_eip = lduw(ssp); | ||
799 | + } | ||
800 | + if ((new_cs & 0xfffc) == 0) | ||
801 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
802 | + if (load_segment(&e1, &e2, new_cs) != 0) | ||
803 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
804 | + if (!(e2 & DESC_S_MASK) || | ||
805 | + !(e2 & DESC_CS_MASK)) | ||
806 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
807 | + cpl = env->segs[R_CS].selector & 3; | ||
808 | + rpl = new_cs & 3; | ||
809 | + if (rpl < cpl) | ||
810 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
811 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | ||
812 | + if (e2 & DESC_CS_MASK) { | ||
813 | + if (dpl > rpl) | ||
814 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
815 | + } else { | ||
816 | + if (dpl != rpl) | ||
817 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | ||
818 | + } | ||
819 | + if (!(e2 & DESC_P_MASK)) | ||
820 | + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); | ||
821 | + | ||
822 | + if (rpl == cpl) { | ||
823 | + /* return to same priledge level */ | ||
824 | + load_seg(R_CS, new_cs, env->eip); | ||
825 | + new_esp = sp + (6 << shift); | ||
826 | + } else { | ||
827 | + /* return to differentr priviledge level */ | ||
828 | + if (shift == 1) { | ||
829 | + /* 32 bits */ | ||
830 | + new_esp = ldl(ssp + 12); | ||
831 | + new_ss = ldl(ssp + 16) & 0xffff; | ||
832 | + } else { | ||
833 | + /* 16 bits */ | ||
834 | + new_esp = lduw(ssp + 6); | ||
835 | + new_ss = lduw(ssp + 8); | ||
836 | + } | ||
837 | + | ||
838 | + if ((new_ss & 3) != rpl) | ||
839 | + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); | ||
840 | + if (load_segment(&e1, &e2, new_ss) != 0) | ||
841 | + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); | ||
842 | + if (!(e2 & DESC_S_MASK) || | ||
843 | + (e2 & DESC_CS_MASK) || | ||
844 | + !(e2 & DESC_W_MASK)) | ||
845 | + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); | ||
846 | + dpl = (e2 >> DESC_DPL_SHIFT) & 3; | ||
847 | + if (dpl != rpl) | ||
848 | + raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); | ||
849 | + if (!(e2 & DESC_P_MASK)) | ||
850 | + raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); | ||
851 | + | ||
852 | + load_seg(R_CS, new_cs, env->eip); | ||
853 | + load_seg(R_SS, new_ss, env->eip); | ||
854 | + } | ||
855 | + if (env->segs[R_SS].flags & DESC_B_MASK) | ||
856 | + env->regs[R_ESP] = new_esp; | ||
857 | + else | ||
858 | + env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | | ||
859 | + (new_esp & 0xffff); | ||
860 | + env->eip = new_eip; | ||
861 | + if (cpl == 0) | ||
862 | + eflags_mask = FL_UPDATE_CPL0_MASK; | ||
863 | + else | ||
864 | + eflags_mask = FL_UPDATE_MASK32; | ||
865 | + if (shift == 0) | ||
866 | + eflags_mask &= 0xffff; | ||
867 | + load_eflags(new_eflags, eflags_mask); | ||
868 | + return; | ||
869 | + | ||
870 | + return_to_vm86: | ||
871 | + new_esp = ldl(ssp + 12); | ||
872 | + new_ss = ldl(ssp + 16); | ||
873 | + new_es = ldl(ssp + 20); | ||
874 | + new_ds = ldl(ssp + 24); | ||
875 | + new_fs = ldl(ssp + 28); | ||
876 | + new_gs = ldl(ssp + 32); | ||
877 | + | ||
878 | + /* modify processor state */ | ||
879 | + load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); | ||
880 | + load_seg_vm(R_CS, new_cs); | ||
881 | + load_seg_vm(R_SS, new_ss); | ||
882 | + load_seg_vm(R_ES, new_es); | ||
883 | + load_seg_vm(R_DS, new_ds); | ||
884 | + load_seg_vm(R_FS, new_fs); | ||
885 | + load_seg_vm(R_GS, new_gs); | ||
886 | + | ||
887 | + env->eip = new_eip; | ||
888 | + env->regs[R_ESP] = new_esp; | ||
889 | +} | ||
890 | + | ||
534 | void helper_movl_crN_T0(int reg) | 891 | void helper_movl_crN_T0(int reg) |
535 | { | 892 | { |
893 | + env->cr[reg] = T0; | ||
536 | switch(reg) { | 894 | switch(reg) { |
537 | case 0: | 895 | case 0: |
538 | - default: | ||
539 | - env->cr[0] = reg; | ||
540 | - break; | ||
541 | - case 2: | ||
542 | - env->cr[2] = reg; | 896 | + cpu_x86_update_cr0(env); |
543 | break; | 897 | break; |
544 | case 3: | 898 | case 3: |
545 | - env->cr[3] = reg; | ||
546 | - break; | ||
547 | - case 4: | ||
548 | - env->cr[4] = reg; | 899 | + cpu_x86_update_cr3(env); |
549 | break; | 900 | break; |
550 | } | 901 | } |
551 | } | 902 | } |
@@ -556,6 +907,11 @@ void helper_movl_drN_T0(int reg) | @@ -556,6 +907,11 @@ void helper_movl_drN_T0(int reg) | ||
556 | env->dr[reg] = T0; | 907 | env->dr[reg] = T0; |
557 | } | 908 | } |
558 | 909 | ||
910 | +void helper_invlpg(unsigned int addr) | ||
911 | +{ | ||
912 | + cpu_x86_flush_tlb(env, addr); | ||
913 | +} | ||
914 | + | ||
559 | /* rdtsc */ | 915 | /* rdtsc */ |
560 | #ifndef __i386__ | 916 | #ifndef __i386__ |
561 | uint64_t emu_time; | 917 | uint64_t emu_time; |
@@ -577,23 +933,12 @@ void helper_rdtsc(void) | @@ -577,23 +933,12 @@ void helper_rdtsc(void) | ||
577 | void helper_lsl(void) | 933 | void helper_lsl(void) |
578 | { | 934 | { |
579 | unsigned int selector, limit; | 935 | unsigned int selector, limit; |
580 | - SegmentCache *dt; | ||
581 | - int index; | ||
582 | uint32_t e1, e2; | 936 | uint32_t e1, e2; |
583 | - uint8_t *ptr; | ||
584 | 937 | ||
585 | CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; | 938 | CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; |
586 | selector = T0 & 0xffff; | 939 | selector = T0 & 0xffff; |
587 | - if (selector & 0x4) | ||
588 | - dt = &env->ldt; | ||
589 | - else | ||
590 | - dt = &env->gdt; | ||
591 | - index = selector & ~7; | ||
592 | - if ((index + 7) > dt->limit) | 940 | + if (load_segment(&e1, &e2, selector) != 0) |
593 | return; | 941 | return; |
594 | - ptr = dt->base + index; | ||
595 | - e1 = ldl(ptr); | ||
596 | - e2 = ldl(ptr + 4); | ||
597 | limit = (e1 & 0xffff) | (e2 & 0x000f0000); | 942 | limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
598 | if (e2 & (1 << 23)) | 943 | if (e2 & (1 << 23)) |
599 | limit = (limit << 12) | 0xfff; | 944 | limit = (limit << 12) | 0xfff; |
@@ -604,22 +949,12 @@ void helper_lsl(void) | @@ -604,22 +949,12 @@ void helper_lsl(void) | ||
604 | void helper_lar(void) | 949 | void helper_lar(void) |
605 | { | 950 | { |
606 | unsigned int selector; | 951 | unsigned int selector; |
607 | - SegmentCache *dt; | ||
608 | - int index; | ||
609 | - uint32_t e2; | ||
610 | - uint8_t *ptr; | 952 | + uint32_t e1, e2; |
611 | 953 | ||
612 | CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; | 954 | CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; |
613 | selector = T0 & 0xffff; | 955 | selector = T0 & 0xffff; |
614 | - if (selector & 0x4) | ||
615 | - dt = &env->ldt; | ||
616 | - else | ||
617 | - dt = &env->gdt; | ||
618 | - index = selector & ~7; | ||
619 | - if ((index + 7) > dt->limit) | 956 | + if (load_segment(&e1, &e2, selector) != 0) |
620 | return; | 957 | return; |
621 | - ptr = dt->base + index; | ||
622 | - e2 = ldl(ptr + 4); | ||
623 | T1 = e2 & 0x00f0ff00; | 958 | T1 = e2 & 0x00f0ff00; |
624 | CC_SRC |= CC_Z; | 959 | CC_SRC |= CC_Z; |
625 | } | 960 | } |
op-i386.c
@@ -493,6 +493,12 @@ void OPPROTO op_jmp_im(void) | @@ -493,6 +493,12 @@ void OPPROTO op_jmp_im(void) | ||
493 | EIP = PARAM1; | 493 | EIP = PARAM1; |
494 | } | 494 | } |
495 | 495 | ||
496 | +void OPPROTO op_hlt(void) | ||
497 | +{ | ||
498 | + env->exception_index = EXCP_HLT; | ||
499 | + cpu_loop_exit(); | ||
500 | +} | ||
501 | + | ||
496 | void OPPROTO op_raise_interrupt(void) | 502 | void OPPROTO op_raise_interrupt(void) |
497 | { | 503 | { |
498 | int intno; | 504 | int intno; |
@@ -954,6 +960,11 @@ void OPPROTO op_ljmp_T0_T1(void) | @@ -954,6 +960,11 @@ void OPPROTO op_ljmp_T0_T1(void) | ||
954 | jmp_seg(T0 & 0xffff, T1); | 960 | jmp_seg(T0 & 0xffff, T1); |
955 | } | 961 | } |
956 | 962 | ||
963 | +void OPPROTO op_iret_protected(void) | ||
964 | +{ | ||
965 | + helper_iret_protected(PARAM1); | ||
966 | +} | ||
967 | + | ||
957 | void OPPROTO op_lldt_T0(void) | 968 | void OPPROTO op_lldt_T0(void) |
958 | { | 969 | { |
959 | helper_lldt_T0(); | 970 | helper_lldt_T0(); |
@@ -983,6 +994,11 @@ void OPPROTO op_lmsw_T0(void) | @@ -983,6 +994,11 @@ void OPPROTO op_lmsw_T0(void) | ||
983 | helper_movl_crN_T0(0); | 994 | helper_movl_crN_T0(0); |
984 | } | 995 | } |
985 | 996 | ||
997 | +void OPPROTO op_invlpg_A0(void) | ||
998 | +{ | ||
999 | + helper_invlpg(A0); | ||
1000 | +} | ||
1001 | + | ||
986 | void OPPROTO op_movl_T0_env(void) | 1002 | void OPPROTO op_movl_T0_env(void) |
987 | { | 1003 | { |
988 | T0 = *(uint32_t *)((char *)env + PARAM1); | 1004 | T0 = *(uint32_t *)((char *)env + PARAM1); |
@@ -1082,8 +1098,7 @@ void OPPROTO op_set_cc_op(void) | @@ -1082,8 +1098,7 @@ void OPPROTO op_set_cc_op(void) | ||
1082 | CC_OP = PARAM1; | 1098 | CC_OP = PARAM1; |
1083 | } | 1099 | } |
1084 | 1100 | ||
1085 | -#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK) | ||
1086 | -#define FL_UPDATE_MASK16 (TF_MASK) | 1101 | +#define FL_UPDATE_MASK16 (FL_UPDATE_MASK32 & 0xffff) |
1087 | 1102 | ||
1088 | void OPPROTO op_movl_eflags_T0(void) | 1103 | void OPPROTO op_movl_eflags_T0(void) |
1089 | { | 1104 | { |
@@ -1092,7 +1107,8 @@ void OPPROTO op_movl_eflags_T0(void) | @@ -1092,7 +1107,8 @@ void OPPROTO op_movl_eflags_T0(void) | ||
1092 | CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); | 1107 | CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); |
1093 | DF = 1 - (2 * ((eflags >> 10) & 1)); | 1108 | DF = 1 - (2 * ((eflags >> 10) & 1)); |
1094 | /* we also update some system flags as in user mode */ | 1109 | /* we also update some system flags as in user mode */ |
1095 | - env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | (eflags & FL_UPDATE_MASK32); | 1110 | + env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | |
1111 | + (eflags & FL_UPDATE_MASK32); | ||
1096 | } | 1112 | } |
1097 | 1113 | ||
1098 | void OPPROTO op_movw_eflags_T0(void) | 1114 | void OPPROTO op_movw_eflags_T0(void) |
@@ -1102,7 +1118,18 @@ void OPPROTO op_movw_eflags_T0(void) | @@ -1102,7 +1118,18 @@ void OPPROTO op_movw_eflags_T0(void) | ||
1102 | CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); | 1118 | CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); |
1103 | DF = 1 - (2 * ((eflags >> 10) & 1)); | 1119 | DF = 1 - (2 * ((eflags >> 10) & 1)); |
1104 | /* we also update some system flags as in user mode */ | 1120 | /* we also update some system flags as in user mode */ |
1105 | - env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | (eflags & FL_UPDATE_MASK16); | 1121 | + env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | |
1122 | + (eflags & FL_UPDATE_MASK16); | ||
1123 | +} | ||
1124 | + | ||
1125 | +void OPPROTO op_movl_eflags_T0_cpl0(void) | ||
1126 | +{ | ||
1127 | + load_eflags(T0, FL_UPDATE_CPL0_MASK); | ||
1128 | +} | ||
1129 | + | ||
1130 | +void OPPROTO op_movw_eflags_T0_cpl0(void) | ||
1131 | +{ | ||
1132 | + load_eflags(T0, FL_UPDATE_CPL0_MASK & 0xffff); | ||
1106 | } | 1133 | } |
1107 | 1134 | ||
1108 | #if 0 | 1135 | #if 0 |