Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm64/iommu/iommu_pmap.c
39478 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2020-2021 Ruslan Bukin <[email protected]>
5
* Copyright (c) 2014-2021 Andrew Turner
6
* Copyright (c) 2014-2016 The FreeBSD Foundation
7
* All rights reserved.
8
*
9
* This work was supported by Innovate UK project 105694, "Digital Security
10
* by Design (DSbD) Technology Platform Prototype".
11
*
12
* Redistribution and use in source and binary forms, with or without
13
* modification, are permitted provided that the following conditions
14
* are met:
15
* 1. Redistributions of source code must retain the above copyright
16
* notice, this list of conditions and the following disclaimer.
17
* 2. Redistributions in binary form must reproduce the above copyright
18
* notice, this list of conditions and the following disclaimer in the
19
* documentation and/or other materials provided with the distribution.
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
* SUCH DAMAGE.
32
*/
33
34
#include <sys/cdefs.h>
35
/*
36
* Manages physical address maps for ARM SMMUv3 and ARM Mali GPU.
37
*/
38
39
#include "opt_vm.h"
40
41
#include <sys/param.h>
42
#include <sys/systm.h>
43
#include <sys/ktr.h>
44
#include <sys/lock.h>
45
#include <sys/mutex.h>
46
#include <sys/rwlock.h>
47
48
#include <vm/vm.h>
49
#include <vm/vm_param.h>
50
#include <vm/vm_page.h>
51
#include <vm/vm_map.h>
52
#include <vm/vm_object.h>
53
#include <vm/vm_pageout.h>
54
#include <vm/vm_radix.h>
55
56
#include <machine/machdep.h>
57
58
#include <arm64/iommu/iommu_pmap.h>
59
#include <arm64/iommu/iommu_pte.h>
60
61
#define IOMMU_PAGE_SIZE 4096
62
63
#define SMMU_PMAP_LOCK(pmap) mtx_lock(&(pmap)->sp_mtx)
64
#define SMMU_PMAP_UNLOCK(pmap) mtx_unlock(&(pmap)->sp_mtx)
65
#define SMMU_PMAP_LOCK_ASSERT(pmap, type) \
66
mtx_assert(&(pmap)->sp_mtx, (type))
67
68
#define NL0PG (IOMMU_PAGE_SIZE/(sizeof (pd_entry_t)))
69
#define NL1PG (IOMMU_PAGE_SIZE/(sizeof (pd_entry_t)))
70
#define NL2PG (IOMMU_PAGE_SIZE/(sizeof (pd_entry_t)))
71
#define NL3PG (IOMMU_PAGE_SIZE/(sizeof (pt_entry_t)))
72
73
#define NUL0E IOMMU_L0_ENTRIES
74
#define NUL1E (NUL0E * NL1PG)
75
#define NUL2E (NUL1E * NL2PG)
76
77
#define smmu_l0_pindex(v) (NUL2E + NUL1E + ((v) >> IOMMU_L0_SHIFT))
78
#define smmu_l1_pindex(v) (NUL2E + ((v) >> IOMMU_L1_SHIFT))
79
#define smmu_l2_pindex(v) ((v) >> IOMMU_L2_SHIFT)
80
81
#define smmu_l0_index(va) (((va) >> IOMMU_L0_SHIFT) & IOMMU_L0_ADDR_MASK)
82
#define smmu_l1_index(va) (((va) >> IOMMU_L1_SHIFT) & IOMMU_Ln_ADDR_MASK)
83
#define smmu_l2_index(va) (((va) >> IOMMU_L2_SHIFT) & IOMMU_Ln_ADDR_MASK)
84
#define smmu_l3_index(va) (((va) >> IOMMU_L3_SHIFT) & IOMMU_Ln_ADDR_MASK)
85
86
static vm_page_t _pmap_alloc_l3(struct smmu_pmap *pmap, vm_pindex_t ptepindex);
87
static void _smmu_pmap_unwire_l3(struct smmu_pmap *pmap, vm_offset_t va,
88
vm_page_t m, struct spglist *free);
89
90
/*
91
* These load the old table data and store the new value.
92
* They need to be atomic as the System MMU may write to the table at
93
* the same time as the CPU.
94
*/
95
#define smmu_pmap_load(table) (*table)
96
#define smmu_pmap_clear(table) atomic_store_64(table, 0)
97
#define smmu_pmap_store(table, entry) atomic_store_64(table, entry)
98
99
/********************/
100
/* Inline functions */
101
/********************/
102
103
static __inline pd_entry_t *
104
smmu_pmap_l0(struct smmu_pmap *pmap, vm_offset_t va)
105
{
106
107
return (&pmap->sp_l0[smmu_l0_index(va)]);
108
}
109
110
static __inline pd_entry_t *
111
smmu_pmap_l0_to_l1(pd_entry_t *l0, vm_offset_t va)
112
{
113
pd_entry_t *l1;
114
115
l1 = (pd_entry_t *)PHYS_TO_DMAP(smmu_pmap_load(l0) & ~ATTR_MASK);
116
return (&l1[smmu_l1_index(va)]);
117
}
118
119
static __inline pd_entry_t *
120
smmu_pmap_l1(struct smmu_pmap *pmap, vm_offset_t va)
121
{
122
pd_entry_t *l0;
123
124
l0 = smmu_pmap_l0(pmap, va);
125
if ((smmu_pmap_load(l0) & ATTR_DESCR_MASK) != IOMMU_L0_TABLE)
126
return (NULL);
127
128
return (smmu_pmap_l0_to_l1(l0, va));
129
}
130
131
static __inline pd_entry_t *
132
smmu_pmap_l1_to_l2(pd_entry_t *l1p, vm_offset_t va)
133
{
134
pd_entry_t l1, *l2p;
135
136
l1 = smmu_pmap_load(l1p);
137
138
/*
139
* The valid bit may be clear if pmap_update_entry() is concurrently
140
* modifying the entry, so for KVA only the entry type may be checked.
141
*/
142
KASSERT(va >= VM_MAX_USER_ADDRESS || (l1 & ATTR_DESCR_VALID) != 0,
143
("%s: L1 entry %#lx for %#lx is invalid", __func__, l1, va));
144
KASSERT((l1 & ATTR_DESCR_TYPE_MASK) == ATTR_DESCR_TYPE_TABLE,
145
("%s: L1 entry %#lx for %#lx is a leaf", __func__, l1, va));
146
l2p = (pd_entry_t *)PHYS_TO_DMAP(l1 & ~ATTR_MASK);
147
return (&l2p[smmu_l2_index(va)]);
148
}
149
150
static __inline pd_entry_t *
151
smmu_pmap_l2(struct smmu_pmap *pmap, vm_offset_t va)
152
{
153
pd_entry_t *l1;
154
155
l1 = smmu_pmap_l1(pmap, va);
156
if ((smmu_pmap_load(l1) & ATTR_DESCR_MASK) != IOMMU_L1_TABLE)
157
return (NULL);
158
159
return (smmu_pmap_l1_to_l2(l1, va));
160
}
161
162
static __inline pt_entry_t *
163
smmu_pmap_l2_to_l3(pd_entry_t *l2p, vm_offset_t va)
164
{
165
pd_entry_t l2;
166
pt_entry_t *l3p;
167
168
l2 = smmu_pmap_load(l2p);
169
170
/*
171
* The valid bit may be clear if pmap_update_entry() is concurrently
172
* modifying the entry, so for KVA only the entry type may be checked.
173
*/
174
KASSERT(va >= VM_MAX_USER_ADDRESS || (l2 & ATTR_DESCR_VALID) != 0,
175
("%s: L2 entry %#lx for %#lx is invalid", __func__, l2, va));
176
KASSERT((l2 & ATTR_DESCR_TYPE_MASK) == ATTR_DESCR_TYPE_TABLE,
177
("%s: L2 entry %#lx for %#lx is a leaf", __func__, l2, va));
178
l3p = (pt_entry_t *)PHYS_TO_DMAP(l2 & ~ATTR_MASK);
179
return (&l3p[smmu_l3_index(va)]);
180
}
181
182
/*
183
* Returns the lowest valid pde for a given virtual address.
184
* The next level may or may not point to a valid page or block.
185
*/
186
static __inline pd_entry_t *
187
smmu_pmap_pde(struct smmu_pmap *pmap, vm_offset_t va, int *level)
188
{
189
pd_entry_t *l0, *l1, *l2, desc;
190
191
l0 = smmu_pmap_l0(pmap, va);
192
desc = smmu_pmap_load(l0) & ATTR_DESCR_MASK;
193
if (desc != IOMMU_L0_TABLE) {
194
*level = -1;
195
return (NULL);
196
}
197
198
l1 = smmu_pmap_l0_to_l1(l0, va);
199
desc = smmu_pmap_load(l1) & ATTR_DESCR_MASK;
200
if (desc != IOMMU_L1_TABLE) {
201
*level = 0;
202
return (l0);
203
}
204
205
l2 = smmu_pmap_l1_to_l2(l1, va);
206
desc = smmu_pmap_load(l2) & ATTR_DESCR_MASK;
207
if (desc != IOMMU_L2_TABLE) {
208
*level = 1;
209
return (l1);
210
}
211
212
*level = 2;
213
return (l2);
214
}
215
216
/*
217
* Returns the lowest valid pte block or table entry for a given virtual
218
* address. If there are no valid entries return NULL and set the level to
219
* the first invalid level.
220
*/
221
static __inline pt_entry_t *
222
smmu_pmap_pte(struct smmu_pmap *pmap, vm_offset_t va, int *level)
223
{
224
pd_entry_t *l1, *l2, desc;
225
pt_entry_t *l3;
226
227
l1 = smmu_pmap_l1(pmap, va);
228
if (l1 == NULL) {
229
*level = 0;
230
return (NULL);
231
}
232
desc = smmu_pmap_load(l1) & ATTR_DESCR_MASK;
233
if (desc == IOMMU_L1_BLOCK) {
234
*level = 1;
235
return (l1);
236
}
237
238
if (desc != IOMMU_L1_TABLE) {
239
*level = 1;
240
return (NULL);
241
}
242
243
l2 = smmu_pmap_l1_to_l2(l1, va);
244
desc = smmu_pmap_load(l2) & ATTR_DESCR_MASK;
245
if (desc == IOMMU_L2_BLOCK) {
246
*level = 2;
247
return (l2);
248
}
249
250
if (desc != IOMMU_L2_TABLE) {
251
*level = 2;
252
return (NULL);
253
}
254
255
*level = 3;
256
l3 = smmu_pmap_l2_to_l3(l2, va);
257
if ((smmu_pmap_load(l3) & ATTR_DESCR_MASK) != IOMMU_L3_PAGE)
258
return (NULL);
259
260
return (l3);
261
}
262
263
static __inline int
264
smmu_pmap_l3_valid(pt_entry_t l3)
265
{
266
267
return ((l3 & ATTR_DESCR_MASK) == IOMMU_L3_PAGE);
268
}
269
270
CTASSERT(IOMMU_L1_BLOCK == IOMMU_L2_BLOCK);
271
272
#ifdef INVARIANTS
273
static __inline void
274
smmu_pmap_resident_count_inc(struct smmu_pmap *pmap, int count)
275
{
276
277
SMMU_PMAP_LOCK_ASSERT(pmap, MA_OWNED);
278
pmap->sp_resident_count += count;
279
}
280
281
static __inline void
282
smmu_pmap_resident_count_dec(struct smmu_pmap *pmap, int count)
283
{
284
285
SMMU_PMAP_LOCK_ASSERT(pmap, MA_OWNED);
286
KASSERT(pmap->sp_resident_count >= count,
287
("pmap %p resident count underflow %ld %d", pmap,
288
pmap->sp_resident_count, count));
289
pmap->sp_resident_count -= count;
290
}
291
#else
292
static __inline void
293
smmu_pmap_resident_count_inc(struct smmu_pmap *pmap, int count)
294
{
295
}
296
297
static __inline void
298
smmu_pmap_resident_count_dec(struct smmu_pmap *pmap, int count)
299
{
300
}
301
#endif
302
303
/***************************************************
304
* Page table page management routines.....
305
***************************************************/
306
/*
307
* Schedule the specified unused page table page to be freed. Specifically,
308
* add the page to the specified list of pages that will be released to the
309
* physical memory manager after the TLB has been updated.
310
*/
311
static __inline void
312
smmu_pmap_add_delayed_free_list(vm_page_t m, struct spglist *free,
313
boolean_t set_PG_ZERO)
314
{
315
316
if (set_PG_ZERO)
317
m->flags |= PG_ZERO;
318
else
319
m->flags &= ~PG_ZERO;
320
SLIST_INSERT_HEAD(free, m, plinks.s.ss);
321
}
322
323
/***************************************************
324
* Low level mapping routines.....
325
***************************************************/
326
327
/*
328
* Decrements a page table page's reference count, which is used to record the
329
* number of valid page table entries within the page. If the reference count
330
* drops to zero, then the page table page is unmapped. Returns TRUE if the
331
* page table page was unmapped and FALSE otherwise.
332
*/
333
static inline boolean_t
334
smmu_pmap_unwire_l3(struct smmu_pmap *pmap, vm_offset_t va, vm_page_t m,
335
struct spglist *free)
336
{
337
338
--m->ref_count;
339
if (m->ref_count == 0) {
340
_smmu_pmap_unwire_l3(pmap, va, m, free);
341
return (TRUE);
342
} else
343
return (FALSE);
344
}
345
346
static void
347
_smmu_pmap_unwire_l3(struct smmu_pmap *pmap, vm_offset_t va, vm_page_t m,
348
struct spglist *free)
349
{
350
351
SMMU_PMAP_LOCK_ASSERT(pmap, MA_OWNED);
352
/*
353
* unmap the page table page
354
*/
355
if (m->pindex >= (NUL2E + NUL1E)) {
356
/* l1 page */
357
pd_entry_t *l0;
358
359
l0 = smmu_pmap_l0(pmap, va);
360
smmu_pmap_clear(l0);
361
} else if (m->pindex >= NUL2E) {
362
/* l2 page */
363
pd_entry_t *l1;
364
365
l1 = smmu_pmap_l1(pmap, va);
366
smmu_pmap_clear(l1);
367
} else {
368
/* l3 page */
369
pd_entry_t *l2;
370
371
l2 = smmu_pmap_l2(pmap, va);
372
smmu_pmap_clear(l2);
373
}
374
smmu_pmap_resident_count_dec(pmap, 1);
375
if (m->pindex < NUL2E) {
376
/* We just released an l3, unhold the matching l2 */
377
pd_entry_t *l1, tl1;
378
vm_page_t l2pg;
379
380
l1 = smmu_pmap_l1(pmap, va);
381
tl1 = smmu_pmap_load(l1);
382
l2pg = PHYS_TO_VM_PAGE(tl1 & ~ATTR_MASK);
383
smmu_pmap_unwire_l3(pmap, va, l2pg, free);
384
} else if (m->pindex < (NUL2E + NUL1E)) {
385
/* We just released an l2, unhold the matching l1 */
386
pd_entry_t *l0, tl0;
387
vm_page_t l1pg;
388
389
l0 = smmu_pmap_l0(pmap, va);
390
tl0 = smmu_pmap_load(l0);
391
l1pg = PHYS_TO_VM_PAGE(tl0 & ~ATTR_MASK);
392
smmu_pmap_unwire_l3(pmap, va, l1pg, free);
393
}
394
395
/*
396
* Put page on a list so that it is released after
397
* *ALL* TLB shootdown is done
398
*/
399
smmu_pmap_add_delayed_free_list(m, free, TRUE);
400
}
401
402
int
403
smmu_pmap_pinit(struct smmu_pmap *pmap)
404
{
405
vm_page_t m;
406
407
/*
408
* allocate the l0 page
409
*/
410
m = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_WIRED |
411
VM_ALLOC_ZERO);
412
pmap->sp_l0_paddr = VM_PAGE_TO_PHYS(m);
413
pmap->sp_l0 = (pd_entry_t *)PHYS_TO_DMAP(pmap->sp_l0_paddr);
414
415
#ifdef INVARIANTS
416
pmap->sp_resident_count = 0;
417
#endif
418
mtx_init(&pmap->sp_mtx, "smmu pmap", NULL, MTX_DEF);
419
420
return (1);
421
}
422
423
/*
424
* This routine is called if the desired page table page does not exist.
425
*
426
* If page table page allocation fails, this routine may sleep before
427
* returning NULL. It sleeps only if a lock pointer was given.
428
*
429
* Note: If a page allocation fails at page table level two or three,
430
* one or two pages may be held during the wait, only to be released
431
* afterwards. This conservative approach is easily argued to avoid
432
* race conditions.
433
*/
434
static vm_page_t
435
_pmap_alloc_l3(struct smmu_pmap *pmap, vm_pindex_t ptepindex)
436
{
437
vm_page_t m, l1pg, l2pg;
438
439
SMMU_PMAP_LOCK_ASSERT(pmap, MA_OWNED);
440
441
/*
442
* Allocate a page table page.
443
*/
444
if ((m = vm_page_alloc_noobj(VM_ALLOC_WIRED | VM_ALLOC_ZERO)) == NULL) {
445
/*
446
* Indicate the need to retry. While waiting, the page table
447
* page may have been allocated.
448
*/
449
return (NULL);
450
}
451
m->pindex = ptepindex;
452
453
/*
454
* Because of AArch64's weak memory consistency model, we must have a
455
* barrier here to ensure that the stores for zeroing "m", whether by
456
* pmap_zero_page() or an earlier function, are visible before adding
457
* "m" to the page table. Otherwise, a page table walk by another
458
* processor's MMU could see the mapping to "m" and a stale, non-zero
459
* PTE within "m".
460
*/
461
dmb(ishst);
462
463
/*
464
* Map the pagetable page into the process address space, if
465
* it isn't already there.
466
*/
467
468
if (ptepindex >= (NUL2E + NUL1E)) {
469
pd_entry_t *l0;
470
vm_pindex_t l0index;
471
472
l0index = ptepindex - (NUL2E + NUL1E);
473
l0 = &pmap->sp_l0[l0index];
474
smmu_pmap_store(l0, VM_PAGE_TO_PHYS(m) | IOMMU_L0_TABLE);
475
} else if (ptepindex >= NUL2E) {
476
vm_pindex_t l0index, l1index;
477
pd_entry_t *l0, *l1;
478
pd_entry_t tl0;
479
480
l1index = ptepindex - NUL2E;
481
l0index = l1index >> IOMMU_L0_ENTRIES_SHIFT;
482
483
l0 = &pmap->sp_l0[l0index];
484
tl0 = smmu_pmap_load(l0);
485
if (tl0 == 0) {
486
/* recurse for allocating page dir */
487
if (_pmap_alloc_l3(pmap, NUL2E + NUL1E + l0index)
488
== NULL) {
489
vm_page_unwire_noq(m);
490
vm_page_free_zero(m);
491
return (NULL);
492
}
493
} else {
494
l1pg = PHYS_TO_VM_PAGE(tl0 & ~ATTR_MASK);
495
l1pg->ref_count++;
496
}
497
498
l1 = (pd_entry_t *)PHYS_TO_DMAP(smmu_pmap_load(l0) &~ATTR_MASK);
499
l1 = &l1[ptepindex & Ln_ADDR_MASK];
500
smmu_pmap_store(l1, VM_PAGE_TO_PHYS(m) | IOMMU_L1_TABLE);
501
} else {
502
vm_pindex_t l0index, l1index;
503
pd_entry_t *l0, *l1, *l2;
504
pd_entry_t tl0, tl1;
505
506
l1index = ptepindex >> IOMMU_Ln_ENTRIES_SHIFT;
507
l0index = l1index >> IOMMU_L0_ENTRIES_SHIFT;
508
509
l0 = &pmap->sp_l0[l0index];
510
tl0 = smmu_pmap_load(l0);
511
if (tl0 == 0) {
512
/* recurse for allocating page dir */
513
if (_pmap_alloc_l3(pmap, NUL2E + l1index) == NULL) {
514
vm_page_unwire_noq(m);
515
vm_page_free_zero(m);
516
return (NULL);
517
}
518
tl0 = smmu_pmap_load(l0);
519
l1 = (pd_entry_t *)PHYS_TO_DMAP(tl0 & ~ATTR_MASK);
520
l1 = &l1[l1index & Ln_ADDR_MASK];
521
} else {
522
l1 = (pd_entry_t *)PHYS_TO_DMAP(tl0 & ~ATTR_MASK);
523
l1 = &l1[l1index & Ln_ADDR_MASK];
524
tl1 = smmu_pmap_load(l1);
525
if (tl1 == 0) {
526
/* recurse for allocating page dir */
527
if (_pmap_alloc_l3(pmap, NUL2E + l1index)
528
== NULL) {
529
vm_page_unwire_noq(m);
530
vm_page_free_zero(m);
531
return (NULL);
532
}
533
} else {
534
l2pg = PHYS_TO_VM_PAGE(tl1 & ~ATTR_MASK);
535
l2pg->ref_count++;
536
}
537
}
538
539
l2 = (pd_entry_t *)PHYS_TO_DMAP(smmu_pmap_load(l1) &~ATTR_MASK);
540
l2 = &l2[ptepindex & Ln_ADDR_MASK];
541
smmu_pmap_store(l2, VM_PAGE_TO_PHYS(m) | IOMMU_L2_TABLE);
542
}
543
544
smmu_pmap_resident_count_inc(pmap, 1);
545
546
return (m);
547
}
548
549
/***************************************************
550
* Pmap allocation/deallocation routines.
551
***************************************************/
552
553
/*
554
* Release any resources held by the given physical map.
555
* Called when a pmap initialized by pmap_pinit is being released.
556
* Should only be called if the map contains no valid mappings.
557
*/
558
void
559
smmu_pmap_release(struct smmu_pmap *pmap)
560
{
561
vm_page_t m;
562
563
KASSERT(pmap->sp_resident_count == 0,
564
("pmap_release: pmap resident count %ld != 0",
565
pmap->sp_resident_count));
566
567
m = PHYS_TO_VM_PAGE(pmap->sp_l0_paddr);
568
vm_page_unwire_noq(m);
569
vm_page_free_zero(m);
570
mtx_destroy(&pmap->sp_mtx);
571
}
572
573
/***************************************************
574
* page management routines.
575
***************************************************/
576
577
/*
578
* Add a single Mali GPU entry. This function does not sleep.
579
*/
580
int
581
pmap_gpu_enter(struct smmu_pmap *pmap, vm_offset_t va, vm_paddr_t pa,
582
vm_prot_t prot, u_int flags)
583
{
584
pd_entry_t *pde;
585
pt_entry_t new_l3;
586
pt_entry_t orig_l3 __diagused;
587
pt_entry_t *l3;
588
vm_page_t mpte;
589
pd_entry_t *l1p;
590
pd_entry_t *l2p;
591
int lvl;
592
int rv;
593
594
KASSERT(va < VM_MAXUSER_ADDRESS, ("wrong address space"));
595
KASSERT((va & PAGE_MASK) == 0, ("va is misaligned"));
596
KASSERT((pa & PAGE_MASK) == 0, ("pa is misaligned"));
597
598
new_l3 = (pt_entry_t)(pa | ATTR_SH(ATTR_SH_IS) | IOMMU_L3_BLOCK);
599
600
if ((prot & VM_PROT_WRITE) != 0)
601
new_l3 |= ATTR_S2_S2AP(ATTR_S2_S2AP_WRITE);
602
if ((prot & VM_PROT_READ) != 0)
603
new_l3 |= ATTR_S2_S2AP(ATTR_S2_S2AP_READ);
604
if ((prot & VM_PROT_EXECUTE) == 0)
605
new_l3 |= ATTR_S2_XN(ATTR_S2_XN_ALL);
606
607
CTR2(KTR_PMAP, "pmap_gpu_enter: %.16lx -> %.16lx", va, pa);
608
609
SMMU_PMAP_LOCK(pmap);
610
611
/*
612
* In the case that a page table page is not
613
* resident, we are creating it here.
614
*/
615
retry:
616
pde = smmu_pmap_pde(pmap, va, &lvl);
617
if (pde != NULL && lvl == 2) {
618
l3 = smmu_pmap_l2_to_l3(pde, va);
619
} else {
620
mpte = _pmap_alloc_l3(pmap, smmu_l2_pindex(va));
621
if (mpte == NULL) {
622
CTR0(KTR_PMAP, "pmap_enter: mpte == NULL");
623
rv = KERN_RESOURCE_SHORTAGE;
624
goto out;
625
}
626
627
/*
628
* Ensure newly created l1, l2 are visible to GPU.
629
* l0 is already visible by similar call in panfrost driver.
630
* The cache entry for l3 handled below.
631
*/
632
633
l1p = smmu_pmap_l1(pmap, va);
634
l2p = smmu_pmap_l2(pmap, va);
635
cpu_dcache_wb_range(l1p, sizeof(pd_entry_t));
636
cpu_dcache_wb_range(l2p, sizeof(pd_entry_t));
637
638
goto retry;
639
}
640
641
orig_l3 = smmu_pmap_load(l3);
642
KASSERT(!smmu_pmap_l3_valid(orig_l3), ("l3 is valid"));
643
644
/* New mapping */
645
smmu_pmap_store(l3, new_l3);
646
647
cpu_dcache_wb_range(l3, sizeof(pt_entry_t));
648
649
smmu_pmap_resident_count_inc(pmap, 1);
650
dsb(ishst);
651
652
rv = KERN_SUCCESS;
653
out:
654
SMMU_PMAP_UNLOCK(pmap);
655
656
return (rv);
657
}
658
659
/*
660
* Remove a single Mali GPU entry.
661
*/
662
int
663
pmap_gpu_remove(struct smmu_pmap *pmap, vm_offset_t va)
664
{
665
pd_entry_t *pde;
666
pt_entry_t *pte;
667
int lvl;
668
int rc;
669
670
KASSERT((va & PAGE_MASK) == 0, ("va is misaligned"));
671
672
SMMU_PMAP_LOCK(pmap);
673
674
pde = smmu_pmap_pde(pmap, va, &lvl);
675
if (pde == NULL || lvl != 2) {
676
rc = KERN_FAILURE;
677
goto out;
678
}
679
680
pte = smmu_pmap_l2_to_l3(pde, va);
681
682
smmu_pmap_resident_count_dec(pmap, 1);
683
smmu_pmap_clear(pte);
684
cpu_dcache_wb_range(pte, sizeof(pt_entry_t));
685
rc = KERN_SUCCESS;
686
687
out:
688
SMMU_PMAP_UNLOCK(pmap);
689
690
return (rc);
691
}
692
693
/*
694
* Add a single SMMU entry. This function does not sleep.
695
*/
696
int
697
smmu_pmap_enter(struct smmu_pmap *pmap, vm_offset_t va, vm_paddr_t pa,
698
vm_prot_t prot, u_int flags)
699
{
700
pd_entry_t *pde;
701
pt_entry_t new_l3;
702
pt_entry_t orig_l3 __diagused;
703
pt_entry_t *l3;
704
vm_page_t mpte;
705
int lvl;
706
int rv;
707
708
KASSERT(va < VM_MAXUSER_ADDRESS, ("wrong address space"));
709
710
va = trunc_page(va);
711
new_l3 = (pt_entry_t)(pa | ATTR_AF | ATTR_SH(ATTR_SH_IS) |
712
ATTR_S1_IDX(VM_MEMATTR_DEVICE) | IOMMU_L3_PAGE);
713
if ((prot & VM_PROT_WRITE) == 0)
714
new_l3 |= ATTR_S1_AP(ATTR_S1_AP_RO);
715
new_l3 |= ATTR_S1_XN; /* Execute never. */
716
new_l3 |= ATTR_S1_AP(ATTR_S1_AP_USER);
717
new_l3 |= ATTR_S1_nG; /* Non global. */
718
719
CTR2(KTR_PMAP, "pmap_senter: %.16lx -> %.16lx", va, pa);
720
721
SMMU_PMAP_LOCK(pmap);
722
723
/*
724
* In the case that a page table page is not
725
* resident, we are creating it here.
726
*/
727
retry:
728
pde = smmu_pmap_pde(pmap, va, &lvl);
729
if (pde != NULL && lvl == 2) {
730
l3 = smmu_pmap_l2_to_l3(pde, va);
731
} else {
732
mpte = _pmap_alloc_l3(pmap, smmu_l2_pindex(va));
733
if (mpte == NULL) {
734
CTR0(KTR_PMAP, "pmap_enter: mpte == NULL");
735
rv = KERN_RESOURCE_SHORTAGE;
736
goto out;
737
}
738
goto retry;
739
}
740
741
orig_l3 = smmu_pmap_load(l3);
742
KASSERT(!smmu_pmap_l3_valid(orig_l3), ("l3 is valid"));
743
744
/* New mapping */
745
smmu_pmap_store(l3, new_l3);
746
smmu_pmap_resident_count_inc(pmap, 1);
747
dsb(ishst);
748
749
rv = KERN_SUCCESS;
750
out:
751
SMMU_PMAP_UNLOCK(pmap);
752
753
return (rv);
754
}
755
756
/*
757
* Remove a single SMMU entry.
758
*/
759
int
760
smmu_pmap_remove(struct smmu_pmap *pmap, vm_offset_t va)
761
{
762
pt_entry_t *pte;
763
int lvl;
764
int rc;
765
766
SMMU_PMAP_LOCK(pmap);
767
768
pte = smmu_pmap_pte(pmap, va, &lvl);
769
KASSERT(lvl == 3,
770
("Invalid SMMU pagetable level: %d != 3", lvl));
771
772
if (pte != NULL) {
773
smmu_pmap_resident_count_dec(pmap, 1);
774
smmu_pmap_clear(pte);
775
rc = KERN_SUCCESS;
776
} else
777
rc = KERN_FAILURE;
778
779
SMMU_PMAP_UNLOCK(pmap);
780
781
return (rc);
782
}
783
784
/*
785
* Remove all the allocated L1, L2 pages from SMMU pmap.
786
* All the L3 entires must be cleared in advance, otherwise
787
* this function panics.
788
*/
789
void
790
smmu_pmap_remove_pages(struct smmu_pmap *pmap)
791
{
792
pd_entry_t l0e, *l1, l1e, *l2, l2e;
793
pt_entry_t *l3, l3e;
794
vm_page_t m, m0, m1;
795
vm_paddr_t pa;
796
vm_paddr_t pa0;
797
vm_paddr_t pa1;
798
int i, j, k, l;
799
800
SMMU_PMAP_LOCK(pmap);
801
802
for (i = 0; i < IOMMU_L0_ENTRIES; i++) {
803
l0e = pmap->sp_l0[i];
804
if ((l0e & ATTR_DESCR_VALID) == 0) {
805
continue;
806
}
807
pa0 = l0e & ~ATTR_MASK;
808
m0 = PHYS_TO_VM_PAGE(pa0);
809
l1 = (pd_entry_t *)PHYS_TO_DMAP(pa0);
810
811
for (j = 0; j < IOMMU_Ln_ENTRIES; j++) {
812
l1e = l1[j];
813
if ((l1e & ATTR_DESCR_VALID) == 0) {
814
continue;
815
}
816
if ((l1e & ATTR_DESCR_MASK) == IOMMU_L1_BLOCK) {
817
continue;
818
}
819
pa1 = l1e & ~ATTR_MASK;
820
m1 = PHYS_TO_VM_PAGE(pa1);
821
l2 = (pd_entry_t *)PHYS_TO_DMAP(pa1);
822
823
for (k = 0; k < IOMMU_Ln_ENTRIES; k++) {
824
l2e = l2[k];
825
if ((l2e & ATTR_DESCR_VALID) == 0) {
826
continue;
827
}
828
pa = l2e & ~ATTR_MASK;
829
m = PHYS_TO_VM_PAGE(pa);
830
l3 = (pt_entry_t *)PHYS_TO_DMAP(pa);
831
832
for (l = 0; l < IOMMU_Ln_ENTRIES; l++) {
833
l3e = l3[l];
834
if ((l3e & ATTR_DESCR_VALID) == 0)
835
continue;
836
panic(
837
"%s: l3e found (indexes %d %d %d %d)",
838
__func__, i, j, k, l);
839
}
840
841
vm_page_unwire_noq(m1);
842
vm_page_unwire_noq(m);
843
smmu_pmap_resident_count_dec(pmap, 1);
844
vm_page_free(m);
845
smmu_pmap_clear(&l2[k]);
846
}
847
848
vm_page_unwire_noq(m0);
849
smmu_pmap_resident_count_dec(pmap, 1);
850
vm_page_free(m1);
851
smmu_pmap_clear(&l1[j]);
852
}
853
854
smmu_pmap_resident_count_dec(pmap, 1);
855
vm_page_free(m0);
856
smmu_pmap_clear(&pmap->sp_l0[i]);
857
}
858
859
KASSERT(pmap->sp_resident_count == 0,
860
("Invalid resident count %jd", pmap->sp_resident_count));
861
862
SMMU_PMAP_UNLOCK(pmap);
863
}
864
865