1e7f2670fSClaudio Fontana /* 2e7f2670fSClaudio Fontana * x86 exception helpers - sysemu code 3e7f2670fSClaudio Fontana * 4e7f2670fSClaudio Fontana * Copyright (c) 2003 Fabrice Bellard 5e7f2670fSClaudio Fontana * 6e7f2670fSClaudio Fontana * This library is free software; you can redistribute it and/or 7e7f2670fSClaudio Fontana * modify it under the terms of the GNU Lesser General Public 8e7f2670fSClaudio Fontana * License as published by the Free Software Foundation; either 9e7f2670fSClaudio Fontana * version 2.1 of the License, or (at your option) any later version. 10e7f2670fSClaudio Fontana * 11e7f2670fSClaudio Fontana * This library is distributed in the hope that it will be useful, 12e7f2670fSClaudio Fontana * but WITHOUT ANY WARRANTY; without even the implied warranty of 13e7f2670fSClaudio Fontana * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14e7f2670fSClaudio Fontana * Lesser General Public License for more details. 15e7f2670fSClaudio Fontana * 16e7f2670fSClaudio Fontana * You should have received a copy of the GNU Lesser General Public 17e7f2670fSClaudio Fontana * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18e7f2670fSClaudio Fontana */ 19e7f2670fSClaudio Fontana 20e7f2670fSClaudio Fontana #include "qemu/osdep.h" 21e7f2670fSClaudio Fontana #include "cpu.h" 22b28b366dSPhilippe Mathieu-Daudé #include "exec/exec-all.h" 23e7f2670fSClaudio Fontana #include "tcg/helper-tcg.h" 24e7f2670fSClaudio Fontana 25*3563362dSRichard Henderson typedef struct TranslateParams { 26*3563362dSRichard Henderson target_ulong addr; 27*3563362dSRichard Henderson target_ulong cr3; 28*3563362dSRichard Henderson int pg_mode; 29*3563362dSRichard Henderson int mmu_idx; 30*3563362dSRichard Henderson MMUAccessType access_type; 31*3563362dSRichard Henderson bool use_stage2; 32*3563362dSRichard Henderson } TranslateParams; 33*3563362dSRichard Henderson 34*3563362dSRichard Henderson typedef struct TranslateResult { 35*3563362dSRichard Henderson hwaddr paddr; 36*3563362dSRichard Henderson int prot; 37*3563362dSRichard Henderson int page_size; 38*3563362dSRichard Henderson } TranslateResult; 39*3563362dSRichard Henderson 40*3563362dSRichard Henderson typedef struct TranslateFault { 41*3563362dSRichard Henderson int exception_index; 42*3563362dSRichard Henderson int error_code; 43*3563362dSRichard Henderson target_ulong cr2; 44*3563362dSRichard Henderson } TranslateFault; 45661ff487SPaolo Bonzini 4633ce155cSPaolo Bonzini #define GET_HPHYS(cs, gpa, access_type, prot) \ 47*3563362dSRichard Henderson (in->use_stage2 ? get_hphys(cs, gpa, access_type, prot) : gpa) 4833ce155cSPaolo Bonzini 49*3563362dSRichard Henderson static bool mmu_translate(CPUX86State *env, const TranslateParams *in, 50*3563362dSRichard Henderson TranslateResult *out, TranslateFault *err) 51e7f2670fSClaudio Fontana { 52*3563362dSRichard Henderson CPUState *cs = env_cpu(env); 53*3563362dSRichard Henderson X86CPU *cpu = env_archcpu(env); 54*3563362dSRichard Henderson const int32_t a20_mask = x86_get_a20_mask(env); 55*3563362dSRichard Henderson const target_ulong addr = in->addr; 56*3563362dSRichard Henderson const int pg_mode = in->pg_mode; 57*3563362dSRichard Henderson const bool is_user = (in->mmu_idx == MMU_USER_IDX); 58*3563362dSRichard Henderson const MMUAccessType access_type = in->access_type; 59e7f2670fSClaudio Fontana uint64_t ptep, pte; 60*3563362dSRichard Henderson hwaddr pde_addr, pte_addr; 61e7f2670fSClaudio Fontana uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); 62e7f2670fSClaudio Fontana uint32_t pkr; 63*3563362dSRichard Henderson int page_size; 64e7f2670fSClaudio Fontana 6531dd35ebSPaolo Bonzini if (!(pg_mode & PG_MODE_NXE)) { 66e7f2670fSClaudio Fontana rsvd_mask |= PG_NX_MASK; 67e7f2670fSClaudio Fontana } 68e7f2670fSClaudio Fontana 6931dd35ebSPaolo Bonzini if (pg_mode & PG_MODE_PAE) { 70e7f2670fSClaudio Fontana uint64_t pde, pdpe; 71e7f2670fSClaudio Fontana target_ulong pdpe_addr; 72e7f2670fSClaudio Fontana 73e7f2670fSClaudio Fontana #ifdef TARGET_X86_64 7493eae358SPaolo Bonzini if (pg_mode & PG_MODE_LMA) { 7531dd35ebSPaolo Bonzini bool la57 = pg_mode & PG_MODE_LA57; 76e7f2670fSClaudio Fontana uint64_t pml5e_addr, pml5e; 77e7f2670fSClaudio Fontana uint64_t pml4e_addr, pml4e; 78e7f2670fSClaudio Fontana 79e7f2670fSClaudio Fontana if (la57) { 80*3563362dSRichard Henderson pml5e_addr = ((in->cr3 & ~0xfff) + 81e7f2670fSClaudio Fontana (((addr >> 48) & 0x1ff) << 3)) & a20_mask; 8233ce155cSPaolo Bonzini pml5e_addr = GET_HPHYS(cs, pml5e_addr, MMU_DATA_STORE, NULL); 83e7f2670fSClaudio Fontana pml5e = x86_ldq_phys(cs, pml5e_addr); 84e7f2670fSClaudio Fontana if (!(pml5e & PG_PRESENT_MASK)) { 85e7f2670fSClaudio Fontana goto do_fault; 86e7f2670fSClaudio Fontana } 87e7f2670fSClaudio Fontana if (pml5e & (rsvd_mask | PG_PSE_MASK)) { 88e7f2670fSClaudio Fontana goto do_fault_rsvd; 89e7f2670fSClaudio Fontana } 90e7f2670fSClaudio Fontana if (!(pml5e & PG_ACCESSED_MASK)) { 91e7f2670fSClaudio Fontana pml5e |= PG_ACCESSED_MASK; 92e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pml5e_addr, pml5e); 93e7f2670fSClaudio Fontana } 94e7f2670fSClaudio Fontana ptep = pml5e ^ PG_NX_MASK; 95e7f2670fSClaudio Fontana } else { 96*3563362dSRichard Henderson pml5e = in->cr3; 97e7f2670fSClaudio Fontana ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; 98e7f2670fSClaudio Fontana } 99e7f2670fSClaudio Fontana 100e7f2670fSClaudio Fontana pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + 101e7f2670fSClaudio Fontana (((addr >> 39) & 0x1ff) << 3)) & a20_mask; 10233ce155cSPaolo Bonzini pml4e_addr = GET_HPHYS(cs, pml4e_addr, MMU_DATA_STORE, NULL); 103e7f2670fSClaudio Fontana pml4e = x86_ldq_phys(cs, pml4e_addr); 104e7f2670fSClaudio Fontana if (!(pml4e & PG_PRESENT_MASK)) { 105e7f2670fSClaudio Fontana goto do_fault; 106e7f2670fSClaudio Fontana } 107e7f2670fSClaudio Fontana if (pml4e & (rsvd_mask | PG_PSE_MASK)) { 108e7f2670fSClaudio Fontana goto do_fault_rsvd; 109e7f2670fSClaudio Fontana } 110e7f2670fSClaudio Fontana if (!(pml4e & PG_ACCESSED_MASK)) { 111e7f2670fSClaudio Fontana pml4e |= PG_ACCESSED_MASK; 112e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); 113e7f2670fSClaudio Fontana } 114e7f2670fSClaudio Fontana ptep &= pml4e ^ PG_NX_MASK; 115e7f2670fSClaudio Fontana pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & 116e7f2670fSClaudio Fontana a20_mask; 11733ce155cSPaolo Bonzini pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL); 118e7f2670fSClaudio Fontana pdpe = x86_ldq_phys(cs, pdpe_addr); 119e7f2670fSClaudio Fontana if (!(pdpe & PG_PRESENT_MASK)) { 120e7f2670fSClaudio Fontana goto do_fault; 121e7f2670fSClaudio Fontana } 122e7f2670fSClaudio Fontana if (pdpe & rsvd_mask) { 123e7f2670fSClaudio Fontana goto do_fault_rsvd; 124e7f2670fSClaudio Fontana } 125e7f2670fSClaudio Fontana ptep &= pdpe ^ PG_NX_MASK; 126e7f2670fSClaudio Fontana if (!(pdpe & PG_ACCESSED_MASK)) { 127e7f2670fSClaudio Fontana pdpe |= PG_ACCESSED_MASK; 128e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); 129e7f2670fSClaudio Fontana } 130e7f2670fSClaudio Fontana if (pdpe & PG_PSE_MASK) { 131e7f2670fSClaudio Fontana /* 1 GB page */ 132*3563362dSRichard Henderson page_size = 1024 * 1024 * 1024; 133e7f2670fSClaudio Fontana pte_addr = pdpe_addr; 134e7f2670fSClaudio Fontana pte = pdpe; 135e7f2670fSClaudio Fontana goto do_check_protect; 136e7f2670fSClaudio Fontana } 137e7f2670fSClaudio Fontana } else 138e7f2670fSClaudio Fontana #endif 139e7f2670fSClaudio Fontana { 140e7f2670fSClaudio Fontana /* XXX: load them when cr3 is loaded ? */ 141*3563362dSRichard Henderson pdpe_addr = ((in->cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & 142e7f2670fSClaudio Fontana a20_mask; 14333ce155cSPaolo Bonzini pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL); 144e7f2670fSClaudio Fontana pdpe = x86_ldq_phys(cs, pdpe_addr); 145e7f2670fSClaudio Fontana if (!(pdpe & PG_PRESENT_MASK)) { 146e7f2670fSClaudio Fontana goto do_fault; 147e7f2670fSClaudio Fontana } 148e7f2670fSClaudio Fontana rsvd_mask |= PG_HI_USER_MASK; 149e7f2670fSClaudio Fontana if (pdpe & (rsvd_mask | PG_NX_MASK)) { 150e7f2670fSClaudio Fontana goto do_fault_rsvd; 151e7f2670fSClaudio Fontana } 152e7f2670fSClaudio Fontana ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; 153e7f2670fSClaudio Fontana } 154e7f2670fSClaudio Fontana 155e7f2670fSClaudio Fontana pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & 156e7f2670fSClaudio Fontana a20_mask; 15733ce155cSPaolo Bonzini pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL); 158e7f2670fSClaudio Fontana pde = x86_ldq_phys(cs, pde_addr); 159e7f2670fSClaudio Fontana if (!(pde & PG_PRESENT_MASK)) { 160e7f2670fSClaudio Fontana goto do_fault; 161e7f2670fSClaudio Fontana } 162e7f2670fSClaudio Fontana if (pde & rsvd_mask) { 163e7f2670fSClaudio Fontana goto do_fault_rsvd; 164e7f2670fSClaudio Fontana } 165e7f2670fSClaudio Fontana ptep &= pde ^ PG_NX_MASK; 166e7f2670fSClaudio Fontana if (pde & PG_PSE_MASK) { 167e7f2670fSClaudio Fontana /* 2 MB page */ 168*3563362dSRichard Henderson page_size = 2048 * 1024; 169e7f2670fSClaudio Fontana pte_addr = pde_addr; 170e7f2670fSClaudio Fontana pte = pde; 171e7f2670fSClaudio Fontana goto do_check_protect; 172e7f2670fSClaudio Fontana } 173e7f2670fSClaudio Fontana /* 4 KB page */ 174e7f2670fSClaudio Fontana if (!(pde & PG_ACCESSED_MASK)) { 175e7f2670fSClaudio Fontana pde |= PG_ACCESSED_MASK; 176e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pde_addr, pde); 177e7f2670fSClaudio Fontana } 178e7f2670fSClaudio Fontana pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & 179e7f2670fSClaudio Fontana a20_mask; 18033ce155cSPaolo Bonzini pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL); 181e7f2670fSClaudio Fontana pte = x86_ldq_phys(cs, pte_addr); 182e7f2670fSClaudio Fontana if (!(pte & PG_PRESENT_MASK)) { 183e7f2670fSClaudio Fontana goto do_fault; 184e7f2670fSClaudio Fontana } 185e7f2670fSClaudio Fontana if (pte & rsvd_mask) { 186e7f2670fSClaudio Fontana goto do_fault_rsvd; 187e7f2670fSClaudio Fontana } 188e7f2670fSClaudio Fontana /* combine pde and pte nx, user and rw protections */ 189e7f2670fSClaudio Fontana ptep &= pte ^ PG_NX_MASK; 190*3563362dSRichard Henderson page_size = 4096; 191e7f2670fSClaudio Fontana } else { 192e7f2670fSClaudio Fontana uint32_t pde; 193e7f2670fSClaudio Fontana 194e7f2670fSClaudio Fontana /* page directory entry */ 195*3563362dSRichard Henderson pde_addr = ((in->cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & 196e7f2670fSClaudio Fontana a20_mask; 19733ce155cSPaolo Bonzini pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL); 198e7f2670fSClaudio Fontana pde = x86_ldl_phys(cs, pde_addr); 199e7f2670fSClaudio Fontana if (!(pde & PG_PRESENT_MASK)) { 200e7f2670fSClaudio Fontana goto do_fault; 201e7f2670fSClaudio Fontana } 202e7f2670fSClaudio Fontana ptep = pde | PG_NX_MASK; 203e7f2670fSClaudio Fontana 204e7f2670fSClaudio Fontana /* if PSE bit is set, then we use a 4MB page */ 20531dd35ebSPaolo Bonzini if ((pde & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) { 206*3563362dSRichard Henderson page_size = 4096 * 1024; 207e7f2670fSClaudio Fontana pte_addr = pde_addr; 208e7f2670fSClaudio Fontana 209e7f2670fSClaudio Fontana /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. 210e7f2670fSClaudio Fontana * Leave bits 20-13 in place for setting accessed/dirty bits below. 211e7f2670fSClaudio Fontana */ 212e7f2670fSClaudio Fontana pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); 213e7f2670fSClaudio Fontana rsvd_mask = 0x200000; 214e7f2670fSClaudio Fontana goto do_check_protect_pse36; 215e7f2670fSClaudio Fontana } 216e7f2670fSClaudio Fontana 217e7f2670fSClaudio Fontana if (!(pde & PG_ACCESSED_MASK)) { 218e7f2670fSClaudio Fontana pde |= PG_ACCESSED_MASK; 219e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pde_addr, pde); 220e7f2670fSClaudio Fontana } 221e7f2670fSClaudio Fontana 222e7f2670fSClaudio Fontana /* page directory entry */ 223e7f2670fSClaudio Fontana pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & 224e7f2670fSClaudio Fontana a20_mask; 22533ce155cSPaolo Bonzini pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL); 226e7f2670fSClaudio Fontana pte = x86_ldl_phys(cs, pte_addr); 227e7f2670fSClaudio Fontana if (!(pte & PG_PRESENT_MASK)) { 228e7f2670fSClaudio Fontana goto do_fault; 229e7f2670fSClaudio Fontana } 230e7f2670fSClaudio Fontana /* combine pde and pte user and rw protections */ 231e7f2670fSClaudio Fontana ptep &= pte | PG_NX_MASK; 232*3563362dSRichard Henderson page_size = 4096; 233e7f2670fSClaudio Fontana rsvd_mask = 0; 234e7f2670fSClaudio Fontana } 235e7f2670fSClaudio Fontana 236e7f2670fSClaudio Fontana do_check_protect: 237*3563362dSRichard Henderson rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; 238e7f2670fSClaudio Fontana do_check_protect_pse36: 239e7f2670fSClaudio Fontana if (pte & rsvd_mask) { 240e7f2670fSClaudio Fontana goto do_fault_rsvd; 241e7f2670fSClaudio Fontana } 242e7f2670fSClaudio Fontana ptep ^= PG_NX_MASK; 243e7f2670fSClaudio Fontana 244e7f2670fSClaudio Fontana /* can the page can be put in the TLB? prot will tell us */ 245e7f2670fSClaudio Fontana if (is_user && !(ptep & PG_USER_MASK)) { 246e7f2670fSClaudio Fontana goto do_fault_protect; 247e7f2670fSClaudio Fontana } 248e7f2670fSClaudio Fontana 249*3563362dSRichard Henderson int prot = 0; 250*3563362dSRichard Henderson if (in->mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { 251*3563362dSRichard Henderson prot |= PAGE_READ; 25231dd35ebSPaolo Bonzini if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) { 253*3563362dSRichard Henderson prot |= PAGE_WRITE; 254e7f2670fSClaudio Fontana } 255e7f2670fSClaudio Fontana } 256e7f2670fSClaudio Fontana if (!(ptep & PG_NX_MASK) && 257*3563362dSRichard Henderson (is_user || 25831dd35ebSPaolo Bonzini !((pg_mode & PG_MODE_SMEP) && (ptep & PG_USER_MASK)))) { 259*3563362dSRichard Henderson prot |= PAGE_EXEC; 260e7f2670fSClaudio Fontana } 261e7f2670fSClaudio Fontana 262991ec976SPaolo Bonzini if (ptep & PG_USER_MASK) { 26331dd35ebSPaolo Bonzini pkr = pg_mode & PG_MODE_PKE ? env->pkru : 0; 264e7f2670fSClaudio Fontana } else { 26531dd35ebSPaolo Bonzini pkr = pg_mode & PG_MODE_PKS ? env->pkrs : 0; 266e7f2670fSClaudio Fontana } 267e7f2670fSClaudio Fontana if (pkr) { 268e7f2670fSClaudio Fontana uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT; 269e7f2670fSClaudio Fontana uint32_t pkr_ad = (pkr >> pk * 2) & 1; 270e7f2670fSClaudio Fontana uint32_t pkr_wd = (pkr >> pk * 2) & 2; 271e7f2670fSClaudio Fontana uint32_t pkr_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 272e7f2670fSClaudio Fontana 273e7f2670fSClaudio Fontana if (pkr_ad) { 274e7f2670fSClaudio Fontana pkr_prot &= ~(PAGE_READ | PAGE_WRITE); 27531dd35ebSPaolo Bonzini } else if (pkr_wd && (is_user || (pg_mode & PG_MODE_WP))) { 276e7f2670fSClaudio Fontana pkr_prot &= ~PAGE_WRITE; 277e7f2670fSClaudio Fontana } 278487d1133SRichard Henderson if ((pkr_prot & (1 << access_type)) == 0) { 279*3563362dSRichard Henderson goto do_fault_pk_protect; 280e7f2670fSClaudio Fontana } 281*3563362dSRichard Henderson prot &= pkr_prot; 282e7f2670fSClaudio Fontana } 283e7f2670fSClaudio Fontana 284*3563362dSRichard Henderson if ((prot & (1 << access_type)) == 0) { 285e7f2670fSClaudio Fontana goto do_fault_protect; 286e7f2670fSClaudio Fontana } 287e7f2670fSClaudio Fontana 288e7f2670fSClaudio Fontana /* yes, it can! */ 289*3563362dSRichard Henderson { 290*3563362dSRichard Henderson uint32_t set = PG_ACCESSED_MASK; 291*3563362dSRichard Henderson if (access_type == MMU_DATA_STORE) { 292*3563362dSRichard Henderson set |= PG_DIRTY_MASK; 293e7f2670fSClaudio Fontana } 294*3563362dSRichard Henderson if (set & ~pte) { 295*3563362dSRichard Henderson pte |= set; 296e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pte_addr, pte); 297e7f2670fSClaudio Fontana } 298*3563362dSRichard Henderson } 299e7f2670fSClaudio Fontana 300e7f2670fSClaudio Fontana if (!(pte & PG_DIRTY_MASK)) { 301e7f2670fSClaudio Fontana /* only set write access if already dirty... otherwise wait 302e7f2670fSClaudio Fontana for dirty access */ 303*3563362dSRichard Henderson assert(access_type != MMU_DATA_STORE); 304*3563362dSRichard Henderson prot &= ~PAGE_WRITE; 305e7f2670fSClaudio Fontana } 306*3563362dSRichard Henderson out->prot = prot; 307*3563362dSRichard Henderson out->page_size = page_size; 308e7f2670fSClaudio Fontana 309e7f2670fSClaudio Fontana /* align to page_size */ 310*3563362dSRichard Henderson out->paddr = (pte & a20_mask & PG_ADDRESS_MASK & ~(page_size - 1)) 311*3563362dSRichard Henderson | (addr & (page_size - 1)); 312*3563362dSRichard Henderson out->paddr = GET_HPHYS(cs, out->paddr, access_type, &out->prot); 313*3563362dSRichard Henderson return true; 314e7f2670fSClaudio Fontana 315*3563362dSRichard Henderson int error_code; 316e7f2670fSClaudio Fontana do_fault_rsvd: 317*3563362dSRichard Henderson error_code = PG_ERROR_RSVD_MASK; 318*3563362dSRichard Henderson goto do_fault_cont; 319e7f2670fSClaudio Fontana do_fault_protect: 320*3563362dSRichard Henderson error_code = PG_ERROR_P_MASK; 321*3563362dSRichard Henderson goto do_fault_cont; 322*3563362dSRichard Henderson do_fault_pk_protect: 323*3563362dSRichard Henderson assert(access_type != MMU_INST_FETCH); 324*3563362dSRichard Henderson error_code = PG_ERROR_PK_MASK | PG_ERROR_P_MASK; 325*3563362dSRichard Henderson goto do_fault_cont; 326e7f2670fSClaudio Fontana do_fault: 327*3563362dSRichard Henderson error_code = 0; 328*3563362dSRichard Henderson do_fault_cont: 329*3563362dSRichard Henderson if (is_user) { 330e7f2670fSClaudio Fontana error_code |= PG_ERROR_U_MASK; 331*3563362dSRichard Henderson } 332*3563362dSRichard Henderson switch (access_type) { 333*3563362dSRichard Henderson case MMU_DATA_LOAD: 334*3563362dSRichard Henderson break; 335*3563362dSRichard Henderson case MMU_DATA_STORE: 336*3563362dSRichard Henderson error_code |= PG_ERROR_W_MASK; 337*3563362dSRichard Henderson break; 338*3563362dSRichard Henderson case MMU_INST_FETCH: 339*3563362dSRichard Henderson if (pg_mode & (PG_MODE_NXE | PG_MODE_SMEP)) { 340e7f2670fSClaudio Fontana error_code |= PG_ERROR_I_D_MASK; 341*3563362dSRichard Henderson } 342*3563362dSRichard Henderson break; 343*3563362dSRichard Henderson } 344*3563362dSRichard Henderson err->exception_index = EXCP0E_PAGE; 345*3563362dSRichard Henderson err->error_code = error_code; 346*3563362dSRichard Henderson err->cr2 = addr; 347*3563362dSRichard Henderson return false; 348661ff487SPaolo Bonzini } 349661ff487SPaolo Bonzini 35052fb8ad3SLara Lazier hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, 35168746930SPaolo Bonzini int *prot) 35268746930SPaolo Bonzini { 35368746930SPaolo Bonzini CPUX86State *env = &X86_CPU(cs)->env; 35468746930SPaolo Bonzini 35568746930SPaolo Bonzini if (likely(!(env->hflags2 & HF2_NPT_MASK))) { 35668746930SPaolo Bonzini return gphys; 357*3563362dSRichard Henderson } else { 358*3563362dSRichard Henderson TranslateParams in = { 359*3563362dSRichard Henderson .addr = gphys, 360*3563362dSRichard Henderson .cr3 = env->nested_cr3, 361*3563362dSRichard Henderson .pg_mode = env->nested_pg_mode, 362*3563362dSRichard Henderson .mmu_idx = MMU_USER_IDX, 363*3563362dSRichard Henderson .access_type = access_type, 364*3563362dSRichard Henderson .use_stage2 = false, 365*3563362dSRichard Henderson }; 366*3563362dSRichard Henderson TranslateResult out; 367*3563362dSRichard Henderson TranslateFault err; 368*3563362dSRichard Henderson uint64_t exit_info_1; 369*3563362dSRichard Henderson 370*3563362dSRichard Henderson if (mmu_translate(env, &in, &out, &err)) { 371*3563362dSRichard Henderson if (prot) { 372*3563362dSRichard Henderson *prot &= out.prot; 373*3563362dSRichard Henderson } 374*3563362dSRichard Henderson return out.paddr; 37568746930SPaolo Bonzini } 37668746930SPaolo Bonzini 377*3563362dSRichard Henderson x86_stq_phys(cs, env->vm_vmcb + 378*3563362dSRichard Henderson offsetof(struct vmcb, control.exit_info_2), gphys); 379*3563362dSRichard Henderson exit_info_1 = err.error_code 380*3563362dSRichard Henderson | (prot ? SVM_NPTEXIT_GPA : SVM_NPTEXIT_GPT); 38168746930SPaolo Bonzini cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr); 38268746930SPaolo Bonzini } 383*3563362dSRichard Henderson } 38468746930SPaolo Bonzini 385*3563362dSRichard Henderson static bool get_physical_address(CPUX86State *env, vaddr addr, 386*3563362dSRichard Henderson MMUAccessType access_type, int mmu_idx, 387*3563362dSRichard Henderson TranslateResult *out, TranslateFault *err) 388661ff487SPaolo Bonzini { 389661ff487SPaolo Bonzini if (!(env->cr[0] & CR0_PG_MASK)) { 390*3563362dSRichard Henderson out->paddr = addr & x86_get_a20_mask(env); 391*3563362dSRichard Henderson 392661ff487SPaolo Bonzini #ifdef TARGET_X86_64 393661ff487SPaolo Bonzini if (!(env->hflags & HF_LMA_MASK)) { 394661ff487SPaolo Bonzini /* Without long mode we can only address 32bits in real mode */ 395*3563362dSRichard Henderson out->paddr = (uint32_t)out->paddr; 396661ff487SPaolo Bonzini } 397661ff487SPaolo Bonzini #endif 398*3563362dSRichard Henderson out->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 399*3563362dSRichard Henderson out->page_size = TARGET_PAGE_SIZE; 400*3563362dSRichard Henderson return true; 401661ff487SPaolo Bonzini } else { 402*3563362dSRichard Henderson TranslateParams in = { 403*3563362dSRichard Henderson .addr = addr, 404*3563362dSRichard Henderson .cr3 = env->cr[3], 405*3563362dSRichard Henderson .pg_mode = get_pg_mode(env), 406*3563362dSRichard Henderson .mmu_idx = mmu_idx, 407*3563362dSRichard Henderson .access_type = access_type, 408*3563362dSRichard Henderson .use_stage2 = true 409*3563362dSRichard Henderson }; 410b04dc92eSPaolo Bonzini 411*3563362dSRichard Henderson if (in.pg_mode & PG_MODE_LMA) { 412b04dc92eSPaolo Bonzini /* test virtual address sign extension */ 413*3563362dSRichard Henderson int shift = in.pg_mode & PG_MODE_LA57 ? 56 : 47; 414*3563362dSRichard Henderson int64_t sext = (int64_t)addr >> shift; 415b04dc92eSPaolo Bonzini if (sext != 0 && sext != -1) { 416*3563362dSRichard Henderson err->exception_index = EXCP0D_GPF; 417*3563362dSRichard Henderson err->error_code = 0; 418*3563362dSRichard Henderson err->cr2 = addr; 419*3563362dSRichard Henderson return false; 420b04dc92eSPaolo Bonzini } 421b04dc92eSPaolo Bonzini } 422*3563362dSRichard Henderson return mmu_translate(env, &in, out, err); 423e7f2670fSClaudio Fontana } 424661ff487SPaolo Bonzini } 425e7f2670fSClaudio Fontana 426e7f2670fSClaudio Fontana bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, 427e7f2670fSClaudio Fontana MMUAccessType access_type, int mmu_idx, 428e7f2670fSClaudio Fontana bool probe, uintptr_t retaddr) 429e7f2670fSClaudio Fontana { 430*3563362dSRichard Henderson CPUX86State *env = cs->env_ptr; 431*3563362dSRichard Henderson TranslateResult out; 432*3563362dSRichard Henderson TranslateFault err; 433e7f2670fSClaudio Fontana 434*3563362dSRichard Henderson if (get_physical_address(env, addr, access_type, mmu_idx, &out, &err)) { 435*3563362dSRichard Henderson /* 436*3563362dSRichard Henderson * Even if 4MB pages, we map only one 4KB page in the cache to 437*3563362dSRichard Henderson * avoid filling it too fast. 438*3563362dSRichard Henderson */ 439*3563362dSRichard Henderson assert(out.prot & (1 << access_type)); 440*3563362dSRichard Henderson tlb_set_page_with_attrs(cs, addr & TARGET_PAGE_MASK, 441*3563362dSRichard Henderson out.paddr & TARGET_PAGE_MASK, 442*3563362dSRichard Henderson cpu_get_mem_attrs(env), 443*3563362dSRichard Henderson out.prot, mmu_idx, out.page_size); 444*3563362dSRichard Henderson return true; 445*3563362dSRichard Henderson } 446*3563362dSRichard Henderson 447e7f2670fSClaudio Fontana /* FIXME: On error in get_hphys we have already jumped out. */ 448e7f2670fSClaudio Fontana g_assert(!probe); 449*3563362dSRichard Henderson 450*3563362dSRichard Henderson if (env->intercept_exceptions & (1 << err.exception_index)) { 451*3563362dSRichard Henderson /* cr2 is not modified in case of exceptions */ 452*3563362dSRichard Henderson x86_stq_phys(cs, env->vm_vmcb + 453*3563362dSRichard Henderson offsetof(struct vmcb, control.exit_info_2), 454*3563362dSRichard Henderson err.cr2); 455*3563362dSRichard Henderson } else { 456*3563362dSRichard Henderson env->cr[2] = err.cr2; 457e7f2670fSClaudio Fontana } 458*3563362dSRichard Henderson raise_exception_err_ra(env, err.exception_index, err.error_code, retaddr); 459e7f2670fSClaudio Fontana } 460958e1dd1SPaolo Bonzini 461958e1dd1SPaolo Bonzini G_NORETURN void x86_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, 462958e1dd1SPaolo Bonzini MMUAccessType access_type, 463958e1dd1SPaolo Bonzini int mmu_idx, uintptr_t retaddr) 464958e1dd1SPaolo Bonzini { 465958e1dd1SPaolo Bonzini X86CPU *cpu = X86_CPU(cs); 466958e1dd1SPaolo Bonzini handle_unaligned_access(&cpu->env, vaddr, access_type, retaddr); 467958e1dd1SPaolo Bonzini } 468