From nobody Fri Dec 19 20:37:43 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail header.i=@wdc.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=wdc.com ARC-Seal: i=1; a=rsa-sha256; t=1572047161; cv=none; d=zoho.com; s=zohoarc; b=RdYBVwmY8deE4Mxvp40HxlRHTdjDQSlmENEFV9C24fHyruboN1z+1qQByKLJBNiK34xLObs5ZCHMbFjh195ushJ1unVJUVU2j0SyHsVzLGDK+zBdNgySRXAQeuYBZzWIPEoSA6Xm+iXogwFMAWcsqGzaqvWPSvCF0BrSMKs8TcQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1572047161; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=DUxdnDaXjOxV5tHN/htSCOqUDyUcri6ltmwJl0MLgSo=; b=HKed8/SOOcuDvw08WCIjKtEQn0jNkefrWq2ee6Gd/CHSNs3P6F0cpd4jlAMjo06X0/LnkV3JXJ5S5rWmbDCwjpzV2Pxd8tybxdtp1L+L6WpBXhe93RvMnV2tuSCPduFnKZyXgNa585vqJ6ZgzyEDE1uGUPK7XA4mEnWGKO4dUOY= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail header.i=@wdc.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1572047161902132.78278549288086; Fri, 25 Oct 2019 16:46:01 -0700 (PDT) Received: from localhost ([::1]:37106 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iO9HI-0002eR-W7 for importer@patchew.org; Fri, 25 Oct 2019 19:45:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:50083) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iO91N-0005YY-Er for qemu-devel@nongnu.org; Fri, 25 Oct 2019 19:29:31 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iO91L-0004gi-It for qemu-devel@nongnu.org; Fri, 25 Oct 2019 19:29:29 -0400 Received: from esa6.hgst.iphmx.com ([216.71.154.45]:36814) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iO91L-0004Yx-5X; Fri, 25 Oct 2019 19:29:27 -0400 Received: from uls-op-cesaip01.wdc.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 26 Oct 2019 07:29:27 +0800 Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 Oct 2019 16:24:52 -0700 Received: from risc6-mainframe.sdcorp.global.sandisk.com (HELO risc6-mainframe.int.fusionio.com) ([10.196.157.58]) by uls-op-cesaip01.wdc.com with ESMTP; 25 Oct 2019 16:29:27 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1572046167; x=1603582167; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9KX4fmzs48B9AnTsmnSKVgxCb5UksLo0R1oD8BBOlRk=; b=Yul4k41LTLY5Xugzw8Qfmp4smWF2Km9edOE3P2vm0LloCWeasY8SkKxT eeLstD1E5AoXWzwUCQxPQB2mh5wof3LrV6JArG/n86avdCqkkoanM+s5Z Av2vy2yknRLMKywMHyGS8Xxu6GdAL4mW62EZGex11I1Ny/V4OMlBu6SEO iIv6FiNoWB7VuD8fT1SfrSQkB5Fwv8jXNzZYx4CeElPBUO4J6MbqjC/Fb +U+V00rfcJ1f/oJtrs+3nV44QJO3jbrZtV71eif73YKEaR18QEJk7W6M/ vAxXj76miAyXgA2lkRd/tFVrpvdBYKaS/6jw+w/Zy/djskAAsRZAv4nR8 A==; IronPort-SDR: w+qKtb/UCC3vtfRetBHUJb3jweTUcGoC089Q7KNASCP96TqYmAkFgpd6+UVbSNC7Zvs7u+BVCS f+biLqbscYkFuIZvfeopdqT8dip6UmOpn/HoH4pWo2mQUoclOMdnuLlivKHt6VoJnqgoBwO6nQ vJE6SCHXLI6St8V9LgTzzwjEwguhQJt0+yOArpg9QzKGg42qB/ONwVR82twTO10x4CbEzaXJe7 1uZO3APIsgRTAxpXgvmVtDD9nQciLQWxV9RnHja1RDhWb1kC4AlbXXnrJ9yV/GZumqwZ2AE3mi 1UE= X-IronPort-AV: E=Sophos;i="5.68,230,1569254400"; d="scan'208";a="122956701" IronPort-SDR: t2pCTgNCBFefpbw9eqAauyLsSktOAxUk429XIMI6dqveF7G3BQS2Znfpovd/yfoFktxA4aclYy 7ia3d4RJQg+WGSg2jV+HgwLQ7m20mkbKFIXufYshxn9mMhCrnbmLjwTicUpJ7lHDiDd+QFKrK7 3mH1Pks9dHQT3W0Iw7cT5Tfy0M3y5aA4DZAyQPSUeg6XxPsD0eBZJvzddCNV/0Cmcx+jN9B04T 69YXFQ7YMcAFq1tBrNd/+DBie1b2F6ymn2lcVhsSSSWWxIo5vBRMtNzgDSRRH6opEWBktq4ZgO EXvb1N7q+Ekw/LeQhqeCc27m IronPort-SDR: GwzkvduGhMLVOQRVkoOSJJ9U1FAGYelBfiEAX+dqtL4KfCmTtI1i7tEDTe+lHNIe6BdJNBkTfA hmPgRpio7HyScIzjJ9FhZ/0byfnMmptwKgmC4SO5fbJbWvZsWLGKRks7sMgejOi6s07QPPC54R 3bVD0U/plCIiT8mfFtqrRfAggDTFbI/LPtj8vVGjXnUJu7g9R7GJMYfU+08BUKACaVnbAbcJLY yst42tuH3meWtKYS0osGMFeihMlI8GN5ruK/pkgfffl3lrbs3M+1/SpqAZVQ8JeM6v2p1Lx3Ab NrI= WDCIronportException: Internal From: Alistair Francis To: qemu-devel@nongnu.org, qemu-riscv@nongnu.org Subject: [PATCH v2 24/27] target/riscv: Implement second stage MMU Date: Fri, 25 Oct 2019 16:24:31 -0700 Message-Id: <6e999bd94410ca9f6aba6dee33d5335c87444606.1572045716.git.alistair.francis@wdc.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 216.71.154.45 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alistair23@gmail.com, palmer@sifive.com, alistair.francis@wdc.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Type: text/plain; charset="utf-8" Signed-off-by: Alistair Francis --- target/riscv/cpu_helper.c | 193 ++++++++++++++++++++++++++++++++++---- 1 file changed, 174 insertions(+), 19 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 275b6c2a67..b3ce345f81 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -304,11 +304,12 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ul= ong newpriv) * @mmu_idx: Indicates current privilege level * @first_stage: Are we in first stage translation? * Second stage is used for hypervisor guest translation + * @two_stage: Are we going to perform two stage translation */ static int get_physical_address(CPURISCVState *env, hwaddr *physical, int *prot, target_ulong addr, int access_type, int mmu_idx, - bool first_stage) + bool first_stage, bool two_stage) { /* NOTE: the env->pc value visible here will not be * correct, but the value visible to the exception handler @@ -316,13 +317,40 @@ static int get_physical_address(CPURISCVState *env, h= waddr *physical, MemTxResult res; MemTxAttrs attrs =3D MEMTXATTRS_UNSPECIFIED; int mode =3D mmu_idx; + bool use_background =3D false; =20 + /* + * Check if we should use the background registers for the two + * stage translation. We don't need to check if we actually need + * two stage translation as that happened before this function + * was called. Background registers will be used if the guest has + * forced a two stage translation to be on (in HS or M mode). + */ if (mode =3D=3D PRV_M && access_type !=3D MMU_INST_FETCH) { if (get_field(*env->mstatus, MSTATUS_MPRV)) { mode =3D get_field(*env->mstatus, MSTATUS_MPP); + + if (riscv_has_ext(env, RVH) && + get_field(*env->mstatus, MSTATUS_MPV)) { + use_background =3D true; + } + } + } + + if (mode =3D=3D PRV_S && access_type !=3D MMU_INST_FETCH && + riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) { + if (get_field(env->hstatus, HSTATUS_SPRV)) { + mode =3D get_field(*env->mstatus, SSTATUS_SPP); + use_background =3D true; } } =20 + if (first_stage =3D=3D false) { + /* We are in stage 2 translation, this is similar to stage 1. */ + /* Stage 2 is always taken as U-mode */ + mode =3D PRV_U; + } + if (mode =3D=3D PRV_M || !riscv_feature(env, RISCV_FEATURE_MMU)) { *physical =3D addr; *prot =3D PAGE_READ | PAGE_WRITE | PAGE_EXEC; @@ -332,13 +360,30 @@ static int get_physical_address(CPURISCVState *env, h= waddr *physical, *prot =3D 0; =20 hwaddr base; - int levels, ptidxbits, ptesize, vm, sum; - int mxr =3D get_field(*env->mstatus, MSTATUS_MXR); + int levels, ptidxbits, ptesize, vm, sum, mxr, widened; + + if (first_stage =3D=3D true) { + mxr =3D get_field(*env->mstatus, MSTATUS_MXR); + } else { + mxr =3D get_field(env->vsstatus, MSTATUS_MXR); + } =20 if (env->priv_ver >=3D PRIV_VERSION_1_10_0) { - base =3D (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT; + if (first_stage =3D=3D true) { + if (use_background) { + base =3D (hwaddr)get_field(env->vsatp, SATP_PPN) << PGSHIF= T; + vm =3D get_field(env->vsatp, SATP_MODE); + } else { + base =3D (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT; + vm =3D get_field(env->satp, SATP_MODE); + } + widened =3D 0; + } else { + base =3D (hwaddr)get_field(env->hgatp, HGATP_PPN) << PGSHIFT; + vm =3D get_field(env->hgatp, HGATP_MODE); + widened =3D 2; + } sum =3D get_field(*env->mstatus, MSTATUS_SUM); - vm =3D get_field(env->satp, SATP_MODE); switch (vm) { case VM_1_10_SV32: levels =3D 2; ptidxbits =3D 10; ptesize =3D 4; break; @@ -356,6 +401,7 @@ static int get_physical_address(CPURISCVState *env, hwa= ddr *physical, g_assert_not_reached(); } } else { + widened =3D 0; base =3D (hwaddr)(env->sptbr) << PGSHIFT; sum =3D !get_field(*env->mstatus, MSTATUS_PUM); vm =3D get_field(*env->mstatus, MSTATUS_VM); @@ -376,9 +422,16 @@ static int get_physical_address(CPURISCVState *env, hw= addr *physical, } =20 CPUState *cs =3D env_cpu(env); - int va_bits =3D PGSHIFT + levels * ptidxbits; - target_ulong mask =3D (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1; - target_ulong masked_msbs =3D (addr >> (va_bits - 1)) & mask; + int va_bits =3D PGSHIFT + levels * ptidxbits + widened; + target_ulong mask, masked_msbs; + + if (TARGET_LONG_BITS > (va_bits - 1)) { + mask =3D (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1; + } else { + mask =3D 0; + } + masked_msbs =3D (addr >> (va_bits - 1)) & mask; + if (masked_msbs !=3D 0 && masked_msbs !=3D mask) { return TRANSLATE_FAIL; } @@ -390,11 +443,29 @@ static int get_physical_address(CPURISCVState *env, h= waddr *physical, restart: #endif for (i =3D 0; i < levels; i++, ptshift -=3D ptidxbits) { - target_ulong idx =3D (addr >> (PGSHIFT + ptshift)) & + target_ulong idx; + if (i =3D=3D 0) { + idx =3D (addr >> (PGSHIFT + ptshift)) & + ((1 << (ptidxbits + widened)) - 1); + } else { + idx =3D (addr >> (PGSHIFT + ptshift)) & ((1 << ptidxbits) - 1); + } =20 /* check that physical address of PTE is legal */ - hwaddr pte_addr =3D base + idx * ptesize; + hwaddr pte_addr; + + if (two_stage && first_stage) { + hwaddr vbase; + + /* Do the second stage translation on the base PTE address. */ + get_physical_address(env, &vbase, prot, base, access_type, + mmu_idx, false, true); + + pte_addr =3D vbase + idx * ptesize; + } else { + pte_addr =3D base + idx * ptesize; + } =20 if (riscv_feature(env, RISCV_FEATURE_PMP) && !pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong), @@ -491,7 +562,12 @@ restart: /* for superpage mappings, make a fake leaf PTE for the TLB's benefit. */ target_ulong vpn =3D addr >> PGSHIFT; - *physical =3D (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT; + if (i =3D=3D 0) { + *physical =3D (ppn | (vpn & ((1L << (ptshift + widened)) -= 1))) << + PGSHIFT; + } else { + *physical =3D (ppn | (vpn & ((1L << ptshift) - 1))) << PGS= HIFT; + } =20 /* set permissions on the TLB entry */ if ((pte & PTE_R) || ((pte & PTE_X) && mxr)) { @@ -550,14 +626,23 @@ static void raise_mmu_exception(CPURISCVState *env, t= arget_ulong address, hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) { RISCVCPU *cpu =3D RISCV_CPU(cs); + CPURISCVState *env =3D &cpu->env; hwaddr phys_addr; int prot; int mmu_idx =3D cpu_mmu_index(&cpu->env, false); =20 - if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_id= x, - true)) { + if (get_physical_address(env, &phys_addr, &prot, addr, 0, mmu_idx, + true, riscv_cpu_virt_enabled(env))) { return -1; } + + if (riscv_cpu_virt_enabled(env)) { + if (get_physical_address(env, &phys_addr, &prot, phys_addr, + 0, mmu_idx, false, true)) { + return -1; + } + } + return phys_addr; } =20 @@ -611,18 +696,36 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, = int size, RISCVCPU *cpu =3D RISCV_CPU(cs); CPURISCVState *env =3D &cpu->env; #ifndef CONFIG_USER_ONLY + vaddr im_address; hwaddr pa =3D 0; int prot; int pmp_size =3D 0; bool pmp_violation =3D false; + bool m_mode_two_stage =3D false; + bool hs_mode_two_stage =3D false; + bool first_stage_error =3D true; int ret =3D TRANSLATE_FAIL; int mode =3D mmu_idx; =20 qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n", __func__, address, access_type, mmu_idx); =20 - ret =3D get_physical_address(env, &pa, &prot, address, access_type, mm= u_idx, - true); + /* + * Determine if we are in M mode and MPRV is set or in HS mode and SPR= V is + * set and we want to access a virtulisation address. + */ + if (riscv_has_ext(env, RVH)) { + m_mode_two_stage =3D env->priv =3D=3D PRV_M && + access_type !=3D MMU_INST_FETCH && + get_field(*env->mstatus, MSTATUS_MPRV) && + get_field(*env->mstatus, MSTATUS_MPV); + + hs_mode_two_stage =3D env->priv =3D=3D PRV_S && + !riscv_cpu_virt_enabled(env) && + access_type !=3D MMU_INST_FETCH && + get_field(env->hstatus, HSTATUS_SPRV) && + get_field(env->hstatus, HSTATUS_SPV); + } =20 if (mode =3D=3D PRV_M && access_type !=3D MMU_INST_FETCH) { if (get_field(*env->mstatus, MSTATUS_MPRV)) { @@ -630,9 +733,56 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, i= nt size, } } =20 - qemu_log_mask(CPU_LOG_MMU, - "%s address=3D%" VADDR_PRIx " ret %d physical " TARGET_F= MT_plx - " prot %d\n", __func__, address, ret, pa, prot); + if (riscv_cpu_virt_enabled(env) || m_mode_two_stage || hs_mode_two_sta= ge) { + /* Two stage lookup */ + ret =3D get_physical_address(env, &pa, &prot, address, access_type, + mmu_idx, true, true); + + qemu_log_mask(CPU_LOG_MMU, + "%s 1st-stage address=3D%" VADDR_PRIx " ret %d physi= cal " + TARGET_FMT_plx " prot %d\n", + __func__, address, ret, pa, prot); + + if (ret =3D=3D TRANSLATE_FAIL) { + goto tlb_lookup_done; + } + + /* Second stage lookup */ + im_address =3D pa; + + ret =3D get_physical_address(env, &pa, &prot, im_address, access_t= ype, mmu_idx, + false, true); + + qemu_log_mask(CPU_LOG_MMU, + "%s 2nd-stage address=3D%" VADDR_PRIx " ret %d physical " + TARGET_FMT_plx " prot %d\n", + __func__, im_address, ret, pa, prot); + + if (riscv_feature(env, RISCV_FEATURE_PMP) && + (ret =3D=3D TRANSLATE_SUCCESS) && + !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) { + ret =3D TRANSLATE_PMP_FAIL; + } + + if (ret !=3D TRANSLATE_SUCCESS) { + /* + * Guest physical address translation failed, this is a HS + * level exception + */ + first_stage_error =3D false; + address =3D im_address | (address & (TARGET_PAGE_SIZE - 1)); + goto tlb_lookup_done; + } + } else { + /* Single stage lookup */ + ret =3D get_physical_address(env, &pa, &prot, address, access_type, + mmu_idx, true, false); + + qemu_log_mask(CPU_LOG_MMU, + "%s address=3D%" VADDR_PRIx " ret %d physical " + TARGET_FMT_plx " prot %d\n", + __func__, address, ret, pa, prot); + } =20 /* * if size is unknown (0), assume that all bytes @@ -644,6 +794,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, in= t size, pmp_size =3D size; } =20 +tlb_lookup_done: if (riscv_feature(env, RISCV_FEATURE_PMP) && (ret =3D=3D TRANSLATE_SUCCESS) && !pmp_hart_has_privs(env, pa, pmp_size, 1 << access_type, mode)) { @@ -652,6 +803,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, in= t size, if (ret =3D=3D TRANSLATE_PMP_FAIL) { pmp_violation =3D true; } + if (ret =3D=3D TRANSLATE_SUCCESS) { tlb_set_page(cs, address & TARGET_PAGE_MASK, pa & TARGET_PAGE_MASK, prot, mmu_idx, TARGET_PAGE_SIZE); @@ -659,9 +811,12 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, i= nt size, } else if (probe) { return false; } else { - raise_mmu_exception(env, address, access_type, pmp_violation, true= ); + raise_mmu_exception(env, address, access_type, pmp_violation, firs= t_stage_error); riscv_raise_exception(env, cs->exception_index, retaddr); } + + return true; + #else switch (access_type) { case MMU_INST_FETCH: --=20 2.23.0