Subversion Repositories HelenOS

Rev

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