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 409bbcf372SRichard Henderson typedef enum TranslateFaultStage2 { 419bbcf372SRichard Henderson S2_NONE, 429bbcf372SRichard Henderson S2_GPA, 439bbcf372SRichard Henderson S2_GPT, 449bbcf372SRichard Henderson } TranslateFaultStage2; 459bbcf372SRichard Henderson 463563362dSRichard Henderson typedef struct TranslateFault { 473563362dSRichard Henderson int exception_index; 483563362dSRichard Henderson int error_code; 493563362dSRichard Henderson target_ulong cr2; 509bbcf372SRichard Henderson TranslateFaultStage2 stage2; 513563362dSRichard Henderson } TranslateFault; 52661ff487SPaolo Bonzini 539bbcf372SRichard Henderson #define PTE_HPHYS(ADDR) \ 549bbcf372SRichard Henderson do { \ 559bbcf372SRichard Henderson if (in->use_stage2) { \ 569bbcf372SRichard Henderson nested_in.addr = (ADDR); \ 579bbcf372SRichard Henderson if (!mmu_translate(env, &nested_in, out, err)) { \ 589bbcf372SRichard Henderson err->stage2 = S2_GPT; \ 599bbcf372SRichard Henderson return false; \ 609bbcf372SRichard Henderson } \ 619bbcf372SRichard Henderson (ADDR) = out->paddr; \ 629bbcf372SRichard Henderson } \ 639bbcf372SRichard Henderson } while (0) 6433ce155cSPaolo Bonzini 653563362dSRichard Henderson static bool mmu_translate(CPUX86State *env, const TranslateParams *in, 663563362dSRichard Henderson TranslateResult *out, TranslateFault *err) 67e7f2670fSClaudio Fontana { 689bbcf372SRichard Henderson TranslateParams nested_in = { 699bbcf372SRichard Henderson /* Use store for page table entries, to allow A/D flag updates. */ 709bbcf372SRichard Henderson .access_type = MMU_DATA_STORE, 719bbcf372SRichard Henderson .cr3 = env->nested_cr3, 729bbcf372SRichard Henderson .pg_mode = env->nested_pg_mode, 739bbcf372SRichard Henderson .mmu_idx = MMU_USER_IDX, 749bbcf372SRichard Henderson .use_stage2 = false, 759bbcf372SRichard Henderson }; 769bbcf372SRichard 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; 85*11b4e971SRichard Henderson hwaddr 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 #ifdef TARGET_X86_64 9693eae358SPaolo Bonzini if (pg_mode & PG_MODE_LMA) { 97*11b4e971SRichard Henderson if (pg_mode & PG_MODE_LA57) { 98*11b4e971SRichard Henderson /* 99*11b4e971SRichard Henderson * Page table level 5 100*11b4e971SRichard Henderson */ 101*11b4e971SRichard Henderson pte_addr = ((in->cr3 & ~0xfff) + 102e7f2670fSClaudio Fontana (((addr >> 48) & 0x1ff) << 3)) & a20_mask; 103*11b4e971SRichard Henderson PTE_HPHYS(pte_addr); 104*11b4e971SRichard Henderson pte = x86_ldq_phys(cs, pte_addr); 105*11b4e971SRichard Henderson if (!(pte & PG_PRESENT_MASK)) { 106e7f2670fSClaudio Fontana goto do_fault; 107e7f2670fSClaudio Fontana } 108*11b4e971SRichard Henderson if (pte & (rsvd_mask | PG_PSE_MASK)) { 109e7f2670fSClaudio Fontana goto do_fault_rsvd; 110e7f2670fSClaudio Fontana } 111*11b4e971SRichard Henderson if (!(pte & PG_ACCESSED_MASK)) { 112*11b4e971SRichard Henderson pte |= PG_ACCESSED_MASK; 113*11b4e971SRichard Henderson x86_stl_phys_notdirty(cs, pte_addr, pte); 114e7f2670fSClaudio Fontana } 115*11b4e971SRichard Henderson ptep = pte ^ PG_NX_MASK; 116e7f2670fSClaudio Fontana } else { 117*11b4e971SRichard Henderson pte = in->cr3; 118e7f2670fSClaudio Fontana ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; 119e7f2670fSClaudio Fontana } 120e7f2670fSClaudio Fontana 121*11b4e971SRichard Henderson /* 122*11b4e971SRichard Henderson * Page table level 4 123*11b4e971SRichard Henderson */ 124*11b4e971SRichard Henderson pte_addr = ((pte & PG_ADDRESS_MASK) + 125e7f2670fSClaudio Fontana (((addr >> 39) & 0x1ff) << 3)) & a20_mask; 126*11b4e971SRichard Henderson PTE_HPHYS(pte_addr); 127*11b4e971SRichard Henderson pte = x86_ldq_phys(cs, pte_addr); 128*11b4e971SRichard Henderson if (!(pte & PG_PRESENT_MASK)) { 129e7f2670fSClaudio Fontana goto do_fault; 130e7f2670fSClaudio Fontana } 131*11b4e971SRichard Henderson if (pte & (rsvd_mask | PG_PSE_MASK)) { 132e7f2670fSClaudio Fontana goto do_fault_rsvd; 133e7f2670fSClaudio Fontana } 134*11b4e971SRichard Henderson if (!(pte & PG_ACCESSED_MASK)) { 135*11b4e971SRichard Henderson pte |= PG_ACCESSED_MASK; 136*11b4e971SRichard Henderson x86_stl_phys_notdirty(cs, pte_addr, pte); 137e7f2670fSClaudio Fontana } 138*11b4e971SRichard Henderson ptep &= pte ^ PG_NX_MASK; 139*11b4e971SRichard Henderson 140*11b4e971SRichard Henderson /* 141*11b4e971SRichard Henderson * Page table level 3 142*11b4e971SRichard Henderson */ 143*11b4e971SRichard Henderson pte_addr = ((pte & PG_ADDRESS_MASK) + 144*11b4e971SRichard Henderson (((addr >> 30) & 0x1ff) << 3)) & a20_mask; 145*11b4e971SRichard Henderson PTE_HPHYS(pte_addr); 146*11b4e971SRichard Henderson pte = x86_ldq_phys(cs, pte_addr); 147*11b4e971SRichard Henderson if (!(pte & PG_PRESENT_MASK)) { 148e7f2670fSClaudio Fontana goto do_fault; 149e7f2670fSClaudio Fontana } 150*11b4e971SRichard Henderson if (pte & rsvd_mask) { 151e7f2670fSClaudio Fontana goto do_fault_rsvd; 152e7f2670fSClaudio Fontana } 153*11b4e971SRichard Henderson ptep &= pte ^ PG_NX_MASK; 154*11b4e971SRichard Henderson if (!(pte & PG_ACCESSED_MASK)) { 155*11b4e971SRichard Henderson pte |= PG_ACCESSED_MASK; 156*11b4e971SRichard Henderson x86_stl_phys_notdirty(cs, pte_addr, pte); 157e7f2670fSClaudio Fontana } 158*11b4e971SRichard Henderson if (pte & PG_PSE_MASK) { 159e7f2670fSClaudio Fontana /* 1 GB page */ 1603563362dSRichard Henderson page_size = 1024 * 1024 * 1024; 161e7f2670fSClaudio Fontana goto do_check_protect; 162e7f2670fSClaudio Fontana } 163e7f2670fSClaudio Fontana } else 164e7f2670fSClaudio Fontana #endif 165e7f2670fSClaudio Fontana { 166*11b4e971SRichard Henderson /* 167*11b4e971SRichard Henderson * Page table level 3 168*11b4e971SRichard Henderson */ 169*11b4e971SRichard Henderson pte_addr = ((in->cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & a20_mask; 170*11b4e971SRichard Henderson PTE_HPHYS(pte_addr); 171*11b4e971SRichard Henderson pte = x86_ldq_phys(cs, pte_addr); 172*11b4e971SRichard Henderson if (!(pte & PG_PRESENT_MASK)) { 173e7f2670fSClaudio Fontana goto do_fault; 174e7f2670fSClaudio Fontana } 175e7f2670fSClaudio Fontana rsvd_mask |= PG_HI_USER_MASK; 176*11b4e971SRichard Henderson if (pte & (rsvd_mask | PG_NX_MASK)) { 177e7f2670fSClaudio Fontana goto do_fault_rsvd; 178e7f2670fSClaudio Fontana } 179e7f2670fSClaudio Fontana ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; 180e7f2670fSClaudio Fontana } 181e7f2670fSClaudio Fontana 182*11b4e971SRichard Henderson /* 183*11b4e971SRichard Henderson * Page table level 2 184*11b4e971SRichard Henderson */ 185*11b4e971SRichard Henderson pte_addr = ((pte & PG_ADDRESS_MASK) + 186*11b4e971SRichard Henderson (((addr >> 21) & 0x1ff) << 3)) & a20_mask; 187*11b4e971SRichard Henderson PTE_HPHYS(pte_addr); 188*11b4e971SRichard Henderson pte = x86_ldq_phys(cs, pte_addr); 189*11b4e971SRichard Henderson if (!(pte & PG_PRESENT_MASK)) { 190e7f2670fSClaudio Fontana goto do_fault; 191e7f2670fSClaudio Fontana } 192*11b4e971SRichard Henderson if (pte & rsvd_mask) { 193e7f2670fSClaudio Fontana goto do_fault_rsvd; 194e7f2670fSClaudio Fontana } 195*11b4e971SRichard Henderson ptep &= pte ^ PG_NX_MASK; 196*11b4e971SRichard Henderson if (pte & PG_PSE_MASK) { 197e7f2670fSClaudio Fontana /* 2 MB page */ 1983563362dSRichard Henderson page_size = 2048 * 1024; 199e7f2670fSClaudio Fontana goto do_check_protect; 200e7f2670fSClaudio Fontana } 201*11b4e971SRichard Henderson if (!(pte & PG_ACCESSED_MASK)) { 202*11b4e971SRichard Henderson pte |= PG_ACCESSED_MASK; 203*11b4e971SRichard Henderson x86_stl_phys_notdirty(cs, pte_addr, pte); 204e7f2670fSClaudio Fontana } 205*11b4e971SRichard Henderson 206*11b4e971SRichard Henderson /* 207*11b4e971SRichard Henderson * Page table level 1 208*11b4e971SRichard Henderson */ 209*11b4e971SRichard Henderson pte_addr = ((pte & PG_ADDRESS_MASK) + 210*11b4e971SRichard Henderson (((addr >> 12) & 0x1ff) << 3)) & a20_mask; 2119bbcf372SRichard Henderson PTE_HPHYS(pte_addr); 212e7f2670fSClaudio Fontana pte = x86_ldq_phys(cs, pte_addr); 213e7f2670fSClaudio Fontana if (!(pte & PG_PRESENT_MASK)) { 214e7f2670fSClaudio Fontana goto do_fault; 215e7f2670fSClaudio Fontana } 216e7f2670fSClaudio Fontana if (pte & rsvd_mask) { 217e7f2670fSClaudio Fontana goto do_fault_rsvd; 218e7f2670fSClaudio Fontana } 219e7f2670fSClaudio Fontana /* combine pde and pte nx, user and rw protections */ 220e7f2670fSClaudio Fontana ptep &= pte ^ PG_NX_MASK; 2213563362dSRichard Henderson page_size = 4096; 222e7f2670fSClaudio Fontana } else { 223*11b4e971SRichard Henderson /* 224*11b4e971SRichard Henderson * Page table level 2 225*11b4e971SRichard Henderson */ 226*11b4e971SRichard Henderson pte_addr = ((in->cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & a20_mask; 227*11b4e971SRichard Henderson PTE_HPHYS(pte_addr); 228*11b4e971SRichard Henderson pte = x86_ldl_phys(cs, pte_addr); 229*11b4e971SRichard Henderson if (!(pte & PG_PRESENT_MASK)) { 230e7f2670fSClaudio Fontana goto do_fault; 231e7f2670fSClaudio Fontana } 232*11b4e971SRichard Henderson ptep = pte | PG_NX_MASK; 233e7f2670fSClaudio Fontana 234e7f2670fSClaudio Fontana /* if PSE bit is set, then we use a 4MB page */ 235*11b4e971SRichard Henderson if ((pte & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) { 2363563362dSRichard Henderson page_size = 4096 * 1024; 237*11b4e971SRichard Henderson /* 238*11b4e971SRichard Henderson * Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. 239e7f2670fSClaudio Fontana * Leave bits 20-13 in place for setting accessed/dirty bits below. 240e7f2670fSClaudio Fontana */ 241*11b4e971SRichard Henderson pte = (uint32_t)pte | ((pte & 0x1fe000LL) << (32 - 13)); 242e7f2670fSClaudio Fontana rsvd_mask = 0x200000; 243e7f2670fSClaudio Fontana goto do_check_protect_pse36; 244e7f2670fSClaudio Fontana } 245*11b4e971SRichard Henderson if (!(pte & PG_ACCESSED_MASK)) { 246*11b4e971SRichard Henderson pte |= PG_ACCESSED_MASK; 247*11b4e971SRichard Henderson x86_stl_phys_notdirty(cs, pte_addr, pte); 248e7f2670fSClaudio Fontana } 249e7f2670fSClaudio Fontana 250*11b4e971SRichard Henderson /* 251*11b4e971SRichard Henderson * Page table level 1 252*11b4e971SRichard Henderson */ 253*11b4e971SRichard Henderson pte_addr = ((pte & ~0xfffu) + ((addr >> 10) & 0xffc)) & a20_mask; 2549bbcf372SRichard Henderson PTE_HPHYS(pte_addr); 255e7f2670fSClaudio Fontana pte = x86_ldl_phys(cs, pte_addr); 256e7f2670fSClaudio Fontana if (!(pte & PG_PRESENT_MASK)) { 257e7f2670fSClaudio Fontana goto do_fault; 258e7f2670fSClaudio Fontana } 259e7f2670fSClaudio Fontana /* combine pde and pte user and rw protections */ 260e7f2670fSClaudio Fontana ptep &= pte | PG_NX_MASK; 2613563362dSRichard Henderson page_size = 4096; 262e7f2670fSClaudio Fontana rsvd_mask = 0; 263e7f2670fSClaudio Fontana } 264e7f2670fSClaudio Fontana 265e7f2670fSClaudio Fontana do_check_protect: 2663563362dSRichard Henderson rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; 267e7f2670fSClaudio Fontana do_check_protect_pse36: 268e7f2670fSClaudio Fontana if (pte & rsvd_mask) { 269e7f2670fSClaudio Fontana goto do_fault_rsvd; 270e7f2670fSClaudio Fontana } 271e7f2670fSClaudio Fontana ptep ^= PG_NX_MASK; 272e7f2670fSClaudio Fontana 273e7f2670fSClaudio Fontana /* can the page can be put in the TLB? prot will tell us */ 274e7f2670fSClaudio Fontana if (is_user && !(ptep & PG_USER_MASK)) { 275e7f2670fSClaudio Fontana goto do_fault_protect; 276e7f2670fSClaudio Fontana } 277e7f2670fSClaudio Fontana 2783563362dSRichard Henderson int prot = 0; 2793563362dSRichard Henderson if (in->mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { 2803563362dSRichard Henderson prot |= PAGE_READ; 28131dd35ebSPaolo Bonzini if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) { 2823563362dSRichard Henderson prot |= PAGE_WRITE; 283e7f2670fSClaudio Fontana } 284e7f2670fSClaudio Fontana } 285e7f2670fSClaudio Fontana if (!(ptep & PG_NX_MASK) && 2863563362dSRichard Henderson (is_user || 28731dd35ebSPaolo Bonzini !((pg_mode & PG_MODE_SMEP) && (ptep & PG_USER_MASK)))) { 2883563362dSRichard Henderson prot |= PAGE_EXEC; 289e7f2670fSClaudio Fontana } 290e7f2670fSClaudio Fontana 291991ec976SPaolo Bonzini if (ptep & PG_USER_MASK) { 29231dd35ebSPaolo Bonzini pkr = pg_mode & PG_MODE_PKE ? env->pkru : 0; 293e7f2670fSClaudio Fontana } else { 29431dd35ebSPaolo Bonzini pkr = pg_mode & PG_MODE_PKS ? env->pkrs : 0; 295e7f2670fSClaudio Fontana } 296e7f2670fSClaudio Fontana if (pkr) { 297e7f2670fSClaudio Fontana uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT; 298e7f2670fSClaudio Fontana uint32_t pkr_ad = (pkr >> pk * 2) & 1; 299e7f2670fSClaudio Fontana uint32_t pkr_wd = (pkr >> pk * 2) & 2; 300e7f2670fSClaudio Fontana uint32_t pkr_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 301e7f2670fSClaudio Fontana 302e7f2670fSClaudio Fontana if (pkr_ad) { 303e7f2670fSClaudio Fontana pkr_prot &= ~(PAGE_READ | PAGE_WRITE); 30431dd35ebSPaolo Bonzini } else if (pkr_wd && (is_user || (pg_mode & PG_MODE_WP))) { 305e7f2670fSClaudio Fontana pkr_prot &= ~PAGE_WRITE; 306e7f2670fSClaudio Fontana } 307487d1133SRichard Henderson if ((pkr_prot & (1 << access_type)) == 0) { 3083563362dSRichard Henderson goto do_fault_pk_protect; 309e7f2670fSClaudio Fontana } 3103563362dSRichard Henderson prot &= pkr_prot; 311e7f2670fSClaudio Fontana } 312e7f2670fSClaudio Fontana 3133563362dSRichard Henderson if ((prot & (1 << access_type)) == 0) { 314e7f2670fSClaudio Fontana goto do_fault_protect; 315e7f2670fSClaudio Fontana } 316e7f2670fSClaudio Fontana 317e7f2670fSClaudio Fontana /* yes, it can! */ 3183563362dSRichard Henderson { 3193563362dSRichard Henderson uint32_t set = PG_ACCESSED_MASK; 3203563362dSRichard Henderson if (access_type == MMU_DATA_STORE) { 3213563362dSRichard Henderson set |= PG_DIRTY_MASK; 322e7f2670fSClaudio Fontana } 3233563362dSRichard Henderson if (set & ~pte) { 3243563362dSRichard Henderson pte |= set; 325e7f2670fSClaudio Fontana x86_stl_phys_notdirty(cs, pte_addr, pte); 326e7f2670fSClaudio Fontana } 3273563362dSRichard Henderson } 328e7f2670fSClaudio Fontana 329e7f2670fSClaudio Fontana if (!(pte & PG_DIRTY_MASK)) { 330e7f2670fSClaudio Fontana /* only set write access if already dirty... otherwise wait 331e7f2670fSClaudio Fontana for dirty access */ 3323563362dSRichard Henderson assert(access_type != MMU_DATA_STORE); 3333563362dSRichard Henderson prot &= ~PAGE_WRITE; 334e7f2670fSClaudio Fontana } 335e7f2670fSClaudio Fontana 336e7f2670fSClaudio Fontana /* align to page_size */ 3373563362dSRichard Henderson out->paddr = (pte & a20_mask & PG_ADDRESS_MASK & ~(page_size - 1)) 3383563362dSRichard Henderson | (addr & (page_size - 1)); 3399bbcf372SRichard Henderson 3409bbcf372SRichard Henderson if (in->use_stage2) { 3419bbcf372SRichard Henderson nested_in.addr = out->paddr; 3429bbcf372SRichard Henderson nested_in.access_type = access_type; 3439bbcf372SRichard Henderson 3449bbcf372SRichard Henderson if (!mmu_translate(env, &nested_in, out, err)) { 3459bbcf372SRichard Henderson err->stage2 = S2_GPA; 3469bbcf372SRichard Henderson return false; 3479bbcf372SRichard Henderson } 3489bbcf372SRichard Henderson 3499bbcf372SRichard Henderson /* Merge stage1 & stage2 protection bits. */ 3509bbcf372SRichard Henderson prot &= out->prot; 3519bbcf372SRichard Henderson 3529bbcf372SRichard Henderson /* Re-verify resulting protection. */ 3539bbcf372SRichard Henderson if ((prot & (1 << access_type)) == 0) { 3549bbcf372SRichard Henderson goto do_fault_protect; 3559bbcf372SRichard Henderson } 3569bbcf372SRichard Henderson } 3579bbcf372SRichard Henderson 3589bbcf372SRichard Henderson out->prot = prot; 3599bbcf372SRichard Henderson out->page_size = page_size; 3603563362dSRichard Henderson return true; 361e7f2670fSClaudio Fontana 3623563362dSRichard Henderson int error_code; 363e7f2670fSClaudio Fontana do_fault_rsvd: 3643563362dSRichard Henderson error_code = PG_ERROR_RSVD_MASK; 3653563362dSRichard Henderson goto do_fault_cont; 366e7f2670fSClaudio Fontana do_fault_protect: 3673563362dSRichard Henderson error_code = PG_ERROR_P_MASK; 3683563362dSRichard Henderson goto do_fault_cont; 3693563362dSRichard Henderson do_fault_pk_protect: 3703563362dSRichard Henderson assert(access_type != MMU_INST_FETCH); 3713563362dSRichard Henderson error_code = PG_ERROR_PK_MASK | PG_ERROR_P_MASK; 3723563362dSRichard Henderson goto do_fault_cont; 373e7f2670fSClaudio Fontana do_fault: 3743563362dSRichard Henderson error_code = 0; 3753563362dSRichard Henderson do_fault_cont: 3763563362dSRichard Henderson if (is_user) { 377e7f2670fSClaudio Fontana error_code |= PG_ERROR_U_MASK; 3783563362dSRichard Henderson } 3793563362dSRichard Henderson switch (access_type) { 3803563362dSRichard Henderson case MMU_DATA_LOAD: 3813563362dSRichard Henderson break; 3823563362dSRichard Henderson case MMU_DATA_STORE: 3833563362dSRichard Henderson error_code |= PG_ERROR_W_MASK; 3843563362dSRichard Henderson break; 3853563362dSRichard Henderson case MMU_INST_FETCH: 3863563362dSRichard Henderson if (pg_mode & (PG_MODE_NXE | PG_MODE_SMEP)) { 387e7f2670fSClaudio Fontana error_code |= PG_ERROR_I_D_MASK; 3883563362dSRichard Henderson } 3893563362dSRichard Henderson break; 3903563362dSRichard Henderson } 3913563362dSRichard Henderson err->exception_index = EXCP0E_PAGE; 3923563362dSRichard Henderson err->error_code = error_code; 3933563362dSRichard Henderson err->cr2 = addr; 3949bbcf372SRichard Henderson err->stage2 = S2_NONE; 3953563362dSRichard Henderson return false; 396661ff487SPaolo Bonzini } 397661ff487SPaolo Bonzini 3989bbcf372SRichard Henderson static G_NORETURN void raise_stage2(CPUX86State *env, TranslateFault *err, 3999bbcf372SRichard Henderson uintptr_t retaddr) 4009bbcf372SRichard Henderson { 4019bbcf372SRichard Henderson uint64_t exit_info_1 = err->error_code; 4029bbcf372SRichard Henderson 4039bbcf372SRichard Henderson switch (err->stage2) { 4049bbcf372SRichard Henderson case S2_GPT: 4059bbcf372SRichard Henderson exit_info_1 |= SVM_NPTEXIT_GPT; 4069bbcf372SRichard Henderson break; 4079bbcf372SRichard Henderson case S2_GPA: 4089bbcf372SRichard Henderson exit_info_1 |= SVM_NPTEXIT_GPA; 4099bbcf372SRichard Henderson break; 4109bbcf372SRichard Henderson default: 4119bbcf372SRichard Henderson g_assert_not_reached(); 4129bbcf372SRichard Henderson } 4139bbcf372SRichard Henderson 4149bbcf372SRichard Henderson x86_stq_phys(env_cpu(env), 4159bbcf372SRichard Henderson env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 4169bbcf372SRichard Henderson err->cr2); 4179bbcf372SRichard Henderson cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, retaddr); 4189bbcf372SRichard Henderson } 4199bbcf372SRichard Henderson 4203563362dSRichard Henderson static bool get_physical_address(CPUX86State *env, vaddr addr, 4213563362dSRichard Henderson MMUAccessType access_type, int mmu_idx, 4223563362dSRichard Henderson TranslateResult *out, TranslateFault *err) 423661ff487SPaolo Bonzini { 42498281984SRichard Henderson TranslateParams in; 42598281984SRichard Henderson bool use_stage2 = env->hflags2 & HF2_NPT_MASK; 4263563362dSRichard Henderson 42798281984SRichard Henderson in.addr = addr; 42898281984SRichard Henderson in.access_type = access_type; 42998281984SRichard Henderson 43098281984SRichard Henderson switch (mmu_idx) { 43198281984SRichard Henderson case MMU_PHYS_IDX: 43298281984SRichard Henderson break; 43398281984SRichard Henderson 43498281984SRichard Henderson case MMU_NESTED_IDX: 43598281984SRichard Henderson if (likely(use_stage2)) { 43698281984SRichard Henderson in.cr3 = env->nested_cr3; 43798281984SRichard Henderson in.pg_mode = env->nested_pg_mode; 43898281984SRichard Henderson in.mmu_idx = MMU_USER_IDX; 43998281984SRichard Henderson in.use_stage2 = false; 44098281984SRichard Henderson 44198281984SRichard Henderson if (!mmu_translate(env, &in, out, err)) { 44298281984SRichard Henderson err->stage2 = S2_GPA; 44398281984SRichard Henderson return false; 444661ff487SPaolo Bonzini } 4453563362dSRichard Henderson return true; 44698281984SRichard Henderson } 44798281984SRichard Henderson break; 448b04dc92eSPaolo Bonzini 44998281984SRichard Henderson default: 45098281984SRichard Henderson in.cr3 = env->cr[3]; 45198281984SRichard Henderson in.mmu_idx = mmu_idx; 45298281984SRichard Henderson in.use_stage2 = use_stage2; 45398281984SRichard Henderson in.pg_mode = get_pg_mode(env); 45498281984SRichard Henderson 45598281984SRichard Henderson if (likely(in.pg_mode)) { 4563563362dSRichard Henderson if (in.pg_mode & PG_MODE_LMA) { 457b04dc92eSPaolo Bonzini /* test virtual address sign extension */ 4583563362dSRichard Henderson int shift = in.pg_mode & PG_MODE_LA57 ? 56 : 47; 4593563362dSRichard Henderson int64_t sext = (int64_t)addr >> shift; 460b04dc92eSPaolo Bonzini if (sext != 0 && sext != -1) { 4613563362dSRichard Henderson err->exception_index = EXCP0D_GPF; 4623563362dSRichard Henderson err->error_code = 0; 4633563362dSRichard Henderson err->cr2 = addr; 4643563362dSRichard Henderson return false; 465b04dc92eSPaolo Bonzini } 466b04dc92eSPaolo Bonzini } 4673563362dSRichard Henderson return mmu_translate(env, &in, out, err); 468e7f2670fSClaudio Fontana } 46998281984SRichard Henderson break; 47098281984SRichard Henderson } 47198281984SRichard Henderson 47298281984SRichard Henderson /* Translation disabled. */ 47398281984SRichard Henderson out->paddr = addr & x86_get_a20_mask(env); 47498281984SRichard Henderson #ifdef TARGET_X86_64 47598281984SRichard Henderson if (!(env->hflags & HF_LMA_MASK)) { 47698281984SRichard Henderson /* Without long mode we can only address 32bits in real mode */ 47798281984SRichard Henderson out->paddr = (uint32_t)out->paddr; 47898281984SRichard Henderson } 47998281984SRichard Henderson #endif 48098281984SRichard Henderson out->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; 48198281984SRichard Henderson out->page_size = TARGET_PAGE_SIZE; 48298281984SRichard Henderson return true; 483661ff487SPaolo Bonzini } 484e7f2670fSClaudio Fontana 485e7f2670fSClaudio Fontana bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, 486e7f2670fSClaudio Fontana MMUAccessType access_type, int mmu_idx, 487e7f2670fSClaudio Fontana bool probe, uintptr_t retaddr) 488e7f2670fSClaudio Fontana { 4893563362dSRichard Henderson CPUX86State *env = cs->env_ptr; 4903563362dSRichard Henderson TranslateResult out; 4913563362dSRichard Henderson TranslateFault err; 492e7f2670fSClaudio Fontana 4933563362dSRichard Henderson if (get_physical_address(env, addr, access_type, mmu_idx, &out, &err)) { 4943563362dSRichard Henderson /* 4953563362dSRichard Henderson * Even if 4MB pages, we map only one 4KB page in the cache to 4963563362dSRichard Henderson * avoid filling it too fast. 4973563362dSRichard Henderson */ 4983563362dSRichard Henderson assert(out.prot & (1 << access_type)); 4993563362dSRichard Henderson tlb_set_page_with_attrs(cs, addr & TARGET_PAGE_MASK, 5003563362dSRichard Henderson out.paddr & TARGET_PAGE_MASK, 5013563362dSRichard Henderson cpu_get_mem_attrs(env), 5023563362dSRichard Henderson out.prot, mmu_idx, out.page_size); 5033563362dSRichard Henderson return true; 5043563362dSRichard Henderson } 5053563362dSRichard Henderson 5069bbcf372SRichard Henderson if (probe) { 5079bbcf372SRichard Henderson return false; 5089bbcf372SRichard Henderson } 5099bbcf372SRichard Henderson 5109bbcf372SRichard Henderson if (err.stage2 != S2_NONE) { 5119bbcf372SRichard Henderson raise_stage2(env, &err, retaddr); 5129bbcf372SRichard Henderson } 5133563362dSRichard Henderson 5143563362dSRichard Henderson if (env->intercept_exceptions & (1 << err.exception_index)) { 5153563362dSRichard Henderson /* cr2 is not modified in case of exceptions */ 5163563362dSRichard Henderson x86_stq_phys(cs, env->vm_vmcb + 5173563362dSRichard Henderson offsetof(struct vmcb, control.exit_info_2), 5183563362dSRichard Henderson err.cr2); 5193563362dSRichard Henderson } else { 5203563362dSRichard Henderson env->cr[2] = err.cr2; 521e7f2670fSClaudio Fontana } 5223563362dSRichard Henderson raise_exception_err_ra(env, err.exception_index, err.error_code, retaddr); 523e7f2670fSClaudio Fontana } 524958e1dd1SPaolo Bonzini 525958e1dd1SPaolo Bonzini G_NORETURN void x86_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, 526958e1dd1SPaolo Bonzini MMUAccessType access_type, 527958e1dd1SPaolo Bonzini int mmu_idx, uintptr_t retaddr) 528958e1dd1SPaolo Bonzini { 529958e1dd1SPaolo Bonzini X86CPU *cpu = X86_CPU(cs); 530958e1dd1SPaolo Bonzini handle_unaligned_access(&cpu->env, vaddr, access_type, retaddr); 531958e1dd1SPaolo Bonzini } 532