From patchwork Wed Apr 25 23:45:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Clark X-Patchwork-Id: 904777 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=sifive.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=sifive.com header.i=@sifive.com header.b="BPEtpsaR"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40WcQn6qkFz9rxs for ; Thu, 26 Apr 2018 09:50:57 +1000 (AEST) Received: from localhost ([::1]:39562 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fBUBb-0006pe-Uv for incoming@patchwork.ozlabs.org; Wed, 25 Apr 2018 19:50:56 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46513) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fBU8h-0004wV-9q for qemu-devel@nongnu.org; Wed, 25 Apr 2018 19:47:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fBU8f-00053N-UR for qemu-devel@nongnu.org; Wed, 25 Apr 2018 19:47:55 -0400 Received: from mail-pf0-x243.google.com ([2607:f8b0:400e:c00::243]:43050) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fBU8f-00052u-MS for qemu-devel@nongnu.org; Wed, 25 Apr 2018 19:47:53 -0400 Received: by mail-pf0-x243.google.com with SMTP id j11so16584352pff.10 for ; Wed, 25 Apr 2018 16:47:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=vklk+9kaz5wRw5OllSTrAjyQZKGHNka0a2qj6ixNI+o=; b=BPEtpsaRU14dOi7Z0YauGozsI8+nyzOASK7bFeMPWvArkpFO0DIUKAFs1vsMYTFf5d tX7j+MVM9FEv2F/7yjSmRzlyJw1aV2vgl3PYkBUZ7Klc5z8OBbPZKsO2+xA76dNdbFtQ QymwOUmuHki85k4x3tJQGfRoAVVxQUHK5IT+H/Wen0HtSjXV4oogrQJmRH1iv48Pu8xF dg/AMdAnRD3ldpNSLukrNQfxbzzAl9Ha/SUSY6veCqdxajmmr5VI1KskjSGQvHnOhQwK T2Doobv8eSJJ95eVuBRroEeVP7OW+OtWDsAzw1lQKwf68mD1lrTudSDW89ycXz9KFKE8 T7pg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=vklk+9kaz5wRw5OllSTrAjyQZKGHNka0a2qj6ixNI+o=; b=YGgMWsodrzJCY9pZXkflhRVE3W4xZZ08DODQ78HMExafk/pCrBk5HL4Q7/n1EGnRyn 2qcnX3WpecQ9bW9AkAjwNcst5NUWGtFU9x/piyjRZ5BdpkBDrObtMdfT7TXYLPPVHv4M NLrhBFjBcQRB2x4TLSS4IN7EBz0Ye8ZEEwbquplGO+0AYuG5qO1BE+uc1J8ftpOz35l7 ea07UGBrIxlK8gEXr1Vc5NUm/Ri5mN8L7oiYcLh86bj+vRmjTlgZF5LhXyh18LtPl0Wb MEdhknIASooXsrR4YgFdy6jyPTAAUdd0lKrGmQ+Pr3P6EY4peQzOGT1EbD7yBK5vk2zE s42A== X-Gm-Message-State: ALQs6tBeUpY58AqhxviNRC+P9Dqyp//gAlooYsA5bdUtJ4CwP/N88TDw zas62Q+1o2jec9ZFhwuBjw4aM/4qIx4= X-Google-Smtp-Source: AB8JxZphS77/gxHiEJnqNUZHRiPMrzlL2ViCiNq5JCy1n1UqxEe69o5oxDzvlmftYEH8N/OpWx34cQ== X-Received: by 10.98.62.194 with SMTP id y63mr6160331pfj.102.1524700072669; Wed, 25 Apr 2018 16:47:52 -0700 (PDT) Received: from localhost.localdomain (122-58-167-38-fibre.bb.spark.co.nz. [122.58.167.38]) by smtp.gmail.com with ESMTPSA id e10sm29577549pfn.67.2018.04.25.16.47.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 25 Apr 2018 16:47:52 -0700 (PDT) From: Michael Clark To: qemu-devel@nongnu.org Date: Thu, 26 Apr 2018 11:45:16 +1200 Message-Id: <1524699938-6764-14-git-send-email-mjc@sifive.com> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1524699938-6764-1-git-send-email-mjc@sifive.com> References: <1524699938-6764-1-git-send-email-mjc@sifive.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c00::243 Subject: [Qemu-devel] [PATCH v8 13/35] RISC-V: Improve page table walker spec compliance 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: Sagar Karandikar , Bastian Koppelmann , Palmer Dabbelt , Michael Clark , Alistair Francis , patches@groups.riscv.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" - Inline PTE_TABLE check for better readability - Change access checks from ternary operator to if - Improve readibility of User page U mode and SUM test - Disallow non U mode from fetching from User pages - Add reserved PTE flag check: W or W|X - Add misaligned PPN check - Set READ protection for PTE X flag and mstatus.mxr - Use memory_region_is_ram in pte update Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: Palmer Dabbelt Cc: Alistair Francis Signed-off-by: Michael Clark Reviewed-by: Alistair Francis --- target/riscv/cpu_bits.h | 2 -- target/riscv/helper.c | 64 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 64aa097..12b4757 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -407,5 +407,3 @@ #define PTE_SOFT 0x300 /* Reserved for Software */ #define PTE_PPN_SHIFT 10 - -#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) diff --git a/target/riscv/helper.c b/target/riscv/helper.c index 02cbcea..459fc97 100644 --- a/target/riscv/helper.c +++ b/target/riscv/helper.c @@ -185,16 +185,39 @@ restart: #endif target_ulong ppn = pte >> PTE_PPN_SHIFT; - if (PTE_TABLE(pte)) { /* next level of page table */ + if (!(pte & PTE_V)) { + /* Invalid PTE */ + return TRANSLATE_FAIL; + } else if (!(pte & (PTE_R | PTE_W | PTE_X))) { + /* Inner PTE, continue walking */ base = ppn << PGSHIFT; - } else if ((pte & PTE_U) ? (mode == PRV_S) && !sum : !(mode == PRV_S)) { - break; - } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { - break; - } else if (access_type == MMU_INST_FETCH ? !(pte & PTE_X) : - access_type == MMU_DATA_LOAD ? !(pte & PTE_R) && - !(mxr && (pte & PTE_X)) : !((pte & PTE_R) && (pte & PTE_W))) { - break; + } else if ((pte & (PTE_R | PTE_W | PTE_X)) == PTE_W) { + /* Reserved leaf PTE flags: PTE_W */ + return TRANSLATE_FAIL; + } else if ((pte & (PTE_R | PTE_W | PTE_X)) == (PTE_W | PTE_X)) { + /* Reserved leaf PTE flags: PTE_W + PTE_X */ + return TRANSLATE_FAIL; + } else if ((pte & PTE_U) && ((mode != PRV_U) && + (!sum || access_type == MMU_INST_FETCH))) { + /* User PTE flags when not U mode and mstatus.SUM is not set, + or the access type is an instruction fetch */ + return TRANSLATE_FAIL; + } else if (!(pte & PTE_U) && (mode != PRV_S)) { + /* Supervisor PTE flags when not S mode */ + return TRANSLATE_FAIL; + } else if (ppn & ((1ULL << ptshift) - 1)) { + /* Misasligned PPN */ + return TRANSLATE_FAIL; + } else if (access_type == MMU_DATA_LOAD && !((pte & PTE_R) || + ((pte & PTE_X) && mxr))) { + /* Read access check failed */ + return TRANSLATE_FAIL; + } else if (access_type == MMU_DATA_STORE && !(pte & PTE_W)) { + /* Write access check failed */ + return TRANSLATE_FAIL; + } else if (access_type == MMU_INST_FETCH && !(pte & PTE_X)) { + /* Fetch access check failed */ + return TRANSLATE_FAIL; } else { /* if necessary, set accessed and dirty bits. */ target_ulong updated_pte = pte | PTE_A | @@ -202,16 +225,19 @@ restart: /* Page table updates need to be atomic with MTTCG enabled */ if (updated_pte != pte) { - /* if accessed or dirty bits need updating, and the PTE is - * in RAM, then we do so atomically with a compare and swap. - * if the PTE is in IO space, then it can't be updated. - * if the PTE changed, then we must re-walk the page table - as the PTE is no longer valid */ + /* + * - if accessed or dirty bits need updating, and the PTE is + * in RAM, then we do so atomically with a compare and swap. + * - if the PTE is in IO space or ROM, then it can't be updated + * and we return TRANSLATE_FAIL. + * - if the PTE changed by the time we went to update it, then + * it is no longer valid and we must re-walk the page table. + */ MemoryRegion *mr; hwaddr l = sizeof(target_ulong), addr1; mr = address_space_translate(cs->as, pte_addr, &addr1, &l, false); - if (memory_access_is_direct(mr, true)) { + if (memory_region_is_ram(mr)) { target_ulong *pte_pa = qemu_map_ram_ptr(mr->ram_block, addr1); #if TCG_OVERSIZED_GUEST @@ -239,15 +265,15 @@ restart: target_ulong vpn = addr >> PGSHIFT; *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT; - if ((pte & PTE_R)) { + /* set permissions on the TLB entry */ + if ((pte & PTE_R) || ((pte & PTE_X) && mxr)) { *prot |= PAGE_READ; } if ((pte & PTE_X)) { *prot |= PAGE_EXEC; } - /* only add write permission on stores or if the page - is already dirty, so that we don't miss further - page table walks to update the dirty bit */ + /* add write permission on stores or if the page is already dirty, + so that we TLB miss on later writes to update the dirty bit */ if ((pte & PTE_W) && (access_type == MMU_DATA_STORE || (pte & PTE_D))) { *prot |= PAGE_WRITE;