/[qemu]/qemu/target-i386/helper.c
ViewVC logotype

Diff of /qemu/target-i386/helper.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.6 by bellard, Thu Nov 13 23:15:36 2003 UTC revision 1.7 by bellard, Sun Nov 16 16:06:03 2003 UTC
# Line 531  void check_iol_DX(void) Line 531  void check_iol_DX(void)
531      check_io(EDX & 0xffff, 4);      check_io(EDX & 0xffff, 4);
532  }  }
533    
534    static inline unsigned int get_sp_mask(unsigned int e2)
535    {
536        if (e2 & DESC_B_MASK)
537            return 0xffffffff;
538        else
539            return 0xffff;
540    }
541    
542    /* XXX: add a is_user flag to have proper security support */
543    #define PUSHW(ssp, sp, sp_mask, val)\
544    {\
545        sp -= 2;\
546        stw_kernel((ssp) + (sp & (sp_mask)), (val));\
547    }
548    
549    #define PUSHL(ssp, sp, sp_mask, val)\
550    {\
551        sp -= 4;\
552        stl_kernel((ssp) + (sp & (sp_mask)), (val));\
553    }
554    
555    #define POPW(ssp, sp, sp_mask, val)\
556    {\
557        val = lduw_kernel((ssp) + (sp & (sp_mask)));\
558        sp += 2;\
559    }
560    
561    #define POPL(ssp, sp, sp_mask, val)\
562    {\
563        val = ldl_kernel((ssp) + (sp & (sp_mask)));\
564        sp += 4;\
565    }
566    
567  /* protected mode interrupt */  /* protected mode interrupt */
568  static void do_interrupt_protected(int intno, int is_int, int error_code,  static void do_interrupt_protected(int intno, int is_int, int error_code,
569                                     unsigned int next_eip, int is_hw)                                     unsigned int next_eip, int is_hw)
570  {  {
571      SegmentCache *dt;      SegmentCache *dt;
572      uint8_t *ptr, *ssp;      uint8_t *ptr, *ssp;
573      int type, dpl, selector, ss_dpl, cpl;      int type, dpl, selector, ss_dpl, cpl, sp_mask;
574      int has_error_code, new_stack, shift;      int has_error_code, new_stack, shift;
575      uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size;      uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
576      uint32_t old_cs, old_ss, old_esp, old_eip;      uint32_t old_eip;
577    
578  #ifdef DEBUG_PCALL  #ifdef DEBUG_PCALL
579      if (loglevel) {      if (loglevel) {
# Line 659  static void do_interrupt_protected(int i Line 692  static void do_interrupt_protected(int i
692          if (!(ss_e2 & DESC_P_MASK))          if (!(ss_e2 & DESC_P_MASK))
693              raise_exception_err(EXCP0A_TSS, ss & 0xfffc);              raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
694          new_stack = 1;          new_stack = 1;
695            sp_mask = get_sp_mask(ss_e2);
696            ssp = get_seg_base(ss_e1, ss_e2);
697      } else if ((e2 & DESC_C_MASK) || dpl == cpl) {      } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
698          /* to same priviledge */          /* to same priviledge */
699          new_stack = 0;          new_stack = 0;
700            sp_mask = get_sp_mask(env->segs[R_SS].flags);
701            ssp = env->segs[R_SS].base;
702            esp = ESP;
703      } else {      } else {
704          raise_exception_err(EXCP0D_GPF, selector & 0xfffc);          raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
705          new_stack = 0; /* avoid warning */          new_stack = 0; /* avoid warning */
706            sp_mask = 0; /* avoid warning */
707            ssp = NULL; /* avoid warning */
708            esp = 0; /* avoid warning */
709      }      }
710    
711      shift = type >> 3;      shift = type >> 3;
712    
713    #if 0
714        /* XXX: check that enough room is available */
715      push_size = 6 + (new_stack << 2) + (has_error_code << 1);      push_size = 6 + (new_stack << 2) + (has_error_code << 1);
716      if (env->eflags & VM_MASK)      if (env->eflags & VM_MASK)
717          push_size += 8;          push_size += 8;
718      push_size <<= shift;      push_size <<= shift;
719    #endif
     /* XXX: check that enough room is available */  
     if (new_stack) {  
         old_esp = ESP;  
         old_ss = env->segs[R_SS].selector;  
         ss = (ss & ~3) | dpl;  
         cpu_x86_load_seg_cache(env, R_SS, ss,  
                        get_seg_base(ss_e1, ss_e2),  
                        get_seg_limit(ss_e1, ss_e2),  
                        ss_e2);  
     } else {  
         old_esp = 0;  
         old_ss = 0;  
         esp = ESP;  
     }  
720      if (is_int)      if (is_int)
721          old_eip = next_eip;          old_eip = next_eip;
722      else      else
723          old_eip = env->eip;          old_eip = env->eip;
     old_cs = env->segs[R_CS].selector;  
     selector = (selector & ~3) | dpl;  
     cpu_x86_load_seg_cache(env, R_CS, selector,  
                    get_seg_base(e1, e2),  
                    get_seg_limit(e1, e2),  
                    e2);  
     cpu_x86_set_cpl(env, dpl);  
     env->eip = offset;  
     ESP = esp - push_size;  
     ssp = env->segs[R_SS].base + esp;  
724      if (shift == 1) {      if (shift == 1) {
         int old_eflags;  
725          if (env->eflags & VM_MASK) {          if (env->eflags & VM_MASK) {
726              ssp -= 4;              PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
727              stl_kernel(ssp, env->segs[R_GS].selector);              PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
728              ssp -= 4;              PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
729              stl_kernel(ssp, env->segs[R_FS].selector);              PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
             ssp -= 4;  
             stl_kernel(ssp, env->segs[R_DS].selector);  
             ssp -= 4;  
             stl_kernel(ssp, env->segs[R_ES].selector);  
730          }          }
731          if (new_stack) {          if (new_stack) {
732              ssp -= 4;              PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
733              stl_kernel(ssp, old_ss);              PUSHL(ssp, esp, sp_mask, ESP);
734              ssp -= 4;          }
735              stl_kernel(ssp, old_esp);          PUSHL(ssp, esp, sp_mask, compute_eflags());
736          }          PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
737          ssp -= 4;          PUSHL(ssp, esp, sp_mask, old_eip);
         old_eflags = compute_eflags();  
         stl_kernel(ssp, old_eflags);  
         ssp -= 4;  
         stl_kernel(ssp, old_cs);  
         ssp -= 4;  
         stl_kernel(ssp, old_eip);  
738          if (has_error_code) {          if (has_error_code) {
739              ssp -= 4;              PUSHL(ssp, esp, sp_mask, error_code);
             stl_kernel(ssp, error_code);  
740          }          }
741      } else {      } else {
742          if (new_stack) {          if (new_stack) {
743              ssp -= 2;              PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
744              stw_kernel(ssp, old_ss);              PUSHW(ssp, esp, sp_mask, ESP);
745              ssp -= 2;          }
746              stw_kernel(ssp, old_esp);          PUSHW(ssp, esp, sp_mask, compute_eflags());
747          }          PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
748          ssp -= 2;          PUSHW(ssp, esp, sp_mask, old_eip);
         stw_kernel(ssp, compute_eflags());  
         ssp -= 2;  
         stw_kernel(ssp, old_cs);  
         ssp -= 2;  
         stw_kernel(ssp, old_eip);  
749          if (has_error_code) {          if (has_error_code) {
750              ssp -= 2;              PUSHW(ssp, esp, sp_mask, error_code);
             stw_kernel(ssp, error_code);  
751          }          }
752      }      }
753            
754        if (new_stack) {
755            ss = (ss & ~3) | dpl;
756            cpu_x86_load_seg_cache(env, R_SS, ss,
757                                   ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
758        }
759        ESP = (ESP & ~sp_mask) | (esp & sp_mask);
760    
761        selector = (selector & ~3) | dpl;
762        cpu_x86_load_seg_cache(env, R_CS, selector,
763                       get_seg_base(e1, e2),
764                       get_seg_limit(e1, e2),
765                       e2);
766        cpu_x86_set_cpl(env, dpl);
767        env->eip = offset;
768    
769      /* interrupt gate clear IF mask */      /* interrupt gate clear IF mask */
770      if ((type & 1) == 0) {      if ((type & 1) == 0) {
771          env->eflags &= ~IF_MASK;          env->eflags &= ~IF_MASK;
# Line 780  static void do_interrupt_real(int intno, Line 797  static void do_interrupt_real(int intno,
797      else      else
798          old_eip = env->eip;          old_eip = env->eip;
799      old_cs = env->segs[R_CS].selector;      old_cs = env->segs[R_CS].selector;
800      esp -= 2;      /* XXX: use SS segment size ? */
801      stw_kernel(ssp + (esp & 0xffff), compute_eflags());      PUSHW(ssp, esp, 0xffff, compute_eflags());
802      esp -= 2;      PUSHW(ssp, esp, 0xffff, old_cs);
803      stw_kernel(ssp + (esp & 0xffff), old_cs);      PUSHW(ssp, esp, 0xffff, old_eip);
     esp -= 2;  
     stw_kernel(ssp + (esp & 0xffff), old_eip);  
804            
805      /* update processor state */      /* update processor state */
806      ESP = (ESP & ~0xffff) | (esp & 0xffff);      ESP = (ESP & ~0xffff) | (esp & 0xffff);
# Line 1247  void helper_lcall_real_T0_T1(int shift, Line 1262  void helper_lcall_real_T0_T1(int shift,
1262      new_cs = T0;      new_cs = T0;
1263      new_eip = T1;      new_eip = T1;
1264      esp = ESP;      esp = ESP;
1265      esp_mask = 0xffffffff;      esp_mask = get_sp_mask(env->segs[R_SS].flags);
     if (!(env->segs[R_SS].flags & DESC_B_MASK))  
         esp_mask = 0xffff;  
1266      ssp = env->segs[R_SS].base;      ssp = env->segs[R_SS].base;
1267      if (shift) {      if (shift) {
1268          esp -= 4;          PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
1269          stl_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector);          PUSHL(ssp, esp, esp_mask, next_eip);
         esp -= 4;  
         stl_kernel(ssp + (esp & esp_mask), next_eip);  
1270      } else {      } else {
1271          esp -= 2;          PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
1272          stw_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector);          PUSHW(ssp, esp, esp_mask, next_eip);
         esp -= 2;  
         stw_kernel(ssp + (esp & esp_mask), next_eip);  
1273      }      }
1274    
1275      if (!(env->segs[R_SS].flags & DESC_B_MASK))      ESP = (ESP & ~esp_mask) | (esp & esp_mask);
         ESP = (ESP & ~0xffff) | (esp & 0xffff);  
     else  
         ESP = esp;  
1276      env->eip = new_eip;      env->eip = new_eip;
1277      env->segs[R_CS].selector = new_cs;      env->segs[R_CS].selector = new_cs;
1278      env->segs[R_CS].base = (uint8_t *)(new_cs << 4);      env->segs[R_CS].base = (uint8_t *)(new_cs << 4);
# Line 1275  void helper_lcall_real_T0_T1(int shift, Line 1281  void helper_lcall_real_T0_T1(int shift,
1281  /* protected mode call */  /* protected mode call */
1282  void helper_lcall_protected_T0_T1(int shift, int next_eip)  void helper_lcall_protected_T0_T1(int shift, int next_eip)
1283  {  {
1284      int new_cs, new_eip;      int new_cs, new_eip, new_stack, i;
1285      uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;      uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
1286      uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl;      uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
1287      uint32_t old_ss, old_esp, val, i, limit;      uint32_t val, limit, old_sp_mask;
1288      uint8_t *ssp, *old_ssp;      uint8_t *ssp, *old_ssp;
1289            
1290      new_cs = T0;      new_cs = T0;
# Line 1319  void helper_lcall_protected_T0_T1(int sh Line 1325  void helper_lcall_protected_T0_T1(int sh
1325              raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);              raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1326    
1327          sp = ESP;          sp = ESP;
1328          if (!(env->segs[R_SS].flags & DESC_B_MASK))          sp_mask = get_sp_mask(env->segs[R_SS].flags);
1329              sp &= 0xffff;          ssp = env->segs[R_SS].base;
         ssp = env->segs[R_SS].base + sp;  
1330          if (shift) {          if (shift) {
1331              ssp -= 4;              PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1332              stl_kernel(ssp, env->segs[R_CS].selector);              PUSHL(ssp, sp, sp_mask, next_eip);
             ssp -= 4;  
             stl_kernel(ssp, next_eip);  
1333          } else {          } else {
1334              ssp -= 2;              PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1335              stw_kernel(ssp, env->segs[R_CS].selector);              PUSHW(ssp, sp, sp_mask, next_eip);
             ssp -= 2;  
             stw_kernel(ssp, next_eip);  
1336          }          }
         sp -= (4 << shift);  
1337                    
1338          limit = get_seg_limit(e1, e2);          limit = get_seg_limit(e1, e2);
1339          if (new_eip > limit)          if (new_eip > limit)
1340              raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);              raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1341          /* from this point, not restartable */          /* from this point, not restartable */
1342          if (!(env->segs[R_SS].flags & DESC_B_MASK))          ESP = (ESP & ~sp_mask) | (sp & sp_mask);
             ESP = (ESP & 0xffff0000) | (sp & 0xffff);  
         else  
             ESP = sp;  
1343          cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,          cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
1344                         get_seg_base(e1, e2), limit, e2);                         get_seg_base(e1, e2), limit, e2);
1345          EIP = new_eip;          EIP = new_eip;
# Line 1413  void helper_lcall_protected_T0_T1(int sh Line 1410  void helper_lcall_protected_T0_T1(int sh
1410              if (!(ss_e2 & DESC_P_MASK))              if (!(ss_e2 & DESC_P_MASK))
1411                  raise_exception_err(EXCP0A_TSS, ss & 0xfffc);                  raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
1412                            
1413              push_size = ((param_count * 2) + 8) << shift;              //            push_size = ((param_count * 2) + 8) << shift;
1414    
1415              old_esp = ESP;              old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
1416              old_ss = env->segs[R_SS].selector;              old_ssp = env->segs[R_SS].base;
             if (!(env->segs[R_SS].flags & DESC_B_MASK))  
                 old_esp &= 0xffff;  
             old_ssp = env->segs[R_SS].base + old_esp;  
1417                            
1418              /* XXX: from this point not restartable */              sp_mask = get_sp_mask(ss_e2);
1419              ss = (ss & ~3) | dpl;              ssp = get_seg_base(ss_e1, ss_e2);
             cpu_x86_load_seg_cache(env, R_SS, ss,  
                            get_seg_base(ss_e1, ss_e2),  
                            get_seg_limit(ss_e1, ss_e2),  
                            ss_e2);  
   
             if (!(ss_e2 & DESC_B_MASK))  
                 sp &= 0xffff;  
             ssp = env->segs[R_SS].base + sp;  
1420              if (shift) {              if (shift) {
1421                  ssp -= 4;                  PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
1422                  stl_kernel(ssp, old_ss);                  PUSHL(ssp, sp, sp_mask, ESP);
1423                  ssp -= 4;                  for(i = param_count - 1; i >= 0; i--) {
1424                  stl_kernel(ssp, old_esp);                      val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
1425                  ssp -= 4 * param_count;                      PUSHL(ssp, sp, sp_mask, val);
                 for(i = 0; i < param_count; i++) {  
                     val = ldl_kernel(old_ssp + i * 4);  
                     stl_kernel(ssp + i * 4, val);  
1426                  }                  }
1427              } else {              } else {
1428                  ssp -= 2;                  PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
1429                  stw_kernel(ssp, old_ss);                  PUSHW(ssp, sp, sp_mask, ESP);
1430                  ssp -= 2;                  for(i = param_count - 1; i >= 0; i--) {
1431                  stw_kernel(ssp, old_esp);                      val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
1432                  ssp -= 2 * param_count;                      PUSHW(ssp, sp, sp_mask, val);
                 for(i = 0; i < param_count; i++) {  
                     val = lduw_kernel(old_ssp + i * 2);  
                     stw_kernel(ssp + i * 2, val);  
1433                  }                  }
1434              }              }
1435                new_stack = 1;
1436          } else {          } else {
1437              /* to same priviledge */              /* to same priviledge */
1438              if (!(env->segs[R_SS].flags & DESC_B_MASK))              sp = ESP;
1439                  sp &= 0xffff;              sp_mask = get_sp_mask(env->segs[R_SS].flags);
1440              ssp = env->segs[R_SS].base + sp;              ssp = env->segs[R_SS].base;
1441              push_size = (4 << shift);              //            push_size = (4 << shift);
1442                new_stack = 0;
1443          }          }
1444    
1445          if (shift) {          if (shift) {
1446              ssp -= 4;              PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
1447              stl_kernel(ssp, env->segs[R_CS].selector);              PUSHL(ssp, sp, sp_mask, next_eip);
             ssp -= 4;  
             stl_kernel(ssp, next_eip);  
1448          } else {          } else {
1449              ssp -= 2;              PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
1450              stw_kernel(ssp, env->segs[R_CS].selector);              PUSHW(ssp, sp, sp_mask, next_eip);
1451              ssp -= 2;          }
1452              stw_kernel(ssp, next_eip);  
1453            /* from this point, not restartable */
1454    
1455            if (new_stack) {
1456                ss = (ss & ~3) | dpl;
1457                cpu_x86_load_seg_cache(env, R_SS, ss,
1458                                       ssp,
1459                                       get_seg_limit(ss_e1, ss_e2),
1460                                       ss_e2);
1461          }          }
1462    
         sp -= push_size;  
1463          selector = (selector & ~3) | dpl;          selector = (selector & ~3) | dpl;
1464          cpu_x86_load_seg_cache(env, R_CS, selector,          cpu_x86_load_seg_cache(env, R_CS, selector,
1465                         get_seg_base(e1, e2),                         get_seg_base(e1, e2),
1466                         get_seg_limit(e1, e2),                         get_seg_limit(e1, e2),
1467                         e2);                         e2);
1468          cpu_x86_set_cpl(env, dpl);          cpu_x86_set_cpl(env, dpl);
1469                    ESP = (ESP & ~sp_mask) | (sp & sp_mask);
         if (!(env->segs[R_SS].flags & DESC_B_MASK))  
             ESP = (ESP & 0xffff0000) | (sp & 0xffff);  
         else  
             ESP = sp;  
1470          EIP = offset;          EIP = offset;
1471      }      }
1472  }  }
# Line 1491  void helper_lcall_protected_T0_T1(int sh Line 1474  void helper_lcall_protected_T0_T1(int sh
1474  /* real and vm86 mode iret */  /* real and vm86 mode iret */
1475  void helper_iret_real(int shift)  void helper_iret_real(int shift)
1476  {  {
1477      uint32_t sp, new_cs, new_eip, new_eflags, new_esp;      uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
1478      uint8_t *ssp;      uint8_t *ssp;
1479      int eflags_mask;      int eflags_mask;
1480    
1481      sp = ESP & 0xffff;      sp_mask = 0xffff; /* XXXX: use SS segment size ? */
1482      ssp = env->segs[R_SS].base + sp;      sp = ESP;
1483        ssp = env->segs[R_SS].base;
1484      if (shift == 1) {      if (shift == 1) {
1485          /* 32 bits */          /* 32 bits */
1486          new_eflags = ldl_kernel(ssp + 8);          POPL(ssp, sp, sp_mask, new_eip);
1487          new_cs = ldl_kernel(ssp + 4) & 0xffff;          POPL(ssp, sp, sp_mask, new_cs);
1488          new_eip = ldl_kernel(ssp) & 0xffff;          new_cs &= 0xffff;
1489            POPL(ssp, sp, sp_mask, new_eflags);
1490      } else {      } else {
1491          /* 16 bits */          /* 16 bits */
1492          new_eflags = lduw_kernel(ssp + 4);          POPW(ssp, sp, sp_mask, new_eip);
1493          new_cs = lduw_kernel(ssp + 2);          POPW(ssp, sp, sp_mask, new_cs);
1494          new_eip = lduw_kernel(ssp);          POPW(ssp, sp, sp_mask, new_eflags);
1495      }      }
1496      new_esp = sp + (6 << shift);      ESP = (ESP & ~sp_mask) | (sp & 0xffff);
     ESP = (ESP & 0xffff0000) |  
         (new_esp & 0xffff);  
1497      load_seg_vm(R_CS, new_cs);      load_seg_vm(R_CS, new_cs);
1498      env->eip = new_eip;      env->eip = new_eip;
1499      if (env->eflags & VM_MASK)      if (env->eflags & VM_MASK)
# Line 1525  void helper_iret_real(int shift) Line 1508  void helper_iret_real(int shift)
1508  /* protected mode iret */  /* protected mode iret */
1509  static inline void helper_ret_protected(int shift, int is_iret, int addend)  static inline void helper_ret_protected(int shift, int is_iret, int addend)
1510  {  {
1511      uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss;      uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss, sp_mask;
1512      uint32_t new_es, new_ds, new_fs, new_gs;      uint32_t new_es, new_ds, new_fs, new_gs;
1513      uint32_t e1, e2, ss_e1, ss_e2;      uint32_t e1, e2, ss_e1, ss_e2;
1514      int cpl, dpl, rpl, eflags_mask;      int cpl, dpl, rpl, eflags_mask;
1515      uint8_t *ssp;      uint8_t *ssp;
1516            
1517        sp_mask = get_sp_mask(env->segs[R_SS].flags);
1518      sp = ESP;      sp = ESP;
1519      if (!(env->segs[R_SS].flags & DESC_B_MASK))      ssp = env->segs[R_SS].base;
         sp &= 0xffff;  
     ssp = env->segs[R_SS].base + sp;  
1520      if (shift == 1) {      if (shift == 1) {
1521          /* 32 bits */          /* 32 bits */
1522          if (is_iret)          POPL(ssp, sp, sp_mask, new_eip);
1523              new_eflags = ldl_kernel(ssp + 8);          POPL(ssp, sp, sp_mask, new_cs);
1524          new_cs = ldl_kernel(ssp + 4) & 0xffff;          new_cs &= 0xffff;
1525          new_eip = ldl_kernel(ssp);          if (is_iret) {
1526          if (is_iret && (new_eflags & VM_MASK))              POPL(ssp, sp, sp_mask, new_eflags);
1527              goto return_to_vm86;              if (new_eflags & VM_MASK)
1528                    goto return_to_vm86;
1529            }
1530      } else {      } else {
1531          /* 16 bits */          /* 16 bits */
1532            POPW(ssp, sp, sp_mask, new_eip);
1533            POPW(ssp, sp, sp_mask, new_cs);
1534          if (is_iret)          if (is_iret)
1535              new_eflags = lduw_kernel(ssp + 4);              POPW(ssp, sp, sp_mask, new_eflags);
         new_cs = lduw_kernel(ssp + 2);  
         new_eip = lduw_kernel(ssp);  
1536      }      }
1537    #ifdef DEBUG_PCALL
1538        if (loglevel) {
1539            fprintf(logfile, "lret new %04x:%08x\n",
1540                    new_cs, new_eip);
1541        }
1542    #endif
1543      if ((new_cs & 0xfffc) == 0)      if ((new_cs & 0xfffc) == 0)
1544          raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);          raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1545      if (load_segment(&e1, &e2, new_cs) != 0)      if (load_segment(&e1, &e2, new_cs) != 0)
# Line 1572  static inline void helper_ret_protected( Line 1562  static inline void helper_ret_protected(
1562      if (!(e2 & DESC_P_MASK))      if (!(e2 & DESC_P_MASK))
1563          raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);          raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
1564            
1565        sp += addend;
1566      if (rpl == cpl) {      if (rpl == cpl) {
1567          /* return to same priledge level */          /* return to same priledge level */
1568          cpu_x86_load_seg_cache(env, R_CS, new_cs,          cpu_x86_load_seg_cache(env, R_CS, new_cs,
1569                         get_seg_base(e1, e2),                         get_seg_base(e1, e2),
1570                         get_seg_limit(e1, e2),                         get_seg_limit(e1, e2),
1571                         e2);                         e2);
         new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend;  
1572      } else {      } else {
1573          /* return to different priviledge level */          /* return to different priviledge level */
         ssp += (4 << shift) + ((2 * is_iret) << shift) + addend;  
1574          if (shift == 1) {          if (shift == 1) {
1575              /* 32 bits */              /* 32 bits */
1576              new_esp = ldl_kernel(ssp);              POPL(ssp, sp, sp_mask, new_esp);
1577              new_ss = ldl_kernel(ssp + 4) & 0xffff;              POPL(ssp, sp, sp_mask, new_ss);
1578                new_ss &= 0xffff;
1579          } else {          } else {
1580              /* 16 bits */              /* 16 bits */
1581              new_esp = lduw_kernel(ssp);              POPW(ssp, sp, sp_mask, new_esp);
1582              new_ss = lduw_kernel(ssp + 2);              POPW(ssp, sp, sp_mask, new_ss);
1583          }          }
1584                    
1585          if ((new_ss & 3) != rpl)          if ((new_ss & 3) != rpl)
# Line 1615  static inline void helper_ret_protected( Line 1605  static inline void helper_ret_protected(
1605                         get_seg_limit(ss_e1, ss_e2),                         get_seg_limit(ss_e1, ss_e2),
1606                         ss_e2);                         ss_e2);
1607          cpu_x86_set_cpl(env, rpl);          cpu_x86_set_cpl(env, rpl);
1608            sp = new_esp;
1609            /* XXX: change sp_mask according to old segment ? */
1610      }      }
1611      if (env->segs[R_SS].flags & DESC_B_MASK)      ESP = (ESP & ~sp_mask) | (sp & sp_mask);
         ESP = new_esp;  
     else  
         ESP = (ESP & 0xffff0000) |  
             (new_esp & 0xffff);  
1612      env->eip = new_eip;      env->eip = new_eip;
1613      if (is_iret) {      if (is_iret) {
1614          /* NOTE: 'cpl' can be different from the current CPL */          /* NOTE: 'cpl' can be different from the current CPL */
# Line 1635  static inline void helper_ret_protected( Line 1623  static inline void helper_ret_protected(
1623      return;      return;
1624    
1625   return_to_vm86:   return_to_vm86:
1626      new_esp = ldl_kernel(ssp + 12);      POPL(ssp, sp, sp_mask, new_esp);
1627      new_ss = ldl_kernel(ssp + 16);      POPL(ssp, sp, sp_mask, new_ss);
1628      new_es = ldl_kernel(ssp + 20);      POPL(ssp, sp, sp_mask, new_es);
1629      new_ds = ldl_kernel(ssp + 24);      POPL(ssp, sp, sp_mask, new_ds);
1630      new_fs = ldl_kernel(ssp + 28);      POPL(ssp, sp, sp_mask, new_fs);
1631      new_gs = ldl_kernel(ssp + 32);      POPL(ssp, sp, sp_mask, new_gs);
1632            
1633      /* modify processor state */      /* modify processor state */
1634      load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK);      load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK);
1635      load_seg_vm(R_CS, new_cs);      load_seg_vm(R_CS, new_cs & 0xffff);
1636      cpu_x86_set_cpl(env, 3);      cpu_x86_set_cpl(env, 3);
1637      load_seg_vm(R_SS, new_ss);      load_seg_vm(R_SS, new_ss & 0xffff);
1638      load_seg_vm(R_ES, new_es);      load_seg_vm(R_ES, new_es & 0xffff);
1639      load_seg_vm(R_DS, new_ds);      load_seg_vm(R_DS, new_ds & 0xffff);
1640      load_seg_vm(R_FS, new_fs);      load_seg_vm(R_FS, new_fs & 0xffff);
1641      load_seg_vm(R_GS, new_gs);      load_seg_vm(R_GS, new_gs & 0xffff);
1642    
1643      env->eip = new_eip;      env->eip = new_eip;
1644      ESP = new_esp;      ESP = new_esp;

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.7

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26