diff options
Diffstat (limited to 'exynos4/hal/libump/os')
-rw-r--r-- | exynos4/hal/libump/os/linux/ump_ioctl.h | 55 | ||||
-rw-r--r-- | exynos4/hal/libump/os/linux/ump_osu_locks.c | 537 | ||||
-rw-r--r-- | exynos4/hal/libump/os/linux/ump_osu_memory.c | 60 | ||||
-rw-r--r-- | exynos4/hal/libump/os/linux/ump_uku.c | 193 | ||||
-rw-r--r-- | exynos4/hal/libump/os/ump_uku.h | 56 |
5 files changed, 901 insertions, 0 deletions
diff --git a/exynos4/hal/libump/os/linux/ump_ioctl.h b/exynos4/hal/libump/os/linux/ump_ioctl.h new file mode 100644 index 0000000..e978858 --- /dev/null +++ b/exynos4/hal/libump/os/linux/ump_ioctl.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010-2011 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/exynos4/hal/libump/os/linux/ump_osu_locks.c b/exynos4/hal/libump/os/linux/ump_osu_locks.c new file mode 100644 index 0000000..97ba858 --- /dev/null +++ b/exynos4/hal/libump/os/linux/ump_osu_locks.c @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2010-2011 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; + + /* 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 1000000ULL +#define UMP_NANOSECS_PER_USEC 1000ULL + + /* 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/exynos4/hal/libump/os/linux/ump_osu_memory.c b/exynos4/hal/libump/os/linux/ump_osu_memory.c new file mode 100644 index 0000000..5807594 --- /dev/null +++ b/exynos4/hal/libump/os/linux/ump_osu_memory.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010-2011 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/exynos4/hal/libump/os/linux/ump_uku.c b/exynos4/hal/libump/os/linux/ump_uku.c new file mode 100644 index 0000000..f46a2c7 --- /dev/null +++ b/exynos4/hal/libump/os/linux/ump_uku.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2010-2011 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/exynos4/hal/libump/os/ump_uku.h b/exynos4/hal/libump/os/ump_uku.h new file mode 100644 index 0000000..7da7185 --- /dev/null +++ b/exynos4/hal/libump/os/ump_uku.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010-2011 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__ */ |