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,6 +126,56 @@ void cpu_loop_exit(void)
126 longjmp(env->jmp_env, 1); 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 static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, 179 static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
130 uint32_t *esp_ptr, int dpl) 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,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 SegmentCache *dt; 277 SegmentCache *dt;
169 int index; 278 int index;
170 uint8_t *ptr; 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 else 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 if ((index + 7) > dt->limit) 450 if ((index + 7) > dt->limit)
178 - return -1; 451 + raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
179 ptr = dt->base + index; 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 /* protected mode interrupt */ 532 /* protected mode interrupt */
@@ -222,6 +540,21 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, @@ -222,6 +540,21 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
222 uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; 540 uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size;
223 uint32_t old_cs, old_ss, old_esp, old_eip; 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 dt = &env->idt; 558 dt = &env->idt;
226 if (intno * 8 + 7 > dt->limit) 559 if (intno * 8 + 7 > dt->limit)
227 raise_exception_err(EXCP0D_GPF, intno * 8 + 2); 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,8 +565,27 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
232 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; 565 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
233 switch(type) { 566 switch(type) {
234 case 5: /* task gate */ 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 case 6: /* 286 interrupt gate */ 589 case 6: /* 286 interrupt gate */
238 case 7: /* 286 trap gate */ 590 case 7: /* 286 trap gate */
239 case 14: /* 386 interrupt gate */ 591 case 14: /* 386 interrupt gate */
@@ -293,20 +645,6 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, @@ -293,20 +645,6 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
293 } 645 }
294 646
295 shift = type >> 3; 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 push_size = 6 + (new_stack << 2) + (has_error_code << 1); 648 push_size = 6 + (new_stack << 2) + (has_error_code << 1);
311 if (env->eflags & VM_MASK) 649 if (env->eflags & VM_MASK)
312 push_size += 8; 650 push_size += 8;
@@ -688,7 +1026,7 @@ void helper_ltr_T0(void) @@ -688,7 +1026,7 @@ void helper_ltr_T0(void)
688 e2 = ldl_kernel(ptr + 4); 1026 e2 = ldl_kernel(ptr + 4);
689 type = (e2 >> DESC_TYPE_SHIFT) & 0xf; 1027 type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
690 if ((e2 & DESC_S_MASK) || 1028 if ((e2 & DESC_S_MASK) ||
691 - (type != 2 && type != 9)) 1029 + (type != 1 && type != 9))
692 raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 1030 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
693 if (!(e2 & DESC_P_MASK)) 1031 if (!(e2 & DESC_P_MASK))
694 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); 1032 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
@@ -701,6 +1039,7 @@ void helper_ltr_T0(void) @@ -701,6 +1039,7 @@ void helper_ltr_T0(void)
701 1039
702 /* only works if protected mode and not VM86. Calling load_seg with 1040 /* only works if protected mode and not VM86. Calling load_seg with
703 seg_reg == R_CS is discouraged */ 1041 seg_reg == R_CS is discouraged */
  1042 +/* XXX: add ring level checks */
704 void load_seg(int seg_reg, int selector, unsigned int cur_eip) 1043 void load_seg(int seg_reg, int selector, unsigned int cur_eip)
705 { 1044 {
706 uint32_t e1, e2; 1045 uint32_t e1, e2;
@@ -725,7 +1064,7 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip) @@ -725,7 +1064,7 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip)
725 } 1064 }
726 1065
727 if (seg_reg == R_SS) { 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 EIP = cur_eip; 1068 EIP = cur_eip;
730 raise_exception_err(EXCP0D_GPF, selector & 0xfffc); 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,7 +1096,7 @@ void load_seg(int seg_reg, int selector, unsigned int cur_eip)
757 /* protected mode jump */ 1096 /* protected mode jump */
758 void helper_ljmp_protected_T0_T1(void) 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 uint32_t e1, e2, cpl, dpl, rpl, limit; 1100 uint32_t e1, e2, cpl, dpl, rpl, limit;
762 1101
763 new_cs = T0; 1102 new_cs = T0;
@@ -771,7 +1110,7 @@ void helper_ljmp_protected_T0_T1(void) @@ -771,7 +1110,7 @@ void helper_ljmp_protected_T0_T1(void)
771 if (!(e2 & DESC_CS_MASK)) 1110 if (!(e2 & DESC_CS_MASK))
772 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 1111 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
773 dpl = (e2 >> DESC_DPL_SHIFT) & 3; 1112 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
774 - if (e2 & DESC_CS_MASK) { 1113 + if (e2 & DESC_C_MASK) {
775 /* conforming code segment */ 1114 /* conforming code segment */
776 if (dpl > cpl) 1115 if (dpl > cpl)
777 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 1116 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
@@ -792,8 +1131,52 @@ void helper_ljmp_protected_T0_T1(void) @@ -792,8 +1131,52 @@ void helper_ljmp_protected_T0_T1(void)
792 get_seg_base(e1, e2), limit, e2); 1131 get_seg_base(e1, e2), limit, e2);
793 EIP = new_eip; 1132 EIP = new_eip;
794 } else { 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,7 +1235,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip)
852 if (!(e2 & DESC_CS_MASK)) 1235 if (!(e2 & DESC_CS_MASK))
853 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 1236 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
854 dpl = (e2 >> DESC_DPL_SHIFT) & 3; 1237 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
855 - if (e2 & DESC_CS_MASK) { 1238 + if (e2 & DESC_C_MASK) {
856 /* conforming code segment */ 1239 /* conforming code segment */
857 if (dpl > cpl) 1240 if (dpl > cpl)
858 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 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,11 +1281,15 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip)
898 } else { 1281 } else {
899 /* check gate type */ 1282 /* check gate type */
900 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; 1283 type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
  1284 + dpl = (e2 >> DESC_DPL_SHIFT) & 3;
  1285 + rpl = new_cs & 3;
901 switch(type) { 1286 switch(type) {
902 case 1: /* available 286 TSS */ 1287 case 1: /* available 286 TSS */
903 case 9: /* available 386 TSS */ 1288 case 9: /* available 386 TSS */
904 case 5: /* task gate */ 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 break; 1293 break;
907 case 4: /* 286 call gate */ 1294 case 4: /* 286 call gate */
908 case 12: /* 386 call gate */ 1295 case 12: /* 386 call gate */
@@ -913,8 +1300,6 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) @@ -913,8 +1300,6 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip)
913 } 1300 }
914 shift = type >> 3; 1301 shift = type >> 3;
915 1302
916 - dpl = (e2 >> DESC_DPL_SHIFT) & 3;  
917 - rpl = new_cs & 3;  
918 if (dpl < cpl || dpl < rpl) 1303 if (dpl < cpl || dpl < rpl)
919 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 1304 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
920 /* check valid bit */ 1305 /* check valid bit */
@@ -1031,13 +1416,13 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) @@ -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 void helper_iret_real(int shift) 1420 void helper_iret_real(int shift)
1036 { 1421 {
1037 uint32_t sp, new_cs, new_eip, new_eflags, new_esp; 1422 uint32_t sp, new_cs, new_eip, new_eflags, new_esp;
1038 uint8_t *ssp; 1423 uint8_t *ssp;
1039 int eflags_mask; 1424 int eflags_mask;
1040 - 1425 +
1041 sp = ESP & 0xffff; 1426 sp = ESP & 0xffff;
1042 ssp = env->segs[R_SS].base + sp; 1427 ssp = env->segs[R_SS].base + sp;
1043 if (shift == 1) { 1428 if (shift == 1) {
@@ -1056,7 +1441,10 @@ void helper_iret_real(int shift) @@ -1056,7 +1441,10 @@ void helper_iret_real(int shift)
1056 (new_esp & 0xffff); 1441 (new_esp & 0xffff);
1057 load_seg_vm(R_CS, new_cs); 1442 load_seg_vm(R_CS, new_cs);
1058 env->eip = new_eip; 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 if (shift == 0) 1448 if (shift == 0)
1061 eflags_mask &= 0xffff; 1449 eflags_mask &= 0xffff;
1062 load_eflags(new_eflags, eflags_mask); 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,7 +1490,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
1102 if (rpl < cpl) 1490 if (rpl < cpl)
1103 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 1491 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1104 dpl = (e2 >> DESC_DPL_SHIFT) & 3; 1492 dpl = (e2 >> DESC_DPL_SHIFT) & 3;
1105 - if (e2 & DESC_CS_MASK) { 1493 + if (e2 & DESC_C_MASK) {
1106 if (dpl > rpl) 1494 if (dpl > rpl)
1107 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 1495 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1108 } else { 1496 } else {
@@ -1198,7 +1586,24 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) @@ -1198,7 +1586,24 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
1198 1586
1199 void helper_iret_protected(int shift) 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 void helper_lret_protected(int shift, int addend) 1609 void helper_lret_protected(int shift, int addend)