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 253563362dSRichard Henderson typedef struct TranslateParams { 263563362dSRichard Henderson target_ulong addr; 273563362dSRichard Henderson target_ulong cr3; 283563362dSRichard Henderson int pg_mode; 293563362dSRichard Henderson int mmu_idx; 303563362dSRichard Henderson MMUAccessType access_type; 313563362dSRichard Henderson bool use_stage2; 323563362dSRichard Henderson } TranslateParams; 333563362dSRichard Henderson 343563362dSRichard Henderson typedef struct TranslateResult { 353563362dSRichard Henderson hwaddr paddr; 363563362dSRichard Henderson int prot; 373563362dSRichard Henderson int page_size; 383563362dSRichard Henderson } TranslateResult; 393563362dSRichard Henderson 40*9bbcf372SRichard Henderson typedef enum TranslateFaultStage2 { 41*9bbcf372SRichard Henderson S2_NONE, 42*9bbcf372SRichard Henderson S2_GPA, 43*9bbcf372SRichard Henderson S2_GPT, 44*9bbcf372SRichard Henderson } TranslateFaultStage2; 45*9bbcf372SRichard Henderson 463563362dSRichard Henderson typedef struct TranslateFault { 473563362dSRichard Henderson int exception_index; 483563362dSRichard Henderson int error_code; 493563362dSRichard Henderson target_ulong cr2; 50*9bbcf372SRichard Henderson TranslateFaultStage2 stage2; 513563362dSRichard Henderson } TranslateFault; 52661ff487SPaolo Bonzini 53*9bbcf372SRichard Henderson #define PTE_HPHYS(ADDR) \ 54*9bbcf372SRichard Henderson do { \ 55*9bbcf372SRichard Henderson if (in->use_stage2) { \ 56*9bbcf372SRichard Henderson nested_in.addr = (ADDR); \ 57*9bbcf372SRichard Henderson if (!mmu_translate(env, &nested_in, out, err)) { \ 58*9bbcf372SRichard Henderson err->stage2 = S2_GPT; \ 59*9bbcf372SRichard Henderson return false; \ 60*9bbcf372SRichard Henderson } \ 61*9bbcf372SRichard Henderson (ADDR) = out->paddr; \ 62*9bbcf372SRichard Henderson } \ 63*9bbcf372SRichard Henderson } while (0) 6433ce155cSPaolo Bonzini 653563362dSRichard Henderson static bool mmu_translate(CPUX86State *env, const TranslateParams *in, 663563362dSRichard Henderson TranslateResult *out, TranslateFault *err) 67e7f2670fSClaudio Fontana { 68*9bbcf372SRichard Henderson TranslateParams nested_in = { 69*9bbcf372SRichard Henderson /* Use store for page table entries, to allow A/D flag updates. */ 70*9bbcf372SRichard Henderson .access_type = MMU_DATA_STORE, 71*9bbcf372SRichard Henderson .cr3 = env->nested_cr3, 72*9bbcf372SRichard Henderson .pg_mode = env->nested_pg_mode, 73*9bbcf372SRichard Henderson .mmu_idx = MMU_USER_IDX, 74*9bbcf372SRichard Henderson .use_stage2 = false, 75*9bbcf372SRichard Henderson }; 76*9bbcf372SRichard Henderson 773563362dSRichard Henderson CPUState *cs = env_cpu(env); 783563362dSRichard Henderson X86CPU *cpu = env_archcpu(env); 793563362dSRichard Henderson const int32_t a20_mask = x86_get_a20_mask(env); 803563362dSRichard Henderson const target_ulong addr = in->addr; 813563362dSRichard Henderson const int pg_mode = in->pg_mode; 823563362dSRichard Henderson const bool is_user = (in->mmu_idx == MMU_USER_IDX); 833563362dSRichard Henderson const MMUAccessType access_type = in->access_type; 84e7f2670fSClaudio Fontana uint64_t ptep, pte; 853563362dSRichard Henderson hwaddr pde_addr, pte_addr; 86e7f2670fSClaudio Fontana uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); 87e7f2670fSClaudio Fontana uint32_t pkr; 883563362dSRichard Henderson int page_size; 89e7f2670fSClaudio Fontana 9031dd35ebSPaolo Bonzini if (!(pg_mode & PG_MODE_NXE)) { 91e7f2670fSClaudio Fontana rsvd_mask |= PG_NX_MASK; 92e7f2670fSClaudio Fontana } 93e7f2670fSClaudio Fontana 9431dd35ebSPaolo Bonzini if (pg_mode & PG_MODE_PAE) { 95e7f2670fSClaudio Fontana uint64_t pde, pdpe; 96e7f2670fSClaudio Fontana target_ulong pdpe_addr; 97e7f2670fSClaudio Fontana 98e7f2670fSClaudio Fontana #ifdef TARGET_X86_64 9993eae358SPaolo Bonzini if (pg_mode & PG_MODE_LMA) { 10031dd35ebSPaolo Bonzini bool la57 = pg_mode & PG_MODE_LA57; 101e7f2670fSClaudio Fontana uint64_t pml5e_addr, pml5e; 102e7f2670fSClaudio Fontana uint64_t pml4e_addr, pml4e; 103e7f2670fSClaudio Fontana 104e7f2670fSClaudio Fontana if (la57) { 1053563362dSRichard Henderson pml5e_addr = ((in->cr3 & ~0xfff) + 106e7f2670fSClaudio Fontana (((addr >> 48) & 0x1ff) << 3)) & a20_mask; 107*9bbcf372SRichard Henderson PTE_HPHYS(pml5e_addr); 108e7f2670fSClaudio Fontana pml5e = x86_ldq_phys(cs, pml5e_addr); 109e7f2670fSClaudio Fontana if (!(pml5e & PG_PRESENT_MASK)) { 110e7f2670fSClaudio Fontana goto do_fault; 111e7f2670fSClaudio Fontana } 112e7f2670fSClaudio Fontana if (pml5e & (rsvd_mask | PG_PSE_MASK)) { 113e7f2670fSClaudio Fontana goto do_fault_rsvd; 114e7f2670fSClaudio Fontana } 115e7f2670fSClaudio Fontana if (!(pml5e & PG_ACCESSED_MASK)) { 116e7f2670fSClaudio Fontana pml5e |= PG_ACCESSED_MASK; 117e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pml5e_addr, pml5e); 118e7f2670fSClaudio Fontana } 119e7f2670fSClaudio Fontana ptep = pml5e ^ PG_NX_MASK; 120e7f2670fSClaudio Fontana } else { 1213563362dSRichard Henderson pml5e = in->cr3; 122e7f2670fSClaudio Fontana ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; 123e7f2670fSClaudio Fontana } 124e7f2670fSClaudio Fontana 125e7f2670fSClaudio Fontana pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + 126e7f2670fSClaudio Fontana (((addr >> 39) & 0x1ff) << 3)) & a20_mask; 127*9bbcf372SRichard Henderson PTE_HPHYS(pml4e_addr); 128e7f2670fSClaudio Fontana pml4e = x86_ldq_phys(cs, pml4e_addr); 129e7f2670fSClaudio Fontana if (!(pml4e & PG_PRESENT_MASK)) { 130e7f2670fSClaudio Fontana goto do_fault; 131e7f2670fSClaudio Fontana } 132e7f2670fSClaudio Fontana if (pml4e & (rsvd_mask | PG_PSE_MASK)) { 133e7f2670fSClaudio Fontana goto do_fault_rsvd; 134e7f2670fSClaudio Fontana } 135e7f2670fSClaudio Fontana if (!(pml4e & PG_ACCESSED_MASK)) { 136e7f2670fSClaudio Fontana pml4e |= PG_ACCESSED_MASK; 137e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); 138e7f2670fSClaudio Fontana } 139e7f2670fSClaudio Fontana ptep &= pml4e ^ PG_NX_MASK; 140e7f2670fSClaudio Fontana pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & 141e7f2670fSClaudio Fontana a20_mask; 142*9bbcf372SRichard Henderson PTE_HPHYS(pdpe_addr); 143e7f2670fSClaudio Fontana pdpe = x86_ldq_phys(cs, pdpe_addr); 144e7f2670fSClaudio Fontana if (!(pdpe & PG_PRESENT_MASK)) { 145e7f2670fSClaudio Fontana goto do_fault; 146e7f2670fSClaudio Fontana } 147e7f2670fSClaudio Fontana if (pdpe & rsvd_mask) { 148e7f2670fSClaudio Fontana goto do_fault_rsvd; 149e7f2670fSClaudio Fontana } 150e7f2670fSClaudio Fontana ptep &= pdpe ^ PG_NX_MASK; 151e7f2670fSClaudio Fontana if (!(pdpe & PG_ACCESSED_MASK)) { 152e7f2670fSClaudio Fontana pdpe |= PG_ACCESSED_MASK; 153e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); 154e7f2670fSClaudio Fontana } 155e7f2670fSClaudio Fontana if (pdpe & PG_PSE_MASK) { 156e7f2670fSClaudio Fontana /* 1 GB page */ 1573563362dSRichard Henderson page_size = 1024 * 1024 * 1024; 158e7f2670fSClaudio Fontana pte_addr = pdpe_addr; 159e7f2670fSClaudio Fontana pte = pdpe; 160e7f2670fSClaudio Fontana goto do_check_protect; 161e7f2670fSClaudio Fontana } 162e7f2670fSClaudio Fontana } else 163e7f2670fSClaudio Fontana #endif 164e7f2670fSClaudio Fontana { 165e7f2670fSClaudio Fontana /* XXX: load them when cr3 is loaded ? */ 1663563362dSRichard Henderson pdpe_addr = ((in->cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & 167e7f2670fSClaudio Fontana a20_mask; 168*9bbcf372SRichard Henderson PTE_HPHYS(pdpe_addr); 169e7f2670fSClaudio Fontana pdpe = x86_ldq_phys(cs, pdpe_addr); 170e7f2670fSClaudio Fontana if (!(pdpe & PG_PRESENT_MASK)) { 171e7f2670fSClaudio Fontana goto do_fault; 172e7f2670fSClaudio Fontana } 173e7f2670fSClaudio Fontana rsvd_mask |= PG_HI_USER_MASK; 174e7f2670fSClaudio Fontana if (pdpe & (rsvd_mask | PG_NX_MASK)) { 175e7f2670fSClaudio Fontana goto do_fault_rsvd; 176e7f2670fSClaudio Fontana } 177e7f2670fSClaudio Fontana ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; 178e7f2670fSClaudio Fontana } 179e7f2670fSClaudio Fontana 180e7f2670fSClaudio Fontana pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & 181e7f2670fSClaudio Fontana a20_mask; 182*9bbcf372SRichard Henderson PTE_HPHYS(pde_addr); 183e7f2670fSClaudio Fontana pde = x86_ldq_phys(cs, pde_addr); 184e7f2670fSClaudio Fontana if (!(pde & PG_PRESENT_MASK)) { 185e7f2670fSClaudio Fontana goto do_fault; 186e7f2670fSClaudio Fontana } 187e7f2670fSClaudio Fontana if (pde & rsvd_mask) { 188e7f2670fSClaudio Fontana goto do_fault_rsvd; 189e7f2670fSClaudio Fontana } 190e7f2670fSClaudio Fontana ptep &= pde ^ PG_NX_MASK; 191e7f2670fSClaudio Fontana if (pde & PG_PSE_MASK) { 192e7f2670fSClaudio Fontana /* 2 MB page */ 1933563362dSRichard Henderson page_size = 2048 * 1024; 194e7f2670fSClaudio Fontana pte_addr = pde_addr; 195e7f2670fSClaudio Fontana pte = pde; 196e7f2670fSClaudio Fontana goto do_check_protect; 197e7f2670fSClaudio Fontana } 198e7f2670fSClaudio Fontana /* 4 KB page */ 199e7f2670fSClaudio Fontana if (!(pde & PG_ACCESSED_MASK)) { 200e7f2670fSClaudio Fontana pde |= PG_ACCESSED_MASK; 201e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pde_addr, pde); 202e7f2670fSClaudio Fontana } 203e7f2670fSClaudio Fontana pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & 204e7f2670fSClaudio Fontana a20_mask; 205*9bbcf372SRichard Henderson PTE_HPHYS(pte_addr); 206e7f2670fSClaudio Fontana pte = x86_ldq_phys(cs, pte_addr); 207e7f2670fSClaudio Fontana if (!(pte & PG_PRESENT_MASK)) { 208e7f2670fSClaudio Fontana goto do_fault; 209e7f2670fSClaudio Fontana } 210e7f2670fSClaudio Fontana if (pte & rsvd_mask) { 211e7f2670fSClaudio Fontana goto do_fault_rsvd; 212e7f2670fSClaudio Fontana } 213e7f2670fSClaudio Fontana /* combine pde and pte nx, user and rw protections */ 214e7f2670fSClaudio Fontana ptep &= pte ^ PG_NX_MASK; 2153563362dSRichard Henderson page_size = 4096; 216e7f2670fSClaudio Fontana } else { 217e7f2670fSClaudio Fontana uint32_t pde; 218e7f2670fSClaudio Fontana 219e7f2670fSClaudio Fontana /* page directory entry */ 2203563362dSRichard Henderson pde_addr = ((in->cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & 221e7f2670fSClaudio Fontana a20_mask; 222*9bbcf372SRichard Henderson PTE_HPHYS(pde_addr); 223e7f2670fSClaudio Fontana pde = x86_ldl_phys(cs, pde_addr); 224e7f2670fSClaudio Fontana if (!(pde & PG_PRESENT_MASK)) { 225e7f2670fSClaudio Fontana goto do_fault; 226e7f2670fSClaudio Fontana } 227e7f2670fSClaudio Fontana ptep = pde | PG_NX_MASK; 228e7f2670fSClaudio Fontana 229e7f2670fSClaudio Fontana /* if PSE bit is set, then we use a 4MB page */ 23031dd35ebSPaolo Bonzini if ((pde & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) { 2313563362dSRichard Henderson page_size = 4096 * 1024; 232e7f2670fSClaudio Fontana pte_addr = pde_addr; 233e7f2670fSClaudio Fontana 234e7f2670fSClaudio Fontana /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. 235e7f2670fSClaudio Fontana * Leave bits 20-13 in place for setting accessed/dirty bits below. 236e7f2670fSClaudio Fontana */ 237e7f2670fSClaudio Fontana pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); 238e7f2670fSClaudio Fontana rsvd_mask = 0x200000; 239e7f2670fSClaudio Fontana goto do_check_protect_pse36; 240e7f2670fSClaudio Fontana } 241e7f2670fSClaudio Fontana 242e7f2670fSClaudio Fontana if (!(pde & PG_ACCESSED_MASK)) { 243e7f2670fSClaudio Fontana pde |= PG_ACCESSED_MASK; 244e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pde_addr, pde); 245e7f2670fSClaudio Fontana } 246e7f2670fSClaudio Fontana 247e7f2670fSClaudio Fontana /* page directory entry */ 248e7f2670fSClaudio Fontana pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & 249e7f2670fSClaudio Fontana a20_mask; 250*9bbcf372SRichard Henderson PTE_HPHYS(pte_addr); 251e7f2670fSClaudio Fontana pte = x86_ldl_phys(cs, pte_addr); 252e7f2670fSClaudio Fontana if (!(pte & PG_PRESENT_MASK)) { 253e7f2670fSClaudio Fontana goto do_fault; 254e7f2670fSClaudio Fontana } 255e7f2670fSClaudio Fontana /* combine pde and pte user and rw protections */ 256e7f2670fSClaudio Fontana ptep &= pte | PG_NX_MASK; 2573563362dSRichard Henderson page_size = 4096; 258e7f2670fSClaudio Fontana rsvd_mask = 0; 259e7f2670fSClaudio Fontana } 260e7f2670fSClaudio Fontana 261e7f2670fSClaudio Fontana do_check_protect: 2623563362dSRichard Henderson rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; 263e7f2670fSClaudio Fontana do_check_protect_pse36: 264e7f2670fSClaudio Fontana if (pte & rsvd_mask) { 265e7f2670fSClaudio Fontana goto do_fault_rsvd; 266e7f2670fSClaudio Fontana } 267e7f2670fSClaudio Fontana ptep ^= PG_NX_MASK; 268e7f2670fSClaudio Fontana 269e7f2670fSClaudio Fontana /* can the page can be put in the TLB? prot will tell us */ 270e7f2670fSClaudio Fontana if (is_user && !(ptep & PG_USER_MASK)) { 271e7f2670fSClaudio Fontana goto do_fault_protect; 272e7f2670fSClaudio Fontana } 273e7f2670fSClaudio Fontana 2743563362dSRichard Henderson int prot = 0; 2753563362dSRichard Henderson if (in->mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { 2763563362dSRichard Henderson prot |= PAGE_READ; 27731dd35ebSPaolo Bonzini if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) { 2783563362dSRichard Henderson prot |= PAGE_WRITE; 279e7f2670fSClaudio Fontana } 280e7f2670fSClaudio Fontana } 281e7f2670fSClaudio Fontana if (!(ptep & PG_NX_MASK) && 2823563362dSRichard Henderson (is_user || 28331dd35ebSPaolo Bonzini !((pg_mode & PG_MODE_SMEP) && (ptep & PG_USER_MASK)))) { 2843563362dSRichard Henderson prot |= PAGE_EXEC; 285e7f2670fSClaudio Fontana } 286e7f2670fSClaudio Fontana 287991ec976SPaolo Bonzini if (ptep & PG_USER_MASK) { 28831dd35ebSPaolo Bonzini pkr = pg_mode & PG_MODE_PKE ? env->pkru : 0; 289e7f2670fSClaudio Fontana } else { 29031dd35ebSPaolo Bonzini pkr = pg_mode & PG_MODE_PKS ? env->pkrs : 0; 291e7f2670fSClaudio Fontana } 292e7f2670fSClaudio Fontana if (pkr) { 293e7f2670fSClaudio Fontana uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT; 294e7f2670fSClaudio Fontana uint32_t pkr_ad = (pkr >> pk * 2) & 1; 295e7f2670fSClaudio Fontana uint32_t pkr_wd = (pkr >> pk * 2) & 2; 296e7f2670fSClaudio Fontana uint32_t pkr_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 297e7f2670fSClaudio Fontana 298e7f2670fSClaudio Fontana if (pkr_ad) { 299e7f2670fSClaudio Fontana pkr_prot &= ~(PAGE_READ | PAGE_WRITE); 30031dd35ebSPaolo Bonzini } else if (pkr_wd && (is_user || (pg_mode & PG_MODE_WP))) { 301e7f2670fSClaudio Fontana pkr_prot &= ~PAGE_WRITE; 302e7f2670fSClaudio Fontana } 303487d1133SRichard Henderson if ((pkr_prot & (1 << access_type)) == 0) { 3043563362dSRichard Henderson goto do_fault_pk_protect; 305e7f2670fSClaudio Fontana } 3063563362dSRichard Henderson prot &= pkr_prot; 307e7f2670fSClaudio Fontana } 308e7f2670fSClaudio Fontana 3093563362dSRichard Henderson if ((prot & (1 << access_type)) == 0) { 310e7f2670fSClaudio Fontana goto do_fault_protect; 311e7f2670fSClaudio Fontana } 312e7f2670fSClaudio Fontana 313e7f2670fSClaudio Fontana /* yes, it can! */ 3143563362dSRichard Henderson { 3153563362dSRichard Henderson uint32_t set = PG_ACCESSED_MASK; 3163563362dSRichard Henderson if (access_type == MMU_DATA_STORE) { 3173563362dSRichard Henderson set |= PG_DIRTY_MASK; 318e7f2670fSClaudio Fontana } 3193563362dSRichard Henderson if (set & ~pte) { 3203563362dSRichard Henderson pte |= set; 321e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pte_addr, pte); 322e7f2670fSClaudio Fontana } 3233563362dSRichard Henderson } 324e7f2670fSClaudio Fontana 325e7f2670fSClaudio Fontana if (!(pte & PG_DIRTY_MASK)) { 326e7f2670fSClaudio Fontana /* only set write access if already dirty... otherwise wait 327e7f2670fSClaudio Fontana for dirty access */ 3283563362dSRichard Henderson assert(access_type != MMU_DATA_STORE); 3293563362dSRichard Henderson prot &= ~PAGE_WRITE; 330e7f2670fSClaudio Fontana } 331e7f2670fSClaudio Fontana 332e7f2670fSClaudio Fontana /* align to page_size */ 3333563362dSRichard Henderson out->paddr = (pte & a20_mask & PG_ADDRESS_MASK & ~(page_size - 1)) 3343563362dSRichard Henderson | (addr & (page_size - 1)); 335*9bbcf372SRichard Henderson 336*9bbcf372SRichard Henderson if (in->use_stage2) { 337*9bbcf372SRichard Henderson nested_in.addr = out->paddr; 338*9bbcf372SRichard Henderson nested_in.access_type = access_type; 339*9bbcf372SRichard Henderson 340*9bbcf372SRichard Henderson if (!mmu_translate(env, &nested_in, out, err)) { 341*9bbcf372SRichard Henderson err->stage2 = S2_GPA; 342*9bbcf372SRichard Henderson return false; 343*9bbcf372SRichard Henderson } 344*9bbcf372SRichard Henderson 345*9bbcf372SRichard Henderson /* Merge stage1 & stage2 protection bits. */ 346*9bbcf372SRichard Henderson prot &= out->prot; 347*9bbcf372SRichard Henderson 348*9bbcf372SRichard Henderson /* Re-verify resulting protection. */ 349*9bbcf372SRichard Henderson if ((prot & (1 << access_type)) == 0) { 350*9bbcf372SRichard Henderson goto do_fault_protect; 351*9bbcf372SRichard Henderson } 352*9bbcf372SRichard Henderson } 353*9bbcf372SRichard Henderson 354*9bbcf372SRichard Henderson out->prot = prot; 355*9bbcf372SRichard Henderson out->page_size = page_size; 3563563362dSRichard Henderson return true; 357e7f2670fSClaudio Fontana 3583563362dSRichard Henderson int error_code; 359e7f2670fSClaudio Fontana do_fault_rsvd: 3603563362dSRichard Henderson error_code = PG_ERROR_RSVD_MASK; 3613563362dSRichard Henderson goto do_fault_cont; 362e7f2670fSClaudio Fontana do_fault_protect: 3633563362dSRichard Henderson error_code = PG_ERROR_P_MASK; 3643563362dSRichard Henderson goto do_fault_cont; 3653563362dSRichard Henderson do_fault_pk_protect: 3663563362dSRichard Henderson assert(access_type != MMU_INST_FETCH); 3673563362dSRichard Henderson error_code = PG_ERROR_PK_MASK | PG_ERROR_P_MASK; 3683563362dSRichard Henderson goto do_fault_cont; 369e7f2670fSClaudio Fontana do_fault: 3703563362dSRichard Henderson error_code = 0; 3713563362dSRichard Henderson do_fault_cont: 3723563362dSRichard Henderson if (is_user) { 373e7f2670fSClaudio Fontana error_code |= PG_ERROR_U_MASK; 3743563362dSRichard Henderson } 3753563362dSRichard Henderson switch (access_type) { 3763563362dSRichard Henderson case MMU_DATA_LOAD: 3773563362dSRichard Henderson break; 3783563362dSRichard Henderson case MMU_DATA_STORE: 3793563362dSRichard Henderson error_code |= PG_ERROR_W_MASK; 3803563362dSRichard Henderson break; 3813563362dSRichard Henderson case MMU_INST_FETCH: 3823563362dSRichard Henderson if (pg_mode & (PG_MODE_NXE | PG_MODE_SMEP)) { 383e7f2670fSClaudio Fontana error_code |= PG_ERROR_I_D_MASK; 3843563362dSRichard Henderson } 3853563362dSRichard Henderson break; 3863563362dSRichard Henderson } 3873563362dSRichard Henderson err->exception_index = EXCP0E_PAGE; 3883563362dSRichard Henderson err->error_code = error_code; 3893563362dSRichard Henderson err->cr2 = addr; 390*9bbcf372SRichard Henderson err->stage2 = S2_NONE; 3913563362dSRichard Henderson return false; 392661ff487SPaolo Bonzini } 393661ff487SPaolo Bonzini 394*9bbcf372SRichard Henderson static G_NORETURN void raise_stage2(CPUX86State *env, TranslateFault *err, 395*9bbcf372SRichard Henderson uintptr_t retaddr) 396*9bbcf372SRichard Henderson { 397*9bbcf372SRichard Henderson uint64_t exit_info_1 = err->error_code; 398*9bbcf372SRichard Henderson 399*9bbcf372SRichard Henderson switch (err->stage2) { 400*9bbcf372SRichard Henderson case S2_GPT: 401*9bbcf372SRichard Henderson exit_info_1 |= SVM_NPTEXIT_GPT; 402*9bbcf372SRichard Henderson break; 403*9bbcf372SRichard Henderson case S2_GPA: 404*9bbcf372SRichard Henderson exit_info_1 |= SVM_NPTEXIT_GPA; 405*9bbcf372SRichard Henderson break; 406*9bbcf372SRichard Henderson default: 407*9bbcf372SRichard Henderson g_assert_not_reached(); 408*9bbcf372SRichard Henderson } 409*9bbcf372SRichard Henderson 410*9bbcf372SRichard Henderson x86_stq_phys(env_cpu(env), 411*9bbcf372SRichard Henderson env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 412*9bbcf372SRichard Henderson err->cr2); 413*9bbcf372SRichard Henderson cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, retaddr); 414*9bbcf372SRichard Henderson } 415*9bbcf372SRichard Henderson 41652fb8ad3SLara Lazier hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, 41768746930SPaolo Bonzini int *prot) 41868746930SPaolo Bonzini { 419*9bbcf372SRichard Henderson CPUX86State *env = cs->env_ptr; 42068746930SPaolo Bonzini 42168746930SPaolo Bonzini if (likely(!(env->hflags2 & HF2_NPT_MASK))) { 42268746930SPaolo Bonzini return gphys; 4233563362dSRichard Henderson } else { 4243563362dSRichard Henderson TranslateParams in = { 4253563362dSRichard Henderson .addr = gphys, 4263563362dSRichard Henderson .cr3 = env->nested_cr3, 4273563362dSRichard Henderson .pg_mode = env->nested_pg_mode, 4283563362dSRichard Henderson .mmu_idx = MMU_USER_IDX, 4293563362dSRichard Henderson .access_type = access_type, 4303563362dSRichard Henderson .use_stage2 = false, 4313563362dSRichard Henderson }; 4323563362dSRichard Henderson TranslateResult out; 4333563362dSRichard Henderson TranslateFault err; 4343563362dSRichard Henderson 435*9bbcf372SRichard Henderson if (!mmu_translate(env, &in, &out, &err)) { 436*9bbcf372SRichard Henderson err.stage2 = prot ? SVM_NPTEXIT_GPA : SVM_NPTEXIT_GPT; 437*9bbcf372SRichard Henderson raise_stage2(env, &err, env->retaddr); 438*9bbcf372SRichard Henderson } 439*9bbcf372SRichard Henderson 4403563362dSRichard Henderson if (prot) { 4413563362dSRichard Henderson *prot &= out.prot; 4423563362dSRichard Henderson } 4433563362dSRichard Henderson return out.paddr; 44468746930SPaolo Bonzini } 4453563362dSRichard Henderson } 44668746930SPaolo Bonzini 4473563362dSRichard Henderson static bool get_physical_address(CPUX86State *env, vaddr addr, 4483563362dSRichard Henderson MMUAccessType access_type, int mmu_idx, 4493563362dSRichard Henderson TranslateResult *out, TranslateFault *err) 450661ff487SPaolo Bonzini { 451661ff487SPaolo Bonzini if (!(env->cr[0] & CR0_PG_MASK)) { 4523563362dSRichard Henderson out->paddr = addr & x86_get_a20_mask(env); 4533563362dSRichard Henderson 454661ff487SPaolo Bonzini #ifdef TARGET_X86_64 455661ff487SPaolo Bonzini if (!(env->hflags & HF_LMA_MASK)) { 456661ff487SPaolo Bonzini /* Without long mode we can only address 32bits in real mode */ 4573563362dSRichard Henderson out->paddr = (uint32_t)out->paddr; 458661ff487SPaolo Bonzini } 459661ff487SPaolo Bonzini #endif 4603563362dSRichard Henderson out->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 4613563362dSRichard Henderson out->page_size = TARGET_PAGE_SIZE; 4623563362dSRichard Henderson return true; 463661ff487SPaolo Bonzini } else { 4643563362dSRichard Henderson TranslateParams in = { 4653563362dSRichard Henderson .addr = addr, 4663563362dSRichard Henderson .cr3 = env->cr[3], 4673563362dSRichard Henderson .pg_mode = get_pg_mode(env), 4683563362dSRichard Henderson .mmu_idx = mmu_idx, 4693563362dSRichard Henderson .access_type = access_type, 470*9bbcf372SRichard Henderson .use_stage2 = env->hflags2 & HF2_NPT_MASK, 4713563362dSRichard Henderson }; 472b04dc92eSPaolo Bonzini 4733563362dSRichard Henderson if (in.pg_mode & PG_MODE_LMA) { 474b04dc92eSPaolo Bonzini /* test virtual address sign extension */ 4753563362dSRichard Henderson int shift = in.pg_mode & PG_MODE_LA57 ? 56 : 47; 4763563362dSRichard Henderson int64_t sext = (int64_t)addr >> shift; 477b04dc92eSPaolo Bonzini if (sext != 0 && sext != -1) { 4783563362dSRichard Henderson err->exception_index = EXCP0D_GPF; 4793563362dSRichard Henderson err->error_code = 0; 4803563362dSRichard Henderson err->cr2 = addr; 4813563362dSRichard Henderson return false; 482b04dc92eSPaolo Bonzini } 483b04dc92eSPaolo Bonzini } 4843563362dSRichard Henderson return mmu_translate(env, &in, out, err); 485e7f2670fSClaudio Fontana } 486661ff487SPaolo Bonzini } 487e7f2670fSClaudio Fontana 488e7f2670fSClaudio Fontana bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, 489e7f2670fSClaudio Fontana MMUAccessType access_type, int mmu_idx, 490e7f2670fSClaudio Fontana bool probe, uintptr_t retaddr) 491e7f2670fSClaudio Fontana { 4923563362dSRichard Henderson CPUX86State *env = cs->env_ptr; 4933563362dSRichard Henderson TranslateResult out; 4943563362dSRichard Henderson TranslateFault err; 495e7f2670fSClaudio Fontana 4963563362dSRichard Henderson if (get_physical_address(env, addr, access_type, mmu_idx, &out, &err)) { 4973563362dSRichard Henderson /* 4983563362dSRichard Henderson * Even if 4MB pages, we map only one 4KB page in the cache to 4993563362dSRichard Henderson * avoid filling it too fast. 5003563362dSRichard Henderson */ 5013563362dSRichard Henderson assert(out.prot & (1 << access_type)); 5023563362dSRichard Henderson tlb_set_page_with_attrs(cs, addr & TARGET_PAGE_MASK, 5033563362dSRichard Henderson out.paddr & TARGET_PAGE_MASK, 5043563362dSRichard Henderson cpu_get_mem_attrs(env), 5053563362dSRichard Henderson out.prot, mmu_idx, out.page_size); 5063563362dSRichard Henderson return true; 5073563362dSRichard Henderson } 5083563362dSRichard Henderson 509*9bbcf372SRichard Henderson if (probe) { 510*9bbcf372SRichard Henderson return false; 511*9bbcf372SRichard Henderson } 512*9bbcf372SRichard Henderson 513*9bbcf372SRichard Henderson if (err.stage2 != S2_NONE) { 514*9bbcf372SRichard Henderson raise_stage2(env, &err, retaddr); 515*9bbcf372SRichard Henderson } 5163563362dSRichard Henderson 5173563362dSRichard Henderson if (env->intercept_exceptions & (1 << err.exception_index)) { 5183563362dSRichard Henderson /* cr2 is not modified in case of exceptions */ 5193563362dSRichard Henderson x86_stq_phys(cs, env->vm_vmcb + 5203563362dSRichard Henderson offsetof(struct vmcb, control.exit_info_2), 5213563362dSRichard Henderson err.cr2); 5223563362dSRichard Henderson } else { 5233563362dSRichard Henderson env->cr[2] = err.cr2; 524e7f2670fSClaudio Fontana } 5253563362dSRichard Henderson raise_exception_err_ra(env, err.exception_index, err.error_code, retaddr); 526e7f2670fSClaudio Fontana } 527958e1dd1SPaolo Bonzini 528958e1dd1SPaolo Bonzini G_NORETURN void x86_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, 529958e1dd1SPaolo Bonzini MMUAccessType access_type, 530958e1dd1SPaolo Bonzini int mmu_idx, uintptr_t retaddr) 531958e1dd1SPaolo Bonzini { 532958e1dd1SPaolo Bonzini X86CPU *cpu = X86_CPU(cs); 533958e1dd1SPaolo Bonzini handle_unaligned_access(&cpu->env, vaddr, access_type, retaddr); 534958e1dd1SPaolo Bonzini } 535