• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010-2011, 2013-2014, 2016-2017 ARM Limited. All rights reserved.
3  *
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  *
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10 
11 #include "mali_kernel_common.h"
12 #include "mali_osk.h"
13 #include "ump_osk.h"
14 #include "ump_kernel_common.h"
15 #include "ump_kernel_types.h"
16 #include "ump_kernel_random_mapping.h"
17 
18 #include <linux/random.h>
19 #include <linux/rbtree.h>
20 #include <linux/sched.h>
21 #include <linux/jiffies.h>
22 
23 
search(struct rb_root * root,int id)24 static ump_dd_mem *search(struct rb_root *root, int id)
25 {
26 	struct rb_node *node = root->rb_node;
27 
28 	while (node) {
29 		ump_dd_mem *e = container_of(node, ump_dd_mem, node);
30 
31 		if (id < e->secure_id) {
32 			node = node->rb_left;
33 		} else if (id > e->secure_id) {
34 			node = node->rb_right;
35 		} else {
36 			return e;
37 		}
38 	}
39 
40 	return NULL;
41 }
42 
insert(struct rb_root * root,int id,ump_dd_mem * mem)43 static mali_bool insert(struct rb_root *root, int id, ump_dd_mem *mem)
44 {
45 	struct rb_node **new = &(root->rb_node);
46 	struct rb_node *parent = NULL;
47 
48 	while (*new) {
49 		ump_dd_mem *this = container_of(*new, ump_dd_mem, node);
50 
51 		parent = *new;
52 		if (id < this->secure_id) {
53 			new = &((*new)->rb_left);
54 		} else if (id > this->secure_id) {
55 			new = &((*new)->rb_right);
56 		} else {
57 			printk(KERN_ERR "UMP: ID already used %x\n", id);
58 			return MALI_FALSE;
59 		}
60 	}
61 
62 	rb_link_node(&mem->node, parent, new);
63 	rb_insert_color(&mem->node, root);
64 
65 	return MALI_TRUE;
66 }
67 
68 
ump_random_mapping_create(void)69 ump_random_mapping *ump_random_mapping_create(void)
70 {
71 	ump_random_mapping *map = _mali_osk_calloc(1, sizeof(ump_random_mapping));
72 
73 	if (NULL == map)
74 		return NULL;
75 
76 	map->lock = _mali_osk_mutex_rw_init(_MALI_OSK_LOCKFLAG_ORDERED,
77 					    _MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP);
78 	if (NULL != map->lock) {
79 		map->root = RB_ROOT;
80 #if UMP_RANDOM_MAP_DELAY
81 		map->failed.count = 0;
82 		map->failed.timestamp = jiffies;
83 #endif
84 		return map;
85 	}
86 	return NULL;
87 }
88 
ump_random_mapping_destroy(ump_random_mapping * map)89 void ump_random_mapping_destroy(ump_random_mapping *map)
90 {
91 	_mali_osk_mutex_rw_term(map->lock);
92 	_mali_osk_free(map);
93 }
94 
ump_random_mapping_insert(ump_random_mapping * map,ump_dd_mem * mem)95 int ump_random_mapping_insert(ump_random_mapping *map, ump_dd_mem *mem)
96 {
97 	_mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RW);
98 
99 	while (1) {
100 		u32 id;
101 
102 		get_random_bytes(&id, sizeof(id));
103 
104 		/* Try a new random number if id happened to be the invalid
105 		 * secure ID (-1). */
106 		if (unlikely(id == UMP_INVALID_SECURE_ID))
107 			continue;
108 
109 		/* Insert into the tree. If the id was already in use, get a
110 		 * new random id and try again. */
111 		if (insert(&map->root, id, mem)) {
112 			mem->secure_id = id;
113 			break;
114 		}
115 	}
116 	_mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RW);
117 
118 	return 0;
119 }
120 
ump_random_mapping_get(ump_random_mapping * map,int id)121 ump_dd_mem *ump_random_mapping_get(ump_random_mapping *map, int id)
122 {
123 	ump_dd_mem *mem = NULL;
124 #if UMP_RANDOM_MAP_DELAY
125 	int do_delay = 0;
126 #endif
127 
128 	DEBUG_ASSERT(map);
129 
130 	_mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RO);
131 	mem = search(&map->root, id);
132 
133 	if (unlikely(NULL == mem)) {
134 #if UMP_RANDOM_MAP_DELAY
135 		map->failed.count++;
136 
137 		if (time_is_before_jiffies(map->failed.timestamp +
138 					   UMP_FAILED_LOOKUP_DELAY * HZ)) {
139 			/* If it is a long time since last failure, reset
140 			 * the counter and skip the delay this time. */
141 			map->failed.count = 0;
142 		} else if (map->failed.count > UMP_FAILED_LOOKUPS_ALLOWED) {
143 			do_delay = 1;
144 		}
145 
146 		map->failed.timestamp = jiffies;
147 #endif /* UMP_RANDOM_MAP_DELAY */
148 	} else {
149 		ump_dd_reference_add(mem);
150 	}
151 	_mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RO);
152 
153 #if UMP_RANDOM_MAP_DELAY
154 	if (do_delay) {
155 		/* Apply delay */
156 		schedule_timeout_killable(UMP_FAILED_LOOKUP_DELAY);
157 	}
158 #endif /* UMP_RANDOM_MAP_DELAY */
159 
160 	return mem;
161 }
162 
ump_random_mapping_remove_internal(ump_random_mapping * map,int id)163 static ump_dd_mem *ump_random_mapping_remove_internal(ump_random_mapping *map, int id)
164 {
165 	ump_dd_mem *mem = NULL;
166 
167 	mem = search(&map->root, id);
168 
169 	if (mem) {
170 		rb_erase(&mem->node, &map->root);
171 	}
172 
173 	return mem;
174 }
175 
ump_random_mapping_put(ump_dd_mem * mem)176 void ump_random_mapping_put(ump_dd_mem *mem)
177 {
178 	int new_ref;
179 
180 	_mali_osk_mutex_rw_wait(device.secure_id_map->lock, _MALI_OSK_LOCKMODE_RW);
181 
182 	new_ref = _ump_osk_atomic_dec_and_read(&mem->ref_count);
183 	DBG_MSG(5, ("Memory reference decremented. ID: %u, new value: %d\n",
184 		    mem->secure_id, new_ref));
185 
186 	if (0 == new_ref) {
187 		DBG_MSG(3, ("Final release of memory. ID: %u\n", mem->secure_id));
188 
189 #ifdef CONFIG_DMA_SHARED_BUFFER
190 		if (mem->import_attach) {
191 			struct dma_buf_attachment *attach = mem->import_attach;
192 			struct dma_buf *dma_buf;
193 
194 			if (mem->sgt)
195 				dma_buf_unmap_attachment(attach, mem->sgt,
196 							 DMA_BIDIRECTIONAL);
197 
198 			dma_buf = attach->dmabuf;
199 			dma_buf_detach(attach->dmabuf, attach);
200 			dma_buf_put(dma_buf);
201 
202 		}
203 #endif
204 		ump_random_mapping_remove_internal(device.secure_id_map, mem->secure_id);
205 
206 		mem->release_func(mem->ctx, mem);
207 		_mali_osk_free(mem);
208 	}
209 
210 	_mali_osk_mutex_rw_signal(device.secure_id_map->lock, _MALI_OSK_LOCKMODE_RW);
211 }
212 
ump_random_mapping_remove(ump_random_mapping * map,int descriptor)213 ump_dd_mem *ump_random_mapping_remove(ump_random_mapping *map, int descriptor)
214 {
215 	ump_dd_mem *mem;
216 
217 	_mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RW);
218 	mem = ump_random_mapping_remove_internal(map, descriptor);
219 	_mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RW);
220 
221 	return mem;
222 }
223