Commit 7e84c2498f0ff3999937d18d1e9abaa030400000

Authored by bellard
1 parent e670b89e

full TSS support - IO map check support - conforming segment check fixes - iret in vm86 mode fix


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@450 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 465 additions and 60 deletions
target-i386/helper.c
... ... @@ -126,6 +126,56 @@ void cpu_loop_exit(void)
126 126 longjmp(env->jmp_env, 1);
127 127 }
128 128  
  129 +/* return non zero if error */
  130 +static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
  131 + int selector)
  132 +{
  133 + SegmentCache *dt;
  134 + int index;
  135 + uint8_t *ptr;
  136 +
  137 + if (selector & 0x4)
  138 + dt = &env->ldt;
  139 + else
  140 + dt = &env->gdt;
  141 + index = selector & ~7;
  142 + if ((index + 7) > dt->limit)
  143 + return -1;
  144 + ptr = dt->base + index;
  145 + *e1_ptr = ldl_kernel(ptr);
  146 + *e2_ptr = ldl_kernel(ptr + 4);
  147 + return 0;
  148 +}
  149 +
  150 +static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
  151 +{
  152 + unsigned int limit;
  153 + limit = (e1 & 0xffff) | (e2 & 0x000f0000);
  154 + if (e2 & DESC_G_MASK)
  155 + limit = (limit << 12) | 0xfff;
  156 + return limit;
  157 +}
  158 +
  159 +static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2)
  160 +{
  161 + return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
  162 +}
  163 +
  164 +static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
  165 +{
  166 + sc->base = get_seg_base(e1, e2);
  167 + sc->limit = get_seg_limit(e1, e2);
  168 + sc->flags = e2;
  169 +}
  170 +
  171 +/* init the segment cache in vm86 mode. */
  172 +static inline void load_seg_vm(int seg, int selector)
  173 +{
  174 + selector &= 0xffff;
  175 + cpu_x86_load_seg_cache(env, seg, selector,
  176 + (uint8_t *)(selector << 4), 0xffff, 0);
  177 +}
  178 +
129 179 static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
130 180 uint32_t *esp_ptr, int dpl)
131 181 {
... ... @@ -161,54 +211,322 @@ static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
161 211 }
162 212 }
163 213  
164   -/* return non zero if error */
165   -static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
166   - int selector)
  214 +/* XXX: merge with load_seg() */
  215 +static void tss_load_seg(int seg_reg, int selector)
167 216 {
  217 + uint32_t e1, e2;
  218 + int rpl, dpl, cpl;
  219 +
  220 + if ((selector & 0xfffc) != 0) {
  221 + if (load_segment(&e1, &e2, selector) != 0)
  222 + raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
  223 + if (!(e2 & DESC_S_MASK))
  224 + raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
  225 + rpl = selector & 3;
  226 + dpl = (e2 >> DESC_DPL_SHIFT) & 3;
  227 + cpl = env->hflags & HF_CPL_MASK;
  228 + if (seg_reg == R_CS) {
  229 + if (!(e2 & DESC_CS_MASK))
  230 + raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
  231 + if (dpl != rpl)
  232 + raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
  233 + if ((e2 & DESC_C_MASK) && dpl > rpl)
  234 + raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
  235 +
  236 + } else if (seg_reg == R_SS) {
  237 + /* SS must be writable data */
  238 + if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
  239 + raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
  240 + if (dpl != cpl || dpl != rpl)
  241 + raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
  242 + } else {
  243 + /* not readable code */
  244 + if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
  245 + raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
  246 + /* if data or non conforming code, checks the rights */
  247 + if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
  248 + if (dpl < cpl || dpl < rpl)
  249 + raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
  250 + }
  251 + }
  252 + if (!(e2 & DESC_P_MASK))
  253 + raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
  254 + cpu_x86_load_seg_cache(env, seg_reg, selector,
  255 + get_seg_base(e1, e2),
  256 + get_seg_limit(e1, e2),
  257 + e2);
  258 + } else {
  259 + if (seg_reg == R_SS || seg_reg == R_CS)
  260 + raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
  261 + }
  262 +}
  263 +
  264 +#define SWITCH_TSS_JMP 0
  265 +#define SWITCH_TSS_IRET 1
  266 +#define SWITCH_TSS_CALL 2
  267 +
  268 +/* XXX: restore CPU state in registers (PowerPC case) */
  269 +static void switch_tss(int tss_selector,
  270 + uint32_t e1, uint32_t e2, int source)
  271 +{
  272 + int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
  273 + uint8_t *tss_base;
  274 + uint32_t new_regs[8], new_segs[6];
  275 + uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
  276 + uint32_t old_eflags, eflags_mask;
168 277 SegmentCache *dt;
169 278 int index;
170 279 uint8_t *ptr;
171 280  
172   - if (selector & 0x4)
173   - dt = &env->ldt;
  281 + type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
  282 +
  283 + /* if task gate, we read the TSS segment and we load it */
  284 + if (type == 5) {
  285 + if (!(e2 & DESC_P_MASK))
  286 + raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
  287 + tss_selector = e1 >> 16;
  288 + if (tss_selector & 4)
  289 + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
  290 + if (load_segment(&e1, &e2, tss_selector) != 0)
  291 + raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
  292 + if (e2 & DESC_S_MASK)
  293 + raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
  294 + type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
  295 + if ((type & 7) != 1)
  296 + raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
  297 + }
  298 +
  299 + if (!(e2 & DESC_P_MASK))
  300 + raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
  301 +
  302 + if (type & 8)
  303 + tss_limit_max = 103;
174 304 else
175   - dt = &env->gdt;
176   - index = selector & ~7;
  305 + tss_limit_max = 43;
  306 + tss_limit = get_seg_limit(e1, e2);
  307 + tss_base = get_seg_base(e1, e2);
  308 + if ((tss_selector & 4) != 0 ||
  309 + tss_limit < tss_limit_max)
  310 + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
  311 + old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
  312 + if (old_type & 8)
  313 + old_tss_limit_max = 103;
  314 + else
  315 + old_tss_limit_max = 43;
  316 +
  317 + /* read all the registers from the new TSS */
  318 + if (type & 8) {
  319 + /* 32 bit */
  320 + new_cr3 = ldl_kernel(tss_base + 0x1c);
  321 + new_eip = ldl_kernel(tss_base + 0x20);
  322 + new_eflags = ldl_kernel(tss_base + 0x24);
  323 + for(i = 0; i < 8; i++)
  324 + new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
  325 + for(i = 0; i < 6; i++)
  326 + new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
  327 + new_ldt = lduw_kernel(tss_base + 0x60);
  328 + new_trap = ldl_kernel(tss_base + 0x64);
  329 + } else {
  330 + /* 16 bit */
  331 + new_cr3 = 0;
  332 + new_eip = lduw_kernel(tss_base + 0x0e);
  333 + new_eflags = lduw_kernel(tss_base + 0x10);
  334 + for(i = 0; i < 8; i++)
  335 + new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
  336 + for(i = 0; i < 4; i++)
  337 + new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
  338 + new_ldt = lduw_kernel(tss_base + 0x2a);
  339 + new_segs[R_FS] = 0;
  340 + new_segs[R_GS] = 0;
  341 + new_trap = 0;
  342 + }
  343 +
  344 + /* NOTE: we must avoid memory exceptions during the task switch,
  345 + so we make dummy accesses before */
  346 + /* XXX: it can still fail in some cases, so a bigger hack is
  347 + necessary to valid the TLB after having done the accesses */
  348 +
  349 + v1 = ldub_kernel(env->tr.base);
  350 + v2 = ldub(env->tr.base + old_tss_limit_max);
  351 + stb_kernel(env->tr.base, v1);
  352 + stb_kernel(env->tr.base + old_tss_limit_max, v2);
  353 +
  354 + /* clear busy bit (it is restartable) */
  355 + if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
  356 + uint8_t *ptr;
  357 + uint32_t e2;
  358 + ptr = env->gdt.base + (env->tr.selector << 3);
  359 + e2 = ldl_kernel(ptr + 4);
  360 + e2 &= ~DESC_TSS_BUSY_MASK;
  361 + stl_kernel(ptr + 4, e2);
  362 + }
  363 + old_eflags = compute_eflags();
  364 + if (source == SWITCH_TSS_IRET)
  365 + old_eflags &= ~NT_MASK;
  366 +
  367 + /* save the current state in the old TSS */
  368 + if (type & 8) {
  369 + /* 32 bit */
  370 + stl_kernel(env->tr.base + 0x20, env->eip);
  371 + stl_kernel(env->tr.base + 0x24, old_eflags);
  372 + for(i = 0; i < 8; i++)
  373 + stl_kernel(env->tr.base + (0x28 + i * 4), env->regs[i]);
  374 + for(i = 0; i < 6; i++)
  375 + stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
  376 + } else {
  377 + /* 16 bit */
  378 + stw_kernel(env->tr.base + 0x0e, new_eip);
  379 + stw_kernel(env->tr.base + 0x10, old_eflags);
  380 + for(i = 0; i < 8; i++)
  381 + stw_kernel(env->tr.base + (0x12 + i * 2), env->regs[i]);
  382 + for(i = 0; i < 4; i++)
  383 + stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
  384 + }
  385 +
  386 + /* now if an exception occurs, it will occurs in the next task
  387 + context */
  388 +
  389 + if (source == SWITCH_TSS_CALL) {
  390 + stw_kernel(tss_base, env->tr.selector);
  391 + new_eflags |= NT_MASK;
  392 + }
  393 +
  394 + /* set busy bit */
  395 + if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
  396 + uint8_t *ptr;
  397 + uint32_t e2;
  398 + ptr = env->gdt.base + (tss_selector << 3);
  399 + e2 = ldl_kernel(ptr + 4);
  400 + e2 |= DESC_TSS_BUSY_MASK;
  401 + stl_kernel(ptr + 4, e2);
  402 + }
  403 +
  404 + /* set the new CPU state */
  405 + /* from this point, any exception which occurs can give problems */
  406 + env->cr[0] |= CR0_TS_MASK;
  407 + env->tr.selector = tss_selector;
  408 + env->tr.base = tss_base;
  409 + env->tr.limit = tss_limit;
  410 + env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
  411 +
  412 + if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
  413 + env->cr[3] = new_cr3;
  414 + cpu_x86_update_cr3(env);
  415 + }
  416 +
  417 + /* load all registers without an exception, then reload them with
  418 + possible exception */
  419 + env->eip = new_eip;
  420 + eflags_mask = FL_UPDATE_CPL0_MASK;
  421 + if (!(type & 8))
  422 + eflags_mask &= 0xffff;
  423 + load_eflags(new_eflags, eflags_mask);
  424 + for(i = 0; i < 8; i++)
  425 + env->regs[i] = new_regs[i];
  426 + if (new_eflags & VM_MASK) {
  427 + for(i = 0; i < 6; i++)
  428 + load_seg_vm(i, new_segs[i]);
  429 + /* in vm86, CPL is always 3 */
  430 + cpu_x86_set_cpl(env, 3);
  431 + } else {
  432 + /* CPL is set the RPL of CS */
  433 + cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
  434 + /* first just selectors as the rest may trigger exceptions */
  435 + for(i = 0; i < 6; i++)
  436 + cpu_x86_load_seg_cache(env, i, new_segs[i], NULL, 0, 0);
  437 + }
  438 +
  439 + env->ldt.selector = new_ldt & ~4;
  440 + env->ldt.base = NULL;
  441 + env->ldt.limit = 0;
  442 + env->ldt.flags = 0;
  443 +
  444 + /* load the LDT */
  445 + if (new_ldt & 4)
  446 + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
  447 +
  448 + dt = &env->gdt;
  449 + index = new_ldt & ~7;
177 450 if ((index + 7) > dt->limit)
178   - return -1;
  451 + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
179 452 ptr = dt->base + index;
180   - *e1_ptr = ldl_kernel(ptr);
181   - *e2_ptr = ldl_kernel(ptr + 4);
182   - return 0;
  453 + e1 = ldl_kernel(ptr);
  454 + e2 = ldl_kernel(ptr + 4);
  455 + if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
  456 + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
  457 + if (!(e2 & DESC_P_MASK))
  458 + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
  459 + load_seg_cache_raw_dt(&env->ldt, e1, e2);
  460 +
  461 + /* load the segments */
  462 + if (!(new_eflags & VM_MASK)) {
  463 + tss_load_seg(R_CS, new_segs[R_CS]);
  464 + tss_load_seg(R_SS, new_segs[R_SS]);
  465 + tss_load_seg(R_ES, new_segs[R_ES]);
  466 + tss_load_seg(R_DS, new_segs[R_DS]);
  467 + tss_load_seg(R_FS, new_segs[R_FS]);
  468 + tss_load_seg(R_GS, new_segs[R_GS]);
  469 + }
  470 +
  471 + /* check that EIP is in the CS segment limits */
  472 + if (new_eip > env->segs[R_CS].limit) {
  473 + raise_exception_err(EXCP0D_GPF, 0);
  474 + }
183 475 }
184   -
185   -static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
  476 +
  477 +/* check if Port I/O is allowed in TSS */
  478 +static inline void check_io(int addr, int size)
186 479 {
187   - unsigned int limit;
188   - limit = (e1 & 0xffff) | (e2 & 0x000f0000);
189   - if (e2 & DESC_G_MASK)
190   - limit = (limit << 12) | 0xfff;
191   - return limit;
  480 + int io_offset, val, mask;
  481 +
  482 + /* TSS must be a valid 32 bit one */
  483 + if (!(env->tr.flags & DESC_P_MASK) ||
  484 + ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
  485 + env->tr.limit < 103)
  486 + goto fail;
  487 + io_offset = lduw_kernel(env->tr.base + 0x66);
  488 + io_offset += (addr >> 3);
  489 + /* Note: the check needs two bytes */
  490 + if ((io_offset + 1) > env->tr.limit)
  491 + goto fail;
  492 + val = lduw_kernel(env->tr.base + io_offset);
  493 + val >>= (addr & 7);
  494 + mask = (1 << size) - 1;
  495 + /* all bits must be zero to allow the I/O */
  496 + if ((val & mask) != 0) {
  497 + fail:
  498 + raise_exception_err(EXCP0D_GPF, 0);
  499 + }
192 500 }
193 501  
194   -static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2)
  502 +void check_iob_T0(void)
195 503 {
196   - return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
  504 + check_io(T0, 1);
197 505 }
198 506  
199   -static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
  507 +void check_iow_T0(void)
200 508 {
201   - sc->base = get_seg_base(e1, e2);
202   - sc->limit = get_seg_limit(e1, e2);
203   - sc->flags = e2;
  509 + check_io(T0, 2);
204 510 }
205 511  
206   -/* init the segment cache in vm86 mode. */
207   -static inline void load_seg_vm(int seg, int selector)
  512 +void check_iol_T0(void)
208 513 {
209   - selector &= 0xffff;
210   - cpu_x86_load_seg_cache(env, seg, selector,
211   - (uint8_t *)(selector << 4), 0xffff, 0);
  514 + check_io(T0, 4);
  515 +}
  516 +
  517 +void check_iob_DX(void)
  518 +{
  519 + check_io(EDX & 0xffff, 1);
  520 +}
  521 +
  522 +void check_iow_DX(void)
  523 +{
  524 + check_io(EDX & 0xffff, 2);
  525 +}
  526 +
  527 +void check_iol_DX(void)
  528 +{
  529 + check_io(EDX & 0xffff, 4);
212 530 }
213 531  
214 532 /* protected mode interrupt */
... ... @@ -222,6 +540,21 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
222 540 uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size;
223 541 uint32_t old_cs, old_ss, old_esp, old_eip;
224 542  
  543 + has_error_code = 0;
  544 + if (!is_int && !is_hw) {
  545 + switch(intno) {
  546 + case 8:
  547 + case 10:
  548 + case 11:
  549 + case 12:
  550 + case 13:
  551 + case 14:
  552 + case 17:
  553 + has_error_code = 1;
  554 + break;
  555 + }
  556 + }
  557 +
225 558 dt = &env->idt;
226 559 if (intno * 8 + 7 > dt->limit)
227 560 raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
... ... @@ -232,8 +565,27 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
232 565 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
233 566 switch(type) {
234 567 case 5: /* task gate */
235   - cpu_abort(env, "task gate not supported");
236   - break;
  568 + /* must do that check here to return the correct error code */
  569 + if (!(e2 & DESC_P_MASK))
  570 + raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
  571 + switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL);
  572 + if (has_error_code) {
  573 + int mask;
  574 + /* push the error code */
  575 + shift = (env->segs[R_CS].flags >> DESC_B_SHIFT) & 1;
  576 + if (env->segs[R_SS].flags & DESC_B_MASK)
  577 + mask = 0xffffffff;
  578 + else
  579 + mask = 0xffff;
  580 + esp = (env->regs[R_ESP] - (2 << shift)) & mask;
  581 + ssp = env->segs[R_SS].base + esp;
  582 + if (shift)
  583 + stl_kernel(ssp, error_code);
  584 + else
  585 + stw_kernel(ssp, error_code);
  586 + env->regs[R_ESP] = (esp & mask) | (env->regs[R_ESP] & ~mask);
  587 + }
  588 + return;
237 589 case 6: /* 286 interrupt gate */
238 590 case 7: /* 286 trap gate */
239 591 case 14: /* 386 interrupt gate */
... ... @@ -293,20 +645,6 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
293 645 }
294 646  
295 647 shift = type >> 3;
296   - has_error_code = 0;
297   - if (!is_int && !is_hw) {
298   - switch(intno) {
299   - case 8:
300   - case 10:
301   - case 11:
302   - case 12:
303   - case 13:
304   - case 14:
305   - case 17:
306   - has_error_code = 1;
307   - break;
308   - }
309   - }
310 648 push_size = 6 + (new_stack << 2) + (has_error_code << 1);
311 649 if (env->eflags & VM_MASK)
312 650 push_size += 8;
... ... @@ -688,7 +1026,7 @@ void helper_ltr_T0(void)
688 1026 e2 = ldl_kernel(ptr + 4);
689 1027 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
690 1028 if ((e2 & DESC_S_MASK) ||
691   - (type != 2 && type != 9))
  1029 + (type != 1 && type != 9))
692 1030 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
693 1031 if (!(e2 & DESC_P_MASK))
694 1032 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
... ... @@ -701,6 +1039,7 @@ void helper_ltr_T0(void)
701 1039  
702 1040 /* only works if protected mode and not VM86. Calling load_seg with
703 1041 seg_reg == R_CS is discouraged */
  1042 +/* XXX: add ring level checks */
704 1043 void load_seg(int seg_reg, int selector, unsigned int cur_eip)
705 1044 {
706 1045 uint32_t e1, e2;
... ... @@ -725,7 +1064,7 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip)
725 1064 }
726 1065  
727 1066 if (seg_reg == R_SS) {
728   - if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) {
  1067 + if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) {
729 1068 EIP = cur_eip;
730 1069 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
731 1070 }
... ... @@ -757,7 +1096,7 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip)
757 1096 /* protected mode jump */
758 1097 void helper_ljmp_protected_T0_T1(void)
759 1098 {
760   - int new_cs, new_eip;
  1099 + int new_cs, new_eip, gate_cs, type;
761 1100 uint32_t e1, e2, cpl, dpl, rpl, limit;
762 1101  
763 1102 new_cs = T0;
... ... @@ -771,7 +1110,7 @@ void helper_ljmp_protected_T0_T1(void)
771 1110 if (!(e2 & DESC_CS_MASK))
772 1111 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
773 1112 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
774   - if (e2 & DESC_CS_MASK) {
  1113 + if (e2 & DESC_C_MASK) {
775 1114 /* conforming code segment */
776 1115 if (dpl > cpl)
777 1116 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
... ... @@ -792,8 +1131,52 @@ void helper_ljmp_protected_T0_T1(void)
792 1131 get_seg_base(e1, e2), limit, e2);
793 1132 EIP = new_eip;
794 1133 } else {
795   - cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x",
796   - new_cs, new_eip);
  1134 + /* jump to call or task gate */
  1135 + dpl = (e2 >> DESC_DPL_SHIFT) & 3;
  1136 + rpl = new_cs & 3;
  1137 + cpl = env->hflags & HF_CPL_MASK;
  1138 + type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
  1139 + switch(type) {
  1140 + case 1: /* 286 TSS */
  1141 + case 9: /* 386 TSS */
  1142 + case 5: /* task gate */
  1143 + if (dpl < cpl || dpl < rpl)
  1144 + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
  1145 + switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP);
  1146 + break;
  1147 + case 4: /* 286 call gate */
  1148 + case 12: /* 386 call gate */
  1149 + if ((dpl < cpl) || (dpl < rpl))
  1150 + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
  1151 + if (!(e2 & DESC_P_MASK))
  1152 + raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
  1153 + gate_cs = e1 >> 16;
  1154 + if (load_segment(&e1, &e2, gate_cs) != 0)
  1155 + raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
  1156 + dpl = (e2 >> DESC_DPL_SHIFT) & 3;
  1157 + /* must be code segment */
  1158 + if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
  1159 + (DESC_S_MASK | DESC_CS_MASK)))
  1160 + raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
  1161 + if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
  1162 + (!(e2 & DESC_C_MASK) && (dpl != cpl)))
  1163 + raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
  1164 + if (!(e2 & DESC_P_MASK))
  1165 + raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
  1166 + new_eip = (e1 & 0xffff);
  1167 + if (type == 12)
  1168 + new_eip |= (e2 & 0xffff0000);
  1169 + limit = get_seg_limit(e1, e2);
  1170 + if (new_eip > limit)
  1171 + raise_exception_err(EXCP0D_GPF, 0);
  1172 + cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
  1173 + get_seg_base(e1, e2), limit, e2);
  1174 + EIP = new_eip;
  1175 + break;
  1176 + default:
  1177 + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
  1178 + break;
  1179 + }
797 1180 }
798 1181 }
799 1182  
... ... @@ -852,7 +1235,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip)
852 1235 if (!(e2 & DESC_CS_MASK))
853 1236 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
854 1237 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
855   - if (e2 & DESC_CS_MASK) {
  1238 + if (e2 & DESC_C_MASK) {
856 1239 /* conforming code segment */
857 1240 if (dpl > cpl)
858 1241 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
... ... @@ -898,11 +1281,15 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip)
898 1281 } else {
899 1282 /* check gate type */
900 1283 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
  1284 + dpl = (e2 >> DESC_DPL_SHIFT) & 3;
  1285 + rpl = new_cs & 3;
901 1286 switch(type) {
902 1287 case 1: /* available 286 TSS */
903 1288 case 9: /* available 386 TSS */
904 1289 case 5: /* task gate */
905   - cpu_abort(env, "task gate not supported");
  1290 + if (dpl < cpl || dpl < rpl)
  1291 + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
  1292 + switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL);
906 1293 break;
907 1294 case 4: /* 286 call gate */
908 1295 case 12: /* 386 call gate */
... ... @@ -913,8 +1300,6 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip)
913 1300 }
914 1301 shift = type >> 3;
915 1302  
916   - dpl = (e2 >> DESC_DPL_SHIFT) & 3;
917   - rpl = new_cs & 3;
918 1303 if (dpl < cpl || dpl < rpl)
919 1304 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
920 1305 /* check valid bit */
... ... @@ -1031,13 +1416,13 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip)
1031 1416 }
1032 1417 }
1033 1418  
1034   -/* real mode iret */
  1419 +/* real and vm86 mode iret */
1035 1420 void helper_iret_real(int shift)
1036 1421 {
1037 1422 uint32_t sp, new_cs, new_eip, new_eflags, new_esp;
1038 1423 uint8_t *ssp;
1039 1424 int eflags_mask;
1040   -
  1425 +
1041 1426 sp = ESP & 0xffff;
1042 1427 ssp = env->segs[R_SS].base + sp;
1043 1428 if (shift == 1) {
... ... @@ -1056,7 +1441,10 @@ void helper_iret_real(int shift)
1056 1441 (new_esp & 0xffff);
1057 1442 load_seg_vm(R_CS, new_cs);
1058 1443 env->eip = new_eip;
1059   - eflags_mask = FL_UPDATE_CPL0_MASK;
  1444 + if (env->eflags & VM_MASK)
  1445 + eflags_mask = FL_UPDATE_MASK32 | IF_MASK | RF_MASK;
  1446 + else
  1447 + eflags_mask = FL_UPDATE_CPL0_MASK;
1060 1448 if (shift == 0)
1061 1449 eflags_mask &= 0xffff;
1062 1450 load_eflags(new_eflags, eflags_mask);
... ... @@ -1102,7 +1490,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
1102 1490 if (rpl < cpl)
1103 1491 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1104 1492 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1105   - if (e2 & DESC_CS_MASK) {
  1493 + if (e2 & DESC_C_MASK) {
1106 1494 if (dpl > rpl)
1107 1495 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1108 1496 } else {
... ... @@ -1198,7 +1586,24 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
1198 1586  
1199 1587 void helper_iret_protected(int shift)
1200 1588 {
1201   - helper_ret_protected(shift, 1, 0);
  1589 + int tss_selector, type;
  1590 + uint32_t e1, e2;
  1591 +
  1592 + /* specific case for TSS */
  1593 + if (env->eflags & NT_MASK) {
  1594 + tss_selector = lduw_kernel(env->tr.base + 0);
  1595 + if (tss_selector & 4)
  1596 + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
  1597 + if (load_segment(&e1, &e2, tss_selector) != 0)
  1598 + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
  1599 + type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
  1600 + /* NOTE: we check both segment and busy TSS */
  1601 + if (type != 3)
  1602 + raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
  1603 + switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET);
  1604 + } else {
  1605 + helper_ret_protected(shift, 1, 0);
  1606 + }
1202 1607 }
1203 1608  
1204 1609 void helper_lret_protected(int shift, int addend)
... ...