63 |
#define ACC_DATA_EW 0x16 /* data, expand-down, |
#define ACC_DATA_EW 0x16 /* data, expand-down, |
64 |
writable */ |
writable */ |
65 |
|
|
66 |
|
#define ACC_TYPE_SYSTEM 0x0f |
67 |
#define ACC_LDT 0x02 /* LDT */ |
#define ACC_LDT 0x02 /* LDT */ |
68 |
#define ACC_CALL_GATE_16 0x04 /* 16-bit call gate */ |
#define ACC_CALL_GATE_16 0x04 /* 16-bit call gate */ |
69 |
#define ACC_TASK_GATE 0x05 /* task gate */ |
#define ACC_TASK_GATE 0x05 /* task gate */ |
70 |
#define ACC_INTR_GATE_16 0x06 |
#define ACC_INTR_GATE_16 0x06 |
71 |
#define ACC_TRAP_GATE_16 0x07 |
#define ACC_TRAP_GATE_16 0x07 |
72 |
#define ACC_TSS 0x09 /* task segment */ |
#define ACC_TSS 0x09 /* task segment */ |
73 |
|
#define ACC_TSS_16 0x01 |
74 |
#define ACC_CALL_GATE 0x0c /* call gate */ |
#define ACC_CALL_GATE 0x0c /* call gate */ |
75 |
#define ACC_INTR_GATE 0x0e /* interrupt gate */ |
#define ACC_INTR_GATE 0x0e /* interrupt gate */ |
76 |
#define ACC_TRAP_GATE 0x0f /* trap gate */ |
#define ACC_TRAP_GATE 0x0f /* trap gate */ |
179 |
us->limit = sd->limit_low | sd->limit_high << 16; |
us->limit = sd->limit_low | sd->limit_high << 16; |
180 |
if (sd->granularity & 8) |
if (sd->granularity & 8) |
181 |
us->limit = (us->limit << 12) | 0xfff; |
us->limit = (us->limit << 12) | 0xfff; |
|
dprintf ("unpack segment: gran = %x\n", sd->granularity); |
|
182 |
us->is_32bit = (sd->granularity & 4 ? 1 : 0); |
us->is_32bit = (sd->granularity & 4 ? 1 : 0); |
183 |
|
us->flags = sd->access; |
184 |
} |
} |
185 |
|
|
186 |
/* Load segment with SELECTOR. SEGNO is the segment that |
/* Load segment with SELECTOR. SEGNO is the segment that |
258 |
{ |
{ |
259 |
CPU (ldt.base) = 0; |
CPU (ldt.base) = 0; |
260 |
CPU (ldt.limit) = 0; |
CPU (ldt.limit) = 0; |
261 |
|
CPU (ldt.flags) = 0; |
262 |
} |
} |
263 |
else |
else |
264 |
{ |
{ |
285 |
|
|
286 |
if ((selector & 0xfffc) == 0) |
if ((selector & 0xfffc) == 0) |
287 |
{ |
{ |
288 |
CPU (ldt.base) = 0; |
CPU (tr.base) = 0; |
289 |
CPU (ldt.limit) = 0; |
CPU (tr.limit) = 0; |
290 |
|
CPU (tr.flags) = 0; |
291 |
} |
} |
292 |
else |
else |
293 |
{ |
{ |
302 |
CPU (tr.selector) = selector; |
CPU (tr.selector) = selector; |
303 |
} |
} |
304 |
|
|
305 |
|
/* Get stack segment selector and stack pointer for DPL from |
306 |
|
the TSS. Returns nonzero if exception was raised. */ |
307 |
|
|
308 |
|
static int |
309 |
|
get_sp_from_tss (struct processor *current_cpu, UWI *ssp, |
310 |
|
UWI *spp, int dpl) |
311 |
|
{ |
312 |
|
struct unpacked_segment *tr = &CPU (tr); |
313 |
|
ADDR index; |
314 |
|
|
315 |
|
if ((tr->flags & ACC_P) == 0 |
316 |
|
|| (tr->flags & ACC_TYPE_USER) != 0 |
317 |
|
|| ((tr->flags & ACC_TYPE_SYSTEM) != ACC_TSS |
318 |
|
&& (tr->flags & ACC_TYPE_SYSTEM) != ACC_TSS_16)) |
319 |
|
{ |
320 |
|
internal_error (__FILE__, __LINE__, "FIXME: invalid tss"); |
321 |
|
} |
322 |
|
if ((tr->flags & ACC_TYPE_SYSTEM) == ACC_TSS) |
323 |
|
{ |
324 |
|
index = tr->base + (dpl * 8 + 4); |
325 |
|
if ((dpl * 8 + 4) + 8 - 1 > tr->limit) |
326 |
|
{ |
327 |
|
i386_raise_exception (current_cpu, EXC_TS, |
328 |
|
tr->selector & 0xfffc, 0, 0); |
329 |
|
return 1; |
330 |
|
} |
331 |
|
*spp = GETMEMUSI (index); |
332 |
|
*ssp = GETMEMUSI (index + 4) & 0xffff; |
333 |
|
} |
334 |
|
else /* 16-bit */ |
335 |
|
{ |
336 |
|
index = tr->base + (dpl * 4 + 2); |
337 |
|
if ((dpl * 4 + 2) + 4 - 1 > tr->limit) |
338 |
|
{ |
339 |
|
i386_raise_exception (current_cpu, EXC_TS, |
340 |
|
tr->selector & 0xfffc, 0, 0); |
341 |
|
return 1; |
342 |
|
} |
343 |
|
*spp = GETMEMUHI (index); |
344 |
|
*ssp = GETMEMUHI (index + 2); |
345 |
|
} |
346 |
|
return 0; |
347 |
|
} |
348 |
|
|
349 |
|
|
350 |
/* Return full value of the EFLAGS register, for CURRENT_CPU. */ |
/* Return full value of the EFLAGS register, for CURRENT_CPU. */ |
351 |
|
|
352 |
UWI |
UWI |
353 |
i386_compute_eflags (struct processor *current_cpu) |
i386_compute_eflags (struct processor *current_cpu) |
354 |
{ |
{ |
355 |
return (CPU (hw_eflags) | cctable[CPU (cc_op)].compute_all () |
return (CPU (hw_eflags) |
356 |
|
| (cctable[CPU (cc_op)].compute_all () & EFL_CC) |
357 |
| (CPU (hw_dflag) & EFL_DF)); |
| (CPU (hw_dflag) & EFL_DF)); |
358 |
} |
} |
359 |
|
|
530 |
CPU (hw_cr[3]) = value; |
CPU (hw_cr[3]) = value; |
531 |
CPU (pgdir) = core_address_from_physical_address (CPU_NODE (current_cpu), |
CPU (pgdir) = core_address_from_physical_address (CPU_NODE (current_cpu), |
532 |
value & ~0xfff); |
value & ~0xfff); |
533 |
|
mtcache_flush_all (&mtcache_data_read); |
534 |
|
mtcache_flush_all (&mtcache_data_write); |
535 |
} |
} |
536 |
|
|
537 |
void |
void |
658 |
i386_protected_mode_ret (struct processor *current_cpu, |
i386_protected_mode_ret (struct processor *current_cpu, |
659 |
int dflag, int is_iret, int addend) |
int dflag, int is_iret, int addend) |
660 |
{ |
{ |
661 |
struct i386_segment_desc sd; |
struct i386_segment_desc sd, stackd; |
662 |
UWI new_eflags = 0, new_cs; |
UWI new_eflags = 0, new_cs, new_ss; |
663 |
int cpl, rpl; |
int cpl, rpl; |
664 |
ADDR sp, stackp, new_sp = 0; |
ADDR sp, stackp, new_sp = 0; |
665 |
IADDR new_pc; |
IADDR new_pc; |
669 |
sp &= 0xffff; |
sp &= 0xffff; |
670 |
stackp = CPU (segs[ss_regno].base) + sp; |
stackp = CPU (segs[ss_regno].base) + sp; |
671 |
|
|
|
|
|
672 |
if (dflag) |
if (dflag) |
673 |
{ |
{ |
674 |
if (is_iret) |
if (is_iret) |
686 |
new_pc = GETMEMUHI (stackp); |
new_pc = GETMEMUHI (stackp); |
687 |
} |
} |
688 |
|
|
689 |
|
/* FIXME nt flag */ |
690 |
|
|
691 |
if ((new_cs & 0xfffc) == 0 |
if ((new_cs & 0xfffc) == 0 |
692 |
|| fetch_segment (current_cpu, NULL, new_cs, &sd) |
|| fetch_segment (current_cpu, NULL, new_cs, &sd) |
693 |
|| (sd.access & ACC_P) == 0 |
|| (sd.access & ACC_P) == 0 |
707 |
} |
} |
708 |
else |
else |
709 |
{ |
{ |
710 |
ABORT (); |
/* Return to a different priviledge level */ |
711 |
|
|
712 |
|
if (dflag) |
713 |
|
{ |
714 |
|
stackp += 8 + addend; |
715 |
|
if (is_iret) |
716 |
|
stackp += 4; |
717 |
|
} |
718 |
|
else |
719 |
|
{ |
720 |
|
stackp += 4 + addend; |
721 |
|
if (is_iret) |
722 |
|
stackp += 2; |
723 |
|
} |
724 |
|
if (dflag) |
725 |
|
{ |
726 |
|
new_ss = GETMEMUSI (stackp + 4) & 0xffff; |
727 |
|
new_sp = GETMEMUSI (stackp); |
728 |
|
} |
729 |
|
else |
730 |
|
{ |
731 |
|
new_ss = GETMEMUHI (stackp + 2); |
732 |
|
new_sp = GETMEMUHI (stackp); |
733 |
|
} |
734 |
|
|
735 |
|
if (new_ss == 0 |
736 |
|
/* If stack segment RPL isn't the same as RPL */ |
737 |
|
|| ((new_ss & 3) != rpl) |
738 |
|
/* If stack segment selector is not within limits */ |
739 |
|
|| fetch_segment (current_cpu, NULL, new_ss, &stackd) |
740 |
|
/* The stack segment must be present */ |
741 |
|
|| ((stackd.access & ACC_P) == 0) |
742 |
|
/* If stack segment DPL isn't the same as RPL */ |
743 |
|
|| ((stackd.access >> 5) & 3) != rpl |
744 |
|
/* If stack segment isn't a writeable data segment */ |
745 |
|
|| ((stackd.access & ACC_TYPE) != ACC_DATA_W |
746 |
|
&& (stackd.access & ACC_TYPE) != ACC_DATA_EW)) |
747 |
|
{ |
748 |
|
i386_raise_exception (current_cpu, EXC_GP, new_ss, 0, 0); |
749 |
|
return; |
750 |
|
} |
751 |
|
unpack_segment (&CPU (segs[ss_regno]), &stackd); |
752 |
|
CPU (segs[ss_regno].selector) = new_ss; |
753 |
|
unpack_segment (&CPU (segs[cs_regno]), &sd); |
754 |
|
CPU (segs[cs_regno].selector) = new_cs; |
755 |
|
|
756 |
|
/* Recalculate state since both the code and stack segment |
757 |
|
has been changed. */ |
758 |
|
CPU (state) = i386_get_state (current_cpu); |
759 |
} |
} |
760 |
|
|
761 |
if (CPU (segs[ss_regno].is_32bit)) |
if (CPU (segs[ss_regno].is_32bit)) |
794 |
IADDR next_pc, int is_hw_intr) |
IADDR next_pc, int is_hw_intr) |
795 |
{ |
{ |
796 |
struct i386_callgate_desc sd; |
struct i386_callgate_desc sd; |
797 |
struct i386_segment_desc seg; |
struct i386_segment_desc seg, stackd; |
798 |
int dpl, selector, cpl; |
UWI save_ss, save_cs, new_cs, new_ss, save_sp, new_sp; |
799 |
UWI save_pc, save_cs, save_eflags; |
int with_error = 0, new_stack; |
800 |
int has_error_code, new_stack, push_size, not_16bit; |
ADDR stackp, save_pc; |
801 |
ADDR stackp, sp; |
int dpl, cpl; |
802 |
|
|
803 |
|
/* FIXME these are here to shut up the compiler */ |
804 |
|
save_ss = 0; |
805 |
|
save_sp = 0; |
806 |
|
new_stack = 0; |
807 |
|
|
808 |
|
/* Put the processor in pseudo-supervisor mode, since we need |
809 |
|
to access supervisor-only available data structures such as |
810 |
|
the TSS, GDT and LDT. */ |
811 |
|
|
812 |
|
CPU (pseudo_supervisor_p) = 1; |
813 |
|
|
814 |
/* If the number of unresolved exceptions equals three, |
/* If the number of unresolved exceptions equals three, |
815 |
take a trippe-fault. FIXME. */ |
take a trippe-fault. FIXME. */ |
|
|
|
816 |
if (CPU (unresolved_exceptions)++ == 3) |
if (CPU (unresolved_exceptions)++ == 3) |
817 |
{ |
{ |
818 |
ABORT (); |
ABORT (); |
819 |
} |
} |
820 |
|
|
821 |
|
/* If (intno * 8) + 7 is not within the IDT limits, take |
822 |
|
general protection fault with the IDT bit set. */ |
823 |
if (fetch_callgate (current_cpu, & CPU (idt), intno*8, &sd)) |
if (fetch_callgate (current_cpu, & CPU (idt), intno*8, &sd)) |
824 |
{ |
{ |
825 |
|
take_gpf: |
826 |
i386_raise_exception (current_cpu, EXC_GP, (intno * 8) + 2, 0, 0); |
i386_raise_exception (current_cpu, EXC_GP, (intno * 8) + 2, 0, 0); |
827 |
return; |
return; |
828 |
} |
} |
829 |
|
|
830 |
|
/* If the selected IDT descriptor is not a interrupt-, trap-, or |
831 |
|
task-gate take general protection fault. */ |
832 |
|
|
833 |
switch (sd.access & ACC_TYPE) |
switch (sd.access & ACC_TYPE) |
834 |
{ |
{ |
835 |
case ACC_TASK_GATE: |
case ACC_TASK_GATE: |
836 |
|
/* FIXME jrydberg: implement task gates */ |
837 |
internal_abort (__FILE__, __LINE__, "task gate not supported"); |
internal_abort (__FILE__, __LINE__, "task gate not supported"); |
838 |
case ACC_INTR_GATE_16: |
case ACC_INTR_GATE_16: |
839 |
case ACC_INTR_GATE: |
case ACC_INTR_GATE: |
841 |
case ACC_TRAP_GATE: |
case ACC_TRAP_GATE: |
842 |
break; |
break; |
843 |
default: |
default: |
844 |
i386_raise_exception (current_cpu, EXC_GP, (intno * 8) + 2, 0, 0); |
goto take_gpf; |
|
return; |
|
845 |
} |
} |
846 |
|
|
847 |
|
/* Values that should be saved in the interrupt frame. */ |
848 |
|
save_cs = CPU (segs[cs_regno].selector); |
849 |
|
save_pc = (is_intr ? next_pc : HW_PC_GET (current_cpu)); |
850 |
|
|
851 |
|
/* ??? DPL */ |
852 |
|
|
853 |
dpl = (sd.access >> 5) & 3; |
dpl = (sd.access >> 5) & 3; |
854 |
cpl = /* ??? */ CPU (segs[cs_regno].selector) & 3; |
cpl = /* ??? */ CPU (segs[cs_regno].selector) & 3; |
855 |
|
|
856 |
if (is_intr && dpl < cpl /* check priviledge */ |
/* If the interrupt is generated by a software action (int N, into, int 3) |
857 |
|| !(sd.access & 0x80)) /* present */ |
then take GP exception if DPL is less than CPL. */ |
858 |
|
if (is_intr && is_hw_intr == 0 && dpl < cpl) |
859 |
{ |
{ |
|
printf ("sd.access = %x\n", sd.access); |
|
860 |
i386_raise_exception (current_cpu, EXC_GP, (intno * 8) + 2, 0, 0); |
i386_raise_exception (current_cpu, EXC_GP, (intno * 8) + 2, 0, 0); |
861 |
return; |
return; |
862 |
} |
} |
863 |
if ((sd.selector & 0xfffc) == 0) |
|
864 |
|
/* If gate is not present, take NP exception. */ |
865 |
|
if ((sd.access & ACC_P) == 0) |
866 |
{ |
{ |
867 |
i386_raise_exception (current_cpu, EXC_GP, 0, 0, 0); |
i386_raise_exception (current_cpu, EXC_NP, (intno * 8) + 2, 0, 0); |
868 |
return; |
return; |
869 |
} |
} |
870 |
if (fetch_segment (current_cpu, NULL, sd.selector, &seg) |
new_cs = sd.selector; |
871 |
#if 0 |
|
872 |
|| !(seg.access & (1 << 12)) |
/* Read segment selector for trap or interrupt gate. |
873 |
|| !(seg.access & (1 << 11)) |
If segment selector for code segment is null, take GP */ |
874 |
#endif |
if ((new_cs & 0xfffc) == 0) |
|
|| (dpl = (seg.access >> 5) & 3) > cpl |
|
|
|| !(seg.access & ACC_P)) |
|
875 |
{ |
{ |
876 |
i386_raise_exception (current_cpu, EXC_GP, sd.selector & 0xfffc, 0, 0); |
i386_raise_exception (current_cpu, EXC_GP, 0, 0, 0); |
877 |
return; |
return; |
878 |
} |
} |
879 |
if (dpl < cpl) /* to inner */ |
|
880 |
{ |
/* If selector is outside limits, or if segment is not a code |
881 |
new_stack = 0; |
segment, take a general protectin fault. */ |
882 |
/* get ss_esp from tss */ |
if (fetch_segment (current_cpu, NULL, new_cs, &seg) |
883 |
ABORT (); |
|| ((seg.access & ACC_TYPE) != ACC_CODE |
884 |
} |
&& (seg.access & ACC_TYPE) != ACC_CODE_R |
885 |
else if (seg.access & (1 << 12) || dpl == cpl) |
&& (seg.access & ACC_TYPE) != ACC_CODE_C |
886 |
|
&& (seg.access & ACC_TYPE) != ACC_CODE_CR)) |
887 |
{ |
{ |
888 |
new_stack = 0; |
/* FIXME is this the correct selector ? */ |
889 |
|
i386_raise_exception (current_cpu, EXC_GP, new_cs & 0xfffc, 0, 0); |
890 |
|
return; |
891 |
} |
} |
892 |
else |
/* If segment is not present, take NP exception */ |
893 |
|
if ((seg.access & ACC_P) == 0) |
894 |
{ |
{ |
895 |
i386_raise_exception (current_cpu, EXC_GP, sd.selector & 0xfffc, 0, 0); |
/* FIXME is this the correct selector ? */ |
896 |
|
i386_raise_exception (current_cpu, EXC_NP, new_cs & 0xfffc, 0, 0); |
897 |
return; |
return; |
898 |
} |
} |
899 |
|
|
900 |
not_16bit = (sd.access & 0x1f) >> 3; |
dpl = (seg.access >> 5) & 3; |
901 |
|
|
902 |
|
/* If the code segment is non-conforming and the DPL is |
903 |
|
less than the CPL it can be a inter-priviledge level interrupt */ |
904 |
|
|
905 |
|
if (((seg.access & ACC_TYPE) == ACC_CODE |
906 |
|
|| (seg.access & ACC_TYPE) == ACC_CODE_R) |
907 |
|
&& dpl < cpl) |
908 |
|
{ |
909 |
|
if ((CPU (hw_eflags) & EFL_VM) == 0) |
910 |
|
{ |
911 |
|
/* inter-privilege level interrupt */ |
912 |
|
|
913 |
|
/* The call to get_sp_from_tss checks so that TSS stack |
914 |
|
address is within the TSS limits. */ |
915 |
|
if (get_sp_from_tss (current_cpu, &new_ss, &new_sp, dpl)) |
916 |
|
return; |
917 |
|
if ((new_ss & 0xfffc) == 0) |
918 |
|
{ |
919 |
|
i386_raise_exception (current_cpu, EXC_TS, 0, 0, 0); |
920 |
|
return; |
921 |
|
} |
922 |
|
if ((new_ss & 3) != dpl |
923 |
|
/* Check that new_ss is within table limits */ |
924 |
|
|| fetch_segment (current_cpu, NULL, new_ss, &stackd) |
925 |
|
/* Stack segment DPL must be same as DPL of code segment */ |
926 |
|
|| (stackd.access >> 5) & 3 != dpl |
927 |
|
/* Stack segment must be present */ |
928 |
|
|| (stackd.access & ACC_P) == 0) |
929 |
|
/* FIXME must also check that the segment has room for |
930 |
|
interrupt frame */ |
931 |
|
{ |
932 |
|
i386_raise_exception (current_cpu, EXC_TS, new_ss & 0xfffc, 0, 0); |
933 |
|
return; |
934 |
|
} |
935 |
|
|
936 |
|
/* Save the values of the stack pointer and stack selector |
937 |
|
on the new stack. */ |
938 |
|
save_sp = CPU (hw_gpr[esp_regno]); |
939 |
|
save_ss = CPU (segs[ss_regno].selector); |
940 |
|
new_stack = 1; |
941 |
|
} |
942 |
|
else |
943 |
|
{ |
944 |
|
if (dpl != 0) |
945 |
|
{ |
946 |
|
i386_raise_exception (current_cpu, EXC_GP, |
947 |
|
new_cs & 0xfffc, 0, 0); |
948 |
|
return; |
949 |
|
} |
950 |
|
internal_error (__FILE__, __LINE__, "intr vm86 not supp"); |
951 |
|
} |
952 |
|
} |
953 |
|
else /* dpl >= cpl */ |
954 |
|
{ |
955 |
|
if (CPU (hw_eflags) & EFL_VM) |
956 |
|
{ |
957 |
|
i386_raise_exception (current_cpu, EXC_GP, |
958 |
|
new_cs & 0xfffc, 0, 0); |
959 |
|
return; |
960 |
|
} |
961 |
|
if (((seg.access & ACC_TYPE) == ACC_CODE_C |
962 |
|
|| (seg.access & ACC_TYPE) == ACC_CODE_CR) |
963 |
|
|| dpl == cpl) |
964 |
|
{ |
965 |
|
/* intra-privilege level interrupt */ |
966 |
|
new_sp = CPU (hw_gpr[esp_regno]); |
967 |
|
new_stack = save_sp = save_ss = 0; |
968 |
|
} |
969 |
|
else |
970 |
|
{ |
971 |
|
i386_raise_exception (current_cpu, EXC_GP, |
972 |
|
new_cs & 0xfffc, 0, 0); |
973 |
|
return; |
974 |
|
} |
975 |
|
} |
976 |
|
|
977 |
has_error_code = 0; |
/* Pushing error code on the stack is only needed if the |
978 |
if (!is_intr && !is_hw_intr) |
interrupt is an exception (!is_intr) and the exception number |
979 |
|
is one of 8, 10, 11, 12, 13, 14 or 17. */ |
980 |
|
if (is_intr == 0) |
981 |
{ |
{ |
982 |
switch(intno) |
switch (intno) |
983 |
{ |
{ |
984 |
case 8: case 10: case 11: case 12: |
case 8: case 10: case 11: case 12: |
985 |
case 13: case 14: case 17: |
case 13: case 14: case 17: |
986 |
has_error_code = 1; |
with_error = 1; |
|
break; |
|
987 |
} |
} |
988 |
} |
} |
|
push_size = 6 + (new_stack ? 4 : 0) + (has_error_code ? 2 : 0); |
|
|
#if 0 |
|
|
if (vm86-mode) |
|
|
push_size += 8; |
|
|
#endif |
|
|
if (not_16bit) |
|
|
push_size = push_size << 1; |
|
989 |
|
|
990 |
|
/* It is important to preserve precise exceptions; Therefor the |
991 |
|
stack and code segment is not updated until all the data is |
992 |
|
saved on the stack (every access may case another exception). */ |
993 |
if (new_stack) |
if (new_stack) |
994 |
{ |
{ |
995 |
sp = 0; |
struct unpacked_segment bal; |
996 |
ABORT (); |
unpack_segment (&bal, &stackd); |
997 |
|
stackp = bal.base + new_sp; |
998 |
} |
} |
999 |
else |
else |
1000 |
{ |
{ |
1001 |
/* old_sp = old_ss = 0; */ |
/* FIXME what if stack segment is 16-bit? */ |
1002 |
sp = CPU (hw_gpr[esp_regno]); |
stackp = CPU (segs[ss_regno].base) + new_sp; |
1003 |
} |
} |
|
save_pc = (is_intr ? next_pc : HW_PC_GET (current_cpu)); |
|
|
save_cs = CPU (segs[cs_regno].selector); |
|
1004 |
|
|
1005 |
selector = (sd.selector & ~3) | dpl; |
if ((sd.access & 0x1f) >> 3) |
|
i386_load_segment (current_cpu, cs_regno, selector); |
|
|
/* FIXME set cpl */ |
|
|
|
|
|
CPU (hw_pc) = (sd.offset_high << 16) | sd.offset_low; |
|
|
|
|
|
stackp = CPU (segs[ss_regno].base) + sp; |
|
|
|
|
|
if (not_16bit) |
|
1006 |
{ |
{ |
1007 |
save_eflags = i386_compute_eflags (current_cpu); |
UWI save_eflags = i386_compute_eflags (current_cpu); |
1008 |
|
|
1009 |
|
/* The stack segment selector is just two bytes, but |
1010 |
|
it is padded up to four. */ |
1011 |
if (new_stack) |
if (new_stack) |
1012 |
{ |
{ |
1013 |
ABORT (); |
stackp -= 4; |
1014 |
|
SETMEMUSI (stackp, save_ss); |
1015 |
|
stackp -= 4; |
1016 |
|
SETMEMUSI (stackp, save_sp); |
1017 |
} |
} |
1018 |
stackp -= 4; |
stackp -= 4; |
1019 |
SETMEMUSI (stackp, save_eflags); |
SETMEMUSI (stackp, save_eflags); |
1021 |
SETMEMUSI (stackp, save_cs); |
SETMEMUSI (stackp, save_cs); |
1022 |
stackp -= 4; |
stackp -= 4; |
1023 |
SETMEMUSI (stackp, save_pc); |
SETMEMUSI (stackp, save_pc); |
1024 |
if (has_error_code) |
|
1025 |
|
if (with_error) |
1026 |
{ |
{ |
1027 |
stackp -= 4; |
stackp -= 4; |
1028 |
SETMEMUSI (stackp, error_code); |
SETMEMUSI (stackp, error_code); |
1029 |
} |
} |
1030 |
|
/* Update the stack pointer so that the value is |
1031 |
|
correct when the register is set. */ |
1032 |
|
new_sp = new_sp - 12 - ((new_stack ? 8 : 0) |
1033 |
|
+ (with_error ? 4 : 0)); |
1034 |
} |
} |
1035 |
else |
else |
1036 |
{ |
{ |
1038 |
|
|
1039 |
if (new_stack) |
if (new_stack) |
1040 |
{ |
{ |
1041 |
ABORT (); |
stackp -= 2; |
1042 |
|
SETMEMUHI (stackp, save_ss); |
1043 |
|
stackp -= 2; |
1044 |
|
SETMEMUHI (stackp, save_sp); |
1045 |
} |
} |
1046 |
stackp -= 2; |
stackp -= 2; |
1047 |
SETMEMUHI (stackp, save_eflags); |
SETMEMUHI (stackp, save_eflags); |
1049 |
SETMEMUHI (stackp, save_cs); |
SETMEMUHI (stackp, save_cs); |
1050 |
stackp -= 2; |
stackp -= 2; |
1051 |
SETMEMUHI (stackp, save_pc); |
SETMEMUHI (stackp, save_pc); |
1052 |
if (has_error_code) |
|
1053 |
|
if (with_error) |
1054 |
{ |
{ |
1055 |
stackp -= 2; |
stackp -= 2; |
1056 |
SETMEMUHI (stackp, error_code); |
SETMEMUHI (stackp, error_code); |
1057 |
} |
} |
1058 |
|
/* Update the stack pointer so that the value is |
1059 |
|
correct when the register is set. */ |
1060 |
|
new_sp = new_sp - 6 - ((new_stack ? 4 : 0) |
1061 |
|
+ (with_error ? 2 : 0)); |
1062 |
} |
} |
1063 |
|
|
1064 |
/* FIXME what if 16-bit stack? */ |
if (new_stack) |
1065 |
CPU (hw_gpr[esp_regno]) = (sp - push_size); |
{ |
1066 |
|
unpack_segment (&CPU(segs[ss_regno]), &stackd); |
1067 |
|
CPU (segs[ss_regno].selector) = new_ss; |
1068 |
|
} |
1069 |
|
CPU (hw_gpr[esp_regno]) = new_sp; |
1070 |
|
|
1071 |
|
/* Set new program counter. |
1072 |
|
FIXME jrydberg: is this correct? no difference between |
1073 |
|
16-bit or 32-bit gate here. */ |
1074 |
|
/* FIXME jrydberg: set CPL */ |
1075 |
|
CPU (hw_pc) = (sd.offset_high << 16) | sd.offset_low; |
1076 |
|
|
1077 |
|
unpack_segment (&CPU(segs[cs_regno]), &seg); |
1078 |
|
CPU (segs[cs_regno].selector) = (new_cs & ~3) | dpl; |
1079 |
|
|
1080 |
|
/* FIXME jrydberg: it seems as there is no difference if the |
1081 |
|
stack segment is 16 bits. verify this */ |
1082 |
|
CPU (hw_gpr[esp_regno]) = new_sp; |
1083 |
|
|
1084 |
/* interrupt gate clear IF mask */ |
/* interrupt gate clear IF mask */ |
1085 |
if ((sd.access & 1) == 0) |
if ((sd.access & 1) == 0) |
1086 |
CPU (hw_eflags) &= ~EFL_IF; |
CPU (hw_eflags) &= ~EFL_IF; |
1087 |
CPU (hw_eflags) &= ~(EFL_TF|EFL_VM|EFL_RF|EFL_NT); |
CPU (hw_eflags) &= ~(EFL_TF|EFL_VM|EFL_RF|EFL_NT); |
1088 |
|
|
1089 |
|
/* The code segment has changed (for sure), and maybe also |
1090 |
|
the stack segment; there is need to re-calc the state. */ |
1091 |
|
CPU (state) = i386_get_state (current_cpu); |
1092 |
|
|
1093 |
/* The exception was resolved. No chance of a tripple-fault. */ |
/* The exception was resolved. No chance of a tripple-fault. */ |
1094 |
CPU (unresolved_exceptions) = 0; |
CPU (unresolved_exceptions) = 0; |
1095 |
|
/* Put processor back in normal mode */ |
1096 |
|
CPU (pseudo_supervisor_p) = 0; |
1097 |
} |
} |
1098 |
|
|
1099 |
|
|
1463 |
fprintf (stderr, "T0 = %#x, T1 = %#x, A0 = %#x\n", t0, t1, t2); |
fprintf (stderr, "T0 = %#x, T1 = %#x, A0 = %#x\n", t0, t1, t2); |
1464 |
} |
} |
1465 |
|
|
1466 |
|
/* Read time stamp counter and store result in %eax:%edx */ |
1467 |
|
|
1468 |
|
void |
1469 |
|
i386_rdts (struct processor *current_cpu) |
1470 |
|
{ |
1471 |
|
unsigned long long val = get_cpu_insn_count (current_cpu); |
1472 |
|
CPU (hw_gpr[eax_regno]) = (val & 0xffffffff); |
1473 |
|
CPU (hw_gpr[edx_regno]) = ((val >> 32) & 0xffffffff); |
1474 |
|
} |
1475 |
|
|
1476 |
/* FIXME clean up this code */ |
/* FIXME clean up this code */ |
1477 |
|
|
1478 |
#define CPUID_FP87 (1 << 0) |
#define CPUID_FP87 (1 << 0) |
1515 |
CPU (hw_gpr[ecx_regno]) = 0; |
CPU (hw_gpr[ecx_regno]) = 0; |
1516 |
CPU (hw_gpr[edx_regno]) |
CPU (hw_gpr[edx_regno]) |
1517 |
= (CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR |
= (CPUID_DE | CPUID_PSE | CPUID_TSC | CPUID_MSR |
1518 |
| CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV); |
| CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | CPUID_FP87); |
1519 |
} |
} |
1520 |
} |
} |