Commit 1ac157da77c863b62b1d2f467626a440d57cf17d
1 parent
64a595f2
more precise TLB invalidation - init cleanup
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@596 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
74 additions
and
48 deletions
target-i386/exec.h
| ... | ... | @@ -134,8 +134,9 @@ void helper_ltr_T0(void); |
| 134 | 134 | void helper_movl_crN_T0(int reg); |
| 135 | 135 | void helper_movl_drN_T0(int reg); |
| 136 | 136 | void helper_invlpg(unsigned int addr); |
| 137 | -void cpu_x86_update_cr0(CPUX86State *env); | |
| 138 | -void cpu_x86_update_cr3(CPUX86State *env); | |
| 137 | +void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); | |
| 138 | +void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3); | |
| 139 | +void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4); | |
| 139 | 140 | void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); |
| 140 | 141 | int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, |
| 141 | 142 | int is_write, int is_user, int is_softmmu); | ... | ... |
target-i386/helper.c
| ... | ... | @@ -424,8 +424,7 @@ static void switch_tss(int tss_selector, |
| 424 | 424 | env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK; |
| 425 | 425 | |
| 426 | 426 | if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) { |
| 427 | - env->cr[3] = new_cr3; | |
| 428 | - cpu_x86_update_cr3(env); | |
| 427 | + cpu_x86_update_cr3(env, new_cr3); | |
| 429 | 428 | } |
| 430 | 429 | |
| 431 | 430 | /* load all registers without an exception, then reload them with |
| ... | ... | @@ -1775,13 +1774,18 @@ void helper_lret_protected(int shift, int addend) |
| 1775 | 1774 | |
| 1776 | 1775 | void helper_movl_crN_T0(int reg) |
| 1777 | 1776 | { |
| 1778 | - env->cr[reg] = T0; | |
| 1779 | 1777 | switch(reg) { |
| 1780 | 1778 | case 0: |
| 1781 | - cpu_x86_update_cr0(env); | |
| 1779 | + cpu_x86_update_cr0(env, T0); | |
| 1782 | 1780 | break; |
| 1783 | 1781 | case 3: |
| 1784 | - cpu_x86_update_cr3(env); | |
| 1782 | + cpu_x86_update_cr3(env, T0); | |
| 1783 | + break; | |
| 1784 | + case 4: | |
| 1785 | + cpu_x86_update_cr4(env, T0); | |
| 1786 | + break; | |
| 1787 | + default: | |
| 1788 | + env->cr[reg] = T0; | |
| 1785 | 1789 | break; |
| 1786 | 1790 | } |
| 1787 | 1791 | } | ... | ... |
target-i386/helper2.c
| ... | ... | @@ -43,17 +43,42 @@ CPUX86State *cpu_x86_init(void) |
| 43 | 43 | if (!env) |
| 44 | 44 | return NULL; |
| 45 | 45 | memset(env, 0, sizeof(CPUX86State)); |
| 46 | - /* basic FPU init */ | |
| 47 | - for(i = 0;i < 8; i++) | |
| 48 | - env->fptags[i] = 1; | |
| 49 | - env->fpuc = 0x37f; | |
| 50 | - /* flags setup : we activate the IRQs by default as in user mode */ | |
| 51 | - env->eflags = 0x2 | IF_MASK; | |
| 52 | 46 | |
| 53 | - tlb_flush(env); | |
| 47 | + /* init to reset state */ | |
| 48 | + | |
| 49 | + tlb_flush(env, 1); | |
| 54 | 50 | #ifdef CONFIG_SOFTMMU |
| 55 | 51 | env->hflags |= HF_SOFTMMU_MASK; |
| 56 | 52 | #endif |
| 53 | + | |
| 54 | + cpu_x86_update_cr0(env, 0x60000010); | |
| 55 | + env->a20_mask = 0xffffffff; | |
| 56 | + | |
| 57 | + env->idt.limit = 0xffff; | |
| 58 | + env->gdt.limit = 0xffff; | |
| 59 | + env->ldt.limit = 0xffff; | |
| 60 | + env->ldt.flags = DESC_P_MASK; | |
| 61 | + env->tr.limit = 0xffff; | |
| 62 | + env->tr.flags = DESC_P_MASK; | |
| 63 | + | |
| 64 | + /* not correct (CS base=0xffff0000) */ | |
| 65 | + cpu_x86_load_seg_cache(env, R_CS, 0xf000, (uint8_t *)0x000f0000, 0xffff, 0); | |
| 66 | + cpu_x86_load_seg_cache(env, R_DS, 0, NULL, 0xffff, 0); | |
| 67 | + cpu_x86_load_seg_cache(env, R_ES, 0, NULL, 0xffff, 0); | |
| 68 | + cpu_x86_load_seg_cache(env, R_SS, 0, NULL, 0xffff, 0); | |
| 69 | + cpu_x86_load_seg_cache(env, R_FS, 0, NULL, 0xffff, 0); | |
| 70 | + cpu_x86_load_seg_cache(env, R_GS, 0, NULL, 0xffff, 0); | |
| 71 | + | |
| 72 | + env->eip = 0xfff0; | |
| 73 | + env->regs[R_EDX] = 0x600; /* indicate P6 processor */ | |
| 74 | + | |
| 75 | + env->eflags = 0x2; | |
| 76 | + | |
| 77 | + /* FPU init */ | |
| 78 | + for(i = 0;i < 8; i++) | |
| 79 | + env->fptags[i] = 1; | |
| 80 | + env->fpuc = 0x37f; | |
| 81 | + | |
| 57 | 82 | /* init various static tables */ |
| 58 | 83 | if (!inited) { |
| 59 | 84 | inited = 1; |
| ... | ... | @@ -179,15 +204,10 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) |
| 179 | 204 | /* x86 mmu */ |
| 180 | 205 | /* XXX: add PGE support */ |
| 181 | 206 | |
| 182 | -/* called when cr3 or PG bit are modified */ | |
| 183 | -static int last_pg_state = -1; | |
| 184 | -static uint32_t a20_mask; | |
| 185 | -int a20_enabled; | |
| 186 | - | |
| 187 | 207 | void cpu_x86_set_a20(CPUX86State *env, int a20_state) |
| 188 | 208 | { |
| 189 | 209 | a20_state = (a20_state != 0); |
| 190 | - if (a20_state != a20_enabled) { | |
| 210 | + if (a20_state != ((env->a20_mask >> 20) & 1)) { | |
| 191 | 211 | #if defined(DEBUG_MMU) |
| 192 | 212 | printf("A20 update: a20=%d\n", a20_state); |
| 193 | 213 | #endif |
| ... | ... | @@ -197,27 +217,24 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state) |
| 197 | 217 | |
| 198 | 218 | /* when a20 is changed, all the MMU mappings are invalid, so |
| 199 | 219 | we must flush everything */ |
| 200 | - tlb_flush(env); | |
| 201 | - a20_enabled = a20_state; | |
| 202 | - if (a20_enabled) | |
| 203 | - a20_mask = 0xffffffff; | |
| 204 | - else | |
| 205 | - a20_mask = 0xffefffff; | |
| 220 | + tlb_flush(env, 1); | |
| 221 | + env->a20_mask = 0xffefffff | (a20_state << 20); | |
| 206 | 222 | } |
| 207 | 223 | } |
| 208 | 224 | |
| 209 | -void cpu_x86_update_cr0(CPUX86State *env) | |
| 225 | +void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0) | |
| 210 | 226 | { |
| 211 | - int pg_state, pe_state; | |
| 227 | + int pe_state; | |
| 212 | 228 | |
| 213 | 229 | #if defined(DEBUG_MMU) |
| 214 | - printf("CR0 update: CR0=0x%08x\n", env->cr[0]); | |
| 230 | + printf("CR0 update: CR0=0x%08x\n", new_cr0); | |
| 215 | 231 | #endif |
| 216 | - pg_state = env->cr[0] & CR0_PG_MASK; | |
| 217 | - if (pg_state != last_pg_state) { | |
| 218 | - tlb_flush(env); | |
| 219 | - last_pg_state = pg_state; | |
| 232 | + if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) != | |
| 233 | + (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) { | |
| 234 | + tlb_flush(env, 1); | |
| 220 | 235 | } |
| 236 | + env->cr[0] = new_cr0; | |
| 237 | + | |
| 221 | 238 | /* update PE flag in hidden flags */ |
| 222 | 239 | pe_state = (env->cr[0] & CR0_PE_MASK); |
| 223 | 240 | env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT); |
| ... | ... | @@ -225,23 +242,27 @@ void cpu_x86_update_cr0(CPUX86State *env) |
| 225 | 242 | env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT); |
| 226 | 243 | } |
| 227 | 244 | |
| 228 | -void cpu_x86_update_cr3(CPUX86State *env) | |
| 245 | +void cpu_x86_update_cr3(CPUX86State *env, uint32_t new_cr3) | |
| 229 | 246 | { |
| 247 | + env->cr[3] = new_cr3; | |
| 230 | 248 | if (env->cr[0] & CR0_PG_MASK) { |
| 231 | 249 | #if defined(DEBUG_MMU) |
| 232 | - printf("CR3 update: CR3=%08x\n", env->cr[3]); | |
| 250 | + printf("CR3 update: CR3=%08x\n", new_cr3); | |
| 233 | 251 | #endif |
| 234 | - tlb_flush(env); | |
| 252 | + tlb_flush(env, 0); | |
| 235 | 253 | } |
| 236 | 254 | } |
| 237 | 255 | |
| 238 | -void cpu_x86_init_mmu(CPUX86State *env) | |
| 256 | +void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) | |
| 239 | 257 | { |
| 240 | - a20_enabled = 1; | |
| 241 | - a20_mask = 0xffffffff; | |
| 242 | - | |
| 243 | - last_pg_state = -1; | |
| 244 | - cpu_x86_update_cr0(env); | |
| 258 | +#if defined(DEBUG_MMU) | |
| 259 | + printf("CR4 update: CR4=%08x\n", env->cr[4]); | |
| 260 | +#endif | |
| 261 | + if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) != | |
| 262 | + (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) { | |
| 263 | + tlb_flush(env, 1); | |
| 264 | + } | |
| 265 | + env->cr[4] = new_cr4; | |
| 245 | 266 | } |
| 246 | 267 | |
| 247 | 268 | /* XXX: also flush 4MB pages */ |
| ... | ... | @@ -285,7 +306,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, |
| 285 | 306 | |
| 286 | 307 | /* page directory entry */ |
| 287 | 308 | pde_ptr = phys_ram_base + |
| 288 | - (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & a20_mask); | |
| 309 | + (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask); | |
| 289 | 310 | pde = ldl_raw(pde_ptr); |
| 290 | 311 | if (!(pde & PG_PRESENT_MASK)) { |
| 291 | 312 | error_code = 0; |
| ... | ... | @@ -323,7 +344,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, |
| 323 | 344 | |
| 324 | 345 | /* page directory entry */ |
| 325 | 346 | pte_ptr = phys_ram_base + |
| 326 | - (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask); | |
| 347 | + (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask); | |
| 327 | 348 | pte = ldl_raw(pte_ptr); |
| 328 | 349 | if (!(pte & PG_PRESENT_MASK)) { |
| 329 | 350 | error_code = 0; |
| ... | ... | @@ -368,7 +389,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, |
| 368 | 389 | } |
| 369 | 390 | |
| 370 | 391 | do_mapping: |
| 371 | - pte = pte & a20_mask; | |
| 392 | + pte = pte & env->a20_mask; | |
| 372 | 393 | |
| 373 | 394 | /* Even if 4MB pages, we map only one 4KB page in the cache to |
| 374 | 395 | avoid filling it too fast */ |
| ... | ... | @@ -405,7 +426,7 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
| 405 | 426 | } else { |
| 406 | 427 | /* page directory entry */ |
| 407 | 428 | pde_ptr = phys_ram_base + |
| 408 | - (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & a20_mask); | |
| 429 | + (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask); | |
| 409 | 430 | pde = ldl_raw(pde_ptr); |
| 410 | 431 | if (!(pde & PG_PRESENT_MASK)) |
| 411 | 432 | return -1; |
| ... | ... | @@ -415,14 +436,14 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) |
| 415 | 436 | } else { |
| 416 | 437 | /* page directory entry */ |
| 417 | 438 | pte_ptr = phys_ram_base + |
| 418 | - (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask); | |
| 439 | + (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask); | |
| 419 | 440 | pte = ldl_raw(pte_ptr); |
| 420 | 441 | if (!(pte & PG_PRESENT_MASK)) |
| 421 | 442 | return -1; |
| 422 | 443 | page_size = 4096; |
| 423 | 444 | } |
| 424 | 445 | } |
| 425 | - pte = pte & a20_mask; | |
| 446 | + pte = pte & env->a20_mask; | |
| 426 | 447 | page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); |
| 427 | 448 | paddr = (pte & TARGET_PAGE_MASK) + page_offset; |
| 428 | 449 | return paddr; | ... | ... |