1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth * OpenRISC MMU.
3fcf5ef2aSThomas Huth *
4fcf5ef2aSThomas Huth * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
5fcf5ef2aSThomas Huth * Zhizhou Zhang <etouzh@gmail.com>
6fcf5ef2aSThomas Huth *
7fcf5ef2aSThomas Huth * This library is free software; you can redistribute it and/or
8fcf5ef2aSThomas Huth * modify it under the terms of the GNU Lesser General Public
9fcf5ef2aSThomas Huth * License as published by the Free Software Foundation; either
10198a2d21SThomas Huth * version 2.1 of the License, or (at your option) any later version.
11fcf5ef2aSThomas Huth *
12fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful,
13fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15fcf5ef2aSThomas Huth * Lesser General Public License for more details.
16fcf5ef2aSThomas Huth *
17fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public
18fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19fcf5ef2aSThomas Huth */
20fcf5ef2aSThomas Huth
21fcf5ef2aSThomas Huth #include "qemu/osdep.h"
22cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h"
23fcf5ef2aSThomas Huth #include "cpu.h"
24fcf5ef2aSThomas Huth #include "exec/exec-all.h"
25*74781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
264ea5fe99SAlex Bennée #include "gdbstub/helpers.h"
27fcf5ef2aSThomas Huth #include "qemu/host-utils.h"
28fcf5ef2aSThomas Huth #include "hw/loader.h"
29fcf5ef2aSThomas Huth
get_phys_nommu(hwaddr * phys_addr,int * prot,target_ulong address)30f0655423SRichard Henderson static inline void get_phys_nommu(hwaddr *phys_addr, int *prot,
3123d45ebdSRichard Henderson target_ulong address)
32fcf5ef2aSThomas Huth {
33f0655423SRichard Henderson *phys_addr = address;
34fcf5ef2aSThomas Huth *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
35fcf5ef2aSThomas Huth }
36fcf5ef2aSThomas Huth
get_phys_mmu(OpenRISCCPU * cpu,hwaddr * phys_addr,int * prot,target_ulong addr,int need,bool super)37f0655423SRichard Henderson static int get_phys_mmu(OpenRISCCPU *cpu, hwaddr *phys_addr, int *prot,
38f0655423SRichard Henderson target_ulong addr, int need, bool super)
39fcf5ef2aSThomas Huth {
40f0655423SRichard Henderson int idx = (addr >> TARGET_PAGE_BITS) & TLB_MASK;
41f0655423SRichard Henderson uint32_t imr = cpu->env.tlb.itlb[idx].mr;
42f0655423SRichard Henderson uint32_t itr = cpu->env.tlb.itlb[idx].tr;
43f0655423SRichard Henderson uint32_t dmr = cpu->env.tlb.dtlb[idx].mr;
44f0655423SRichard Henderson uint32_t dtr = cpu->env.tlb.dtlb[idx].tr;
45f0655423SRichard Henderson int right, match, valid;
46fcf5ef2aSThomas Huth
47f0655423SRichard Henderson /* If the ITLB and DTLB indexes map to the same page, we want to
48f0655423SRichard Henderson load all permissions all at once. If the destination pages do
49f0655423SRichard Henderson not match, zap the one we don't need. */
50f0655423SRichard Henderson if (unlikely((itr ^ dtr) & TARGET_PAGE_MASK)) {
51f0655423SRichard Henderson if (need & PAGE_EXEC) {
52f0655423SRichard Henderson dmr = dtr = 0;
53fcf5ef2aSThomas Huth } else {
54f0655423SRichard Henderson imr = itr = 0;
55fcf5ef2aSThomas Huth }
56fcf5ef2aSThomas Huth }
57fcf5ef2aSThomas Huth
58f0655423SRichard Henderson /* Check if either of the entries matches the source address. */
59f0655423SRichard Henderson match = (imr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_EXEC;
60f0655423SRichard Henderson match |= (dmr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_READ | PAGE_WRITE;
61f0655423SRichard Henderson
62f0655423SRichard Henderson /* Check if either of the entries is valid. */
63f0655423SRichard Henderson valid = imr & 1 ? PAGE_EXEC : 0;
64f0655423SRichard Henderson valid |= dmr & 1 ? PAGE_READ | PAGE_WRITE : 0;
65f0655423SRichard Henderson valid &= match;
66f0655423SRichard Henderson
67f0655423SRichard Henderson /* Collect the permissions from the entries. */
68f0655423SRichard Henderson right = itr & (super ? SXE : UXE) ? PAGE_EXEC : 0;
69f0655423SRichard Henderson right |= dtr & (super ? SRE : URE) ? PAGE_READ : 0;
70f0655423SRichard Henderson right |= dtr & (super ? SWE : UWE) ? PAGE_WRITE : 0;
71f0655423SRichard Henderson right &= valid;
72f0655423SRichard Henderson
73f0655423SRichard Henderson /* Note that above we validated that itr and dtr match on page.
74f0655423SRichard Henderson So oring them together changes nothing without having to
75f0655423SRichard Henderson check which one we needed. We also want to store to these
76f0655423SRichard Henderson variables even on failure, as it avoids compiler warnings. */
77f0655423SRichard Henderson *phys_addr = ((itr | dtr) & TARGET_PAGE_MASK) | (addr & ~TARGET_PAGE_MASK);
78fcf5ef2aSThomas Huth *prot = right;
79f0655423SRichard Henderson
80f0655423SRichard Henderson qemu_log_mask(CPU_LOG_MMU,
81f0655423SRichard Henderson "MMU lookup: need %d match %d valid %d right %d -> %s\n",
82f0655423SRichard Henderson need, match, valid, right, (need & right) ? "OK" : "FAIL");
83f0655423SRichard Henderson
84f0655423SRichard Henderson /* Check the collective permissions are present. */
85f0655423SRichard Henderson if (likely(need & right)) {
86f0655423SRichard Henderson return 0; /* success! */
87fcf5ef2aSThomas Huth }
88fcf5ef2aSThomas Huth
89f0655423SRichard Henderson /* Determine what kind of failure we have. */
90f0655423SRichard Henderson if (need & valid) {
91f0655423SRichard Henderson return need & PAGE_EXEC ? EXCP_IPF : EXCP_DPF;
92fcf5ef2aSThomas Huth } else {
93f0655423SRichard Henderson return need & PAGE_EXEC ? EXCP_ITLBMISS : EXCP_DTLBMISS;
94fcf5ef2aSThomas Huth }
95fcf5ef2aSThomas Huth }
96fcf5ef2aSThomas Huth
raise_mmu_exception(OpenRISCCPU * cpu,target_ulong address,int exception)97f0655423SRichard Henderson static void raise_mmu_exception(OpenRISCCPU *cpu, target_ulong address,
98f0655423SRichard Henderson int exception)
99fcf5ef2aSThomas Huth {
100fcf5ef2aSThomas Huth CPUState *cs = CPU(cpu);
101fcf5ef2aSThomas Huth
102fcf5ef2aSThomas Huth cs->exception_index = exception;
103fcf5ef2aSThomas Huth cpu->env.eear = address;
104930c3d00SRichard Henderson cpu->env.lock_addr = -1;
105fcf5ef2aSThomas Huth }
106fcf5ef2aSThomas Huth
openrisc_cpu_tlb_fill(CPUState * cs,vaddr addr,int size,MMUAccessType access_type,int mmu_idx,bool probe,uintptr_t retaddr)10735e911aeSRichard Henderson bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
10835e911aeSRichard Henderson MMUAccessType access_type, int mmu_idx,
10935e911aeSRichard Henderson bool probe, uintptr_t retaddr)
110fcf5ef2aSThomas Huth {
111fcf5ef2aSThomas Huth OpenRISCCPU *cpu = OPENRISC_CPU(cs);
11235e911aeSRichard Henderson int excp = EXCP_DPF;
11335e911aeSRichard Henderson int prot;
11435e911aeSRichard Henderson hwaddr phys_addr;
11535e911aeSRichard Henderson
11635e911aeSRichard Henderson if (mmu_idx == MMU_NOMMU_IDX) {
11735e911aeSRichard Henderson /* The mmu is disabled; lookups never fail. */
11835e911aeSRichard Henderson get_phys_nommu(&phys_addr, &prot, addr);
11935e911aeSRichard Henderson excp = 0;
12035e911aeSRichard Henderson } else {
12135e911aeSRichard Henderson bool super = mmu_idx == MMU_SUPERVISOR_IDX;
12235e911aeSRichard Henderson int need = (access_type == MMU_INST_FETCH ? PAGE_EXEC
12335e911aeSRichard Henderson : access_type == MMU_DATA_STORE ? PAGE_WRITE
12435e911aeSRichard Henderson : PAGE_READ);
12535e911aeSRichard Henderson excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, need, super);
12635e911aeSRichard Henderson }
12735e911aeSRichard Henderson
12835e911aeSRichard Henderson if (likely(excp == 0)) {
12935e911aeSRichard Henderson tlb_set_page(cs, addr & TARGET_PAGE_MASK,
13035e911aeSRichard Henderson phys_addr & TARGET_PAGE_MASK, prot,
13135e911aeSRichard Henderson mmu_idx, TARGET_PAGE_SIZE);
13235e911aeSRichard Henderson return true;
13335e911aeSRichard Henderson }
13435e911aeSRichard Henderson if (probe) {
13535e911aeSRichard Henderson return false;
13635e911aeSRichard Henderson }
13735e911aeSRichard Henderson
13835e911aeSRichard Henderson raise_mmu_exception(cpu, addr, excp);
13935e911aeSRichard Henderson cpu_loop_exit_restore(cs, retaddr);
1405ce5dad3SRichard Henderson }
141fcf5ef2aSThomas Huth
openrisc_cpu_get_phys_page_debug(CPUState * cs,vaddr addr)142fcf5ef2aSThomas Huth hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
143fcf5ef2aSThomas Huth {
144fcf5ef2aSThomas Huth OpenRISCCPU *cpu = OPENRISC_CPU(cs);
145f0655423SRichard Henderson int prot, excp, sr = cpu->env.sr;
146fcf5ef2aSThomas Huth hwaddr phys_addr;
147fcf5ef2aSThomas Huth
148f0655423SRichard Henderson switch (sr & (SR_DME | SR_IME)) {
149f0655423SRichard Henderson case SR_DME | SR_IME:
150f0655423SRichard Henderson /* The mmu is definitely enabled. */
151f0655423SRichard Henderson excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
1520fd8a106SStafford Horne PAGE_READ,
1530fd8a106SStafford Horne (sr & SR_SM) != 0);
1540fd8a106SStafford Horne if (!excp) {
1550fd8a106SStafford Horne return phys_addr;
1560fd8a106SStafford Horne }
1570fd8a106SStafford Horne excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
1580fd8a106SStafford Horne PAGE_EXEC,
159f0655423SRichard Henderson (sr & SR_SM) != 0);
160f0655423SRichard Henderson return excp ? -1 : phys_addr;
161461a4b94SStafford Horne
162f0655423SRichard Henderson default:
163f0655423SRichard Henderson /* The mmu is partially enabled, and we don't really have
164f0655423SRichard Henderson a "real" access type. Begin by trying the mmu, but if
165f0655423SRichard Henderson that fails try again without. */
166f0655423SRichard Henderson excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
167f0655423SRichard Henderson PAGE_EXEC | PAGE_READ | PAGE_WRITE,
168f0655423SRichard Henderson (sr & SR_SM) != 0);
169f0655423SRichard Henderson if (!excp) {
170f0655423SRichard Henderson return phys_addr;
171fcf5ef2aSThomas Huth }
172f0655423SRichard Henderson /* fallthru */
173fcf5ef2aSThomas Huth
174f0655423SRichard Henderson case 0:
175f0655423SRichard Henderson /* The mmu is definitely disabled; lookups never fail. */
176f0655423SRichard Henderson get_phys_nommu(&phys_addr, &prot, addr);
177fcf5ef2aSThomas Huth return phys_addr;
178fcf5ef2aSThomas Huth }
179461a4b94SStafford Horne }
180