| 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 |
} |
} |