]> git.proxmox.com Git - mirror_qemu.git/blame - target/openrisc/mmu.c
tcg: Use CPUClass::tlb_fill in cputlb.c
[mirror_qemu.git] / target / openrisc / mmu.c
CommitLineData
e67db06e
JL
1/*
2 * OpenRISC MMU.
3 *
4 * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
5 * Zhizhou Zhang <etouzh@gmail.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
198a2d21 10 * version 2.1 of the License, or (at your option) any later version.
e67db06e
JL
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
ed2decc6 21#include "qemu/osdep.h"
e67db06e 22#include "cpu.h"
63c91552 23#include "exec/exec-all.h"
e67db06e 24#include "qemu-common.h"
022c62cb 25#include "exec/gdbstub.h"
1de7afc9 26#include "qemu/host-utils.h"
e67db06e
JL
27#ifndef CONFIG_USER_ONLY
28#include "hw/loader.h"
29#endif
30
726fe045 31#ifndef CONFIG_USER_ONLY
f0655423
RH
32static inline void get_phys_nommu(hwaddr *phys_addr, int *prot,
33 target_ulong address)
726fe045 34{
f0655423 35 *phys_addr = address;
04359e6b 36 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
726fe045
JL
37}
38
f0655423
RH
39static int get_phys_mmu(OpenRISCCPU *cpu, hwaddr *phys_addr, int *prot,
40 target_ulong addr, int need, bool super)
726fe045 41{
f0655423
RH
42 int idx = (addr >> TARGET_PAGE_BITS) & TLB_MASK;
43 uint32_t imr = cpu->env.tlb.itlb[idx].mr;
44 uint32_t itr = cpu->env.tlb.itlb[idx].tr;
45 uint32_t dmr = cpu->env.tlb.dtlb[idx].mr;
46 uint32_t dtr = cpu->env.tlb.dtlb[idx].tr;
47 int right, match, valid;
48
49 /* If the ITLB and DTLB indexes map to the same page, we want to
50 load all permissions all at once. If the destination pages do
51 not match, zap the one we don't need. */
52 if (unlikely((itr ^ dtr) & TARGET_PAGE_MASK)) {
53 if (need & PAGE_EXEC) {
54 dmr = dtr = 0;
55 } else {
56 imr = itr = 0;
726fe045
JL
57 }
58 }
726fe045 59
f0655423
RH
60 /* Check if either of the entries matches the source address. */
61 match = (imr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_EXEC;
62 match |= (dmr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_READ | PAGE_WRITE;
726fe045 63
f0655423
RH
64 /* Check if either of the entries is valid. */
65 valid = imr & 1 ? PAGE_EXEC : 0;
66 valid |= dmr & 1 ? PAGE_READ | PAGE_WRITE : 0;
67 valid &= match;
726fe045 68
f0655423
RH
69 /* Collect the permissions from the entries. */
70 right = itr & (super ? SXE : UXE) ? PAGE_EXEC : 0;
71 right |= dtr & (super ? SRE : URE) ? PAGE_READ : 0;
72 right |= dtr & (super ? SWE : UWE) ? PAGE_WRITE : 0;
73 right &= valid;
726fe045 74
f0655423
RH
75 /* Note that above we validated that itr and dtr match on page.
76 So oring them together changes nothing without having to
77 check which one we needed. We also want to store to these
78 variables even on failure, as it avoids compiler warnings. */
79 *phys_addr = ((itr | dtr) & TARGET_PAGE_MASK) | (addr & ~TARGET_PAGE_MASK);
726fe045 80 *prot = right;
726fe045 81
f0655423
RH
82 qemu_log_mask(CPU_LOG_MMU,
83 "MMU lookup: need %d match %d valid %d right %d -> %s\n",
84 need, match, valid, right, (need & right) ? "OK" : "FAIL");
23d45ebd 85
f0655423
RH
86 /* Check the collective permissions are present. */
87 if (likely(need & right)) {
88 return 0; /* success! */
89 }
23d45ebd 90
f0655423
RH
91 /* Determine what kind of failure we have. */
92 if (need & valid) {
93 return need & PAGE_EXEC ? EXCP_IPF : EXCP_DPF;
23d45ebd 94 } else {
f0655423 95 return need & PAGE_EXEC ? EXCP_ITLBMISS : EXCP_DTLBMISS;
726fe045 96 }
726fe045
JL
97}
98#endif
99
f0655423
RH
100static void raise_mmu_exception(OpenRISCCPU *cpu, target_ulong address,
101 int exception)
726fe045 102{
27103424 103 CPUState *cs = CPU(cpu);
726fe045 104
27103424 105 cs->exception_index = exception;
726fe045 106 cpu->env.eear = address;
930c3d00 107 cpu->env.lock_addr = -1;
726fe045
JL
108}
109
35e911ae
RH
110bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
111 MMUAccessType access_type, int mmu_idx,
112 bool probe, uintptr_t retaddr)
726fe045 113{
7510454e 114 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
35e911ae
RH
115 int excp = EXCP_DPF;
116
117#ifndef CONFIG_USER_ONLY
118 int prot;
119 hwaddr phys_addr;
120
121 if (mmu_idx == MMU_NOMMU_IDX) {
122 /* The mmu is disabled; lookups never fail. */
123 get_phys_nommu(&phys_addr, &prot, addr);
124 excp = 0;
125 } else {
126 bool super = mmu_idx == MMU_SUPERVISOR_IDX;
127 int need = (access_type == MMU_INST_FETCH ? PAGE_EXEC
128 : access_type == MMU_DATA_STORE ? PAGE_WRITE
129 : PAGE_READ);
130 excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, need, super);
131 }
132
133 if (likely(excp == 0)) {
134 tlb_set_page(cs, addr & TARGET_PAGE_MASK,
135 phys_addr & TARGET_PAGE_MASK, prot,
136 mmu_idx, TARGET_PAGE_SIZE);
137 return true;
138 }
139 if (probe) {
140 return false;
141 }
726fe045 142#endif
35e911ae
RH
143
144 raise_mmu_exception(cpu, addr, excp);
145 cpu_loop_exit_restore(cs, retaddr);
5ce5dad3 146}
726fe045 147
e67db06e 148#ifndef CONFIG_USER_ONLY
00b941e5 149hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
e67db06e 150{
00b941e5 151 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
f0655423 152 int prot, excp, sr = cpu->env.sr;
a8170e5e 153 hwaddr phys_addr;
726fe045 154
f0655423
RH
155 switch (sr & (SR_DME | SR_IME)) {
156 case SR_DME | SR_IME:
157 /* The mmu is definitely enabled. */
158 excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
159 PAGE_EXEC | PAGE_READ | PAGE_WRITE,
160 (sr & SR_SM) != 0);
161 return excp ? -1 : phys_addr;
461a4b94 162
f0655423
RH
163 default:
164 /* The mmu is partially enabled, and we don't really have
165 a "real" access type. Begin by trying the mmu, but if
166 that fails try again without. */
167 excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
168 PAGE_EXEC | PAGE_READ | PAGE_WRITE,
169 (sr & SR_SM) != 0);
170 if (!excp) {
171 return phys_addr;
172 }
173 /* fallthru */
726fe045 174
f0655423
RH
175 case 0:
176 /* The mmu is definitely disabled; lookups never fail. */
177 get_phys_nommu(&phys_addr, &prot, addr);
461a4b94
SH
178 return phys_addr;
179 }
e67db06e 180}
e67db06e 181#endif