Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/riscv/iommu/iommu_pmap.c
288965 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2026 Ruslan Bukin <[email protected]>
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. 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
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/param.h>
29
#include <sys/systm.h>
30
#include <sys/ktr.h>
31
#include <sys/lock.h>
32
#include <sys/mutex.h>
33
34
#include <vm/vm.h>
35
#include <vm/vm_param.h>
36
#include <vm/vm_page.h>
37
38
#include <riscv/iommu/iommu_pmap.h>
39
40
/*
41
* Boundary values for the page table page index space:
42
*
43
* L3 pages: [0, NUL2E)
44
* L2 pages: [NUL2E, NUL2E + NUL1E)
45
* L1 pages: [NUL2E + NUL1E, NUL2E + NUL1E + NUL0E)
46
*
47
* Note that these ranges are used in both SV39 and SV48 mode. In SV39 mode the
48
* ranges are not fully populated since there are at most Ln_ENTRIES^2 L3 pages
49
* in a set of page tables.
50
*/
51
#define NUL0E Ln_ENTRIES
52
#define NUL1E (Ln_ENTRIES * NUL0E)
53
#define NUL2E (Ln_ENTRIES * NUL1E)
54
55
#define pmap_l1_pindex(v) (NUL2E + ((v) >> L1_SHIFT))
56
#define pmap_l2_pindex(v) ((v) >> L2_SHIFT)
57
58
#define pmap_clear(pte) pmap_store(pte, 0)
59
#define pmap_clear_bits(pte, bits) atomic_clear_64(pte, bits)
60
#define pmap_load_store(pte, entry) atomic_swap_64(pte, entry)
61
#define pmap_load_clear(pte) pmap_load_store(pte, 0)
62
#define pmap_load(pte) atomic_load_64(pte)
63
#define pmap_store(pte, entry) atomic_store_64(pte, entry)
64
#define pmap_store_bits(pte, bits) atomic_set_64(pte, bits)
65
66
#define pmap_l0_index(va) (((va) >> L0_SHIFT) & Ln_ADDR_MASK)
67
#define pmap_l1_index(va) (((va) >> L1_SHIFT) & Ln_ADDR_MASK)
68
#define pmap_l2_index(va) (((va) >> L2_SHIFT) & Ln_ADDR_MASK)
69
#define pmap_l3_index(va) (((va) >> L3_SHIFT) & Ln_ADDR_MASK)
70
71
#define PTE_TO_PHYS(pte) \
72
((((pte) & ~PTE_HI_MASK) >> PTE_PPN0_S) * PAGE_SIZE)
73
#define L2PTE_TO_PHYS(l2) \
74
((((l2) & ~PTE_HI_MASK) >> PTE_PPN1_S) << L2_SHIFT)
75
#define L1PTE_TO_PHYS(l1) \
76
((((l1) & ~PTE_HI_MASK) >> PTE_PPN2_S) << L1_SHIFT)
77
#define PTE_TO_VM_PAGE(pte) PHYS_TO_VM_PAGE(PTE_TO_PHYS(pte))
78
79
/********************/
80
/* Inline functions */
81
/********************/
82
83
static __inline pd_entry_t *
84
pmap_l0(struct riscv_iommu_pmap *pmap, vm_offset_t va)
85
{
86
KASSERT(pmap->pm_mode != PMAP_MODE_SV39,
87
("%s: in SV39 mode", __func__));
88
KASSERT(VIRT_IS_VALID(va),
89
("%s: malformed virtual address %#lx", __func__, va));
90
return (&pmap->pm_top[pmap_l0_index(va)]);
91
}
92
93
static __inline pd_entry_t *
94
pmap_l0_to_l1(struct riscv_iommu_pmap *pmap, pd_entry_t *l0, vm_offset_t va)
95
{
96
vm_paddr_t phys;
97
pd_entry_t *l1;
98
99
KASSERT(pmap->pm_mode != PMAP_MODE_SV39,
100
("%s: in SV39 mode", __func__));
101
phys = PTE_TO_PHYS(pmap_load(l0));
102
l1 = (pd_entry_t *)PHYS_TO_DMAP(phys);
103
104
return (&l1[pmap_l1_index(va)]);
105
}
106
107
static __inline pd_entry_t *
108
pmap_l1(struct riscv_iommu_pmap *pmap, vm_offset_t va)
109
{
110
pd_entry_t *l0;
111
112
KASSERT(VIRT_IS_VALID(va),
113
("%s: malformed virtual address %#lx", __func__, va));
114
if (pmap->pm_mode == PMAP_MODE_SV39) {
115
return (&pmap->pm_top[pmap_l1_index(va)]);
116
} else {
117
l0 = pmap_l0(pmap, va);
118
if ((pmap_load(l0) & PTE_V) == 0)
119
return (NULL);
120
if ((pmap_load(l0) & PTE_RX) != 0)
121
return (NULL);
122
return (pmap_l0_to_l1(pmap, l0, va));
123
}
124
}
125
126
static __inline pd_entry_t *
127
pmap_l1_to_l2(pd_entry_t *l1, vm_offset_t va)
128
{
129
vm_paddr_t phys;
130
pd_entry_t *l2;
131
132
phys = PTE_TO_PHYS(pmap_load(l1));
133
l2 = (pd_entry_t *)PHYS_TO_DMAP(phys);
134
135
return (&l2[pmap_l2_index(va)]);
136
}
137
138
static __inline pd_entry_t *
139
pmap_l2(struct riscv_iommu_pmap *pmap, vm_offset_t va)
140
{
141
pd_entry_t *l1;
142
143
l1 = pmap_l1(pmap, va);
144
if (l1 == NULL)
145
return (NULL);
146
if ((pmap_load(l1) & PTE_V) == 0)
147
return (NULL);
148
if ((pmap_load(l1) & PTE_RX) != 0)
149
return (NULL);
150
151
return (pmap_l1_to_l2(l1, va));
152
}
153
154
static __inline pt_entry_t *
155
pmap_l2_to_l3(pd_entry_t *l2, vm_offset_t va)
156
{
157
vm_paddr_t phys;
158
pt_entry_t *l3;
159
160
phys = PTE_TO_PHYS(pmap_load(l2));
161
l3 = (pd_entry_t *)PHYS_TO_DMAP(phys);
162
163
return (&l3[pmap_l3_index(va)]);
164
}
165
166
static __inline pt_entry_t *
167
pmap_l3(struct riscv_iommu_pmap *pmap, vm_offset_t va)
168
{
169
pd_entry_t *l2;
170
171
l2 = pmap_l2(pmap, va);
172
if (l2 == NULL)
173
return (NULL);
174
if ((pmap_load(l2) & PTE_V) == 0)
175
return (NULL);
176
if ((pmap_load(l2) & PTE_RX) != 0)
177
return (NULL);
178
179
return (pmap_l2_to_l3(l2, va));
180
}
181
182
#ifdef INVARIANTS
183
static __inline void
184
pmap_resident_count_inc(struct riscv_iommu_pmap *pmap, int count)
185
{
186
187
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
188
pmap->sp_resident_count += count;
189
}
190
191
static __inline void
192
pmap_resident_count_dec(struct riscv_iommu_pmap *pmap, int count)
193
{
194
195
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
196
KASSERT(pmap->sp_resident_count >= count,
197
("pmap %p resident count underflow %ld %d", pmap,
198
pmap->sp_resident_count, count));
199
pmap->sp_resident_count -= count;
200
}
201
#else
202
static __inline void
203
pmap_resident_count_inc(struct riscv_iommu_pmap *pmap, int count)
204
{
205
}
206
207
static __inline void
208
pmap_resident_count_dec(struct riscv_iommu_pmap *pmap, int count)
209
{
210
}
211
#endif
212
213
/***************************************************
214
* Page table page management routines.....
215
***************************************************/
216
217
int
218
iommu_pmap_pinit(struct riscv_iommu_pmap *pmap, enum pmap_mode pm_mode)
219
{
220
vm_paddr_t topphys;
221
vm_page_t m;
222
223
m = vm_page_alloc_noobj(VM_ALLOC_WIRED | VM_ALLOC_ZERO |
224
VM_ALLOC_WAITOK);
225
topphys = VM_PAGE_TO_PHYS(m);
226
pmap->pm_top = (pd_entry_t *)PHYS_TO_DMAP(topphys);
227
pmap->pm_mode = pm_mode;
228
229
switch (pm_mode) {
230
case PMAP_MODE_SV39:
231
pmap->pm_satp = SATP_MODE_SV39;
232
break;
233
case PMAP_MODE_SV48:
234
pmap->pm_satp = SATP_MODE_SV48;
235
break;
236
default:
237
panic("Unknown virtual memory system");
238
};
239
240
pmap->pm_satp |= (topphys >> PAGE_SHIFT);
241
242
#ifdef INVARIANTS
243
pmap->sp_resident_count = 0;
244
#endif
245
246
mtx_init(&pmap->pm_mtx, "iommu pmap", NULL, MTX_DEF);
247
248
return (1);
249
}
250
251
/*
252
* Release any resources held by the given physical map.
253
* Called when a pmap initialized by pmap_pinit is being released.
254
* Should only be called if the map contains no valid mappings.
255
*/
256
void
257
iommu_pmap_release(struct riscv_iommu_pmap *pmap)
258
{
259
vm_page_t m;
260
261
KASSERT(pmap->sp_resident_count == 0,
262
("pmap_release: pmap resident count %ld != 0",
263
pmap->sp_resident_count));
264
265
m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pmap->pm_top));
266
vm_page_unwire_noq(m);
267
vm_page_free_zero(m);
268
mtx_destroy(&pmap->pm_mtx);
269
}
270
271
/*
272
* This routine is called if the desired page table page does not exist.
273
*
274
* If page table page allocation fails, this routine may sleep before
275
* returning NULL. It sleeps only if a lock pointer was given.
276
*
277
* Note: If a page allocation fails at page table level two or three,
278
* one or two pages may be held during the wait, only to be released
279
* afterwards. This conservative approach is easily argued to avoid
280
* race conditions.
281
*/
282
static vm_page_t
283
_pmap_alloc_l3(struct riscv_iommu_pmap *pmap, vm_pindex_t ptepindex)
284
{
285
vm_page_t m, pdpg;
286
pt_entry_t entry;
287
vm_paddr_t phys;
288
pn_t pn;
289
290
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
291
292
/*
293
* Allocate a page table page.
294
*/
295
m = vm_page_alloc_noobj(VM_ALLOC_WIRED | VM_ALLOC_ZERO);
296
if (m == NULL) {
297
/*
298
* Indicate the need to retry. While waiting, the page table
299
* page may have been allocated.
300
*/
301
return (NULL);
302
}
303
m->pindex = ptepindex;
304
305
/*
306
* Map the pagetable page into the process address space, if
307
* it isn't already there.
308
*/
309
pn = VM_PAGE_TO_PHYS(m) >> PAGE_SHIFT;
310
if (ptepindex >= NUL2E + NUL1E) {
311
pd_entry_t *l0;
312
vm_pindex_t l0index;
313
314
KASSERT(pmap->pm_mode != PMAP_MODE_SV39,
315
("%s: pindex %#lx in SV39 mode", __func__, ptepindex));
316
KASSERT(ptepindex < NUL2E + NUL1E + NUL0E,
317
("%s: pindex %#lx out of range", __func__, ptepindex));
318
319
l0index = ptepindex - (NUL2E + NUL1E);
320
l0 = &pmap->pm_top[l0index];
321
KASSERT((pmap_load(l0) & PTE_V) == 0,
322
("%s: L0 entry %#lx is valid", __func__, pmap_load(l0)));
323
324
entry = PTE_V | (pn << PTE_PPN0_S);
325
pmap_store(l0, entry);
326
} else if (ptepindex >= NUL2E) {
327
pd_entry_t *l0, *l1;
328
vm_pindex_t l0index, l1index;
329
330
l1index = ptepindex - NUL2E;
331
if (pmap->pm_mode == PMAP_MODE_SV39) {
332
l1 = &pmap->pm_top[l1index];
333
} else {
334
l0index = l1index >> Ln_ENTRIES_SHIFT;
335
l0 = &pmap->pm_top[l0index];
336
if (pmap_load(l0) == 0) {
337
/* Recurse to allocate the L1 page. */
338
if (_pmap_alloc_l3(pmap,
339
NUL2E + NUL1E + l0index) == NULL)
340
goto fail;
341
phys = PTE_TO_PHYS(pmap_load(l0));
342
} else {
343
phys = PTE_TO_PHYS(pmap_load(l0));
344
pdpg = PHYS_TO_VM_PAGE(phys);
345
pdpg->ref_count++;
346
}
347
l1 = (pd_entry_t *)PHYS_TO_DMAP(phys);
348
l1 = &l1[ptepindex & Ln_ADDR_MASK];
349
}
350
KASSERT((pmap_load(l1) & PTE_V) == 0,
351
("%s: L1 entry %#lx is valid", __func__, pmap_load(l1)));
352
353
entry = PTE_V | (pn << PTE_PPN0_S);
354
pmap_store(l1, entry);
355
} else {
356
vm_pindex_t l0index, l1index;
357
pd_entry_t *l0, *l1, *l2;
358
359
l1index = ptepindex >> (L1_SHIFT - L2_SHIFT);
360
if (pmap->pm_mode == PMAP_MODE_SV39) {
361
l1 = &pmap->pm_top[l1index];
362
if (pmap_load(l1) == 0) {
363
/* recurse for allocating page dir */
364
if (_pmap_alloc_l3(pmap, NUL2E + l1index)
365
== NULL)
366
goto fail;
367
} else {
368
pdpg = PTE_TO_VM_PAGE(pmap_load(l1));
369
pdpg->ref_count++;
370
}
371
} else {
372
l0index = l1index >> Ln_ENTRIES_SHIFT;
373
l0 = &pmap->pm_top[l0index];
374
if (pmap_load(l0) == 0) {
375
/* Recurse to allocate the L1 entry. */
376
if (_pmap_alloc_l3(pmap, NUL2E + l1index)
377
== NULL)
378
goto fail;
379
phys = PTE_TO_PHYS(pmap_load(l0));
380
l1 = (pd_entry_t *)PHYS_TO_DMAP(phys);
381
l1 = &l1[l1index & Ln_ADDR_MASK];
382
} else {
383
phys = PTE_TO_PHYS(pmap_load(l0));
384
l1 = (pd_entry_t *)PHYS_TO_DMAP(phys);
385
l1 = &l1[l1index & Ln_ADDR_MASK];
386
if (pmap_load(l1) == 0) {
387
/* Recurse to allocate the L2 page. */
388
if (_pmap_alloc_l3(pmap,
389
NUL2E + l1index) == NULL)
390
goto fail;
391
} else {
392
pdpg = PTE_TO_VM_PAGE(pmap_load(l1));
393
pdpg->ref_count++;
394
}
395
}
396
}
397
398
phys = PTE_TO_PHYS(pmap_load(l1));
399
l2 = (pd_entry_t *)PHYS_TO_DMAP(phys);
400
l2 = &l2[ptepindex & Ln_ADDR_MASK];
401
KASSERT((pmap_load(l2) & PTE_V) == 0,
402
("%s: L2 entry %#lx is valid", __func__, pmap_load(l2)));
403
404
entry = PTE_V | (pn << PTE_PPN0_S);
405
pmap_store(l2, entry);
406
}
407
408
pmap_resident_count_inc(pmap, 1);
409
410
return (m);
411
412
fail:
413
vm_page_unwire_noq(m);
414
vm_page_free_zero(m);
415
return (NULL);
416
}
417
418
/*
419
* Remove a single IOMMU entry.
420
*/
421
int
422
iommu_pmap_remove(struct riscv_iommu_pmap *pmap, vm_offset_t va)
423
{
424
pt_entry_t *l3;
425
int rc;
426
427
PMAP_LOCK(pmap);
428
429
l3 = pmap_l3(pmap, va);
430
if (l3 != NULL) {
431
pmap_resident_count_dec(pmap, 1);
432
pmap_clear(l3);
433
rc = KERN_SUCCESS;
434
} else
435
rc = KERN_FAILURE;
436
437
PMAP_UNLOCK(pmap);
438
439
return (rc);
440
}
441
442
/* Add a single IOMMU entry. This function does not sleep. */
443
int
444
iommu_pmap_enter(struct riscv_iommu_pmap *pmap, vm_offset_t va, vm_paddr_t pa,
445
vm_prot_t prot, u_int flags)
446
{
447
pd_entry_t *l2, l2e;
448
pt_entry_t new_l3;
449
pt_entry_t *l3;
450
vm_page_t mpte;
451
pn_t pn;
452
int rv;
453
454
pn = (pa / PAGE_SIZE);
455
456
new_l3 = PTE_V | PTE_R | PTE_A;
457
if (prot & VM_PROT_EXECUTE)
458
new_l3 |= PTE_X;
459
if (flags & VM_PROT_WRITE)
460
new_l3 |= PTE_D;
461
if (prot & VM_PROT_WRITE)
462
new_l3 |= PTE_W;
463
if (va < VM_MAX_USER_ADDRESS)
464
new_l3 |= PTE_U;
465
466
new_l3 |= (pn << PTE_PPN0_S);
467
new_l3 |= PTE_MA_IO;
468
469
/*
470
* Set modified bit gratuitously for writeable mappings if
471
* the page is unmanaged. We do not want to take a fault
472
* to do the dirty bit accounting for these mappings.
473
*/
474
if (prot & VM_PROT_WRITE)
475
new_l3 |= PTE_D;
476
477
CTR2(KTR_PMAP, "pmap_enter: %.16lx -> %.16lx", va, pa);
478
479
mpte = NULL;
480
PMAP_LOCK(pmap);
481
482
l2 = pmap_l2(pmap, va);
483
if (l2 != NULL && ((l2e = pmap_load(l2)) & PTE_V) != 0 &&
484
((l2e & PTE_RWX) == 0)) {
485
l3 = pmap_l2_to_l3(l2, va);
486
} else if (va < VM_MAXUSER_ADDRESS) {
487
mpte = _pmap_alloc_l3(pmap, pmap_l2_pindex(va));
488
if (mpte == NULL) {
489
CTR0(KTR_PMAP, "pmap_enter: mpte == NULL");
490
rv = KERN_RESOURCE_SHORTAGE;
491
goto out;
492
}
493
l3 = pmap_l3(pmap, va);
494
} else
495
panic("pmap_enter: missing L3 table for kernel va %#lx", va);
496
497
KASSERT((pmap_load(l3) & PTE_V) == 0, ("l3 is valid"));
498
499
pmap_store(l3, new_l3);
500
pmap_resident_count_inc(pmap, 1);
501
502
rv = KERN_SUCCESS;
503
out:
504
PMAP_UNLOCK(pmap);
505
506
return (rv);
507
}
508
509
static void
510
iommu_pmap_remove_pages_sv48(struct riscv_iommu_pmap *pmap)
511
{
512
pd_entry_t l0e, *l1, l1e, *l2, l2e, *l3, l3e;
513
vm_paddr_t pa0, pa1, pa;
514
vm_page_t m0, m1, m;
515
int i, j, k, l;
516
517
PMAP_LOCK(pmap);
518
519
for (i = 0; i < Ln_ENTRIES; i++) {
520
l0e = pmap->pm_top[i];
521
if ((l0e & PTE_V) == 0)
522
continue;
523
pa0 = PTE_TO_PHYS(l0e);
524
m0 = PHYS_TO_VM_PAGE(pa0);
525
l1 = (pd_entry_t *)PHYS_TO_DMAP(pa0);
526
527
for (j = 0; j < Ln_ENTRIES; j++) {
528
l1e = l1[j];
529
if ((l1e & PTE_V) == 0)
530
continue;
531
pa1 = PTE_TO_PHYS(l1e);
532
m1 = PHYS_TO_VM_PAGE(pa1);
533
l2 = (pd_entry_t *)PHYS_TO_DMAP(pa1);
534
535
for (k = 0; k < Ln_ENTRIES; k++) {
536
l2e = l2[k];
537
if ((l2e & PTE_V) == 0)
538
continue;
539
pa = PTE_TO_PHYS(l2e);
540
m = PHYS_TO_VM_PAGE(pa);
541
l3 = (pt_entry_t *)PHYS_TO_DMAP(pa);
542
543
for (l = 0; l < Ln_ENTRIES; l++) {
544
l3e = l3[l];
545
if ((l3e & PTE_V) == 0)
546
continue;
547
panic("%s: l3e found (idx %d %d %d %d)",
548
__func__, i, j, k, l);
549
}
550
551
vm_page_unwire_noq(m1);
552
vm_page_unwire_noq(m);
553
pmap_resident_count_dec(pmap, 1);
554
vm_page_free(m);
555
pmap_clear(&l2[k]);
556
}
557
558
vm_page_unwire_noq(m0);
559
pmap_resident_count_dec(pmap, 1);
560
vm_page_free(m1);
561
pmap_clear(&l1[j]);
562
}
563
564
pmap_resident_count_dec(pmap, 1);
565
vm_page_free(m0);
566
pmap_clear(&pmap->pm_top[i]);
567
}
568
569
KASSERT(pmap->sp_resident_count == 0,
570
("Invalid resident count %jd", pmap->sp_resident_count));
571
572
PMAP_UNLOCK(pmap);
573
}
574
575
static void
576
iommu_pmap_remove_pages_sv39(struct riscv_iommu_pmap *pmap)
577
{
578
pd_entry_t l1e, *l2, l2e, *l3, l3e;
579
vm_paddr_t pa1, pa;
580
vm_page_t m1, m;
581
int j, k, l;
582
583
PMAP_LOCK(pmap);
584
585
for (j = 0; j < Ln_ENTRIES; j++) {
586
l1e = pmap->pm_top[j];
587
if ((l1e & PTE_V) == 0)
588
continue;
589
pa1 = PTE_TO_PHYS(l1e);
590
m1 = PHYS_TO_VM_PAGE(pa1);
591
l2 = (pd_entry_t *)PHYS_TO_DMAP(pa1);
592
593
for (k = 0; k < Ln_ENTRIES; k++) {
594
l2e = l2[k];
595
if ((l2e & PTE_V) == 0)
596
continue;
597
pa = PTE_TO_PHYS(l2e);
598
m = PHYS_TO_VM_PAGE(pa);
599
l3 = (pt_entry_t *)PHYS_TO_DMAP(pa);
600
601
for (l = 0; l < Ln_ENTRIES; l++) {
602
l3e = l3[l];
603
if ((l3e & PTE_V) == 0)
604
continue;
605
panic("%s: l3e found (idx %d %d %d)",
606
__func__, j, k, l);
607
}
608
609
vm_page_unwire_noq(m1);
610
vm_page_unwire_noq(m);
611
pmap_resident_count_dec(pmap, 1);
612
vm_page_free(m);
613
pmap_clear(&l2[k]);
614
}
615
616
pmap_resident_count_dec(pmap, 1);
617
vm_page_free(m1);
618
pmap_clear(&pmap->pm_top[j]);
619
}
620
621
KASSERT(pmap->sp_resident_count == 0,
622
("Invalid resident count %jd", pmap->sp_resident_count));
623
624
PMAP_UNLOCK(pmap);
625
}
626
627
void
628
iommu_pmap_remove_pages(struct riscv_iommu_pmap *pmap)
629
{
630
631
switch (pmap->pm_mode) {
632
case PMAP_MODE_SV39:
633
iommu_pmap_remove_pages_sv39(pmap);
634
break;
635
case PMAP_MODE_SV48:
636
iommu_pmap_remove_pages_sv48(pmap);
637
break;
638
default:
639
panic("Unknown virtual memory system");
640
}
641
}
642
643