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,8 +134,9 @@ void helper_ltr_T0(void); | ||
| 134 | void helper_movl_crN_T0(int reg); | 134 | void helper_movl_crN_T0(int reg); |
| 135 | void helper_movl_drN_T0(int reg); | 135 | void helper_movl_drN_T0(int reg); |
| 136 | void helper_invlpg(unsigned int addr); | 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 | void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); | 140 | void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); |
| 140 | int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, | 141 | int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, |
| 141 | int is_write, int is_user, int is_softmmu); | 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,8 +424,7 @@ static void switch_tss(int tss_selector, | ||
| 424 | env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK; | 424 | env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK; |
| 425 | 425 | ||
| 426 | if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) { | 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 | /* load all registers without an exception, then reload them with | 430 | /* load all registers without an exception, then reload them with |
| @@ -1775,13 +1774,18 @@ void helper_lret_protected(int shift, int addend) | @@ -1775,13 +1774,18 @@ void helper_lret_protected(int shift, int addend) | ||
| 1775 | 1774 | ||
| 1776 | void helper_movl_crN_T0(int reg) | 1775 | void helper_movl_crN_T0(int reg) |
| 1777 | { | 1776 | { |
| 1778 | - env->cr[reg] = T0; | ||
| 1779 | switch(reg) { | 1777 | switch(reg) { |
| 1780 | case 0: | 1778 | case 0: |
| 1781 | - cpu_x86_update_cr0(env); | 1779 | + cpu_x86_update_cr0(env, T0); |
| 1782 | break; | 1780 | break; |
| 1783 | case 3: | 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 | break; | 1789 | break; |
| 1786 | } | 1790 | } |
| 1787 | } | 1791 | } |
target-i386/helper2.c
| @@ -43,17 +43,42 @@ CPUX86State *cpu_x86_init(void) | @@ -43,17 +43,42 @@ CPUX86State *cpu_x86_init(void) | ||
| 43 | if (!env) | 43 | if (!env) |
| 44 | return NULL; | 44 | return NULL; |
| 45 | memset(env, 0, sizeof(CPUX86State)); | 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 | #ifdef CONFIG_SOFTMMU | 50 | #ifdef CONFIG_SOFTMMU |
| 55 | env->hflags |= HF_SOFTMMU_MASK; | 51 | env->hflags |= HF_SOFTMMU_MASK; |
| 56 | #endif | 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 | /* init various static tables */ | 82 | /* init various static tables */ |
| 58 | if (!inited) { | 83 | if (!inited) { |
| 59 | inited = 1; | 84 | inited = 1; |
| @@ -179,15 +204,10 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) | @@ -179,15 +204,10 @@ void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) | ||
| 179 | /* x86 mmu */ | 204 | /* x86 mmu */ |
| 180 | /* XXX: add PGE support */ | 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 | void cpu_x86_set_a20(CPUX86State *env, int a20_state) | 207 | void cpu_x86_set_a20(CPUX86State *env, int a20_state) |
| 188 | { | 208 | { |
| 189 | a20_state = (a20_state != 0); | 209 | a20_state = (a20_state != 0); |
| 190 | - if (a20_state != a20_enabled) { | 210 | + if (a20_state != ((env->a20_mask >> 20) & 1)) { |
| 191 | #if defined(DEBUG_MMU) | 211 | #if defined(DEBUG_MMU) |
| 192 | printf("A20 update: a20=%d\n", a20_state); | 212 | printf("A20 update: a20=%d\n", a20_state); |
| 193 | #endif | 213 | #endif |
| @@ -197,27 +217,24 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state) | @@ -197,27 +217,24 @@ void cpu_x86_set_a20(CPUX86State *env, int a20_state) | ||
| 197 | 217 | ||
| 198 | /* when a20 is changed, all the MMU mappings are invalid, so | 218 | /* when a20 is changed, all the MMU mappings are invalid, so |
| 199 | we must flush everything */ | 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 | #if defined(DEBUG_MMU) | 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 | #endif | 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 | /* update PE flag in hidden flags */ | 238 | /* update PE flag in hidden flags */ |
| 222 | pe_state = (env->cr[0] & CR0_PE_MASK); | 239 | pe_state = (env->cr[0] & CR0_PE_MASK); |
| 223 | env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT); | 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,23 +242,27 @@ void cpu_x86_update_cr0(CPUX86State *env) | ||
| 225 | env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT); | 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 | if (env->cr[0] & CR0_PG_MASK) { | 248 | if (env->cr[0] & CR0_PG_MASK) { |
| 231 | #if defined(DEBUG_MMU) | 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 | #endif | 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 | /* XXX: also flush 4MB pages */ | 268 | /* XXX: also flush 4MB pages */ |
| @@ -285,7 +306,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, | @@ -285,7 +306,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, | ||
| 285 | 306 | ||
| 286 | /* page directory entry */ | 307 | /* page directory entry */ |
| 287 | pde_ptr = phys_ram_base + | 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 | pde = ldl_raw(pde_ptr); | 310 | pde = ldl_raw(pde_ptr); |
| 290 | if (!(pde & PG_PRESENT_MASK)) { | 311 | if (!(pde & PG_PRESENT_MASK)) { |
| 291 | error_code = 0; | 312 | error_code = 0; |
| @@ -323,7 +344,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, | @@ -323,7 +344,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, | ||
| 323 | 344 | ||
| 324 | /* page directory entry */ | 345 | /* page directory entry */ |
| 325 | pte_ptr = phys_ram_base + | 346 | pte_ptr = phys_ram_base + |
| 326 | - (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask); | 347 | + (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask); |
| 327 | pte = ldl_raw(pte_ptr); | 348 | pte = ldl_raw(pte_ptr); |
| 328 | if (!(pte & PG_PRESENT_MASK)) { | 349 | if (!(pte & PG_PRESENT_MASK)) { |
| 329 | error_code = 0; | 350 | error_code = 0; |
| @@ -368,7 +389,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, | @@ -368,7 +389,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, | ||
| 368 | } | 389 | } |
| 369 | 390 | ||
| 370 | do_mapping: | 391 | do_mapping: |
| 371 | - pte = pte & a20_mask; | 392 | + pte = pte & env->a20_mask; |
| 372 | 393 | ||
| 373 | /* Even if 4MB pages, we map only one 4KB page in the cache to | 394 | /* Even if 4MB pages, we map only one 4KB page in the cache to |
| 374 | avoid filling it too fast */ | 395 | avoid filling it too fast */ |
| @@ -405,7 +426,7 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | @@ -405,7 +426,7 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | ||
| 405 | } else { | 426 | } else { |
| 406 | /* page directory entry */ | 427 | /* page directory entry */ |
| 407 | pde_ptr = phys_ram_base + | 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 | pde = ldl_raw(pde_ptr); | 430 | pde = ldl_raw(pde_ptr); |
| 410 | if (!(pde & PG_PRESENT_MASK)) | 431 | if (!(pde & PG_PRESENT_MASK)) |
| 411 | return -1; | 432 | return -1; |
| @@ -415,14 +436,14 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | @@ -415,14 +436,14 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) | ||
| 415 | } else { | 436 | } else { |
| 416 | /* page directory entry */ | 437 | /* page directory entry */ |
| 417 | pte_ptr = phys_ram_base + | 438 | pte_ptr = phys_ram_base + |
| 418 | - (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask); | 439 | + (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask); |
| 419 | pte = ldl_raw(pte_ptr); | 440 | pte = ldl_raw(pte_ptr); |
| 420 | if (!(pte & PG_PRESENT_MASK)) | 441 | if (!(pte & PG_PRESENT_MASK)) |
| 421 | return -1; | 442 | return -1; |
| 422 | page_size = 4096; | 443 | page_size = 4096; |
| 423 | } | 444 | } |
| 424 | } | 445 | } |
| 425 | - pte = pte & a20_mask; | 446 | + pte = pte & env->a20_mask; |
| 426 | page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); | 447 | page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); |
| 427 | paddr = (pte & TARGET_PAGE_MASK) + page_offset; | 448 | paddr = (pte & TARGET_PAGE_MASK) + page_offset; |
| 428 | return paddr; | 449 | return paddr; |