153 |
if (index + (4 << shift) - 1 > env->tr.limit) |
if (index + (4 << shift) - 1 > env->tr.limit) |
154 |
raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); |
raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); |
155 |
if (shift == 0) { |
if (shift == 0) { |
156 |
*esp_ptr = lduw(env->tr.base + index); |
*esp_ptr = lduw_kernel(env->tr.base + index); |
157 |
*ss_ptr = lduw(env->tr.base + index + 2); |
*ss_ptr = lduw_kernel(env->tr.base + index + 2); |
158 |
} else { |
} else { |
159 |
*esp_ptr = ldl(env->tr.base + index); |
*esp_ptr = ldl_kernel(env->tr.base + index); |
160 |
*ss_ptr = lduw(env->tr.base + index + 4); |
*ss_ptr = lduw_kernel(env->tr.base + index + 4); |
161 |
} |
} |
162 |
} |
} |
163 |
|
|
177 |
if ((index + 7) > dt->limit) |
if ((index + 7) > dt->limit) |
178 |
return -1; |
return -1; |
179 |
ptr = dt->base + index; |
ptr = dt->base + index; |
180 |
*e1_ptr = ldl(ptr); |
*e1_ptr = ldl_kernel(ptr); |
181 |
*e2_ptr = ldl(ptr + 4); |
*e2_ptr = ldl_kernel(ptr + 4); |
182 |
return 0; |
return 0; |
183 |
} |
} |
184 |
|
|
226 |
if (intno * 8 + 7 > dt->limit) |
if (intno * 8 + 7 > dt->limit) |
227 |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
228 |
ptr = dt->base + intno * 8; |
ptr = dt->base + intno * 8; |
229 |
e1 = ldl(ptr); |
e1 = ldl_kernel(ptr); |
230 |
e2 = ldl(ptr + 4); |
e2 = ldl_kernel(ptr + 4); |
231 |
/* check gate type */ |
/* check gate type */ |
232 |
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; |
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; |
233 |
switch(type) { |
switch(type) { |
344 |
int old_eflags; |
int old_eflags; |
345 |
if (env->eflags & VM_MASK) { |
if (env->eflags & VM_MASK) { |
346 |
ssp -= 4; |
ssp -= 4; |
347 |
stl(ssp, env->segs[R_GS].selector); |
stl_kernel(ssp, env->segs[R_GS].selector); |
348 |
ssp -= 4; |
ssp -= 4; |
349 |
stl(ssp, env->segs[R_FS].selector); |
stl_kernel(ssp, env->segs[R_FS].selector); |
350 |
ssp -= 4; |
ssp -= 4; |
351 |
stl(ssp, env->segs[R_DS].selector); |
stl_kernel(ssp, env->segs[R_DS].selector); |
352 |
ssp -= 4; |
ssp -= 4; |
353 |
stl(ssp, env->segs[R_ES].selector); |
stl_kernel(ssp, env->segs[R_ES].selector); |
354 |
} |
} |
355 |
if (new_stack) { |
if (new_stack) { |
356 |
ssp -= 4; |
ssp -= 4; |
357 |
stl(ssp, old_ss); |
stl_kernel(ssp, old_ss); |
358 |
ssp -= 4; |
ssp -= 4; |
359 |
stl(ssp, old_esp); |
stl_kernel(ssp, old_esp); |
360 |
} |
} |
361 |
ssp -= 4; |
ssp -= 4; |
362 |
old_eflags = compute_eflags(); |
old_eflags = compute_eflags(); |
363 |
stl(ssp, old_eflags); |
stl_kernel(ssp, old_eflags); |
364 |
ssp -= 4; |
ssp -= 4; |
365 |
stl(ssp, old_cs); |
stl_kernel(ssp, old_cs); |
366 |
ssp -= 4; |
ssp -= 4; |
367 |
stl(ssp, old_eip); |
stl_kernel(ssp, old_eip); |
368 |
if (has_error_code) { |
if (has_error_code) { |
369 |
ssp -= 4; |
ssp -= 4; |
370 |
stl(ssp, error_code); |
stl_kernel(ssp, error_code); |
371 |
} |
} |
372 |
} else { |
} else { |
373 |
if (new_stack) { |
if (new_stack) { |
374 |
ssp -= 2; |
ssp -= 2; |
375 |
stw(ssp, old_ss); |
stw_kernel(ssp, old_ss); |
376 |
ssp -= 2; |
ssp -= 2; |
377 |
stw(ssp, old_esp); |
stw_kernel(ssp, old_esp); |
378 |
} |
} |
379 |
ssp -= 2; |
ssp -= 2; |
380 |
stw(ssp, compute_eflags()); |
stw_kernel(ssp, compute_eflags()); |
381 |
ssp -= 2; |
ssp -= 2; |
382 |
stw(ssp, old_cs); |
stw_kernel(ssp, old_cs); |
383 |
ssp -= 2; |
ssp -= 2; |
384 |
stw(ssp, old_eip); |
stw_kernel(ssp, old_eip); |
385 |
if (has_error_code) { |
if (has_error_code) { |
386 |
ssp -= 2; |
ssp -= 2; |
387 |
stw(ssp, error_code); |
stw_kernel(ssp, error_code); |
388 |
} |
} |
389 |
} |
} |
390 |
|
|
410 |
if (intno * 4 + 3 > dt->limit) |
if (intno * 4 + 3 > dt->limit) |
411 |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
412 |
ptr = dt->base + intno * 4; |
ptr = dt->base + intno * 4; |
413 |
offset = lduw(ptr); |
offset = lduw_kernel(ptr); |
414 |
selector = lduw(ptr + 2); |
selector = lduw_kernel(ptr + 2); |
415 |
esp = ESP; |
esp = ESP; |
416 |
ssp = env->segs[R_SS].base; |
ssp = env->segs[R_SS].base; |
417 |
if (is_int) |
if (is_int) |
420 |
old_eip = env->eip; |
old_eip = env->eip; |
421 |
old_cs = env->segs[R_CS].selector; |
old_cs = env->segs[R_CS].selector; |
422 |
esp -= 2; |
esp -= 2; |
423 |
stw(ssp + (esp & 0xffff), compute_eflags()); |
stw_kernel(ssp + (esp & 0xffff), compute_eflags()); |
424 |
esp -= 2; |
esp -= 2; |
425 |
stw(ssp + (esp & 0xffff), old_cs); |
stw_kernel(ssp + (esp & 0xffff), old_cs); |
426 |
esp -= 2; |
esp -= 2; |
427 |
stw(ssp + (esp & 0xffff), old_eip); |
stw_kernel(ssp + (esp & 0xffff), old_eip); |
428 |
|
|
429 |
/* update processor state */ |
/* update processor state */ |
430 |
ESP = (ESP & ~0xffff) | (esp & 0xffff); |
ESP = (ESP & ~0xffff) | (esp & 0xffff); |
445 |
|
|
446 |
dt = &env->idt; |
dt = &env->idt; |
447 |
ptr = dt->base + (intno * 8); |
ptr = dt->base + (intno * 8); |
448 |
e2 = ldl(ptr + 4); |
e2 = ldl_kernel(ptr + 4); |
449 |
|
|
450 |
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
451 |
cpl = env->hflags & HF_CPL_MASK; |
cpl = env->hflags & HF_CPL_MASK; |
651 |
if ((index + 7) > dt->limit) |
if ((index + 7) > dt->limit) |
652 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
653 |
ptr = dt->base + index; |
ptr = dt->base + index; |
654 |
e1 = ldl(ptr); |
e1 = ldl_kernel(ptr); |
655 |
e2 = ldl(ptr + 4); |
e2 = ldl_kernel(ptr + 4); |
656 |
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) |
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) |
657 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
658 |
if (!(e2 & DESC_P_MASK)) |
if (!(e2 & DESC_P_MASK)) |
684 |
if ((index + 7) > dt->limit) |
if ((index + 7) > dt->limit) |
685 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
686 |
ptr = dt->base + index; |
ptr = dt->base + index; |
687 |
e1 = ldl(ptr); |
e1 = ldl_kernel(ptr); |
688 |
e2 = ldl(ptr + 4); |
e2 = ldl_kernel(ptr + 4); |
689 |
type = (e2 >> DESC_TYPE_SHIFT) & 0xf; |
type = (e2 >> DESC_TYPE_SHIFT) & 0xf; |
690 |
if ((e2 & DESC_S_MASK) || |
if ((e2 & DESC_S_MASK) || |
691 |
(type != 2 && type != 9)) |
(type != 2 && type != 9)) |
694 |
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
695 |
load_seg_cache_raw_dt(&env->tr, e1, e2); |
load_seg_cache_raw_dt(&env->tr, e1, e2); |
696 |
e2 |= 0x00000200; /* set the busy bit */ |
e2 |= 0x00000200; /* set the busy bit */ |
697 |
stl(ptr + 4, e2); |
stl_kernel(ptr + 4, e2); |
698 |
} |
} |
699 |
env->tr.selector = selector; |
env->tr.selector = selector; |
700 |
} |
} |
813 |
ssp = env->segs[R_SS].base; |
ssp = env->segs[R_SS].base; |
814 |
if (shift) { |
if (shift) { |
815 |
esp -= 4; |
esp -= 4; |
816 |
stl(ssp + (esp & esp_mask), env->segs[R_CS].selector); |
stl_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector); |
817 |
esp -= 4; |
esp -= 4; |
818 |
stl(ssp + (esp & esp_mask), next_eip); |
stl_kernel(ssp + (esp & esp_mask), next_eip); |
819 |
} else { |
} else { |
820 |
esp -= 2; |
esp -= 2; |
821 |
stw(ssp + (esp & esp_mask), env->segs[R_CS].selector); |
stw_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector); |
822 |
esp -= 2; |
esp -= 2; |
823 |
stw(ssp + (esp & esp_mask), next_eip); |
stw_kernel(ssp + (esp & esp_mask), next_eip); |
824 |
} |
} |
825 |
|
|
826 |
if (!(env->segs[R_SS].flags & DESC_B_MASK)) |
if (!(env->segs[R_SS].flags & DESC_B_MASK)) |
873 |
ssp = env->segs[R_SS].base + sp; |
ssp = env->segs[R_SS].base + sp; |
874 |
if (shift) { |
if (shift) { |
875 |
ssp -= 4; |
ssp -= 4; |
876 |
stl(ssp, env->segs[R_CS].selector); |
stl_kernel(ssp, env->segs[R_CS].selector); |
877 |
ssp -= 4; |
ssp -= 4; |
878 |
stl(ssp, next_eip); |
stl_kernel(ssp, next_eip); |
879 |
} else { |
} else { |
880 |
ssp -= 2; |
ssp -= 2; |
881 |
stw(ssp, env->segs[R_CS].selector); |
stw_kernel(ssp, env->segs[R_CS].selector); |
882 |
ssp -= 2; |
ssp -= 2; |
883 |
stw(ssp, next_eip); |
stw_kernel(ssp, next_eip); |
884 |
} |
} |
885 |
sp -= (4 << shift); |
sp -= (4 << shift); |
886 |
|
|
975 |
ssp = env->segs[R_SS].base + sp; |
ssp = env->segs[R_SS].base + sp; |
976 |
if (shift) { |
if (shift) { |
977 |
ssp -= 4; |
ssp -= 4; |
978 |
stl(ssp, old_ss); |
stl_kernel(ssp, old_ss); |
979 |
ssp -= 4; |
ssp -= 4; |
980 |
stl(ssp, old_esp); |
stl_kernel(ssp, old_esp); |
981 |
ssp -= 4 * param_count; |
ssp -= 4 * param_count; |
982 |
for(i = 0; i < param_count; i++) { |
for(i = 0; i < param_count; i++) { |
983 |
val = ldl(old_ssp + i * 4); |
val = ldl_kernel(old_ssp + i * 4); |
984 |
stl(ssp + i * 4, val); |
stl_kernel(ssp + i * 4, val); |
985 |
} |
} |
986 |
} else { |
} else { |
987 |
ssp -= 2; |
ssp -= 2; |
988 |
stw(ssp, old_ss); |
stw_kernel(ssp, old_ss); |
989 |
ssp -= 2; |
ssp -= 2; |
990 |
stw(ssp, old_esp); |
stw_kernel(ssp, old_esp); |
991 |
ssp -= 2 * param_count; |
ssp -= 2 * param_count; |
992 |
for(i = 0; i < param_count; i++) { |
for(i = 0; i < param_count; i++) { |
993 |
val = lduw(old_ssp + i * 2); |
val = lduw_kernel(old_ssp + i * 2); |
994 |
stw(ssp + i * 2, val); |
stw_kernel(ssp + i * 2, val); |
995 |
} |
} |
996 |
} |
} |
997 |
} else { |
} else { |
1004 |
|
|
1005 |
if (shift) { |
if (shift) { |
1006 |
ssp -= 4; |
ssp -= 4; |
1007 |
stl(ssp, env->segs[R_CS].selector); |
stl_kernel(ssp, env->segs[R_CS].selector); |
1008 |
ssp -= 4; |
ssp -= 4; |
1009 |
stl(ssp, next_eip); |
stl_kernel(ssp, next_eip); |
1010 |
} else { |
} else { |
1011 |
ssp -= 2; |
ssp -= 2; |
1012 |
stw(ssp, env->segs[R_CS].selector); |
stw_kernel(ssp, env->segs[R_CS].selector); |
1013 |
ssp -= 2; |
ssp -= 2; |
1014 |
stw(ssp, next_eip); |
stw_kernel(ssp, next_eip); |
1015 |
} |
} |
1016 |
|
|
1017 |
sp -= push_size; |
sp -= push_size; |
1042 |
ssp = env->segs[R_SS].base + sp; |
ssp = env->segs[R_SS].base + sp; |
1043 |
if (shift == 1) { |
if (shift == 1) { |
1044 |
/* 32 bits */ |
/* 32 bits */ |
1045 |
new_eflags = ldl(ssp + 8); |
new_eflags = ldl_kernel(ssp + 8); |
1046 |
new_cs = ldl(ssp + 4) & 0xffff; |
new_cs = ldl_kernel(ssp + 4) & 0xffff; |
1047 |
new_eip = ldl(ssp) & 0xffff; |
new_eip = ldl_kernel(ssp) & 0xffff; |
1048 |
} else { |
} else { |
1049 |
/* 16 bits */ |
/* 16 bits */ |
1050 |
new_eflags = lduw(ssp + 4); |
new_eflags = lduw_kernel(ssp + 4); |
1051 |
new_cs = lduw(ssp + 2); |
new_cs = lduw_kernel(ssp + 2); |
1052 |
new_eip = lduw(ssp); |
new_eip = lduw_kernel(ssp); |
1053 |
} |
} |
1054 |
new_esp = sp + (6 << shift); |
new_esp = sp + (6 << shift); |
1055 |
ESP = (ESP & 0xffff0000) | |
ESP = (ESP & 0xffff0000) | |
1078 |
if (shift == 1) { |
if (shift == 1) { |
1079 |
/* 32 bits */ |
/* 32 bits */ |
1080 |
if (is_iret) |
if (is_iret) |
1081 |
new_eflags = ldl(ssp + 8); |
new_eflags = ldl_kernel(ssp + 8); |
1082 |
new_cs = ldl(ssp + 4) & 0xffff; |
new_cs = ldl_kernel(ssp + 4) & 0xffff; |
1083 |
new_eip = ldl(ssp); |
new_eip = ldl_kernel(ssp); |
1084 |
if (is_iret && (new_eflags & VM_MASK)) |
if (is_iret && (new_eflags & VM_MASK)) |
1085 |
goto return_to_vm86; |
goto return_to_vm86; |
1086 |
} else { |
} else { |
1087 |
/* 16 bits */ |
/* 16 bits */ |
1088 |
if (is_iret) |
if (is_iret) |
1089 |
new_eflags = lduw(ssp + 4); |
new_eflags = lduw_kernel(ssp + 4); |
1090 |
new_cs = lduw(ssp + 2); |
new_cs = lduw_kernel(ssp + 2); |
1091 |
new_eip = lduw(ssp); |
new_eip = lduw_kernel(ssp); |
1092 |
} |
} |
1093 |
if ((new_cs & 0xfffc) == 0) |
if ((new_cs & 0xfffc) == 0) |
1094 |
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
1124 |
ssp += (4 << shift) + ((2 * is_iret) << shift) + addend; |
ssp += (4 << shift) + ((2 * is_iret) << shift) + addend; |
1125 |
if (shift == 1) { |
if (shift == 1) { |
1126 |
/* 32 bits */ |
/* 32 bits */ |
1127 |
new_esp = ldl(ssp); |
new_esp = ldl_kernel(ssp); |
1128 |
new_ss = ldl(ssp + 4) & 0xffff; |
new_ss = ldl_kernel(ssp + 4) & 0xffff; |
1129 |
} else { |
} else { |
1130 |
/* 16 bits */ |
/* 16 bits */ |
1131 |
new_esp = lduw(ssp); |
new_esp = lduw_kernel(ssp); |
1132 |
new_ss = lduw(ssp + 2); |
new_ss = lduw_kernel(ssp + 2); |
1133 |
} |
} |
1134 |
|
|
1135 |
if ((new_ss & 3) != rpl) |
if ((new_ss & 3) != rpl) |
1175 |
return; |
return; |
1176 |
|
|
1177 |
return_to_vm86: |
return_to_vm86: |
1178 |
new_esp = ldl(ssp + 12); |
new_esp = ldl_kernel(ssp + 12); |
1179 |
new_ss = ldl(ssp + 16); |
new_ss = ldl_kernel(ssp + 16); |
1180 |
new_es = ldl(ssp + 20); |
new_es = ldl_kernel(ssp + 20); |
1181 |
new_ds = ldl(ssp + 24); |
new_ds = ldl_kernel(ssp + 24); |
1182 |
new_fs = ldl(ssp + 28); |
new_fs = ldl_kernel(ssp + 28); |
1183 |
new_gs = ldl(ssp + 32); |
new_gs = ldl_kernel(ssp + 32); |
1184 |
|
|
1185 |
/* modify processor state */ |
/* modify processor state */ |
1186 |
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); |
1770 |
} |
} |
1771 |
} |
} |
1772 |
|
|
1773 |
|
#if !defined(CONFIG_USER_ONLY) |
1774 |
|
|
1775 |
|
#define MMUSUFFIX _mmu |
1776 |
|
#define GETPC() (__builtin_return_address(0)) |
1777 |
|
|
1778 |
#define SHIFT 0 |
#define SHIFT 0 |
1779 |
#include "softmmu_template.h" |
#include "softmmu_template.h" |
1780 |
|
|
1787 |
#define SHIFT 3 |
#define SHIFT 3 |
1788 |
#include "softmmu_template.h" |
#include "softmmu_template.h" |
1789 |
|
|
1790 |
/* try to fill the TLB and return an exception if error */ |
#endif |
1791 |
void tlb_fill(unsigned long addr, int is_write, void *retaddr) |
|
1792 |
|
/* try to fill the TLB and return an exception if error. If retaddr is |
1793 |
|
NULL, it means that the function was called in C code (i.e. not |
1794 |
|
from generated code or from helper.c) */ |
1795 |
|
/* XXX: fix it to restore all registers */ |
1796 |
|
void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) |
1797 |
{ |
{ |
1798 |
TranslationBlock *tb; |
TranslationBlock *tb; |
1799 |
int ret; |
int ret; |
1800 |
unsigned long pc; |
unsigned long pc; |
1801 |
ret = cpu_x86_handle_mmu_fault(env, addr, is_write); |
CPUX86State *saved_env; |
1802 |
|
|
1803 |
|
/* XXX: hack to restore env in all cases, even if not called from |
1804 |
|
generated code */ |
1805 |
|
saved_env = env; |
1806 |
|
env = cpu_single_env; |
1807 |
|
if (is_write && page_unprotect(addr)) { |
1808 |
|
/* nothing more to do: the page was write protected because |
1809 |
|
there was code in it. page_unprotect() flushed the code. */ |
1810 |
|
} |
1811 |
|
|
1812 |
|
ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1); |
1813 |
if (ret) { |
if (ret) { |
1814 |
/* now we have a real cpu fault */ |
if (retaddr) { |
1815 |
pc = (unsigned long)retaddr; |
/* now we have a real cpu fault */ |
1816 |
tb = tb_find_pc(pc); |
pc = (unsigned long)retaddr; |
1817 |
if (tb) { |
tb = tb_find_pc(pc); |
1818 |
/* the PC is inside the translated code. It means that we have |
if (tb) { |
1819 |
a virtual CPU fault */ |
/* the PC is inside the translated code. It means that we have |
1820 |
cpu_restore_state(tb, env, pc); |
a virtual CPU fault */ |
1821 |
|
cpu_restore_state(tb, env, pc); |
1822 |
|
} |
1823 |
} |
} |
1824 |
raise_exception_err(EXCP0E_PAGE, env->error_code); |
raise_exception_err(EXCP0E_PAGE, env->error_code); |
1825 |
} |
} |
1826 |
|
env = saved_env; |
1827 |
} |
} |