]> git.proxmox.com Git - mirror_qemu.git/blame - target/openrisc/mmu.c
i386: Update new x86_apicid parsing rules with die_offset support
[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"
022c62cb 24#include "exec/gdbstub.h"
1de7afc9 25#include "qemu/host-utils.h"
e67db06e
JL
26#ifndef CONFIG_USER_ONLY
27#include "hw/loader.h"
28#endif
29
726fe045 30#ifndef CONFIG_USER_ONLY
f0655423
RH
31static inline void get_phys_nommu(hwaddr *phys_addr, int *prot,
32 target_ulong address)
726fe045 33{
f0655423 34 *phys_addr = address;
04359e6b 35 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
726fe045
JL
36}
37
f0655423
RH
38static int get_phys_mmu(OpenRISCCPU *cpu, hwaddr *phys_addr, int *prot,
39 target_ulong addr, int need, bool super)
726fe045 40{
f0655423
RH
41 int idx = (addr >> TARGET_PAGE_BITS) & TLB_MASK;
42 uint32_t imr = cpu->env.tlb.itlb[idx].mr;
43 uint32_t itr = cpu->env.tlb.itlb[idx].tr;
44 uint32_t dmr = cpu->env.tlb.dtlb[idx].mr;
45 uint32_t dtr = cpu->env.tlb.dtlb[idx].tr;
46 int right, match, valid;
47
48 /* If the ITLB and DTLB indexes map to the same page, we want to
49 load all permissions all at once. If the destination pages do
50 not match, zap the one we don't need. */
51 if (unlikely((itr ^ dtr) & TARGET_PAGE_MASK)) {
52 if (need & PAGE_EXEC) {
53 dmr = dtr = 0;
54 } else {
55 imr = itr = 0;
726fe045
JL
56 }
57 }
726fe045 58
f0655423
RH
59 /* Check if either of the entries matches the source address. */
60 match = (imr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_EXEC;
61 match |= (dmr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_READ | PAGE_WRITE;
726fe045 62
f0655423
RH
63 /* Check if either of the entries is valid. */
64 valid = imr & 1 ? PAGE_EXEC : 0;
65 valid |= dmr & 1 ? PAGE_READ | PAGE_WRITE : 0;
66 valid &= match;
726fe045 67
f0655423
RH
68 /* Collect the permissions from the entries. */
69 right = itr & (super ? SXE : UXE) ? PAGE_EXEC : 0;
70 right |= dtr & (super ? SRE : URE) ? PAGE_READ : 0;
71 right |= dtr & (super ? SWE : UWE) ? PAGE_WRITE : 0;
72 right &= valid;
726fe045 73
f0655423
RH
74 /* Note that above we validated that itr and dtr match on page.
75 So oring them together changes nothing without having to
76 check which one we needed. We also want to store to these
77 variables even on failure, as it avoids compiler warnings. */
78 *phys_addr = ((itr | dtr) & TARGET_PAGE_MASK) | (addr & ~TARGET_PAGE_MASK);
726fe045 79 *prot = right;
726fe045 80
f0655423
RH
81 qemu_log_mask(CPU_LOG_MMU,
82 "MMU lookup: need %d match %d valid %d right %d -> %s\n",
83 need, match, valid, right, (need & right) ? "OK" : "FAIL");
23d45ebd 84
f0655423
RH
85 /* Check the collective permissions are present. */
86 if (likely(need & right)) {
87 return 0; /* success! */
88 }
23d45ebd 89
f0655423
RH
90 /* Determine what kind of failure we have. */
91 if (need & valid) {
92 return need & PAGE_EXEC ? EXCP_IPF : EXCP_DPF;
23d45ebd 93 } else {
f0655423 94 return need & PAGE_EXEC ? EXCP_ITLBMISS : EXCP_DTLBMISS;
726fe045 95 }
726fe045
JL
96}
97#endif
98
f0655423
RH
99static void raise_mmu_exception(OpenRISCCPU *cpu, target_ulong address,
100 int exception)
726fe045 101{
27103424 102 CPUState *cs = CPU(cpu);
726fe045 103
27103424 104 cs->exception_index = exception;
726fe045 105 cpu->env.eear = address;
930c3d00 106 cpu->env.lock_addr = -1;
726fe045
JL
107}
108
35e911ae
RH
109bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
110 MMUAccessType access_type, int mmu_idx,
111 bool probe, uintptr_t retaddr)
726fe045 112{
7510454e 113 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
35e911ae
RH
114 int excp = EXCP_DPF;
115
116#ifndef CONFIG_USER_ONLY
117 int prot;
118 hwaddr phys_addr;
119
120 if (mmu_idx == MMU_NOMMU_IDX) {
121 /* The mmu is disabled; lookups never fail. */
122 get_phys_nommu(&phys_addr, &prot, addr);
123 excp = 0;
124 } else {
125 bool super = mmu_idx == MMU_SUPERVISOR_IDX;
126 int need = (access_type == MMU_INST_FETCH ? PAGE_EXEC
127 : access_type == MMU_DATA_STORE ? PAGE_WRITE
128 : PAGE_READ);
129 excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, need, super);
130 }
131
132 if (likely(excp == 0)) {
133 tlb_set_page(cs, addr & TARGET_PAGE_MASK,
134 phys_addr & TARGET_PAGE_MASK, prot,
135 mmu_idx, TARGET_PAGE_SIZE);
136 return true;
137 }
138 if (probe) {
139 return false;
140 }
726fe045 141#endif
35e911ae
RH
142
143 raise_mmu_exception(cpu, addr, excp);
144 cpu_loop_exit_restore(cs, retaddr);
5ce5dad3 145}
726fe045 146
e67db06e 147#ifndef CONFIG_USER_ONLY
00b941e5 148hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
e67db06e 149{
00b941e5 150 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
f0655423 151 int prot, excp, sr = cpu->env.sr;
a8170e5e 152 hwaddr phys_addr;
726fe045 153
f0655423
RH
154 switch (sr & (SR_DME | SR_IME)) {
155 case SR_DME | SR_IME:
156 /* The mmu is definitely enabled. */
157 excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
158 PAGE_EXEC | PAGE_READ | PAGE_WRITE,
159 (sr & SR_SM) != 0);
160 return excp ? -1 : phys_addr;
461a4b94 161
f0655423
RH
162 default:
163 /* The mmu is partially enabled, and we don't really have
164 a "real" access type. Begin by trying the mmu, but if
165 that fails try again without. */
166 excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
167 PAGE_EXEC | PAGE_READ | PAGE_WRITE,
168 (sr & SR_SM) != 0);
169 if (!excp) {
170 return phys_addr;
171 }
172 /* fallthru */
726fe045 173
f0655423
RH
174 case 0:
175 /* The mmu is definitely disabled; lookups never fail. */
176 get_phys_nommu(&phys_addr, &prot, addr);
461a4b94
SH
177 return phys_addr;
178 }
e67db06e 179}
e67db06e 180#endif