Statistics
| Branch: | Revision:

root / target-openrisc / mmu.c @ 1de7afc9

History | View | Annotate | Download (6.8 kB)

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
10
 * version 2 of the License, or (at your option) any later version.
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

    
21
#include "cpu.h"
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"
27
#endif
28

    
29
#ifndef CONFIG_USER_ONLY
30
int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu,
31
                                hwaddr *physical,
32
                                int *prot, target_ulong address, int rw)
33
{
34
    *physical = address;
35
    *prot = PAGE_READ | PAGE_WRITE;
36
    return TLBRET_MATCH;
37
}
38

    
39
int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu,
40
                               hwaddr *physical,
41
                               int *prot, target_ulong address, int rw)
42
{
43
    int vpn = address >> TARGET_PAGE_BITS;
44
    int idx = vpn & ITLB_MASK;
45
    int right = 0;
46

    
47
    if ((cpu->env.tlb->itlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
48
        return TLBRET_NOMATCH;
49
    }
50
    if (!(cpu->env.tlb->itlb[0][idx].mr & 1)) {
51
        return TLBRET_INVALID;
52
    }
53

    
54
    if (cpu->env.sr & SR_SM) { /* supervisor mode */
55
        if (cpu->env.tlb->itlb[0][idx].tr & SXE) {
56
            right |= PAGE_EXEC;
57
        }
58
    } else {
59
        if (cpu->env.tlb->itlb[0][idx].tr & UXE) {
60
            right |= PAGE_EXEC;
61
        }
62
    }
63

    
64
    if ((rw & 2) && ((right & PAGE_EXEC) == 0)) {
65
        return TLBRET_BADADDR;
66
    }
67

    
68
    *physical = (cpu->env.tlb->itlb[0][idx].tr & TARGET_PAGE_MASK) |
69
                (address & (TARGET_PAGE_SIZE-1));
70
    *prot = right;
71
    return TLBRET_MATCH;
72
}
73

    
74
int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
75
                               hwaddr *physical,
76
                               int *prot, target_ulong address, int rw)
77
{
78
    int vpn = address >> TARGET_PAGE_BITS;
79
    int idx = vpn & DTLB_MASK;
80
    int right = 0;
81

    
82
    if ((cpu->env.tlb->dtlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
83
        return TLBRET_NOMATCH;
84
    }
85
    if (!(cpu->env.tlb->dtlb[0][idx].mr & 1)) {
86
        return TLBRET_INVALID;
87
    }
88

    
89
    if (cpu->env.sr & SR_SM) { /* supervisor mode */
90
        if (cpu->env.tlb->dtlb[0][idx].tr & SRE) {
91
            right |= PAGE_READ;
92
        }
93
        if (cpu->env.tlb->dtlb[0][idx].tr & SWE) {
94
            right |= PAGE_WRITE;
95
        }
96
    } else {
97
        if (cpu->env.tlb->dtlb[0][idx].tr & URE) {
98
            right |= PAGE_READ;
99
        }
100
        if (cpu->env.tlb->dtlb[0][idx].tr & UWE) {
101
            right |= PAGE_WRITE;
102
        }
103
    }
104

    
105
    if ((rw & 0) && ((right & PAGE_READ) == 0)) {
106
        return TLBRET_BADADDR;
107
    }
108
    if ((rw & 1) && ((right & PAGE_WRITE) == 0)) {
109
        return TLBRET_BADADDR;
110
    }
111

    
112
    *physical = (cpu->env.tlb->dtlb[0][idx].tr & TARGET_PAGE_MASK) |
113
                (address & (TARGET_PAGE_SIZE-1));
114
    *prot = right;
115
    return TLBRET_MATCH;
116
}
117

    
118
static int cpu_openrisc_get_phys_addr(OpenRISCCPU *cpu,
119
                                      hwaddr *physical,
120
                                      int *prot, target_ulong address,
121
                                      int rw)
122
{
123
    int ret = TLBRET_MATCH;
124

    
125
    /* [0x0000--0x2000]: unmapped */
126
    if (address < 0x2000 && (cpu->env.sr & SR_SM)) {
127
        *physical = address;
128
        *prot = PAGE_READ | PAGE_WRITE;
129
        return ret;
130
    }
131

    
132
    if (rw == 2) {    /* ITLB */
133
       *physical = 0;
134
        ret = cpu->env.tlb->cpu_openrisc_map_address_code(cpu, physical,
135
                                                          prot, address, rw);
136
    } else {          /* DTLB */
137
        ret = cpu->env.tlb->cpu_openrisc_map_address_data(cpu, physical,
138
                                                          prot, address, rw);
139
    }
140

    
141
    return ret;
142
}
143
#endif
144

    
145
static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU *cpu,
146
                                             target_ulong address,
147
                                             int rw, int tlb_error)
148
{
149
    int exception = 0;
150

    
151
    switch (tlb_error) {
152
    default:
153
        if (rw == 2) {
154
            exception = EXCP_IPF;
155
        } else {
156
            exception = EXCP_DPF;
157
        }
158
        break;
159
#ifndef CONFIG_USER_ONLY
160
    case TLBRET_BADADDR:
161
        if (rw == 2) {
162
            exception = EXCP_IPF;
163
        } else {
164
            exception = EXCP_DPF;
165
        }
166
        break;
167
    case TLBRET_INVALID:
168
    case TLBRET_NOMATCH:
169
        /* No TLB match for a mapped address */
170
        if (rw == 2) {
171
            exception = EXCP_ITLBMISS;
172
        } else {
173
            exception = EXCP_DTLBMISS;
174
        }
175
        break;
176
#endif
177
    }
178

    
179
    cpu->env.exception_index = exception;
180
    cpu->env.eear = address;
181
}
182

    
183
#ifndef CONFIG_USER_ONLY
184
int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
185
                                  target_ulong address, int rw, int mmu_idx)
186
{
187
    int ret = 0;
188
    hwaddr physical = 0;
189
    int prot = 0;
190
    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
191

    
192
    ret = cpu_openrisc_get_phys_addr(cpu, &physical, &prot,
193
                                     address, rw);
194

    
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);
199
        ret = 0;
200
    } else if (ret < 0) {
201
        cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
202
        ret = 1;
203
    }
204

    
205
    return ret;
206
}
207
#else
208
int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
209
                                  target_ulong address, int rw, int mmu_idx)
210
{
211
    int ret = 0;
212
    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
213

    
214
    cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
215
    ret = 1;
216

    
217
    return ret;
218
}
219
#endif
220

    
221
#ifndef CONFIG_USER_ONLY
222
hwaddr cpu_get_phys_page_debug(CPUOpenRISCState *env,
223
                                           target_ulong addr)
224
{
225
    hwaddr phys_addr;
226
    int prot;
227
    OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
228

    
229
    if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) {
230
        return -1;
231
    }
232

    
233
    return phys_addr;
234
}
235

    
236
void cpu_openrisc_mmu_init(OpenRISCCPU *cpu)
237
{
238
    cpu->env.tlb = g_malloc0(sizeof(CPUOpenRISCTLBContext));
239

    
240
    cpu->env.tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
241
    cpu->env.tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;
242
}
243
#endif