Statistics
| Branch: | Revision:

root / target-openrisc / mmu.c @ a8170e5e

History | View | Annotate | Download (6.8 kB)

1 e67db06e Jia Liu
/*
2 e67db06e Jia Liu
 * OpenRISC MMU.
3 e67db06e Jia Liu
 *
4 e67db06e Jia Liu
 * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
5 e67db06e Jia Liu
 *                         Zhizhou Zhang <etouzh@gmail.com>
6 e67db06e Jia Liu
 *
7 e67db06e Jia Liu
 * This library is free software; you can redistribute it and/or
8 e67db06e Jia Liu
 * modify it under the terms of the GNU Lesser General Public
9 e67db06e Jia Liu
 * License as published by the Free Software Foundation; either
10 e67db06e Jia Liu
 * version 2 of the License, or (at your option) any later version.
11 e67db06e Jia Liu
 *
12 e67db06e Jia Liu
 * This library is distributed in the hope that it will be useful,
13 e67db06e Jia Liu
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 e67db06e Jia Liu
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 e67db06e Jia Liu
 * Lesser General Public License for more details.
16 e67db06e Jia Liu
 *
17 e67db06e Jia Liu
 * You should have received a copy of the GNU Lesser General Public
18 e67db06e Jia Liu
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 e67db06e Jia Liu
 */
20 e67db06e Jia Liu
21 e67db06e Jia Liu
#include "cpu.h"
22 e67db06e Jia Liu
#include "qemu-common.h"
23 e67db06e Jia Liu
#include "gdbstub.h"
24 e67db06e Jia Liu
#include "host-utils.h"
25 e67db06e Jia Liu
#ifndef CONFIG_USER_ONLY
26 e67db06e Jia Liu
#include "hw/loader.h"
27 e67db06e Jia Liu
#endif
28 e67db06e Jia Liu
29 e67db06e Jia Liu
#ifndef CONFIG_USER_ONLY
30 726fe045 Jia Liu
int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu,
31 a8170e5e Avi Kivity
                                hwaddr *physical,
32 726fe045 Jia Liu
                                int *prot, target_ulong address, int rw)
33 726fe045 Jia Liu
{
34 726fe045 Jia Liu
    *physical = address;
35 726fe045 Jia Liu
    *prot = PAGE_READ | PAGE_WRITE;
36 726fe045 Jia Liu
    return TLBRET_MATCH;
37 726fe045 Jia Liu
}
38 726fe045 Jia Liu
39 726fe045 Jia Liu
int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu,
40 a8170e5e Avi Kivity
                               hwaddr *physical,
41 726fe045 Jia Liu
                               int *prot, target_ulong address, int rw)
42 726fe045 Jia Liu
{
43 726fe045 Jia Liu
    int vpn = address >> TARGET_PAGE_BITS;
44 726fe045 Jia Liu
    int idx = vpn & ITLB_MASK;
45 726fe045 Jia Liu
    int right = 0;
46 726fe045 Jia Liu
47 726fe045 Jia Liu
    if ((cpu->env.tlb->itlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
48 726fe045 Jia Liu
        return TLBRET_NOMATCH;
49 726fe045 Jia Liu
    }
50 726fe045 Jia Liu
    if (!(cpu->env.tlb->itlb[0][idx].mr & 1)) {
51 726fe045 Jia Liu
        return TLBRET_INVALID;
52 726fe045 Jia Liu
    }
53 726fe045 Jia Liu
54 726fe045 Jia Liu
    if (cpu->env.sr & SR_SM) { /* supervisor mode */
55 726fe045 Jia Liu
        if (cpu->env.tlb->itlb[0][idx].tr & SXE) {
56 726fe045 Jia Liu
            right |= PAGE_EXEC;
57 726fe045 Jia Liu
        }
58 726fe045 Jia Liu
    } else {
59 726fe045 Jia Liu
        if (cpu->env.tlb->itlb[0][idx].tr & UXE) {
60 726fe045 Jia Liu
            right |= PAGE_EXEC;
61 726fe045 Jia Liu
        }
62 726fe045 Jia Liu
    }
63 726fe045 Jia Liu
64 726fe045 Jia Liu
    if ((rw & 2) && ((right & PAGE_EXEC) == 0)) {
65 726fe045 Jia Liu
        return TLBRET_BADADDR;
66 726fe045 Jia Liu
    }
67 726fe045 Jia Liu
68 726fe045 Jia Liu
    *physical = (cpu->env.tlb->itlb[0][idx].tr & TARGET_PAGE_MASK) |
69 726fe045 Jia Liu
                (address & (TARGET_PAGE_SIZE-1));
70 726fe045 Jia Liu
    *prot = right;
71 726fe045 Jia Liu
    return TLBRET_MATCH;
72 726fe045 Jia Liu
}
73 726fe045 Jia Liu
74 726fe045 Jia Liu
int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
75 a8170e5e Avi Kivity
                               hwaddr *physical,
76 726fe045 Jia Liu
                               int *prot, target_ulong address, int rw)
77 726fe045 Jia Liu
{
78 726fe045 Jia Liu
    int vpn = address >> TARGET_PAGE_BITS;
79 726fe045 Jia Liu
    int idx = vpn & DTLB_MASK;
80 726fe045 Jia Liu
    int right = 0;
81 726fe045 Jia Liu
82 726fe045 Jia Liu
    if ((cpu->env.tlb->dtlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
83 726fe045 Jia Liu
        return TLBRET_NOMATCH;
84 726fe045 Jia Liu
    }
85 726fe045 Jia Liu
    if (!(cpu->env.tlb->dtlb[0][idx].mr & 1)) {
86 726fe045 Jia Liu
        return TLBRET_INVALID;
87 726fe045 Jia Liu
    }
88 726fe045 Jia Liu
89 726fe045 Jia Liu
    if (cpu->env.sr & SR_SM) { /* supervisor mode */
90 726fe045 Jia Liu
        if (cpu->env.tlb->dtlb[0][idx].tr & SRE) {
91 726fe045 Jia Liu
            right |= PAGE_READ;
92 726fe045 Jia Liu
        }
93 726fe045 Jia Liu
        if (cpu->env.tlb->dtlb[0][idx].tr & SWE) {
94 726fe045 Jia Liu
            right |= PAGE_WRITE;
95 726fe045 Jia Liu
        }
96 726fe045 Jia Liu
    } else {
97 726fe045 Jia Liu
        if (cpu->env.tlb->dtlb[0][idx].tr & URE) {
98 726fe045 Jia Liu
            right |= PAGE_READ;
99 726fe045 Jia Liu
        }
100 726fe045 Jia Liu
        if (cpu->env.tlb->dtlb[0][idx].tr & UWE) {
101 726fe045 Jia Liu
            right |= PAGE_WRITE;
102 726fe045 Jia Liu
        }
103 726fe045 Jia Liu
    }
104 726fe045 Jia Liu
105 726fe045 Jia Liu
    if ((rw & 0) && ((right & PAGE_READ) == 0)) {
106 726fe045 Jia Liu
        return TLBRET_BADADDR;
107 726fe045 Jia Liu
    }
108 726fe045 Jia Liu
    if ((rw & 1) && ((right & PAGE_WRITE) == 0)) {
109 726fe045 Jia Liu
        return TLBRET_BADADDR;
110 726fe045 Jia Liu
    }
111 726fe045 Jia Liu
112 726fe045 Jia Liu
    *physical = (cpu->env.tlb->dtlb[0][idx].tr & TARGET_PAGE_MASK) |
113 726fe045 Jia Liu
                (address & (TARGET_PAGE_SIZE-1));
114 726fe045 Jia Liu
    *prot = right;
115 726fe045 Jia Liu
    return TLBRET_MATCH;
116 726fe045 Jia Liu
}
117 726fe045 Jia Liu
118 726fe045 Jia Liu
static int cpu_openrisc_get_phys_addr(OpenRISCCPU *cpu,
119 a8170e5e Avi Kivity
                                      hwaddr *physical,
120 726fe045 Jia Liu
                                      int *prot, target_ulong address,
121 726fe045 Jia Liu
                                      int rw)
122 726fe045 Jia Liu
{
123 726fe045 Jia Liu
    int ret = TLBRET_MATCH;
124 726fe045 Jia Liu
125 726fe045 Jia Liu
    /* [0x0000--0x2000]: unmapped */
126 726fe045 Jia Liu
    if (address < 0x2000 && (cpu->env.sr & SR_SM)) {
127 726fe045 Jia Liu
        *physical = address;
128 726fe045 Jia Liu
        *prot = PAGE_READ | PAGE_WRITE;
129 726fe045 Jia Liu
        return ret;
130 726fe045 Jia Liu
    }
131 726fe045 Jia Liu
132 726fe045 Jia Liu
    if (rw == 2) {    /* ITLB */
133 726fe045 Jia Liu
       *physical = 0;
134 726fe045 Jia Liu
        ret = cpu->env.tlb->cpu_openrisc_map_address_code(cpu, physical,
135 726fe045 Jia Liu
                                                          prot, address, rw);
136 726fe045 Jia Liu
    } else {          /* DTLB */
137 726fe045 Jia Liu
        ret = cpu->env.tlb->cpu_openrisc_map_address_data(cpu, physical,
138 726fe045 Jia Liu
                                                          prot, address, rw);
139 726fe045 Jia Liu
    }
140 726fe045 Jia Liu
141 726fe045 Jia Liu
    return ret;
142 726fe045 Jia Liu
}
143 726fe045 Jia Liu
#endif
144 726fe045 Jia Liu
145 726fe045 Jia Liu
static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU *cpu,
146 726fe045 Jia Liu
                                             target_ulong address,
147 726fe045 Jia Liu
                                             int rw, int tlb_error)
148 726fe045 Jia Liu
{
149 726fe045 Jia Liu
    int exception = 0;
150 726fe045 Jia Liu
151 726fe045 Jia Liu
    switch (tlb_error) {
152 726fe045 Jia Liu
    default:
153 726fe045 Jia Liu
        if (rw == 2) {
154 726fe045 Jia Liu
            exception = EXCP_IPF;
155 726fe045 Jia Liu
        } else {
156 726fe045 Jia Liu
            exception = EXCP_DPF;
157 726fe045 Jia Liu
        }
158 726fe045 Jia Liu
        break;
159 726fe045 Jia Liu
#ifndef CONFIG_USER_ONLY
160 726fe045 Jia Liu
    case TLBRET_BADADDR:
161 726fe045 Jia Liu
        if (rw == 2) {
162 726fe045 Jia Liu
            exception = EXCP_IPF;
163 726fe045 Jia Liu
        } else {
164 726fe045 Jia Liu
            exception = EXCP_DPF;
165 726fe045 Jia Liu
        }
166 726fe045 Jia Liu
        break;
167 726fe045 Jia Liu
    case TLBRET_INVALID:
168 726fe045 Jia Liu
    case TLBRET_NOMATCH:
169 726fe045 Jia Liu
        /* No TLB match for a mapped address */
170 726fe045 Jia Liu
        if (rw == 2) {
171 726fe045 Jia Liu
            exception = EXCP_ITLBMISS;
172 726fe045 Jia Liu
        } else {
173 726fe045 Jia Liu
            exception = EXCP_DTLBMISS;
174 726fe045 Jia Liu
        }
175 726fe045 Jia Liu
        break;
176 726fe045 Jia Liu
#endif
177 726fe045 Jia Liu
    }
178 726fe045 Jia Liu
179 726fe045 Jia Liu
    cpu->env.exception_index = exception;
180 726fe045 Jia Liu
    cpu->env.eear = address;
181 726fe045 Jia Liu
}
182 726fe045 Jia Liu
183 726fe045 Jia Liu
#ifndef CONFIG_USER_ONLY
184 726fe045 Jia Liu
int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
185 726fe045 Jia Liu
                                  target_ulong address, int rw, int mmu_idx)
186 726fe045 Jia Liu
{
187 726fe045 Jia Liu
    int ret = 0;
188 a8170e5e Avi Kivity
    hwaddr physical = 0;
189 726fe045 Jia Liu
    int prot = 0;
190 726fe045 Jia Liu
    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
191 726fe045 Jia Liu
192 726fe045 Jia Liu
    ret = cpu_openrisc_get_phys_addr(cpu, &physical, &prot,
193 726fe045 Jia Liu
                                     address, rw);
194 726fe045 Jia Liu
195 726fe045 Jia Liu
    if (ret == TLBRET_MATCH) {
196 726fe045 Jia Liu
        tlb_set_page(env, address & TARGET_PAGE_MASK,
197 726fe045 Jia Liu
                     physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
198 726fe045 Jia Liu
                     mmu_idx, TARGET_PAGE_SIZE);
199 726fe045 Jia Liu
        ret = 0;
200 726fe045 Jia Liu
    } else if (ret < 0) {
201 726fe045 Jia Liu
        cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
202 726fe045 Jia Liu
        ret = 1;
203 726fe045 Jia Liu
    }
204 726fe045 Jia Liu
205 726fe045 Jia Liu
    return ret;
206 726fe045 Jia Liu
}
207 726fe045 Jia Liu
#else
208 726fe045 Jia Liu
int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
209 726fe045 Jia Liu
                                  target_ulong address, int rw, int mmu_idx)
210 726fe045 Jia Liu
{
211 726fe045 Jia Liu
    int ret = 0;
212 726fe045 Jia Liu
    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
213 726fe045 Jia Liu
214 726fe045 Jia Liu
    cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
215 726fe045 Jia Liu
    ret = 1;
216 726fe045 Jia Liu
217 726fe045 Jia Liu
    return ret;
218 726fe045 Jia Liu
}
219 726fe045 Jia Liu
#endif
220 726fe045 Jia Liu
221 726fe045 Jia Liu
#ifndef CONFIG_USER_ONLY
222 a8170e5e Avi Kivity
hwaddr cpu_get_phys_page_debug(CPUOpenRISCState *env,
223 e67db06e Jia Liu
                                           target_ulong addr)
224 e67db06e Jia Liu
{
225 a8170e5e Avi Kivity
    hwaddr phys_addr;
226 726fe045 Jia Liu
    int prot;
227 726fe045 Jia Liu
    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
228 726fe045 Jia Liu
229 726fe045 Jia Liu
    if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) {
230 726fe045 Jia Liu
        return -1;
231 726fe045 Jia Liu
    }
232 726fe045 Jia Liu
233 726fe045 Jia Liu
    return phys_addr;
234 e67db06e Jia Liu
}
235 e67db06e Jia Liu
236 e67db06e Jia Liu
void cpu_openrisc_mmu_init(OpenRISCCPU *cpu)
237 e67db06e Jia Liu
{
238 726fe045 Jia Liu
    cpu->env.tlb = g_malloc0(sizeof(CPUOpenRISCTLBContext));
239 726fe045 Jia Liu
240 726fe045 Jia Liu
    cpu->env.tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
241 726fe045 Jia Liu
    cpu->env.tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;
242 e67db06e Jia Liu
}
243 e67db06e Jia Liu
#endif