Subversion Repositories HelenOS

Rev

Rev 1702 | Rev 1733 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1215 decky 1
/*
2
 * Copyright (C) 2006 Martin Decky
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
 
1730 decky 29
/** @addtogroup ppc32mm
1702 cejka 30
 * @{
31
 */
32
/** @file
33
 */
34
 
1215 decky 35
#include <mm/tlb.h>
1730 decky 36
#include <arch/mm/tlb.h>
37
#include <arch/interrupt.h>
38
#include <mm/as.h>
39
#include <arch.h>
40
#include <print.h>
41
#include <symtab.h>
1215 decky 42
 
43
 
1730 decky 44
/** Try to find PTE for faulting address
1215 decky 45
 *
1730 decky 46
 * Try to find PTE for faulting address.
47
 * The as->lock must be held on entry to this function
48
 * if lock is true.
1215 decky 49
 *
1730 decky 50
 * @param as       Address space.
51
 * @param lock     Lock/unlock the address space.
52
 * @param badvaddr Faulting virtual address.
53
 * @param access   Access mode that caused the fault.
54
 * @param istate   Pointer to interrupted state.
55
 * @param pfrc     Pointer to variable where as_page_fault() return code will be stored.
56
 * @return         PTE on success, NULL otherwise.
57
 *
1215 decky 58
 */
1730 decky 59
static pte_t *find_mapping_and_check(as_t *as, bool lock, __address badvaddr, int access, istate_t *istate, int *pfrc)
60
{
61
    /*
62
     * Check if the mapping exists in page tables.
63
     */
64
    pte_t *pte = page_mapping_find(as, badvaddr);
65
    if ((pte) && (pte->p)) {
66
        /*
67
         * Mapping found in page tables.
68
         * Immediately succeed.
69
         */
70
        return pte;
71
    } else {
72
        int rc;
73
 
74
        /*
75
         * Mapping not found in page tables.
76
         * Resort to higher-level page fault handler.
77
         */
78
        page_table_unlock(as, lock);
79
        switch (rc = as_page_fault(badvaddr, access, istate)) {
80
            case AS_PF_OK:
81
                /*
82
                 * The higher-level page fault handler succeeded,
83
                 * The mapping ought to be in place.
84
                 */
85
                page_table_lock(as, lock);
86
                pte = page_mapping_find(as, badvaddr);
87
                ASSERT((pte) && (pte->p));
88
                return pte;
89
            case AS_PF_DEFER:
90
                page_table_lock(as, lock);
91
                *pfrc = rc;
92
                return NULL;
93
            case AS_PF_FAULT:
94
                page_table_lock(as, lock);
95
                printf("Page fault.\n");
96
                *pfrc = rc;
97
                return NULL;
98
            default:
99
                panic("unexpected rc (%d)\n", rc);
100
        }  
101
    }
102
}
103
 
104
 
105
static void pht_refill_fail(__address badvaddr, istate_t *istate)
106
{
107
    char *symbol = "";
108
    char *sym2 = "";
109
 
110
    char *s = get_symtab_entry(istate->pc);
111
    if (s)
112
        symbol = s;
113
    s = get_symtab_entry(istate->lr);
114
    if (s)
115
        sym2 = s;
116
    panic("%p: PHT Refill Exception at %p (%s<-%s)\n", badvaddr, istate->pc, symbol, sym2);
117
}
118
 
119
 
120
static void pht_insert(const __address vaddr, const pfn_t pfn)
121
{
122
    __u32 page = (vaddr >> 12) & 0xffff;
123
    __u32 api = (vaddr >> 22) & 0x3f;
124
 
125
    __u32 vsid;
126
    asm volatile (
127
        "mfsrin %0, %1\n"
128
        : "=r" (vsid)
129
        : "r" (vaddr)
130
    );
131
 
132
    __u32 sdr1;
133
    asm volatile (
134
        "mfsdr1 %0\n"
135
        : "=r" (sdr1)
136
    );
137
    phte_t *phte = (phte_t *) PA2KA(sdr1 & 0xffff0000);
138
 
139
    /* Primary hash (xor) */
140
    __u32 h = 0;
141
    __u32 hash = vsid ^ page;
142
    __u32 base = (hash & 0x3ff) << 3;
143
    __u32 i;
144
    bool found = false;
145
 
146
    /* Find unused or colliding
147
       PTE in PTEG */
148
    for (i = 0; i < 8; i++) {
149
        if ((!phte[base + i].v) || ((phte[base + i].vsid == vsid) && (phte[base + i].api == api))) {
150
            found = true;
151
            break;
152
        }
153
    }
154
 
155
    if (!found) {
156
        /* Secondary hash (not) */
157
        __u32 base2 = (~hash & 0x3ff) << 3;
158
 
159
        /* Find unused or colliding
160
           PTE in PTEG */
161
        for (i = 0; i < 8; i++) {
162
            if ((!phte[base2 + i].v) || ((phte[base2 + i].vsid == vsid) && (phte[base2 + i].api == api))) {
163
                found = true;
164
                base = base2;
165
                h = 1;
166
                break;
167
            }
168
        }
169
 
170
        if (!found) {
171
            // TODO: A/C precedence groups
172
            i = page % 8;
173
        }
174
    }
175
 
176
    phte[base + i].v = 1;
177
    phte[base + i].vsid = vsid;
178
    phte[base + i].h = h;
179
    phte[base + i].api = api;
180
    phte[base + i].rpn = pfn;
181
    phte[base + i].r = 0;
182
    phte[base + i].c = 0;
183
    phte[base + i].pp = 2; // FIXME
184
}
185
 
186
 
187
static void pht_real_insert(const __address vaddr, const pfn_t pfn)
188
{
189
    __u32 page = (vaddr >> 12) & 0xffff;
190
    __u32 api = (vaddr >> 22) & 0x3f;
191
 
192
    __u32 vsid;
193
    asm volatile (
194
        "mfsrin %0, %1\n"
195
        : "=r" (vsid)
196
        : "r" (vaddr)
197
    );
198
 
199
    __u32 sdr1;
200
    asm volatile (
201
        "mfsdr1 %0\n"
202
        : "=r" (sdr1)
203
    );
204
    phte_t *phte_physical = (phte_t *) (sdr1 & 0xffff0000);
205
 
206
    /* Primary hash (xor) */
207
    __u32 h = 0;
208
    __u32 hash = vsid ^ page;
209
    __u32 base = (hash & 0x3ff) << 3;
210
    __u32 i;
211
    bool found = false;
212
 
213
    /* Find unused or colliding
214
       PTE in PTEG */
215
    for (i = 0; i < 8; i++) {
216
        if ((!phte_physical[base + i].v) || ((phte_physical[base + i].vsid == vsid) && (phte_physical[base + i].api == api))) {
217
            found = true;
218
            break;
219
        }
220
    }
221
 
222
    if (!found) {
223
        /* Secondary hash (not) */
224
        __u32 base2 = (~hash & 0x3ff) << 3;
225
 
226
        /* Find unused or colliding
227
           PTE in PTEG */
228
        for (i = 0; i < 8; i++) {
229
            if ((!phte_physical[base2 + i].v) || ((phte_physical[base2 + i].vsid == vsid) && (phte_physical[base2 + i].api == api))) {
230
                found = true;
231
                base = base2;
232
                h = 1;
233
                break;
234
            }
235
        }
236
 
237
        if (!found) {
238
            // TODO: A/C precedence groups
239
            i = page % 8;
240
        }
241
    }
242
 
243
    phte_physical[base + i].v = 1;
244
    phte_physical[base + i].vsid = vsid;
245
    phte_physical[base + i].h = h;
246
    phte_physical[base + i].api = api;
247
    phte_physical[base + i].rpn = pfn;
248
    phte_physical[base + i].r = 0;
249
    phte_physical[base + i].c = 0;
250
    phte_physical[base + i].pp = 2; // FIXME
251
}
252
 
253
 
254
/** Process Instruction/Data Storage Interrupt
255
 *
256
 * @param n Interrupt vector number.
257
 * @param istate Interrupted register context.
258
 *
259
 */
260
void pht_refill(int n, istate_t *istate)
261
{
262
    __address badvaddr;
263
    pte_t *pte;
264
    int pfrc;
265
    as_t *as;
266
    bool lock;
267
 
268
    if (AS == NULL) {
269
        as = AS_KERNEL;
270
        lock = false;
271
    } else {
272
        as = AS;
273
        lock = true;
274
    }
275
 
276
    if (n == VECTOR_DATA_STORAGE) {
277
        asm volatile (
278
            "mfdar %0\n"
279
            : "=r" (badvaddr)
280
        );
281
    } else
282
        badvaddr = istate->pc;
283
 
284
    page_table_lock(as, lock);
285
 
286
    pte = find_mapping_and_check(as, lock, badvaddr, PF_ACCESS_READ /* FIXME */, istate, &pfrc);
287
    if (!pte) {
288
        switch (pfrc) {
289
            case AS_PF_FAULT:
290
                goto fail;
291
                break;
292
            case AS_PF_DEFER:
293
                /*
294
                 * The page fault came during copy_from_uspace()
295
                 * or copy_to_uspace().
296
                 */
297
                page_table_unlock(as, lock);
298
                return;
299
            default:
300
                panic("Unexpected pfrc (%d)\n", pfrc);
301
        }
302
    }
303
 
304
    pte->a = 1; /* Record access to PTE */
305
    pht_insert(badvaddr, pte->pfn);
306
 
307
    page_table_unlock(as, lock);
308
    return;
309
 
310
fail:
311
    page_table_unlock(as, lock);
312
    pht_refill_fail(badvaddr, istate);
313
}
314
 
315
 
316
/** Process Instruction/Data Storage Interrupt in Real Mode
317
 *
318
 * @param n Interrupt vector number.
319
 * @param istate Interrupted register context.
320
 *
321
 */
322
bool pht_real_refill(int n, istate_t *istate)
323
{
324
    __address badvaddr;
325
 
326
    if (n == VECTOR_DATA_STORAGE) {
327
        asm volatile (
328
            "mfdar %0\n"
329
            : "=r" (badvaddr)
330
        );
331
    } else
332
        badvaddr = istate->pc;
333
 
334
    __u32 physmem;
335
    asm volatile (
336
        "mfsprg3 %0\n"
337
        : "=r" (physmem)
338
    );
339
 
340
    if ((badvaddr >= PA2KA(0)) && (badvaddr < PA2KA(physmem))) {
341
        pht_real_insert(badvaddr, KA2PA(badvaddr) >> 12);
342
        return true;
343
    }
344
 
345
    return false;
346
}
347
 
348
 
1215 decky 349
void tlb_arch_init(void)
350
{
1384 decky 351
    tlb_invalidate_all();
352
}
353
 
354
 
355
void tlb_invalidate_all(void)
356
{
1269 decky 357
    asm volatile (
1374 decky 358
        "tlbia\n"
1384 decky 359
        "tlbsync\n"
1269 decky 360
    );
1215 decky 361
}
362
 
363
 
1384 decky 364
void tlb_invalidate_asid(asid_t asid)
1328 decky 365
{
1730 decky 366
    // TODO
1384 decky 367
    tlb_invalidate_all();
1328 decky 368
}
369
 
1730 decky 370
 
1384 decky 371
void tlb_invalidate_pages(asid_t asid, __address page, count_t cnt)
372
{
1730 decky 373
    // TODO
1384 decky 374
    tlb_invalidate_all();
375
}
1328 decky 376
 
1384 decky 377
 
1215 decky 378
void tlb_print(void)
379
{
1730 decky 380
    // TODO
1215 decky 381
}
1702 cejka 382
 
1730 decky 383
/** @}
1702 cejka 384
 */