Statistics
| Branch: | Revision:

root / target-microblaze / helper.c @ d65f0831

History | View | Annotate | Download (9.5 kB)

1
/*
2
 *  MicroBlaze helper routines.
3
 *
4
 *  Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 */
19

    
20
#include <stdio.h>
21
#include <string.h>
22
#include <assert.h>
23

    
24
#include "config.h"
25
#include "cpu.h"
26
#include "exec-all.h"
27
#include "host-utils.h"
28

    
29
#define D(x)
30
#define DMMU(x)
31

    
32
#if defined(CONFIG_USER_ONLY)
33

    
34
void do_interrupt (CPUState *env)
35
{
36
    env->exception_index = -1;
37
    env->regs[14] = env->sregs[SR_PC];
38
}
39

    
40
int cpu_mb_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
41
                             int mmu_idx, int is_softmmu)
42
{
43
    env->exception_index = 0xaa;
44
    cpu_dump_state(env, stderr, fprintf, 0);
45
    return 1;
46
}
47

    
48
#else /* !CONFIG_USER_ONLY */
49

    
50
int cpu_mb_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
51
                               int mmu_idx, int is_softmmu)
52
{
53
    unsigned int hit;
54
    unsigned int mmu_available;
55
    int r = 1;
56
    int prot;
57

    
58
    mmu_available = 0;
59
    if (env->pvr.regs[0] & PVR0_USE_MMU) {
60
        mmu_available = 1;
61
        if ((env->pvr.regs[0] & PVR0_PVR_FULL_MASK)
62
            && (env->pvr.regs[11] & PVR11_USE_MMU) != PVR11_USE_MMU) {
63
            mmu_available = 0;
64
        }
65
    }
66

    
67
    /* Translate if the MMU is available and enabled.  */
68
    if (mmu_available && (env->sregs[SR_MSR] & MSR_VM)) {
69
        target_ulong vaddr, paddr;
70
        struct microblaze_mmu_lookup lu;
71

    
72
        hit = mmu_translate(&env->mmu, &lu, address, rw, mmu_idx);
73
        if (hit) {
74
            vaddr = address & TARGET_PAGE_MASK;
75
            paddr = lu.paddr + vaddr - lu.vaddr;
76

    
77
            DMMU(qemu_log("MMU map mmu=%d v=%x p=%x prot=%x\n",
78
                     mmu_idx, vaddr, paddr, lu.prot));
79
            tlb_set_page(env, vaddr, paddr, lu.prot, mmu_idx, TARGET_PAGE_SIZE);
80
            r = 0;
81
        } else {
82
            env->sregs[SR_EAR] = address;
83
            DMMU(qemu_log("mmu=%d miss v=%x\n", mmu_idx, address));
84

    
85
            switch (lu.err) {
86
                case ERR_PROT:
87
                    env->sregs[SR_ESR] = rw == 2 ? 17 : 16;
88
                    env->sregs[SR_ESR] |= (rw == 1) << 10;
89
                    break;
90
                case ERR_MISS:
91
                    env->sregs[SR_ESR] = rw == 2 ? 19 : 18;
92
                    env->sregs[SR_ESR] |= (rw == 1) << 10;
93
                    break;
94
                default:
95
                    abort();
96
                    break;
97
            }
98

    
99
            if (env->exception_index == EXCP_MMU) {
100
                cpu_abort(env, "recursive faults\n");
101
            }
102

    
103
            /* TLB miss.  */
104
            env->exception_index = EXCP_MMU;
105
        }
106
    } else {
107
        /* MMU disabled or not available.  */
108
        address &= TARGET_PAGE_MASK;
109
        prot = PAGE_BITS;
110
        tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
111
        r = 0;
112
    }
113
    return r;
114
}
115

    
116
void do_interrupt(CPUState *env)
117
{
118
    uint32_t t;
119

    
120
    /* IMM flag cannot propagate accross a branch and into the dslot.  */
121
    assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG)));
122
    assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)));
123
/*    assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions.  */
124
    switch (env->exception_index) {
125
        case EXCP_HW_EXCP:
126
            if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) {
127
                qemu_log("Exception raised on system without exceptions!\n");
128
                return;
129
            }
130

    
131
            env->regs[17] = env->sregs[SR_PC] + 4;
132
            env->sregs[SR_ESR] &= ~(1 << 12);
133

    
134
            /* Exception breaks branch + dslot sequence?  */
135
            if (env->iflags & D_FLAG) {
136
                env->sregs[SR_ESR] |= 1 << 12 ;
137
                env->sregs[SR_BTR] = env->btarget;
138
            }
139

    
140
            /* Disable the MMU.  */
141
            t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
142
            env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
143
            env->sregs[SR_MSR] |= t;
144
            /* Exception in progress.  */
145
            env->sregs[SR_MSR] |= MSR_EIP;
146

    
147
            qemu_log_mask(CPU_LOG_INT,
148
                          "hw exception at pc=%x ear=%x esr=%x iflags=%x\n",
149
                          env->sregs[SR_PC], env->sregs[SR_EAR],
150
                          env->sregs[SR_ESR], env->iflags);
151
            log_cpu_state_mask(CPU_LOG_INT, env, 0);
152
            env->iflags &= ~(IMM_FLAG | D_FLAG);
153
            env->sregs[SR_PC] = 0x20;
154
            break;
155

    
156
        case EXCP_MMU:
157
            env->regs[17] = env->sregs[SR_PC];
158

    
159
            env->sregs[SR_ESR] &= ~(1 << 12);
160
            /* Exception breaks branch + dslot sequence?  */
161
            if (env->iflags & D_FLAG) {
162
                D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm));
163
                env->sregs[SR_ESR] |= 1 << 12 ;
164
                env->sregs[SR_BTR] = env->btarget;
165

    
166
                /* Reexecute the branch.  */
167
                env->regs[17] -= 4;
168
                /* was the branch immprefixed?.  */
169
                if (env->bimm) {
170
                    qemu_log_mask(CPU_LOG_INT,
171
                                  "bimm exception at pc=%x iflags=%x\n",
172
                                  env->sregs[SR_PC], env->iflags);
173
                    env->regs[17] -= 4;
174
                    log_cpu_state_mask(CPU_LOG_INT, env, 0);
175
                }
176
            } else if (env->iflags & IMM_FLAG) {
177
                D(qemu_log("IMM_FLAG set at exception\n"));
178
                env->regs[17] -= 4;
179
            }
180

    
181
            /* Disable the MMU.  */
182
            t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
183
            env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
184
            env->sregs[SR_MSR] |= t;
185
            /* Exception in progress.  */
186
            env->sregs[SR_MSR] |= MSR_EIP;
187

    
188
            qemu_log_mask(CPU_LOG_INT,
189
                          "exception at pc=%x ear=%x iflags=%x\n",
190
                          env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags);
191
            log_cpu_state_mask(CPU_LOG_INT, env, 0);
192
            env->iflags &= ~(IMM_FLAG | D_FLAG);
193
            env->sregs[SR_PC] = 0x20;
194
            break;
195

    
196
        case EXCP_IRQ:
197
            assert(!(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)));
198
            assert(env->sregs[SR_MSR] & MSR_IE);
199
            assert(!(env->iflags & D_FLAG));
200

    
201
            t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
202

    
203
#if 0
204
#include "disas.h"
205

206
/* Useful instrumentation when debugging interrupt issues in either
207
   the models or in sw.  */
208
            {
209
                const char *sym;
210

211
                sym = lookup_symbol(env->sregs[SR_PC]);
212
                if (sym
213
                    && (!strcmp("netif_rx", sym)
214
                        || !strcmp("process_backlog", sym))) {
215

216
                    qemu_log(
217
                         "interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n",
218
                         env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags,
219
                         sym);
220

221
                    log_cpu_state(env, 0);
222
                }
223
            }
224
#endif
225
            qemu_log_mask(CPU_LOG_INT,
226
                         "interrupt at pc=%x msr=%x %x iflags=%x\n",
227
                         env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
228

    
229
            env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \
230
                                    | MSR_UM | MSR_IE);
231
            env->sregs[SR_MSR] |= t;
232

    
233
            env->regs[14] = env->sregs[SR_PC];
234
            env->sregs[SR_PC] = 0x10;
235
            //log_cpu_state_mask(CPU_LOG_INT, env, 0);
236
            break;
237

    
238
        case EXCP_BREAK:
239
        case EXCP_HW_BREAK:
240
            assert(!(env->iflags & IMM_FLAG));
241
            assert(!(env->iflags & D_FLAG));
242
            t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
243
            qemu_log_mask(CPU_LOG_INT,
244
                        "break at pc=%x msr=%x %x iflags=%x\n",
245
                        env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
246
            log_cpu_state_mask(CPU_LOG_INT, env, 0);
247
            env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
248
            env->sregs[SR_MSR] |= t;
249
            env->sregs[SR_MSR] |= MSR_BIP;
250
            if (env->exception_index == EXCP_HW_BREAK) {
251
                env->regs[16] = env->sregs[SR_PC];
252
                env->sregs[SR_MSR] |= MSR_BIP;
253
                env->sregs[SR_PC] = 0x18;
254
            } else
255
                env->sregs[SR_PC] = env->btarget;
256
            break;
257
        default:
258
            cpu_abort(env, "unhandled exception type=%d\n",
259
                      env->exception_index);
260
            break;
261
    }
262
}
263

    
264
target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
265
{
266
    target_ulong vaddr, paddr = 0;
267
    struct microblaze_mmu_lookup lu;
268
    unsigned int hit;
269

    
270
    if (env->sregs[SR_MSR] & MSR_VM) {
271
        hit = mmu_translate(&env->mmu, &lu, addr, 0, 0);
272
        if (hit) {
273
            vaddr = addr & TARGET_PAGE_MASK;
274
            paddr = lu.paddr + vaddr - lu.vaddr;
275
        } else
276
            paddr = 0; /* ???.  */
277
    } else
278
        paddr = addr & TARGET_PAGE_MASK;
279

    
280
    return paddr;
281
}
282
#endif