Revision 14ce26e7 target-i386/helper.c
b/target-i386/helper.c | ||
---|---|---|
119 | 119 |
{ |
120 | 120 |
SegmentCache *dt; |
121 | 121 |
int index; |
122 |
uint8_t *ptr;
|
|
122 |
target_ulong ptr;
|
|
123 | 123 |
|
124 | 124 |
if (selector & 0x4) |
125 | 125 |
dt = &env->ldt; |
... | ... | |
143 | 143 |
return limit; |
144 | 144 |
} |
145 | 145 |
|
146 |
static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2)
|
|
146 |
static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
|
|
147 | 147 |
{ |
148 |
return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
|
|
148 |
return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); |
|
149 | 149 |
} |
150 | 150 |
|
151 | 151 |
static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) |
... | ... | |
160 | 160 |
{ |
161 | 161 |
selector &= 0xffff; |
162 | 162 |
cpu_x86_load_seg_cache(env, seg, selector, |
163 |
(uint8_t *)(selector << 4), 0xffff, 0);
|
|
163 |
(selector << 4), 0xffff, 0); |
|
164 | 164 |
} |
165 | 165 |
|
166 | 166 |
static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, |
... | ... | |
258 | 258 |
uint32_t next_eip) |
259 | 259 |
{ |
260 | 260 |
int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i; |
261 |
uint8_t *tss_base;
|
|
261 |
target_ulong tss_base;
|
|
262 | 262 |
uint32_t new_regs[8], new_segs[6]; |
263 | 263 |
uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap; |
264 | 264 |
uint32_t old_eflags, eflags_mask; |
265 | 265 |
SegmentCache *dt; |
266 | 266 |
int index; |
267 |
uint8_t *ptr;
|
|
267 |
target_ulong ptr;
|
|
268 | 268 |
|
269 | 269 |
type = (e2 >> DESC_TYPE_SHIFT) & 0xf; |
270 | 270 |
#ifdef DEBUG_PCALL |
... | ... | |
345 | 345 |
|
346 | 346 |
/* clear busy bit (it is restartable) */ |
347 | 347 |
if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { |
348 |
uint8_t *ptr;
|
|
348 |
target_ulong ptr;
|
|
349 | 349 |
uint32_t e2; |
350 | 350 |
ptr = env->gdt.base + (env->tr.selector & ~7); |
351 | 351 |
e2 = ldl_kernel(ptr + 4); |
... | ... | |
397 | 397 |
|
398 | 398 |
/* set busy bit */ |
399 | 399 |
if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) { |
400 |
uint8_t *ptr;
|
|
400 |
target_ulong ptr;
|
|
401 | 401 |
uint32_t e2; |
402 | 402 |
ptr = env->gdt.base + (tss_selector & ~7); |
403 | 403 |
e2 = ldl_kernel(ptr + 4); |
... | ... | |
445 | 445 |
cpu_x86_set_cpl(env, new_segs[R_CS] & 3); |
446 | 446 |
/* first just selectors as the rest may trigger exceptions */ |
447 | 447 |
for(i = 0; i < 6; i++) |
448 |
cpu_x86_load_seg_cache(env, i, new_segs[i], NULL, 0, 0);
|
|
448 |
cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
|
|
449 | 449 |
} |
450 | 450 |
|
451 | 451 |
env->ldt.selector = new_ldt & ~4; |
452 |
env->ldt.base = NULL;
|
|
452 |
env->ldt.base = 0;
|
|
453 | 453 |
env->ldt.limit = 0; |
454 | 454 |
env->ldt.flags = 0; |
455 | 455 |
|
... | ... | |
573 | 573 |
|
574 | 574 |
#define POPL(ssp, sp, sp_mask, val)\ |
575 | 575 |
{\ |
576 |
val = ldl_kernel((ssp) + (sp & (sp_mask)));\ |
|
576 |
val = (uint32_t)ldl_kernel((ssp) + (sp & (sp_mask)));\
|
|
577 | 577 |
sp += 4;\ |
578 | 578 |
} |
579 | 579 |
|
... | ... | |
582 | 582 |
unsigned int next_eip, int is_hw) |
583 | 583 |
{ |
584 | 584 |
SegmentCache *dt; |
585 |
uint8_t *ptr, *ssp;
|
|
585 |
target_ulong ptr, ssp;
|
|
586 | 586 |
int type, dpl, selector, ss_dpl, cpl, sp_mask; |
587 | 587 |
int has_error_code, new_stack, shift; |
588 | 588 |
uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2; |
... | ... | |
703 | 703 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
704 | 704 |
new_stack = 0; /* avoid warning */ |
705 | 705 |
sp_mask = 0; /* avoid warning */ |
706 |
ssp = NULL; /* avoid warning */
|
|
706 |
ssp = 0; /* avoid warning */
|
|
707 | 707 |
esp = 0; /* avoid warning */ |
708 | 708 |
} |
709 | 709 |
|
... | ... | |
754 | 754 |
|
755 | 755 |
if (new_stack) { |
756 | 756 |
if (env->eflags & VM_MASK) { |
757 |
cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0, 0);
|
|
758 |
cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0, 0);
|
|
759 |
cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0, 0);
|
|
760 |
cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0, 0);
|
|
757 |
cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
|
|
758 |
cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
|
|
759 |
cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
|
|
760 |
cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
|
|
761 | 761 |
} |
762 | 762 |
ss = (ss & ~3) | dpl; |
763 | 763 |
cpu_x86_load_seg_cache(env, R_SS, ss, |
... | ... | |
780 | 780 |
env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); |
781 | 781 |
} |
782 | 782 |
|
783 |
#ifdef TARGET_X86_64 |
|
784 |
|
|
785 |
#define PUSHQ(sp, val)\ |
|
786 |
{\ |
|
787 |
sp -= 8;\ |
|
788 |
stq_kernel(sp, (val));\ |
|
789 |
} |
|
790 |
|
|
791 |
#define POPQ(sp, val)\ |
|
792 |
{\ |
|
793 |
val = ldq_kernel(sp);\ |
|
794 |
sp += 8;\ |
|
795 |
} |
|
796 |
|
|
797 |
static inline target_ulong get_rsp_from_tss(int level) |
|
798 |
{ |
|
799 |
int index; |
|
800 |
|
|
801 |
#if 0 |
|
802 |
printf("TR: base=" TARGET_FMT_lx " limit=%x\n", |
|
803 |
env->tr.base, env->tr.limit); |
|
804 |
#endif |
|
805 |
|
|
806 |
if (!(env->tr.flags & DESC_P_MASK)) |
|
807 |
cpu_abort(env, "invalid tss"); |
|
808 |
index = 8 * level + 4; |
|
809 |
if ((index + 7) > env->tr.limit) |
|
810 |
raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); |
|
811 |
return ldq_kernel(env->tr.base + index); |
|
812 |
} |
|
813 |
|
|
814 |
/* 64 bit interrupt */ |
|
815 |
static void do_interrupt64(int intno, int is_int, int error_code, |
|
816 |
target_ulong next_eip, int is_hw) |
|
817 |
{ |
|
818 |
SegmentCache *dt; |
|
819 |
target_ulong ptr; |
|
820 |
int type, dpl, selector, cpl, ist; |
|
821 |
int has_error_code, new_stack; |
|
822 |
uint32_t e1, e2, e3, ss; |
|
823 |
target_ulong old_eip, esp, offset; |
|
824 |
|
|
825 |
has_error_code = 0; |
|
826 |
if (!is_int && !is_hw) { |
|
827 |
switch(intno) { |
|
828 |
case 8: |
|
829 |
case 10: |
|
830 |
case 11: |
|
831 |
case 12: |
|
832 |
case 13: |
|
833 |
case 14: |
|
834 |
case 17: |
|
835 |
has_error_code = 1; |
|
836 |
break; |
|
837 |
} |
|
838 |
} |
|
839 |
if (is_int) |
|
840 |
old_eip = next_eip; |
|
841 |
else |
|
842 |
old_eip = env->eip; |
|
843 |
|
|
844 |
dt = &env->idt; |
|
845 |
if (intno * 16 + 15 > dt->limit) |
|
846 |
raise_exception_err(EXCP0D_GPF, intno * 16 + 2); |
|
847 |
ptr = dt->base + intno * 16; |
|
848 |
e1 = ldl_kernel(ptr); |
|
849 |
e2 = ldl_kernel(ptr + 4); |
|
850 |
e3 = ldl_kernel(ptr + 8); |
|
851 |
/* check gate type */ |
|
852 |
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; |
|
853 |
switch(type) { |
|
854 |
case 14: /* 386 interrupt gate */ |
|
855 |
case 15: /* 386 trap gate */ |
|
856 |
break; |
|
857 |
default: |
|
858 |
raise_exception_err(EXCP0D_GPF, intno * 16 + 2); |
|
859 |
break; |
|
860 |
} |
|
861 |
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
|
862 |
cpl = env->hflags & HF_CPL_MASK; |
|
863 |
/* check privledge if software int */ |
|
864 |
if (is_int && dpl < cpl) |
|
865 |
raise_exception_err(EXCP0D_GPF, intno * 16 + 2); |
|
866 |
/* check valid bit */ |
|
867 |
if (!(e2 & DESC_P_MASK)) |
|
868 |
raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2); |
|
869 |
selector = e1 >> 16; |
|
870 |
offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff); |
|
871 |
ist = e2 & 7; |
|
872 |
if ((selector & 0xfffc) == 0) |
|
873 |
raise_exception_err(EXCP0D_GPF, 0); |
|
874 |
|
|
875 |
if (load_segment(&e1, &e2, selector) != 0) |
|
876 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
|
877 |
if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) |
|
878 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
|
879 |
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
|
880 |
if (dpl > cpl) |
|
881 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
|
882 |
if (!(e2 & DESC_P_MASK)) |
|
883 |
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
|
884 |
if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK)) |
|
885 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
|
886 |
if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { |
|
887 |
/* to inner priviledge */ |
|
888 |
if (ist != 0) |
|
889 |
esp = get_rsp_from_tss(ist + 3); |
|
890 |
else |
|
891 |
esp = get_rsp_from_tss(dpl); |
|
892 |
ss = 0; |
|
893 |
new_stack = 1; |
|
894 |
} else if ((e2 & DESC_C_MASK) || dpl == cpl) { |
|
895 |
/* to same priviledge */ |
|
896 |
if (env->eflags & VM_MASK) |
|
897 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
|
898 |
new_stack = 0; |
|
899 |
esp = ESP & ~0xf; /* align stack */ |
|
900 |
dpl = cpl; |
|
901 |
} else { |
|
902 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
|
903 |
new_stack = 0; /* avoid warning */ |
|
904 |
esp = 0; /* avoid warning */ |
|
905 |
} |
|
906 |
|
|
907 |
PUSHQ(esp, env->segs[R_SS].selector); |
|
908 |
PUSHQ(esp, ESP); |
|
909 |
PUSHQ(esp, compute_eflags()); |
|
910 |
PUSHQ(esp, env->segs[R_CS].selector); |
|
911 |
PUSHQ(esp, old_eip); |
|
912 |
if (has_error_code) { |
|
913 |
PUSHQ(esp, error_code); |
|
914 |
} |
|
915 |
|
|
916 |
if (new_stack) { |
|
917 |
ss = 0 | dpl; |
|
918 |
cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0); |
|
919 |
} |
|
920 |
ESP = esp; |
|
921 |
|
|
922 |
selector = (selector & ~3) | dpl; |
|
923 |
cpu_x86_load_seg_cache(env, R_CS, selector, |
|
924 |
get_seg_base(e1, e2), |
|
925 |
get_seg_limit(e1, e2), |
|
926 |
e2); |
|
927 |
cpu_x86_set_cpl(env, dpl); |
|
928 |
env->eip = offset; |
|
929 |
|
|
930 |
/* interrupt gate clear IF mask */ |
|
931 |
if ((type & 1) == 0) { |
|
932 |
env->eflags &= ~IF_MASK; |
|
933 |
} |
|
934 |
env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); |
|
935 |
} |
|
936 |
|
|
937 |
void helper_syscall(void) |
|
938 |
{ |
|
939 |
int selector; |
|
940 |
|
|
941 |
if (!(env->efer & MSR_EFER_SCE)) { |
|
942 |
raise_exception_err(EXCP06_ILLOP, 0); |
|
943 |
} |
|
944 |
selector = (env->star >> 32) & 0xffff; |
|
945 |
if (env->hflags & HF_LMA_MASK) { |
|
946 |
ECX = env->eip; |
|
947 |
env->regs[11] = compute_eflags(); |
|
948 |
|
|
949 |
cpu_x86_set_cpl(env, 0); |
|
950 |
cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, |
|
951 |
0, 0xffffffff, |
|
952 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
|
953 |
DESC_S_MASK | |
|
954 |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); |
|
955 |
cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, |
|
956 |
0, 0xffffffff, |
|
957 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
|
958 |
DESC_S_MASK | |
|
959 |
DESC_W_MASK | DESC_A_MASK); |
|
960 |
env->eflags &= ~env->fmask; |
|
961 |
if (env->hflags & HF_CS64_MASK) |
|
962 |
env->eip = env->lstar; |
|
963 |
else |
|
964 |
env->eip = env->cstar; |
|
965 |
} else { |
|
966 |
ECX = (uint32_t)env->eip; |
|
967 |
|
|
968 |
cpu_x86_set_cpl(env, 0); |
|
969 |
cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, |
|
970 |
0, 0xffffffff, |
|
971 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
|
972 |
DESC_S_MASK | |
|
973 |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); |
|
974 |
cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, |
|
975 |
0, 0xffffffff, |
|
976 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
|
977 |
DESC_S_MASK | |
|
978 |
DESC_W_MASK | DESC_A_MASK); |
|
979 |
env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); |
|
980 |
env->eip = (uint32_t)env->star; |
|
981 |
} |
|
982 |
} |
|
983 |
|
|
984 |
void helper_sysret(int dflag) |
|
985 |
{ |
|
986 |
int cpl, selector; |
|
987 |
|
|
988 |
cpl = env->hflags & HF_CPL_MASK; |
|
989 |
if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { |
|
990 |
raise_exception_err(EXCP0D_GPF, 0); |
|
991 |
} |
|
992 |
selector = (env->star >> 48) & 0xffff; |
|
993 |
if (env->hflags & HF_LMA_MASK) { |
|
994 |
if (dflag == 2) { |
|
995 |
cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, |
|
996 |
0, 0xffffffff, |
|
997 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
|
998 |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) | |
|
999 |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | |
|
1000 |
DESC_L_MASK); |
|
1001 |
env->eip = ECX; |
|
1002 |
} else { |
|
1003 |
cpu_x86_load_seg_cache(env, R_CS, selector | 3, |
|
1004 |
0, 0xffffffff, |
|
1005 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
|
1006 |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) | |
|
1007 |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); |
|
1008 |
env->eip = (uint32_t)ECX; |
|
1009 |
} |
|
1010 |
cpu_x86_load_seg_cache(env, R_SS, selector + 8, |
|
1011 |
0, 0xffffffff, |
|
1012 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
|
1013 |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) | |
|
1014 |
DESC_W_MASK | DESC_A_MASK); |
|
1015 |
load_eflags((uint32_t)(env->regs[11]), 0xffffffff); |
|
1016 |
cpu_x86_set_cpl(env, 3); |
|
1017 |
} else { |
|
1018 |
cpu_x86_load_seg_cache(env, R_CS, selector | 3, |
|
1019 |
0, 0xffffffff, |
|
1020 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
|
1021 |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) | |
|
1022 |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); |
|
1023 |
env->eip = (uint32_t)ECX; |
|
1024 |
cpu_x86_load_seg_cache(env, R_SS, selector + 8, |
|
1025 |
0, 0xffffffff, |
|
1026 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
|
1027 |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) | |
|
1028 |
DESC_W_MASK | DESC_A_MASK); |
|
1029 |
env->eflags |= IF_MASK; |
|
1030 |
cpu_x86_set_cpl(env, 3); |
|
1031 |
} |
|
1032 |
} |
|
1033 |
#endif |
|
1034 |
|
|
783 | 1035 |
/* real mode interrupt */ |
784 | 1036 |
static void do_interrupt_real(int intno, int is_int, int error_code, |
785 | 1037 |
unsigned int next_eip) |
786 | 1038 |
{ |
787 | 1039 |
SegmentCache *dt; |
788 |
uint8_t *ptr, *ssp;
|
|
1040 |
target_ulong ptr, ssp;
|
|
789 | 1041 |
int selector; |
790 | 1042 |
uint32_t offset, esp; |
791 | 1043 |
uint32_t old_cs, old_eip; |
... | ... | |
813 | 1065 |
ESP = (ESP & ~0xffff) | (esp & 0xffff); |
814 | 1066 |
env->eip = offset; |
815 | 1067 |
env->segs[R_CS].selector = selector; |
816 |
env->segs[R_CS].base = (uint8_t *)(selector << 4);
|
|
1068 |
env->segs[R_CS].base = (selector << 4); |
|
817 | 1069 |
env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); |
818 | 1070 |
} |
819 | 1071 |
|
820 | 1072 |
/* fake user mode interrupt */ |
821 | 1073 |
void do_interrupt_user(int intno, int is_int, int error_code, |
822 |
unsigned int next_eip)
|
|
1074 |
target_ulong next_eip)
|
|
823 | 1075 |
{ |
824 | 1076 |
SegmentCache *dt; |
825 |
uint8_t *ptr;
|
|
1077 |
target_ulong ptr;
|
|
826 | 1078 |
int dpl, cpl; |
827 | 1079 |
uint32_t e2; |
828 | 1080 |
|
... | ... | |
849 | 1101 |
* instruction. It is only relevant if is_int is TRUE. |
850 | 1102 |
*/ |
851 | 1103 |
void do_interrupt(int intno, int is_int, int error_code, |
852 |
unsigned int next_eip, int is_hw)
|
|
1104 |
target_ulong next_eip, int is_hw)
|
|
853 | 1105 |
{ |
854 | 1106 |
#ifdef DEBUG_PCALL |
855 | 1107 |
if (loglevel & (CPU_LOG_PCALL | CPU_LOG_INT)) { |
856 | 1108 |
if ((env->cr[0] & CR0_PE_MASK)) { |
857 | 1109 |
static int count; |
858 |
fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:%08x pc=%08x SP=%04x:%08x",
|
|
1110 |
fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
|
|
859 | 1111 |
count, intno, error_code, is_int, |
860 | 1112 |
env->hflags & HF_CPL_MASK, |
861 | 1113 |
env->segs[R_CS].selector, EIP, |
862 | 1114 |
(int)env->segs[R_CS].base + EIP, |
863 | 1115 |
env->segs[R_SS].selector, ESP); |
864 | 1116 |
if (intno == 0x0e) { |
865 |
fprintf(logfile, " CR2=%08x", env->cr[2]);
|
|
1117 |
fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]);
|
|
866 | 1118 |
} else { |
867 |
fprintf(logfile, " EAX=%08x", EAX);
|
|
1119 |
fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX);
|
|
868 | 1120 |
} |
869 | 1121 |
fprintf(logfile, "\n"); |
870 |
#if 0 |
|
871 | 1122 |
cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); |
1123 |
#if 0 |
|
872 | 1124 |
{ |
873 | 1125 |
int i; |
874 | 1126 |
uint8_t *ptr; |
... | ... | |
885 | 1137 |
} |
886 | 1138 |
#endif |
887 | 1139 |
if (env->cr[0] & CR0_PE_MASK) { |
888 |
do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); |
|
1140 |
#if TARGET_X86_64 |
|
1141 |
if (env->hflags & HF_LMA_MASK) { |
|
1142 |
do_interrupt64(intno, is_int, error_code, next_eip, is_hw); |
|
1143 |
} else |
|
1144 |
#endif |
|
1145 |
{ |
|
1146 |
do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); |
|
1147 |
} |
|
889 | 1148 |
} else { |
890 | 1149 |
do_interrupt_real(intno, is_int, error_code, next_eip); |
891 | 1150 |
} |
... | ... | |
932 | 1191 |
#ifdef BUGGY_GCC_DIV64 |
933 | 1192 |
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we |
934 | 1193 |
call it from another function */ |
935 |
uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den)
|
|
1194 |
uint32_t div32(uint32_t *q_ptr, uint64_t num, uint32_t den)
|
|
936 | 1195 |
{ |
937 | 1196 |
*q_ptr = num / den; |
938 | 1197 |
return num % den; |
939 | 1198 |
} |
940 | 1199 |
|
941 |
int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den)
|
|
1200 |
int32_t idiv32(int32_t *q_ptr, int64_t num, int32_t den)
|
|
942 | 1201 |
{ |
943 | 1202 |
*q_ptr = num / den; |
944 | 1203 |
return num % den; |
945 | 1204 |
} |
946 | 1205 |
#endif |
947 | 1206 |
|
948 |
void helper_divl_EAX_T0(uint32_t eip)
|
|
1207 |
void helper_divl_EAX_T0(void)
|
|
949 | 1208 |
{ |
950 | 1209 |
unsigned int den, q, r; |
951 | 1210 |
uint64_t num; |
... | ... | |
953 | 1212 |
num = EAX | ((uint64_t)EDX << 32); |
954 | 1213 |
den = T0; |
955 | 1214 |
if (den == 0) { |
956 |
EIP = eip; |
|
957 | 1215 |
raise_exception(EXCP00_DIVZ); |
958 | 1216 |
} |
959 | 1217 |
#ifdef BUGGY_GCC_DIV64 |
960 |
r = div64(&q, num, den);
|
|
1218 |
r = div32(&q, num, den);
|
|
961 | 1219 |
#else |
962 | 1220 |
q = (num / den); |
963 | 1221 |
r = (num % den); |
964 | 1222 |
#endif |
965 |
EAX = q; |
|
966 |
EDX = r; |
|
1223 |
EAX = (uint32_t)q;
|
|
1224 |
EDX = (uint32_t)r;
|
|
967 | 1225 |
} |
968 | 1226 |
|
969 |
void helper_idivl_EAX_T0(uint32_t eip)
|
|
1227 |
void helper_idivl_EAX_T0(void)
|
|
970 | 1228 |
{ |
971 | 1229 |
int den, q, r; |
972 | 1230 |
int64_t num; |
... | ... | |
974 | 1232 |
num = EAX | ((uint64_t)EDX << 32); |
975 | 1233 |
den = T0; |
976 | 1234 |
if (den == 0) { |
977 |
EIP = eip; |
|
978 | 1235 |
raise_exception(EXCP00_DIVZ); |
979 | 1236 |
} |
980 | 1237 |
#ifdef BUGGY_GCC_DIV64 |
981 |
r = idiv64(&q, num, den);
|
|
1238 |
r = idiv32(&q, num, den);
|
|
982 | 1239 |
#else |
983 | 1240 |
q = (num / den); |
984 | 1241 |
r = (num % den); |
985 | 1242 |
#endif |
986 |
EAX = q; |
|
987 |
EDX = r; |
|
1243 |
EAX = (uint32_t)q;
|
|
1244 |
EDX = (uint32_t)r;
|
|
988 | 1245 |
} |
989 | 1246 |
|
990 | 1247 |
void helper_cmpxchg8b(void) |
... | ... | |
993 | 1250 |
int eflags; |
994 | 1251 |
|
995 | 1252 |
eflags = cc_table[CC_OP].compute_all(); |
996 |
d = ldq((uint8_t *)A0);
|
|
1253 |
d = ldq(A0); |
|
997 | 1254 |
if (d == (((uint64_t)EDX << 32) | EAX)) { |
998 |
stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX);
|
|
1255 |
stq(A0, ((uint64_t)ECX << 32) | EBX); |
|
999 | 1256 |
eflags |= CC_Z; |
1000 | 1257 |
} else { |
1001 | 1258 |
EDX = d >> 32; |
... | ... | |
1005 | 1262 |
CC_SRC = eflags; |
1006 | 1263 |
} |
1007 | 1264 |
|
1008 |
#define CPUID_FP87 (1 << 0) |
|
1009 |
#define CPUID_VME (1 << 1) |
|
1010 |
#define CPUID_DE (1 << 2) |
|
1011 |
#define CPUID_PSE (1 << 3) |
|
1012 |
#define CPUID_TSC (1 << 4) |
|
1013 |
#define CPUID_MSR (1 << 5) |
|
1014 |
#define CPUID_PAE (1 << 6) |
|
1015 |
#define CPUID_MCE (1 << 7) |
|
1016 |
#define CPUID_CX8 (1 << 8) |
|
1017 |
#define CPUID_APIC (1 << 9) |
|
1018 |
#define CPUID_SEP (1 << 11) /* sysenter/sysexit */ |
|
1019 |
#define CPUID_MTRR (1 << 12) |
|
1020 |
#define CPUID_PGE (1 << 13) |
|
1021 |
#define CPUID_MCA (1 << 14) |
|
1022 |
#define CPUID_CMOV (1 << 15) |
|
1023 |
/* ... */ |
|
1024 |
#define CPUID_MMX (1 << 23) |
|
1025 |
#define CPUID_FXSR (1 << 24) |
|
1026 |
#define CPUID_SSE (1 << 25) |
|
1027 |
#define CPUID_SSE2 (1 << 26) |
|
1028 |
|
|
1029 | 1265 |
void helper_cpuid(void) |
1030 | 1266 |
{ |
1031 |
switch(EAX) { |
|
1267 |
switch((uint32_t)EAX) {
|
|
1032 | 1268 |
case 0: |
1033 | 1269 |
EAX = 2; /* max EAX index supported */ |
1034 |
EBX = 0x756e6547;
|
|
1035 |
ECX = 0x6c65746e;
|
|
1036 |
EDX = 0x49656e69;
|
|
1270 |
EBX = env->cpuid_vendor1;
|
|
1271 |
EDX = env->cpuid_vendor2;
|
|
1272 |
ECX = env->cpuid_vendor3;
|
|
1037 | 1273 |
break; |
1038 | 1274 |
case 1: |
1039 |
{ |
|
1040 |
int family, model, stepping; |
|
1041 |
/* EAX = 1 info */ |
|
1042 |
#if 0 |
|
1043 |
/* pentium 75-200 */ |
|
1044 |
family = 5; |
|
1045 |
model = 2; |
|
1046 |
stepping = 11; |
|
1047 |
#else |
|
1048 |
/* pentium pro */ |
|
1049 |
family = 6; |
|
1050 |
model = 1; |
|
1051 |
stepping = 3; |
|
1052 |
#endif |
|
1053 |
EAX = (family << 8) | (model << 4) | stepping; |
|
1054 |
EBX = 0; |
|
1055 |
ECX = 0; |
|
1056 |
EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | |
|
1057 |
CPUID_TSC | CPUID_MSR | CPUID_MCE | |
|
1058 |
CPUID_CX8 | CPUID_PGE | CPUID_CMOV; |
|
1059 |
} |
|
1275 |
EAX = env->cpuid_version; |
|
1276 |
EBX = 0; |
|
1277 |
ECX = 0; |
|
1278 |
EDX = env->cpuid_features; |
|
1060 | 1279 |
break; |
1061 | 1280 |
default: |
1062 | 1281 |
/* cache info: needed for Pentium Pro compatibility */ |
... | ... | |
1065 | 1284 |
ECX = 0; |
1066 | 1285 |
EDX = 0; |
1067 | 1286 |
break; |
1287 |
#ifdef TARGET_X86_64 |
|
1288 |
case 0x80000000: |
|
1289 |
EAX = 0x80000008; |
|
1290 |
EBX = env->cpuid_vendor1; |
|
1291 |
EDX = env->cpuid_vendor2; |
|
1292 |
ECX = env->cpuid_vendor3; |
|
1293 |
break; |
|
1294 |
case 0x80000001: |
|
1295 |
EAX = env->cpuid_features; |
|
1296 |
EBX = 0; |
|
1297 |
ECX = 0; |
|
1298 |
/* long mode + syscall/sysret features */ |
|
1299 |
EDX = (env->cpuid_features & 0x0183F3FF) | (1 << 29) | (1 << 11); |
|
1300 |
break; |
|
1301 |
case 0x80000008: |
|
1302 |
/* virtual & phys address size in low 2 bytes. */ |
|
1303 |
EAX = 0x00003028; |
|
1304 |
EBX = 0; |
|
1305 |
ECX = 0; |
|
1306 |
EDX = 0; |
|
1307 |
break; |
|
1308 |
#endif |
|
1068 | 1309 |
} |
1069 | 1310 |
} |
1070 | 1311 |
|
1071 | 1312 |
void helper_enter_level(int level, int data32) |
1072 | 1313 |
{ |
1073 |
uint8_t *ssp;
|
|
1314 |
target_ulong ssp;
|
|
1074 | 1315 |
uint32_t esp_mask, esp, ebp; |
1075 | 1316 |
|
1076 | 1317 |
esp_mask = get_sp_mask(env->segs[R_SS].flags); |
... | ... | |
1105 | 1346 |
int selector; |
1106 | 1347 |
SegmentCache *dt; |
1107 | 1348 |
uint32_t e1, e2; |
1108 |
int index; |
|
1109 |
uint8_t *ptr;
|
|
1349 |
int index, entry_limit;
|
|
1350 |
target_ulong ptr;
|
|
1110 | 1351 |
|
1111 | 1352 |
selector = T0 & 0xffff; |
1112 | 1353 |
if ((selector & 0xfffc) == 0) { |
1113 | 1354 |
/* XXX: NULL selector case: invalid LDT */ |
1114 |
env->ldt.base = NULL;
|
|
1355 |
env->ldt.base = 0;
|
|
1115 | 1356 |
env->ldt.limit = 0; |
1116 | 1357 |
} else { |
1117 | 1358 |
if (selector & 0x4) |
1118 | 1359 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1119 | 1360 |
dt = &env->gdt; |
1120 | 1361 |
index = selector & ~7; |
1121 |
if ((index + 7) > dt->limit) |
|
1362 |
#ifdef TARGET_X86_64 |
|
1363 |
if (env->hflags & HF_LMA_MASK) |
|
1364 |
entry_limit = 15; |
|
1365 |
else |
|
1366 |
#endif |
|
1367 |
entry_limit = 7; |
|
1368 |
if ((index + entry_limit) > dt->limit) |
|
1122 | 1369 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1123 | 1370 |
ptr = dt->base + index; |
1124 | 1371 |
e1 = ldl_kernel(ptr); |
... | ... | |
1127 | 1374 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1128 | 1375 |
if (!(e2 & DESC_P_MASK)) |
1129 | 1376 |
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
1130 |
load_seg_cache_raw_dt(&env->ldt, e1, e2); |
|
1377 |
#ifdef TARGET_X86_64 |
|
1378 |
if (env->hflags & HF_LMA_MASK) { |
|
1379 |
uint32_t e3; |
|
1380 |
e3 = ldl_kernel(ptr + 8); |
|
1381 |
load_seg_cache_raw_dt(&env->ldt, e1, e2); |
|
1382 |
env->ldt.base |= (target_ulong)e3 << 32; |
|
1383 |
} else |
|
1384 |
#endif |
|
1385 |
{ |
|
1386 |
load_seg_cache_raw_dt(&env->ldt, e1, e2); |
|
1387 |
} |
|
1131 | 1388 |
} |
1132 | 1389 |
env->ldt.selector = selector; |
1133 | 1390 |
} |
... | ... | |
1137 | 1394 |
int selector; |
1138 | 1395 |
SegmentCache *dt; |
1139 | 1396 |
uint32_t e1, e2; |
1140 |
int index, type; |
|
1141 |
uint8_t *ptr;
|
|
1397 |
int index, type, entry_limit;
|
|
1398 |
target_ulong ptr;
|
|
1142 | 1399 |
|
1143 | 1400 |
selector = T0 & 0xffff; |
1144 | 1401 |
if ((selector & 0xfffc) == 0) { |
1145 |
/* NULL selector case: invalid LDT */
|
|
1146 |
env->tr.base = NULL;
|
|
1402 |
/* NULL selector case: invalid TR */
|
|
1403 |
env->tr.base = 0;
|
|
1147 | 1404 |
env->tr.limit = 0; |
1148 | 1405 |
env->tr.flags = 0; |
1149 | 1406 |
} else { |
... | ... | |
1151 | 1408 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1152 | 1409 |
dt = &env->gdt; |
1153 | 1410 |
index = selector & ~7; |
1154 |
if ((index + 7) > dt->limit) |
|
1411 |
#ifdef TARGET_X86_64 |
|
1412 |
if (env->hflags & HF_LMA_MASK) |
|
1413 |
entry_limit = 15; |
|
1414 |
else |
|
1415 |
#endif |
|
1416 |
entry_limit = 7; |
|
1417 |
if ((index + entry_limit) > dt->limit) |
|
1155 | 1418 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1156 | 1419 |
ptr = dt->base + index; |
1157 | 1420 |
e1 = ldl_kernel(ptr); |
... | ... | |
1162 | 1425 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1163 | 1426 |
if (!(e2 & DESC_P_MASK)) |
1164 | 1427 |
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
1165 |
load_seg_cache_raw_dt(&env->tr, e1, e2); |
|
1428 |
#ifdef TARGET_X86_64 |
|
1429 |
if (env->hflags & HF_LMA_MASK) { |
|
1430 |
uint32_t e3; |
|
1431 |
e3 = ldl_kernel(ptr + 8); |
|
1432 |
load_seg_cache_raw_dt(&env->tr, e1, e2); |
|
1433 |
env->tr.base |= (target_ulong)e3 << 32; |
|
1434 |
} else |
|
1435 |
#endif |
|
1436 |
{ |
|
1437 |
load_seg_cache_raw_dt(&env->tr, e1, e2); |
|
1438 |
} |
|
1166 | 1439 |
e2 |= DESC_TSS_BUSY_MASK; |
1167 | 1440 |
stl_kernel(ptr + 4, e2); |
1168 | 1441 |
} |
... | ... | |
1176 | 1449 |
int cpl, dpl, rpl; |
1177 | 1450 |
SegmentCache *dt; |
1178 | 1451 |
int index; |
1179 |
uint8_t *ptr;
|
|
1452 |
target_ulong ptr;
|
|
1180 | 1453 |
|
1181 | 1454 |
selector &= 0xffff; |
1182 | 1455 |
if ((selector & 0xfffc) == 0) { |
1183 | 1456 |
/* null selector case */ |
1184 | 1457 |
if (seg_reg == R_SS) |
1185 | 1458 |
raise_exception_err(EXCP0D_GPF, 0); |
1186 |
cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
|
|
1459 |
cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
|
|
1187 | 1460 |
} else { |
1188 | 1461 |
|
1189 | 1462 |
if (selector & 0x4) |
... | ... | |
1196 | 1469 |
ptr = dt->base + index; |
1197 | 1470 |
e1 = ldl_kernel(ptr); |
1198 | 1471 |
e2 = ldl_kernel(ptr + 4); |
1199 |
|
|
1472 |
|
|
1200 | 1473 |
if (!(e2 & DESC_S_MASK)) |
1201 | 1474 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1202 | 1475 |
rpl = selector & 3; |
... | ... | |
1247 | 1520 |
/* protected mode jump */ |
1248 | 1521 |
void helper_ljmp_protected_T0_T1(int next_eip) |
1249 | 1522 |
{ |
1250 |
int new_cs, new_eip, gate_cs, type;
|
|
1523 |
int new_cs, gate_cs, type; |
|
1251 | 1524 |
uint32_t e1, e2, cpl, dpl, rpl, limit; |
1252 |
|
|
1525 |
target_ulong new_eip; |
|
1526 |
|
|
1253 | 1527 |
new_cs = T0; |
1254 | 1528 |
new_eip = T1; |
1255 | 1529 |
if ((new_cs & 0xfffc) == 0) |
... | ... | |
1312 | 1586 |
if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != |
1313 | 1587 |
(DESC_S_MASK | DESC_CS_MASK))) |
1314 | 1588 |
raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); |
1315 |
if (((e2 & DESC_C_MASK) && (dpl > cpl)) || |
|
1589 |
if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
|
|
1316 | 1590 |
(!(e2 & DESC_C_MASK) && (dpl != cpl))) |
1317 | 1591 |
raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc); |
1318 | 1592 |
if (!(e2 & DESC_P_MASK)) |
... | ... | |
1336 | 1610 |
{ |
1337 | 1611 |
int new_cs, new_eip; |
1338 | 1612 |
uint32_t esp, esp_mask; |
1339 |
uint8_t *ssp;
|
|
1613 |
target_ulong ssp;
|
|
1340 | 1614 |
|
1341 | 1615 |
new_cs = T0; |
1342 | 1616 |
new_eip = T1; |
... | ... | |
1354 | 1628 |
ESP = (ESP & ~esp_mask) | (esp & esp_mask); |
1355 | 1629 |
env->eip = new_eip; |
1356 | 1630 |
env->segs[R_CS].selector = new_cs; |
1357 |
env->segs[R_CS].base = (uint8_t *)(new_cs << 4);
|
|
1631 |
env->segs[R_CS].base = (new_cs << 4); |
|
1358 | 1632 |
} |
1359 | 1633 |
|
1360 | 1634 |
/* protected mode call */ |
... | ... | |
1364 | 1638 |
uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; |
1365 | 1639 |
uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; |
1366 | 1640 |
uint32_t val, limit, old_sp_mask; |
1367 |
uint8_t *ssp, *old_ssp;
|
|
1641 |
target_ulong ssp, old_ssp;
|
|
1368 | 1642 |
|
1369 | 1643 |
new_cs = T0; |
1370 | 1644 |
new_eip = T1; |
... | ... | |
1471 | 1745 |
get_ss_esp_from_tss(&ss, &sp, dpl); |
1472 | 1746 |
#ifdef DEBUG_PCALL |
1473 | 1747 |
if (loglevel & CPU_LOG_PCALL) |
1474 |
fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=%x\n",
|
|
1748 |
fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
|
|
1475 | 1749 |
ss, sp, param_count, ESP); |
1476 | 1750 |
#endif |
1477 | 1751 |
if ((ss & 0xfffc) == 0) |
... | ... | |
1555 | 1829 |
void helper_iret_real(int shift) |
1556 | 1830 |
{ |
1557 | 1831 |
uint32_t sp, new_cs, new_eip, new_eflags, sp_mask; |
1558 |
uint8_t *ssp;
|
|
1832 |
target_ulong ssp;
|
|
1559 | 1833 |
int eflags_mask; |
1560 | 1834 |
|
1561 | 1835 |
sp_mask = 0xffff; /* XXXX: use SS segment size ? */ |
... | ... | |
1595 | 1869 |
if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { |
1596 | 1870 |
/* data or non conforming code segment */ |
1597 | 1871 |
if (dpl < cpl) { |
1598 |
cpu_x86_load_seg_cache(env, seg_reg, 0, NULL, 0, 0);
|
|
1872 |
cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
|
|
1599 | 1873 |
} |
1600 | 1874 |
} |
1601 | 1875 |
} |
... | ... | |
1603 | 1877 |
/* protected mode iret */ |
1604 | 1878 |
static inline void helper_ret_protected(int shift, int is_iret, int addend) |
1605 | 1879 |
{ |
1606 |
uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss, sp_mask;
|
|
1880 |
uint32_t new_cs, new_eflags, new_ss;
|
|
1607 | 1881 |
uint32_t new_es, new_ds, new_fs, new_gs; |
1608 | 1882 |
uint32_t e1, e2, ss_e1, ss_e2; |
1609 | 1883 |
int cpl, dpl, rpl, eflags_mask, iopl; |
1610 |
uint8_t *ssp;
|
|
1884 |
target_ulong ssp, sp, new_eip, new_esp, sp_mask;
|
|
1611 | 1885 |
|
1612 |
sp_mask = get_sp_mask(env->segs[R_SS].flags); |
|
1886 |
#ifdef TARGET_X86_64 |
|
1887 |
if (shift == 2) |
|
1888 |
sp_mask = -1; |
|
1889 |
else |
|
1890 |
#endif |
|
1891 |
sp_mask = get_sp_mask(env->segs[R_SS].flags); |
|
1613 | 1892 |
sp = ESP; |
1614 | 1893 |
ssp = env->segs[R_SS].base; |
1615 | 1894 |
new_eflags = 0; /* avoid warning */ |
1895 |
#ifdef TARGET_X86_64 |
|
1896 |
if (shift == 2) { |
|
1897 |
POPQ(sp, new_eip); |
|
1898 |
POPQ(sp, new_cs); |
|
1899 |
new_cs &= 0xffff; |
|
1900 |
if (is_iret) { |
|
1901 |
POPQ(sp, new_eflags); |
|
1902 |
} |
|
1903 |
} else |
|
1904 |
#endif |
|
1616 | 1905 |
if (shift == 1) { |
1617 | 1906 |
/* 32 bits */ |
1618 | 1907 |
POPL(ssp, sp, sp_mask, new_eip); |
... | ... | |
1632 | 1921 |
} |
1633 | 1922 |
#ifdef DEBUG_PCALL |
1634 | 1923 |
if (loglevel & CPU_LOG_PCALL) { |
1635 |
fprintf(logfile, "lret new %04x:%08x s=%d addend=0x%x\n",
|
|
1924 |
fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
|
|
1636 | 1925 |
new_cs, new_eip, shift, addend); |
1637 | 1926 |
cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP); |
1638 | 1927 |
} |
... | ... | |
1660 | 1949 |
raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); |
1661 | 1950 |
|
1662 | 1951 |
sp += addend; |
1663 |
if (rpl == cpl) { |
|
1952 |
if (rpl == cpl && !(env->hflags & HF_CS64_MASK)) {
|
|
1664 | 1953 |
/* return to same priledge level */ |
1665 | 1954 |
cpu_x86_load_seg_cache(env, R_CS, new_cs, |
1666 | 1955 |
get_seg_base(e1, e2), |
... | ... | |
1668 | 1957 |
e2); |
1669 | 1958 |
} else { |
1670 | 1959 |
/* return to different priviledge level */ |
1960 |
#ifdef TARGET_X86_64 |
|
1961 |
if (shift == 2) { |
|
1962 |
POPQ(sp, new_esp); |
|
1963 |
POPQ(sp, new_ss); |
|
1964 |
new_ss &= 0xffff; |
|
1965 |
} else |
|
1966 |
#endif |
|
1671 | 1967 |
if (shift == 1) { |
1672 | 1968 |
/* 32 bits */ |
1673 | 1969 |
POPL(ssp, sp, sp_mask, new_esp); |
... | ... | |
1680 | 1976 |
} |
1681 | 1977 |
#ifdef DEBUG_PCALL |
1682 | 1978 |
if (loglevel & CPU_LOG_PCALL) { |
1683 |
fprintf(logfile, "new ss:esp=%04x:%08x\n",
|
|
1979 |
fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n",
|
|
1684 | 1980 |
new_ss, new_esp); |
1685 | 1981 |
} |
1686 | 1982 |
#endif |
1687 |
|
|
1688 |
if ((new_ss & 3) != rpl) |
|
1689 |
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |
|
1690 |
if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) |
|
1691 |
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |
|
1692 |
if (!(ss_e2 & DESC_S_MASK) || |
|
1693 |
(ss_e2 & DESC_CS_MASK) || |
|
1694 |
!(ss_e2 & DESC_W_MASK)) |
|
1695 |
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |
|
1696 |
dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; |
|
1697 |
if (dpl != rpl) |
|
1698 |
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |
|
1699 |
if (!(ss_e2 & DESC_P_MASK)) |
|
1700 |
raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); |
|
1983 |
if ((env->hflags & HF_LMA_MASK) && (new_ss & 0xfffc) == 0) { |
|
1984 |
/* NULL ss is allowed in long mode */ |
|
1985 |
cpu_x86_load_seg_cache(env, R_SS, new_ss, |
|
1986 |
0, 0xffffffff, |
|
1987 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
|
1988 |
DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | |
|
1989 |
DESC_W_MASK | DESC_A_MASK); |
|
1990 |
} else { |
|
1991 |
if ((new_ss & 3) != rpl) |
|
1992 |
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |
|
1993 |
if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) |
|
1994 |
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |
|
1995 |
if (!(ss_e2 & DESC_S_MASK) || |
|
1996 |
(ss_e2 & DESC_CS_MASK) || |
|
1997 |
!(ss_e2 & DESC_W_MASK)) |
|
1998 |
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |
|
1999 |
dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; |
|
2000 |
if (dpl != rpl) |
|
2001 |
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |
|
2002 |
if (!(ss_e2 & DESC_P_MASK)) |
|
2003 |
raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); |
|
2004 |
cpu_x86_load_seg_cache(env, R_SS, new_ss, |
|
2005 |
get_seg_base(ss_e1, ss_e2), |
|
2006 |
get_seg_limit(ss_e1, ss_e2), |
|
2007 |
ss_e2); |
|
2008 |
} |
|
1701 | 2009 |
|
1702 | 2010 |
cpu_x86_load_seg_cache(env, R_CS, new_cs, |
1703 | 2011 |
get_seg_base(e1, e2), |
1704 | 2012 |
get_seg_limit(e1, e2), |
1705 | 2013 |
e2); |
1706 |
cpu_x86_load_seg_cache(env, R_SS, new_ss, |
|
1707 |
get_seg_base(ss_e1, ss_e2), |
|
1708 |
get_seg_limit(ss_e1, ss_e2), |
|
1709 |
ss_e2); |
|
1710 | 2014 |
cpu_x86_set_cpl(env, rpl); |
1711 | 2015 |
sp = new_esp; |
1712 |
sp_mask = get_sp_mask(ss_e2); |
|
2016 |
#ifdef TARGET_X86_64 |
|
2017 |
if (shift == 2) |
|
2018 |
sp_mask = -1; |
|
2019 |
else |
|
2020 |
#endif |
|
2021 |
sp_mask = get_sp_mask(ss_e2); |
|
1713 | 2022 |
|
1714 | 2023 |
/* validate data segments */ |
1715 | 2024 |
validate_seg(R_ES, cpl); |
... | ... | |
1765 | 2074 |
|
1766 | 2075 |
/* specific case for TSS */ |
1767 | 2076 |
if (env->eflags & NT_MASK) { |
2077 |
#ifdef TARGET_X86_64 |
|
2078 |
if (env->hflags & HF_LMA_MASK) |
|
2079 |
raise_exception_err(EXCP0D_GPF, 0); |
|
2080 |
#endif |
|
1768 | 2081 |
tss_selector = lduw_kernel(env->tr.base + 0); |
1769 | 2082 |
if (tss_selector & 4) |
1770 | 2083 |
raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); |
... | ... | |
1793 | 2106 |
env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); |
1794 | 2107 |
cpu_x86_set_cpl(env, 0); |
1795 | 2108 |
cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, |
1796 |
NULL, 0xffffffff,
|
|
2109 |
0, 0xffffffff,
|
|
1797 | 2110 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
1798 | 2111 |
DESC_S_MASK | |
1799 | 2112 |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); |
1800 | 2113 |
cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, |
1801 |
NULL, 0xffffffff,
|
|
2114 |
0, 0xffffffff,
|
|
1802 | 2115 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
1803 | 2116 |
DESC_S_MASK | |
1804 | 2117 |
DESC_W_MASK | DESC_A_MASK); |
... | ... | |
1816 | 2129 |
} |
1817 | 2130 |
cpu_x86_set_cpl(env, 3); |
1818 | 2131 |
cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, |
1819 |
NULL, 0xffffffff,
|
|
2132 |
0, 0xffffffff,
|
|
1820 | 2133 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
1821 | 2134 |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) | |
1822 | 2135 |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); |
1823 | 2136 |
cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, |
1824 |
NULL, 0xffffffff,
|
|
2137 |
0, 0xffffffff,
|
|
1825 | 2138 |
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
1826 | 2139 |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) | |
1827 | 2140 |
DESC_W_MASK | DESC_A_MASK); |
... | ... | |
1863 | 2176 |
uint64_t val; |
1864 | 2177 |
|
1865 | 2178 |
val = cpu_get_tsc(env); |
1866 |
EAX = val; |
|
1867 |
EDX = val >> 32; |
|
2179 |
EAX = (uint32_t)(val); |
|
2180 |
EDX = (uint32_t)(val >> 32); |
|
2181 |
} |
|
2182 |
|
|
2183 |
#if defined(CONFIG_USER_ONLY) |
|
2184 |
void helper_wrmsr(void) |
|
2185 |
{ |
|
1868 | 2186 |
} |
1869 | 2187 |
|
2188 |
void helper_rdmsr(void) |
|
2189 |
{ |
|
2190 |
} |
|
2191 |
#else |
|
1870 | 2192 |
void helper_wrmsr(void) |
1871 | 2193 |
{ |
1872 |
switch(ECX) { |
|
2194 |
uint64_t val; |
|
2195 |
|
|
2196 |
val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); |
|
2197 |
|
|
2198 |
switch((uint32_t)ECX) { |
|
1873 | 2199 |
case MSR_IA32_SYSENTER_CS: |
1874 |
env->sysenter_cs = EAX & 0xffff;
|
|
2200 |
env->sysenter_cs = val & 0xffff;
|
|
1875 | 2201 |
break; |
1876 | 2202 |
case MSR_IA32_SYSENTER_ESP: |
1877 |
env->sysenter_esp = EAX;
|
|
2203 |
env->sysenter_esp = val;
|
|
1878 | 2204 |
break; |
1879 | 2205 |
case MSR_IA32_SYSENTER_EIP: |
1880 |
env->sysenter_eip = EAX; |
|
2206 |
env->sysenter_eip = val; |
|
2207 |
break; |
|
2208 |
case MSR_IA32_APICBASE: |
|
2209 |
cpu_set_apic_base(env, val); |
|
2210 |
break; |
|
2211 |
#ifdef TARGET_X86_64 |
|
2212 |
case MSR_EFER: |
|
2213 |
#define MSR_EFER_UPDATE_MASK (MSR_EFER_SCE | MSR_EFER_LME | \ |
|
2214 |
MSR_EFER_NXE | MSR_EFER_FFXSR) |
|
2215 |
env->efer = (env->efer & ~MSR_EFER_UPDATE_MASK) | |
|
2216 |
(val & MSR_EFER_UPDATE_MASK); |
|
1881 | 2217 |
break; |
2218 |
case MSR_STAR: |
|
2219 |
env->star = val; |
|
2220 |
break; |
|
2221 |
case MSR_LSTAR: |
|
2222 |
env->lstar = val; |
|
2223 |
break; |
|
2224 |
case MSR_CSTAR: |
|
2225 |
env->cstar = val; |
|
2226 |
break; |
|
2227 |
case MSR_FMASK: |
|
2228 |
env->fmask = val; |
|
2229 |
break; |
|
2230 |
case MSR_FSBASE: |
|
2231 |
env->segs[R_FS].base = val; |
|
2232 |
break; |
|
2233 |
case MSR_GSBASE: |
|
2234 |
env->segs[R_GS].base = val; |
|
2235 |
break; |
|
2236 |
case MSR_KERNELGSBASE: |
|
2237 |
env->kernelgsbase = val; |
|
2238 |
break; |
|
2239 |
#endif |
|
1882 | 2240 |
default: |
1883 | 2241 |
/* XXX: exception ? */ |
1884 | 2242 |
break; |
... | ... | |
1887 | 2245 |
|
1888 | 2246 |
void helper_rdmsr(void) |
1889 | 2247 |
{ |
1890 |
switch(ECX) { |
|
2248 |
uint64_t val; |
|
2249 |
switch((uint32_t)ECX) { |
|
1891 | 2250 |
case MSR_IA32_SYSENTER_CS: |
1892 |
EAX = env->sysenter_cs; |
|
1893 |
EDX = 0; |
|
2251 |
val = env->sysenter_cs; |
|
1894 | 2252 |
break; |
1895 | 2253 |
case MSR_IA32_SYSENTER_ESP: |
1896 |
EAX = env->sysenter_esp; |
|
1897 |
EDX = 0; |
|
2254 |
val = env->sysenter_esp; |
|
1898 | 2255 |
break; |
1899 | 2256 |
case MSR_IA32_SYSENTER_EIP: |
1900 |
EAX = env->sysenter_eip; |
|
1901 |
EDX = 0; |
|
2257 |
val = env->sysenter_eip; |
|
2258 |
break; |
|
2259 |
case MSR_IA32_APICBASE: |
|
2260 |
val = cpu_get_apic_base(env); |
|
2261 |
break; |
|
2262 |
#ifdef TARGET_X86_64 |
|
2263 |
case MSR_EFER: |
|
2264 |
val = env->efer; |
|
2265 |
break; |
|
2266 |
case MSR_STAR: |
|
2267 |
val = env->star; |
|
2268 |
break; |
|
2269 |
case MSR_LSTAR: |
|
2270 |
val = env->lstar; |
|
2271 |
break; |
|
2272 |
case MSR_CSTAR: |
|
2273 |
val = env->cstar; |
|
2274 |
break; |
|
2275 |
case MSR_FMASK: |
|
2276 |
val = env->fmask; |
|
2277 |
break; |
|
2278 |
case MSR_FSBASE: |
|
2279 |
val = env->segs[R_FS].base; |
|
2280 |
break; |
|
2281 |
case MSR_GSBASE: |
|
2282 |
val = env->segs[R_GS].base; |
|
1902 | 2283 |
break; |
2284 |
case MSR_KERNELGSBASE: |
|
2285 |
val = env->kernelgsbase; |
|
2286 |
break; |
|
2287 |
#endif |
|
1903 | 2288 |
default: |
1904 | 2289 |
/* XXX: exception ? */ |
2290 |
val = 0; |
|
1905 | 2291 |
break; |
1906 | 2292 |
} |
2293 |
EAX = (uint32_t)(val); |
|
2294 |
EDX = (uint32_t)(val >> 32); |
|
1907 | 2295 |
} |
2296 |
#endif |
|
1908 | 2297 |
|
1909 | 2298 |
void helper_lsl(void) |
1910 | 2299 |
{ |
... | ... | |
2055 | 2444 |
{ |
2056 | 2445 |
int new_fpstt; |
2057 | 2446 |
new_fpstt = (env->fpstt - 1) & 7; |
2058 |
env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0);
|
|
2447 |
env->fpregs[new_fpstt] = helper_fldt(A0); |
|
2059 | 2448 |
env->fpstt = new_fpstt; |
2060 | 2449 |
env->fptags[new_fpstt] = 0; /* validate stack entry */ |
2061 | 2450 |
} |
2062 | 2451 |
|
2063 | 2452 |
void helper_fstt_ST0_A0(void) |
2064 | 2453 |
{ |
2065 |
helper_fstt(ST0, (uint8_t *)A0);
|
|
2454 |
helper_fstt(ST0, A0); |
|
2066 | 2455 |
} |
2067 | 2456 |
|
2068 | 2457 |
void fpu_set_exception(int mask) |
... | ... | |
2102 | 2491 |
|
2103 | 2492 |
val = 0; |
2104 | 2493 |
for(i = 8; i >= 0; i--) { |
2105 |
v = ldub((uint8_t *)A0 + i);
|
|
2494 |
v = ldub(A0 + i); |
|
2106 | 2495 |
val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); |
2107 | 2496 |
} |
2108 | 2497 |
tmp = val; |
2109 |
if (ldub((uint8_t *)A0 + 9) & 0x80)
|
|
2498 |
if (ldub(A0 + 9) & 0x80) |
|
2110 | 2499 |
tmp = -tmp; |
2111 | 2500 |
fpush(); |
2112 | 2501 |
ST0 = tmp; |
... | ... | |
2116 | 2505 |
{ |
2117 | 2506 |
CPU86_LDouble tmp; |
2118 | 2507 |
int v; |
2119 |
uint8_t *mem_ref, *mem_end;
|
|
2508 |
target_ulong mem_ref, mem_end;
|
|
2120 | 2509 |
int64_t val; |
2121 | 2510 |
|
2122 | 2511 |
tmp = rint(ST0); |
2123 | 2512 |
val = (int64_t)tmp; |
2124 |
mem_ref = (uint8_t *)A0;
|
|
2513 |
mem_ref = A0; |
|
2125 | 2514 |
mem_end = mem_ref + 9; |
2126 | 2515 |
if (val < 0) { |
2127 | 2516 |
stb(mem_end, 0x80); |
... | ... | |
2402 | 2791 |
} |
2403 | 2792 |
} |
2404 | 2793 |
|
2405 |
void helper_fstenv(uint8_t *ptr, int data32)
|
|
2794 |
void helper_fstenv(target_ulong ptr, int data32)
|
|
2406 | 2795 |
{ |
2407 | 2796 |
int fpus, fptag, exp, i; |
2408 | 2797 |
uint64_t mant; |
... | ... | |
2452 | 2841 |
} |
2453 | 2842 |
} |
2454 | 2843 |
|
2455 |
void helper_fldenv(uint8_t *ptr, int data32)
|
|
2844 |
void helper_fldenv(target_ulong ptr, int data32)
|
|
2456 | 2845 |
{ |
2457 | 2846 |
int i, fpus, fptag; |
2458 | 2847 |
|
... | ... | |
2474 | 2863 |
} |
2475 | 2864 |
} |
2476 | 2865 |
|
2477 |
void helper_fsave(uint8_t *ptr, int data32)
|
|
2866 |
void helper_fsave(target_ulong ptr, int data32)
|
|
2478 | 2867 |
{ |
2479 | 2868 |
CPU86_LDouble tmp; |
2480 | 2869 |
int i; |
... | ... | |
2502 | 2891 |
env->fptags[7] = 1; |
2503 | 2892 |
} |
2504 | 2893 |
|
2505 |
void helper_frstor(uint8_t *ptr, int data32)
|
|
2894 |
void helper_frstor(target_ulong ptr, int data32)
|
|
2506 | 2895 |
{ |
2507 | 2896 |
CPU86_LDouble tmp; |
2508 | 2897 |
int i; |
... | ... | |
2517 | 2906 |
} |
2518 | 2907 |
} |
2519 | 2908 |
|
2520 |
/* XXX: merge with helper_fstt ? */ |
|
2909 |
void helper_fxsave(target_ulong ptr, int data64) |
|
2910 |
{ |
|
2911 |
int fpus, fptag, i, nb_xmm_regs; |
|
2912 |
CPU86_LDouble tmp; |
|
2913 |
target_ulong addr; |
|
2914 |
|
|
2915 |
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; |
|
2916 |
fptag = 0; |
|
2917 |
for(i = 0; i < 8; i++) { |
|
2918 |
fptag |= ((!env->fptags[(env->fpstt + i) & 7]) << i); |
|
2919 |
} |
|
2920 |
stw(ptr, env->fpuc); |
|
2921 |
stw(ptr + 2, fpus); |
|
2922 |
stw(ptr + 4, fptag); |
|
2923 |
|
|
2924 |
addr = ptr + 0x20; |
|
2925 |
for(i = 0;i < 8; i++) { |
|
2926 |
tmp = ST(i); |
|
2927 |
helper_fstt(tmp, addr); |
|
2928 |
addr += 16; |
|
2929 |
} |
|
2930 |
|
|
2931 |
if (env->cr[4] & CR4_OSFXSR_MASK) { |
|
2932 |
/* XXX: finish it, endianness */ |
|
2933 |
stl(ptr + 0x18, 0); /* mxcsr */ |
|
2934 |
stl(ptr + 0x1c, 0); /* mxcsr_mask */ |
|
2935 |
nb_xmm_regs = 8 << data64; |
|
2936 |
addr = ptr + 0xa0; |
|
2937 |
for(i = 0; i < nb_xmm_regs; i++) { |
|
2938 |
stq(addr, env->xmm_regs[i].u.q[0]); |
|
2939 |
stq(addr, env->xmm_regs[i].u.q[1]); |
|
2940 |
addr += 16; |
|
2941 |
} |
|
2942 |
} |
|
2943 |
} |
|
2944 |
|
|
2945 |
void helper_fxrstor(target_ulong ptr, int data64) |
|
2946 |
{ |
|
2947 |
int i, fpus, fptag, nb_xmm_regs; |
|
2948 |
CPU86_LDouble tmp; |
|
2949 |
target_ulong addr; |
|
2950 |
|
|
2951 |
env->fpuc = lduw(ptr); |
|
2952 |
fpus = lduw(ptr + 2); |
|
2953 |
fptag = ldub(ptr + 4); |
|
2954 |
env->fpstt = (fpus >> 11) & 7; |
|
2955 |
env->fpus = fpus & ~0x3800; |
|
2956 |
fptag ^= 0xff; |
|
2957 |
for(i = 0;i < 8; i++) { |
|
2958 |
env->fptags[(env->fpstt + i) & 7] = ((fptag >> i) & 1); |
|
2959 |
} |
|
2960 |
|
|
2961 |
addr = ptr + 0x20; |
|
2962 |
for(i = 0;i < 8; i++) { |
|
2963 |
tmp = helper_fldt(addr); |
|
2964 |
ST(i) = tmp; |
|
2965 |
addr += 16; |
|
2966 |
} |
|
2967 |
|
|
2968 |
if (env->cr[4] & CR4_OSFXSR_MASK) { |
|
2969 |
/* XXX: finish it, endianness */ |
|
2970 |
//ldl(ptr + 0x18); |
|
2971 |
//ldl(ptr + 0x1c); |
|
2972 |
nb_xmm_regs = 8 << data64; |
|
2973 |
addr = ptr + 0xa0; |
|
2974 |
for(i = 0; i < nb_xmm_regs; i++) { |
|
2975 |
env->xmm_regs[i].u.q[0] = ldq(addr); |
|
2976 |
env->xmm_regs[i].u.q[1] = ldq(addr); |
|
2977 |
addr += 16; |
|
2978 |
} |
|
2979 |
} |
|
2980 |
} |
|
2521 | 2981 |
|
2522 | 2982 |
#ifndef USE_X86LDOUBLE |
2523 | 2983 |
|
... | ... | |
2575 | 3035 |
} |
2576 | 3036 |
#endif |
2577 | 3037 |
|
3038 |
#ifdef TARGET_X86_64 |
|
3039 |
|
|
3040 |
//#define DEBUG_MULDIV |
|
3041 |
|
|
3042 |
static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) |
|
3043 |
{ |
|
3044 |
*plow += a; |
|
3045 |
/* carry test */ |
|
3046 |
if (*plow < a) |
|
3047 |
(*phigh)++; |
|
3048 |
*phigh += b; |
|
3049 |
} |
|
3050 |
|
|
3051 |
static void neg128(uint64_t *plow, uint64_t *phigh) |
|
3052 |
{ |
|
3053 |
*plow = ~ *plow; |
|
3054 |
*phigh = ~ *phigh; |
|
3055 |
add128(plow, phigh, 1, 0); |
|
3056 |
} |
|
3057 |
|
|
3058 |
static void mul64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) |
|
3059 |
{ |
|
3060 |
uint32_t a0, a1, b0, b1; |
|
3061 |
uint64_t v; |
|
3062 |
|
|
3063 |
a0 = a; |
|
3064 |
a1 = a >> 32; |
|
3065 |
|
|
3066 |
b0 = b; |
|
3067 |
b1 = b >> 32; |
|
3068 |
|
|
3069 |
v = (uint64_t)a0 * (uint64_t)b0; |
|
3070 |
*plow = v; |
|
3071 |
*phigh = 0; |
|
3072 |
|
|
3073 |
v = (uint64_t)a0 * (uint64_t)b1; |
|
3074 |
add128(plow, phigh, v << 32, v >> 32); |
|
3075 |
|
|
3076 |
v = (uint64_t)a1 * (uint64_t)b0; |
|
3077 |
add128(plow, phigh, v << 32, v >> 32); |
|
3078 |
|
|
3079 |
v = (uint64_t)a1 * (uint64_t)b1; |
|
3080 |
*phigh += v; |
|
3081 |
#ifdef DEBUG_MULDIV |
|
3082 |
printf("mul: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", |
|
3083 |
a, b, *phigh, *plow); |
|
3084 |
#endif |
|
3085 |
} |
|
3086 |
|
|
3087 |
static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) |
|
3088 |
{ |
|
3089 |
int sa, sb; |
|
3090 |
sa = (a < 0); |
|
3091 |
if (sa) |
|
3092 |
a = -a; |
|
3093 |
sb = (b < 0); |
|
3094 |
if (sb) |
|
3095 |
b = -b; |
|
3096 |
mul64(plow, phigh, a, b); |
|
3097 |
if (sa ^ sb) { |
|
3098 |
neg128(plow, phigh); |
|
3099 |
} |
|
3100 |
} |
|
3101 |
|
|
3102 |
static void div64(uint64_t *plow, uint64_t *phigh, uint64_t b) |
|
3103 |
{ |
|
3104 |
uint64_t q, r, a1, a0; |
|
3105 |
int i, qb; |
|
3106 |
|
|
3107 |
a0 = *plow; |
|
3108 |
a1 = *phigh; |
|
3109 |
if (a1 == 0) { |
|
3110 |
q = a0 / b; |
|
3111 |
r = a0 % b; |
|
3112 |
*plow = q; |
|
3113 |
*phigh = r; |
|
3114 |
} else { |
|
3115 |
/* XXX: use a better algorithm */ |
|
3116 |
for(i = 0; i < 64; i++) { |
|
3117 |
if (a1 >= b) { |
|
3118 |
a1 -= b; |
|
3119 |
qb = 1; |
|
3120 |
} else { |
|
3121 |
qb = 0; |
|
3122 |
} |
|
3123 |
a1 = (a1 << 1) | (a0 >> 63); |
|
3124 |
a0 = (a0 << 1) | qb; |
|
3125 |
} |
|
3126 |
#if defined(DEBUG_MULDIV) || 1 |
|
3127 |
printf("div: 0x%016llx%016llx / 0x%016llx: q=0x%016llx r=0x%016llx\n", |
|
3128 |
*phigh, *plow, b, a0, a1); |
|
3129 |
#endif |
|
3130 |
*plow = a0; |
|
3131 |
*phigh = a1; |
|
3132 |
} |
|
3133 |
} |
|
3134 |
|
|
3135 |
static void idiv64(uint64_t *plow, uint64_t *phigh, uint64_t b) |
|
3136 |
{ |
|
3137 |
int sa, sb; |
|
3138 |
sa = ((int64_t)*phigh < 0); |
|
3139 |
if (sa) |
|
3140 |
neg128(plow, phigh); |
|
3141 |
sb = (b < 0); |
|
3142 |
if (sb) |
|
3143 |
b = -b; |
|
3144 |
div64(plow, phigh, b); |
|
3145 |
if (sa ^ sb) |
|
3146 |
*plow = - *plow; |
|
3147 |
if (sb) |
|
3148 |
*phigh = - *phigh; |
|
3149 |
} |
|
3150 |
|
|
3151 |
void helper_mulq_EAX_T0(void) |
|
3152 |
{ |
|
3153 |
uint64_t r0, r1; |
|
3154 |
|
|
3155 |
mul64(&r0, &r1, EAX, T0); |
|
3156 |
EAX = r0; |
|
3157 |
EDX = r1; |
|
3158 |
CC_DST = r0; |
|
3159 |
CC_SRC = r1; |
|
3160 |
} |
|
3161 |
|
|
3162 |
void helper_imulq_EAX_T0(void) |
|
3163 |
{ |
|
3164 |
uint64_t r0, r1; |
|
3165 |
|
|
3166 |
imul64(&r0, &r1, EAX, T0); |
|
3167 |
EAX = r0; |
|
3168 |
EDX = r1; |
|
3169 |
CC_DST = r0; |
|
3170 |
CC_SRC = (r1 != (r0 >> 63)); |
|
3171 |
} |
|
3172 |
|
|
3173 |
void helper_imulq_T0_T1(void) |
|
3174 |
{ |
|
3175 |
uint64_t r0, r1; |
|
3176 |
|
|
3177 |
imul64(&r0, &r1, T0, T1); |
|
3178 |
T0 = r0; |
|
3179 |
CC_DST = r0; |
|
3180 |
CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); |
|
3181 |
} |
|
3182 |
|
|
3183 |
void helper_divq_EAX_T0(void) |
|
3184 |
{ |
|
3185 |
uint64_t r0, r1; |
|
3186 |
if (T0 == 0) { |
|
3187 |
raise_exception(EXCP00_DIVZ); |
|
3188 |
} |
|
3189 |
r0 = EAX; |
|
3190 |
r1 = EDX; |
|
3191 |
div64(&r0, &r1, T0); |
|
3192 |
EAX = r0; |
|
3193 |
EDX = r1; |
|
3194 |
} |
|
3195 |
|
|
3196 |
void helper_idivq_EAX_T0(void) |
|
3197 |
{ |
|
3198 |
uint64_t r0, r1; |
|
3199 |
if (T0 == 0) { |
|
3200 |
raise_exception(EXCP00_DIVZ); |
|
3201 |
} |
Also available in: Unified diff