Statistics
| Branch: | Revision:

root / target-ppc / mmu-hash64.c @ 10b46525

History | View | Annotate | Download (5.6 kB)

1
/*
2
 *  PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
3
 *
4
 *  Copyright (c) 2003-2007 Jocelyn Mayer
5
 *  Copyright (c) 2013 David Gibson, IBM Corporation
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
#include "cpu.h"
21
#include "helper.h"
22
#include "sysemu/kvm.h"
23
#include "kvm_ppc.h"
24
#include "mmu-hash64.h"
25

    
26
//#define DEBUG_SLB
27

    
28
#ifdef DEBUG_SLB
29
#  define LOG_SLB(...) qemu_log(__VA_ARGS__)
30
#else
31
#  define LOG_SLB(...) do { } while (0)
32
#endif
33

    
34
/*
35
 * SLB handling
36
 */
37

    
38
ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
39
{
40
    uint64_t esid_256M, esid_1T;
41
    int n;
42

    
43
    LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
44

    
45
    esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
46
    esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
47

    
48
    for (n = 0; n < env->slb_nr; n++) {
49
        ppc_slb_t *slb = &env->slb[n];
50

    
51
        LOG_SLB("%s: slot %d %016" PRIx64 " %016"
52
                    PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
53
        /* We check for 1T matches on all MMUs here - if the MMU
54
         * doesn't have 1T segment support, we will have prevented 1T
55
         * entries from being inserted in the slbmte code. */
56
        if (((slb->esid == esid_256M) &&
57
             ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
58
            || ((slb->esid == esid_1T) &&
59
                ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
60
            return slb;
61
        }
62
    }
63

    
64
    return NULL;
65
}
66

    
67
void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
68
{
69
    int i;
70
    uint64_t slbe, slbv;
71

    
72
    cpu_synchronize_state(env);
73

    
74
    cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
75
    for (i = 0; i < env->slb_nr; i++) {
76
        slbe = env->slb[i].esid;
77
        slbv = env->slb[i].vsid;
78
        if (slbe == 0 && slbv == 0) {
79
            continue;
80
        }
81
        cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n",
82
                    i, slbe, slbv);
83
    }
84
}
85

    
86
void helper_slbia(CPUPPCState *env)
87
{
88
    int n, do_invalidate;
89

    
90
    do_invalidate = 0;
91
    /* XXX: Warning: slbia never invalidates the first segment */
92
    for (n = 1; n < env->slb_nr; n++) {
93
        ppc_slb_t *slb = &env->slb[n];
94

    
95
        if (slb->esid & SLB_ESID_V) {
96
            slb->esid &= ~SLB_ESID_V;
97
            /* XXX: given the fact that segment size is 256 MB or 1TB,
98
             *      and we still don't have a tlb_flush_mask(env, n, mask)
99
             *      in QEMU, we just invalidate all TLBs
100
             */
101
            do_invalidate = 1;
102
        }
103
    }
104
    if (do_invalidate) {
105
        tlb_flush(env, 1);
106
    }
107
}
108

    
109
void helper_slbie(CPUPPCState *env, target_ulong addr)
110
{
111
    ppc_slb_t *slb;
112

    
113
    slb = slb_lookup(env, addr);
114
    if (!slb) {
115
        return;
116
    }
117

    
118
    if (slb->esid & SLB_ESID_V) {
119
        slb->esid &= ~SLB_ESID_V;
120

    
121
        /* XXX: given the fact that segment size is 256 MB or 1TB,
122
         *      and we still don't have a tlb_flush_mask(env, n, mask)
123
         *      in QEMU, we just invalidate all TLBs
124
         */
125
        tlb_flush(env, 1);
126
    }
127
}
128

    
129
int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
130
{
131
    int slot = rb & 0xfff;
132
    ppc_slb_t *slb = &env->slb[slot];
133

    
134
    if (rb & (0x1000 - env->slb_nr)) {
135
        return -1; /* Reserved bits set or slot too high */
136
    }
137
    if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
138
        return -1; /* Bad segment size */
139
    }
140
    if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
141
        return -1; /* 1T segment on MMU that doesn't support it */
142
    }
143

    
144
    /* Mask out the slot number as we store the entry */
145
    slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
146
    slb->vsid = rs;
147

    
148
    LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
149
            " %016" PRIx64 "\n", __func__, slot, rb, rs,
150
            slb->esid, slb->vsid);
151

    
152
    return 0;
153
}
154

    
155
static int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb,
156
                             target_ulong *rt)
157
{
158
    int slot = rb & 0xfff;
159
    ppc_slb_t *slb = &env->slb[slot];
160

    
161
    if (slot >= env->slb_nr) {
162
        return -1;
163
    }
164

    
165
    *rt = slb->esid;
166
    return 0;
167
}
168

    
169
static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb,
170
                             target_ulong *rt)
171
{
172
    int slot = rb & 0xfff;
173
    ppc_slb_t *slb = &env->slb[slot];
174

    
175
    if (slot >= env->slb_nr) {
176
        return -1;
177
    }
178

    
179
    *rt = slb->vsid;
180
    return 0;
181
}
182

    
183
void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
184
{
185
    if (ppc_store_slb(env, rb, rs) < 0) {
186
        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
187
                                   POWERPC_EXCP_INVAL);
188
    }
189
}
190

    
191
target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
192
{
193
    target_ulong rt = 0;
194

    
195
    if (ppc_load_slb_esid(env, rb, &rt) < 0) {
196
        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
197
                                   POWERPC_EXCP_INVAL);
198
    }
199
    return rt;
200
}
201

    
202
target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
203
{
204
    target_ulong rt = 0;
205

    
206
    if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
207
        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
208
                                   POWERPC_EXCP_INVAL);
209
    }
210
    return rt;
211
}