Commit a4a0ffdb2be25b381df38758b1b0a32ae04491d0
1 parent
0ea00c9a
added cmpxchg8b, cpuid, bound, eflags support, vm86 mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@53 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
108 additions
and
9 deletions
op-i386.c
| @@ -607,11 +607,49 @@ void OPPROTO op_into(void) | @@ -607,11 +607,49 @@ void OPPROTO op_into(void) | ||
| 607 | int eflags; | 607 | int eflags; |
| 608 | eflags = cc_table[CC_OP].compute_all(); | 608 | eflags = cc_table[CC_OP].compute_all(); |
| 609 | if (eflags & CC_O) { | 609 | if (eflags & CC_O) { |
| 610 | - EIP = PARAM1; | ||
| 611 | raise_exception(EXCP04_INTO); | 610 | raise_exception(EXCP04_INTO); |
| 611 | + } | ||
| 612 | +} | ||
| 613 | + | ||
| 614 | +void OPPROTO op_boundw(void) | ||
| 615 | +{ | ||
| 616 | + int low, high, v; | ||
| 617 | + low = ldsw((uint8_t *)A0); | ||
| 618 | + high = ldsw((uint8_t *)A0 + 2); | ||
| 619 | + v = (int16_t)T0; | ||
| 620 | + if (v < low || v > high) | ||
| 621 | + raise_exception(EXCP05_BOUND); | ||
| 622 | + FORCE_RET(); | ||
| 623 | +} | ||
| 624 | + | ||
| 625 | +void OPPROTO op_boundl(void) | ||
| 626 | +{ | ||
| 627 | + int low, high, v; | ||
| 628 | + low = ldl((uint8_t *)A0); | ||
| 629 | + high = ldl((uint8_t *)A0 + 4); | ||
| 630 | + v = T0; | ||
| 631 | + if (v < low || v > high) | ||
| 632 | + raise_exception(EXCP05_BOUND); | ||
| 633 | + FORCE_RET(); | ||
| 634 | +} | ||
| 635 | + | ||
| 636 | +void OPPROTO op_cmpxchg8b(void) | ||
| 637 | +{ | ||
| 638 | + uint64_t d; | ||
| 639 | + int eflags; | ||
| 640 | + | ||
| 641 | + eflags = cc_table[CC_OP].compute_all(); | ||
| 642 | + d = ldq((uint8_t *)A0); | ||
| 643 | + if (d == (((uint64_t)EDX << 32) | EAX)) { | ||
| 644 | + stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX); | ||
| 645 | + eflags |= CC_Z; | ||
| 612 | } else { | 646 | } else { |
| 613 | - EIP = PARAM2; | 647 | + EDX = d >> 32; |
| 648 | + EAX = d; | ||
| 649 | + eflags &= ~CC_Z; | ||
| 614 | } | 650 | } |
| 651 | + CC_SRC = eflags; | ||
| 652 | + FORCE_RET(); | ||
| 615 | } | 653 | } |
| 616 | 654 | ||
| 617 | /* string ops */ | 655 | /* string ops */ |
| @@ -793,7 +831,8 @@ void op_addw_ESP_im(void) | @@ -793,7 +831,8 @@ void op_addw_ESP_im(void) | ||
| 793 | #ifndef __i386__ | 831 | #ifndef __i386__ |
| 794 | uint64_t emu_time; | 832 | uint64_t emu_time; |
| 795 | #endif | 833 | #endif |
| 796 | -void op_rdtsc(void) | 834 | + |
| 835 | +void OPPROTO op_rdtsc(void) | ||
| 797 | { | 836 | { |
| 798 | uint64_t val; | 837 | uint64_t val; |
| 799 | #ifdef __i386__ | 838 | #ifdef __i386__ |
| @@ -806,6 +845,51 @@ void op_rdtsc(void) | @@ -806,6 +845,51 @@ void op_rdtsc(void) | ||
| 806 | EDX = val >> 32; | 845 | EDX = val >> 32; |
| 807 | } | 846 | } |
| 808 | 847 | ||
| 848 | +/* We simulate a pre-MMX pentium as in valgrind */ | ||
| 849 | +#define CPUID_FP87 (1 << 0) | ||
| 850 | +#define CPUID_VME (1 << 1) | ||
| 851 | +#define CPUID_DE (1 << 2) | ||
| 852 | +#define CPUID_PSE (1 << 3) | ||
| 853 | +#define CPUID_TSC (1 << 4) | ||
| 854 | +#define CPUID_MSR (1 << 5) | ||
| 855 | +#define CPUID_PAE (1 << 6) | ||
| 856 | +#define CPUID_MCE (1 << 7) | ||
| 857 | +#define CPUID_CX8 (1 << 8) | ||
| 858 | +#define CPUID_APIC (1 << 9) | ||
| 859 | +#define CPUID_SEP (1 << 11) /* sysenter/sysexit */ | ||
| 860 | +#define CPUID_MTRR (1 << 12) | ||
| 861 | +#define CPUID_PGE (1 << 13) | ||
| 862 | +#define CPUID_MCA (1 << 14) | ||
| 863 | +#define CPUID_CMOV (1 << 15) | ||
| 864 | +/* ... */ | ||
| 865 | +#define CPUID_MMX (1 << 23) | ||
| 866 | +#define CPUID_FXSR (1 << 24) | ||
| 867 | +#define CPUID_SSE (1 << 25) | ||
| 868 | +#define CPUID_SSE2 (1 << 26) | ||
| 869 | + | ||
| 870 | +void helper_cpuid(void) | ||
| 871 | +{ | ||
| 872 | + if (EAX == 0) { | ||
| 873 | + EAX = 1; /* max EAX index supported */ | ||
| 874 | + EBX = 0x756e6547; | ||
| 875 | + ECX = 0x6c65746e; | ||
| 876 | + EDX = 0x49656e69; | ||
| 877 | + } else { | ||
| 878 | + /* EAX = 1 info */ | ||
| 879 | + EAX = 0x52b; | ||
| 880 | + EBX = 0; | ||
| 881 | + ECX = 0; | ||
| 882 | + EDX = CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | | ||
| 883 | + CPUID_TSC | CPUID_MSR | CPUID_MCE | | ||
| 884 | + CPUID_CX8; | ||
| 885 | + } | ||
| 886 | +} | ||
| 887 | + | ||
| 888 | +void OPPROTO op_cpuid(void) | ||
| 889 | +{ | ||
| 890 | + helper_cpuid(); | ||
| 891 | +} | ||
| 892 | + | ||
| 809 | /* bcd */ | 893 | /* bcd */ |
| 810 | 894 | ||
| 811 | /* XXX: exception */ | 895 | /* XXX: exception */ |
| @@ -938,6 +1022,7 @@ void OPPROTO op_das(void) | @@ -938,6 +1022,7 @@ void OPPROTO op_das(void) | ||
| 938 | 1022 | ||
| 939 | /* segment handling */ | 1023 | /* segment handling */ |
| 940 | 1024 | ||
| 1025 | +/* XXX: use static VM86 information */ | ||
| 941 | void load_seg(int seg_reg, int selector) | 1026 | void load_seg(int seg_reg, int selector) |
| 942 | { | 1027 | { |
| 943 | SegmentCache *sc; | 1028 | SegmentCache *sc; |
| @@ -948,7 +1033,7 @@ void load_seg(int seg_reg, int selector) | @@ -948,7 +1033,7 @@ void load_seg(int seg_reg, int selector) | ||
| 948 | 1033 | ||
| 949 | env->segs[seg_reg] = selector; | 1034 | env->segs[seg_reg] = selector; |
| 950 | sc = &env->seg_cache[seg_reg]; | 1035 | sc = &env->seg_cache[seg_reg]; |
| 951 | - if (env->vm86) { | 1036 | + if (env->eflags & VM_MASK) { |
| 952 | sc->base = (void *)(selector << 4); | 1037 | sc->base = (void *)(selector << 4); |
| 953 | sc->limit = 0xffff; | 1038 | sc->limit = 0xffff; |
| 954 | sc->seg_32bit = 0; | 1039 | sc->seg_32bit = 0; |
| @@ -985,6 +1070,11 @@ void OPPROTO op_movl_T0_seg(void) | @@ -985,6 +1070,11 @@ void OPPROTO op_movl_T0_seg(void) | ||
| 985 | T0 = env->segs[PARAM1]; | 1070 | T0 = env->segs[PARAM1]; |
| 986 | } | 1071 | } |
| 987 | 1072 | ||
| 1073 | +void OPPROTO op_movl_A0_seg(void) | ||
| 1074 | +{ | ||
| 1075 | + A0 = *(unsigned long *)((char *)env + PARAM1); | ||
| 1076 | +} | ||
| 1077 | + | ||
| 988 | void OPPROTO op_addl_A0_seg(void) | 1078 | void OPPROTO op_addl_A0_seg(void) |
| 989 | { | 1079 | { |
| 990 | A0 += *(unsigned long *)((char *)env + PARAM1); | 1080 | A0 += *(unsigned long *)((char *)env + PARAM1); |
| @@ -1144,10 +1234,16 @@ void OPPROTO op_set_cc_op(void) | @@ -1144,10 +1234,16 @@ void OPPROTO op_set_cc_op(void) | ||
| 1144 | CC_OP = PARAM1; | 1234 | CC_OP = PARAM1; |
| 1145 | } | 1235 | } |
| 1146 | 1236 | ||
| 1237 | +#define FL_UPDATE_MASK (TF_MASK | AC_MASK | ID_MASK) | ||
| 1238 | + | ||
| 1147 | void OPPROTO op_movl_eflags_T0(void) | 1239 | void OPPROTO op_movl_eflags_T0(void) |
| 1148 | { | 1240 | { |
| 1149 | - CC_SRC = T0; | ||
| 1150 | - DF = 1 - (2 * ((T0 >> 10) & 1)); | 1241 | + int eflags; |
| 1242 | + eflags = T0; | ||
| 1243 | + CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); | ||
| 1244 | + DF = 1 - (2 * ((eflags >> 10) & 1)); | ||
| 1245 | + /* we also update some system flags as in user mode */ | ||
| 1246 | + env->eflags = (env->eflags & ~FL_UPDATE_MASK) | (eflags & FL_UPDATE_MASK); | ||
| 1151 | } | 1247 | } |
| 1152 | 1248 | ||
| 1153 | /* XXX: compute only O flag */ | 1249 | /* XXX: compute only O flag */ |
| @@ -1155,13 +1251,16 @@ void OPPROTO op_movb_eflags_T0(void) | @@ -1155,13 +1251,16 @@ void OPPROTO op_movb_eflags_T0(void) | ||
| 1155 | { | 1251 | { |
| 1156 | int of; | 1252 | int of; |
| 1157 | of = cc_table[CC_OP].compute_all() & CC_O; | 1253 | of = cc_table[CC_OP].compute_all() & CC_O; |
| 1158 | - CC_SRC = T0 | of; | 1254 | + CC_SRC = (T0 & (CC_S | CC_Z | CC_A | CC_P | CC_C)) | of; |
| 1159 | } | 1255 | } |
| 1160 | 1256 | ||
| 1161 | void OPPROTO op_movl_T0_eflags(void) | 1257 | void OPPROTO op_movl_T0_eflags(void) |
| 1162 | { | 1258 | { |
| 1163 | - T0 = cc_table[CC_OP].compute_all(); | ||
| 1164 | - T0 |= (DF & DIRECTION_FLAG); | 1259 | + int eflags; |
| 1260 | + eflags = cc_table[CC_OP].compute_all(); | ||
| 1261 | + eflags |= (DF & DF_MASK); | ||
| 1262 | + eflags |= env->eflags & ~(VM_MASK | RF_MASK); | ||
| 1263 | + T0 = eflags; | ||
| 1165 | } | 1264 | } |
| 1166 | 1265 | ||
| 1167 | void OPPROTO op_cld(void) | 1266 | void OPPROTO op_cld(void) |