Commit 8d7b0fbb3f301e3cd9a018cc0650807e433c1ec5

Authored by bellard
1 parent 5e966ce6

32 bit RSP update fix (aka Open Solaris x86_64 bug)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2186 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 24 additions and 9 deletions
target-i386/helper.c
... ... @@ -553,6 +553,20 @@ static inline unsigned int get_sp_mask(unsigned int e2)
553 553 return 0xffff;
554 554 }
555 555  
  556 +#ifdef TARGET_X86_64
  557 +#define SET_ESP(val, sp_mask)\
  558 +do {\
  559 + if ((sp_mask) == 0xffff)\
  560 + ESP = (ESP & ~0xffff) | ((val) & 0xffff);\
  561 + else if ((sp_mask) == 0xffffffffLL)\
  562 + ESP = (uint32_t)(val);\
  563 + else\
  564 + ESP = (val);\
  565 +} while (0)
  566 +#else
  567 +#define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))
  568 +#endif
  569 +
556 570 /* XXX: add a is_user flag to have proper security support */
557 571 #define PUSHW(ssp, sp, sp_mask, val)\
558 572 {\
... ... @@ -584,10 +598,10 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
584 598 {
585 599 SegmentCache *dt;
586 600 target_ulong ptr, ssp;
587   - int type, dpl, selector, ss_dpl, cpl, sp_mask;
  601 + int type, dpl, selector, ss_dpl, cpl;
588 602 int has_error_code, new_stack, shift;
589 603 uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
590   - uint32_t old_eip;
  604 + uint32_t old_eip, sp_mask;
591 605  
592 606 has_error_code = 0;
593 607 if (!is_int && !is_hw) {
... ... @@ -623,7 +637,8 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
623 637 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
624 638 switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
625 639 if (has_error_code) {
626   - int mask, type;
  640 + int type;
  641 + uint32_t mask;
627 642 /* push the error code */
628 643 type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
629 644 shift = type >> 3;
... ... @@ -637,7 +652,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
637 652 stl_kernel(ssp, error_code);
638 653 else
639 654 stw_kernel(ssp, error_code);
640   - ESP = (esp & mask) | (ESP & ~mask);
  655 + SET_ESP(esp, mask);
641 656 }
642 657 return;
643 658 case 6: /* 286 interrupt gate */
... ... @@ -765,7 +780,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
765 780 cpu_x86_load_seg_cache(env, R_SS, ss,
766 781 ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
767 782 }
768   - ESP = (ESP & ~sp_mask) | (esp & sp_mask);
  783 + SET_ESP(esp, sp_mask);
769 784  
770 785 selector = (selector & ~3) | dpl;
771 786 cpu_x86_load_seg_cache(env, R_CS, selector,
... ... @@ -2015,7 +2030,7 @@ void helper_lcall_real_T0_T1(int shift, int next_eip)
2015 2030 PUSHW(ssp, esp, esp_mask, next_eip);
2016 2031 }
2017 2032  
2018   - ESP = (ESP & ~esp_mask) | (esp & esp_mask);
  2033 + SET_ESP(esp, esp_mask);
2019 2034 env->eip = new_eip;
2020 2035 env->segs[R_CS].selector = new_cs;
2021 2036 env->segs[R_CS].base = (new_cs << 4);
... ... @@ -2101,7 +2116,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend)
2101 2116 if (new_eip > limit)
2102 2117 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
2103 2118 /* from this point, not restartable */
2104   - ESP = (ESP & ~sp_mask) | (sp & sp_mask);
  2119 + SET_ESP(sp, sp_mask);
2105 2120 cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
2106 2121 get_seg_base(e1, e2), limit, e2);
2107 2122 EIP = new_eip;
... ... @@ -2230,7 +2245,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend)
2230 2245 get_seg_limit(e1, e2),
2231 2246 e2);
2232 2247 cpu_x86_set_cpl(env, dpl);
2233   - ESP = (ESP & ~sp_mask) | (sp & sp_mask);
  2248 + SET_ESP(sp, sp_mask);
2234 2249 EIP = offset;
2235 2250 }
2236 2251 #ifdef USE_KQEMU
... ... @@ -2459,7 +2474,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
2459 2474  
2460 2475 sp += addend;
2461 2476 }
2462   - ESP = (ESP & ~sp_mask) | (sp & sp_mask);
  2477 + SET_ESP(sp, sp_mask);
2463 2478 env->eip = new_eip;
2464 2479 if (is_iret) {
2465 2480 /* NOTE: 'cpl' is the _old_ CPL */
... ...