Commit 90a9fdae1f1acc791abc2c20731eddf01ba73ae6

Authored by bellard
1 parent 3fb2ded1

more ring 0 operations


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@261 c046a42c-6fe2-441c-8c8c-71466251a162
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