From patchwork Mon Jun 18 18:40:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 139053 Delivered-To: patch@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp4287023lji; Mon, 18 Jun 2018 11:50:24 -0700 (PDT) X-Google-Smtp-Source: ADUXVKLbS2jpHGqgFIa14oCyX4GJWXcgyXbfbF0wO1EgkiI9YISPj4nz+XH6BFHG5FlumURhB+6r X-Received: by 2002:ac8:2dc6:: with SMTP id q6-v6mr12039689qta.83.1529347824838; Mon, 18 Jun 2018 11:50:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529347824; cv=none; d=google.com; s=arc-20160816; b=s+72zB4ZuWDuuauX7hCWcGp/m4gZ+tWJ6up0pw+fQeF4U2avtKFSTATxuv241vJITL sjnZPAixl/qh54tuYovkhVPG3no45GixRlyj1uvUnAUwwgm5lq7elkhbZUv4h/zXTTWL DH+W+kgzh1fEPGCI4LC8sgJDCLJmCsNIxEdeu5y6n277Geoln1mz7RGFu7LYguFEatAo sFQEHNzoN76FvjGfPttxPJGnoI7bheD8B/RUMhUEOezKnK9hUNQh+KAt0L8hsCsNRhiC HS07YJ1c0T3EwIblbe7J8Vr+xklawnHwUeKr1HKPMs6tJ7+bORLS5M5Fdl5H/F55gsVk pCzA== 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=aa/SHG/LxURCrjFybFC++2LSNmmhU6rlmBikxJvyPmI=; b=T8SB1wj5rcw9J6xsF8UBbJK+eec7DNF3fxKmo9FrwclBRmN+nyL0fb1hX768S7+zem zykf5AD5R+5ewJAO405iBlK2w+RrV+VtsP9868eAAwOMAvHY86i/sVzDJuNhOu8HWEIj 2tR4VSqrjKHBb3tBe8xDiUPVNH6eOynqlHN7qapeGfdVqA3z8yZjqbFKsE9g+UEWPMD0 MIURQnM5m1aIl+CiYLNwDw3R3bYnhKt8ePQJdCug1PA9nUeYI9VuOLYB2CHRDEHP0S0F ET0FxC7WfJkcMg5uZTFiAjW8hGHaZb1dla9JZfIhhIwtPZ5SaZQuFnzl232KumuUlh9C ydKg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=cHJOV70v; 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 r5-v6si2115556qvc.200.2018.06.18.11.50.24 for (version=TLS1 cipher=AES128-SHA bits=128/128); Mon, 18 Jun 2018 11:50:24 -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=cHJOV70v; 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]:36510 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUzEO-0002ef-8k for patch@linaro.org; Mon, 18 Jun 2018 14:50:24 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57491) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUz5h-0003ba-G6 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 14:41:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUz5f-00050O-UD for qemu-devel@nongnu.org; Mon, 18 Jun 2018 14:41:25 -0400 Received: from mail-pf0-x244.google.com ([2607:f8b0:400e:c00::244]:39683) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fUz5f-0004zN-L8 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 14:41:23 -0400 Received: by mail-pf0-x244.google.com with SMTP id r11-v6so8605587pfl.6 for ; Mon, 18 Jun 2018 11:41:23 -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=aa/SHG/LxURCrjFybFC++2LSNmmhU6rlmBikxJvyPmI=; b=cHJOV70vdK/XEuWa7snnFuTGEfwlgQ5AEJtxIzVxXCIk3gGvRAwj9dgQCggovAEAnU UX9DQ6p+TfvosjYQ0vROdicl3jhq5wpS4Iwbn9BC4JLXI+AhHbbbZMAFgA5FOXdFoSDq 3+Oex2n/0sEZh9cfP+uuVW33Ikflpmrtk72yY= 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=aa/SHG/LxURCrjFybFC++2LSNmmhU6rlmBikxJvyPmI=; b=nKTjvK0UIK3YGtgrD9ZcRkrloLNwuSqX2pCcS1wxny3WAJiBj1GwOOgvlutLAWYD0x +DAwDUChDAz/fmastP89MSavi1XXvpej+f2NA4Pk5HCy93JCv5fgdliGPuX8byz7dLFU eyOQcZnRwxtJSi9e08oxTLASi9sLRwIUp2vq0NDsZhjzlCkrpWGayqAaOQLz9l6S+hnt KQ89MjVSHMeNMpDvY6uO25ANOBC0wkKMKadXohrT1DVgvN4bQS9eG+/CuZodcpGYpJbX lCyGdZ8dEiAEJPhdXzMlRO6P8QsExJick7pgfGSSfDtZnZkRz1cNCBUsaLw2n2RlFV3F YHcg== X-Gm-Message-State: APt69E0qdDs531hwSbk1alAE88YNRt8nktFFILUsFv8M6UBfFr8fUH/G 3G9tSU8E7d6oyc+82w9L5EqksTbs3ss= X-Received: by 2002:a62:904c:: with SMTP id a73-v6mr14695788pfe.145.1529347282434; Mon, 18 Jun 2018 11:41:22 -0700 (PDT) Received: from cloudburst.twiddle.net (mta-98-147-121-51.hawaii.rr.com. [98.147.121.51]) by smtp.gmail.com with ESMTPSA id i65-v6sm49457254pfd.17.2018.06.18.11.41.20 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 18 Jun 2018 11:41:21 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 08:40:42 -1000 Message-Id: <20180618184046.6270-19-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180618184046.6270-1-richard.henderson@linaro.org> References: <20180618184046.6270-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:c00::244 Subject: [Qemu-devel] [PATCH v2 18/22] 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 8035654087..1efffa5269 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