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/>.
22 #include "qemu-common.h"
23 #include "exec/gdbstub.h"
24 #include "qemu/host-utils.h"
25 #ifndef CONFIG_USER_ONLY
26 #include "hw/loader.h"
29 #ifndef CONFIG_USER_ONLY
30 int cpu_openrisc_get_phys_nommu(OpenRISCCPU
*cpu
,
32 int *prot
, target_ulong address
, int rw
)
35 *prot
= PAGE_READ
| PAGE_WRITE
;
39 int cpu_openrisc_get_phys_code(OpenRISCCPU
*cpu
,
41 int *prot
, target_ulong address
, int rw
)
43 int vpn
= address
>> TARGET_PAGE_BITS
;
44 int idx
= vpn
& ITLB_MASK
;
47 if ((cpu
->env
.tlb
->itlb
[0][idx
].mr
>> TARGET_PAGE_BITS
) != vpn
) {
48 return TLBRET_NOMATCH
;
50 if (!(cpu
->env
.tlb
->itlb
[0][idx
].mr
& 1)) {
51 return TLBRET_INVALID
;
54 if (cpu
->env
.sr
& SR_SM
) { /* supervisor mode */
55 if (cpu
->env
.tlb
->itlb
[0][idx
].tr
& SXE
) {
59 if (cpu
->env
.tlb
->itlb
[0][idx
].tr
& UXE
) {
64 if ((rw
& 2) && ((right
& PAGE_EXEC
) == 0)) {
65 return TLBRET_BADADDR
;
68 *physical
= (cpu
->env
.tlb
->itlb
[0][idx
].tr
& TARGET_PAGE_MASK
) |
69 (address
& (TARGET_PAGE_SIZE
-1));
74 int cpu_openrisc_get_phys_data(OpenRISCCPU
*cpu
,
76 int *prot
, target_ulong address
, int rw
)
78 int vpn
= address
>> TARGET_PAGE_BITS
;
79 int idx
= vpn
& DTLB_MASK
;
82 if ((cpu
->env
.tlb
->dtlb
[0][idx
].mr
>> TARGET_PAGE_BITS
) != vpn
) {
83 return TLBRET_NOMATCH
;
85 if (!(cpu
->env
.tlb
->dtlb
[0][idx
].mr
& 1)) {
86 return TLBRET_INVALID
;
89 if (cpu
->env
.sr
& SR_SM
) { /* supervisor mode */
90 if (cpu
->env
.tlb
->dtlb
[0][idx
].tr
& SRE
) {
93 if (cpu
->env
.tlb
->dtlb
[0][idx
].tr
& SWE
) {
97 if (cpu
->env
.tlb
->dtlb
[0][idx
].tr
& URE
) {
100 if (cpu
->env
.tlb
->dtlb
[0][idx
].tr
& UWE
) {
105 if ((rw
& 0) && ((right
& PAGE_READ
) == 0)) {
106 return TLBRET_BADADDR
;
108 if ((rw
& 1) && ((right
& PAGE_WRITE
) == 0)) {
109 return TLBRET_BADADDR
;
112 *physical
= (cpu
->env
.tlb
->dtlb
[0][idx
].tr
& TARGET_PAGE_MASK
) |
113 (address
& (TARGET_PAGE_SIZE
-1));
118 static int cpu_openrisc_get_phys_addr(OpenRISCCPU
*cpu
,
120 int *prot
, target_ulong address
,
123 int ret
= TLBRET_MATCH
;
125 /* [0x0000--0x2000]: unmapped */
126 if (address
< 0x2000 && (cpu
->env
.sr
& SR_SM
)) {
128 *prot
= PAGE_READ
| PAGE_WRITE
;
132 if (rw
== 2) { /* ITLB */
134 ret
= cpu
->env
.tlb
->cpu_openrisc_map_address_code(cpu
, physical
,
137 ret
= cpu
->env
.tlb
->cpu_openrisc_map_address_data(cpu
, physical
,
145 static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU
*cpu
,
146 target_ulong address
,
147 int rw
, int tlb_error
)
154 exception
= EXCP_IPF
;
156 exception
= EXCP_DPF
;
159 #ifndef CONFIG_USER_ONLY
162 exception
= EXCP_IPF
;
164 exception
= EXCP_DPF
;
169 /* No TLB match for a mapped address */
171 exception
= EXCP_ITLBMISS
;
173 exception
= EXCP_DTLBMISS
;
179 cpu
->env
.exception_index
= exception
;
180 cpu
->env
.eear
= address
;
183 #ifndef CONFIG_USER_ONLY
184 int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState
*env
,
185 target_ulong address
, int rw
, int mmu_idx
)
190 OpenRISCCPU
*cpu
= openrisc_env_get_cpu(env
);
192 ret
= cpu_openrisc_get_phys_addr(cpu
, &physical
, &prot
,
195 if (ret
== TLBRET_MATCH
) {
196 tlb_set_page(env
, address
& TARGET_PAGE_MASK
,
197 physical
& TARGET_PAGE_MASK
, prot
| PAGE_EXEC
,
198 mmu_idx
, TARGET_PAGE_SIZE
);
200 } else if (ret
< 0) {
201 cpu_openrisc_raise_mmu_exception(cpu
, address
, rw
, ret
);
208 int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState
*env
,
209 target_ulong address
, int rw
, int mmu_idx
)
212 OpenRISCCPU
*cpu
= openrisc_env_get_cpu(env
);
214 cpu_openrisc_raise_mmu_exception(cpu
, address
, rw
, ret
);
221 #ifndef CONFIG_USER_ONLY
222 hwaddr
openrisc_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
224 OpenRISCCPU
*cpu
= OPENRISC_CPU(cs
);
228 if (cpu_openrisc_get_phys_addr(cpu
, &phys_addr
, &prot
, addr
, 0)) {
235 void cpu_openrisc_mmu_init(OpenRISCCPU
*cpu
)
237 cpu
->env
.tlb
= g_malloc0(sizeof(CPUOpenRISCTLBContext
));
239 cpu
->env
.tlb
->cpu_openrisc_map_address_code
= &cpu_openrisc_get_phys_nommu
;
240 cpu
->env
.tlb
->cpu_openrisc_map_address_data
= &cpu_openrisc_get_phys_nommu
;