Subversion Repositories HelenOS

Rev

Rev 1702 | Rev 1733 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1702 Rev 1730
1
/*
1
/*
2
 * Copyright (C) 2006 Martin Decky
2
 * Copyright (C) 2006 Martin Decky
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
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
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.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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
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.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
 /** @addtogroup ppc32mm   
29
/** @addtogroup ppc32mm
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <mm/tlb.h>
35
#include <mm/tlb.h>
-
 
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>
36
 
42
 
37
 
43
 
38
/** Initialize Page Hash Table.
44
/** Try to find PTE for faulting address
39
 *
45
 *
40
 * Setup the Page Hash Table with no entries.
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.
-
 
49
 *
-
 
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.
41
 *
57
 *
42
 */
58
 */
-
 
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
 
43
void tlb_arch_init(void)
349
void tlb_arch_init(void)
44
{
350
{
45
    tlb_invalidate_all();
351
    tlb_invalidate_all();
46
}
352
}
47
 
353
 
48
 
354
 
49
void tlb_invalidate_all(void)
355
void tlb_invalidate_all(void)
50
{
356
{
51
    asm volatile (
357
    asm volatile (
52
        "tlbia\n"
358
        "tlbia\n"
53
        "tlbsync\n"
359
        "tlbsync\n"
54
    );
360
    );
55
}
361
}
56
 
362
 
57
 
363
 
58
/** Invalidate all entries in TLB that belong to specified address space.
-
 
59
 *
-
 
60
 * @param asid This parameter is ignored as the architecture doesn't support it.
-
 
61
 */
-
 
62
void tlb_invalidate_asid(asid_t asid)
364
void tlb_invalidate_asid(asid_t asid)
63
{
365
{
-
 
366
    // TODO
64
    tlb_invalidate_all();
367
    tlb_invalidate_all();
65
}
368
}
66
 
369
 
67
/** Invalidate TLB entries for specified page range belonging to specified address space.
-
 
68
 *
370
 
69
 * @param asid This parameter is ignored as the architecture doesn't support it.
-
 
70
 * @param page Address of the first page whose entry is to be invalidated.
-
 
71
 * @param cnt Number of entries to invalidate.
-
 
72
 */
-
 
73
void tlb_invalidate_pages(asid_t asid, __address page, count_t cnt)
371
void tlb_invalidate_pages(asid_t asid, __address page, count_t cnt)
74
{
372
{
-
 
373
    // TODO
75
    tlb_invalidate_all();
374
    tlb_invalidate_all();
76
}
375
}
77
 
376
 
78
 
377
 
79
 
-
 
80
/** Print contents of Page Hash Table. */
-
 
81
void tlb_print(void)
378
void tlb_print(void)
82
{
379
{
-
 
380
    // TODO
83
}
381
}
84
 
382
 
85
 /** @}
383
/** @}
86
 */
384
 */
87
 
-
 
88
 
385