Revision 43057ab1 target-mips/helper.c

b/target-mips/helper.c
28 28
#include "cpu.h"
29 29
#include "exec-all.h"
30 30

  
31
enum {
32
    TLBRET_DIRTY = -4,
33
    TLBRET_INVALID = -3,
34
    TLBRET_NOMATCH = -2,
35
    TLBRET_BADADDR = -1,
36
    TLBRET_MATCH = 0
37
};
38

  
31 39
/* MIPS32 4K MMU emulation */
32 40
#ifdef MIPS_USES_R4K_TLB
33 41
static int map_address (CPUState *env, target_ulong *physical, int *prot,
34 42
                        target_ulong address, int rw, int access_type)
35 43
{
44
    target_ulong tag = address & (TARGET_PAGE_MASK << 1);
45
    uint8_t ASID = env->CP0_EntryHi & 0xFF;
36 46
    tlb_t *tlb;
37
    target_ulong tag;
38
    uint8_t ASID;
39 47
    int i, n;
40
    int ret;
41 48

  
42
    ret = -2;
43
    tag = address & 0xFFFFE000;
44
    ASID = env->CP0_EntryHi & 0xFF;
45 49
    for (i = 0; i < MIPS_TLB_NB; i++) {
46 50
        tlb = &env->tlb[i];
47 51
        /* Check ASID, virtual page number & size */
48 52
        if ((tlb->G == 1 || tlb->ASID == ASID) &&
49 53
            tlb->VPN == tag && address < tlb->end2) {
50 54
            /* TLB match */
51
            n = (address >> 12) & 1;
55
            n = (address >> TARGET_PAGE_BITS) & 1;
52 56
            /* Check access rights */
53
	    if (!(n ? tlb->V1 : tlb->V0))
54
                return -3;
55
	    if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
56
                *physical = tlb->PFN[n] | (address & 0xFFF);
57
           if (!(n ? tlb->V1 : tlb->V0))
58
                return TLBRET_INVALID;
59
           if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
60
                *physical = tlb->PFN[n] | (address & ~TARGET_PAGE_MASK);
57 61
                *prot = PAGE_READ;
58 62
                if (n ? tlb->D1 : tlb->D0)
59 63
                    *prot |= PAGE_WRITE;
60
                return 0;
64
                return TLBRET_MATCH;
61 65
            }
62
            return -4;
66
            return TLBRET_DIRTY;
63 67
        }
64 68
    }
65

  
66
    return ret;
69
    return TLBRET_NOMATCH;
67 70
}
68 71
#endif
69 72

  
70
int get_physical_address (CPUState *env, target_ulong *physical, int *prot,
71
                          target_ulong address, int rw, int access_type)
73
static int get_physical_address (CPUState *env, target_ulong *physical,
74
                                int *prot, target_ulong address,
75
                                int rw, int access_type)
72 76
{
73
    int user_mode;
74
    int ret;
75

  
76 77
    /* User mode can only access useg */
77
    user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
78
    int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
79
    int ret = TLBRET_MATCH;
80

  
78 81
#if 0
79 82
    if (logfile) {
80 83
        fprintf(logfile, "user mode %d h %08x\n",
......
82 85
    }
83 86
#endif
84 87
    if (user_mode && address > 0x7FFFFFFFUL)
85
        return -1;
86
    ret = 0;
88
        return TLBRET_BADADDR;
87 89
    if (address < 0x80000000UL) {
88 90
        if (!(env->hflags & MIPS_HFLAG_ERL)) {
89 91
#ifdef MIPS_USES_R4K_TLB
......
181 183
    access_type = ACCESS_INT;
182 184
    if (env->user_mode_only) {
183 185
        /* user mode only emulation */
184
        ret = -2;
186
        ret = TLBRET_NOMATCH;
185 187
        goto do_fault;
186 188
    }
187 189
    ret = get_physical_address(env, &physical, &prot,
......
190 192
        fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n",
191 193
                __func__, address, ret, physical, prot);
192 194
    }
193
    if (ret == 0) {
194
	ret = tlb_set_page(env, address & ~0xFFF, physical & ~0xFFF, prot,
195
			   is_user, is_softmmu);
195
    if (ret == TLBRET_MATCH) {
196
       ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
197
                          physical & TARGET_PAGE_MASK, prot,
198
                          is_user, is_softmmu);
196 199
    } else if (ret < 0) {
197 200
    do_fault:
198 201
        switch (ret) {
199 202
        default:
200
        case -1:
203
        case TLBRET_BADADDR:
201 204
            /* Reference to kernel address from user mode or supervisor mode */
202 205
            /* Reference to supervisor address from user mode */
203 206
            if (rw)
......
205 208
            else
206 209
                exception = EXCP_AdEL;
207 210
            break;
208
        case -2:
211
        case TLBRET_NOMATCH:
209 212
            /* No TLB match for a mapped address */
210 213
            if (rw)
211 214
                exception = EXCP_TLBS;
......
213 216
                exception = EXCP_TLBL;
214 217
            error_code = 1;
215 218
            break;
216
        case -3:
219
        case TLBRET_INVALID:
217 220
            /* TLB match with no valid bit */
218 221
            if (rw)
219 222
                exception = EXCP_TLBS;
220 223
            else
221 224
                exception = EXCP_TLBL;
222 225
            break;
223
        case -4:
226
        case TLBRET_DIRTY:
224 227
            /* TLB match but 'D' bit is cleared */
225 228
            exception = EXCP_LTLBL;
226 229
            break;
......
231 234
        env->CP0_Context = (env->CP0_Context & 0xff800000) |
232 235
	                   ((address >> 9) &   0x007ffff0);
233 236
        env->CP0_EntryHi =
234
            (env->CP0_EntryHi & 0xFF) | (address & 0xFFFFE000);
237
            (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
235 238
        env->exception_index = exception;
236 239
        env->error_code = error_code;
237 240
        ret = 1;

Also available in: Unified diff