xref: /openbmc/qemu/target/i386/tcg/system/excp_helper.c (revision d9a4282c4b690e45d25c2b933f318bb41eeb271d)
132cad1ffSPhilippe Mathieu-Daudé /*
232cad1ffSPhilippe Mathieu-Daudé  *  x86 exception helpers - system code
332cad1ffSPhilippe Mathieu-Daudé  *
432cad1ffSPhilippe Mathieu-Daudé  *  Copyright (c) 2003 Fabrice Bellard
532cad1ffSPhilippe Mathieu-Daudé  *
632cad1ffSPhilippe Mathieu-Daudé  * This library is free software; you can redistribute it and/or
732cad1ffSPhilippe Mathieu-Daudé  * modify it under the terms of the GNU Lesser General Public
832cad1ffSPhilippe Mathieu-Daudé  * License as published by the Free Software Foundation; either
932cad1ffSPhilippe Mathieu-Daudé  * version 2.1 of the License, or (at your option) any later version.
1032cad1ffSPhilippe Mathieu-Daudé  *
1132cad1ffSPhilippe Mathieu-Daudé  * This library is distributed in the hope that it will be useful,
1232cad1ffSPhilippe Mathieu-Daudé  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1332cad1ffSPhilippe Mathieu-Daudé  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1432cad1ffSPhilippe Mathieu-Daudé  * Lesser General Public License for more details.
1532cad1ffSPhilippe Mathieu-Daudé  *
1632cad1ffSPhilippe Mathieu-Daudé  * You should have received a copy of the GNU Lesser General Public
1732cad1ffSPhilippe Mathieu-Daudé  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1832cad1ffSPhilippe Mathieu-Daudé  */
1932cad1ffSPhilippe Mathieu-Daudé 
2032cad1ffSPhilippe Mathieu-Daudé #include "qemu/osdep.h"
2132cad1ffSPhilippe Mathieu-Daudé #include "cpu.h"
2232cad1ffSPhilippe Mathieu-Daudé #include "exec/cpu_ldst.h"
23*2809e2d6SPhilippe Mathieu-Daudé #include "exec/cputlb.h"
2432cad1ffSPhilippe Mathieu-Daudé #include "exec/page-protection.h"
2532cad1ffSPhilippe Mathieu-Daudé #include "tcg/helper-tcg.h"
2632cad1ffSPhilippe Mathieu-Daudé 
2732cad1ffSPhilippe Mathieu-Daudé typedef struct TranslateParams {
2832cad1ffSPhilippe Mathieu-Daudé     target_ulong addr;
2932cad1ffSPhilippe Mathieu-Daudé     target_ulong cr3;
3032cad1ffSPhilippe Mathieu-Daudé     int pg_mode;
3132cad1ffSPhilippe Mathieu-Daudé     int mmu_idx;
3232cad1ffSPhilippe Mathieu-Daudé     int ptw_idx;
3332cad1ffSPhilippe Mathieu-Daudé     MMUAccessType access_type;
3432cad1ffSPhilippe Mathieu-Daudé } TranslateParams;
3532cad1ffSPhilippe Mathieu-Daudé 
3632cad1ffSPhilippe Mathieu-Daudé typedef struct TranslateResult {
3732cad1ffSPhilippe Mathieu-Daudé     hwaddr paddr;
3832cad1ffSPhilippe Mathieu-Daudé     int prot;
3932cad1ffSPhilippe Mathieu-Daudé     int page_size;
4032cad1ffSPhilippe Mathieu-Daudé } TranslateResult;
4132cad1ffSPhilippe Mathieu-Daudé 
4232cad1ffSPhilippe Mathieu-Daudé typedef enum TranslateFaultStage2 {
4332cad1ffSPhilippe Mathieu-Daudé     S2_NONE,
4432cad1ffSPhilippe Mathieu-Daudé     S2_GPA,
4532cad1ffSPhilippe Mathieu-Daudé     S2_GPT,
4632cad1ffSPhilippe Mathieu-Daudé } TranslateFaultStage2;
4732cad1ffSPhilippe Mathieu-Daudé 
4832cad1ffSPhilippe Mathieu-Daudé typedef struct TranslateFault {
4932cad1ffSPhilippe Mathieu-Daudé     int exception_index;
5032cad1ffSPhilippe Mathieu-Daudé     int error_code;
5132cad1ffSPhilippe Mathieu-Daudé     target_ulong cr2;
5232cad1ffSPhilippe Mathieu-Daudé     TranslateFaultStage2 stage2;
5332cad1ffSPhilippe Mathieu-Daudé } TranslateFault;
5432cad1ffSPhilippe Mathieu-Daudé 
5532cad1ffSPhilippe Mathieu-Daudé typedef struct PTETranslate {
5632cad1ffSPhilippe Mathieu-Daudé     CPUX86State *env;
5732cad1ffSPhilippe Mathieu-Daudé     TranslateFault *err;
5832cad1ffSPhilippe Mathieu-Daudé     int ptw_idx;
5932cad1ffSPhilippe Mathieu-Daudé     void *haddr;
6032cad1ffSPhilippe Mathieu-Daudé     hwaddr gaddr;
6132cad1ffSPhilippe Mathieu-Daudé } PTETranslate;
6232cad1ffSPhilippe Mathieu-Daudé 
ptw_translate(PTETranslate * inout,hwaddr addr)6332cad1ffSPhilippe Mathieu-Daudé static bool ptw_translate(PTETranslate *inout, hwaddr addr)
6432cad1ffSPhilippe Mathieu-Daudé {
6532cad1ffSPhilippe Mathieu-Daudé     int flags;
6632cad1ffSPhilippe Mathieu-Daudé 
6732cad1ffSPhilippe Mathieu-Daudé     inout->gaddr = addr;
6832cad1ffSPhilippe Mathieu-Daudé     flags = probe_access_full_mmu(inout->env, addr, 0, MMU_DATA_STORE,
6932cad1ffSPhilippe Mathieu-Daudé                                   inout->ptw_idx, &inout->haddr, NULL);
7032cad1ffSPhilippe Mathieu-Daudé 
7132cad1ffSPhilippe Mathieu-Daudé     if (unlikely(flags & TLB_INVALID_MASK)) {
7232cad1ffSPhilippe Mathieu-Daudé         TranslateFault *err = inout->err;
7332cad1ffSPhilippe Mathieu-Daudé 
7432cad1ffSPhilippe Mathieu-Daudé         assert(inout->ptw_idx == MMU_NESTED_IDX);
7532cad1ffSPhilippe Mathieu-Daudé         *err = (TranslateFault){
7632cad1ffSPhilippe Mathieu-Daudé             .error_code = inout->env->error_code,
7732cad1ffSPhilippe Mathieu-Daudé             .cr2 = addr,
7832cad1ffSPhilippe Mathieu-Daudé             .stage2 = S2_GPT,
7932cad1ffSPhilippe Mathieu-Daudé         };
8032cad1ffSPhilippe Mathieu-Daudé         return false;
8132cad1ffSPhilippe Mathieu-Daudé     }
8232cad1ffSPhilippe Mathieu-Daudé     return true;
8332cad1ffSPhilippe Mathieu-Daudé }
8432cad1ffSPhilippe Mathieu-Daudé 
ptw_ldl(const PTETranslate * in,uint64_t ra)8532cad1ffSPhilippe Mathieu-Daudé static inline uint32_t ptw_ldl(const PTETranslate *in, uint64_t ra)
8632cad1ffSPhilippe Mathieu-Daudé {
8732cad1ffSPhilippe Mathieu-Daudé     if (likely(in->haddr)) {
8832cad1ffSPhilippe Mathieu-Daudé         return ldl_p(in->haddr);
8932cad1ffSPhilippe Mathieu-Daudé     }
9032cad1ffSPhilippe Mathieu-Daudé     return cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, ra);
9132cad1ffSPhilippe Mathieu-Daudé }
9232cad1ffSPhilippe Mathieu-Daudé 
ptw_ldq(const PTETranslate * in,uint64_t ra)9332cad1ffSPhilippe Mathieu-Daudé static inline uint64_t ptw_ldq(const PTETranslate *in, uint64_t ra)
9432cad1ffSPhilippe Mathieu-Daudé {
9532cad1ffSPhilippe Mathieu-Daudé     if (likely(in->haddr)) {
9632cad1ffSPhilippe Mathieu-Daudé         return ldq_p(in->haddr);
9732cad1ffSPhilippe Mathieu-Daudé     }
9832cad1ffSPhilippe Mathieu-Daudé     return cpu_ldq_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, ra);
9932cad1ffSPhilippe Mathieu-Daudé }
10032cad1ffSPhilippe Mathieu-Daudé 
10132cad1ffSPhilippe Mathieu-Daudé /*
10232cad1ffSPhilippe Mathieu-Daudé  * Note that we can use a 32-bit cmpxchg for all page table entries,
10332cad1ffSPhilippe Mathieu-Daudé  * even 64-bit ones, because PG_PRESENT_MASK, PG_ACCESSED_MASK and
10432cad1ffSPhilippe Mathieu-Daudé  * PG_DIRTY_MASK are all in the low 32 bits.
10532cad1ffSPhilippe Mathieu-Daudé  */
ptw_setl_slow(const PTETranslate * in,uint32_t old,uint32_t new)10632cad1ffSPhilippe Mathieu-Daudé static bool ptw_setl_slow(const PTETranslate *in, uint32_t old, uint32_t new)
10732cad1ffSPhilippe Mathieu-Daudé {
10832cad1ffSPhilippe Mathieu-Daudé     uint32_t cmp;
10932cad1ffSPhilippe Mathieu-Daudé 
11032cad1ffSPhilippe Mathieu-Daudé     CPUState *cpu = env_cpu(in->env);
11132cad1ffSPhilippe Mathieu-Daudé     /* We are in cpu_exec, and start_exclusive can't be called directly.*/
11232cad1ffSPhilippe Mathieu-Daudé     g_assert(cpu->running);
11332cad1ffSPhilippe Mathieu-Daudé     cpu_exec_end(cpu);
11432cad1ffSPhilippe Mathieu-Daudé     /* Does x86 really perform a rmw cycle on mmio for ptw? */
11532cad1ffSPhilippe Mathieu-Daudé     start_exclusive();
11632cad1ffSPhilippe Mathieu-Daudé     cmp = cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0);
11732cad1ffSPhilippe Mathieu-Daudé     if (cmp == old) {
11832cad1ffSPhilippe Mathieu-Daudé         cpu_stl_mmuidx_ra(in->env, in->gaddr, new, in->ptw_idx, 0);
11932cad1ffSPhilippe Mathieu-Daudé     }
12032cad1ffSPhilippe Mathieu-Daudé     end_exclusive();
12132cad1ffSPhilippe Mathieu-Daudé     cpu_exec_start(cpu);
12232cad1ffSPhilippe Mathieu-Daudé     return cmp == old;
12332cad1ffSPhilippe Mathieu-Daudé }
12432cad1ffSPhilippe Mathieu-Daudé 
ptw_setl(const PTETranslate * in,uint32_t old,uint32_t set)12532cad1ffSPhilippe Mathieu-Daudé static inline bool ptw_setl(const PTETranslate *in, uint32_t old, uint32_t set)
12632cad1ffSPhilippe Mathieu-Daudé {
12732cad1ffSPhilippe Mathieu-Daudé     if (set & ~old) {
12832cad1ffSPhilippe Mathieu-Daudé         uint32_t new = old | set;
12932cad1ffSPhilippe Mathieu-Daudé         if (likely(in->haddr)) {
13032cad1ffSPhilippe Mathieu-Daudé             old = cpu_to_le32(old);
13132cad1ffSPhilippe Mathieu-Daudé             new = cpu_to_le32(new);
13232cad1ffSPhilippe Mathieu-Daudé             return qatomic_cmpxchg((uint32_t *)in->haddr, old, new) == old;
13332cad1ffSPhilippe Mathieu-Daudé         }
13432cad1ffSPhilippe Mathieu-Daudé         return ptw_setl_slow(in, old, new);
13532cad1ffSPhilippe Mathieu-Daudé     }
13632cad1ffSPhilippe Mathieu-Daudé     return true;
13732cad1ffSPhilippe Mathieu-Daudé }
13832cad1ffSPhilippe Mathieu-Daudé 
mmu_translate(CPUX86State * env,const TranslateParams * in,TranslateResult * out,TranslateFault * err,uint64_t ra)13932cad1ffSPhilippe Mathieu-Daudé static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
14032cad1ffSPhilippe Mathieu-Daudé                           TranslateResult *out, TranslateFault *err,
14132cad1ffSPhilippe Mathieu-Daudé                           uint64_t ra)
14232cad1ffSPhilippe Mathieu-Daudé {
14332cad1ffSPhilippe Mathieu-Daudé     const target_ulong addr = in->addr;
14432cad1ffSPhilippe Mathieu-Daudé     const int pg_mode = in->pg_mode;
14532cad1ffSPhilippe Mathieu-Daudé     const bool is_user = is_mmu_index_user(in->mmu_idx);
14632cad1ffSPhilippe Mathieu-Daudé     const MMUAccessType access_type = in->access_type;
14732cad1ffSPhilippe Mathieu-Daudé     uint64_t ptep, pte, rsvd_mask;
14832cad1ffSPhilippe Mathieu-Daudé     PTETranslate pte_trans = {
14932cad1ffSPhilippe Mathieu-Daudé         .env = env,
15032cad1ffSPhilippe Mathieu-Daudé         .err = err,
15132cad1ffSPhilippe Mathieu-Daudé         .ptw_idx = in->ptw_idx,
15232cad1ffSPhilippe Mathieu-Daudé     };
15332cad1ffSPhilippe Mathieu-Daudé     hwaddr pte_addr, paddr;
15432cad1ffSPhilippe Mathieu-Daudé     uint32_t pkr;
15532cad1ffSPhilippe Mathieu-Daudé     int page_size;
15632cad1ffSPhilippe Mathieu-Daudé     int error_code;
15732cad1ffSPhilippe Mathieu-Daudé     int prot;
15832cad1ffSPhilippe Mathieu-Daudé 
15932cad1ffSPhilippe Mathieu-Daudé  restart_all:
16032cad1ffSPhilippe Mathieu-Daudé     rsvd_mask = ~MAKE_64BIT_MASK(0, env_archcpu(env)->phys_bits);
16132cad1ffSPhilippe Mathieu-Daudé     rsvd_mask &= PG_ADDRESS_MASK;
16232cad1ffSPhilippe Mathieu-Daudé     if (!(pg_mode & PG_MODE_NXE)) {
16332cad1ffSPhilippe Mathieu-Daudé         rsvd_mask |= PG_NX_MASK;
16432cad1ffSPhilippe Mathieu-Daudé     }
16532cad1ffSPhilippe Mathieu-Daudé 
16632cad1ffSPhilippe Mathieu-Daudé     if (pg_mode & PG_MODE_PAE) {
16732cad1ffSPhilippe Mathieu-Daudé #ifdef TARGET_X86_64
16832cad1ffSPhilippe Mathieu-Daudé         if (pg_mode & PG_MODE_LMA) {
16932cad1ffSPhilippe Mathieu-Daudé             if (pg_mode & PG_MODE_LA57) {
17032cad1ffSPhilippe Mathieu-Daudé                 /*
17132cad1ffSPhilippe Mathieu-Daudé                  * Page table level 5
17232cad1ffSPhilippe Mathieu-Daudé                  */
17332cad1ffSPhilippe Mathieu-Daudé                 pte_addr = (in->cr3 & ~0xfff) + (((addr >> 48) & 0x1ff) << 3);
17432cad1ffSPhilippe Mathieu-Daudé                 if (!ptw_translate(&pte_trans, pte_addr)) {
17532cad1ffSPhilippe Mathieu-Daudé                     return false;
17632cad1ffSPhilippe Mathieu-Daudé                 }
17732cad1ffSPhilippe Mathieu-Daudé             restart_5:
17832cad1ffSPhilippe Mathieu-Daudé                 pte = ptw_ldq(&pte_trans, ra);
17932cad1ffSPhilippe Mathieu-Daudé                 if (!(pte & PG_PRESENT_MASK)) {
18032cad1ffSPhilippe Mathieu-Daudé                     goto do_fault;
18132cad1ffSPhilippe Mathieu-Daudé                 }
18232cad1ffSPhilippe Mathieu-Daudé                 if (pte & (rsvd_mask | PG_PSE_MASK)) {
18332cad1ffSPhilippe Mathieu-Daudé                     goto do_fault_rsvd;
18432cad1ffSPhilippe Mathieu-Daudé                 }
18532cad1ffSPhilippe Mathieu-Daudé                 if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
18632cad1ffSPhilippe Mathieu-Daudé                     goto restart_5;
18732cad1ffSPhilippe Mathieu-Daudé                 }
18832cad1ffSPhilippe Mathieu-Daudé                 ptep = pte ^ PG_NX_MASK;
18932cad1ffSPhilippe Mathieu-Daudé             } else {
19032cad1ffSPhilippe Mathieu-Daudé                 pte = in->cr3;
19132cad1ffSPhilippe Mathieu-Daudé                 ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
19232cad1ffSPhilippe Mathieu-Daudé             }
19332cad1ffSPhilippe Mathieu-Daudé 
19432cad1ffSPhilippe Mathieu-Daudé             /*
19532cad1ffSPhilippe Mathieu-Daudé              * Page table level 4
19632cad1ffSPhilippe Mathieu-Daudé              */
19732cad1ffSPhilippe Mathieu-Daudé             pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 39) & 0x1ff) << 3);
19832cad1ffSPhilippe Mathieu-Daudé             if (!ptw_translate(&pte_trans, pte_addr)) {
19932cad1ffSPhilippe Mathieu-Daudé                 return false;
20032cad1ffSPhilippe Mathieu-Daudé             }
20132cad1ffSPhilippe Mathieu-Daudé         restart_4:
20232cad1ffSPhilippe Mathieu-Daudé             pte = ptw_ldq(&pte_trans, ra);
20332cad1ffSPhilippe Mathieu-Daudé             if (!(pte & PG_PRESENT_MASK)) {
20432cad1ffSPhilippe Mathieu-Daudé                 goto do_fault;
20532cad1ffSPhilippe Mathieu-Daudé             }
20632cad1ffSPhilippe Mathieu-Daudé             if (pte & (rsvd_mask | PG_PSE_MASK)) {
20732cad1ffSPhilippe Mathieu-Daudé                 goto do_fault_rsvd;
20832cad1ffSPhilippe Mathieu-Daudé             }
20932cad1ffSPhilippe Mathieu-Daudé             if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
21032cad1ffSPhilippe Mathieu-Daudé                 goto restart_4;
21132cad1ffSPhilippe Mathieu-Daudé             }
21232cad1ffSPhilippe Mathieu-Daudé             ptep &= pte ^ PG_NX_MASK;
21332cad1ffSPhilippe Mathieu-Daudé 
21432cad1ffSPhilippe Mathieu-Daudé             /*
21532cad1ffSPhilippe Mathieu-Daudé              * Page table level 3
21632cad1ffSPhilippe Mathieu-Daudé              */
21732cad1ffSPhilippe Mathieu-Daudé             pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3);
21832cad1ffSPhilippe Mathieu-Daudé             if (!ptw_translate(&pte_trans, pte_addr)) {
21932cad1ffSPhilippe Mathieu-Daudé                 return false;
22032cad1ffSPhilippe Mathieu-Daudé             }
22132cad1ffSPhilippe Mathieu-Daudé         restart_3_lma:
22232cad1ffSPhilippe Mathieu-Daudé             pte = ptw_ldq(&pte_trans, ra);
22332cad1ffSPhilippe Mathieu-Daudé             if (!(pte & PG_PRESENT_MASK)) {
22432cad1ffSPhilippe Mathieu-Daudé                 goto do_fault;
22532cad1ffSPhilippe Mathieu-Daudé             }
22632cad1ffSPhilippe Mathieu-Daudé             if (pte & rsvd_mask) {
22732cad1ffSPhilippe Mathieu-Daudé                 goto do_fault_rsvd;
22832cad1ffSPhilippe Mathieu-Daudé             }
22932cad1ffSPhilippe Mathieu-Daudé             if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
23032cad1ffSPhilippe Mathieu-Daudé                 goto restart_3_lma;
23132cad1ffSPhilippe Mathieu-Daudé             }
23232cad1ffSPhilippe Mathieu-Daudé             ptep &= pte ^ PG_NX_MASK;
23332cad1ffSPhilippe Mathieu-Daudé             if (pte & PG_PSE_MASK) {
23432cad1ffSPhilippe Mathieu-Daudé                 /* 1 GB page */
23532cad1ffSPhilippe Mathieu-Daudé                 page_size = 1024 * 1024 * 1024;
23632cad1ffSPhilippe Mathieu-Daudé                 goto do_check_protect;
23732cad1ffSPhilippe Mathieu-Daudé             }
23832cad1ffSPhilippe Mathieu-Daudé         } else
23932cad1ffSPhilippe Mathieu-Daudé #endif
24032cad1ffSPhilippe Mathieu-Daudé         {
24132cad1ffSPhilippe Mathieu-Daudé             /*
24232cad1ffSPhilippe Mathieu-Daudé              * Page table level 3
24332cad1ffSPhilippe Mathieu-Daudé              */
24432cad1ffSPhilippe Mathieu-Daudé             pte_addr = (in->cr3 & 0xffffffe0ULL) + ((addr >> 27) & 0x18);
24532cad1ffSPhilippe Mathieu-Daudé             if (!ptw_translate(&pte_trans, pte_addr)) {
24632cad1ffSPhilippe Mathieu-Daudé                 return false;
24732cad1ffSPhilippe Mathieu-Daudé             }
24832cad1ffSPhilippe Mathieu-Daudé             rsvd_mask |= PG_HI_USER_MASK;
24932cad1ffSPhilippe Mathieu-Daudé         restart_3_nolma:
25032cad1ffSPhilippe Mathieu-Daudé             pte = ptw_ldq(&pte_trans, ra);
25132cad1ffSPhilippe Mathieu-Daudé             if (!(pte & PG_PRESENT_MASK)) {
25232cad1ffSPhilippe Mathieu-Daudé                 goto do_fault;
25332cad1ffSPhilippe Mathieu-Daudé             }
25432cad1ffSPhilippe Mathieu-Daudé             if (pte & (rsvd_mask | PG_NX_MASK)) {
25532cad1ffSPhilippe Mathieu-Daudé                 goto do_fault_rsvd;
25632cad1ffSPhilippe Mathieu-Daudé             }
25732cad1ffSPhilippe Mathieu-Daudé             if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
25832cad1ffSPhilippe Mathieu-Daudé                 goto restart_3_nolma;
25932cad1ffSPhilippe Mathieu-Daudé             }
26032cad1ffSPhilippe Mathieu-Daudé             ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
26132cad1ffSPhilippe Mathieu-Daudé         }
26232cad1ffSPhilippe Mathieu-Daudé 
26332cad1ffSPhilippe Mathieu-Daudé         /*
26432cad1ffSPhilippe Mathieu-Daudé          * Page table level 2
26532cad1ffSPhilippe Mathieu-Daudé          */
26632cad1ffSPhilippe Mathieu-Daudé         pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3);
26732cad1ffSPhilippe Mathieu-Daudé         if (!ptw_translate(&pte_trans, pte_addr)) {
26832cad1ffSPhilippe Mathieu-Daudé             return false;
26932cad1ffSPhilippe Mathieu-Daudé         }
27032cad1ffSPhilippe Mathieu-Daudé     restart_2_pae:
27132cad1ffSPhilippe Mathieu-Daudé         pte = ptw_ldq(&pte_trans, ra);
27232cad1ffSPhilippe Mathieu-Daudé         if (!(pte & PG_PRESENT_MASK)) {
27332cad1ffSPhilippe Mathieu-Daudé             goto do_fault;
27432cad1ffSPhilippe Mathieu-Daudé         }
27532cad1ffSPhilippe Mathieu-Daudé         if (pte & rsvd_mask) {
27632cad1ffSPhilippe Mathieu-Daudé             goto do_fault_rsvd;
27732cad1ffSPhilippe Mathieu-Daudé         }
27832cad1ffSPhilippe Mathieu-Daudé         if (pte & PG_PSE_MASK) {
27932cad1ffSPhilippe Mathieu-Daudé             /* 2 MB page */
28032cad1ffSPhilippe Mathieu-Daudé             page_size = 2048 * 1024;
28132cad1ffSPhilippe Mathieu-Daudé             ptep &= pte ^ PG_NX_MASK;
28232cad1ffSPhilippe Mathieu-Daudé             goto do_check_protect;
28332cad1ffSPhilippe Mathieu-Daudé         }
28432cad1ffSPhilippe Mathieu-Daudé         if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
28532cad1ffSPhilippe Mathieu-Daudé             goto restart_2_pae;
28632cad1ffSPhilippe Mathieu-Daudé         }
28732cad1ffSPhilippe Mathieu-Daudé         ptep &= pte ^ PG_NX_MASK;
28832cad1ffSPhilippe Mathieu-Daudé 
28932cad1ffSPhilippe Mathieu-Daudé         /*
29032cad1ffSPhilippe Mathieu-Daudé          * Page table level 1
29132cad1ffSPhilippe Mathieu-Daudé          */
29232cad1ffSPhilippe Mathieu-Daudé         pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3);
29332cad1ffSPhilippe Mathieu-Daudé         if (!ptw_translate(&pte_trans, pte_addr)) {
29432cad1ffSPhilippe Mathieu-Daudé             return false;
29532cad1ffSPhilippe Mathieu-Daudé         }
29632cad1ffSPhilippe Mathieu-Daudé         pte = ptw_ldq(&pte_trans, ra);
29732cad1ffSPhilippe Mathieu-Daudé         if (!(pte & PG_PRESENT_MASK)) {
29832cad1ffSPhilippe Mathieu-Daudé             goto do_fault;
29932cad1ffSPhilippe Mathieu-Daudé         }
30032cad1ffSPhilippe Mathieu-Daudé         if (pte & rsvd_mask) {
30132cad1ffSPhilippe Mathieu-Daudé             goto do_fault_rsvd;
30232cad1ffSPhilippe Mathieu-Daudé         }
30332cad1ffSPhilippe Mathieu-Daudé         /* combine pde and pte nx, user and rw protections */
30432cad1ffSPhilippe Mathieu-Daudé         ptep &= pte ^ PG_NX_MASK;
30532cad1ffSPhilippe Mathieu-Daudé         page_size = 4096;
30632cad1ffSPhilippe Mathieu-Daudé     } else if (pg_mode & PG_MODE_PG) {
30732cad1ffSPhilippe Mathieu-Daudé         /*
30832cad1ffSPhilippe Mathieu-Daudé          * Page table level 2
30932cad1ffSPhilippe Mathieu-Daudé          */
31032cad1ffSPhilippe Mathieu-Daudé         pte_addr = (in->cr3 & 0xfffff000ULL) + ((addr >> 20) & 0xffc);
31132cad1ffSPhilippe Mathieu-Daudé         if (!ptw_translate(&pte_trans, pte_addr)) {
31232cad1ffSPhilippe Mathieu-Daudé             return false;
31332cad1ffSPhilippe Mathieu-Daudé         }
31432cad1ffSPhilippe Mathieu-Daudé     restart_2_nopae:
31532cad1ffSPhilippe Mathieu-Daudé         pte = ptw_ldl(&pte_trans, ra);
31632cad1ffSPhilippe Mathieu-Daudé         if (!(pte & PG_PRESENT_MASK)) {
31732cad1ffSPhilippe Mathieu-Daudé             goto do_fault;
31832cad1ffSPhilippe Mathieu-Daudé         }
31932cad1ffSPhilippe Mathieu-Daudé         ptep = pte | PG_NX_MASK;
32032cad1ffSPhilippe Mathieu-Daudé 
32132cad1ffSPhilippe Mathieu-Daudé         /* if PSE bit is set, then we use a 4MB page */
32232cad1ffSPhilippe Mathieu-Daudé         if ((pte & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) {
32332cad1ffSPhilippe Mathieu-Daudé             page_size = 4096 * 1024;
32432cad1ffSPhilippe Mathieu-Daudé             /*
32532cad1ffSPhilippe Mathieu-Daudé              * Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved.
32632cad1ffSPhilippe Mathieu-Daudé              * Leave bits 20-13 in place for setting accessed/dirty bits below.
32732cad1ffSPhilippe Mathieu-Daudé              */
32832cad1ffSPhilippe Mathieu-Daudé             pte = (uint32_t)pte | ((pte & 0x1fe000LL) << (32 - 13));
32932cad1ffSPhilippe Mathieu-Daudé             rsvd_mask = 0x200000;
33032cad1ffSPhilippe Mathieu-Daudé             goto do_check_protect_pse36;
33132cad1ffSPhilippe Mathieu-Daudé         }
33232cad1ffSPhilippe Mathieu-Daudé         if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
33332cad1ffSPhilippe Mathieu-Daudé             goto restart_2_nopae;
33432cad1ffSPhilippe Mathieu-Daudé         }
33532cad1ffSPhilippe Mathieu-Daudé 
33632cad1ffSPhilippe Mathieu-Daudé         /*
33732cad1ffSPhilippe Mathieu-Daudé          * Page table level 1
33832cad1ffSPhilippe Mathieu-Daudé          */
33932cad1ffSPhilippe Mathieu-Daudé         pte_addr = (pte & ~0xfffu) + ((addr >> 10) & 0xffc);
34032cad1ffSPhilippe Mathieu-Daudé         if (!ptw_translate(&pte_trans, pte_addr)) {
34132cad1ffSPhilippe Mathieu-Daudé             return false;
34232cad1ffSPhilippe Mathieu-Daudé         }
34332cad1ffSPhilippe Mathieu-Daudé         pte = ptw_ldl(&pte_trans, ra);
34432cad1ffSPhilippe Mathieu-Daudé         if (!(pte & PG_PRESENT_MASK)) {
34532cad1ffSPhilippe Mathieu-Daudé             goto do_fault;
34632cad1ffSPhilippe Mathieu-Daudé         }
34732cad1ffSPhilippe Mathieu-Daudé         /* combine pde and pte user and rw protections */
34832cad1ffSPhilippe Mathieu-Daudé         ptep &= pte | PG_NX_MASK;
34932cad1ffSPhilippe Mathieu-Daudé         page_size = 4096;
35032cad1ffSPhilippe Mathieu-Daudé         rsvd_mask = 0;
35132cad1ffSPhilippe Mathieu-Daudé     } else {
35232cad1ffSPhilippe Mathieu-Daudé         /*
35332cad1ffSPhilippe Mathieu-Daudé          * No paging (real mode), let's tentatively resolve the address as 1:1
35432cad1ffSPhilippe Mathieu-Daudé          * here, but conditionally still perform an NPT walk on it later.
35532cad1ffSPhilippe Mathieu-Daudé          */
35632cad1ffSPhilippe Mathieu-Daudé         page_size = 0x40000000;
35732cad1ffSPhilippe Mathieu-Daudé         paddr = in->addr;
35832cad1ffSPhilippe Mathieu-Daudé         prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
35932cad1ffSPhilippe Mathieu-Daudé         goto stage2;
36032cad1ffSPhilippe Mathieu-Daudé     }
36132cad1ffSPhilippe Mathieu-Daudé 
36232cad1ffSPhilippe Mathieu-Daudé do_check_protect:
36332cad1ffSPhilippe Mathieu-Daudé     rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK;
36432cad1ffSPhilippe Mathieu-Daudé do_check_protect_pse36:
36532cad1ffSPhilippe Mathieu-Daudé     if (pte & rsvd_mask) {
36632cad1ffSPhilippe Mathieu-Daudé         goto do_fault_rsvd;
36732cad1ffSPhilippe Mathieu-Daudé     }
36832cad1ffSPhilippe Mathieu-Daudé     ptep ^= PG_NX_MASK;
36932cad1ffSPhilippe Mathieu-Daudé 
37032cad1ffSPhilippe Mathieu-Daudé     /* can the page can be put in the TLB?  prot will tell us */
37132cad1ffSPhilippe Mathieu-Daudé     if (is_user && !(ptep & PG_USER_MASK)) {
37232cad1ffSPhilippe Mathieu-Daudé         goto do_fault_protect;
37332cad1ffSPhilippe Mathieu-Daudé     }
37432cad1ffSPhilippe Mathieu-Daudé 
37532cad1ffSPhilippe Mathieu-Daudé     prot = 0;
37632cad1ffSPhilippe Mathieu-Daudé     if (!is_mmu_index_smap(in->mmu_idx) || !(ptep & PG_USER_MASK)) {
37732cad1ffSPhilippe Mathieu-Daudé         prot |= PAGE_READ;
37832cad1ffSPhilippe Mathieu-Daudé         if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) {
37932cad1ffSPhilippe Mathieu-Daudé             prot |= PAGE_WRITE;
38032cad1ffSPhilippe Mathieu-Daudé         }
38132cad1ffSPhilippe Mathieu-Daudé     }
38232cad1ffSPhilippe Mathieu-Daudé     if (!(ptep & PG_NX_MASK) &&
38332cad1ffSPhilippe Mathieu-Daudé         (is_user ||
38432cad1ffSPhilippe Mathieu-Daudé          !((pg_mode & PG_MODE_SMEP) && (ptep & PG_USER_MASK)))) {
38532cad1ffSPhilippe Mathieu-Daudé         prot |= PAGE_EXEC;
38632cad1ffSPhilippe Mathieu-Daudé     }
38732cad1ffSPhilippe Mathieu-Daudé 
38832cad1ffSPhilippe Mathieu-Daudé     if (ptep & PG_USER_MASK) {
38932cad1ffSPhilippe Mathieu-Daudé         pkr = pg_mode & PG_MODE_PKE ? env->pkru : 0;
39032cad1ffSPhilippe Mathieu-Daudé     } else {
39132cad1ffSPhilippe Mathieu-Daudé         pkr = pg_mode & PG_MODE_PKS ? env->pkrs : 0;
39232cad1ffSPhilippe Mathieu-Daudé     }
39332cad1ffSPhilippe Mathieu-Daudé     if (pkr) {
39432cad1ffSPhilippe Mathieu-Daudé         uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT;
39532cad1ffSPhilippe Mathieu-Daudé         uint32_t pkr_ad = (pkr >> pk * 2) & 1;
39632cad1ffSPhilippe Mathieu-Daudé         uint32_t pkr_wd = (pkr >> pk * 2) & 2;
39732cad1ffSPhilippe Mathieu-Daudé         uint32_t pkr_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
39832cad1ffSPhilippe Mathieu-Daudé 
39932cad1ffSPhilippe Mathieu-Daudé         if (pkr_ad) {
40032cad1ffSPhilippe Mathieu-Daudé             pkr_prot &= ~(PAGE_READ | PAGE_WRITE);
40132cad1ffSPhilippe Mathieu-Daudé         } else if (pkr_wd && (is_user || (pg_mode & PG_MODE_WP))) {
40232cad1ffSPhilippe Mathieu-Daudé             pkr_prot &= ~PAGE_WRITE;
40332cad1ffSPhilippe Mathieu-Daudé         }
40432cad1ffSPhilippe Mathieu-Daudé         if ((pkr_prot & (1 << access_type)) == 0) {
40532cad1ffSPhilippe Mathieu-Daudé             goto do_fault_pk_protect;
40632cad1ffSPhilippe Mathieu-Daudé         }
40732cad1ffSPhilippe Mathieu-Daudé         prot &= pkr_prot;
40832cad1ffSPhilippe Mathieu-Daudé     }
40932cad1ffSPhilippe Mathieu-Daudé 
41032cad1ffSPhilippe Mathieu-Daudé     if ((prot & (1 << access_type)) == 0) {
41132cad1ffSPhilippe Mathieu-Daudé         goto do_fault_protect;
41232cad1ffSPhilippe Mathieu-Daudé     }
41332cad1ffSPhilippe Mathieu-Daudé 
41432cad1ffSPhilippe Mathieu-Daudé     /* yes, it can! */
41532cad1ffSPhilippe Mathieu-Daudé     {
41632cad1ffSPhilippe Mathieu-Daudé         uint32_t set = PG_ACCESSED_MASK;
41732cad1ffSPhilippe Mathieu-Daudé         if (access_type == MMU_DATA_STORE) {
41832cad1ffSPhilippe Mathieu-Daudé             set |= PG_DIRTY_MASK;
41932cad1ffSPhilippe Mathieu-Daudé         } else if (!(pte & PG_DIRTY_MASK)) {
42032cad1ffSPhilippe Mathieu-Daudé             /*
42132cad1ffSPhilippe Mathieu-Daudé              * Only set write access if already dirty...
42232cad1ffSPhilippe Mathieu-Daudé              * otherwise wait for dirty access.
42332cad1ffSPhilippe Mathieu-Daudé              */
42432cad1ffSPhilippe Mathieu-Daudé             prot &= ~PAGE_WRITE;
42532cad1ffSPhilippe Mathieu-Daudé         }
42632cad1ffSPhilippe Mathieu-Daudé         if (!ptw_setl(&pte_trans, pte, set)) {
42732cad1ffSPhilippe Mathieu-Daudé             /*
42832cad1ffSPhilippe Mathieu-Daudé              * We can arrive here from any of 3 levels and 2 formats.
42932cad1ffSPhilippe Mathieu-Daudé              * The only safe thing is to restart the entire lookup.
43032cad1ffSPhilippe Mathieu-Daudé              */
43132cad1ffSPhilippe Mathieu-Daudé             goto restart_all;
43232cad1ffSPhilippe Mathieu-Daudé         }
43332cad1ffSPhilippe Mathieu-Daudé     }
43432cad1ffSPhilippe Mathieu-Daudé 
43532cad1ffSPhilippe Mathieu-Daudé     /* merge offset within page */
43632cad1ffSPhilippe Mathieu-Daudé     paddr = (pte & PG_ADDRESS_MASK & ~(page_size - 1)) | (addr & (page_size - 1));
43732cad1ffSPhilippe Mathieu-Daudé  stage2:
43832cad1ffSPhilippe Mathieu-Daudé 
43932cad1ffSPhilippe Mathieu-Daudé     /*
44032cad1ffSPhilippe Mathieu-Daudé      * Note that NPT is walked (for both paging structures and final guest
44132cad1ffSPhilippe Mathieu-Daudé      * addresses) using the address with the A20 bit set.
44232cad1ffSPhilippe Mathieu-Daudé      */
44332cad1ffSPhilippe Mathieu-Daudé     if (in->ptw_idx == MMU_NESTED_IDX) {
44432cad1ffSPhilippe Mathieu-Daudé         CPUTLBEntryFull *full;
44532cad1ffSPhilippe Mathieu-Daudé         int flags, nested_page_size;
44632cad1ffSPhilippe Mathieu-Daudé 
44732cad1ffSPhilippe Mathieu-Daudé         flags = probe_access_full_mmu(env, paddr, 0, access_type,
44832cad1ffSPhilippe Mathieu-Daudé                                       MMU_NESTED_IDX, &pte_trans.haddr, &full);
44932cad1ffSPhilippe Mathieu-Daudé         if (unlikely(flags & TLB_INVALID_MASK)) {
45032cad1ffSPhilippe Mathieu-Daudé             *err = (TranslateFault){
45132cad1ffSPhilippe Mathieu-Daudé                 .error_code = env->error_code,
45232cad1ffSPhilippe Mathieu-Daudé                 .cr2 = paddr,
45332cad1ffSPhilippe Mathieu-Daudé                 .stage2 = S2_GPA,
45432cad1ffSPhilippe Mathieu-Daudé             };
45532cad1ffSPhilippe Mathieu-Daudé             return false;
45632cad1ffSPhilippe Mathieu-Daudé         }
45732cad1ffSPhilippe Mathieu-Daudé 
45832cad1ffSPhilippe Mathieu-Daudé         /* Merge stage1 & stage2 protection bits. */
45932cad1ffSPhilippe Mathieu-Daudé         prot &= full->prot;
46032cad1ffSPhilippe Mathieu-Daudé 
46132cad1ffSPhilippe Mathieu-Daudé         /* Re-verify resulting protection. */
46232cad1ffSPhilippe Mathieu-Daudé         if ((prot & (1 << access_type)) == 0) {
46332cad1ffSPhilippe Mathieu-Daudé             goto do_fault_protect;
46432cad1ffSPhilippe Mathieu-Daudé         }
46532cad1ffSPhilippe Mathieu-Daudé 
46632cad1ffSPhilippe Mathieu-Daudé         /* Merge stage1 & stage2 addresses to final physical address. */
46732cad1ffSPhilippe Mathieu-Daudé         nested_page_size = 1 << full->lg_page_size;
46832cad1ffSPhilippe Mathieu-Daudé         paddr = (full->phys_addr & ~(nested_page_size - 1))
46932cad1ffSPhilippe Mathieu-Daudé               | (paddr & (nested_page_size - 1));
47032cad1ffSPhilippe Mathieu-Daudé 
47132cad1ffSPhilippe Mathieu-Daudé         /*
47232cad1ffSPhilippe Mathieu-Daudé          * Use the larger of stage1 & stage2 page sizes, so that
47332cad1ffSPhilippe Mathieu-Daudé          * invalidation works.
47432cad1ffSPhilippe Mathieu-Daudé          */
47532cad1ffSPhilippe Mathieu-Daudé         if (nested_page_size > page_size) {
47632cad1ffSPhilippe Mathieu-Daudé             page_size = nested_page_size;
47732cad1ffSPhilippe Mathieu-Daudé         }
47832cad1ffSPhilippe Mathieu-Daudé     }
47932cad1ffSPhilippe Mathieu-Daudé 
48032cad1ffSPhilippe Mathieu-Daudé     out->paddr = paddr & x86_get_a20_mask(env);
48132cad1ffSPhilippe Mathieu-Daudé     out->prot = prot;
48232cad1ffSPhilippe Mathieu-Daudé     out->page_size = page_size;
48332cad1ffSPhilippe Mathieu-Daudé     return true;
48432cad1ffSPhilippe Mathieu-Daudé 
48532cad1ffSPhilippe Mathieu-Daudé  do_fault_rsvd:
48632cad1ffSPhilippe Mathieu-Daudé     error_code = PG_ERROR_RSVD_MASK;
48732cad1ffSPhilippe Mathieu-Daudé     goto do_fault_cont;
48832cad1ffSPhilippe Mathieu-Daudé  do_fault_protect:
48932cad1ffSPhilippe Mathieu-Daudé     error_code = PG_ERROR_P_MASK;
49032cad1ffSPhilippe Mathieu-Daudé     goto do_fault_cont;
49132cad1ffSPhilippe Mathieu-Daudé  do_fault_pk_protect:
49232cad1ffSPhilippe Mathieu-Daudé     assert(access_type != MMU_INST_FETCH);
49332cad1ffSPhilippe Mathieu-Daudé     error_code = PG_ERROR_PK_MASK | PG_ERROR_P_MASK;
49432cad1ffSPhilippe Mathieu-Daudé     goto do_fault_cont;
49532cad1ffSPhilippe Mathieu-Daudé  do_fault:
49632cad1ffSPhilippe Mathieu-Daudé     error_code = 0;
49732cad1ffSPhilippe Mathieu-Daudé  do_fault_cont:
49832cad1ffSPhilippe Mathieu-Daudé     if (is_user) {
49932cad1ffSPhilippe Mathieu-Daudé         error_code |= PG_ERROR_U_MASK;
50032cad1ffSPhilippe Mathieu-Daudé     }
50132cad1ffSPhilippe Mathieu-Daudé     switch (access_type) {
50232cad1ffSPhilippe Mathieu-Daudé     case MMU_DATA_LOAD:
50332cad1ffSPhilippe Mathieu-Daudé         break;
50432cad1ffSPhilippe Mathieu-Daudé     case MMU_DATA_STORE:
50532cad1ffSPhilippe Mathieu-Daudé         error_code |= PG_ERROR_W_MASK;
50632cad1ffSPhilippe Mathieu-Daudé         break;
50732cad1ffSPhilippe Mathieu-Daudé     case MMU_INST_FETCH:
50832cad1ffSPhilippe Mathieu-Daudé         if (pg_mode & (PG_MODE_NXE | PG_MODE_SMEP)) {
50932cad1ffSPhilippe Mathieu-Daudé             error_code |= PG_ERROR_I_D_MASK;
51032cad1ffSPhilippe Mathieu-Daudé         }
51132cad1ffSPhilippe Mathieu-Daudé         break;
51232cad1ffSPhilippe Mathieu-Daudé     }
51332cad1ffSPhilippe Mathieu-Daudé     *err = (TranslateFault){
51432cad1ffSPhilippe Mathieu-Daudé         .exception_index = EXCP0E_PAGE,
51532cad1ffSPhilippe Mathieu-Daudé         .error_code = error_code,
51632cad1ffSPhilippe Mathieu-Daudé         .cr2 = addr,
51732cad1ffSPhilippe Mathieu-Daudé     };
51832cad1ffSPhilippe Mathieu-Daudé     return false;
51932cad1ffSPhilippe Mathieu-Daudé }
52032cad1ffSPhilippe Mathieu-Daudé 
raise_stage2(CPUX86State * env,TranslateFault * err,uintptr_t retaddr)52132cad1ffSPhilippe Mathieu-Daudé static G_NORETURN void raise_stage2(CPUX86State *env, TranslateFault *err,
52232cad1ffSPhilippe Mathieu-Daudé                                     uintptr_t retaddr)
52332cad1ffSPhilippe Mathieu-Daudé {
52432cad1ffSPhilippe Mathieu-Daudé     uint64_t exit_info_1 = err->error_code;
52532cad1ffSPhilippe Mathieu-Daudé 
52632cad1ffSPhilippe Mathieu-Daudé     switch (err->stage2) {
52732cad1ffSPhilippe Mathieu-Daudé     case S2_GPT:
52832cad1ffSPhilippe Mathieu-Daudé         exit_info_1 |= SVM_NPTEXIT_GPT;
52932cad1ffSPhilippe Mathieu-Daudé         break;
53032cad1ffSPhilippe Mathieu-Daudé     case S2_GPA:
53132cad1ffSPhilippe Mathieu-Daudé         exit_info_1 |= SVM_NPTEXIT_GPA;
53232cad1ffSPhilippe Mathieu-Daudé         break;
53332cad1ffSPhilippe Mathieu-Daudé     default:
53432cad1ffSPhilippe Mathieu-Daudé         g_assert_not_reached();
53532cad1ffSPhilippe Mathieu-Daudé     }
53632cad1ffSPhilippe Mathieu-Daudé 
53732cad1ffSPhilippe Mathieu-Daudé     x86_stq_phys(env_cpu(env),
53832cad1ffSPhilippe Mathieu-Daudé                  env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
53932cad1ffSPhilippe Mathieu-Daudé                  err->cr2);
54032cad1ffSPhilippe Mathieu-Daudé     cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, retaddr);
54132cad1ffSPhilippe Mathieu-Daudé }
54232cad1ffSPhilippe Mathieu-Daudé 
get_physical_address(CPUX86State * env,vaddr addr,MMUAccessType access_type,int mmu_idx,TranslateResult * out,TranslateFault * err,uint64_t ra)54332cad1ffSPhilippe Mathieu-Daudé static bool get_physical_address(CPUX86State *env, vaddr addr,
54432cad1ffSPhilippe Mathieu-Daudé                                  MMUAccessType access_type, int mmu_idx,
54532cad1ffSPhilippe Mathieu-Daudé                                  TranslateResult *out, TranslateFault *err,
54632cad1ffSPhilippe Mathieu-Daudé                                  uint64_t ra)
54732cad1ffSPhilippe Mathieu-Daudé {
54832cad1ffSPhilippe Mathieu-Daudé     TranslateParams in;
54932cad1ffSPhilippe Mathieu-Daudé     bool use_stage2 = env->hflags2 & HF2_NPT_MASK;
55032cad1ffSPhilippe Mathieu-Daudé 
55132cad1ffSPhilippe Mathieu-Daudé     in.addr = addr;
55232cad1ffSPhilippe Mathieu-Daudé     in.access_type = access_type;
55332cad1ffSPhilippe Mathieu-Daudé 
55432cad1ffSPhilippe Mathieu-Daudé     switch (mmu_idx) {
55532cad1ffSPhilippe Mathieu-Daudé     case MMU_PHYS_IDX:
55632cad1ffSPhilippe Mathieu-Daudé         break;
55732cad1ffSPhilippe Mathieu-Daudé 
55832cad1ffSPhilippe Mathieu-Daudé     case MMU_NESTED_IDX:
55932cad1ffSPhilippe Mathieu-Daudé         if (likely(use_stage2)) {
56032cad1ffSPhilippe Mathieu-Daudé             in.cr3 = env->nested_cr3;
56132cad1ffSPhilippe Mathieu-Daudé             in.pg_mode = env->nested_pg_mode;
56232cad1ffSPhilippe Mathieu-Daudé             in.mmu_idx =
56332cad1ffSPhilippe Mathieu-Daudé                 env->nested_pg_mode & PG_MODE_LMA ? MMU_USER64_IDX : MMU_USER32_IDX;
56432cad1ffSPhilippe Mathieu-Daudé             in.ptw_idx = MMU_PHYS_IDX;
56532cad1ffSPhilippe Mathieu-Daudé 
56632cad1ffSPhilippe Mathieu-Daudé             if (!mmu_translate(env, &in, out, err, ra)) {
56732cad1ffSPhilippe Mathieu-Daudé                 err->stage2 = S2_GPA;
56832cad1ffSPhilippe Mathieu-Daudé                 return false;
56932cad1ffSPhilippe Mathieu-Daudé             }
57032cad1ffSPhilippe Mathieu-Daudé             return true;
57132cad1ffSPhilippe Mathieu-Daudé         }
57232cad1ffSPhilippe Mathieu-Daudé         break;
57332cad1ffSPhilippe Mathieu-Daudé 
57432cad1ffSPhilippe Mathieu-Daudé     default:
57532cad1ffSPhilippe Mathieu-Daudé         if (is_mmu_index_32(mmu_idx)) {
57632cad1ffSPhilippe Mathieu-Daudé             addr = (uint32_t)addr;
57732cad1ffSPhilippe Mathieu-Daudé         }
57832cad1ffSPhilippe Mathieu-Daudé 
57932cad1ffSPhilippe Mathieu-Daudé         if (likely(env->cr[0] & CR0_PG_MASK || use_stage2)) {
58032cad1ffSPhilippe Mathieu-Daudé             in.cr3 = env->cr[3];
58132cad1ffSPhilippe Mathieu-Daudé             in.mmu_idx = mmu_idx;
58232cad1ffSPhilippe Mathieu-Daudé             in.ptw_idx = use_stage2 ? MMU_NESTED_IDX : MMU_PHYS_IDX;
58332cad1ffSPhilippe Mathieu-Daudé             in.pg_mode = get_pg_mode(env);
58432cad1ffSPhilippe Mathieu-Daudé 
58532cad1ffSPhilippe Mathieu-Daudé             if (in.pg_mode & PG_MODE_LMA) {
58632cad1ffSPhilippe Mathieu-Daudé                 /* test virtual address sign extension */
58732cad1ffSPhilippe Mathieu-Daudé                 int shift = in.pg_mode & PG_MODE_LA57 ? 56 : 47;
58832cad1ffSPhilippe Mathieu-Daudé                 int64_t sext = (int64_t)addr >> shift;
58932cad1ffSPhilippe Mathieu-Daudé                 if (sext != 0 && sext != -1) {
59032cad1ffSPhilippe Mathieu-Daudé                     *err = (TranslateFault){
59132cad1ffSPhilippe Mathieu-Daudé                         .exception_index = EXCP0D_GPF,
59232cad1ffSPhilippe Mathieu-Daudé                         .cr2 = addr,
59332cad1ffSPhilippe Mathieu-Daudé                     };
59432cad1ffSPhilippe Mathieu-Daudé                     return false;
59532cad1ffSPhilippe Mathieu-Daudé                 }
59632cad1ffSPhilippe Mathieu-Daudé             }
59732cad1ffSPhilippe Mathieu-Daudé             return mmu_translate(env, &in, out, err, ra);
59832cad1ffSPhilippe Mathieu-Daudé         }
59932cad1ffSPhilippe Mathieu-Daudé         break;
60032cad1ffSPhilippe Mathieu-Daudé     }
60132cad1ffSPhilippe Mathieu-Daudé 
60232cad1ffSPhilippe Mathieu-Daudé     /* No translation needed. */
60332cad1ffSPhilippe Mathieu-Daudé     out->paddr = addr & x86_get_a20_mask(env);
60432cad1ffSPhilippe Mathieu-Daudé     out->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
60532cad1ffSPhilippe Mathieu-Daudé     out->page_size = TARGET_PAGE_SIZE;
60632cad1ffSPhilippe Mathieu-Daudé     return true;
60732cad1ffSPhilippe Mathieu-Daudé }
60832cad1ffSPhilippe Mathieu-Daudé 
x86_cpu_tlb_fill(CPUState * cs,vaddr addr,int size,MMUAccessType access_type,int mmu_idx,bool probe,uintptr_t retaddr)60932cad1ffSPhilippe Mathieu-Daudé bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
61032cad1ffSPhilippe Mathieu-Daudé                       MMUAccessType access_type, int mmu_idx,
61132cad1ffSPhilippe Mathieu-Daudé                       bool probe, uintptr_t retaddr)
61232cad1ffSPhilippe Mathieu-Daudé {
61332cad1ffSPhilippe Mathieu-Daudé     CPUX86State *env = cpu_env(cs);
61432cad1ffSPhilippe Mathieu-Daudé     TranslateResult out;
61532cad1ffSPhilippe Mathieu-Daudé     TranslateFault err;
61632cad1ffSPhilippe Mathieu-Daudé 
61732cad1ffSPhilippe Mathieu-Daudé     if (get_physical_address(env, addr, access_type, mmu_idx, &out, &err,
61832cad1ffSPhilippe Mathieu-Daudé                              retaddr)) {
61932cad1ffSPhilippe Mathieu-Daudé         /*
62032cad1ffSPhilippe Mathieu-Daudé          * Even if 4MB pages, we map only one 4KB page in the cache to
62132cad1ffSPhilippe Mathieu-Daudé          * avoid filling it too fast.
62232cad1ffSPhilippe Mathieu-Daudé          */
62332cad1ffSPhilippe Mathieu-Daudé         assert(out.prot & (1 << access_type));
62432cad1ffSPhilippe Mathieu-Daudé         tlb_set_page_with_attrs(cs, addr & TARGET_PAGE_MASK,
62532cad1ffSPhilippe Mathieu-Daudé                                 out.paddr & TARGET_PAGE_MASK,
62632cad1ffSPhilippe Mathieu-Daudé                                 cpu_get_mem_attrs(env),
62732cad1ffSPhilippe Mathieu-Daudé                                 out.prot, mmu_idx, out.page_size);
62832cad1ffSPhilippe Mathieu-Daudé         return true;
62932cad1ffSPhilippe Mathieu-Daudé     }
63032cad1ffSPhilippe Mathieu-Daudé 
63132cad1ffSPhilippe Mathieu-Daudé     if (probe) {
63232cad1ffSPhilippe Mathieu-Daudé         /* This will be used if recursing for stage2 translation. */
63332cad1ffSPhilippe Mathieu-Daudé         env->error_code = err.error_code;
63432cad1ffSPhilippe Mathieu-Daudé         return false;
63532cad1ffSPhilippe Mathieu-Daudé     }
63632cad1ffSPhilippe Mathieu-Daudé 
63732cad1ffSPhilippe Mathieu-Daudé     if (err.stage2 != S2_NONE) {
63832cad1ffSPhilippe Mathieu-Daudé         raise_stage2(env, &err, retaddr);
63932cad1ffSPhilippe Mathieu-Daudé     }
64032cad1ffSPhilippe Mathieu-Daudé 
64132cad1ffSPhilippe Mathieu-Daudé     if (env->intercept_exceptions & (1 << err.exception_index)) {
64232cad1ffSPhilippe Mathieu-Daudé         /* cr2 is not modified in case of exceptions */
64332cad1ffSPhilippe Mathieu-Daudé         x86_stq_phys(cs, env->vm_vmcb +
64432cad1ffSPhilippe Mathieu-Daudé                      offsetof(struct vmcb, control.exit_info_2),
64532cad1ffSPhilippe Mathieu-Daudé                      err.cr2);
64632cad1ffSPhilippe Mathieu-Daudé     } else {
64732cad1ffSPhilippe Mathieu-Daudé         env->cr[2] = err.cr2;
64832cad1ffSPhilippe Mathieu-Daudé     }
64932cad1ffSPhilippe Mathieu-Daudé     raise_exception_err_ra(env, err.exception_index, err.error_code, retaddr);
65032cad1ffSPhilippe Mathieu-Daudé }
65132cad1ffSPhilippe Mathieu-Daudé 
x86_cpu_do_unaligned_access(CPUState * cs,vaddr vaddr,MMUAccessType access_type,int mmu_idx,uintptr_t retaddr)65232cad1ffSPhilippe Mathieu-Daudé G_NORETURN void x86_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
65332cad1ffSPhilippe Mathieu-Daudé                                             MMUAccessType access_type,
65432cad1ffSPhilippe Mathieu-Daudé                                             int mmu_idx, uintptr_t retaddr)
65532cad1ffSPhilippe Mathieu-Daudé {
65632cad1ffSPhilippe Mathieu-Daudé     X86CPU *cpu = X86_CPU(cs);
65732cad1ffSPhilippe Mathieu-Daudé     handle_unaligned_access(&cpu->env, vaddr, access_type, retaddr);
65832cad1ffSPhilippe Mathieu-Daudé }
659