From nobody Thu Nov 6 06:34:38 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1539257468757397.0858709233065; Thu, 11 Oct 2018 04:31:08 -0700 (PDT) Received: from localhost ([::1]:33601 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gAZBL-0002f7-Cu for importer@patchew.org; Thu, 11 Oct 2018 07:31:07 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52556) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gAZ4z-0005r1-4p for qemu-devel@nongnu.org; Thu, 11 Oct 2018 07:24:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gAZ4w-0007Yy-0x for qemu-devel@nongnu.org; Thu, 11 Oct 2018 07:24:31 -0400 Received: from mx2.rt-rk.com ([89.216.37.149]:54664 helo=mail.rt-rk.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gAZ4t-0007UX-T0 for qemu-devel@nongnu.org; Thu, 11 Oct 2018 07:24:29 -0400 Received: from localhost (localhost [127.0.0.1]) by mail.rt-rk.com (Postfix) with ESMTP id 964231A1E95; Thu, 11 Oct 2018 13:24:23 +0200 (CEST) Received: from rtrkw774-lin.domain.local (rtrkw774-lin.domain.local [10.10.13.43]) by mail.rt-rk.com (Postfix) with ESMTPSA id 7536B1A1DF0; Thu, 11 Oct 2018 13:24:23 +0200 (CEST) X-Virus-Scanned: amavisd-new at rt-rk.com From: Aleksandar Markovic To: qemu-devel@nongnu.org Date: Thu, 11 Oct 2018 13:22:13 +0200 Message-Id: <1539256947-22807-9-git-send-email-aleksandar.markovic@rt-rk.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1539256947-22807-1-git-send-email-aleksandar.markovic@rt-rk.com> References: <1539256947-22807-1-git-send-email-aleksandar.markovic@rt-rk.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 89.216.37.149 Subject: [Qemu-devel] [PATCH v4 08/22] target/mips: Implement hardware page table walker X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: smarkovic@wavecomp.com, riku.voipio@iki.fi, richard.henderson@linaro.org, laurent@vivier.eu, amarkovic@wavecomp.com, pjovanovic@wavecomp.com, aurelien@aurel32.net Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Yongbok Kim Implement hardware page table walker. Signed-off-by: Yongbok Kim Signed-off-by: Aleksandar Markovic Reviewed-by: Aleksandar Markovic --- target/mips/helper.c | 369 ++++++++++++++++++++++++++++++++++++++++++++= +++- target/mips/internal.h | 1 + target/mips/op_helper.c | 7 +- 3 files changed, 374 insertions(+), 3 deletions(-) diff --git a/target/mips/helper.c b/target/mips/helper.c index f0c268b..2b166cc 100644 --- a/target/mips/helper.c +++ b/target/mips/helper.c @@ -537,6 +537,346 @@ hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vad= dr addr) } #endif =20 +#if !defined(CONFIG_USER_ONLY) +#if !defined(TARGET_MIPS64) + +/* Perform hardware page table walk +* +* Memory accesses are performed using the KERNEL privilege level. +* Synchronous exceptions detected on memory accesses cause a silent exit +* from page table walking, resulting in a TLB or XTLB Refill exception. +* +* Implementations are not required to support page table walk memory +* accesses from mapped memory regions. When an unsupported access is +* attempted, a silent exit is taken, resulting in a TLB or XTLB Refill +* exception. +* +* Note that if an exception is caused by AddressTranslation or LoadMemory +* functions, the exception is not taken, a silent exit is taken, +* resulting in a TLB or XTLB Refill exception. +*/ + +static bool get_pte(CPUMIPSState *env, uint64_t vaddr, int entry_size, + uint64_t *pte) +{ + if ((vaddr & ((entry_size >> 3) - 1)) !=3D 0) { + return false; + } + if (entry_size =3D=3D 64) { + *pte =3D cpu_ldq_code(env, vaddr); + } else { + *pte =3D cpu_ldl_code(env, vaddr); + } + return true; +} + +static uint64_t get_tlb_entry_layout(CPUMIPSState *env, uint64_t entry, + int entry_size, int ptei) +{ + uint64_t result =3D entry; + uint64_t rixi; + if (ptei > entry_size) { + ptei -=3D 32; + } + result >>=3D (ptei - 2); + rixi =3D result & 3; + result >>=3D 2; + result |=3D rixi << CP0EnLo_XI; + return result; +} + +static int walk_directory(CPUMIPSState *env, uint64_t *vaddr, + int directory_index, bool *huge_page, bool *hgpg_directory_hit, + uint64_t *pw_entrylo0, uint64_t *pw_entrylo1) +{ + int dph =3D (env->CP0_PWCtl >> CP0PC_DPH) & 0x1; + int psn =3D (env->CP0_PWCtl >> CP0PC_PSN) & 0x3F; + int hugepg =3D (env->CP0_PWCtl >> CP0PC_HUGEPG) & 0x1; + int ptei =3D (env->CP0_PWField >> CP0PF_PTEI) & 0x3F; + int ptew =3D (env->CP0_PWSize >> CP0PS_PTEW) & 0x3F; + int native_shift =3D (((env->CP0_PWSize >> CP0PS_PS) & 1) =3D=3D 0) ? = 2 : 3; + int directory_shift =3D (ptew > 1) ? -1 : + (hugepg && (ptew =3D=3D 1)) ? native_shift + 1 : native_shift; + int leaf_shift =3D (ptew > 1) ? -1 : + (ptew =3D=3D 1) ? native_shift + 1 : native_shift; + uint32_t direntry_size =3D 1 << (directory_shift + 3); + uint32_t leafentry_size =3D 1 << (leaf_shift + 3); + + uint64_t entry; + uint64_t paddr; + int prot; + uint64_t lsb =3D 0; + uint64_t w =3D 0; + + if (get_physical_address(env, &paddr, &prot, *vaddr, MMU_DATA_LOAD, + ACCESS_INT, cpu_mmu_index(env, false)) + !=3D TLBRET_MATCH) { + /* wrong base address */ + return 0; + } + if (!get_pte(env, *vaddr, direntry_size, &entry)) { + return 0; + } + + if ((entry & (1 << psn)) && hugepg) { + *huge_page =3D true; + *hgpg_directory_hit =3D true; + entry =3D get_tlb_entry_layout(env, entry, leafentry_size, + ptei); + w =3D directory_index - 1; + if (directory_index & 0x1) { + /* generate adjacent page from same PTE for odd TLB page */ + lsb =3D (1 << w) >> 6; + *pw_entrylo0 =3D entry & ~lsb; /* even page */ + *pw_entrylo1 =3D entry | lsb; /* odd page */ + } else if (dph) { + int oddpagebit =3D 1 << leaf_shift; + uint64_t vaddr2 =3D *vaddr ^ oddpagebit; + if (*vaddr & oddpagebit) { + *pw_entrylo1 =3D entry; + } else { + *pw_entrylo0 =3D entry; + } + if (get_physical_address(env, &paddr, &prot, vaddr2, + MMU_DATA_LOAD, ACCESS_INT, + cpu_mmu_index(env, false)) + !=3D TLBRET_MATCH) { + return 0; + } + if (!get_pte(env, vaddr2, leafentry_size, &entry)) { + return 0; + } + entry =3D get_tlb_entry_layout(env, entry, + leafentry_size, ptei); + if (*vaddr & oddpagebit) { + *pw_entrylo0 =3D entry; + } else { + *pw_entrylo1 =3D entry; + } + } else { + return 0; + } + return 1; + } else { + *vaddr =3D entry; + return 2; + } +} + +static bool page_table_walk_refill(CPUMIPSState *env, vaddr address, int r= w, + int mmu_idx) +{ + int gdw =3D (env->CP0_PWSize >> CP0PS_GDW) & 0x3f; + int udw =3D (env->CP0_PWSize >> CP0PS_UDW) & 0x3f; + int mdw =3D (env->CP0_PWSize >> CP0PS_MDW) & 0x3f; + int ptw =3D (env->CP0_PWSize >> CP0PS_PTW) & 0x3F; + + /* Initial values */ + bool huge_page =3D false; + bool hgpg_bdhit =3D false; + bool hgpg_gdhit =3D false; + bool hgpg_udhit =3D false; + bool hgpg_mdhit =3D false; + + int32_t pw_pagemask =3D 0; + target_ulong pw_entryhi =3D 0; + uint64_t pw_entrylo0 =3D 0; + uint64_t pw_entrylo1 =3D 0; + + /* Native pointer size */ + /*For the 32-bit architectures, this bit is fixed to 0.*/ + int native_shift =3D (((env->CP0_PWSize >> CP0PS_PS) & 1) =3D=3D 0) ? = 2 : 3; + + /* Indices from PWField */ + int gdi =3D (env->CP0_PWField >> CP0PF_GDI) & 0x3F; + int udi =3D (env->CP0_PWField >> CP0PF_UDI) & 0x3F; + int mdi =3D (env->CP0_PWField >> CP0PF_MDI) & 0x3F; + int pti =3D (env->CP0_PWField >> CP0PF_PTI) & 0x3F; + int ptei =3D (env->CP0_PWField >> CP0PF_PTEI) & 0x3F; + int ptew =3D (env->CP0_PWSize >> CP0PS_PTEW) & 0x3F; + + /* Indices computed from faulting address */ + int gindex =3D (address >> gdi) & ((1 << gdw) - 1); + int uindex =3D (address >> udi) & ((1 << udw) - 1); + int mindex =3D (address >> mdi) & ((1 << mdw) - 1); + int ptindex =3D (address >> pti) & ((1 << ptw) - 1); + + /* Other HTW configs */ + int hugepg =3D (env->CP0_PWCtl >> CP0PC_HUGEPG) & 0x1; + + /* HTW Shift values (depend on entry size) */ + int directory_shift =3D (ptew > 1) ? -1 : + (hugepg && (ptew =3D=3D 1)) ? native_shift + 1 : native_shift; + int leaf_shift =3D (ptew > 1) ? -1 : + (ptew =3D=3D 1) ? native_shift + 1 : native_shift; + + /* Offsets into tables */ + int goffset =3D gindex << directory_shift; + int uoffset =3D uindex << directory_shift; + int moffset =3D mindex << directory_shift; + int ptoffset0 =3D (ptindex >> 1) << (leaf_shift + 1); + int ptoffset1 =3D ptoffset0 | (1 << (leaf_shift)); + + uint32_t leafentry_size =3D 1 << (leaf_shift + 3); + + /* Starting address - Page Table Base */ + uint64_t vaddr =3D env->CP0_PWBase; + + uint64_t dir_entry; + uint64_t paddr; + int prot; + int m; + + if (!(env->CP0_Config3 & (1 << CP0C3_PW))) { + /* walker is unimplemented */ + return false; + } + if (!(env->CP0_PWCtl & (1 << CP0PC_PWEN))) { + /* walker is disabled */ + return false; + } + if (!(gdw > 0 || udw > 0 || mdw > 0)) { + /* no structure to walk */ + return false; + } + if ((directory_shift =3D=3D -1) || (leaf_shift =3D=3D -1)) { + return false; + } + + /* Global Directory */ + if (gdw > 0) { + vaddr |=3D goffset; + switch (walk_directory(env, &vaddr, + gdi, &huge_page, &hgpg_gdhit, + &pw_entrylo0, &pw_entrylo1)) { + case 0: + return false; + case 1: + goto refill; + case 2: + default: + break; + } + } + + /* Upper directory */ + if (udw > 0) { + vaddr |=3D uoffset; + switch (walk_directory(env, &vaddr, + udi, &huge_page, &hgpg_udhit, + &pw_entrylo0, &pw_entrylo1)) { + case 0: + return false; + case 1: + goto refill; + case 2: + default: + break; + } + } + + /* Middle directory */ + if (mdw > 0) { + vaddr |=3D moffset; + switch (walk_directory(env, &vaddr, + mdi, &huge_page, &hgpg_mdhit, + &pw_entrylo0, &pw_entrylo1)) { + case 0: + return false; + case 1: + goto refill; + case 2: + default: + break; + } + } + + /* Leaf Level Page Table - First half of PTE pair */ + vaddr |=3D ptoffset0; + if (get_physical_address(env, &paddr, &prot, vaddr, + MMU_DATA_LOAD, ACCESS_INT, + cpu_mmu_index(env, false)) + !=3D TLBRET_MATCH) { + return false; + } + if (!get_pte(env, vaddr, leafentry_size, &dir_entry)) { + return false; + } + dir_entry =3D get_tlb_entry_layout(env, dir_entry, leafentry_size, pte= i); + pw_entrylo0 =3D dir_entry; + + /* Leaf Level Page Table - Second half of PTE pair */ + vaddr |=3D ptoffset1; + if (get_physical_address(env, &paddr, &prot, vaddr, + MMU_DATA_LOAD, ACCESS_INT, + cpu_mmu_index(env, false)) !=3D TLBRET_MATCH)= { + return false; + } + if (!get_pte(env, vaddr, leafentry_size, &dir_entry)) { + return false; + } + dir_entry =3D get_tlb_entry_layout(env, dir_entry, leafentry_size, pte= i); + pw_entrylo1 =3D dir_entry; + +refill: + m =3D (1 << pti) - 1; + + if (huge_page) { + switch (hgpg_bdhit << 3 | hgpg_gdhit << 2 | hgpg_udhit << 1 | + hgpg_mdhit) { + case 4: + m =3D (1 << gdi) - 1; + if (gdi & 1) { + m >>=3D 1; + } + break; + case 2: + m =3D (1 << udi) - 1; + if (udi & 1) { + m >>=3D 1; + } + break; + case 1: + m =3D (1 << mdi) - 1; + if (mdi & 1) { + m >>=3D 1; + } + break; + } + } + + pw_pagemask =3D m >> 12; + update_pagemask(env, pw_pagemask << 13, &pw_pagemask); + pw_entryhi =3D (address & ~0x1fff) | (env->CP0_EntryHi & 0xFF); + + { + target_ulong tmp_entryhi =3D env->CP0_EntryHi; + int32_t tmp_pagemask =3D env->CP0_PageMask; + uint64_t tmp_entrylo0 =3D env->CP0_EntryLo0; + uint64_t tmp_entrylo1 =3D env->CP0_EntryLo1; + + env->CP0_EntryHi =3D pw_entryhi; + env->CP0_PageMask =3D pw_pagemask; + env->CP0_EntryLo0 =3D pw_entrylo0; + env->CP0_EntryLo1 =3D pw_entrylo1; + + /* + * The hardware page walker inserts a page into the TLB in a manner + * identical to a TLBWR instruction as executed by the software re= fill + * handler. + */ + r4k_helper_tlbwr(env); + + env->CP0_EntryHi =3D tmp_entryhi; + env->CP0_PageMask =3D tmp_pagemask; + env->CP0_EntryLo0 =3D tmp_entrylo0; + env->CP0_EntryLo1 =3D tmp_entrylo1; + } + return true; +} +#endif +#endif + int mips_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int r= w, int mmu_idx) { @@ -558,8 +898,7 @@ int mips_cpu_handle_mmu_fault(CPUState *cs, vaddr addre= ss, int size, int rw, =20 /* data access */ #if !defined(CONFIG_USER_ONLY) - /* XXX: put correct access by using cpu_restore_state() - correctly */ + /* XXX: put correct access by using cpu_restore_state() correctly */ access_type =3D ACCESS_INT; ret =3D get_physical_address(env, &physical, &prot, address, rw, access_type, mmu_idx); @@ -583,6 +922,32 @@ int mips_cpu_handle_mmu_fault(CPUState *cs, vaddr addr= ess, int size, int rw, } else if (ret < 0) #endif { +#if !defined(CONFIG_USER_ONLY) +#if !defined(TARGET_MIPS64) + if ((ret =3D=3D TLBRET_NOMATCH) && (env->tlb->nb_tlb > 1)) { + /* + * Memory reads during hardware page table walking are perform= ed + * as if they were kernel-mode load instructions. + */ + int mode =3D (env->hflags & MIPS_HFLAG_KSU); + bool ret_walker; + env->hflags &=3D ~MIPS_HFLAG_KSU; + ret_walker =3D page_table_walk_refill(env, address, rw, mmu_id= x); + env->hflags |=3D mode; + if (ret_walker) { + ret =3D get_physical_address(env, &physical, &prot, + address, rw, access_type, mmu_i= dx); + if (ret =3D=3D TLBRET_MATCH) { + tlb_set_page(cs, address & TARGET_PAGE_MASK, + physical & TARGET_PAGE_MASK, prot | PAGE_EXEC, + mmu_idx, TARGET_PAGE_SIZE); + ret =3D 0; + return ret; + } + } + } +#endif +#endif raise_mmu_exception(env, address, rw, ret); ret =3D 1; } diff --git a/target/mips/internal.h b/target/mips/internal.h index e41051f..2898bfc 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -211,6 +211,7 @@ uint64_t float_class_d(uint64_t arg, float_status *fst); =20 extern unsigned int ieee_rm[]; int ieee_ex_to_mips(int xcpt); +void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagema= sk); =20 static inline void restore_rounding_mode(CPUMIPSState *env) { diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index e649bd0..af130f6 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -1400,7 +1400,7 @@ void helper_mtc0_context(CPUMIPSState *env, target_ul= ong arg1) env->CP0_Context =3D (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007F= FFFF); } =20 -void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) +void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagema= sk) { uint64_t mask =3D arg1 >> (TARGET_PAGE_BITS + 1); if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 =3D=3D ~0) || @@ -1411,6 +1411,11 @@ void helper_mtc0_pagemask(CPUMIPSState *env, target_= ulong arg1) } } =20 +void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) +{ + update_pagemask(env, arg1, &env->CP0_PageMask); +} + void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) { /* SmartMIPS not implemented */ --=20 2.7.4