2 * This confidential and proprietary software may be used only as
3 * authorised by a licensing agreement from ARM Limited
4 * (C) COPYRIGHT 2009-2013 ARM Limited
6 * The entire notice above must be reproduced on all authorised
7 * copies and copies may only be made to the extent permitted
8 * by a licensing agreement from ARM Limited.
11 #include "mali_kernel_common.h"
13 #include "mali_osk_bitops.h"
14 #include "mali_osk_list.h"
16 #include "ump_uk_types.h"
18 #include "ump_kernel_common.h"
19 #include "ump_kernel_descriptor_mapping.h"
20 #include "ump_kernel_memory_backend.h"
25 * Define the initial and maximum size of number of secure_ids on the system
27 #define UMP_SECURE_ID_TABLE_ENTRIES_INITIAL (128 )
28 #define UMP_SECURE_ID_TABLE_ENTRIES_MAXIMUM (4096 )
32 * Define the initial and maximum size of the ump_session_data::cookies_map,
33 * which is a \ref ump_descriptor_mapping. This limits how many secure_ids
34 * may be mapped into a particular process using _ump_ukk_map_mem().
37 #define UMP_COOKIES_PER_SESSION_INITIAL (UMP_SECURE_ID_TABLE_ENTRIES_INITIAL )
38 #define UMP_COOKIES_PER_SESSION_MAXIMUM (UMP_SECURE_ID_TABLE_ENTRIES_MAXIMUM)
40 struct ump_dev device
;
42 _mali_osk_errcode_t
ump_kernel_constructor(void)
44 _mali_osk_errcode_t err
;
46 /* Perform OS Specific initialization */
47 err
= _ump_osk_init();
48 if( _MALI_OSK_ERR_OK
!= err
) {
49 MSG_ERR(("Failed to initiaze the UMP Device Driver"));
53 /* Init the global device */
54 _mali_osk_memset(&device
, 0, sizeof(device
) );
56 /* Create the descriptor map, which will be used for mapping secure ID to ump_dd_mem structs */
57 device
.secure_id_map_lock
= _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_UNORDERED
, 0);
58 if (NULL
== device
.secure_id_map_lock
) {
59 MSG_ERR(("Failed to create OSK lock for secure id lookup table\n"));
60 return _MALI_OSK_ERR_NOMEM
;
63 device
.secure_id_map
= ump_descriptor_mapping_create(UMP_SECURE_ID_TABLE_ENTRIES_INITIAL
, UMP_SECURE_ID_TABLE_ENTRIES_MAXIMUM
);
64 if (NULL
== device
.secure_id_map
) {
65 _mali_osk_mutex_term(device
.secure_id_map_lock
);
66 MSG_ERR(("Failed to create secure id lookup table\n"));
67 return _MALI_OSK_ERR_NOMEM
;
70 /* Init memory backend */
71 device
.backend
= ump_memory_backend_create();
72 if (NULL
== device
.backend
) {
73 MSG_ERR(("Failed to create memory backend\n"));
74 _mali_osk_mutex_term(device
.secure_id_map_lock
);
75 ump_descriptor_mapping_destroy(device
.secure_id_map
);
76 return _MALI_OSK_ERR_NOMEM
;
79 return _MALI_OSK_ERR_OK
;
82 void ump_kernel_destructor(void)
84 DEBUG_ASSERT_POINTER(device
.secure_id_map
);
85 DEBUG_ASSERT_POINTER(device
.secure_id_map_lock
);
87 _mali_osk_mutex_term(device
.secure_id_map_lock
);
88 device
.secure_id_map_lock
= NULL
;
90 ump_descriptor_mapping_destroy(device
.secure_id_map
);
91 device
.secure_id_map
= NULL
;
93 device
.backend
->shutdown(device
.backend
);
94 device
.backend
= NULL
;
96 ump_memory_backend_destroy();
101 /** Creates a new UMP session
103 _mali_osk_errcode_t
_ump_ukk_open( void** context
)
105 struct ump_session_data
* session_data
;
107 /* allocated struct to track this session */
108 session_data
= (struct ump_session_data
*)_mali_osk_malloc(sizeof(struct ump_session_data
));
109 if (NULL
== session_data
) {
110 MSG_ERR(("Failed to allocate ump_session_data in ump_file_open()\n"));
111 return _MALI_OSK_ERR_NOMEM
;
114 session_data
->lock
= _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_UNORDERED
, 0);
115 if( NULL
== session_data
->lock
) {
116 MSG_ERR(("Failed to initialize lock for ump_session_data in ump_file_open()\n"));
117 _mali_osk_free(session_data
);
118 return _MALI_OSK_ERR_NOMEM
;
121 session_data
->cookies_map
= ump_descriptor_mapping_create( UMP_COOKIES_PER_SESSION_INITIAL
, UMP_COOKIES_PER_SESSION_MAXIMUM
);
123 if ( NULL
== session_data
->cookies_map
) {
124 MSG_ERR(("Failed to create descriptor mapping for _ump_ukk_map_mem cookies\n"));
126 _mali_osk_mutex_term(session_data
->lock
);
127 _mali_osk_free( session_data
);
128 return _MALI_OSK_ERR_NOMEM
;
131 _MALI_OSK_INIT_LIST_HEAD(&session_data
->list_head_session_memory_list
);
133 _MALI_OSK_INIT_LIST_HEAD(&session_data
->list_head_session_memory_mappings_list
);
135 /* Since initial version of the UMP interface did not use the API_VERSION ioctl we have to assume
136 that it is this version, and not the "latest" one: UMP_IOCTL_API_VERSION
137 Current and later API versions would do an additional call to this IOCTL and update this variable
138 to the correct one.*/
139 session_data
->api_version
= MAKE_VERSION_ID(1);
141 *context
= (void*)session_data
;
143 session_data
->cache_operations_ongoing
= 0 ;
144 session_data
->has_pending_level1_cache_flush
= 0;
146 DBG_MSG(2, ("New session opened\n"));
148 return _MALI_OSK_ERR_OK
;
151 _mali_osk_errcode_t
_ump_ukk_close( void** context
)
153 struct ump_session_data
* session_data
;
154 ump_session_memory_list_element
* item
;
155 ump_session_memory_list_element
* tmp
;
157 session_data
= (struct ump_session_data
*)*context
;
158 if (NULL
== session_data
) {
159 MSG_ERR(("Session data is NULL in _ump_ukk_close()\n"));
160 return _MALI_OSK_ERR_INVALID_ARGS
;
163 /* Unmap any descriptors mapped in. */
164 if (0 == _mali_osk_list_empty(&session_data
->list_head_session_memory_mappings_list
)) {
165 ump_memory_allocation
*descriptor
;
166 ump_memory_allocation
*temp
;
168 DBG_MSG(1, ("Memory mappings found on session usage list during session termination\n"));
170 /* use the 'safe' list iterator, since freeing removes the active block from the list we're iterating */
171 _MALI_OSK_LIST_FOREACHENTRY(descriptor
, temp
, &session_data
->list_head_session_memory_mappings_list
, ump_memory_allocation
, list
) {
172 _ump_uk_unmap_mem_s unmap_args
;
173 DBG_MSG(4, ("Freeing block with phys address 0x%x size 0x%x mapped in user space at 0x%x\n",
174 descriptor
->phys_addr
, descriptor
->size
, descriptor
->mapping
));
175 unmap_args
.ctx
= (void*)session_data
;
176 unmap_args
.mapping
= descriptor
->mapping
;
177 unmap_args
.size
= descriptor
->size
;
178 unmap_args
._ukk_private
= NULL
; /* NOTE: unused */
179 unmap_args
.cookie
= descriptor
->cookie
;
181 /* NOTE: This modifies the list_head_session_memory_mappings_list */
182 _ump_ukk_unmap_mem( &unmap_args
);
186 /* ASSERT that we really did free everything, because _ump_ukk_unmap_mem()
187 * can fail silently. */
188 DEBUG_ASSERT( _mali_osk_list_empty(&session_data
->list_head_session_memory_mappings_list
) );
190 _MALI_OSK_LIST_FOREACHENTRY(item
, tmp
, &session_data
->list_head_session_memory_list
, ump_session_memory_list_element
, list
) {
191 _mali_osk_list_del(&item
->list
);
192 DBG_MSG(2, ("Releasing UMP memory %u as part of file close\n", item
->mem
->secure_id
));
193 ump_dd_reference_release(item
->mem
);
194 _mali_osk_free(item
);
197 ump_descriptor_mapping_destroy( session_data
->cookies_map
);
199 _mali_osk_mutex_term(session_data
->lock
);
200 _mali_osk_free(session_data
);
202 DBG_MSG(2, ("Session closed\n"));
204 return _MALI_OSK_ERR_OK
;
207 _mali_osk_errcode_t
_ump_ukk_map_mem( _ump_uk_map_mem_s
*args
)
209 struct ump_session_data
* session_data
;
210 ump_memory_allocation
* descriptor
; /* Describes current mapping of memory */
211 _mali_osk_errcode_t err
;
212 unsigned long offset
= 0;
214 ump_dd_handle handle
; /* The real UMP handle for this memory. Its real datatype is ump_dd_mem* */
215 ump_dd_mem
* mem
; /* The real UMP memory. It is equal to the handle, but with exposed struct */
219 session_data
= (ump_session_data
*)args
->ctx
;
220 if( NULL
== session_data
) {
221 MSG_ERR(("Session data is NULL in _ump_ukk_map_mem()\n"));
222 return _MALI_OSK_ERR_INVALID_ARGS
;
225 descriptor
= (ump_memory_allocation
*) _mali_osk_calloc( 1, sizeof(ump_memory_allocation
));
226 if (NULL
== descriptor
) {
227 MSG_ERR(("ump_ukk_map_mem: descriptor allocation failed\n"));
228 return _MALI_OSK_ERR_NOMEM
;
231 handle
= ump_dd_handle_create_from_secure_id(args
->secure_id
);
232 if ( UMP_DD_HANDLE_INVALID
== handle
) {
233 _mali_osk_free(descriptor
);
234 DBG_MSG(1, ("Trying to map unknown secure ID %u\n", args
->secure_id
));
235 return _MALI_OSK_ERR_FAULT
;
238 mem
= (ump_dd_mem
*)handle
;
240 if (mem
->size_bytes
!= args
->size
) {
241 _mali_osk_free(descriptor
);
242 ump_dd_reference_release(handle
);
243 DBG_MSG(1, ("Trying to map too much or little. ID: %u, virtual size=%lu, UMP size: %lu\n", args
->secure_id
, args
->size
, mem
->size_bytes
));
244 return _MALI_OSK_ERR_FAULT
;
247 map_id
= ump_descriptor_mapping_allocate_mapping( session_data
->cookies_map
, (void*) descriptor
);
250 _mali_osk_free(descriptor
);
251 ump_dd_reference_release(handle
);
252 DBG_MSG(1, ("ump_ukk_map_mem: unable to allocate a descriptor_mapping for return cookie\n"));
254 return _MALI_OSK_ERR_NOMEM
;
257 descriptor
->size
= args
->size
;
258 descriptor
->handle
= handle
;
259 descriptor
->phys_addr
= args
->phys_addr
;
260 descriptor
->process_mapping_info
= args
->_ukk_private
;
261 descriptor
->ump_session
= session_data
;
262 descriptor
->cookie
= (u32
)map_id
;
264 if ( mem
->is_cached
) {
265 descriptor
->is_cached
= 1;
267 DBG_MSG(3, ("Mapping UMP secure_id: %d as cached.\n", args
->secure_id
));
269 descriptor
->is_cached
= 0;
271 DBG_MSG(3, ("Mapping UMP secure_id: %d as Uncached.\n", args
->secure_id
));
274 _mali_osk_list_init( &descriptor
->list
);
276 err
= _ump_osk_mem_mapregion_init( descriptor
);
277 if( _MALI_OSK_ERR_OK
!= err
) {
278 DBG_MSG(1, ("Failed to initialize memory mapping in _ump_ukk_map_mem(). ID: %u\n", args
->secure_id
));
279 ump_descriptor_mapping_free( session_data
->cookies_map
, map_id
);
280 _mali_osk_free(descriptor
);
281 ump_dd_reference_release(mem
);
285 DBG_MSG(4, ("Mapping virtual to physical memory: ID: %u, size:%lu, first physical addr: 0x%08lx, number of regions: %lu\n",
288 ((NULL
!= mem
->block_array
) ? mem
->block_array
->addr
: 0),
291 left
= descriptor
->size
;
292 /* loop over all blocks and map them in */
293 for (block
= 0; block
< mem
->nr_blocks
; block
++) {
294 unsigned long size_to_map
;
296 if (left
> mem
->block_array
[block
].size
) {
297 size_to_map
= mem
->block_array
[block
].size
;
302 if (_MALI_OSK_ERR_OK
!= _ump_osk_mem_mapregion_map(descriptor
, offset
, (u32
*)&(mem
->block_array
[block
].addr
), size_to_map
) ) {
303 DBG_MSG(1, ("WARNING: _ump_ukk_map_mem failed to map memory into userspace\n"));
304 ump_descriptor_mapping_free( session_data
->cookies_map
, map_id
);
305 ump_dd_reference_release(mem
);
306 _ump_osk_mem_mapregion_term( descriptor
);
307 _mali_osk_free(descriptor
);
308 return _MALI_OSK_ERR_FAULT
;
311 offset
+= size_to_map
;
314 /* Add to the ump_memory_allocation tracking list */
315 _mali_osk_mutex_wait(session_data
->lock
);
316 _mali_osk_list_add( &descriptor
->list
, &session_data
->list_head_session_memory_mappings_list
);
317 _mali_osk_mutex_signal(session_data
->lock
);
319 args
->mapping
= descriptor
->mapping
;
320 args
->cookie
= descriptor
->cookie
;
322 return _MALI_OSK_ERR_OK
;
325 void _ump_ukk_unmap_mem( _ump_uk_unmap_mem_s
*args
)
327 struct ump_session_data
* session_data
;
328 ump_memory_allocation
* descriptor
;
329 ump_dd_handle handle
;
331 session_data
= (ump_session_data
*)args
->ctx
;
333 if( NULL
== session_data
) {
334 MSG_ERR(("Session data is NULL in _ump_ukk_map_mem()\n"));
338 if (0 != ump_descriptor_mapping_get( session_data
->cookies_map
, (int)args
->cookie
, (void**)&descriptor
) ) {
339 MSG_ERR(("_ump_ukk_map_mem: cookie 0x%X not found for this session\n", args
->cookie
));
343 DEBUG_ASSERT_POINTER(descriptor
);
345 handle
= descriptor
->handle
;
346 if ( UMP_DD_HANDLE_INVALID
== handle
) {
347 DBG_MSG(1, ("WARNING: Trying to unmap unknown handle: UNKNOWN\n"));
351 /* Remove the ump_memory_allocation from the list of tracked mappings */
352 _mali_osk_mutex_wait(session_data
->lock
);
353 _mali_osk_list_del( &descriptor
->list
);
354 _mali_osk_mutex_signal(session_data
->lock
);
356 ump_descriptor_mapping_free( session_data
->cookies_map
, (int)args
->cookie
);
358 ump_dd_reference_release(handle
);
360 _ump_osk_mem_mapregion_term( descriptor
);
361 _mali_osk_free(descriptor
);
364 u32
_ump_ukk_report_memory_usage( void )
366 if(device
.backend
->stat
)
367 return device
.backend
->stat(device
.backend
);