summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuc Verhaegen <libv@skynet.be>2013-10-20 03:07:10 +0400
committerLuc Verhaegen <libv@skynet.be>2014-03-26 01:04:12 +0400
commitfa5ad94ac2873793dcca65dafc3ea211de5e7226 (patch)
tree40c63a755bad14be73ff228113cd5879ae3340b6
parentcb781d1c630183f4d61ebd7f536a61d496278fe4 (diff)
downloadlibump-fa5ad94ac2873793dcca65dafc3ea211de5e7226.tar.xz
import ump r2p4 source
Signed-off-by: Luc Verhaegen <libv@skynet.be>
-rw-r--r--src/ump.h268
-rw-r--r--src/ump_arch.c260
-rw-r--r--src/ump_arch.h65
-rw-r--r--src/ump_debug.h287
-rw-r--r--src/ump_frontend.c213
-rw-r--r--src/ump_internal.h62
-rw-r--r--src/ump_ioctl.h55
-rw-r--r--src/ump_osu.h430
-rw-r--r--src/ump_osu_locks.c539
-rw-r--r--src/ump_osu_memory.c60
-rw-r--r--src/ump_platform.h68
-rw-r--r--src/ump_ref_drv.c124
-rw-r--r--src/ump_ref_drv.h66
-rw-r--r--src/ump_uk_types.h147
-rw-r--r--src/ump_uku.c193
-rw-r--r--src/ump_uku.h56
16 files changed, 2893 insertions, 0 deletions
diff --git a/src/ump.h b/src/ump.h
new file mode 100644
index 0000000..793cf84
--- /dev/null
+++ b/src/ump.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump.h
+ *
+ * This file contains the user space part of the UMP API.
+ */
+
+#ifndef _UNIFIED_MEMORY_PROVIDER_H_
+#define _UNIFIED_MEMORY_PROVIDER_H_
+
+
+/** @defgroup ump_user_space_api UMP User Space API
+ * @{ */
+
+
+#include "ump_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * External representation of a UMP handle in user space.
+ */
+typedef void * ump_handle;
+
+/**
+ * Typedef for a secure ID, a system wide identificator for UMP memory buffers.
+ */
+typedef unsigned int ump_secure_id;
+
+/**
+ * Value to indicate an invalid UMP memory handle.
+ */
+#define UMP_INVALID_MEMORY_HANDLE ((ump_handle)0)
+
+/**
+ * Value to indicate an invalid secure Id.
+ */
+#define UMP_INVALID_SECURE_ID ((ump_secure_id)-1)
+
+/**
+ * UMP error codes for user space.
+ */
+typedef enum
+{
+ UMP_OK = 0, /**< indicates success */
+ UMP_ERROR, /**< indicates failure */
+} ump_result;
+
+
+/**
+ * Opens and initializes the UMP library.
+ *
+ * This function must be called at least once before calling any other UMP API functions.
+ * Each open is reference counted and must be matched with a call to @ref ump_close "ump_close".
+ *
+ * @see ump_close
+ *
+ * @return UMP_OK indicates success, UMP_ERROR indicates failure.
+ */
+UMP_API_EXPORT ump_result ump_open(void);
+
+
+/**
+ * Terminate the UMP library.
+ *
+ * This must be called once for every successful @ref ump_open "ump_open". The UMP library is
+ * terminated when, and only when, the last open reference to the UMP interface is closed.
+ *
+ * @see ump_open
+ */
+UMP_API_EXPORT void ump_close(void);
+
+
+/**
+ * Retrieves the secure ID for the specified UMP memory.
+ *
+ * This identificator is unique across the entire system, and uniquely identifies
+ * the specified UMP memory. This identificator can later be used through the
+ * @ref ump_handle_create_from_secure_id "ump_handle_create_from_secure_id" or
+ * @ref ump_dd_handle_create_from_secure_id "ump_dd_handle_create_from_secure_id"
+ * functions in order to access this UMP memory, for instance from another process.
+ *
+ * @note There is a kernel space equivalent function called @ref ump_dd_secure_id_get "ump_dd_secure_id_get"
+ *
+ * @see ump_handle_create_from_secure_id
+ * @see ump_dd_handle_create_from_secure_id
+ * @see ump_dd_secure_id_get
+ *
+ * @param mem Handle to UMP memory.
+ *
+ * @return Returns the secure ID for the specified UMP memory.
+ */
+UMP_API_EXPORT ump_secure_id ump_secure_id_get(ump_handle mem);
+
+
+/**
+ * Retrieves a handle to allocated UMP memory.
+ *
+ * The usage of UMP memory is reference counted, so this will increment the reference
+ * count by one for the specified UMP memory.
+ * Use @ref ump_reference_release "ump_reference_release" when there is no longer any
+ * use for the retrieved handle.
+ *
+ * @note There is a kernel space equivalent function called @ref ump_dd_handle_create_from_secure_id "ump_dd_handle_create_from_secure_id"
+ *
+ * @see ump_reference_release
+ * @see ump_dd_handle_create_from_secure_id
+ *
+ * @param secure_id The secure ID of the UMP memory to open, that can be retrieved using the @ref ump_secure_id_get "ump_secure_id_get " function.
+ *
+ * @return UMP_INVALID_MEMORY_HANDLE indicates failure, otherwise a valid handle is returned.
+ */
+UMP_API_EXPORT ump_handle ump_handle_create_from_secure_id(ump_secure_id secure_id);
+
+
+/**
+ * Retrieves the actual size of the specified UMP memory.
+ *
+ * The size is reported in bytes, and is typically page aligned.
+ *
+ * @note There is a kernel space equivalent function called @ref ump_dd_size_get "ump_dd_size_get"
+ *
+ * @see ump_dd_size_get
+ *
+ * @param mem Handle to UMP memory.
+ *
+ * @return Returns the allocated size of the specified UMP memory, in bytes.
+ */
+UMP_API_EXPORT unsigned long ump_size_get(ump_handle mem);
+
+
+/**
+ * Read from specified UMP memory.
+ *
+ * Another way of reading from (and writing to) UMP memory is to use the
+ * @ref ump_mapped_pointer_get "ump_mapped_pointer_get" to retrieve
+ * a CPU mapped pointer to the memory.
+ *
+ * @see ump_mapped_pointer_get
+ *
+ * @param dst Destination buffer.
+ * @param src Handle to UMP memory to read from.
+ * @param offset Where to start reading, given in bytes.
+ * @param length How much to read, given in bytes.
+ */
+UMP_API_EXPORT void ump_read(void * dst, ump_handle src, unsigned long offset, unsigned long length);
+
+
+/**
+ * Write to specified UMP memory.
+ *
+ * Another way of writing to (and reading from) UMP memory is to use the
+ * @ref ump_mapped_pointer_get "ump_mapped_pointer_get" to retrieve
+ * a CPU mapped pointer to the memory.
+ *
+ * @see ump_mapped_pointer_get
+ *
+ * @param dst Handle to UMP memory to write to.
+ * @param offset Where to start writing, given in bytes.
+ * @param src Buffer to read from.
+ * @param length How much to write, given in bytes.
+ */
+UMP_API_EXPORT void ump_write(ump_handle dst, unsigned long offset, const void * src, unsigned long length);
+
+
+/**
+ * Retrieves a memory mapped pointer to the specified UMP memory.
+ *
+ * This function retrieves a memory mapped pointer to the specified UMP memory,
+ * that can be used by the CPU. Every successful call to
+ * @ref ump_mapped_pointer_get "ump_mapped_pointer_get" is reference counted,
+ * and must therefor be followed by a call to
+ * @ref ump_mapped_pointer_release "ump_mapped_pointer_release " when the
+ * memory mapping is no longer needed.
+ *
+ * @note Systems without a MMU for the CPU only return the physical address, because no mapping is required.
+ *
+ * @see ump_mapped_pointer_release
+ *
+ * @param mem Handle to UMP memory.
+ *
+ * @return NULL indicates failure, otherwise a CPU mapped pointer is returned.
+ */
+UMP_API_EXPORT void * ump_mapped_pointer_get(ump_handle mem);
+
+
+/**
+ * Releases a previously mapped pointer to the specified UMP memory.
+ *
+ * The CPU mapping of the specified UMP memory memory is reference counted,
+ * so every call to @ref ump_mapped_pointer_get "ump_mapped_pointer_get" must
+ * be matched with a call to this function when the mapping is no longer needed.
+ *
+ * The CPU mapping is not removed before all references to the mapping is released.
+ *
+ * @note Systems without a MMU must still implement this function, even though no unmapping should be needed.
+ *
+ * @param mem Handle to UMP memory.
+ */
+UMP_API_EXPORT void ump_mapped_pointer_release(ump_handle mem);
+
+
+/**
+ * Adds an extra reference to the specified UMP memory.
+ *
+ * This function adds an extra reference to the specified UMP memory. This function should
+ * be used every time a UMP memory handle is duplicated, that is, assigned to another ump_handle
+ * variable. The function @ref ump_reference_release "ump_reference_release" must then be used
+ * to release each copy of the UMP memory handle.
+ *
+ * @note You are not required to call @ref ump_reference_add "ump_reference_add"
+ * for UMP handles returned from
+ * @ref ump_handle_create_from_secure_id "ump_handle_create_from_secure_id",
+ * because these handles are already reference counted by this function.
+ *
+ * @note There is a kernel space equivalent function called @ref ump_dd_reference_add "ump_dd_reference_add"
+ *
+ * @see ump_dd_reference_add
+ *
+ * @param mem Handle to UMP memory.
+ */
+UMP_API_EXPORT void ump_reference_add(ump_handle mem);
+
+
+/**
+ * Releases a reference from the specified UMP memory.
+ *
+ * This function should be called once for every reference to the UMP memory handle.
+ * When the last reference is released, all resources associated with this UMP memory
+ * handle are freed.
+ *
+ * @note There is a kernel space equivalent function called @ref ump_dd_reference_release "ump_dd_reference_release"
+ *
+ * @see ump_dd_reference_release
+ *
+ * @param mem Handle to UMP memory.
+ */
+UMP_API_EXPORT void ump_reference_release(ump_handle mem);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/** @} */ /* end group ump_user_space_api */
+
+
+#endif /*_UNIFIED_MEMORY_PROVIDER_H_ */
diff --git a/src/ump_arch.c b/src/ump_arch.c
new file mode 100644
index 0000000..3395d52
--- /dev/null
+++ b/src/ump_arch.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump_arch.c
+ *
+ * UMP arch layer for UMP-UDD
+ */
+
+#include <ump/ump.h>
+#include "ump_arch.h"
+#include <ump/ump_debug.h>
+
+#include <ump/ump_uk_types.h>
+#include "ump_uku.h"
+
+/** Pointer to an OS-Specific context that we should pass in _uku_ calls */
+void *ump_uk_ctx = NULL;
+
+/** Reference counting of ump_arch_open() and ump_arch_close(). */
+static volatile int ump_ref_count = 0;
+
+/** Lock for critical section in open/close */
+_ump_osu_lock_t * ump_lock_arch = NULL;
+
+ump_result ump_arch_open(void)
+{
+ ump_result retval = UMP_OK;
+
+ _ump_osu_lock_auto_init( &ump_lock_arch, 0, 0, 0 );
+
+ /* Check that the lock was initialized */
+ if (NULL == ump_lock_arch)
+ {
+ UMP_DEBUG_PRINT(1, ("UMP: ump_arch_open() failed to init lock\n"));
+ return UMP_ERROR;
+ }
+
+ /* Attempt to obtain a lock */
+ if( _UMP_OSU_ERR_OK != _ump_osu_lock_wait( ump_lock_arch, _UMP_OSU_LOCKMODE_RW ) )
+ {
+ UMP_DEBUG_PRINT(1, ("UMP: ump_arch_open() failed to acquire lock\n"));
+ return UMP_ERROR;
+ }
+
+ /* ASSERT NEEDED */
+ UMP_DEBUG_ASSERT(0 <= ump_ref_count, ("UMP: Reference count invalid at _ump_base_arch_open()"));
+ ump_ref_count++;
+
+ if (1 == ump_ref_count)
+ {
+ /* We are the first, open the UMP device driver */
+
+ if (_UMP_OSU_ERR_OK != _ump_uku_open( &ump_uk_ctx ))
+ {
+ UMP_DEBUG_PRINT(1, ("UMP: ump_arch_open() failed to open UMP device driver\n"));
+ retval = UMP_ERROR;
+ ump_ref_count--;
+ }
+ }
+
+ /* Signal the lock so someone else can use it */
+ _ump_osu_lock_signal( ump_lock_arch, _UMP_OSU_LOCKMODE_RW );
+
+ return retval;
+}
+
+
+
+void ump_arch_close(void)
+{
+ _ump_osu_lock_auto_init( &ump_lock_arch, 0, 0, 0 );
+
+ /* Check that the lock was initialized */
+ if(NULL == ump_lock_arch)
+ {
+ UMP_DEBUG_PRINT(1, ("UMP: ump_arch_close() failed to init lock\n"));
+ return;
+ }
+
+ /* Attempt to obtain a lock */
+ if( _UMP_OSU_ERR_OK != _ump_osu_lock_wait( ump_lock_arch, _UMP_OSU_LOCKMODE_RW ) )
+ {
+ UMP_DEBUG_PRINT(1, ("UMP: ump_arch_close() failed to acquire lock\n"));
+ return;
+ }
+
+ UMP_DEBUG_ASSERT(0 < ump_ref_count, ("UMP: ump_arch_close() called while no references exist"));
+ if (ump_ref_count > 0)
+ {
+ ump_ref_count--;
+ if (0 == ump_ref_count)
+ {
+ _ump_osu_errcode_t retval = _ump_uku_close(&ump_uk_ctx);
+ UMP_DEBUG_ASSERT(retval == _UMP_OSU_ERR_OK, ("UMP: Failed to close UMP interface"));
+ UMP_IGNORE(retval);
+ ump_uk_ctx = NULL;
+ _ump_osu_lock_signal( ump_lock_arch, _UMP_OSU_LOCKMODE_RW );
+ _ump_osu_lock_term( ump_lock_arch ); /* Not 100% thread safe, since another thread can already be waiting for this lock in ump_arch_open() */
+ ump_lock_arch = NULL;
+ return;
+ }
+ }
+
+ /* Signal the lock so someone else can use it */
+ _ump_osu_lock_signal( ump_lock_arch, _UMP_OSU_LOCKMODE_RW );
+}
+
+
+
+ump_secure_id ump_arch_allocate(unsigned long * size, ump_alloc_constraints constraints)
+{
+ _ump_uk_allocate_s call_arg;
+
+ if ( NULL == size )
+ {
+ return UMP_INVALID_SECURE_ID;
+ }
+
+ call_arg.ctx = ump_uk_ctx;
+ call_arg.secure_id = UMP_INVALID_SECURE_ID;
+ call_arg.size = *size;
+#ifdef UMP_DEBUG_SKIP_CODE
+ /** Run-time ASSERTing that _ump_uk_api_version_s and ump_alloc_constraints are
+ * interchangable */
+ switch (constraints)
+ {
+ case UMP_REF_DRV_CONSTRAINT_NONE:
+ UMP_DEBUG_ASSERT( UMP_REF_DRV_UK_CONSTRAINT_NONE == constraints, ("ump_uk_alloc_constraints out of sync with ump_alloc_constraints") );
+ break;
+ case UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR:
+ UMP_DEBUG_ASSERT( UMP_REF_DRV_UK_CONSTRAINT_PHYSICALLY_LINEAR == constraints, ("ump_uk_alloc_constraints out of sync with ump_alloc_constraints") );
+ break;
+ default:
+ UMP_DEBUG_ASSERT( 1, ("ump_uk_alloc_constraints out of sync with ump_alloc_constraints: %d unrecognized", constraints) );
+ break;
+ }
+#endif
+ call_arg.constraints = (ump_uk_alloc_constraints)constraints;
+
+ if ( _UMP_OSU_ERR_OK != _ump_uku_allocate(&call_arg) )
+ {
+ return UMP_INVALID_SECURE_ID;
+ }
+
+ *size = call_arg.size;
+
+ UMP_DEBUG_PRINT(4, ("UMP: Allocated ID %u, size %ul", call_arg.secure_id, call_arg.size));
+
+ return call_arg.secure_id;
+}
+
+
+
+unsigned long ump_arch_size_get(ump_secure_id secure_id)
+{
+ _ump_uk_size_get_s dd_size_call_arg;
+
+ dd_size_call_arg.ctx = ump_uk_ctx;
+ dd_size_call_arg.secure_id = secure_id;
+ dd_size_call_arg.size = 0;
+
+ if (_UMP_OSU_ERR_OK == _ump_uku_size_get( &dd_size_call_arg ) )
+ {
+ return dd_size_call_arg.size;
+ }
+
+ return 0;
+}
+
+
+void ump_arch_reference_release(ump_secure_id secure_id)
+{
+ _ump_uk_release_s dd_release_call_arg;
+ _ump_osu_errcode_t retval;
+
+ dd_release_call_arg.ctx = ump_uk_ctx;
+ dd_release_call_arg.secure_id = secure_id;
+
+ UMP_DEBUG_PRINT(4, ("UMP: Releasing ID %u", secure_id));
+
+ retval = _ump_uku_release( &dd_release_call_arg );
+ UMP_DEBUG_ASSERT(retval == _UMP_OSU_ERR_OK, ("UMP: Failed to release reference to UMP memory"));
+ UMP_IGNORE(retval);
+}
+
+
+void* ump_arch_map(ump_secure_id secure_id, unsigned long size, ump_cache_enabled cache, unsigned long *cookie_out)
+{
+ _ump_uk_map_mem_s dd_map_call_arg;
+
+ UMP_DEBUG_ASSERT_POINTER( cookie_out );
+
+ dd_map_call_arg.ctx = ump_uk_ctx;
+ dd_map_call_arg.secure_id = secure_id;
+ dd_map_call_arg.size = size;
+ dd_map_call_arg.is_cached = (u32) (UMP_CACHE_ENABLE==cache);
+
+ if ( -1 == _ump_uku_map_mem( &dd_map_call_arg ) )
+ {
+ UMP_DEBUG_PRINT(4, ("UMP: Mapping failed for ID %u", secure_id));
+ return NULL;
+ }
+
+ UMP_DEBUG_PRINT(4, ("Mapped %u at 0x%08lx", secure_id, (unsigned long)dd_map_call_arg.mapping));
+
+ *cookie_out = dd_map_call_arg.cookie;
+ return dd_map_call_arg.mapping;
+}
+
+
+
+void ump_arch_unmap(void* mapping, unsigned long size, unsigned long cookie)
+{
+ _ump_uk_unmap_mem_s dd_unmap_call_arg;
+
+ dd_unmap_call_arg.ctx = ump_uk_ctx;
+ dd_unmap_call_arg.mapping = mapping;
+ dd_unmap_call_arg.size = size;
+ dd_unmap_call_arg.cookie = cookie;
+
+ UMP_DEBUG_PRINT(4, ("Unmapping 0x%08lx", (unsigned long)mapping));
+ _ump_uku_unmap_mem( &dd_unmap_call_arg );
+}
+
+/** Memory synchronization - cache flushing of mapped memory */
+int ump_arch_msync(ump_secure_id secure_id, void* mapping, unsigned long cookie, void * address, unsigned long size, ump_cpu_msync_op op)
+{
+ _ump_uk_msync_s dd_msync_call_arg;
+
+ dd_msync_call_arg.ctx = ump_uk_ctx;
+ dd_msync_call_arg.mapping = mapping;
+ dd_msync_call_arg.address = address;
+ dd_msync_call_arg.size = size;
+ dd_msync_call_arg.op = (ump_uk_msync_op)op;
+ dd_msync_call_arg.cookie = cookie;
+ dd_msync_call_arg.secure_id = secure_id;
+ dd_msync_call_arg.is_cached = 0;
+
+ UMP_DEBUG_PRINT(4, ("Msync 0x%08lx", (unsigned long)mapping));
+ _ump_uku_msynch( &dd_msync_call_arg );
+ if ( 0==dd_msync_call_arg.is_cached )
+ {
+ UMP_DEBUG_PRINT(4, ("Trying to flush uncached UMP mem ID: %d", secure_id));
+ }
+ return dd_msync_call_arg.is_cached;
+}
diff --git a/src/ump_arch.h b/src/ump_arch.h
new file mode 100644
index 0000000..22c1530
--- /dev/null
+++ b/src/ump_arch.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump_arch.h
+ *
+ * Header file for the arch dependent backend, which will do the communication with the UMP device driver.
+ */
+
+#ifndef _UNIFIED_MEMORY_PROVIDER_ARCH_H_
+#define _UNIFIED_MEMORY_PROVIDER_ARCH_H_
+
+#include <ump/ump.h>
+#include <ump/ump_ref_drv.h>
+#include "ump_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/** Open UMP interface. */
+ump_result ump_arch_open(void);
+
+/** Close UMP interface. */
+void ump_arch_close(void);
+
+/** Allocate UMP memory. */
+ump_secure_id ump_arch_allocate(unsigned long * size, ump_alloc_constraints constraints);
+
+/** Query size of specified UMP memory, in bytes. */
+unsigned long ump_arch_size_get(ump_secure_id secure_id);
+
+/** Release a reference from specified UMP memory. */
+void ump_arch_reference_release(ump_secure_id secure_id);
+
+/** Map specified UMP memory into CPU address space */
+void* ump_arch_map(ump_secure_id secure_id, unsigned long size, ump_cache_enabled cache, unsigned long *cookie_out);
+
+/** Unmap specified UMP memory from CPU adderss space */
+void ump_arch_unmap(void* mapping, unsigned long size, unsigned long cookie);
+
+/** Memory synchronization - cache flushing of mapped memory
+ * @return Is_cached: 1==True 0==NonCached */
+int ump_arch_msync(ump_secure_id secure_id, void* mapping, unsigned long cookie, void * address, unsigned long size, ump_cpu_msync_op op);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UNIFIED_MEMORY_PROVIDER_ARCH_H_ */
diff --git a/src/ump_debug.h b/src/ump_debug.h
new file mode 100644
index 0000000..d75fd3f
--- /dev/null
+++ b/src/ump_debug.h
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump_debug.h
+ *
+ * The file include several useful macros for debugging and printing.
+ * - UMP_PRINTF(...) Do not use this function: Will be included in Release builds.
+ * - UMP_DEBUG_TRACE() Prints current location in code.
+ * - UMP_DEBUG_PRINT(nr, (X) ) Prints the second argument if nr<=UMP_DEBUG_LEVEL.
+ * - UMP_DEBUG_TPRINT(nr, X ) Prints the source trace and second argument if nr<=UMP_DEBUG_LEVEL.
+ * - UMP_DEBUG_ERROR( (X) ) Prints an errortext, a source trace, and the given error message.
+ * - UMP_DEBUG_ASSERT(exp,(X)) If the asserted expr is false, the program will exit.
+ * - UMP_DEBUG_ASSERT_RANGE(x, min, max) Triggers if variable x is not between or equal to max and min.
+ * - UMP_DEBUG_ASSERT_LEQ(x, max) Triggers if variable x is not less than equal to max.
+ * - UMP_DEBUG_ASSERT_POINTER(pointer) Triggers if the pointer is a zero pointer.
+ * - UMP_DEBUG_CODE( X ) The code inside the macro is only copiled in Debug builds.
+ *
+ * The (X) means that you must add an extra parantese around the argumentlist.
+ *
+ * The printf function: UMP_PRINTF(...) is routed to _ump_sys_printf
+ *
+ * Suggested range for the DEBUG-LEVEL is [1:6] where
+ * [1:2] Is messages with highest priority, indicate possible errors.
+ * [3:4] Is messages with medium priority, output important variables.
+ * [5:6] Is messages with low priority, used during extensive debugging.
+ *
+ */
+#ifndef _UMP_DEBUG_H_
+#define _UMP_DEBUG_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* START: Configuration */
+#ifndef UMP_PRINTF
+ #define UMP_PRINTF printf
+#endif /* UMP_PRINTF */
+
+#ifndef UMP_PRINT_FLUSH
+ #define UMP_PRINT_FLUSH do {} while (0)
+#endif /* UMP_PRINT_FLUSH */
+
+#ifndef UMP_DEBUG_LEVEL
+ #define UMP_DEBUG_LEVEL 1
+#endif /* UMP_DEBUG_LEVEL */
+
+#ifndef UMP_DEBUG_ERROR_START_MSG
+ #define UMP_DEBUG_ERROR_START_MSG do {\
+ UMP_PRINTF("*********************************************************************\n");\
+ UMP_PRINT_FLUSH; } while (0)
+#endif /* UMP_DEBUG_ERROR_START_MSG */
+
+#ifndef UMP_DEBUG_ERROR_STOP_MSG
+ #define UMP_DEBUG_ERROR_STOP_MSG do { UMP_PRINTF("\n"); UMP_PRINT_FLUSH; } while (0)
+#endif /* UMP_DEBUG_ERROR_STOP_MSG */
+
+#ifndef UMP_ASSERT_QUIT_CMD
+ #define UMP_ASSERT_QUIT_CMD abort()
+#endif /* UMP_ASSERT_QUIT_CMD */
+/* STOP: Configuration */
+
+/**
+ * The macro UMP_FUNCTION evaluates to the name of the function enclosing
+ * this macro's usage, or "<unknown>" if not supported.
+ */
+#if (defined(__SYMBIAN32__) && defined(__ARMCC__)) || defined(_MSC_VER)
+# define UMP_FUNCTION __FUNCTION__
+#elif __STDC__ && __STDC_VERSION__ >= 199901L
+# define UMP_FUNCTION __FUNCTION__
+#elif defined(__GNUC__) && __GNUC__ >= 2
+# define UMP_FUNCTION __FUNCTION__
+#elif defined(__func__)
+# define UMP_FUNCTION __func__
+#else
+# define UMP_FUNCTION "<unknown>"
+#endif
+
+/**
+ * Explicitly ignore a parameter passed into a function, to suppress compiler warnings.
+ * Should only be used with parameter names.
+ */
+#define UMP_IGNORE(x) (void)x
+
+/**
+ * @def UMP_DEBUG_TRACE()
+ * @brief Prints current location in code.
+ * Can be turned off by defining UMP_DEBUG_SKIP_TRACE
+ */
+
+#ifndef UMP_DEBUG_SKIP_TRACE
+ #ifndef UMP_DEBUG_SKIP_PRINT_FUNCTION_NAME
+ #define UMP_DEBUG_TRACE() do { UMP_PRINTF( "In file: "__FILE__ \
+ " function: %s() line:%4d\n" , UMP_FUNCTION, __LINE__); UMP_PRINT_FLUSH; } while (0)
+ #else
+ #define UMP_DEBUG_TRACE() do { UMP_PRINTF( "In file: "__FILE__ " line:%4d\n" , __LINE__); UMP_PRINT_FLUSH; } while (0)
+ #endif /* UMP_DEBUG_SKIP_PRINT_FUNCTION_NAME */
+#else
+ #define UMP_DEBUG_TRACE()
+#endif /* UMP_DEBUG_SKIP_TRACE */
+
+/**
+ * @def UMP_DEBUG_PRINT(nr, (X) )
+ * @brief Prints the second argument if nr<=UMP_DEBUG_LEVEL.
+ * Can be turned off by defining UMP_DEBUG_SKIP_PRINT
+ * @param nr If nr <= UMP_DEBUG_LEVEL, we print the text.
+ * @param X A parantese with the contents to be sent to UMP_PRINTF
+ */
+#ifndef UMP_DEBUG_SKIP_PRINT
+ #define UMP_DEBUG_PRINT(nr, X ) do { if ( nr<=UMP_DEBUG_LEVEL ) { UMP_PRINTF X ; UMP_PRINT_FLUSH; } } while (0)
+#else
+ #define UMP_DEBUG_PRINT(nr, X )
+#endif /* UMP_DEBUG_SKIP_PRINT */
+
+/**
+ * @def UMP_DEBUG_TPRINT(nr, (X) )
+ * @brief Prints the second argument if nr<=UMP_DEBUG_LEVEL.
+ * Can be turned off by defining UMP_DEBUG_SKIP_TPRINT.
+ * Can be shortened by defining UMP_DEBUG_TPRINT_SKIP_FUNCTION.
+ * @param nr If nr <= UMP_DEBUG_LEVEL, we print the text.
+ * @param X A parantese with the contents to be sent to UMP_PRINTF
+ */
+
+/* helper to handle if the function name should be included or not */
+#ifndef UMP_DEBUG_TPRINT_SKIP_FUNCTION
+ #define UMP_DEBUG_TPRINT_INTERN do {UMP_PRINTF( ""__FILE__" %s()%4d " , UMP_FUNCTION, __LINE__); UMP_PRINT_FLUSH; } while (0)
+#else
+ #define UMP_DEBUG_TPRINT_INTERN do {UMP_PRINTF( ""__FILE__ "%4d " , __LINE__); UMP_PRINT_FLUSH; } while (0)
+#endif /* UMP_DEBUG_TPRINT_SKIP_FUNCTION */
+
+#ifndef UMP_DEBUG_SKIP_TPRINT
+ #define UMP_DEBUG_TPRINT(nr, X ) \
+ do{\
+ if ( nr<=UMP_DEBUG_LEVEL )\
+ {\
+ UMP_DEBUG_TPRINT_INTERN;\
+ UMP_PRINTF X ;\
+ UMP_PRINT_FLUSH;\
+ }\
+ } while (0)
+#else
+ #define UMP_DEBUG_TPRINT(nr, X )
+#endif /* UMP_DEBUG_SKIP_TPRINT */
+
+/**
+ * @def UMP_DEBUG_ERROR( (X) )
+ * @brief Prints an errortext, a source Trace, and the given error message.
+ * Prints filename, function, linenr, and the given error message.
+ * The error message must be inside a second parantese.
+ * The error message is written on a separate line, and a NL char is added.
+ * Can be turned of by defining UMP_DEBUG_SKIP_ERROR;
+ * You do not need to type the words ERROR in the message, since it will
+ * be added anyway.
+ *
+ * @note You should not end the text with a newline, since it is added by the macro.
+ * @note You should not write "ERROR" in the text, since it is added by the macro.
+ * @param X A parantese with the contents to be sent to UMP_PRINTF
+ */
+
+#ifndef UMP_DEBUG_SKIP_ERROR
+ #define UMP_DEBUG_ERROR( X ) \
+ do{ \
+ UMP_DEBUG_ERROR_START_MSG;\
+ UMP_PRINTF("ERROR: ");\
+ UMP_PRINT_FLUSH;\
+ UMP_DEBUG_TRACE(); \
+ UMP_PRINTF X ; \
+ UMP_PRINT_FLUSH;\
+ UMP_DEBUG_ERROR_STOP_MSG;\
+ } while (0)
+#else
+ #define UMP_DEBUG_ERROR( X ) do{ ; } while ( 0 )
+#endif /* UMP_DEBUG_SKIP_ERROR */
+
+/**
+ * @def UMP_DEBUG_ASSERT(expr, (X) )
+ * @brief If the asserted expr is false, the program will exit.
+ * Prints filename, function, linenr, and the given error message.
+ * The error message must be inside a second parantese.
+ * The error message is written on a separate line, and a NL char is added.
+ * Can be turned of by defining UMP_DEBUG_SKIP_ERROR;
+ * You do not need to type the words ASSERT in the message, since it will
+ * be added anyway.
+ *
+ * @param X A parantese with the contents to be sent to UMP_PRINTF
+ * Prints filename, function, linenr, and the error message
+ * on a separte line. A newline char is added at the end.
+ * Can be turned of by defining UMP_DEBUG_SKIP_ASSERT
+ * @param expr Will exit program if \a expr is false;
+ * @param (X) Text that will be written if the assertion toggles.
+ */
+
+#ifndef UMP_DEBUG_SKIP_ASSERT
+ #define UMP_DEBUG_ASSERT(expr, X ) \
+ do{\
+ if ( !(expr) ) \
+ { \
+ UMP_DEBUG_ERROR_START_MSG;\
+ UMP_PRINTF("ASSERT EXIT: ");\
+ UMP_PRINT_FLUSH;\
+ UMP_DEBUG_TRACE(); \
+ UMP_PRINTF X ; \
+ UMP_PRINT_FLUSH;\
+ UMP_DEBUG_ERROR_STOP_MSG;\
+ UMP_ASSERT_QUIT_CMD;\
+ }\
+ } while (0)
+#else
+ #define UMP_DEBUG_ASSERT(expr, X)
+#endif /* UMP_DEBUG_SKIP_ASSERT */
+
+
+/**
+ * @def UMP_DEBUG_ASSERT_POINTER(pointer)
+ * @brief If the asserted pointer is NULL, the program terminates and TRACE info is printed
+ * The checking is disabled if "UMP_DEBUG_SKIP_ASSERT" is defined.
+ */
+#define UMP_DEBUG_ASSERT_POINTER(pointer) UMP_DEBUG_ASSERT(pointer, ("Null pointer " #pointer) )
+
+/**
+ * @def UMP_DEBUG_ASSERT_HANDLE(handle)
+ * @brief If the asserted handle is not a valid handle, the program terminates and TRACE info is printed
+ * The checking is disabled if "UMP_DEBUG_SKIP_ASSERT" is defined.
+ */
+#define UMP_DEBUG_ASSERT_HANDLE(handle) UMP_DEBUG_ASSERT(UMP_NO_HANDLE != (handle), ("Invalid handle" #handle) )
+
+/**
+ * @def UMP_DEBUG_ASSERT_ALIGNMENT(ptr, align)
+ * @brief If the asserted pointer is not aligned to align, the program terminates with trace info printed.
+ * The checking is disabled if "UMP_DEBUG_SKIP_ASSERT" is defined.
+ */
+#ifndef UMP_DEBUG_SKIP_ASSERT
+ #define UMP_DEBUG_ASSERT_ALIGNMENT(ptr, align) do { \
+ UMP_DEBUG_ASSERT(0 == (align & (align - 1)), ("align %d is not a power-of-two", align)); \
+ UMP_DEBUG_ASSERT(0 == (((u32)(ptr)) & (align - 1)), ("ptr %p not aligned to %d bytes", (void*)ptr, align)); \
+ } while (0)
+#else
+ #define UMP_DEBUG_ASSERT_ALIGNMENT(ptr, align)
+#endif /* UMP_DEBUG_SKIP_ASSERT */
+
+/**
+ * @def UMP_DEBUG_ASSERT_RANGE(x,min,max)
+ * @brief If variable x is not between or equal to max and min, the assertion triggers.
+ * The checking is disabled if "UMP_DEBUG_SKIP_ASSERT" is defined.
+ */
+#define UMP_DEBUG_ASSERT_RANGE(x, min, max) \
+ UMP_DEBUG_ASSERT( (x) >= (min) && (x) <= (max), \
+ (#x " out of range (%2.2f)", (double)x ) \
+ )
+
+/**
+ * @def UMP_DEBUG_ASSERT_LEQ(x,max)
+ * @brief If variable x is less than or equal to max, the assertion triggers.
+ * The checking is disabled if "UMP_DEBUG_SKIP_ASSERT" is defined.
+ */
+#define UMP_DEBUG_ASSERT_LEQ(x, max) \
+ UMP_DEBUG_ASSERT( (x) <= (max), \
+ (#x " out of range (%2.2f)", (double)x ) \
+ )
+
+/**
+ * @def UMP_DEBUG_CODE( X )
+ * @brief Run the code X on debug builds.
+ * The code will not be used if UMP_DEBUG_SKIP_CODE is defined .
+ *
+ */
+#ifdef UMP_DEBUG_SKIP_CODE
+ #define UMP_DEBUG_CODE( X )
+#else
+ #define UMP_DEBUG_CODE( X ) X
+#endif /* UMP_DEBUG_SKIP_CODE */
+
+#endif /* _UMP_DEBUG_H_ */
+
diff --git a/src/ump_frontend.c b/src/ump_frontend.c
new file mode 100644
index 0000000..4f7d809
--- /dev/null
+++ b/src/ump_frontend.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump_frontend.c
+ *
+ * This file implements the user space API of the UMP API.
+ * It relies heavily on a arch backend to do the communication with the UMP device driver.
+ */
+
+#include <ump/ump.h>
+#include "ump_internal.h"
+#include "ump_arch.h"
+#include <ump/ump_debug.h>
+#include <ump/ump_osu.h>
+
+UMP_API_EXPORT ump_result ump_open(void)
+{
+ return ump_arch_open();
+}
+
+UMP_API_EXPORT void ump_close(void)
+{
+ ump_arch_close();
+}
+
+UMP_API_EXPORT ump_secure_id ump_secure_id_get(ump_handle memh)
+{
+ ump_mem * mem = (ump_mem*)memh;
+
+ UMP_DEBUG_ASSERT(UMP_INVALID_MEMORY_HANDLE != memh, ("Handle is invalid"));
+ UMP_DEBUG_ASSERT(UMP_INVALID_SECURE_ID != mem->secure_id, ("Secure ID is inavlid"));
+ UMP_DEBUG_ASSERT(0 < mem->ref_count, ("Reference count too low"));
+ UMP_DEBUG_ASSERT(0 < mem->size, ("Memory size of passed handle too low"));
+
+ return mem->secure_id;
+}
+
+UMP_API_EXPORT ump_handle ump_handle_create_from_secure_id(ump_secure_id secure_id)
+{
+ unsigned long size;
+
+ UMP_DEBUG_ASSERT(UMP_INVALID_SECURE_ID != secure_id, ("Secure ID is invalid"));
+
+ size = ump_arch_size_get(secure_id);
+ if (0 != size)
+ {
+ unsigned long cookie;
+ /*
+ * The UMP memory which the secure_id referes to could now be deleted and re-created
+ * since we don't have any references to it yet. The mapping below will however fail if
+ * we have supplied incorrect size, so we are safe.
+ */
+ void * mapping = ump_arch_map(secure_id, size, UMP_CACHE_DISABLE, &cookie);
+ if (NULL != mapping)
+ {
+ ump_mem * mem = _ump_osu_calloc(1, sizeof(*mem));
+ if (NULL != mem)
+ {
+ mem->secure_id = secure_id;
+ mem->mapped_mem = mapping;
+ mem->size = size;
+ mem->cookie = cookie;
+ mem->is_cached = 1; /* Is set to actually check in the ump_cpu_msync_now() function */
+
+ _ump_osu_lock_auto_init(&mem->ref_lock, 0, 0, 0);
+ UMP_DEBUG_ASSERT(NULL != mem->ref_lock, ("Failed to initialize lock\n"));
+ mem->ref_count = 1;
+
+ /* This is called only to set the cache settings in this handle */
+ ump_cpu_msync_now((ump_handle)mem, UMP_MSYNC_READOUT_CACHE_ENABLED, NULL, 0);
+
+ UMP_DEBUG_PRINT(4, ("UMP handle created for ID %u of size %lu, mapped into address 0x%08lx", mem->secure_id, mem->size, (unsigned long)mem->mapped_mem));
+
+ return (ump_handle)mem;
+ }
+
+ ump_arch_unmap(mapping, size, cookie);
+ }
+ }
+
+ UMP_DEBUG_PRINT(2, ("UMP handle creation failed for ID %u", secure_id));
+
+ return UMP_INVALID_MEMORY_HANDLE;
+}
+
+UMP_API_EXPORT unsigned long ump_size_get(ump_handle memh)
+{
+ ump_mem * mem = (ump_mem*)memh;
+
+ UMP_DEBUG_ASSERT(UMP_INVALID_MEMORY_HANDLE != memh, ("Handle is invalid"));
+ UMP_DEBUG_ASSERT(UMP_INVALID_SECURE_ID != mem->secure_id, ("Secure ID is inavlid"));
+ UMP_DEBUG_ASSERT(0 < mem->ref_count, ("Reference count too low"));
+ UMP_DEBUG_ASSERT(0 < mem->size, ("Memory size of passed handle too low"));
+
+ return mem->size;
+}
+
+UMP_API_EXPORT void ump_read(void *dst, ump_handle srch, unsigned long offset, unsigned long length)
+{
+ ump_mem * src = (ump_mem*)srch;
+
+ UMP_DEBUG_ASSERT(UMP_INVALID_MEMORY_HANDLE != srch, ("Handle is invalid"));
+ UMP_DEBUG_ASSERT(UMP_INVALID_SECURE_ID != src->secure_id, ("Secure ID is inavlid"));
+ UMP_DEBUG_ASSERT(0 < src->ref_count, ("Reference count too low"));
+ UMP_DEBUG_ASSERT(0 < src->size, ("Memory size of passed handle too low"));
+ UMP_DEBUG_ASSERT(NULL != src->mapped_mem, ("UMP Memory is not mapped"));
+ UMP_DEBUG_ASSERT((src->size) >= (offset + length), ("Requested read beyond end of UMP memory"));
+
+ _ump_osu_memcpy(dst,(char*)(src->mapped_mem) + offset, length);
+}
+
+UMP_API_EXPORT void ump_write(ump_handle dsth, unsigned long offset, const void *src, unsigned long length)
+{
+ ump_mem * dst = (ump_mem*)dsth;
+
+ UMP_DEBUG_ASSERT(UMP_INVALID_MEMORY_HANDLE != dsth, ("Handle is invalid"));
+ UMP_DEBUG_ASSERT(UMP_INVALID_SECURE_ID != dst->secure_id, ("Secure ID is inavlid"));
+ UMP_DEBUG_ASSERT(0 < dst->ref_count, ("Reference count too low"));
+ UMP_DEBUG_ASSERT(0 < dst->size, ("Memory size of passed handle too low"));
+ UMP_DEBUG_ASSERT(NULL != dst->mapped_mem, ("UMP Memory is not mapped"));
+ UMP_DEBUG_ASSERT((dst->size) >= (offset + length), ("Requested write beyond end of UMP memory"));
+
+ _ump_osu_memcpy((char*)(dst->mapped_mem) + offset, src, length);
+}
+
+
+
+UMP_API_EXPORT void* ump_mapped_pointer_get(ump_handle memh)
+{
+ ump_mem * mem = (ump_mem*)memh;
+
+ UMP_DEBUG_ASSERT(UMP_INVALID_MEMORY_HANDLE != memh, ("Handle is invalid"));
+ UMP_DEBUG_ASSERT(UMP_INVALID_SECURE_ID != mem->secure_id, ("Secure ID is inavlid"));
+ UMP_DEBUG_ASSERT(0 < mem->ref_count, ("Reference count too low"));
+ UMP_DEBUG_ASSERT(0 < mem->size, ("Memory size of passed handle too low"));
+ UMP_DEBUG_ASSERT(NULL != mem->mapped_mem, ("Error in mapping pointer (not mapped)"));
+
+ return mem->mapped_mem;
+}
+
+
+
+UMP_API_EXPORT void ump_mapped_pointer_release(ump_handle memh)
+{
+ UMP_DEBUG_ASSERT(UMP_INVALID_MEMORY_HANDLE != memh, ("Handle is invalid"));
+ UMP_DEBUG_ASSERT(UMP_INVALID_SECURE_ID != ((ump_mem*)memh)->secure_id, ("Secure ID is inavlid"));
+ UMP_DEBUG_ASSERT(0 < ((ump_mem*)memh)->ref_count, ("Reference count too low"));
+ UMP_DEBUG_ASSERT(0 < ((ump_mem*)memh)->size, ("Memory size of passed handle too low"));
+ UMP_DEBUG_ASSERT(NULL != ((ump_mem*)memh)->mapped_mem, ("Error in mapping pointer (not mapped)"));
+
+ /* noop, cos we map in the pointer when handle is created, and unmap it when handle is destroyed */
+}
+
+
+
+UMP_API_EXPORT void ump_reference_add(ump_handle memh)
+{
+ ump_mem * mem = (ump_mem*)memh;
+
+ UMP_DEBUG_ASSERT(UMP_INVALID_MEMORY_HANDLE != memh, ("Handle is invalid"));
+ UMP_DEBUG_ASSERT(UMP_INVALID_SECURE_ID != mem->secure_id, ("Secure ID is inavlid"));
+ UMP_DEBUG_ASSERT(0 < mem->ref_count, ("Reference count too low"));
+ UMP_DEBUG_ASSERT(0 < mem->size, ("Memory size of passed handle too low"));
+
+ _ump_osu_lock_wait(mem->ref_lock, _UMP_OSU_LOCKMODE_RW);
+ mem->ref_count += 1;
+ _ump_osu_lock_signal(mem->ref_lock, _UMP_OSU_LOCKMODE_RW);
+}
+
+
+
+UMP_API_EXPORT void ump_reference_release(ump_handle memh)
+{
+ ump_mem * mem = (ump_mem*)memh;
+
+ UMP_DEBUG_ASSERT(UMP_INVALID_MEMORY_HANDLE != memh, ("Handle is invalid"));
+ UMP_DEBUG_ASSERT(UMP_INVALID_SECURE_ID != ((ump_mem*)mem)->secure_id, ("Secure ID is inavlid"));
+ UMP_DEBUG_ASSERT(0 < (((ump_mem*)mem)->ref_count), ("Reference count too low"));
+ UMP_DEBUG_ASSERT(0 < ((ump_mem*)mem)->size, ("Memory size of passed handle too low"));
+ UMP_DEBUG_ASSERT(NULL != ((ump_mem*)mem)->mapped_mem, ("Error in mapping pointer (not mapped)"));
+
+ _ump_osu_lock_wait(mem->ref_lock, _UMP_OSU_LOCKMODE_RW);
+ mem->ref_count -= 1;
+ if (0 == mem->ref_count)
+ {
+ /* Remove memory mapping, which holds our only reference towards the UMP kernel space driver */
+ ump_arch_unmap(mem->mapped_mem, mem->size, mem->cookie);
+
+ _ump_osu_lock_signal(mem->ref_lock, _UMP_OSU_LOCKMODE_RW);
+
+ /* Free the lock protecting the reference count */
+ _ump_osu_lock_term(mem->ref_lock);
+
+ /* Free the memory for this handle */
+ _ump_osu_free(mem);
+ } else {
+ _ump_osu_lock_signal(mem->ref_lock, _UMP_OSU_LOCKMODE_RW);
+ }
+}
diff --git a/src/ump_internal.h b/src/ump_internal.h
new file mode 100644
index 0000000..28d353a
--- /dev/null
+++ b/src/ump_internal.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump_internal.c
+ *
+ * Internal definitions and debugging macros for the UMP implementation.
+ */
+
+#ifndef _UNIFIED_MEMORY_PROVIDER_INTERNAL_H_
+#define _UNIFIED_MEMORY_PROVIDER_INTERNAL_H_
+
+#include <ump/ump.h>
+#include <ump/ump_osu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum ump_cache_enabled
+{
+ UMP_CACHE_DISABLE = 0,
+ UMP_CACHE_ENABLE = 1
+} ump_cache_enabled;
+
+/**
+ * The actual (hidden) definition of ump_handles.
+ */
+typedef struct ump_mem
+{
+ ump_secure_id secure_id; /**< UMP device driver cookie */
+ void * mapped_mem; /**< Mapped memory; all read and write use this */
+ unsigned long size; /**< Size of allocated memory */
+ _ump_osu_lock_t* ref_lock; /**< Lock protection ref_count */
+ int ref_count; /**< The reference count of the ump_handle in userspace. It is used for finding out
+ when to free the memory used by this userspace handle. It is NOT the same as the
+ real ump_mem reference count in the devicedriver which do reference counting
+ for the memory that this handle reveals. */
+ unsigned long cookie; /**< cookie for use in arch_unmap calls */
+ ump_cache_enabled is_cached;
+} ump_mem;
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif /* _UNIFIED_MEMORY_PROVIDER_INTERNAL_H_ */
diff --git a/src/ump_ioctl.h b/src/ump_ioctl.h
new file mode 100644
index 0000000..e009da2
--- /dev/null
+++ b/src/ump_ioctl.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UMP_IOCTL_H__
+#define __UMP_IOCTL_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#include <ump_uk_types.h>
+
+#ifndef __user
+#define __user
+#endif
+
+
+/**
+ * @file UMP_ioctl.h
+ * This file describes the interface needed to use the Linux device driver.
+ * The interface is used by the userpace UMP driver.
+ */
+
+#define UMP_IOCTL_NR 0x90
+
+
+#define UMP_IOC_QUERY_API_VERSION _IOR(UMP_IOCTL_NR, _UMP_IOC_QUERY_API_VERSION, _ump_uk_api_version_s)
+#define UMP_IOC_ALLOCATE _IOWR(UMP_IOCTL_NR, _UMP_IOC_ALLOCATE, _ump_uk_allocate_s)
+#define UMP_IOC_RELEASE _IOR(UMP_IOCTL_NR, _UMP_IOC_RELEASE, _ump_uk_release_s)
+#define UMP_IOC_SIZE_GET _IOWR(UMP_IOCTL_NR, _UMP_IOC_SIZE_GET, _ump_uk_size_get_s)
+#define UMP_IOC_MSYNC _IOW(UMP_IOCTL_NR, _UMP_IOC_MSYNC, _ump_uk_size_get_s)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UMP_IOCTL_H__ */
diff --git a/src/ump_osu.h b/src/ump_osu.h
new file mode 100644
index 0000000..6b82484
--- /dev/null
+++ b/src/ump_osu.h
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump_osu.h
+ * Defines the OS abstraction layer for the base driver
+ */
+
+#ifndef __UMP_OSU_H__
+#define __UMP_OSU_H__
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+typedef unsigned int u32;
+#ifdef _MSC_VER
+ typedef unsigned __int64 u64;
+ typedef signed __int64 s64;
+#else
+ typedef unsigned long long u64;
+ typedef signed long long s64;
+#endif
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+typedef unsigned long ump_bool;
+
+#ifndef UMP_TRUE
+#define UMP_TRUE ((ump_bool)1)
+#endif
+
+#ifndef UMP_FALSE
+#define UMP_FALSE ((ump_bool)0)
+#endif
+
+#define UMP_STATIC static
+
+/**
+ * @addtogroup ump_user_space_api Unified Device Driver (UDD) APIs used by UMP
+ *
+ * @{
+ */
+
+/**
+ * @defgroup ump_osuapi UDD OS Abstraction for User-side (OSU) APIs for UMP
+ *
+ * @{
+ */
+
+/* The following is necessary to prevent the _ump_osk_errcode_t doxygen from
+ * becoming unreadable: */
+/** @cond OSU_COPY_OF__UMP_OSU_ERRCODE_T */
+
+/**
+ * @brief OSU/OSK Error codes.
+ *
+ * Each OS may use its own set of error codes, and may require that the
+ * User/Kernel interface take certain error code. This means that the common
+ * error codes need to be sufficiently rich to pass the correct error code
+ * through from the OSK/OSU to U/K layer, across all OSs.
+ *
+ * The result is that some error codes will appear redundant on some OSs.
+ * Under all OSs, the OSK/OSU layer must translate native OS error codes to
+ * _ump_osk/u_errcode_t codes. Similarly, the U/K layer must translate from
+ * _ump_osk/u_errcode_t codes to native OS error codes.
+ *
+ */
+typedef enum
+{
+ _UMP_OSK_ERR_OK = 0, /**< Success. */
+ _UMP_OSK_ERR_FAULT = -1, /**< General non-success */
+ _UMP_OSK_ERR_INVALID_FUNC = -2, /**< Invalid function requested through User/Kernel interface (e.g. bad IOCTL number) */
+ _UMP_OSK_ERR_INVALID_ARGS = -3, /**< Invalid arguments passed through User/Kernel interface */
+ _UMP_OSK_ERR_NOMEM = -4, /**< Insufficient memory */
+ _UMP_OSK_ERR_TIMEOUT = -5, /**< Timeout occured */
+ _UMP_OSK_ERR_RESTARTSYSCALL = -6, /**< Special: On certain OSs, must report when an interruptable mutex is interrupted. Ignore otherwise. */
+ _UMP_OSK_ERR_ITEM_NOT_FOUND = -7, /**< Table Lookup failed */
+ _UMP_OSK_ERR_BUSY = -8, /**< Device/operation is busy. Try again later */
+ _UMP_OSK_ERR_UNSUPPORTED = -9, /**< Optional part of the interface used, and is unsupported */
+} _ump_osk_errcode_t;
+
+/** @endcond */ /* end cond OSU_COPY_OF__UMP_OSU_ERRCODE_T */
+
+/**
+ * @brief OSU Error codes.
+ *
+ * OSU error codes - enum values intentionally same as OSK
+ */
+typedef enum
+{
+ _UMP_OSU_ERR_OK = 0, /**< Success. */
+ _UMP_OSU_ERR_FAULT = -1, /**< General non-success */
+ _UMP_OSU_ERR_TIMEOUT = -2, /**< Timeout occured */
+} _ump_osu_errcode_t;
+
+/** @brief Translate OSU error code to base driver error code.
+ *
+ * The _UMP_OSU_TRANSLATE_ERROR macro translates an OSU error code to the
+ * error codes in use by the base driver.
+ */
+#define _UMP_OSU_TRANSLATE_ERROR(_ump_osu_errcode) ( ( _UMP_OSU_ERR_OK == (_ump_osu_errcode) ) ? UMP_ERR_NO_ERROR : UMP_ERR_FUNCTION_FAILED)
+
+/** @defgroup _ump_osu_lock OSU Mutual Exclusion Locks
+ * @{ */
+
+/** @brief OSU Mutual Exclusion Lock flags type.
+ *
+ * This is made to look like and function identically to the OSK locks (refer
+ * to \ref _ump_osk_lock). However, please note the following \b important
+ * differences:
+ * - the OSU default lock is a Sleeping, non-interruptible mutex.
+ * - the OSU adds the ANYUNLOCK type of lock which allows a thread which doesn't
+ * own the lock to release the lock.
+ * - the order parameter when creating a lock is currently unused
+ *
+ * @note Pay careful attention to the difference in default locks for OSU and
+ * OSK locks; OSU locks are always non-interruptible, but OSK locks are by
+ * default, interruptible. This has implications for systems that do not
+ * distinguish between user and kernel mode.
+ */
+typedef enum
+{
+ _UMP_OSU_LOCKFLAG_DEFAULT = 0, /**< Default lock type. */
+ /** @enum _ump_osu_lock_flags_t
+ *
+ * Flags from 0x0--0x8000 are RESERVED for Kernel-mode
+ */
+ _UMP_OSU_LOCKFLAG_ANYUNLOCK = 0x10000, /**< Mutex that guarantees that any thread can unlock it when locked. Otherwise, this will not be possible. */
+ /** @enum _ump_osu_lock_flags_t
+ *
+ * Flags from 0x10000 are RESERVED for User-mode
+ */
+ _UMP_OSU_LOCKFLAG_STATIC = 0x20000, /* Flag in OSU reserved range to identify lock as a statically initialized lock */
+
+ } _ump_osu_lock_flags_t;
+
+typedef enum
+{
+ _UMP_OSU_LOCKMODE_UNDEF = -1, /**< Undefined lock mode. For internal use only */
+ _UMP_OSU_LOCKMODE_RW = 0x0, /**< Default. Lock is used to protect data that is read from and written to */
+ /** @enum _ump_osu_lock_mode_t
+ *
+ * Lock modes 0x1--0x3F are RESERVED for Kernel-mode */
+} _ump_osu_lock_mode_t;
+
+/** @brief Private type for Mutual Exclusion lock objects. */
+typedef struct _ump_osu_lock_t_struct _ump_osu_lock_t;
+
+/** @brief The number of static locks supported in _ump_osu_lock_static(). */
+#define UMP_OSU_STATIC_LOCK_COUNT (sizeof(_ump_osu_static_locks) / sizeof(_ump_osu_lock_t))
+
+/** @} */ /* end group _ump_osu_lock */
+
+/** @defgroup _ump_osu_memory OSU Memory Allocation
+ * @{ */
+
+/** @brief Allocate zero-initialized memory.
+ *
+ * Returns a buffer capable of containing at least \a n elements of \a size
+ * bytes each. The buffer is initialized to zero.
+ *
+ * The buffer is suitably aligned for storage and subsequent access of every
+ * type that the compiler supports. Therefore, the pointer to the start of the
+ * buffer may be cast into any pointer type, and be subsequently accessed from
+ * such a pointer, without loss of information.
+ *
+ * When the buffer is no longer in use, it must be freed with _ump_osu_free().
+ * Failure to do so will cause a memory leak.
+ *
+ * @note Most toolchains supply memory allocation functions that meet the
+ * compiler's alignment requirements.
+ *
+ * @param n Number of elements to allocate
+ * @param size Size of each element
+ * @return On success, the zero-initialized buffer allocated. NULL on failure
+ */
+void *_ump_osu_calloc( u32 n, u32 size );
+
+/** @brief Allocate memory.
+ *
+ * Returns a buffer capable of containing at least \a size bytes. The
+ * contents of the buffer are undefined.
+ *
+ * The buffer is suitably aligned for storage and subsequent access of every
+ * type that the compiler supports. Therefore, the pointer to the start of the
+ * buffer may be cast into any pointer type, and be subsequently accessed from
+ * such a pointer, without loss of information.
+ *
+ * When the buffer is no longer in use, it must be freed with _ump_osu_free().
+ * Failure to do so will cause a memory leak.
+ *
+ * @note Most toolchains supply memory allocation functions that meet the
+ * compiler's alignment requirements.
+ *
+ * Remember to free memory using _ump_osu_free().
+ * @param size Number of bytes to allocate
+ * @return On success, the buffer allocated. NULL on failure.
+ */
+void *_ump_osu_malloc( u32 size );
+
+/** @brief Free memory.
+ *
+ * Reclaims the buffer pointed to by the parameter \a ptr for the system.
+ * All memory returned from _ump_osu_malloc(), _ump_osu_calloc() and
+ * _ump_osu_realloc() must be freed before the application exits. Otherwise,
+ * a memory leak will occur.
+ *
+ * Memory must be freed once. It is an error to free the same non-NULL pointer
+ * more than once.
+ *
+ * It is legal to free the NULL pointer.
+ *
+ * @param ptr Pointer to buffer to free
+ */
+void _ump_osu_free( void *ptr );
+
+/** @brief Copies memory.
+ *
+ * Copies the \a len bytes from the buffer pointed by the parameter \a src
+ * directly to the buffer pointed by \a dst.
+ *
+ * It is an error for \a src to overlap \a dst anywhere in \a len bytes.
+ *
+ * @param dst Pointer to the destination array where the content is to be
+ * copied.
+ * @param src Pointer to the source of data to be copied.
+ * @param len Number of bytes to copy.
+ * @return \a dst is always passed through unmodified.
+ */
+void *_ump_osu_memcpy( void *dst, const void *src, u32 len );
+
+/** @brief Fills memory.
+ *
+ * Sets the first \a size bytes of the block of memory pointed to by \a ptr to
+ * the specified value
+ * @param ptr Pointer to the block of memory to fill.
+ * @param chr Value to be set, passed as u32. Only the 8 Least Significant Bits (LSB)
+ * are used.
+ * @param size Number of bytes to be set to the value.
+ * @return \a ptr is always passed through unmodified
+ */
+void *_ump_osu_memset( void *ptr, u32 chr, u32 size );
+
+/** @} */ /* end group _ump_osu_memory */
+
+
+/** @addtogroup _ump_osu_lock
+ * @{ */
+
+/** @brief Initialize a Mutual Exclusion Lock.
+ *
+ * Locks are created in the signalled (unlocked) state.
+ *
+ * The parameter \a initial must be zero.
+ *
+ * At present, the parameter \a order must be zero. It remains for future
+ * expansion for mutex order checking.
+ *
+ * @param flags flags combined with bitwise OR ('|'), or zero. There are
+ * restrictions on which flags can be combined, see \ref _ump_osu_lock_flags_t.
+ * @param initial For future expansion into semaphores. SBZ.
+ * @param order The locking order of the mutex. SBZ.
+ * @return On success, a pointer to a \ref _ump_osu_lock_t object. NULL on failure.
+ */
+_ump_osu_lock_t *_ump_osu_lock_init( _ump_osu_lock_flags_t flags, u32 initial, u32 order );
+
+/** @brief Obtain a statically initialized Mutual Exclusion Lock.
+ *
+ * Retrieves a reference to a statically initialized lock. Up to
+ * _UMP_OSU_STATIC_LOCK_COUNT statically initialized locks are
+ * available. Only _ump_osu_lock_wait(), _ump_osu_lock_trywait(),
+ * _ump_osu_lock_signal() can be used with statically initialized locks.
+ * _UMP_OSU_LOCKMODE_RW mode should be used when waiting and signalling
+ * statically initialized locks.
+ *
+ * For the same \a nr a pointer to the same statically initialized lock is
+ * returned. That is, given the following code:
+ * @code
+ * extern u32 n;
+ *
+ * _ump_osu_lock_t *locka = _ump_osu_lock_static(n);
+ * _ump_osu_lock_t *lockb = _ump_osu_lock_static(n);
+ * @endcode
+ * Then (locka == lockb), for all 0 <= n < UMP_OSU_STATIC_LOCK_COUNT.
+ *
+ * @param nr index of a statically initialized lock [0..UMP_OSU_STATIC_LOCK_COUNT-1]
+ * @return On success, a pointer to a _ump_osu_lock_t object. NULL on failure.
+ */
+_ump_osu_lock_t *_ump_osu_lock_static( u32 nr );
+
+/** @brief Initialize a Mutual Exclusion Lock safely across multiple threads.
+ *
+ * The _ump_osu_lock_auto_init() function guarantees that the given lock will
+ * be initialized once and precisely once, even in a situation involving
+ * multiple threads.
+ *
+ * This is necessary because the first call to certain Public API functions must
+ * initialize the API. However, there can be a race involved to call the first
+ * library function in multi-threaded applications. To resolve this race, a
+ * mutex can be used. This mutex must be initialized, but initialized only once
+ * by any thread that might compete for its initialization. This function
+ * guarantees the initialization to happen correctly, even when there is an
+ * initialization race between multiple threads.
+ *
+ * Otherwise, the operation is identical to the _ump_osu_lock_init() function.
+ * For more details, refer to _ump_osu_lock_init().
+ *
+ * @param pplock pointer to storage for a _ump_osu_lock_t pointer. This
+ * _ump_osu_lock_t pointer may point to a _ump_osu_lock_t that has been
+ * initialized already
+ * @param flags flags combined with bitwise OR ('|'), or zero. There are
+ * restrictions on which flags can be combined. Refer to
+ * \ref _ump_osu_lock_flags_t for more information.
+ * The absence of any flags (the value 0) results in a sleeping-mutex,
+ * which is non-interruptible.
+ * @param initial For future expansion into semaphores. SBZ.
+ * @param order The locking order of the mutex. SBZ.
+ * @return On success, _UMP_OSU_ERR_OK is returned and a pointer to an
+ * initialized \ref _ump_osu_lock_t object is written into \a *pplock.
+ * _UMP_OSU_ERR_FAULT is returned on failure.
+ */
+_ump_osu_errcode_t _ump_osu_lock_auto_init( _ump_osu_lock_t **pplock, _ump_osu_lock_flags_t flags, u32 initial, u32 order );
+
+/** @brief Wait for a lock to be signalled (obtained).
+ *
+ * After a thread has successfully waited on the lock, the lock is obtained by
+ * the thread, and is marked as unsignalled. The thread releases the lock by
+ * signalling it.
+ *
+ * To prevent deadlock, locks must always be obtained in the same order.
+ *
+ * @param lock the lock to wait upon (obtain).
+ * @param mode the mode in which the lock should be obtained. Currently this
+ * must be _UMP_OSU_LOCKMODE_RW.
+ * @return On success, _UMP_OSU_ERR_OK, _UMP_OSU_ERR_FAULT on error.
+ */
+_ump_osu_errcode_t _ump_osu_lock_wait( _ump_osu_lock_t *lock, _ump_osu_lock_mode_t mode);
+
+/** @brief Wait for a lock to be signalled (obtained) with timeout
+ *
+ * After a thread has successfully waited on the lock, the lock is obtained by
+ * the thread, and is marked as unsignalled. The thread releases the lock by
+ * signalling it.
+ *
+ * To prevent deadlock, locks must always be obtained in the same order.
+ *
+ * This version can return early if it cannot obtain the lock within the given timeout.
+ *
+ * @param lock the lock to wait upon (obtain).
+ * @param mode the mode in which the lock should be obtained. Currently this
+ * must be _UMP_OSU_LOCKMODE_RW.
+ * @param timeout Relative time in microseconds for the timeout
+ * @return _UMP_OSU_ERR_OK if the lock was obtained, _UMP_OSU_ERR_TIMEOUT if the timeout expired or _UMP_OSU_ERR_FAULT on error.
+ */
+_ump_osu_errcode_t _ump_osu_lock_timed_wait( _ump_osu_lock_t *lock, _ump_osu_lock_mode_t mode, u64 timeout);
+
+/** @brief Test for a lock to be signalled and obtains the lock when so.
+ *
+ * Obtains the lock only when it is in signalled state. The lock is then
+ * marked as unsignalled. The lock is released again by signalling
+ * it by _ump_osu_lock_signal().
+ *
+ * If the lock could not be obtained immediately (that is, another thread
+ * currently holds the lock), then this function \b does \b not wait for the
+ * lock to be in a signalled state. Instead, an error code is immediately
+ * returned to indicate that the thread could not obtain the lock.
+ *
+ * To prevent deadlock, locks must always be obtained in the same order.
+ *
+ * @param lock the lock to wait upon (obtain).
+ * @param mode the mode in which the lock should be obtained. Currently this
+ * must be _UMP_OSU_LOCKMODE_RW.
+ * @return When the lock was obtained, _UMP_OSU_ERR_OK. If the lock could not
+ * be obtained, _UMP_OSU_ERR_FAULT.
+ */
+_ump_osu_errcode_t _ump_osu_lock_trywait( _ump_osu_lock_t *lock, _ump_osu_lock_mode_t mode);
+
+/** @brief Signal (release) a lock.
+ *
+ * Locks may only be signalled by the thread that originally waited upon the
+ * lock, unless the lock was created using the _UMP_OSU_LOCKFLAG_ANYUNLOCK flag.
+ *
+ * @param lock the lock to signal (release).
+ * @param mode the mode in which the lock should be obtained. This must match
+ * the mode in which the lock was waited upon.
+ */
+void _ump_osu_lock_signal( _ump_osu_lock_t *lock, _ump_osu_lock_mode_t mode );
+
+/** @brief Terminate a lock.
+ *
+ * This terminates a lock and frees all associated resources.
+ *
+ * It is a programming error to terminate the lock when it is held (unsignalled)
+ * by a thread.
+ *
+ * @param lock the lock to terminate.
+ */
+void _ump_osu_lock_term( _ump_osu_lock_t *lock );
+/** @} */ /* end group _ump_osu_lock */
+
+/** @} */ /* end group osuapi */
+
+/** @} */ /* end group uddapi */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UMP_OSU_H__ */
diff --git a/src/ump_osu_locks.c b/src/ump_osu_locks.c
new file mode 100644
index 0000000..a1d06f1
--- /dev/null
+++ b/src/ump_osu_locks.c
@@ -0,0 +1,539 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if ((!defined _XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 600))
+#undef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600
+#endif
+
+
+#define _POSIX_C_SOURCE 200112L
+
+#include <ump/ump_osu.h>
+#include <ump/ump_debug.h>
+
+#include <pthread.h>
+#include <time.h>
+#include <sys/time.h>
+#include <errno.h>
+
+/**
+ * @file ump_osu_locks.c
+ * File implements the user side of the OS interface
+ */
+
+/** @opt Most of the time, we use the plain mutex type of osu_lock, and so
+ * only require the flags and mutex members. This costs 2 extra DWORDS, but
+ * most of the time we don't use those DWORDS.
+ * Therefore, ANY_UNLOCK type osu_locks can be implemented as a second
+ * structure containing the member _ump_osu_lock_t lock_t, plus the extra
+ * state required. Then, we use &container->lock_t when passing out of the
+ * OSU api, and CONTAINER_OF() when passing back in to recover the original
+ * structure. */
+
+/** Private declaration of the OSU lock type */
+struct _ump_osu_lock_t_struct
+{
+ /** At present, only two types of mutex, so we store this information as
+ * the flags supplied at init time */
+ _ump_osu_lock_flags_t flags;
+
+ pthread_mutex_t mutex; /**< Used in both plain and ANY_UNLOCK osu_locks */
+
+ /* Extra State for ANY_UNLOCK osu_locks. These are UNINITIALIZED when
+ * flags does not contain _UMP_OSU_LOCKFLAG_ANYUNLOCK: */
+ pthread_cond_t condition; /**< The condition object to use while blocking */
+ ump_bool state; /**< The boolean which indicates the event's state */
+
+ UMP_DEBUG_CODE(
+ /** debug checking of locks */
+ _ump_osu_lock_mode_t locked_as;
+ ) /* UMP_DEBUG_CODE */
+
+};
+
+/* Provide two statically initialized locks */
+UMP_STATIC _ump_osu_lock_t _ump_osu_static_locks[] =
+{
+ {
+ _UMP_OSU_LOCKFLAG_STATIC,
+ PTHREAD_MUTEX_INITIALIZER,
+ PTHREAD_COND_INITIALIZER,
+ UMP_FALSE,
+ UMP_DEBUG_CODE( _UMP_OSU_LOCKMODE_UNDEF )
+ },
+ {
+ _UMP_OSU_LOCKFLAG_STATIC,
+ PTHREAD_MUTEX_INITIALIZER,
+ PTHREAD_COND_INITIALIZER,
+ UMP_FALSE,
+ UMP_DEBUG_CODE( _UMP_OSU_LOCKMODE_UNDEF )
+ },
+ {
+ _UMP_OSU_LOCKFLAG_STATIC,
+ PTHREAD_MUTEX_INITIALIZER,
+ PTHREAD_COND_INITIALIZER,
+ UMP_FALSE,
+ UMP_DEBUG_CODE( _UMP_OSU_LOCKMODE_UNDEF )
+ },
+ {
+ _UMP_OSU_LOCKFLAG_STATIC,
+ PTHREAD_MUTEX_INITIALIZER,
+ PTHREAD_COND_INITIALIZER,
+ UMP_FALSE,
+ UMP_DEBUG_CODE( _UMP_OSU_LOCKMODE_UNDEF )
+ },
+};
+
+/* Critical section for auto_init */
+UMP_STATIC pthread_mutex_t static_auto_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+_ump_osu_errcode_t _ump_osu_lock_auto_init( _ump_osu_lock_t **pplock, _ump_osu_lock_flags_t flags, u32 initial, u32 order )
+{
+ int call_result;
+ /* Validate parameters: */
+ UMP_DEBUG_ASSERT_POINTER( pplock );
+
+ /** @opt We don't lock the Critical Section or do anything if this is already non-null */
+ if ( NULL != *pplock)
+ {
+ return _UMP_OSU_ERR_OK;
+ }
+
+ /* We MIGHT need to initialize it, lock the Critical Section and check again */
+ call_result = pthread_mutex_lock(&static_auto_init_mutex);
+ /* It would be a programming error for this to fail: */
+ UMP_DEBUG_ASSERT( 0 == call_result,
+ ("failed to lock critical section\n") );
+
+ if ( NULL != *pplock )
+ {
+ /*
+ We caught a race condition to initialize this osu_lock.
+ The other thread won the race, so the osu_lock is now initialized.
+ */
+ call_result = pthread_mutex_unlock(&static_auto_init_mutex);
+
+ UMP_DEBUG_ASSERT(0 == call_result,
+ ("failed to unlock critical section\n"));
+
+ return _UMP_OSU_ERR_OK;
+ }
+
+ /* We're the first thread in: initialize the osu_lock */
+ *pplock = _ump_osu_lock_init( flags, initial, order );
+
+ if ( NULL == *pplock )
+ {
+ /* osu_lock creation failed */
+ call_result = pthread_mutex_unlock(&static_auto_init_mutex);
+ UMP_DEBUG_ASSERT(0 == call_result,
+ ("failed to unlock critical section\n"));
+
+ return _UMP_OSU_ERR_FAULT;
+ }
+
+
+ /* osu_lock created OK */
+ call_result = pthread_mutex_unlock(&static_auto_init_mutex);
+
+ UMP_DEBUG_ASSERT(0 == call_result,
+ ("failed to unlock critical section\n"));
+
+ UMP_IGNORE( call_result );
+
+ return _UMP_OSU_ERR_OK;
+}
+
+
+_ump_osu_lock_t *_ump_osu_lock_init( _ump_osu_lock_flags_t flags, u32 initial, u32 order )
+{
+ _ump_osu_lock_t * lock;
+ pthread_mutexattr_t mutex_attributes;
+
+ UMP_IGNORE(order); /* order isn't implemented yet, for now callers should set it to zero. */
+
+ /* Validate parameters: */
+ /* Flags acceptable */
+ UMP_DEBUG_ASSERT( 0 == ( flags & ~( _UMP_OSU_LOCKFLAG_ANYUNLOCK)),
+ ("incorrect flags or trying to initialise a statically initialized lock, %.8X\n", flags) );
+
+ /* Parameter initial SBZ - for future expansion */
+ UMP_DEBUG_ASSERT( 0 == initial,
+ ("initial must be zero\n") );
+
+ if (0 != pthread_mutexattr_init(&mutex_attributes))
+ {
+ return NULL;
+ }
+
+#if UMP_DEBUG_EXTENDED_MUTEX_LOCK_CHECKING
+#define UMP_PTHREADS_MUTEX_TYPE PTHREAD_MUTEX_ERRORCHECK
+#else
+#define UMP_PTHREADS_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT
+#endif
+
+ if (0 != pthread_mutexattr_settype(&mutex_attributes, UMP_PTHREADS_MUTEX_TYPE))
+ {
+ /** Return NULL on failure */
+ pthread_mutexattr_destroy(&mutex_attributes);
+ return NULL;
+
+ }
+
+#undef UMP_PTHREADS_MUTEX_TYPE
+
+ /** @opt use containing structures for the ANY_UNLOCK type, to
+ * save 2 DWORDS when not in use */
+ lock = _ump_osu_malloc( sizeof(_ump_osu_lock_t) );
+
+ if( NULL == lock )
+ {
+ /** Return NULL on failure */
+ pthread_mutexattr_destroy(&mutex_attributes);
+ return NULL;
+ }
+
+ if (0 != pthread_mutex_init( &lock->mutex, &mutex_attributes ))
+ {
+ pthread_mutexattr_destroy(&mutex_attributes);
+ _ump_osu_free( lock );
+ return NULL;
+ }
+
+ /* done with the mutexattr object */
+ pthread_mutexattr_destroy(&mutex_attributes);
+
+ /* ANY_UNLOCK type */
+ if ( flags & _UMP_OSU_LOCKFLAG_ANYUNLOCK )
+ {
+ if (0 != pthread_cond_init( &lock->condition, NULL ))
+ {
+ /* cleanup */
+ pthread_mutex_destroy( &lock->mutex );
+ _ump_osu_free( lock );
+ return NULL;
+ }
+ lock->state = UMP_FALSE; /* mark as unlocked by default */
+ }
+
+ lock->flags = flags;
+
+ /** Debug lock checking */
+ UMP_DEBUG_CODE( lock->locked_as = _UMP_OSU_LOCKMODE_UNDEF );
+
+ return lock;
+}
+
+_ump_osu_errcode_t _ump_osu_lock_timed_wait( _ump_osu_lock_t *lock, _ump_osu_lock_mode_t mode, u64 timeout)
+{
+ /* absolute time specifier */
+ struct timespec ts;
+ struct timeval tv;
+
+ /* Parameter validation */
+ UMP_DEBUG_ASSERT_POINTER( lock );
+
+ UMP_DEBUG_ASSERT( _UMP_OSU_LOCKMODE_RW == mode,
+ ("unrecognised mode, %.8X\n", mode) );
+ UMP_DEBUG_ASSERT( _UMP_OSU_LOCKFLAG_ANYUNLOCK == lock->flags, ("Timed operations only implemented for ANYUNLOCK type locks"));
+
+ /* calculate the realtime timeout value */
+
+ if (0 != gettimeofday(&tv, NULL))
+ {
+ UMP_DEBUG_PRINT(1,("Could not get the current realtime value to calculate the absolute value for a timed mutex lock with a timeout"));
+ return _UMP_OSU_ERR_FAULT;
+ }
+
+ tv.tv_usec += timeout;
+
+#define UMP_USECS_PER_SECOND 1000000LL
+#define UMP_NANOSECS_PER_USEC 1000LL
+
+ /* did we overflow a second in the usec part? */
+ while (tv.tv_usec >= UMP_USECS_PER_SECOND)
+ {
+ tv.tv_usec -= UMP_USECS_PER_SECOND;
+ tv.tv_sec++;
+ }
+
+ /* copy to the correct struct */
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = (tv.tv_usec * UMP_NANOSECS_PER_USEC);
+
+#undef UMP_USECS_PER_SECOND
+#undef UMP_NANOSECS_PER_USEC
+
+ /* lock the mutex protecting access to the state field */
+ pthread_mutex_lock( &lock->mutex );
+ /* loop while locked (state is UMP_TRUE) */
+ /* pthread_cond_timedwait unlocks the mutex, wait, and locks the mutex once unblocked (either due to the event or the timeout) */
+ while ( UMP_TRUE == lock->state )
+ {
+ int res;
+ res = pthread_cond_timedwait( &lock->condition, &lock->mutex, &ts );
+ if (0 == res) continue; /* test the state variable again (loop condition) */
+ else if (ETIMEDOUT == res)
+ {
+ /* timeout, need to clean up and return the correct error code */
+ pthread_mutex_unlock(&lock->mutex);
+ return _UMP_OSU_ERR_TIMEOUT;
+ }
+ else
+ {
+ UMP_DEBUG_PRINT(1, ("Unexpected return from pthread_cond_timedwait 0x%08X\n", res));
+
+ pthread_mutex_unlock(&lock->mutex);
+ return _UMP_OSU_ERR_FAULT;
+ }
+
+ }
+
+ /* DEBUG tracking of previously locked state - occurs while lock is obtained */
+ UMP_DEBUG_ASSERT( _UMP_OSU_LOCKMODE_UNDEF == lock->locked_as,
+ ("This lock was already locked\n") );
+ UMP_DEBUG_CODE( lock->locked_as = mode );
+
+ /* the state is UMP_FALSE (unlocked), so we set it to UMP_TRUE to indicate that it's locked and can return knowing that we own the lock */
+ lock->state = UMP_TRUE;
+ /* final unlock of the mutex */
+ pthread_mutex_unlock(&lock->mutex);
+
+ return _UMP_OSU_ERR_OK;
+
+}
+
+_ump_osu_errcode_t _ump_osu_lock_wait( _ump_osu_lock_t *lock, _ump_osu_lock_mode_t mode)
+{
+ /* Parameter validation */
+ UMP_DEBUG_ASSERT_POINTER( lock );
+
+ UMP_DEBUG_ASSERT( _UMP_OSU_LOCKMODE_RW == mode,
+ ("unrecognised mode, %.8X\n", mode) );
+
+ /** @note since only one flag can be set, we use a switch statement here.
+ * Otherwise, MUST add an enum into the _ump_osu_lock_t to store the
+ * implemented lock type */
+ switch ( lock->flags )
+ {
+ case _UMP_OSU_LOCKFLAG_STATIC:
+ case 0:
+ /* Usual Mutex type */
+ {
+ int call_result;
+ call_result = pthread_mutex_lock( &lock->mutex );
+ UMP_DEBUG_ASSERT( 0 == call_result,
+ ("pthread_mutex_lock call failed with error code %d\n", call_result));
+ UMP_IGNORE( call_result );
+ }
+
+ /* DEBUG tracking of previously locked state - occurs while lock is obtained */
+ UMP_DEBUG_ASSERT( _UMP_OSU_LOCKMODE_UNDEF == lock->locked_as,
+ ("This lock was already locked\n") );
+ UMP_DEBUG_CODE( lock->locked_as = mode );
+ break;
+
+ case _UMP_OSU_LOCKFLAG_ANYUNLOCK:
+ /** @note Use of bitflags in a case statement ONLY works because this
+ * is the ONLY flag that is supported */
+
+ /* lock the mutex protecting access to the state field */
+ pthread_mutex_lock( &lock->mutex );
+ /* loop while locked (state is UMP_TRUE) */
+ /* pthread_cond_wait unlocks the mutex, wait, and locks the mutex once unblocked */
+ while ( UMP_TRUE == lock->state ) pthread_cond_wait( &lock->condition, &lock->mutex );
+
+ /* DEBUG tracking of previously locked state - occurs while lock is obtained */
+ UMP_DEBUG_ASSERT( _UMP_OSU_LOCKMODE_UNDEF == lock->locked_as,
+ ("This lock was already locked\n") );
+ UMP_DEBUG_CODE( lock->locked_as = mode );
+
+ /* the state is UMP_FALSE (unlocked), so we set it to UMP_TRUE to indicate that it's locked and can return knowing that we own the lock */
+ lock->state = UMP_TRUE;
+ /* final unlock of the mutex */
+ pthread_mutex_unlock(&lock->mutex);
+ break;
+
+ default:
+ UMP_DEBUG_ERROR( ("lock has incorrect flags==%.8X\n", lock->flags) );
+ break;
+ }
+
+ return _UMP_OSU_ERR_OK;
+}
+
+_ump_osu_errcode_t _ump_osu_lock_trywait( _ump_osu_lock_t *lock, _ump_osu_lock_mode_t mode)
+{
+ _ump_osu_errcode_t err = _UMP_OSU_ERR_FAULT;
+ /* Parameter validation */
+ UMP_DEBUG_ASSERT_POINTER( lock );
+
+ UMP_DEBUG_ASSERT( _UMP_OSU_LOCKMODE_RW == mode,
+ ("unrecognised mode, %.8X\n", mode) );
+
+ /** @note since only one flag can be set, we use a switch statement here.
+ * Otherwise, MUST add an enum into the _ump_osu_lock_t to store the
+ * implemented lock type */
+ switch ( lock->flags )
+ {
+ case _UMP_OSU_LOCKFLAG_STATIC:
+ case 0:
+ /* Usual Mutex type */
+ {
+ /* This is not subject to UMP_CHECK - overriding the result would cause a programming error */
+ if ( 0 == pthread_mutex_trylock( &lock->mutex ) )
+ {
+ err = _UMP_OSU_ERR_OK;
+
+ /* DEBUG tracking of previously locked state - occurs while lock is obtained */
+ UMP_DEBUG_ASSERT( _UMP_OSU_LOCKMODE_UNDEF == lock->locked_as
+ || mode == lock->locked_as,
+ ("tried as mode==%.8X, but was locked as %.8X\n", mode, lock->locked_as) );
+ UMP_DEBUG_CODE( lock->locked_as = mode );
+ }
+ }
+ break;
+
+ case _UMP_OSU_LOCKFLAG_ANYUNLOCK:
+ /** @note Use of bitflags in a case statement ONLY works because this
+ * is the ONLY flag that is supported */
+
+ /* lock the mutex protecting access to the state field */
+ pthread_mutex_lock(&lock->mutex);
+
+ if ( UMP_FALSE == lock->state)
+ {
+ /* unlocked, take the lock */
+ lock->state = UMP_TRUE;
+ err = _UMP_OSU_ERR_OK;
+ }
+
+ /* DEBUG tracking of previously locked state - occurs while lock is obtained */
+ /* Can do this regardless of whether we obtained ANYUNLOCK: */
+
+
+ UMP_DEBUG_ASSERT( _UMP_OSU_LOCKMODE_UNDEF == lock->locked_as
+ || mode == lock->locked_as,
+ ("tried as mode==%.8X, but was locked as %.8X\n", mode, lock->locked_as) );
+ /* If we were already locked, this does no harm, because of the above assert: */
+ UMP_DEBUG_CODE( lock->locked_as = mode );
+
+ pthread_mutex_unlock(&lock->mutex);
+ break;
+
+ default:
+ UMP_DEBUG_ERROR( ("lock has incorrect flags==%.8X\n", lock->flags) );
+ break;
+ }
+
+ return err;
+}
+
+
+void _ump_osu_lock_signal( _ump_osu_lock_t *lock, _ump_osu_lock_mode_t mode )
+{
+ /* Parameter validation */
+ UMP_DEBUG_ASSERT_POINTER( lock );
+
+ UMP_DEBUG_ASSERT( _UMP_OSU_LOCKMODE_RW == mode,
+ ("unrecognised mode, %.8X\n", mode) );
+
+ /** @note since only one flag can be set, we use a switch statement here.
+ * Otherwise, MUST add an enum into the _ump_osu_lock_t to store the
+ * implemented lock type */
+ switch ( lock->flags )
+ {
+ case _UMP_OSU_LOCKFLAG_STATIC:
+ case 0:
+ /* Usual Mutex type */
+
+ /* DEBUG tracking of previously locked state - occurs while lock is obtained */
+ UMP_DEBUG_ASSERT( mode == lock->locked_as,
+ ("This lock was locked as==%.8X, but tried to unlock as mode==%.8X\n", lock->locked_as, mode));
+ UMP_DEBUG_CODE( lock->locked_as = _UMP_OSU_LOCKMODE_UNDEF );
+
+ {
+ int call_result;
+ call_result = pthread_mutex_unlock( &lock->mutex );
+ UMP_DEBUG_ASSERT( 0 == call_result,
+ ("pthread_mutex_lock call failed with error code %d\n", call_result));
+ UMP_IGNORE( call_result );
+ }
+ break;
+
+ case _UMP_OSU_LOCKFLAG_ANYUNLOCK:
+ /** @note Use of bitflags in a case statement ONLY works because this
+ * is the ONLY flag that is supported */
+
+ pthread_mutex_lock(&lock->mutex);
+ UMP_DEBUG_ASSERT( UMP_TRUE == lock->state, ("Unlocking a _ump_osu_lock_t %p which is not locked\n", lock));
+
+ /* DEBUG tracking of previously locked state - occurs while lock is obtained */
+ UMP_DEBUG_ASSERT( mode == lock->locked_as,
+ ("This lock was locked as==%.8X, but tried to unlock as %.8X\n", lock->locked_as, mode ));
+ UMP_DEBUG_CODE( lock->locked_as = _UMP_OSU_LOCKMODE_UNDEF );
+
+ /* mark as unlocked */
+ lock->state = UMP_FALSE;
+
+ /* signal the condition, only wake a single thread */
+ pthread_cond_signal(&lock->condition);
+
+ pthread_mutex_unlock(&lock->mutex);
+ break;
+
+ default:
+ UMP_DEBUG_ERROR( ("lock has incorrect flags==%.8X\n", lock->flags) );
+ break;
+ }
+}
+
+void _ump_osu_lock_term( _ump_osu_lock_t *lock )
+{
+ int call_result;
+ UMP_DEBUG_ASSERT_POINTER( lock );
+
+ /** Debug lock checking: */
+ /* Lock is signalled on terminate - not a guarantee, since we could be locked immediately beforehand */
+ UMP_DEBUG_ASSERT( _UMP_OSU_LOCKMODE_UNDEF == lock->locked_as,
+ ("cannot terminate held lock\n") );
+
+ call_result = pthread_mutex_destroy( &lock->mutex );
+ UMP_DEBUG_ASSERT( 0 == call_result,
+ ("Incorrect mutex use detected: pthread_mutex_destroy call failed with error code %d\n", call_result) );
+
+ /* Destroy extra state for ANY_UNLOCK type osu_locks */
+ if ( lock->flags & _UMP_OSU_LOCKFLAG_ANYUNLOCK )
+ {
+ UMP_DEBUG_ASSERT( UMP_FALSE == lock->state, ("terminate called on locked object %p\n", lock));
+ call_result = pthread_cond_destroy(&lock->condition);
+ UMP_DEBUG_ASSERT( 0 == call_result,
+ ("Incorrect condition-variable use detected: pthread_cond_destroy call failed with error code %d\n", call_result) );
+ }
+
+ UMP_IGNORE(call_result);
+
+ _ump_osu_free( lock );
+}
+
+_ump_osu_lock_t *_ump_osu_lock_static( u32 nr )
+{
+ UMP_DEBUG_ASSERT( nr < UMP_OSU_STATIC_LOCK_COUNT,
+ ("provided static lock index (%d) out of bounds (0 < nr < %d)\n", nr, UMP_OSU_STATIC_LOCK_COUNT) );
+ return &_ump_osu_static_locks[nr];
+}
diff --git a/src/ump_osu_memory.c b/src/ump_osu_memory.c
new file mode 100644
index 0000000..629cf7f
--- /dev/null
+++ b/src/ump_osu_memory.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ump/ump_osu.h>
+
+#include <stdlib.h>
+#include <string.h> /* memcmp, memchr, memset */
+
+/**
+ * @file ump_osu_memory.c
+ * File implements the user side of the OS interface
+ */
+
+void *_ump_osu_calloc( u32 n, u32 size )
+{
+ return calloc( n, size );
+}
+
+void *_ump_osu_malloc( u32 size )
+{
+ return malloc( size );
+}
+
+void *_ump_osu_realloc( void *ptr, u32 size )
+{
+ return realloc( ptr, size );
+}
+
+void _ump_osu_free( void *ptr )
+{
+ free( ptr );
+}
+
+void *_ump_osu_memcpy( void *dst, const void *src, u32 len )
+{
+ return memcpy( dst, src, len );
+}
+
+void *_ump_osu_memset( void *ptr, u32 chr, u32 size )
+{
+ return memset( ptr, chr, size );
+}
+
+int _ump_osu_memcmp( const void *ptr1, const void *ptr2, u32 size )
+{
+ return memcmp( ptr1, ptr2, size );
+}
diff --git a/src/ump_platform.h b/src/ump_platform.h
new file mode 100644
index 0000000..f3b55e6
--- /dev/null
+++ b/src/ump_platform.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump_platform.h
+ *
+ * This file should define UMP_API_EXPORT,
+ * which dictates how the UMP user space API should be exported/imported.
+ * Modify this file, if needed, to match your platform setup.
+ */
+
+#ifndef __UMP_PLATFORM_H__
+#define __UMP_PLATFORM_H__
+
+/** @addtogroup ump_user_space_api
+ * @{ */
+
+/**
+ * A define which controls how UMP user space API functions are imported and exported.
+ * This define should be set by the implementor of the UMP API.
+ */
+#if defined(_WIN32)
+
+#define UMP_API_EXPORT
+
+#elif defined(__SYMBIAN32__)
+
+#define UMP_API_EXPORT IMPORT_C
+
+#else
+
+#if defined(__GNUC__)
+#if __GNUC__ >= 4
+# define MALI_VISIBLE __attribute__ ((visibility ("default"))) /**< Function should be visible from outside the dll */
+#else
+# define MALI_VISIBLE
+#endif
+
+#elif defined(__ARMCC_VERSION)
+/* ARMCC specific */
+# define MALI_VISIBLE __declspec(dllexport)
+
+#else
+# define MALI_VISIBLE
+
+#endif
+
+#define UMP_API_EXPORT MALI_VISIBLE
+
+#endif
+
+/** @} */ /* end group ump_user_space_api */
+
+
+#endif /* __UMP_PLATFORM_H__ */
diff --git a/src/ump_ref_drv.c b/src/ump_ref_drv.c
new file mode 100644
index 0000000..1df6f0b
--- /dev/null
+++ b/src/ump_ref_drv.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump_ref_drv.c
+ *
+ * Implementation of the user space API extensions provided by the reference implementation.
+ */
+
+#include <ump/ump_ref_drv.h>
+#include <ump/ump.h>
+#include "ump_internal.h"
+#include "ump_arch.h"
+#include <ump/ump_debug.h>
+#include <ump/ump_osu.h>
+
+/* Allocate a buffer which can be used directly by hardware, 4kb aligned */
+static ump_handle ump_ref_drv_allocate_internal(unsigned long size, ump_alloc_constraints constraints, ump_cache_enabled cache);
+
+
+
+/* Allocate a buffer which can be used directly by hardware, 4kb aligned */
+ump_handle ump_ref_drv_allocate(unsigned long size, ump_alloc_constraints constraints)
+{
+ ump_cache_enabled cache= UMP_CACHE_DISABLE;
+ if ( 0!=(constraints&UMP_REF_DRV_CONSTRAINT_USE_CACHE) )
+ {
+ cache = UMP_CACHE_ENABLE;
+ }
+ return ump_ref_drv_allocate_internal(size, constraints, cache);
+}
+
+UMP_API_EXPORT int ump_cpu_msync_now(ump_handle memh, ump_cpu_msync_op op, void* address, int size)
+{
+ ump_mem * mem = (ump_mem*)memh;
+ UMP_DEBUG_ASSERT(UMP_INVALID_MEMORY_HANDLE != memh, ("Handle is invalid"));
+
+ /* If the op is readout, we do the readout from DD.
+ Else we skip flushing if the userspace handle says that it is uncached */
+ if ((UMP_MSYNC_READOUT_CACHE_ENABLED!=op) && (0 == mem->is_cached) ) return 0;
+
+ UMP_DEBUG_ASSERT(0 < (((ump_mem*)mem)->ref_count), ("Reference count too low"));
+ UMP_DEBUG_ASSERT((size>=0) && (size <= (int)((ump_mem*)mem)->size), ("Memory size of passed handle too low"));
+ UMP_DEBUG_ASSERT(NULL != ((ump_mem*)mem)->mapped_mem, ("Error in mapping pointer (not mapped)"));
+
+ if (size > (int)mem->size) size = mem->size;
+
+ mem->is_cached = ump_arch_msync(mem->secure_id, mem->mapped_mem, mem->cookie, address, size, op);
+ return mem->is_cached ;
+}
+
+/* Allocate a buffer which can be used directly by hardware, 4kb aligned */
+static ump_handle ump_ref_drv_allocate_internal(unsigned long size, ump_alloc_constraints constraints, ump_cache_enabled cache)
+{
+ ump_secure_id secure_id;
+ unsigned long allocated_size = size;
+
+ UMP_DEBUG_PRINT(4, ("Allocating UMP memory of size %lu", size));
+
+ secure_id = ump_arch_allocate(&allocated_size, constraints);
+ if (secure_id != UMP_INVALID_SECURE_ID)
+ {
+ unsigned long cookie;
+ void * mapping;
+
+ mapping = ump_arch_map(secure_id, allocated_size, cache, &cookie);
+ if (NULL != mapping)
+ {
+ /*
+ * PS: By now we have actually increased the ref count in the device driver by 2,
+ * one for the allocation iteself, and one for the mapping.
+ */
+ ump_mem * mem;
+ mem = _ump_osu_calloc(1, sizeof(*mem));
+ if (NULL != mem)
+ {
+ mem->secure_id = secure_id;
+ mem->mapped_mem = mapping;
+ mem->size = allocated_size;
+ mem->cookie = cookie;
+ mem->is_cached = 1; /* Default to ON, is disabled later if not */
+
+ _ump_osu_lock_auto_init(&mem->ref_lock, 0, 0, 0);
+ UMP_DEBUG_ASSERT(NULL != mem->ref_lock, ("Failed to initialize lock\n"));
+ mem->ref_count = 1;
+
+ /*
+ * ump_arch_allocate() gave us a kernel space reference, and the same did ump_arch_map()
+ * We release the one from ump_arch_allocate(), and rely solely on the one from the ump_arch_map()
+ * That is, ump_arch_unmap() should now do the final release towards the UMP kernel space driver.
+ */
+ ump_arch_reference_release(secure_id);
+
+ /* This is called only to set the cache settings in this handle */
+ ump_cpu_msync_now((ump_handle)mem, UMP_MSYNC_READOUT_CACHE_ENABLED, NULL, 0);
+
+ UMP_DEBUG_PRINT(4, ("UMP handle created for ID %u of size %lu, mapped into address 0x%08lx", mem->secure_id, mem->size, (unsigned long)mem->mapped_mem));
+
+ return (ump_handle)mem;
+ }
+
+ ump_arch_unmap(mapping, allocated_size, cookie); /* Unmap the memory */
+ ump_arch_reference_release(secure_id); /* Release reference added when we allocated the UMP memory */
+ }
+
+ ump_arch_reference_release(secure_id); /* Release reference added when we allocated the UMP memory */
+ }
+
+ UMP_DEBUG_PRINT(4, ("Allocation of UMP memory failed"));
+ return UMP_INVALID_MEMORY_HANDLE;
+}
diff --git a/src/ump_ref_drv.h b/src/ump_ref_drv.h
new file mode 100644
index 0000000..c8c6a0a
--- /dev/null
+++ b/src/ump_ref_drv.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010, 2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump_ref_drv.h
+ *
+ * Reference driver extensions to the UMP user space API for allocating UMP memory
+ */
+
+#ifndef _UNIFIED_MEMORY_PROVIDER_REF_DRV_H_
+#define _UNIFIED_MEMORY_PROVIDER_REF_DRV_H_
+
+#include "ump.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum
+{
+ /* This enum must match with the IOCTL enum in ump_ioctl.h */
+ UMP_REF_DRV_CONSTRAINT_NONE = 0,
+ UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR = 1,
+ UMP_REF_DRV_CONSTRAINT_USE_CACHE = 4,
+} ump_alloc_constraints;
+
+/** Allocate an UMP handle containing a memory buffer.
+ * Input: Size: The minimum size for the allocation.
+ * Usage: If this is UMP_REF_DRV_CONSTRAINT_USE_CACHE, the allocation is mapped as cached by the cpu.
+ * If it is UMP_REF_DRV_CONSTRAINT_NONE it is mapped as noncached.
+ * The flag UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR is not supported.*/
+UMP_API_EXPORT ump_handle ump_ref_drv_allocate(unsigned long size, ump_alloc_constraints usage);
+
+typedef enum
+{
+ UMP_MSYNC_CLEAN = 0 ,
+ UMP_MSYNC_CLEAN_AND_INVALIDATE = 1,
+ UMP_MSYNC_READOUT_CACHE_ENABLED = 128,
+} ump_cpu_msync_op;
+
+/** Flushing cache for an ump_handle.
+ * The function will always CLEAN_AND_INVALIDATE as long as the \a op is not UMP_MSYNC_READOUT_CACHE_ENABLED.
+ * If so it will only report back if the given ump_handle is cacheable.
+ * At the momement the implementation does not use \a address or \a size.
+ * Return value is 1 if cache is enabled, and 0 if it is disabled for the given allocation.*/
+UMP_API_EXPORT int ump_cpu_msync_now(ump_handle mem, ump_cpu_msync_op op, void* address, int size);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_UNIFIED_MEMORY_PROVIDER_REF_DRV_H_ */
diff --git a/src/ump_uk_types.h b/src/ump_uk_types.h
new file mode 100644
index 0000000..791e776
--- /dev/null
+++ b/src/ump_uk_types.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010, 2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump_uk_types.h
+ * Defines the types and constants used in the user-kernel interface
+ */
+
+#ifndef __UMP_UK_TYPES_H__
+#define __UMP_UK_TYPES_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Helpers for API version handling */
+#define MAKE_VERSION_ID(x) (((x) << 16UL) | (x))
+#define IS_VERSION_ID(x) (((x) & 0xFFFF) == (((x) >> 16UL) & 0xFFFF))
+#define GET_VERSION(x) (((x) >> 16UL) & 0xFFFF)
+#define IS_API_MATCH(x, y) (IS_VERSION_ID((x)) && IS_VERSION_ID((y)) && (GET_VERSION((x)) == GET_VERSION((y))))
+
+/**
+ * API version define.
+ * Indicates the version of the kernel API
+ * The version is a 16bit integer incremented on each API change.
+ * The 16bit integer is stored twice in a 32bit integer
+ * So for version 1 the value would be 0x00010001
+ */
+#define UMP_IOCTL_API_VERSION MAKE_VERSION_ID(2)
+
+typedef enum
+{
+ _UMP_IOC_QUERY_API_VERSION = 1,
+ _UMP_IOC_ALLOCATE,
+ _UMP_IOC_RELEASE,
+ _UMP_IOC_SIZE_GET,
+ _UMP_IOC_MAP_MEM, /* not used in Linux */
+ _UMP_IOC_UNMAP_MEM, /* not used in Linux */
+ _UMP_IOC_MSYNC,
+}_ump_uk_functions;
+
+typedef enum
+{
+ UMP_REF_DRV_UK_CONSTRAINT_NONE = 0,
+ UMP_REF_DRV_UK_CONSTRAINT_PHYSICALLY_LINEAR = 1,
+ UMP_REF_DRV_UK_CONSTRAINT_USE_CACHE = 4,
+} ump_uk_alloc_constraints;
+
+typedef enum
+{
+ _UMP_UK_MSYNC_CLEAN = 0,
+ _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE = 1,
+ _UMP_UK_MSYNC_READOUT_CACHE_ENABLED = 128,
+} ump_uk_msync_op;
+
+/**
+ * Get API version ([in,out] u32 api_version, [out] u32 compatible)
+ */
+typedef struct _ump_uk_api_version_s
+{
+ void *ctx; /**< [in,out] user-kernel context (trashed on output) */
+ u32 version; /**< Set to the user space version on entry, stores the device driver version on exit */
+ u32 compatible; /**< Non-null if the device is compatible with the client */
+} _ump_uk_api_version_s;
+
+/**
+ * ALLOCATE ([out] u32 secure_id, [in,out] u32 size, [in] contraints)
+ */
+typedef struct _ump_uk_allocate_s
+{
+ void *ctx; /**< [in,out] user-kernel context (trashed on output) */
+ u32 secure_id; /**< Return value from DD to Userdriver */
+ u32 size; /**< Input and output. Requested size; input. Returned size; output */
+ ump_uk_alloc_constraints constraints; /**< Only input to Devicedriver */
+} _ump_uk_allocate_s;
+
+/**
+ * SIZE_GET ([in] u32 secure_id, [out]size )
+ */
+typedef struct _ump_uk_size_get_s
+{
+ void *ctx; /**< [in,out] user-kernel context (trashed on output) */
+ u32 secure_id; /**< Input to DD */
+ u32 size; /**< Returned size; output */
+} _ump_uk_size_get_s;
+
+/**
+ * Release ([in] u32 secure_id)
+ */
+typedef struct _ump_uk_release_s
+{
+ void *ctx; /**< [in,out] user-kernel context (trashed on output) */
+ u32 secure_id; /**< Input to DD */
+} _ump_uk_release_s;
+
+typedef struct _ump_uk_map_mem_s
+{
+ void *ctx; /**< [in,out] user-kernel context (trashed on output) */
+ void *mapping; /**< [out] Returns user-space virtual address for the mapping */
+ void *phys_addr; /**< [in] physical address */
+ unsigned long size; /**< [in] size */
+ u32 secure_id; /**< [in] secure_id to assign to mapping */
+ void * _ukk_private; /**< Only used inside linux port between kernel frontend and common part to store vma */
+ u32 cookie;
+ u32 is_cached; /**< [in,out] caching of CPU mappings */
+} _ump_uk_map_mem_s;
+
+typedef struct _ump_uk_unmap_mem_s
+{
+ void *ctx; /**< [in,out] user-kernel context (trashed on output) */
+ void *mapping;
+ u32 size;
+ void * _ukk_private;
+ u32 cookie;
+} _ump_uk_unmap_mem_s;
+
+typedef struct _ump_uk_msync_s
+{
+ void *ctx; /**< [in,out] user-kernel context (trashed on output) */
+ void *mapping; /**< [in] mapping addr */
+ void *address; /**< [in] flush start addr */
+ u32 size; /**< [in] size to flush */
+ ump_uk_msync_op op; /**< [in] flush operation */
+ u32 cookie; /**< [in] cookie stored with reference to the kernel mapping internals */
+ u32 secure_id; /**< [in] cookie stored with reference to the kernel mapping internals */
+ u32 is_cached; /**< [out] caching of CPU mappings */
+} _ump_uk_msync_s;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UMP_UK_TYPES_H__ */
diff --git a/src/ump_uku.c b/src/ump_uku.c
new file mode 100644
index 0000000..5d4604f
--- /dev/null
+++ b/src/ump_uku.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump_uku.c
+ * File implements the user side of the user-kernel interface
+ */
+
+#include "ump_uku.h"
+#include <stdio.h>
+#include "ump_ioctl.h"
+
+#include <sys/mman.h>
+
+/* Needed for file operations on the device file*/
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+static _ump_osu_errcode_t ump_driver_ioctl(void *context, u32 command, void *args);
+
+static int ump_ioctl_api_version_used = UMP_IOCTL_API_VERSION;
+
+/**
+ * The device file to access the UMP device driver
+ * This is a character special file giving access to the device driver.
+ * Usually created using the mknod command line utility.
+ */
+static const char ump_device_file_name[] = "/dev/ump";
+
+_ump_osu_errcode_t _ump_uku_open( void **context )
+{
+ int ump_device_file;
+ if(NULL == context)
+ {
+ return _UMP_OSU_ERR_FAULT;
+ }
+
+ ump_device_file = open(ump_device_file_name, O_RDWR);
+
+ if (-1 == ump_device_file)
+ {
+ return _UMP_OSU_ERR_FAULT;
+ }
+
+ {
+ struct _ump_uk_api_version_s args;
+ args.ctx = (void*)ump_device_file;
+ args.version = UMP_IOCTL_API_VERSION;
+ args.compatible = 3;
+ ump_driver_ioctl(args.ctx, UMP_IOC_QUERY_API_VERSION, &args);
+ if ( 1 != args.compatible )
+ {
+ if (IS_API_MATCH(MAKE_VERSION_ID(1), args.version))
+ {
+ ump_ioctl_api_version_used = MAKE_VERSION_ID(1);
+ UMP_PRINTF("The UMP devicedriver does not support cached UMP. Update it if this is needed.\n");
+ }
+ else
+ {
+ UMP_PRINTF("The UMP devicedriver is version: %d, UMP libraries is version: %d.\n", GET_VERSION(args.version), GET_VERSION(UMP_IOCTL_API_VERSION) );
+ close(ump_device_file);
+ return _UMP_OSU_ERR_FAULT;
+ }
+ }
+ }
+
+ *context = (void *) ump_device_file;
+ return _UMP_OSU_ERR_OK;
+}
+
+_ump_osu_errcode_t _ump_uku_close( void **context )
+{
+ if(NULL == context)
+ {
+ return _UMP_OSU_ERR_FAULT;
+ }
+
+ if(-1 == (int)*context)
+ {
+ return _UMP_OSU_ERR_FAULT;
+ }
+
+ close((int)*context);
+ *context = (void *)-1;
+
+ return _UMP_OSU_ERR_OK;
+}
+
+int _ump_uku_allocate(_ump_uk_allocate_s *args)
+{
+ return ump_driver_ioctl(args->ctx, UMP_IOC_ALLOCATE, args);
+}
+
+_ump_osu_errcode_t _ump_uku_release(_ump_uk_release_s *args)
+{
+ return ump_driver_ioctl(args->ctx, UMP_IOC_RELEASE, args);
+}
+
+_ump_osu_errcode_t _ump_uku_size_get(_ump_uk_size_get_s *args)
+{
+ return ump_driver_ioctl(args->ctx, UMP_IOC_SIZE_GET, args);
+}
+
+
+void _ump_uku_msynch(_ump_uk_msync_s *args)
+{
+ /* This is for backwards compatibillity */
+ if ( MAKE_VERSION_ID(1) == ump_ioctl_api_version_used)
+ {
+ args->is_cached = 0;
+ if ( _UMP_UK_MSYNC_READOUT_CACHE_ENABLED != args->op )
+ {
+ UMP_DEBUG_PRINT(3, ("Warning: Doing UMP cache flush operations on a Device Driver that does not support cached UMP mem.\n"));
+ }
+ return;
+ }
+ ump_driver_ioctl(args->ctx, UMP_IOC_MSYNC, args);
+}
+
+int _ump_uku_map_mem(_ump_uk_map_mem_s *args)
+{
+ int flags;
+ if( -1 == (int)args->ctx )
+ {
+ return -1;
+ }
+
+ flags = MAP_SHARED;
+
+ /* This is for backwards compatibillity */
+ if ( MAKE_VERSION_ID(1) == ump_ioctl_api_version_used)
+ {
+ args->is_cached = 0;
+ }
+
+ /* If we want the Caching to be enabled we set the flags to be PRIVATE. The UMP DD reads this and do proper handling
+ Note: this enforces the user to use proper invalidation*/
+ if ( args->is_cached ) flags = MAP_PRIVATE;
+
+ args->mapping = mmap(NULL, args->size, PROT_READ | PROT_WRITE ,flags , (int)args->ctx, (off_t)args->secure_id * sysconf(_SC_PAGE_SIZE));
+ if (MAP_FAILED == args->mapping)
+ {
+ return -1;
+ }
+
+ args->cookie = 0; /* Cookie is not used in linux _ump_uku_unmap_mem */
+
+ return 0;
+}
+
+void _ump_uku_unmap_mem( _ump_uk_unmap_mem_s *args )
+{
+ /*
+ * If a smaller size is used Linux will just remove the requested range but don't tell
+ * the ump driver before all of it is unmapped, either via another unmap request or upon process shutdown.
+ * Unmapping too much will just ignore the overhead or hit undefined behavior,
+ * only affecting the calling process which could mess itself up in other ways anyway.
+ * So we don't need any security checks here.
+ */
+ munmap(args->mapping, args->size);
+}
+
+static _ump_osu_errcode_t ump_driver_ioctl(void *context, u32 command, void *args)
+{
+ /*UMP_CHECK_NON_NULL(args, _UMP_OSK_ERR_INVALID_ARGS);*/
+
+ /* check for a valid file descriptor */
+ /** @note manual type safety check-point */
+ if( -1 == (int)context )
+ {
+ return _UMP_OSU_ERR_FAULT;
+ }
+
+ /* call ioctl handler of driver */
+ if (0 != ioctl((int)context, command, args)) return -1;
+ return _UMP_OSU_ERR_OK;
+}
diff --git a/src/ump_uku.h b/src/ump_uku.h
new file mode 100644
index 0000000..79a7e79
--- /dev/null
+++ b/src/ump_uku.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ump_uku.h
+ * Defines the user-side interface of the user-kernel interface
+ */
+
+#ifndef __UMP_UKU_H__
+#define __UMP_UKU_H__
+
+#include <ump/ump_osu.h>
+#include <ump/ump_debug.h>
+#include <ump/ump_uk_types.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+_ump_osu_errcode_t _ump_uku_open( void **context );
+
+_ump_osu_errcode_t _ump_uku_close( void **context );
+
+_ump_osu_errcode_t _ump_uku_allocate( _ump_uk_allocate_s *args );
+
+_ump_osu_errcode_t _ump_uku_release( _ump_uk_release_s *args );
+
+_ump_osu_errcode_t _ump_uku_size_get( _ump_uk_size_get_s *args );
+
+_ump_osu_errcode_t _ump_uku_get_api_version( _ump_uk_api_version_s *args );
+
+int _ump_uku_map_mem( _ump_uk_map_mem_s *args );
+
+void _ump_uku_unmap_mem( _ump_uk_unmap_mem_s *args );
+
+void _ump_uku_msynch(_ump_uk_msync_s *args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UMP_UKU_H__ */