Subversion Repositories HelenOS

Rev

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

Rev Author Line No. Line
1 jermar 1
/*
2071 jermar 2
 * Copyright (c) 2003-2004 Jakub Jermar
1 jermar 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
 
1776 jermar 29
/** @addtogroup mips32mm   
1702 cejka 30
 * @{
31
 */
32
/** @file
33
 */
34
 
1 jermar 35
#include <arch/mm/tlb.h>
727 jermar 36
#include <mm/asid.h>
1 jermar 37
#include <mm/tlb.h>
391 jermar 38
#include <mm/page.h>
703 jermar 39
#include <mm/as.h>
1 jermar 40
#include <arch/cp0.h>
41
#include <panic.h>
42
#include <arch.h>
268 palkovsky 43
#include <symtab.h>
391 jermar 44
#include <synch/spinlock.h>
45
#include <print.h>
396 jermar 46
#include <debug.h>
983 palkovsky 47
#include <align.h>
1595 palkovsky 48
#include <interrupt.h>
268 palkovsky 49
 
958 jermar 50
static void tlb_refill_fail(istate_t *istate);
51
static void tlb_invalid_fail(istate_t *istate);
52
static void tlb_modified_fail(istate_t *istate);
391 jermar 53
 
1780 jermar 54
static pte_t *find_mapping_and_check(uintptr_t badvaddr, int access, istate_t *istate, int *pfrc);
399 jermar 55
 
1780 jermar 56
static void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, bool cacheable, uintptr_t pfn);
57
static void prepare_entry_hi(entry_hi_t *hi, asid_t asid, uintptr_t addr);
394 jermar 58
 
391 jermar 59
/** Initialize TLB
60
 *
61
 * Initialize TLB.
62
 * Invalidate all entries and mark wired entries.
63
 */
569 jermar 64
void tlb_arch_init(void)
389 jermar 65
{
599 jermar 66
    int i;
67
 
389 jermar 68
    cp0_pagemask_write(TLB_PAGE_MASK_16K);
599 jermar 69
    cp0_entry_hi_write(0);
70
    cp0_entry_lo0_write(0);
71
    cp0_entry_lo1_write(0);
389 jermar 72
 
599 jermar 73
    /* Clear and initialize TLB. */
74
 
75
    for (i = 0; i < TLB_ENTRY_COUNT; i++) {
76
        cp0_index_write(i);
77
        tlbwi();
78
    }
612 jermar 79
 
598 jermar 80
 
389 jermar 81
    /*
82
     * The kernel is going to make use of some wired
391 jermar 83
     * entries (e.g. mapping kernel stacks in kseg3).
389 jermar 84
     */
85
    cp0_wired_write(TLB_WIRED);
86
}
87
 
391 jermar 88
/** Process TLB Refill Exception
89
 *
90
 * Process TLB Refill Exception.
91
 *
958 jermar 92
 * @param istate Interrupted register context.
391 jermar 93
 */
958 jermar 94
void tlb_refill(istate_t *istate)
1 jermar 95
{
396 jermar 96
    entry_lo_t lo;
1044 jermar 97
    entry_hi_t hi;
98
    asid_t asid;
1780 jermar 99
    uintptr_t badvaddr;
391 jermar 100
    pte_t *pte;
1288 jermar 101
    int pfrc;
397 jermar 102
 
391 jermar 103
    badvaddr = cp0_badvaddr_read();
397 jermar 104
 
1044 jermar 105
    spinlock_lock(&AS->lock);
106
    asid = AS->asid;
107
    spinlock_unlock(&AS->lock);
399 jermar 108
 
1044 jermar 109
    page_table_lock(AS, true);
110
 
1411 jermar 111
    pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate, &pfrc);
1288 jermar 112
    if (!pte) {
113
        switch (pfrc) {
114
        case AS_PF_FAULT:
115
            goto fail;
116
            break;
117
        case AS_PF_DEFER:
118
            /*
119
             * The page fault came during copy_from_uspace()
120
             * or copy_to_uspace().
121
             */
122
            page_table_unlock(AS, true);
123
            return;
124
        default:
125
            panic("unexpected pfrc (%d)\n", pfrc);
126
        }
127
    }
391 jermar 128
 
129
    /*
394 jermar 130
     * Record access to PTE.
391 jermar 131
     */
394 jermar 132
    pte->a = 1;
391 jermar 133
 
1044 jermar 134
    prepare_entry_hi(&hi, asid, badvaddr);
831 jermar 135
    prepare_entry_lo(&lo, pte->g, pte->p, pte->d, pte->cacheable, pte->pfn);
394 jermar 136
 
391 jermar 137
    /*
138
     * New entry is to be inserted into TLB
139
     */
399 jermar 140
    cp0_entry_hi_write(hi.value);
391 jermar 141
    if ((badvaddr/PAGE_SIZE) % 2 == 0) {
396 jermar 142
        cp0_entry_lo0_write(lo.value);
391 jermar 143
        cp0_entry_lo1_write(0);
144
    }
145
    else {
146
        cp0_entry_lo0_write(0);
396 jermar 147
        cp0_entry_lo1_write(lo.value);
391 jermar 148
    }
612 jermar 149
    cp0_pagemask_write(TLB_PAGE_MASK_16K);
391 jermar 150
    tlbwr();
151
 
1044 jermar 152
    page_table_unlock(AS, true);
391 jermar 153
    return;
154
 
155
fail:
1044 jermar 156
    page_table_unlock(AS, true);
958 jermar 157
    tlb_refill_fail(istate);
391 jermar 158
}
159
 
394 jermar 160
/** Process TLB Invalid Exception
161
 *
162
 * Process TLB Invalid Exception.
163
 *
958 jermar 164
 * @param istate Interrupted register context.
394 jermar 165
 */
958 jermar 166
void tlb_invalid(istate_t *istate)
391 jermar 167
{
396 jermar 168
    tlb_index_t index;
1780 jermar 169
    uintptr_t badvaddr;
396 jermar 170
    entry_lo_t lo;
399 jermar 171
    entry_hi_t hi;
394 jermar 172
    pte_t *pte;
1288 jermar 173
    int pfrc;
394 jermar 174
 
175
    badvaddr = cp0_badvaddr_read();
176
 
177
    /*
178
     * Locate the faulting entry in TLB.
179
     */
399 jermar 180
    hi.value = cp0_entry_hi_read();
181
    prepare_entry_hi(&hi, hi.asid, badvaddr);
182
    cp0_entry_hi_write(hi.value);
394 jermar 183
    tlbp();
396 jermar 184
    index.value = cp0_index_read();
1044 jermar 185
 
186
    page_table_lock(AS, true); 
394 jermar 187
 
188
    /*
189
     * Fail if the entry is not in TLB.
190
     */
396 jermar 191
    if (index.p) {
192
        printf("TLB entry not found.\n");
394 jermar 193
        goto fail;
396 jermar 194
    }
394 jermar 195
 
1411 jermar 196
    pte = find_mapping_and_check(badvaddr, PF_ACCESS_READ, istate, &pfrc);
1288 jermar 197
    if (!pte) {
198
        switch (pfrc) {
199
        case AS_PF_FAULT:
200
            goto fail;
201
            break;
202
        case AS_PF_DEFER:
203
            /*
204
             * The page fault came during copy_from_uspace()
205
             * or copy_to_uspace().
206
             */
207
            page_table_unlock(AS, true);             
208
            return;
209
        default:
210
            panic("unexpected pfrc (%d)\n", pfrc);
211
        }
212
    }
394 jermar 213
 
214
    /*
215
     * Read the faulting TLB entry.
216
     */
217
    tlbr();
218
 
219
    /*
220
     * Record access to PTE.
221
     */
222
    pte->a = 1;
223
 
831 jermar 224
    prepare_entry_lo(&lo, pte->g, pte->p, pte->d, pte->cacheable, pte->pfn);
394 jermar 225
 
226
    /*
227
     * The entry is to be updated in TLB.
228
     */
229
    if ((badvaddr/PAGE_SIZE) % 2 == 0)
396 jermar 230
        cp0_entry_lo0_write(lo.value);
394 jermar 231
    else
396 jermar 232
        cp0_entry_lo1_write(lo.value);
612 jermar 233
    cp0_pagemask_write(TLB_PAGE_MASK_16K);
394 jermar 234
    tlbwi();
235
 
1044 jermar 236
    page_table_unlock(AS, true);
394 jermar 237
    return;
238
 
239
fail:
1044 jermar 240
    page_table_unlock(AS, true);
958 jermar 241
    tlb_invalid_fail(istate);
391 jermar 242
}
243
 
394 jermar 244
/** Process TLB Modified Exception
245
 *
246
 * Process TLB Modified Exception.
247
 *
958 jermar 248
 * @param istate Interrupted register context.
394 jermar 249
 */
958 jermar 250
void tlb_modified(istate_t *istate)
391 jermar 251
{
396 jermar 252
    tlb_index_t index;
1780 jermar 253
    uintptr_t badvaddr;
396 jermar 254
    entry_lo_t lo;
399 jermar 255
    entry_hi_t hi;
394 jermar 256
    pte_t *pte;
1288 jermar 257
    int pfrc;
394 jermar 258
 
259
    badvaddr = cp0_badvaddr_read();
260
 
261
    /*
262
     * Locate the faulting entry in TLB.
263
     */
399 jermar 264
    hi.value = cp0_entry_hi_read();
265
    prepare_entry_hi(&hi, hi.asid, badvaddr);
266
    cp0_entry_hi_write(hi.value);
394 jermar 267
    tlbp();
396 jermar 268
    index.value = cp0_index_read();
1044 jermar 269
 
270
    page_table_lock(AS, true); 
394 jermar 271
 
272
    /*
273
     * Fail if the entry is not in TLB.
274
     */
396 jermar 275
    if (index.p) {
276
        printf("TLB entry not found.\n");
394 jermar 277
        goto fail;
396 jermar 278
    }
394 jermar 279
 
1411 jermar 280
    pte = find_mapping_and_check(badvaddr, PF_ACCESS_WRITE, istate, &pfrc);
1288 jermar 281
    if (!pte) {
282
        switch (pfrc) {
283
        case AS_PF_FAULT:
284
            goto fail;
285
            break;
286
        case AS_PF_DEFER:
287
            /*
288
             * The page fault came during copy_from_uspace()
289
             * or copy_to_uspace().
290
             */
291
            page_table_unlock(AS, true);             
292
            return;
293
        default:
294
            panic("unexpected pfrc (%d)\n", pfrc);
295
        }
296
    }
394 jermar 297
 
298
    /*
299
     * Fail if the page is not writable.
300
     */
301
    if (!pte->w)
302
        goto fail;
303
 
304
    /*
305
     * Read the faulting TLB entry.
306
     */
307
    tlbr();
308
 
309
    /*
310
     * Record access and write to PTE.
311
     */
312
    pte->a = 1;
831 jermar 313
    pte->d = 1;
394 jermar 314
 
831 jermar 315
    prepare_entry_lo(&lo, pte->g, pte->p, pte->w, pte->cacheable, pte->pfn);
394 jermar 316
 
317
    /*
318
     * The entry is to be updated in TLB.
319
     */
320
    if ((badvaddr/PAGE_SIZE) % 2 == 0)
396 jermar 321
        cp0_entry_lo0_write(lo.value);
394 jermar 322
    else
396 jermar 323
        cp0_entry_lo1_write(lo.value);
612 jermar 324
    cp0_pagemask_write(TLB_PAGE_MASK_16K);
394 jermar 325
    tlbwi();
326
 
1044 jermar 327
    page_table_unlock(AS, true);
394 jermar 328
    return;
329
 
330
fail:
1044 jermar 331
    page_table_unlock(AS, true);
958 jermar 332
    tlb_modified_fail(istate);
391 jermar 333
}
334
 
958 jermar 335
void tlb_refill_fail(istate_t *istate)
391 jermar 336
{
324 palkovsky 337
    char *symbol = "";
338
    char *sym2 = "";
339
 
958 jermar 340
    char *s = get_symtab_entry(istate->epc);
332 palkovsky 341
    if (s)
342
        symbol = s;
958 jermar 343
    s = get_symtab_entry(istate->ra);
332 palkovsky 344
    if (s)
345
        sym2 = s;
1595 palkovsky 346
 
1735 decky 347
    fault_if_from_uspace(istate, "TLB Refill Exception on %p", cp0_badvaddr_read());
348
    panic("%x: TLB Refill Exception at %x(%s<-%s)\n", cp0_badvaddr_read(), istate->epc, symbol, sym2);
1 jermar 349
}
350
 
391 jermar 351
 
958 jermar 352
void tlb_invalid_fail(istate_t *istate)
1 jermar 353
{
268 palkovsky 354
    char *symbol = "";
355
 
958 jermar 356
    char *s = get_symtab_entry(istate->epc);
332 palkovsky 357
    if (s)
358
        symbol = s;
1735 decky 359
    fault_if_from_uspace(istate, "TLB Invalid Exception on %p", cp0_badvaddr_read());
360
    panic("%x: TLB Invalid Exception at %x(%s)\n", cp0_badvaddr_read(), istate->epc, symbol);
1 jermar 361
}
362
 
958 jermar 363
void tlb_modified_fail(istate_t *istate)
389 jermar 364
{
365
    char *symbol = "";
366
 
958 jermar 367
    char *s = get_symtab_entry(istate->epc);
389 jermar 368
    if (s)
369
        symbol = s;
1735 decky 370
    fault_if_from_uspace(istate, "TLB Modified Exception on %p", cp0_badvaddr_read());
371
    panic("%x: TLB Modified Exception at %x(%s)\n", cp0_badvaddr_read(), istate->epc, symbol);
389 jermar 372
}
373
 
394 jermar 374
/** Try to find PTE for faulting address
375
 *
376
 * Try to find PTE for faulting address.
703 jermar 377
 * The AS->lock must be held on entry to this function.
394 jermar 378
 *
379
 * @param badvaddr Faulting virtual address.
1411 jermar 380
 * @param access Access mode that caused the fault.
1288 jermar 381
 * @param istate Pointer to interrupted state.
382
 * @param pfrc Pointer to variable where as_page_fault() return code will be stored.
394 jermar 383
 *
384
 * @return PTE on success, NULL otherwise.
385
 */
1780 jermar 386
pte_t *find_mapping_and_check(uintptr_t badvaddr, int access, istate_t *istate, int *pfrc)
394 jermar 387
{
396 jermar 388
    entry_hi_t hi;
394 jermar 389
    pte_t *pte;
390
 
396 jermar 391
    hi.value = cp0_entry_hi_read();
394 jermar 392
 
393
    /*
394
     * Handler cannot succeed if the ASIDs don't match.
395
     */
703 jermar 396
    if (hi.asid != AS->asid) {
397
        printf("EntryHi.asid=%d, AS->asid=%d\n", hi.asid, AS->asid);
394 jermar 398
        return NULL;
396 jermar 399
    }
703 jermar 400
 
394 jermar 401
    /*
703 jermar 402
     * Check if the mapping exists in page tables.
403
     */
756 jermar 404
    pte = page_mapping_find(AS, badvaddr);
831 jermar 405
    if (pte && pte->p) {
703 jermar 406
        /*
407
         * Mapping found in page tables.
408
         * Immediately succeed.
409
         */
410
        return pte;
411
    } else {
1288 jermar 412
        int rc;
413
 
703 jermar 414
        /*
415
         * Mapping not found in page tables.
416
         * Resort to higher-level page fault handler.
417
         */
1044 jermar 418
        page_table_unlock(AS, true);
1411 jermar 419
        switch (rc = as_page_fault(badvaddr, access, istate)) {
1288 jermar 420
        case AS_PF_OK:
703 jermar 421
            /*
422
             * The higher-level page fault handler succeeded,
423
             * The mapping ought to be in place.
424
             */
1044 jermar 425
            page_table_lock(AS, true);
756 jermar 426
            pte = page_mapping_find(AS, badvaddr);
831 jermar 427
            ASSERT(pte && pte->p);
703 jermar 428
            return pte;
1288 jermar 429
            break;
430
        case AS_PF_DEFER:
1044 jermar 431
            page_table_lock(AS, true);
1288 jermar 432
            *pfrc = AS_PF_DEFER;
433
            return NULL;
434
            break;
435
        case AS_PF_FAULT:
436
            page_table_lock(AS, true);
1044 jermar 437
            printf("Page fault.\n");
1288 jermar 438
            *pfrc = AS_PF_FAULT;
1044 jermar 439
            return NULL;
1288 jermar 440
            break;
441
        default:
442
            panic("unexpected rc (%d)\n", rc);
703 jermar 443
        }
1044 jermar 444
 
703 jermar 445
    }
394 jermar 446
}
447
 
1780 jermar 448
void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, bool cacheable, uintptr_t pfn)
394 jermar 449
{
399 jermar 450
    lo->value = 0;
394 jermar 451
    lo->g = g;
452
    lo->v = v;
453
    lo->d = d;
831 jermar 454
    lo->c = cacheable ? PAGE_CACHEABLE_EXC_WRITE : PAGE_UNCACHED;
394 jermar 455
    lo->pfn = pfn;
456
}
399 jermar 457
 
1780 jermar 458
void prepare_entry_hi(entry_hi_t *hi, asid_t asid, uintptr_t addr)
399 jermar 459
{
983 palkovsky 460
    hi->value = ALIGN_DOWN(addr, PAGE_SIZE * 2);
399 jermar 461
    hi->asid = asid;
462
}
569 jermar 463
 
594 jermar 464
/** Print contents of TLB. */
569 jermar 465
void tlb_print(void)
466
{
612 jermar 467
    page_mask_t mask;
594 jermar 468
    entry_lo_t lo0, lo1;
704 jermar 469
    entry_hi_t hi, hi_save;
2720 decky 470
    unsigned int i;
594 jermar 471
 
704 jermar 472
    hi_save.value = cp0_entry_hi_read();
2720 decky 473
 
474
    printf("#  ASID VPN2   MASK G V D C PFN\n");
475
    printf("-- ---- ------ ---- - - - - ------\n");
476
 
594 jermar 477
    for (i = 0; i < TLB_ENTRY_COUNT; i++) {
478
        cp0_index_write(i);
479
        tlbr();
480
 
612 jermar 481
        mask.value = cp0_pagemask_read();
594 jermar 482
        hi.value = cp0_entry_hi_read();
483
        lo0.value = cp0_entry_lo0_read();
484
        lo1.value = cp0_entry_lo1_read();
485
 
2720 decky 486
        printf("%-2u %-4u %#6x %#4x %1u %1u %1u %1u %#6x\n",
487
            i, hi.asid, hi.vpn2, mask.mask,
488
            lo0.g, lo0.v, lo0.d, lo0.c, lo0.pfn);
489
        printf("                    %1u %1u %1u %1u %#6x\n",
490
            lo1.g, lo1.v, lo1.d, lo1.c, lo1.pfn);
594 jermar 491
    }
704 jermar 492
 
493
    cp0_entry_hi_write(hi_save.value);
569 jermar 494
}
598 jermar 495
 
618 jermar 496
/** Invalidate all not wired TLB entries. */
598 jermar 497
void tlb_invalidate_all(void)
498
{
599 jermar 499
    ipl_t ipl;
500
    entry_lo_t lo0, lo1;
704 jermar 501
    entry_hi_t hi_save;
598 jermar 502
    int i;
503
 
704 jermar 504
    hi_save.value = cp0_entry_hi_read();
599 jermar 505
    ipl = interrupts_disable();
598 jermar 506
 
618 jermar 507
    for (i = TLB_WIRED; i < TLB_ENTRY_COUNT; i++) {
598 jermar 508
        cp0_index_write(i);
599 jermar 509
        tlbr();
510
 
511
        lo0.value = cp0_entry_lo0_read();
512
        lo1.value = cp0_entry_lo1_read();
513
 
514
        lo0.v = 0;
515
        lo1.v = 0;
516
 
517
        cp0_entry_lo0_write(lo0.value);
518
        cp0_entry_lo1_write(lo1.value);
519
 
598 jermar 520
        tlbwi();
521
    }
599 jermar 522
 
523
    interrupts_restore(ipl);
704 jermar 524
    cp0_entry_hi_write(hi_save.value);
598 jermar 525
}
526
 
527
/** Invalidate all TLB entries belonging to specified address space.
528
 *
529
 * @param asid Address space identifier.
530
 */
531
void tlb_invalidate_asid(asid_t asid)
532
{
599 jermar 533
    ipl_t ipl;
534
    entry_lo_t lo0, lo1;
704 jermar 535
    entry_hi_t hi, hi_save;
598 jermar 536
    int i;
537
 
599 jermar 538
    ASSERT(asid != ASID_INVALID);
539
 
704 jermar 540
    hi_save.value = cp0_entry_hi_read();
599 jermar 541
    ipl = interrupts_disable();
542
 
598 jermar 543
    for (i = 0; i < TLB_ENTRY_COUNT; i++) {
544
        cp0_index_write(i);
545
        tlbr();
546
 
599 jermar 547
        hi.value = cp0_entry_hi_read();
548
 
598 jermar 549
        if (hi.asid == asid) {
599 jermar 550
            lo0.value = cp0_entry_lo0_read();
551
            lo1.value = cp0_entry_lo1_read();
552
 
553
            lo0.v = 0;
554
            lo1.v = 0;
555
 
556
            cp0_entry_lo0_write(lo0.value);
557
            cp0_entry_lo1_write(lo1.value);
558
 
598 jermar 559
            tlbwi();
560
        }
561
    }
599 jermar 562
 
563
    interrupts_restore(ipl);
704 jermar 564
    cp0_entry_hi_write(hi_save.value);
598 jermar 565
}
566
 
727 jermar 567
/** Invalidate TLB entries for specified page range belonging to specified address space.
598 jermar 568
 *
569
 * @param asid Address space identifier.
727 jermar 570
 * @param page First page whose TLB entry is to be invalidated.
571
 * @param cnt Number of entries to invalidate.
598 jermar 572
 */
1780 jermar 573
void tlb_invalidate_pages(asid_t asid, uintptr_t page, count_t cnt)
598 jermar 574
{
2745 decky 575
    unsigned int i;
599 jermar 576
    ipl_t ipl;
577
    entry_lo_t lo0, lo1;
704 jermar 578
    entry_hi_t hi, hi_save;
598 jermar 579
    tlb_index_t index;
580
 
599 jermar 581
    ASSERT(asid != ASID_INVALID);
582
 
704 jermar 583
    hi_save.value = cp0_entry_hi_read();
599 jermar 584
    ipl = interrupts_disable();
585
 
2745 decky 586
    for (i = 0; i < cnt + 1; i += 2) {
727 jermar 587
        hi.value = 0;
588
        prepare_entry_hi(&hi, asid, page + i * PAGE_SIZE);
589
        cp0_entry_hi_write(hi.value);
599 jermar 590
 
727 jermar 591
        tlbp();
592
        index.value = cp0_index_read();
598 jermar 593
 
727 jermar 594
        if (!index.p) {
595
            /* Entry was found, index register contains valid index. */
596
            tlbr();
599 jermar 597
 
727 jermar 598
            lo0.value = cp0_entry_lo0_read();
599
            lo1.value = cp0_entry_lo1_read();
599 jermar 600
 
727 jermar 601
            lo0.v = 0;
602
            lo1.v = 0;
599 jermar 603
 
727 jermar 604
            cp0_entry_lo0_write(lo0.value);
605
            cp0_entry_lo1_write(lo1.value);
599 jermar 606
 
727 jermar 607
            tlbwi();
608
        }
598 jermar 609
    }
599 jermar 610
 
611
    interrupts_restore(ipl);
704 jermar 612
    cp0_entry_hi_write(hi_save.value);
598 jermar 613
}
1702 cejka 614
 
1776 jermar 615
/** @}
1702 cejka 616
 */