11b248f14SClaudio Fontana /* 21b248f14SClaudio Fontana * x86 exception helpers 31b248f14SClaudio Fontana * 41b248f14SClaudio Fontana * Copyright (c) 2003 Fabrice Bellard 51b248f14SClaudio Fontana * 61b248f14SClaudio Fontana * This library is free software; you can redistribute it and/or 71b248f14SClaudio Fontana * modify it under the terms of the GNU Lesser General Public 81b248f14SClaudio Fontana * License as published by the Free Software Foundation; either 91b248f14SClaudio Fontana * version 2.1 of the License, or (at your option) any later version. 101b248f14SClaudio Fontana * 111b248f14SClaudio Fontana * This library is distributed in the hope that it will be useful, 121b248f14SClaudio Fontana * but WITHOUT ANY WARRANTY; without even the implied warranty of 131b248f14SClaudio Fontana * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 141b248f14SClaudio Fontana * Lesser General Public License for more details. 151b248f14SClaudio Fontana * 161b248f14SClaudio Fontana * You should have received a copy of the GNU Lesser General Public 171b248f14SClaudio Fontana * License along with this library; if not, see <http://www.gnu.org/licenses/>. 181b248f14SClaudio Fontana */ 191b248f14SClaudio Fontana 201b248f14SClaudio Fontana #include "qemu/osdep.h" 211b248f14SClaudio Fontana #include "cpu.h" 221b248f14SClaudio Fontana #include "exec/exec-all.h" 231b248f14SClaudio Fontana #include "qemu/log.h" 241b248f14SClaudio Fontana #include "sysemu/runstate.h" 251b248f14SClaudio Fontana #include "exec/helper-proto.h" 26*ed69e831SClaudio Fontana #include "helper-tcg.h" 271b248f14SClaudio Fontana 281b248f14SClaudio Fontana void helper_raise_interrupt(CPUX86State *env, int intno, int next_eip_addend) 291b248f14SClaudio Fontana { 301b248f14SClaudio Fontana raise_interrupt(env, intno, 1, 0, next_eip_addend); 311b248f14SClaudio Fontana } 321b248f14SClaudio Fontana 331b248f14SClaudio Fontana void helper_raise_exception(CPUX86State *env, int exception_index) 341b248f14SClaudio Fontana { 351b248f14SClaudio Fontana raise_exception(env, exception_index); 361b248f14SClaudio Fontana } 371b248f14SClaudio Fontana 381b248f14SClaudio Fontana /* 391b248f14SClaudio Fontana * Check nested exceptions and change to double or triple fault if 401b248f14SClaudio Fontana * needed. It should only be called, if this is not an interrupt. 411b248f14SClaudio Fontana * Returns the new exception number. 421b248f14SClaudio Fontana */ 431b248f14SClaudio Fontana static int check_exception(CPUX86State *env, int intno, int *error_code, 441b248f14SClaudio Fontana uintptr_t retaddr) 451b248f14SClaudio Fontana { 461b248f14SClaudio Fontana int first_contributory = env->old_exception == 0 || 471b248f14SClaudio Fontana (env->old_exception >= 10 && 481b248f14SClaudio Fontana env->old_exception <= 13); 491b248f14SClaudio Fontana int second_contributory = intno == 0 || 501b248f14SClaudio Fontana (intno >= 10 && intno <= 13); 511b248f14SClaudio Fontana 521b248f14SClaudio Fontana qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n", 531b248f14SClaudio Fontana env->old_exception, intno); 541b248f14SClaudio Fontana 551b248f14SClaudio Fontana #if !defined(CONFIG_USER_ONLY) 561b248f14SClaudio Fontana if (env->old_exception == EXCP08_DBLE) { 571b248f14SClaudio Fontana if (env->hflags & HF_GUEST_MASK) { 581b248f14SClaudio Fontana cpu_vmexit(env, SVM_EXIT_SHUTDOWN, 0, retaddr); /* does not return */ 591b248f14SClaudio Fontana } 601b248f14SClaudio Fontana 611b248f14SClaudio Fontana qemu_log_mask(CPU_LOG_RESET, "Triple fault\n"); 621b248f14SClaudio Fontana 631b248f14SClaudio Fontana qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 641b248f14SClaudio Fontana return EXCP_HLT; 651b248f14SClaudio Fontana } 661b248f14SClaudio Fontana #endif 671b248f14SClaudio Fontana 681b248f14SClaudio Fontana if ((first_contributory && second_contributory) 691b248f14SClaudio Fontana || (env->old_exception == EXCP0E_PAGE && 701b248f14SClaudio Fontana (second_contributory || (intno == EXCP0E_PAGE)))) { 711b248f14SClaudio Fontana intno = EXCP08_DBLE; 721b248f14SClaudio Fontana *error_code = 0; 731b248f14SClaudio Fontana } 741b248f14SClaudio Fontana 751b248f14SClaudio Fontana if (second_contributory || (intno == EXCP0E_PAGE) || 761b248f14SClaudio Fontana (intno == EXCP08_DBLE)) { 771b248f14SClaudio Fontana env->old_exception = intno; 781b248f14SClaudio Fontana } 791b248f14SClaudio Fontana 801b248f14SClaudio Fontana return intno; 811b248f14SClaudio Fontana } 821b248f14SClaudio Fontana 831b248f14SClaudio Fontana /* 841b248f14SClaudio Fontana * Signal an interruption. It is executed in the main CPU loop. 851b248f14SClaudio Fontana * is_int is TRUE if coming from the int instruction. next_eip is the 861b248f14SClaudio Fontana * env->eip value AFTER the interrupt instruction. It is only relevant if 871b248f14SClaudio Fontana * is_int is TRUE. 881b248f14SClaudio Fontana */ 891b248f14SClaudio Fontana static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno, 901b248f14SClaudio Fontana int is_int, int error_code, 911b248f14SClaudio Fontana int next_eip_addend, 921b248f14SClaudio Fontana uintptr_t retaddr) 931b248f14SClaudio Fontana { 941b248f14SClaudio Fontana CPUState *cs = env_cpu(env); 951b248f14SClaudio Fontana 961b248f14SClaudio Fontana if (!is_int) { 971b248f14SClaudio Fontana cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno, 981b248f14SClaudio Fontana error_code, retaddr); 991b248f14SClaudio Fontana intno = check_exception(env, intno, &error_code, retaddr); 1001b248f14SClaudio Fontana } else { 1011b248f14SClaudio Fontana cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0, retaddr); 1021b248f14SClaudio Fontana } 1031b248f14SClaudio Fontana 1041b248f14SClaudio Fontana cs->exception_index = intno; 1051b248f14SClaudio Fontana env->error_code = error_code; 1061b248f14SClaudio Fontana env->exception_is_int = is_int; 1071b248f14SClaudio Fontana env->exception_next_eip = env->eip + next_eip_addend; 1081b248f14SClaudio Fontana cpu_loop_exit_restore(cs, retaddr); 1091b248f14SClaudio Fontana } 1101b248f14SClaudio Fontana 1111b248f14SClaudio Fontana /* shortcuts to generate exceptions */ 1121b248f14SClaudio Fontana 1131b248f14SClaudio Fontana void QEMU_NORETURN raise_interrupt(CPUX86State *env, int intno, int is_int, 1141b248f14SClaudio Fontana int error_code, int next_eip_addend) 1151b248f14SClaudio Fontana { 1161b248f14SClaudio Fontana raise_interrupt2(env, intno, is_int, error_code, next_eip_addend, 0); 1171b248f14SClaudio Fontana } 1181b248f14SClaudio Fontana 1191b248f14SClaudio Fontana void raise_exception_err(CPUX86State *env, int exception_index, 1201b248f14SClaudio Fontana int error_code) 1211b248f14SClaudio Fontana { 1221b248f14SClaudio Fontana raise_interrupt2(env, exception_index, 0, error_code, 0, 0); 1231b248f14SClaudio Fontana } 1241b248f14SClaudio Fontana 1251b248f14SClaudio Fontana void raise_exception_err_ra(CPUX86State *env, int exception_index, 1261b248f14SClaudio Fontana int error_code, uintptr_t retaddr) 1271b248f14SClaudio Fontana { 1281b248f14SClaudio Fontana raise_interrupt2(env, exception_index, 0, error_code, 0, retaddr); 1291b248f14SClaudio Fontana } 1301b248f14SClaudio Fontana 1311b248f14SClaudio Fontana void raise_exception(CPUX86State *env, int exception_index) 1321b248f14SClaudio Fontana { 1331b248f14SClaudio Fontana raise_interrupt2(env, exception_index, 0, 0, 0, 0); 1341b248f14SClaudio Fontana } 1351b248f14SClaudio Fontana 1361b248f14SClaudio Fontana void raise_exception_ra(CPUX86State *env, int exception_index, uintptr_t retaddr) 1371b248f14SClaudio Fontana { 1381b248f14SClaudio Fontana raise_interrupt2(env, exception_index, 0, 0, 0, retaddr); 1391b248f14SClaudio Fontana } 1401b248f14SClaudio Fontana 1411b248f14SClaudio Fontana #if !defined(CONFIG_USER_ONLY) 1421b248f14SClaudio Fontana static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, 1431b248f14SClaudio Fontana int *prot) 1441b248f14SClaudio Fontana { 1451b248f14SClaudio Fontana CPUX86State *env = &X86_CPU(cs)->env; 1461b248f14SClaudio Fontana uint64_t rsvd_mask = PG_HI_RSVD_MASK; 1471b248f14SClaudio Fontana uint64_t ptep, pte; 1481b248f14SClaudio Fontana uint64_t exit_info_1 = 0; 1491b248f14SClaudio Fontana target_ulong pde_addr, pte_addr; 1501b248f14SClaudio Fontana uint32_t page_offset; 1511b248f14SClaudio Fontana int page_size; 1521b248f14SClaudio Fontana 1531b248f14SClaudio Fontana if (likely(!(env->hflags2 & HF2_NPT_MASK))) { 1541b248f14SClaudio Fontana return gphys; 1551b248f14SClaudio Fontana } 1561b248f14SClaudio Fontana 1571b248f14SClaudio Fontana if (!(env->nested_pg_mode & SVM_NPT_NXE)) { 1581b248f14SClaudio Fontana rsvd_mask |= PG_NX_MASK; 1591b248f14SClaudio Fontana } 1601b248f14SClaudio Fontana 1611b248f14SClaudio Fontana if (env->nested_pg_mode & SVM_NPT_PAE) { 1621b248f14SClaudio Fontana uint64_t pde, pdpe; 1631b248f14SClaudio Fontana target_ulong pdpe_addr; 1641b248f14SClaudio Fontana 1651b248f14SClaudio Fontana #ifdef TARGET_X86_64 1661b248f14SClaudio Fontana if (env->nested_pg_mode & SVM_NPT_LMA) { 1671b248f14SClaudio Fontana uint64_t pml5e; 1681b248f14SClaudio Fontana uint64_t pml4e_addr, pml4e; 1691b248f14SClaudio Fontana 1701b248f14SClaudio Fontana pml5e = env->nested_cr3; 1711b248f14SClaudio Fontana ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; 1721b248f14SClaudio Fontana 1731b248f14SClaudio Fontana pml4e_addr = (pml5e & PG_ADDRESS_MASK) + 1741b248f14SClaudio Fontana (((gphys >> 39) & 0x1ff) << 3); 1751b248f14SClaudio Fontana pml4e = x86_ldq_phys(cs, pml4e_addr); 1761b248f14SClaudio Fontana if (!(pml4e & PG_PRESENT_MASK)) { 1771b248f14SClaudio Fontana goto do_fault; 1781b248f14SClaudio Fontana } 1791b248f14SClaudio Fontana if (pml4e & (rsvd_mask | PG_PSE_MASK)) { 1801b248f14SClaudio Fontana goto do_fault_rsvd; 1811b248f14SClaudio Fontana } 1821b248f14SClaudio Fontana if (!(pml4e & PG_ACCESSED_MASK)) { 1831b248f14SClaudio Fontana pml4e |= PG_ACCESSED_MASK; 1841b248f14SClaudio Fontana x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); 1851b248f14SClaudio Fontana } 1861b248f14SClaudio Fontana ptep &= pml4e ^ PG_NX_MASK; 1871b248f14SClaudio Fontana pdpe_addr = (pml4e & PG_ADDRESS_MASK) + 1881b248f14SClaudio Fontana (((gphys >> 30) & 0x1ff) << 3); 1891b248f14SClaudio Fontana pdpe = x86_ldq_phys(cs, pdpe_addr); 1901b248f14SClaudio Fontana if (!(pdpe & PG_PRESENT_MASK)) { 1911b248f14SClaudio Fontana goto do_fault; 1921b248f14SClaudio Fontana } 1931b248f14SClaudio Fontana if (pdpe & rsvd_mask) { 1941b248f14SClaudio Fontana goto do_fault_rsvd; 1951b248f14SClaudio Fontana } 1961b248f14SClaudio Fontana ptep &= pdpe ^ PG_NX_MASK; 1971b248f14SClaudio Fontana if (!(pdpe & PG_ACCESSED_MASK)) { 1981b248f14SClaudio Fontana pdpe |= PG_ACCESSED_MASK; 1991b248f14SClaudio Fontana x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); 2001b248f14SClaudio Fontana } 2011b248f14SClaudio Fontana if (pdpe & PG_PSE_MASK) { 2021b248f14SClaudio Fontana /* 1 GB page */ 2031b248f14SClaudio Fontana page_size = 1024 * 1024 * 1024; 2041b248f14SClaudio Fontana pte_addr = pdpe_addr; 2051b248f14SClaudio Fontana pte = pdpe; 2061b248f14SClaudio Fontana goto do_check_protect; 2071b248f14SClaudio Fontana } 2081b248f14SClaudio Fontana } else 2091b248f14SClaudio Fontana #endif 2101b248f14SClaudio Fontana { 2111b248f14SClaudio Fontana pdpe_addr = (env->nested_cr3 & ~0x1f) + ((gphys >> 27) & 0x18); 2121b248f14SClaudio Fontana pdpe = x86_ldq_phys(cs, pdpe_addr); 2131b248f14SClaudio Fontana if (!(pdpe & PG_PRESENT_MASK)) { 2141b248f14SClaudio Fontana goto do_fault; 2151b248f14SClaudio Fontana } 2161b248f14SClaudio Fontana rsvd_mask |= PG_HI_USER_MASK; 2171b248f14SClaudio Fontana if (pdpe & (rsvd_mask | PG_NX_MASK)) { 2181b248f14SClaudio Fontana goto do_fault_rsvd; 2191b248f14SClaudio Fontana } 2201b248f14SClaudio Fontana ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; 2211b248f14SClaudio Fontana } 2221b248f14SClaudio Fontana 2231b248f14SClaudio Fontana pde_addr = (pdpe & PG_ADDRESS_MASK) + (((gphys >> 21) & 0x1ff) << 3); 2241b248f14SClaudio Fontana pde = x86_ldq_phys(cs, pde_addr); 2251b248f14SClaudio Fontana if (!(pde & PG_PRESENT_MASK)) { 2261b248f14SClaudio Fontana goto do_fault; 2271b248f14SClaudio Fontana } 2281b248f14SClaudio Fontana if (pde & rsvd_mask) { 2291b248f14SClaudio Fontana goto do_fault_rsvd; 2301b248f14SClaudio Fontana } 2311b248f14SClaudio Fontana ptep &= pde ^ PG_NX_MASK; 2321b248f14SClaudio Fontana if (pde & PG_PSE_MASK) { 2331b248f14SClaudio Fontana /* 2 MB page */ 2341b248f14SClaudio Fontana page_size = 2048 * 1024; 2351b248f14SClaudio Fontana pte_addr = pde_addr; 2361b248f14SClaudio Fontana pte = pde; 2371b248f14SClaudio Fontana goto do_check_protect; 2381b248f14SClaudio Fontana } 2391b248f14SClaudio Fontana /* 4 KB page */ 2401b248f14SClaudio Fontana if (!(pde & PG_ACCESSED_MASK)) { 2411b248f14SClaudio Fontana pde |= PG_ACCESSED_MASK; 2421b248f14SClaudio Fontana x86_stl_phys_notdirty(cs, pde_addr, pde); 2431b248f14SClaudio Fontana } 2441b248f14SClaudio Fontana pte_addr = (pde & PG_ADDRESS_MASK) + (((gphys >> 12) & 0x1ff) << 3); 2451b248f14SClaudio Fontana pte = x86_ldq_phys(cs, pte_addr); 2461b248f14SClaudio Fontana if (!(pte & PG_PRESENT_MASK)) { 2471b248f14SClaudio Fontana goto do_fault; 2481b248f14SClaudio Fontana } 2491b248f14SClaudio Fontana if (pte & rsvd_mask) { 2501b248f14SClaudio Fontana goto do_fault_rsvd; 2511b248f14SClaudio Fontana } 2521b248f14SClaudio Fontana /* combine pde and pte nx, user and rw protections */ 2531b248f14SClaudio Fontana ptep &= pte ^ PG_NX_MASK; 2541b248f14SClaudio Fontana page_size = 4096; 2551b248f14SClaudio Fontana } else { 2561b248f14SClaudio Fontana uint32_t pde; 2571b248f14SClaudio Fontana 2581b248f14SClaudio Fontana /* page directory entry */ 2591b248f14SClaudio Fontana pde_addr = (env->nested_cr3 & ~0xfff) + ((gphys >> 20) & 0xffc); 2601b248f14SClaudio Fontana pde = x86_ldl_phys(cs, pde_addr); 2611b248f14SClaudio Fontana if (!(pde & PG_PRESENT_MASK)) { 2621b248f14SClaudio Fontana goto do_fault; 2631b248f14SClaudio Fontana } 2641b248f14SClaudio Fontana ptep = pde | PG_NX_MASK; 2651b248f14SClaudio Fontana 2661b248f14SClaudio Fontana /* if host cr4 PSE bit is set, then we use a 4MB page */ 2671b248f14SClaudio Fontana if ((pde & PG_PSE_MASK) && (env->nested_pg_mode & SVM_NPT_PSE)) { 2681b248f14SClaudio Fontana page_size = 4096 * 1024; 2691b248f14SClaudio Fontana pte_addr = pde_addr; 2701b248f14SClaudio Fontana 2711b248f14SClaudio Fontana /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. 2721b248f14SClaudio Fontana * Leave bits 20-13 in place for setting accessed/dirty bits below. 2731b248f14SClaudio Fontana */ 2741b248f14SClaudio Fontana pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); 2751b248f14SClaudio Fontana rsvd_mask = 0x200000; 2761b248f14SClaudio Fontana goto do_check_protect_pse36; 2771b248f14SClaudio Fontana } 2781b248f14SClaudio Fontana 2791b248f14SClaudio Fontana if (!(pde & PG_ACCESSED_MASK)) { 2801b248f14SClaudio Fontana pde |= PG_ACCESSED_MASK; 2811b248f14SClaudio Fontana x86_stl_phys_notdirty(cs, pde_addr, pde); 2821b248f14SClaudio Fontana } 2831b248f14SClaudio Fontana 2841b248f14SClaudio Fontana /* page directory entry */ 2851b248f14SClaudio Fontana pte_addr = (pde & ~0xfff) + ((gphys >> 10) & 0xffc); 2861b248f14SClaudio Fontana pte = x86_ldl_phys(cs, pte_addr); 2871b248f14SClaudio Fontana if (!(pte & PG_PRESENT_MASK)) { 2881b248f14SClaudio Fontana goto do_fault; 2891b248f14SClaudio Fontana } 2901b248f14SClaudio Fontana /* combine pde and pte user and rw protections */ 2911b248f14SClaudio Fontana ptep &= pte | PG_NX_MASK; 2921b248f14SClaudio Fontana page_size = 4096; 2931b248f14SClaudio Fontana rsvd_mask = 0; 2941b248f14SClaudio Fontana } 2951b248f14SClaudio Fontana 2961b248f14SClaudio Fontana do_check_protect: 2971b248f14SClaudio Fontana rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; 2981b248f14SClaudio Fontana do_check_protect_pse36: 2991b248f14SClaudio Fontana if (pte & rsvd_mask) { 3001b248f14SClaudio Fontana goto do_fault_rsvd; 3011b248f14SClaudio Fontana } 3021b248f14SClaudio Fontana ptep ^= PG_NX_MASK; 3031b248f14SClaudio Fontana 3041b248f14SClaudio Fontana if (!(ptep & PG_USER_MASK)) { 3051b248f14SClaudio Fontana goto do_fault_protect; 3061b248f14SClaudio Fontana } 3071b248f14SClaudio Fontana if (ptep & PG_NX_MASK) { 3081b248f14SClaudio Fontana if (access_type == MMU_INST_FETCH) { 3091b248f14SClaudio Fontana goto do_fault_protect; 3101b248f14SClaudio Fontana } 3111b248f14SClaudio Fontana *prot &= ~PAGE_EXEC; 3121b248f14SClaudio Fontana } 3131b248f14SClaudio Fontana if (!(ptep & PG_RW_MASK)) { 3141b248f14SClaudio Fontana if (access_type == MMU_DATA_STORE) { 3151b248f14SClaudio Fontana goto do_fault_protect; 3161b248f14SClaudio Fontana } 3171b248f14SClaudio Fontana *prot &= ~PAGE_WRITE; 3181b248f14SClaudio Fontana } 3191b248f14SClaudio Fontana 3201b248f14SClaudio Fontana pte &= PG_ADDRESS_MASK & ~(page_size - 1); 3211b248f14SClaudio Fontana page_offset = gphys & (page_size - 1); 3221b248f14SClaudio Fontana return pte + page_offset; 3231b248f14SClaudio Fontana 3241b248f14SClaudio Fontana do_fault_rsvd: 3251b248f14SClaudio Fontana exit_info_1 |= SVM_NPTEXIT_RSVD; 3261b248f14SClaudio Fontana do_fault_protect: 3271b248f14SClaudio Fontana exit_info_1 |= SVM_NPTEXIT_P; 3281b248f14SClaudio Fontana do_fault: 3291b248f14SClaudio Fontana x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 3301b248f14SClaudio Fontana gphys); 3311b248f14SClaudio Fontana exit_info_1 |= SVM_NPTEXIT_US; 3321b248f14SClaudio Fontana if (access_type == MMU_DATA_STORE) { 3331b248f14SClaudio Fontana exit_info_1 |= SVM_NPTEXIT_RW; 3341b248f14SClaudio Fontana } else if (access_type == MMU_INST_FETCH) { 3351b248f14SClaudio Fontana exit_info_1 |= SVM_NPTEXIT_ID; 3361b248f14SClaudio Fontana } 3371b248f14SClaudio Fontana if (prot) { 3381b248f14SClaudio Fontana exit_info_1 |= SVM_NPTEXIT_GPA; 3391b248f14SClaudio Fontana } else { /* page table access */ 3401b248f14SClaudio Fontana exit_info_1 |= SVM_NPTEXIT_GPT; 3411b248f14SClaudio Fontana } 3421b248f14SClaudio Fontana cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr); 3431b248f14SClaudio Fontana } 3441b248f14SClaudio Fontana 3451b248f14SClaudio Fontana /* return value: 3461b248f14SClaudio Fontana * -1 = cannot handle fault 3471b248f14SClaudio Fontana * 0 = nothing more to do 3481b248f14SClaudio Fontana * 1 = generate PF fault 3491b248f14SClaudio Fontana */ 3501b248f14SClaudio Fontana static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, 3511b248f14SClaudio Fontana int is_write1, int mmu_idx) 3521b248f14SClaudio Fontana { 3531b248f14SClaudio Fontana X86CPU *cpu = X86_CPU(cs); 3541b248f14SClaudio Fontana CPUX86State *env = &cpu->env; 3551b248f14SClaudio Fontana uint64_t ptep, pte; 3561b248f14SClaudio Fontana int32_t a20_mask; 3571b248f14SClaudio Fontana target_ulong pde_addr, pte_addr; 3581b248f14SClaudio Fontana int error_code = 0; 3591b248f14SClaudio Fontana int is_dirty, prot, page_size, is_write, is_user; 3601b248f14SClaudio Fontana hwaddr paddr; 3611b248f14SClaudio Fontana uint64_t rsvd_mask = PG_HI_RSVD_MASK; 3621b248f14SClaudio Fontana uint32_t page_offset; 3631b248f14SClaudio Fontana target_ulong vaddr; 3641b248f14SClaudio Fontana 3651b248f14SClaudio Fontana is_user = mmu_idx == MMU_USER_IDX; 3661b248f14SClaudio Fontana #if defined(DEBUG_MMU) 3671b248f14SClaudio Fontana printf("MMU fault: addr=%" VADDR_PRIx " w=%d u=%d eip=" TARGET_FMT_lx "\n", 3681b248f14SClaudio Fontana addr, is_write1, is_user, env->eip); 3691b248f14SClaudio Fontana #endif 3701b248f14SClaudio Fontana is_write = is_write1 & 1; 3711b248f14SClaudio Fontana 3721b248f14SClaudio Fontana a20_mask = x86_get_a20_mask(env); 3731b248f14SClaudio Fontana if (!(env->cr[0] & CR0_PG_MASK)) { 3741b248f14SClaudio Fontana pte = addr; 3751b248f14SClaudio Fontana #ifdef TARGET_X86_64 3761b248f14SClaudio Fontana if (!(env->hflags & HF_LMA_MASK)) { 3771b248f14SClaudio Fontana /* Without long mode we can only address 32bits in real mode */ 3781b248f14SClaudio Fontana pte = (uint32_t)pte; 3791b248f14SClaudio Fontana } 3801b248f14SClaudio Fontana #endif 3811b248f14SClaudio Fontana prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 3821b248f14SClaudio Fontana page_size = 4096; 3831b248f14SClaudio Fontana goto do_mapping; 3841b248f14SClaudio Fontana } 3851b248f14SClaudio Fontana 3861b248f14SClaudio Fontana if (!(env->efer & MSR_EFER_NXE)) { 3871b248f14SClaudio Fontana rsvd_mask |= PG_NX_MASK; 3881b248f14SClaudio Fontana } 3891b248f14SClaudio Fontana 3901b248f14SClaudio Fontana if (env->cr[4] & CR4_PAE_MASK) { 3911b248f14SClaudio Fontana uint64_t pde, pdpe; 3921b248f14SClaudio Fontana target_ulong pdpe_addr; 3931b248f14SClaudio Fontana 3941b248f14SClaudio Fontana #ifdef TARGET_X86_64 3951b248f14SClaudio Fontana if (env->hflags & HF_LMA_MASK) { 3961b248f14SClaudio Fontana bool la57 = env->cr[4] & CR4_LA57_MASK; 3971b248f14SClaudio Fontana uint64_t pml5e_addr, pml5e; 3981b248f14SClaudio Fontana uint64_t pml4e_addr, pml4e; 3991b248f14SClaudio Fontana int32_t sext; 4001b248f14SClaudio Fontana 4011b248f14SClaudio Fontana /* test virtual address sign extension */ 4021b248f14SClaudio Fontana sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47; 4031b248f14SClaudio Fontana if (sext != 0 && sext != -1) { 4041b248f14SClaudio Fontana env->error_code = 0; 4051b248f14SClaudio Fontana cs->exception_index = EXCP0D_GPF; 4061b248f14SClaudio Fontana return 1; 4071b248f14SClaudio Fontana } 4081b248f14SClaudio Fontana 4091b248f14SClaudio Fontana if (la57) { 4101b248f14SClaudio Fontana pml5e_addr = ((env->cr[3] & ~0xfff) + 4111b248f14SClaudio Fontana (((addr >> 48) & 0x1ff) << 3)) & a20_mask; 4121b248f14SClaudio Fontana pml5e_addr = get_hphys(cs, pml5e_addr, MMU_DATA_STORE, NULL); 4131b248f14SClaudio Fontana pml5e = x86_ldq_phys(cs, pml5e_addr); 4141b248f14SClaudio Fontana if (!(pml5e & PG_PRESENT_MASK)) { 4151b248f14SClaudio Fontana goto do_fault; 4161b248f14SClaudio Fontana } 4171b248f14SClaudio Fontana if (pml5e & (rsvd_mask | PG_PSE_MASK)) { 4181b248f14SClaudio Fontana goto do_fault_rsvd; 4191b248f14SClaudio Fontana } 4201b248f14SClaudio Fontana if (!(pml5e & PG_ACCESSED_MASK)) { 4211b248f14SClaudio Fontana pml5e |= PG_ACCESSED_MASK; 4221b248f14SClaudio Fontana x86_stl_phys_notdirty(cs, pml5e_addr, pml5e); 4231b248f14SClaudio Fontana } 4241b248f14SClaudio Fontana ptep = pml5e ^ PG_NX_MASK; 4251b248f14SClaudio Fontana } else { 4261b248f14SClaudio Fontana pml5e = env->cr[3]; 4271b248f14SClaudio Fontana ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; 4281b248f14SClaudio Fontana } 4291b248f14SClaudio Fontana 4301b248f14SClaudio Fontana pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + 4311b248f14SClaudio Fontana (((addr >> 39) & 0x1ff) << 3)) & a20_mask; 4321b248f14SClaudio Fontana pml4e_addr = get_hphys(cs, pml4e_addr, MMU_DATA_STORE, false); 4331b248f14SClaudio Fontana pml4e = x86_ldq_phys(cs, pml4e_addr); 4341b248f14SClaudio Fontana if (!(pml4e & PG_PRESENT_MASK)) { 4351b248f14SClaudio Fontana goto do_fault; 4361b248f14SClaudio Fontana } 4371b248f14SClaudio Fontana if (pml4e & (rsvd_mask | PG_PSE_MASK)) { 4381b248f14SClaudio Fontana goto do_fault_rsvd; 4391b248f14SClaudio Fontana } 4401b248f14SClaudio Fontana if (!(pml4e & PG_ACCESSED_MASK)) { 4411b248f14SClaudio Fontana pml4e |= PG_ACCESSED_MASK; 4421b248f14SClaudio Fontana x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); 4431b248f14SClaudio Fontana } 4441b248f14SClaudio Fontana ptep &= pml4e ^ PG_NX_MASK; 4451b248f14SClaudio Fontana pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & 4461b248f14SClaudio Fontana a20_mask; 4471b248f14SClaudio Fontana pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, NULL); 4481b248f14SClaudio Fontana pdpe = x86_ldq_phys(cs, pdpe_addr); 4491b248f14SClaudio Fontana if (!(pdpe & PG_PRESENT_MASK)) { 4501b248f14SClaudio Fontana goto do_fault; 4511b248f14SClaudio Fontana } 4521b248f14SClaudio Fontana if (pdpe & rsvd_mask) { 4531b248f14SClaudio Fontana goto do_fault_rsvd; 4541b248f14SClaudio Fontana } 4551b248f14SClaudio Fontana ptep &= pdpe ^ PG_NX_MASK; 4561b248f14SClaudio Fontana if (!(pdpe & PG_ACCESSED_MASK)) { 4571b248f14SClaudio Fontana pdpe |= PG_ACCESSED_MASK; 4581b248f14SClaudio Fontana x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); 4591b248f14SClaudio Fontana } 4601b248f14SClaudio Fontana if (pdpe & PG_PSE_MASK) { 4611b248f14SClaudio Fontana /* 1 GB page */ 4621b248f14SClaudio Fontana page_size = 1024 * 1024 * 1024; 4631b248f14SClaudio Fontana pte_addr = pdpe_addr; 4641b248f14SClaudio Fontana pte = pdpe; 4651b248f14SClaudio Fontana goto do_check_protect; 4661b248f14SClaudio Fontana } 4671b248f14SClaudio Fontana } else 4681b248f14SClaudio Fontana #endif 4691b248f14SClaudio Fontana { 4701b248f14SClaudio Fontana /* XXX: load them when cr3 is loaded ? */ 4711b248f14SClaudio Fontana pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & 4721b248f14SClaudio Fontana a20_mask; 4731b248f14SClaudio Fontana pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, false); 4741b248f14SClaudio Fontana pdpe = x86_ldq_phys(cs, pdpe_addr); 4751b248f14SClaudio Fontana if (!(pdpe & PG_PRESENT_MASK)) { 4761b248f14SClaudio Fontana goto do_fault; 4771b248f14SClaudio Fontana } 4781b248f14SClaudio Fontana rsvd_mask |= PG_HI_USER_MASK; 4791b248f14SClaudio Fontana if (pdpe & (rsvd_mask | PG_NX_MASK)) { 4801b248f14SClaudio Fontana goto do_fault_rsvd; 4811b248f14SClaudio Fontana } 4821b248f14SClaudio Fontana ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; 4831b248f14SClaudio Fontana } 4841b248f14SClaudio Fontana 4851b248f14SClaudio Fontana pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & 4861b248f14SClaudio Fontana a20_mask; 4871b248f14SClaudio Fontana pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL); 4881b248f14SClaudio Fontana pde = x86_ldq_phys(cs, pde_addr); 4891b248f14SClaudio Fontana if (!(pde & PG_PRESENT_MASK)) { 4901b248f14SClaudio Fontana goto do_fault; 4911b248f14SClaudio Fontana } 4921b248f14SClaudio Fontana if (pde & rsvd_mask) { 4931b248f14SClaudio Fontana goto do_fault_rsvd; 4941b248f14SClaudio Fontana } 4951b248f14SClaudio Fontana ptep &= pde ^ PG_NX_MASK; 4961b248f14SClaudio Fontana if (pde & PG_PSE_MASK) { 4971b248f14SClaudio Fontana /* 2 MB page */ 4981b248f14SClaudio Fontana page_size = 2048 * 1024; 4991b248f14SClaudio Fontana pte_addr = pde_addr; 5001b248f14SClaudio Fontana pte = pde; 5011b248f14SClaudio Fontana goto do_check_protect; 5021b248f14SClaudio Fontana } 5031b248f14SClaudio Fontana /* 4 KB page */ 5041b248f14SClaudio Fontana if (!(pde & PG_ACCESSED_MASK)) { 5051b248f14SClaudio Fontana pde |= PG_ACCESSED_MASK; 5061b248f14SClaudio Fontana x86_stl_phys_notdirty(cs, pde_addr, pde); 5071b248f14SClaudio Fontana } 5081b248f14SClaudio Fontana pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & 5091b248f14SClaudio Fontana a20_mask; 5101b248f14SClaudio Fontana pte_addr = get_hphys(cs, pte_addr, MMU_DATA_STORE, NULL); 5111b248f14SClaudio Fontana pte = x86_ldq_phys(cs, pte_addr); 5121b248f14SClaudio Fontana if (!(pte & PG_PRESENT_MASK)) { 5131b248f14SClaudio Fontana goto do_fault; 5141b248f14SClaudio Fontana } 5151b248f14SClaudio Fontana if (pte & rsvd_mask) { 5161b248f14SClaudio Fontana goto do_fault_rsvd; 5171b248f14SClaudio Fontana } 5181b248f14SClaudio Fontana /* combine pde and pte nx, user and rw protections */ 5191b248f14SClaudio Fontana ptep &= pte ^ PG_NX_MASK; 5201b248f14SClaudio Fontana page_size = 4096; 5211b248f14SClaudio Fontana } else { 5221b248f14SClaudio Fontana uint32_t pde; 5231b248f14SClaudio Fontana 5241b248f14SClaudio Fontana /* page directory entry */ 5251b248f14SClaudio Fontana pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & 5261b248f14SClaudio Fontana a20_mask; 5271b248f14SClaudio Fontana pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL); 5281b248f14SClaudio Fontana pde = x86_ldl_phys(cs, pde_addr); 5291b248f14SClaudio Fontana if (!(pde & PG_PRESENT_MASK)) { 5301b248f14SClaudio Fontana goto do_fault; 5311b248f14SClaudio Fontana } 5321b248f14SClaudio Fontana ptep = pde | PG_NX_MASK; 5331b248f14SClaudio Fontana 5341b248f14SClaudio Fontana /* if PSE bit is set, then we use a 4MB page */ 5351b248f14SClaudio Fontana if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { 5361b248f14SClaudio Fontana page_size = 4096 * 1024; 5371b248f14SClaudio Fontana pte_addr = pde_addr; 5381b248f14SClaudio Fontana 5391b248f14SClaudio Fontana /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. 5401b248f14SClaudio Fontana * Leave bits 20-13 in place for setting accessed/dirty bits below. 5411b248f14SClaudio Fontana */ 5421b248f14SClaudio Fontana pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); 5431b248f14SClaudio Fontana rsvd_mask = 0x200000; 5441b248f14SClaudio Fontana goto do_check_protect_pse36; 5451b248f14SClaudio Fontana } 5461b248f14SClaudio Fontana 5471b248f14SClaudio Fontana if (!(pde & PG_ACCESSED_MASK)) { 5481b248f14SClaudio Fontana pde |= PG_ACCESSED_MASK; 5491b248f14SClaudio Fontana x86_stl_phys_notdirty(cs, pde_addr, pde); 5501b248f14SClaudio Fontana } 5511b248f14SClaudio Fontana 5521b248f14SClaudio Fontana /* page directory entry */ 5531b248f14SClaudio Fontana pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & 5541b248f14SClaudio Fontana a20_mask; 5551b248f14SClaudio Fontana pte_addr = get_hphys(cs, pte_addr, MMU_DATA_STORE, NULL); 5561b248f14SClaudio Fontana pte = x86_ldl_phys(cs, pte_addr); 5571b248f14SClaudio Fontana if (!(pte & PG_PRESENT_MASK)) { 5581b248f14SClaudio Fontana goto do_fault; 5591b248f14SClaudio Fontana } 5601b248f14SClaudio Fontana /* combine pde and pte user and rw protections */ 5611b248f14SClaudio Fontana ptep &= pte | PG_NX_MASK; 5621b248f14SClaudio Fontana page_size = 4096; 5631b248f14SClaudio Fontana rsvd_mask = 0; 5641b248f14SClaudio Fontana } 5651b248f14SClaudio Fontana 5661b248f14SClaudio Fontana do_check_protect: 5671b248f14SClaudio Fontana rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; 5681b248f14SClaudio Fontana do_check_protect_pse36: 5691b248f14SClaudio Fontana if (pte & rsvd_mask) { 5701b248f14SClaudio Fontana goto do_fault_rsvd; 5711b248f14SClaudio Fontana } 5721b248f14SClaudio Fontana ptep ^= PG_NX_MASK; 5731b248f14SClaudio Fontana 5741b248f14SClaudio Fontana /* can the page can be put in the TLB? prot will tell us */ 5751b248f14SClaudio Fontana if (is_user && !(ptep & PG_USER_MASK)) { 5761b248f14SClaudio Fontana goto do_fault_protect; 5771b248f14SClaudio Fontana } 5781b248f14SClaudio Fontana 5791b248f14SClaudio Fontana prot = 0; 5801b248f14SClaudio Fontana if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { 5811b248f14SClaudio Fontana prot |= PAGE_READ; 5821b248f14SClaudio Fontana if ((ptep & PG_RW_MASK) || (!is_user && !(env->cr[0] & CR0_WP_MASK))) { 5831b248f14SClaudio Fontana prot |= PAGE_WRITE; 5841b248f14SClaudio Fontana } 5851b248f14SClaudio Fontana } 5861b248f14SClaudio Fontana if (!(ptep & PG_NX_MASK) && 5871b248f14SClaudio Fontana (mmu_idx == MMU_USER_IDX || 5881b248f14SClaudio Fontana !((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK)))) { 5891b248f14SClaudio Fontana prot |= PAGE_EXEC; 5901b248f14SClaudio Fontana } 5911b248f14SClaudio Fontana if ((env->cr[4] & CR4_PKE_MASK) && (env->hflags & HF_LMA_MASK) && 5921b248f14SClaudio Fontana (ptep & PG_USER_MASK) && env->pkru) { 5931b248f14SClaudio Fontana uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT; 5941b248f14SClaudio Fontana uint32_t pkru_ad = (env->pkru >> pk * 2) & 1; 5951b248f14SClaudio Fontana uint32_t pkru_wd = (env->pkru >> pk * 2) & 2; 5961b248f14SClaudio Fontana uint32_t pkru_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 5971b248f14SClaudio Fontana 5981b248f14SClaudio Fontana if (pkru_ad) { 5991b248f14SClaudio Fontana pkru_prot &= ~(PAGE_READ | PAGE_WRITE); 6001b248f14SClaudio Fontana } else if (pkru_wd && (is_user || env->cr[0] & CR0_WP_MASK)) { 6011b248f14SClaudio Fontana pkru_prot &= ~PAGE_WRITE; 6021b248f14SClaudio Fontana } 6031b248f14SClaudio Fontana 6041b248f14SClaudio Fontana prot &= pkru_prot; 6051b248f14SClaudio Fontana if ((pkru_prot & (1 << is_write1)) == 0) { 6061b248f14SClaudio Fontana assert(is_write1 != 2); 6071b248f14SClaudio Fontana error_code |= PG_ERROR_PK_MASK; 6081b248f14SClaudio Fontana goto do_fault_protect; 6091b248f14SClaudio Fontana } 6101b248f14SClaudio Fontana } 6111b248f14SClaudio Fontana 6121b248f14SClaudio Fontana if ((prot & (1 << is_write1)) == 0) { 6131b248f14SClaudio Fontana goto do_fault_protect; 6141b248f14SClaudio Fontana } 6151b248f14SClaudio Fontana 6161b248f14SClaudio Fontana /* yes, it can! */ 6171b248f14SClaudio Fontana is_dirty = is_write && !(pte & PG_DIRTY_MASK); 6181b248f14SClaudio Fontana if (!(pte & PG_ACCESSED_MASK) || is_dirty) { 6191b248f14SClaudio Fontana pte |= PG_ACCESSED_MASK; 6201b248f14SClaudio Fontana if (is_dirty) { 6211b248f14SClaudio Fontana pte |= PG_DIRTY_MASK; 6221b248f14SClaudio Fontana } 6231b248f14SClaudio Fontana x86_stl_phys_notdirty(cs, pte_addr, pte); 6241b248f14SClaudio Fontana } 6251b248f14SClaudio Fontana 6261b248f14SClaudio Fontana if (!(pte & PG_DIRTY_MASK)) { 6271b248f14SClaudio Fontana /* only set write access if already dirty... otherwise wait 6281b248f14SClaudio Fontana for dirty access */ 6291b248f14SClaudio Fontana assert(!is_write); 6301b248f14SClaudio Fontana prot &= ~PAGE_WRITE; 6311b248f14SClaudio Fontana } 6321b248f14SClaudio Fontana 6331b248f14SClaudio Fontana do_mapping: 6341b248f14SClaudio Fontana pte = pte & a20_mask; 6351b248f14SClaudio Fontana 6361b248f14SClaudio Fontana /* align to page_size */ 6371b248f14SClaudio Fontana pte &= PG_ADDRESS_MASK & ~(page_size - 1); 6381b248f14SClaudio Fontana page_offset = addr & (page_size - 1); 6391b248f14SClaudio Fontana paddr = get_hphys(cs, pte + page_offset, is_write1, &prot); 6401b248f14SClaudio Fontana 6411b248f14SClaudio Fontana /* Even if 4MB pages, we map only one 4KB page in the cache to 6421b248f14SClaudio Fontana avoid filling it too fast */ 6431b248f14SClaudio Fontana vaddr = addr & TARGET_PAGE_MASK; 6441b248f14SClaudio Fontana paddr &= TARGET_PAGE_MASK; 6451b248f14SClaudio Fontana 6461b248f14SClaudio Fontana assert(prot & (1 << is_write1)); 6471b248f14SClaudio Fontana tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env), 6481b248f14SClaudio Fontana prot, mmu_idx, page_size); 6491b248f14SClaudio Fontana return 0; 6501b248f14SClaudio Fontana do_fault_rsvd: 6511b248f14SClaudio Fontana error_code |= PG_ERROR_RSVD_MASK; 6521b248f14SClaudio Fontana do_fault_protect: 6531b248f14SClaudio Fontana error_code |= PG_ERROR_P_MASK; 6541b248f14SClaudio Fontana do_fault: 6551b248f14SClaudio Fontana error_code |= (is_write << PG_ERROR_W_BIT); 6561b248f14SClaudio Fontana if (is_user) 6571b248f14SClaudio Fontana error_code |= PG_ERROR_U_MASK; 6581b248f14SClaudio Fontana if (is_write1 == 2 && 6591b248f14SClaudio Fontana (((env->efer & MSR_EFER_NXE) && 6601b248f14SClaudio Fontana (env->cr[4] & CR4_PAE_MASK)) || 6611b248f14SClaudio Fontana (env->cr[4] & CR4_SMEP_MASK))) 6621b248f14SClaudio Fontana error_code |= PG_ERROR_I_D_MASK; 6631b248f14SClaudio Fontana if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) { 6641b248f14SClaudio Fontana /* cr2 is not modified in case of exceptions */ 6651b248f14SClaudio Fontana x86_stq_phys(cs, 6661b248f14SClaudio Fontana env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 6671b248f14SClaudio Fontana addr); 6681b248f14SClaudio Fontana } else { 6691b248f14SClaudio Fontana env->cr[2] = addr; 6701b248f14SClaudio Fontana } 6711b248f14SClaudio Fontana env->error_code = error_code; 6721b248f14SClaudio Fontana cs->exception_index = EXCP0E_PAGE; 6731b248f14SClaudio Fontana return 1; 6741b248f14SClaudio Fontana } 6751b248f14SClaudio Fontana #endif 6761b248f14SClaudio Fontana 6771b248f14SClaudio Fontana bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, 6781b248f14SClaudio Fontana MMUAccessType access_type, int mmu_idx, 6791b248f14SClaudio Fontana bool probe, uintptr_t retaddr) 6801b248f14SClaudio Fontana { 6811b248f14SClaudio Fontana X86CPU *cpu = X86_CPU(cs); 6821b248f14SClaudio Fontana CPUX86State *env = &cpu->env; 6831b248f14SClaudio Fontana 6841b248f14SClaudio Fontana #ifdef CONFIG_USER_ONLY 6851b248f14SClaudio Fontana /* user mode only emulation */ 6861b248f14SClaudio Fontana env->cr[2] = addr; 6871b248f14SClaudio Fontana env->error_code = (access_type == MMU_DATA_STORE) << PG_ERROR_W_BIT; 6881b248f14SClaudio Fontana env->error_code |= PG_ERROR_U_MASK; 6891b248f14SClaudio Fontana cs->exception_index = EXCP0E_PAGE; 6901b248f14SClaudio Fontana env->exception_is_int = 0; 6911b248f14SClaudio Fontana env->exception_next_eip = -1; 6921b248f14SClaudio Fontana cpu_loop_exit_restore(cs, retaddr); 6931b248f14SClaudio Fontana #else 6941b248f14SClaudio Fontana env->retaddr = retaddr; 6951b248f14SClaudio Fontana if (handle_mmu_fault(cs, addr, size, access_type, mmu_idx)) { 6961b248f14SClaudio Fontana /* FIXME: On error in get_hphys we have already jumped out. */ 6971b248f14SClaudio Fontana g_assert(!probe); 6981b248f14SClaudio Fontana raise_exception_err_ra(env, cs->exception_index, 6991b248f14SClaudio Fontana env->error_code, retaddr); 7001b248f14SClaudio Fontana } 7011b248f14SClaudio Fontana return true; 7021b248f14SClaudio Fontana #endif 7031b248f14SClaudio Fontana } 704