1646a8671SFrançois Tigeot /*
2106adca4SFrançois Tigeot * Copyright (c) 2017-2019 François Tigeot <ftigeot@wolfpond.org>
3646a8671SFrançois Tigeot * All rights reserved.
4646a8671SFrançois Tigeot *
5646a8671SFrançois Tigeot * Redistribution and use in source and binary forms, with or without
6646a8671SFrançois Tigeot * modification, are permitted provided that the following conditions
7646a8671SFrançois Tigeot * are met:
8646a8671SFrançois Tigeot * 1. Redistributions of source code must retain the above copyright
9646a8671SFrançois Tigeot * notice unmodified, this list of conditions, and the following
10646a8671SFrançois Tigeot * disclaimer.
11646a8671SFrançois Tigeot * 2. Redistributions in binary form must reproduce the above copyright
12646a8671SFrançois Tigeot * notice, this list of conditions and the following disclaimer in the
13646a8671SFrançois Tigeot * documentation and/or other materials provided with the distribution.
14646a8671SFrançois Tigeot *
15646a8671SFrançois Tigeot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16646a8671SFrançois Tigeot * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17646a8671SFrançois Tigeot * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18646a8671SFrançois Tigeot * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19646a8671SFrançois Tigeot * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20646a8671SFrançois Tigeot * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21646a8671SFrançois Tigeot * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22646a8671SFrançois Tigeot * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23646a8671SFrançois Tigeot * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24646a8671SFrançois Tigeot * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25646a8671SFrançois Tigeot */
26646a8671SFrançois Tigeot
27646a8671SFrançois Tigeot #include <sys/queue.h>
282cce721cSFrançois Tigeot #include <vm/vm_extern.h>
29646a8671SFrançois Tigeot
30646a8671SFrançois Tigeot #include <linux/vmalloc.h>
31646a8671SFrançois Tigeot #include <linux/slab.h>
32646a8671SFrançois Tigeot #include <linux/mm.h>
33646a8671SFrançois Tigeot
34646a8671SFrançois Tigeot struct vmap {
35646a8671SFrançois Tigeot void *addr;
36646a8671SFrançois Tigeot int npages;
37646a8671SFrançois Tigeot SLIST_ENTRY(vmap) vm_vmaps;
38646a8671SFrançois Tigeot };
39646a8671SFrançois Tigeot
40d1af0a4cSFrançois Tigeot struct lock vmap_lock = LOCK_INITIALIZER("dlvml", 0, LK_CANRECURSE);
41d1af0a4cSFrançois Tigeot
42646a8671SFrançois Tigeot SLIST_HEAD(vmap_list_head, vmap) vmap_list = SLIST_HEAD_INITIALIZER(vmap_list);
43646a8671SFrançois Tigeot
44646a8671SFrançois Tigeot /* vmap: map an array of pages into virtually contiguous space */
45646a8671SFrançois Tigeot void *
vmap(struct page ** pages,unsigned int count,unsigned long flags,pgprot_t prot)46f0bba3d1SFrançois Tigeot vmap(struct page **pages, unsigned int count,
47b3816793SFrançois Tigeot unsigned long flags, pgprot_t prot)
48646a8671SFrançois Tigeot {
49646a8671SFrançois Tigeot struct vmap *vmp;
50646a8671SFrançois Tigeot vm_offset_t off;
51646a8671SFrançois Tigeot size_t size;
52646a8671SFrançois Tigeot
53646a8671SFrançois Tigeot vmp = kmalloc(sizeof(struct vmap), M_DRM, M_WAITOK | M_ZERO);
54646a8671SFrançois Tigeot
55646a8671SFrançois Tigeot size = count * PAGE_SIZE;
56*9eb96077SSergey Zigachev off = kmem_alloc_nofault(kernel_map, size,
57646a8671SFrançois Tigeot VM_SUBSYS_DRM_VMAP, PAGE_SIZE);
58646a8671SFrançois Tigeot if (off == 0)
59646a8671SFrançois Tigeot return (NULL);
60646a8671SFrançois Tigeot
61646a8671SFrançois Tigeot vmp->addr = (void *)off;
62646a8671SFrançois Tigeot vmp->npages = count;
63f0bba3d1SFrançois Tigeot pmap_qenter(off, (struct vm_page **)pages, count);
64d1af0a4cSFrançois Tigeot lockmgr(&vmap_lock, LK_EXCLUSIVE);
65646a8671SFrançois Tigeot SLIST_INSERT_HEAD(&vmap_list, vmp, vm_vmaps);
66d1af0a4cSFrançois Tigeot lockmgr(&vmap_lock, LK_RELEASE);
67646a8671SFrançois Tigeot
68646a8671SFrançois Tigeot return (void *)off;
69646a8671SFrançois Tigeot }
70646a8671SFrançois Tigeot
71646a8671SFrançois Tigeot void
vunmap(const void * addr)72646a8671SFrançois Tigeot vunmap(const void *addr)
73646a8671SFrançois Tigeot {
74646a8671SFrançois Tigeot struct vmap *vmp, *tmp_vmp;
75646a8671SFrançois Tigeot size_t size;
76646a8671SFrançois Tigeot
77646a8671SFrançois Tigeot SLIST_FOREACH_MUTABLE(vmp, &vmap_list, vm_vmaps, tmp_vmp) {
78646a8671SFrançois Tigeot if (vmp->addr == addr) {
79646a8671SFrançois Tigeot size = vmp->npages * PAGE_SIZE;
80646a8671SFrançois Tigeot
81646a8671SFrançois Tigeot pmap_qremove((vm_offset_t)addr, vmp->npages);
82*9eb96077SSergey Zigachev kmem_free(kernel_map, (vm_offset_t)addr, size);
83646a8671SFrançois Tigeot goto found;
84646a8671SFrançois Tigeot }
85646a8671SFrançois Tigeot }
86646a8671SFrançois Tigeot
87646a8671SFrançois Tigeot found:
88d1af0a4cSFrançois Tigeot lockmgr(&vmap_lock, LK_EXCLUSIVE);
89646a8671SFrançois Tigeot SLIST_REMOVE(&vmap_list, vmp, vmap, vm_vmaps);
90d1af0a4cSFrançois Tigeot lockmgr(&vmap_lock, LK_RELEASE);
91646a8671SFrançois Tigeot kfree(vmp);
92646a8671SFrançois Tigeot }
93646a8671SFrançois Tigeot
94646a8671SFrançois Tigeot int
is_vmalloc_addr(const void * x)95646a8671SFrançois Tigeot is_vmalloc_addr(const void *x)
96646a8671SFrançois Tigeot {
97646a8671SFrançois Tigeot struct vmap *vmp, *tmp_vmp;
98646a8671SFrançois Tigeot
99646a8671SFrançois Tigeot SLIST_FOREACH_MUTABLE(vmp, &vmap_list, vm_vmaps, tmp_vmp) {
100646a8671SFrançois Tigeot if (vmp->addr == x)
101646a8671SFrançois Tigeot return 1;
102646a8671SFrançois Tigeot }
103646a8671SFrançois Tigeot
104646a8671SFrançois Tigeot return false;
105646a8671SFrançois Tigeot }
1062cce721cSFrançois Tigeot
107106adca4SFrançois Tigeot void *
vmalloc(unsigned long size)108106adca4SFrançois Tigeot vmalloc(unsigned long size)
109106adca4SFrançois Tigeot {
110106adca4SFrançois Tigeot return kmalloc(size, M_DRM, M_WAITOK);
111106adca4SFrançois Tigeot }
112106adca4SFrançois Tigeot
113106adca4SFrançois Tigeot void *
vzalloc(unsigned long size)114106adca4SFrançois Tigeot vzalloc(unsigned long size)
115106adca4SFrançois Tigeot {
116106adca4SFrançois Tigeot return kmalloc(size, M_DRM, M_WAITOK | M_ZERO);
117106adca4SFrançois Tigeot }
118106adca4SFrançois Tigeot
1192cce721cSFrançois Tigeot /* allocate zeroed virtually contiguous memory for userspace */
1202cce721cSFrançois Tigeot void *
vmalloc_user(unsigned long size)1212cce721cSFrançois Tigeot vmalloc_user(unsigned long size)
1222cce721cSFrançois Tigeot {
1232cce721cSFrançois Tigeot return kmalloc(size, M_DRM, M_WAITOK | M_ZERO);
1242cce721cSFrançois Tigeot }
1252cce721cSFrançois Tigeot
1262cce721cSFrançois Tigeot void
vfree(const void * addr)1272cce721cSFrançois Tigeot vfree(const void *addr)
1282cce721cSFrançois Tigeot {
1292cce721cSFrançois Tigeot void *nc_addr;
1302cce721cSFrançois Tigeot
1312cce721cSFrançois Tigeot memcpy(&nc_addr, &addr, sizeof(void *));
1322cce721cSFrançois Tigeot kfree(nc_addr);
1332cce721cSFrançois Tigeot }
1342cecdd68SFrançois Tigeot
1352cecdd68SFrançois Tigeot void *
kvmalloc_array(size_t n,size_t size,gfp_t flags)1362cecdd68SFrançois Tigeot kvmalloc_array(size_t n, size_t size, gfp_t flags)
1372cecdd68SFrançois Tigeot {
1382cecdd68SFrançois Tigeot if (n == 0)
1392cecdd68SFrançois Tigeot return NULL;
1402cecdd68SFrançois Tigeot
1412cecdd68SFrançois Tigeot if (n > SIZE_MAX / size)
1422cecdd68SFrançois Tigeot return NULL;
1432cecdd68SFrançois Tigeot
1442cecdd68SFrançois Tigeot return kmalloc(n * size, M_DRM, flags);
1452cecdd68SFrançois Tigeot }
146