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
 */