From patchwork Thu Jun 28 03:03:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 140403 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp1653670ljj; Wed, 27 Jun 2018 20:18:30 -0700 (PDT) X-Google-Smtp-Source: AAOMgpdDtObkRe0ipk2P4YjpXNuyONw4+wpnXTKlewR7f9Wh0OSRKYiPFAvY0FJhq9wEXkBzBrLH X-Received: by 2002:a0c:8c4c:: with SMTP id o12-v6mr7610491qvb.185.1530155910040; Wed, 27 Jun 2018 20:18:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530155910; cv=none; d=google.com; s=arc-20160816; b=xZipV6hiwsqMmr39i5pWXAhdI07YYtVGEyMvE9FFgPGj8bvHyhy0scjSRnT7z3PUwb XpVSzOXUGMF+zOceIMFfZ6wu5iok5DlKbTGu4W37V59VL5LZkep7ZrgaFjbwYK/jlU+z AohCxbF0d6PJVSVDErqKUjUesaQxQj8A/eL/3BAwjkVhZXgUJ5sT/xu2SITaegFMS9T4 PlIjzjCKWLACyv+P9Te0tDVVCyX2fXChw+SRh2BnqkXFSqPdqkDFUe4pdZSXvA9rUQRE lHVqk+QNA36IPAUff9ySJpIIctxK5qpDIpJZwqjqct8P3c18o63a0+Vv4ss62YFgQ98v fp8Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature:arc-authentication-results; bh=gwN/7WgsND7BL7PgsVURX7sh5YIFP5WSPDM5slNfWQM=; b=h1OcQCD2OyCSmHRMI8oeUKOBA+qZsVkCl/BqdfFoOLjJmhqyMD4oxfjBrQ3mTmu2yr yQKoFsYDGZbI5MMVfQP1uMXsPC3qfmgd8IT5Tykpu15Ye7GlXvn5fkkieszVYL3lA/m2 hdzCel51FNRq7iNt17CMOj8K4MQl1vFSxTD7oI4rgPlioViR4sUnWfYlzR5vj2k5nSck nPlaEHrXbd+pQgx1MH20iOeyhYBDUavGfVJBmLi/RWHi4vrGQes0LssB/qemlYQcaFBy J3YDWKudPGKNLSBOTQaA2lffIXPaQwMxqW7uuFj6nGYrDC/izDxcTKrDswjFesqNysKu XlEQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=Ie8oebXh; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id a126-v6si4763264qkf.46.2018.06.27.20.18.29 for (version=TLS1 cipher=AES128-SHA bits=128/128); Wed, 27 Jun 2018 20:18:30 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=Ie8oebXh; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:34316 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYNS1-0000Dj-CO for patch@linaro.org; Wed, 27 Jun 2018 23:18:29 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40085) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYNE3-0005Ee-NG for qemu-devel@nongnu.org; Wed, 27 Jun 2018 23:04:05 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYNE2-0008Dq-1P for qemu-devel@nongnu.org; Wed, 27 Jun 2018 23:04:03 -0400 Received: from mail-pg0-x241.google.com ([2607:f8b0:400e:c05::241]:38932) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fYNE1-0008Cf-PK for qemu-devel@nongnu.org; Wed, 27 Jun 2018 23:04:01 -0400 Received: by mail-pg0-x241.google.com with SMTP id n2-v6so1797231pgq.6 for ; Wed, 27 Jun 2018 20:04:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=gwN/7WgsND7BL7PgsVURX7sh5YIFP5WSPDM5slNfWQM=; b=Ie8oebXhpJNAB1wzv4WWz2hBDwtuty6IyGcVQUTzD0qgno7gBpnnnvErneliihnqLU z37RzlFZZ1tpks0bf5RMY7Rw9aeSOfasQXonGtxw59staMWQ9bA0ZmQ1I6gH03j7CRzw 2HYw57v+x/Vst7gpAUXlhXW22mJotnYH7t/bo= 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=gwN/7WgsND7BL7PgsVURX7sh5YIFP5WSPDM5slNfWQM=; b=Msgxj+oo+vfbrjxnhWE7HUGLNkWsoP3AeVk8FTgp5omKqc3z5iVe1JvaU7a56wPt+d CrUSURGeIXWITTjuC+dkBooj8FRlhB9LLpLOyTP5epyynOUugHrKtWoZQ7GzGZv6oMyM XjE7KURz3ir4mAEyDHWQz4oNyJK6ndL7NS/2nLlwU+d2YqrndPHeHHLS7d6azPFF+g5e aDrQGt3+jrrybCEAbdmXYjnIJ+zxOmKfop9HgN38DLVEqwaSDQN9ymea6GXxJnVjQG+n rivRSBWqpKVypiBgjZiID2UC/Gjk8vbG/IA6lA8zFVFPm+kePiBife6dOcwsAGDVM7pT jiGg== X-Gm-Message-State: APt69E1axWIeqXsPLf8nGmhBkazhx/GfDMwZzRfNTbOtwosbHkJQkk6W Ilx3NcZs0VICoQtveWKTEru5w8JsqnU= X-Received: by 2002:a62:ae08:: with SMTP id q8-v6mr7783467pff.126.1530155040357; Wed, 27 Jun 2018 20:04:00 -0700 (PDT) Received: from cloudburst.twiddle.net (97-126-112-211.tukw.qwest.net. [97.126.112.211]) by smtp.gmail.com with ESMTPSA id y15-v6sm8030489pfm.136.2018.06.27.20.03.59 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 27 Jun 2018 20:03:59 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Wed, 27 Jun 2018 20:03:27 -0700 Message-Id: <20180628030330.15615-21-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180628030330.15615-1-richard.henderson@linaro.org> References: <20180628030330.15615-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c05::241 Subject: [Qemu-devel] [PATCH v3 20/23] target/openrisc: Reorg tlb lookup 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: shorne@gmail.com Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" While openrisc has a split i/d tlb, qemu does not. Perform a lookup on both i & d tlbs in parallel and put the composite rights into qemu's tlb. This avoids ping-ponging the qemu tlb between EXEC and READ. Signed-off-by: Richard Henderson --- target/openrisc/cpu.h | 8 -- target/openrisc/mmu.c | 254 +++++++++++++++--------------------------- 2 files changed, 90 insertions(+), 172 deletions(-) -- 2.17.1 diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index b180e30e9e..f1b31bc24a 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -237,14 +237,6 @@ enum { UXE = (1 << 7), }; -/* check if tlb available */ -enum { - TLBRET_INVALID = -3, - TLBRET_NOMATCH = -2, - TLBRET_BADADDR = -1, - TLBRET_MATCH = 0 -}; - typedef struct OpenRISCTLBEntry { uint32_t mr; uint32_t tr; diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c index f4c0a3e217..d3796ae41e 100644 --- a/target/openrisc/mmu.c +++ b/target/openrisc/mmu.c @@ -29,148 +29,78 @@ #endif #ifndef CONFIG_USER_ONLY -static inline int get_phys_nommu(hwaddr *physical, int *prot, - target_ulong address) +static inline void get_phys_nommu(hwaddr *phys_addr, int *prot, + target_ulong address) { - *physical = address; + *phys_addr = address; *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - return TLBRET_MATCH; } -static int get_phys_code(OpenRISCCPU *cpu, hwaddr *physical, int *prot, - target_ulong address, int rw, bool supervisor) +static int get_phys_mmu(OpenRISCCPU *cpu, hwaddr *phys_addr, int *prot, + target_ulong addr, int need, bool super) { - int vpn = address >> TARGET_PAGE_BITS; - int idx = vpn & TLB_MASK; - int right = 0; - uint32_t mr = cpu->env.tlb.itlb[idx].mr; - uint32_t tr = cpu->env.tlb.itlb[idx].tr; + int idx = (addr >> TARGET_PAGE_BITS) & TLB_MASK; + uint32_t imr = cpu->env.tlb.itlb[idx].mr; + uint32_t itr = cpu->env.tlb.itlb[idx].tr; + uint32_t dmr = cpu->env.tlb.dtlb[idx].mr; + uint32_t dtr = cpu->env.tlb.dtlb[idx].tr; + int right, match, valid; - if ((mr >> TARGET_PAGE_BITS) != vpn) { - return TLBRET_NOMATCH; - } - if (!(mr & 1)) { - return TLBRET_INVALID; - } - if (supervisor) { - if (tr & SXE) { - right |= PAGE_EXEC; - } - } else { - if (tr & UXE) { - right |= PAGE_EXEC; + /* If the ITLB and DTLB indexes map to the same page, we want to + load all permissions all at once. If the destination pages do + not match, zap the one we don't need. */ + if (unlikely((itr ^ dtr) & TARGET_PAGE_MASK)) { + if (need & PAGE_EXEC) { + dmr = dtr = 0; + } else { + imr = itr = 0; } } - if ((rw & 2) && ((right & PAGE_EXEC) == 0)) { - return TLBRET_BADADDR; - } - *physical = (tr & TARGET_PAGE_MASK) | (address & ~TARGET_PAGE_MASK); + /* Check if either of the entries matches the source address. */ + match = (imr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_EXEC; + match |= (dmr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_READ | PAGE_WRITE; + + /* Check if either of the entries is valid. */ + valid = imr & 1 ? PAGE_EXEC : 0; + valid |= dmr & 1 ? PAGE_READ | PAGE_WRITE : 0; + valid &= match; + + /* Collect the permissions from the entries. */ + right = itr & (super ? SXE : UXE) ? PAGE_EXEC : 0; + right |= dtr & (super ? SRE : URE) ? PAGE_READ : 0; + right |= dtr & (super ? SWE : UWE) ? PAGE_WRITE : 0; + right &= valid; + + /* Note that above we validated that itr and dtr match on page. + So oring them together changes nothing without having to + check which one we needed. We also want to store to these + variables even on failure, as it avoids compiler warnings. */ + *phys_addr = ((itr | dtr) & TARGET_PAGE_MASK) | (addr & ~TARGET_PAGE_MASK); *prot = right; - return TLBRET_MATCH; -} -static int get_phys_data(OpenRISCCPU *cpu, hwaddr *physical, int *prot, - target_ulong address, int rw, bool supervisor) -{ - int vpn = address >> TARGET_PAGE_BITS; - int idx = vpn & TLB_MASK; - int right = 0; - uint32_t mr = cpu->env.tlb.dtlb[idx].mr; - uint32_t tr = cpu->env.tlb.dtlb[idx].tr; + qemu_log_mask(CPU_LOG_MMU, + "MMU lookup: need %d match %d valid %d right %d -> %s\n", + need, match, valid, right, (need & right) ? "OK" : "FAIL"); - if ((mr >> TARGET_PAGE_BITS) != vpn) { - return TLBRET_NOMATCH; + /* Check the collective permissions are present. */ + if (likely(need & right)) { + return 0; /* success! */ } - if (!(mr & 1)) { - return TLBRET_INVALID; - } - if (supervisor) { - if (tr & SRE) { - right |= PAGE_READ; - } - if (tr & SWE) { - right |= PAGE_WRITE; - } + + /* Determine what kind of failure we have. */ + if (need & valid) { + return need & PAGE_EXEC ? EXCP_IPF : EXCP_DPF; } else { - if (tr & URE) { - right |= PAGE_READ; - } - if (tr & UWE) { - right |= PAGE_WRITE; - } + return need & PAGE_EXEC ? EXCP_ITLBMISS : EXCP_DTLBMISS; } - - if (!(rw & 1) && ((right & PAGE_READ) == 0)) { - return TLBRET_BADADDR; - } - if ((rw & 1) && ((right & PAGE_WRITE) == 0)) { - return TLBRET_BADADDR; - } - - *physical = (tr & TARGET_PAGE_MASK) | (address & ~TARGET_PAGE_MASK); - *prot = right; - return TLBRET_MATCH; -} - -static int get_phys_addr(OpenRISCCPU *cpu, hwaddr *physical, - int *prot, target_ulong address, int rw) -{ - bool supervisor = (cpu->env.sr & SR_SM) != 0; - int ret; - - /* Assume nommu results for a moment. */ - ret = get_phys_nommu(physical, prot, address); - - /* Overwrite with TLB lookup if enabled. */ - if (rw == MMU_INST_FETCH) { - if (cpu->env.sr & SR_IME) { - ret = get_phys_code(cpu, physical, prot, address, rw, supervisor); - } - } else { - if (cpu->env.sr & SR_DME) { - ret = get_phys_data(cpu, physical, prot, address, rw, supervisor); - } - } - - return ret; } #endif -static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU *cpu, - target_ulong address, - int rw, int tlb_error) +static void raise_mmu_exception(OpenRISCCPU *cpu, target_ulong address, + int exception) { CPUState *cs = CPU(cpu); - int exception = 0; - - switch (tlb_error) { - default: - if (rw == 2) { - exception = EXCP_IPF; - } else { - exception = EXCP_DPF; - } - break; -#ifndef CONFIG_USER_ONLY - case TLBRET_BADADDR: - if (rw == 2) { - exception = EXCP_IPF; - } else { - exception = EXCP_DPF; - } - break; - case TLBRET_INVALID: - case TLBRET_NOMATCH: - /* No TLB match for a mapped address */ - if (rw == 2) { - exception = EXCP_ITLBMISS; - } else { - exception = EXCP_DTLBMISS; - } - break; -#endif - } cs->exception_index = exception; cpu->env.eear = address; @@ -182,7 +112,7 @@ int openrisc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, { #ifdef CONFIG_USER_ONLY OpenRISCCPU *cpu = OPENRISC_CPU(cs); - cpu_openrisc_raise_mmu_exception(cpu, address, rw, 0); + raise_mmu_exception(cpu, address, EXCP_DPF); return 1; #else g_assert_not_reached(); @@ -193,27 +123,32 @@ int openrisc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) { OpenRISCCPU *cpu = OPENRISC_CPU(cs); + int prot, excp, sr = cpu->env.sr; hwaddr phys_addr; - int prot; - int miss; - /* Check memory for any kind of address, since during debug the - gdb can ask for anything, check data tlb for address */ - miss = get_phys_addr(cpu, &phys_addr, &prot, addr, 0); + switch (sr & (SR_DME | SR_IME)) { + case SR_DME | SR_IME: + /* The mmu is definitely enabled. */ + excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, + PROT_EXEC | PROT_READ | PROT_WRITE, + (sr & SR_SM) != 0); + return excp ? -1 : phys_addr; - /* Check instruction tlb */ - if (miss) { - miss = get_phys_addr(cpu, &phys_addr, &prot, addr, MMU_INST_FETCH); - } + default: + /* The mmu is partially enabled, and we don't really have + a "real" access type. Begin by trying the mmu, but if + that fails try again without. */ + excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, + PROT_EXEC | PROT_READ | PROT_WRITE, + (sr & SR_SM) != 0); + if (!excp) { + return phys_addr; + } + /* fallthru */ - /* Last, fall back to a plain address */ - if (miss) { - miss = get_phys_nommu(&phys_addr, &prot, addr); - } - - if (miss) { - return -1; - } else { + case 0: + /* The mmu is definitely disabled; lookups never fail. */ + get_phys_nommu(&phys_addr, &prot, addr); return phys_addr; } } @@ -222,37 +157,28 @@ void tlb_fill(CPUState *cs, target_ulong addr, int size, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { OpenRISCCPU *cpu = OPENRISC_CPU(cs); - int ret, prot = 0; - hwaddr physical = 0; + int prot, excp; + hwaddr phys_addr; if (mmu_idx == MMU_NOMMU_IDX) { - ret = get_phys_nommu(&physical, &prot, addr); + /* The mmu is disabled; lookups never fail. */ + get_phys_nommu(&phys_addr, &prot, addr); + excp = 0; } else { bool super = mmu_idx == MMU_SUPERVISOR_IDX; - if (access_type == MMU_INST_FETCH) { - ret = get_phys_code(cpu, &physical, &prot, addr, 2, super); - } else { - ret = get_phys_data(cpu, &physical, &prot, addr, - access_type == MMU_DATA_STORE, super); - } + int need = (access_type == MMU_INST_FETCH ? PROT_EXEC + : access_type == MMU_DATA_STORE ? PROT_WRITE + : PROT_READ); + excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, need, super); } - if (ret == TLBRET_MATCH) { - tlb_set_page(cs, addr & TARGET_PAGE_MASK, - physical & TARGET_PAGE_MASK, prot, - mmu_idx, TARGET_PAGE_SIZE); - } else if (ret < 0) { - int rw; - if (access_type == MMU_INST_FETCH) { - rw = 2; - } else if (access_type == MMU_DATA_STORE) { - rw = 1; - } else { - rw = 0; - } - cpu_openrisc_raise_mmu_exception(cpu, addr, rw, ret); - /* Raise Exception. */ + if (unlikely(excp)) { + raise_mmu_exception(cpu, addr, excp); cpu_loop_exit_restore(cs, retaddr); } + + tlb_set_page(cs, addr & TARGET_PAGE_MASK, + phys_addr & TARGET_PAGE_MASK, prot, + mmu_idx, TARGET_PAGE_SIZE); } #endif