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