4 * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
5 * Zhizhou Zhang <etouzh@gmail.com>
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
10 * version 2 of the License, or (at your option) any later version.
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.
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/>.
21 #include "qemu/osdep.h"
23 #include "exec/exec-all.h"
24 #include "qemu-common.h"
25 #include "exec/gdbstub.h"
26 #include "qemu/host-utils.h"
27 #ifndef CONFIG_USER_ONLY
28 #include "hw/loader.h"
31 #ifndef CONFIG_USER_ONLY
32 static inline int get_phys_nommu(hwaddr
*physical
, int *prot
,
36 *prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
40 static int get_phys_code(OpenRISCCPU
*cpu
, hwaddr
*physical
, int *prot
,
41 target_ulong address
, int rw
, bool supervisor
)
43 int vpn
= address
>> TARGET_PAGE_BITS
;
44 int idx
= vpn
& ITLB_MASK
;
46 uint32_t mr
= cpu
->env
.tlb
.itlb
[idx
].mr
;
47 uint32_t tr
= cpu
->env
.tlb
.itlb
[idx
].tr
;
49 if ((mr
>> TARGET_PAGE_BITS
) != vpn
) {
50 return TLBRET_NOMATCH
;
53 return TLBRET_INVALID
;
64 if ((rw
& 2) && ((right
& PAGE_EXEC
) == 0)) {
65 return TLBRET_BADADDR
;
68 *physical
= (tr
& TARGET_PAGE_MASK
) | (address
& ~TARGET_PAGE_MASK
);
73 static int get_phys_data(OpenRISCCPU
*cpu
, hwaddr
*physical
, int *prot
,
74 target_ulong address
, int rw
, bool supervisor
)
76 int vpn
= address
>> TARGET_PAGE_BITS
;
77 int idx
= vpn
& DTLB_MASK
;
79 uint32_t mr
= cpu
->env
.tlb
.dtlb
[idx
].mr
;
80 uint32_t tr
= cpu
->env
.tlb
.dtlb
[idx
].tr
;
82 if ((mr
>> TARGET_PAGE_BITS
) != vpn
) {
83 return TLBRET_NOMATCH
;
86 return TLBRET_INVALID
;
104 if (!(rw
& 1) && ((right
& PAGE_READ
) == 0)) {
105 return TLBRET_BADADDR
;
107 if ((rw
& 1) && ((right
& PAGE_WRITE
) == 0)) {
108 return TLBRET_BADADDR
;
111 *physical
= (tr
& TARGET_PAGE_MASK
) | (address
& ~TARGET_PAGE_MASK
);
116 static int get_phys_addr(OpenRISCCPU
*cpu
, hwaddr
*physical
,
117 int *prot
, target_ulong address
, int rw
)
119 bool supervisor
= (cpu
->env
.sr
& SR_SM
) != 0;
122 /* Assume nommu results for a moment. */
123 ret
= get_phys_nommu(physical
, prot
, address
);
125 /* Overwrite with TLB lookup if enabled. */
126 if (rw
== MMU_INST_FETCH
) {
127 if (cpu
->env
.sr
& SR_IME
) {
128 ret
= get_phys_code(cpu
, physical
, prot
, address
, rw
, supervisor
);
131 if (cpu
->env
.sr
& SR_DME
) {
132 ret
= get_phys_data(cpu
, physical
, prot
, address
, rw
, supervisor
);
140 static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU
*cpu
,
141 target_ulong address
,
142 int rw
, int tlb_error
)
144 CPUState
*cs
= CPU(cpu
);
150 exception
= EXCP_IPF
;
152 exception
= EXCP_DPF
;
155 #ifndef CONFIG_USER_ONLY
158 exception
= EXCP_IPF
;
160 exception
= EXCP_DPF
;
165 /* No TLB match for a mapped address */
167 exception
= EXCP_ITLBMISS
;
169 exception
= EXCP_DTLBMISS
;
175 cs
->exception_index
= exception
;
176 cpu
->env
.eear
= address
;
177 cpu
->env
.lock_addr
= -1;
180 #ifndef CONFIG_USER_ONLY
181 int openrisc_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int size
,
184 OpenRISCCPU
*cpu
= OPENRISC_CPU(cs
);
189 ret
= get_phys_addr(cpu
, &physical
, &prot
, address
, rw
);
191 if (ret
== TLBRET_MATCH
) {
192 tlb_set_page(cs
, address
& TARGET_PAGE_MASK
,
193 physical
& TARGET_PAGE_MASK
, prot
,
194 mmu_idx
, TARGET_PAGE_SIZE
);
196 } else if (ret
< 0) {
197 cpu_openrisc_raise_mmu_exception(cpu
, address
, rw
, ret
);
204 int openrisc_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
, int size
,
207 OpenRISCCPU
*cpu
= OPENRISC_CPU(cs
);
210 cpu_openrisc_raise_mmu_exception(cpu
, address
, rw
, ret
);
217 #ifndef CONFIG_USER_ONLY
218 hwaddr
openrisc_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
220 OpenRISCCPU
*cpu
= OPENRISC_CPU(cs
);
225 /* Check memory for any kind of address, since during debug the
226 gdb can ask for anything, check data tlb for address */
227 miss
= get_phys_addr(cpu
, &phys_addr
, &prot
, addr
, 0);
229 /* Check instruction tlb */
231 miss
= get_phys_addr(cpu
, &phys_addr
, &prot
, addr
, MMU_INST_FETCH
);
234 /* Last, fall back to a plain address */
236 miss
= get_phys_nommu(&phys_addr
, &prot
, addr
);
246 void tlb_fill(CPUState
*cs
, target_ulong addr
, int size
,
247 MMUAccessType access_type
, int mmu_idx
, uintptr_t retaddr
)
249 int ret
= openrisc_cpu_handle_mmu_fault(cs
, addr
, size
,
250 access_type
, mmu_idx
);
252 /* Raise Exception. */
253 cpu_loop_exit_restore(cs
, retaddr
);