blob: 011ee159efdeb9bda5b97af89f40efcb27ffceef [file] [log] [blame]
/*
* Copyright (C) 2010-2013 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/fs.h> /* file system operations */
#include <asm/uaccess.h> /* user space access */
#include "mali_ukk.h"
#include "mali_osk.h"
#include "mali_kernel_common.h"
#include "mali_session.h"
#include "mali_ukk_wrappers.h"
int mem_init_wrapper(struct mali_session_data *session_data, _mali_uk_init_mem_s __user *uargs)
{
_mali_uk_init_mem_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_init_mem(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
return map_errcode(err);
}
if (0 != put_user(kargs.mali_address_base, &uargs->mali_address_base)) goto mem_init_rollback;
if (0 != put_user(kargs.memory_size, &uargs->memory_size)) goto mem_init_rollback;
return 0;
mem_init_rollback:
{
_mali_uk_term_mem_s kargs;
kargs.ctx = session_data;
err = _mali_ukk_term_mem(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
MALI_DEBUG_PRINT(4, ("reverting _mali_ukk_init_mem, as a result of failing put_user(), failed\n"));
}
}
return -EFAULT;
}
int mem_term_wrapper(struct mali_session_data *session_data, _mali_uk_term_mem_s __user *uargs)
{
_mali_uk_term_mem_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_term_mem(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
return map_errcode(err);
}
return 0;
}
int mem_write_safe_wrapper(struct mali_session_data *session_data, _mali_uk_mem_write_safe_s __user * uargs)
{
_mali_uk_mem_write_safe_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
MALI_CHECK_NON_NULL(session_data, -EINVAL);
if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_mem_write_safe_s)))
{
return -EFAULT;
}
kargs.ctx = session_data;
/* Check if we can access the buffers */
if (!access_ok(VERIFY_WRITE, kargs.dest, kargs.size)
|| !access_ok(VERIFY_READ, kargs.src, kargs.size))
{
return -EINVAL;
}
/* Check if size wraps */
if ((kargs.size + kargs.dest) <= kargs.dest
|| (kargs.size + kargs.src) <= kargs.src)
{
return -EINVAL;
}
err = _mali_ukk_mem_write_safe(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
return map_errcode(err);
}
if (0 != put_user(kargs.size, &uargs->size))
{
return -EFAULT;
}
return 0;
}
int mem_map_ext_wrapper(struct mali_session_data *session_data, _mali_uk_map_external_mem_s __user * argument)
{
_mali_uk_map_external_mem_s uk_args;
_mali_osk_errcode_t err_code;
/* validate input */
/* the session_data pointer was validated by caller */
MALI_CHECK_NON_NULL( argument, -EINVAL);
/* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_map_external_mem_s)) )
{
return -EFAULT;
}
uk_args.ctx = session_data;
err_code = _mali_ukk_map_external_mem( &uk_args );
if (0 != put_user(uk_args.cookie, &argument->cookie))
{
if (_MALI_OSK_ERR_OK == err_code)
{
/* Rollback */
_mali_uk_unmap_external_mem_s uk_args_unmap;
uk_args_unmap.ctx = session_data;
uk_args_unmap.cookie = uk_args.cookie;
err_code = _mali_ukk_unmap_external_mem( &uk_args_unmap );
if (_MALI_OSK_ERR_OK != err_code)
{
MALI_DEBUG_PRINT(4, ("reverting _mali_ukk_unmap_external_mem, as a result of failing put_user(), failed\n"));
}
}
return -EFAULT;
}
/* Return the error that _mali_ukk_free_big_block produced */
return map_errcode(err_code);
}
int mem_unmap_ext_wrapper(struct mali_session_data *session_data, _mali_uk_unmap_external_mem_s __user * argument)
{
_mali_uk_unmap_external_mem_s uk_args;
_mali_osk_errcode_t err_code;
/* validate input */
/* the session_data pointer was validated by caller */
MALI_CHECK_NON_NULL( argument, -EINVAL);
/* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_unmap_external_mem_s)) )
{
return -EFAULT;
}
uk_args.ctx = session_data;
err_code = _mali_ukk_unmap_external_mem( &uk_args );
/* Return the error that _mali_ukk_free_big_block produced */
return map_errcode(err_code);
}
#if defined(CONFIG_MALI400_UMP)
int mem_release_ump_wrapper(struct mali_session_data *session_data, _mali_uk_release_ump_mem_s __user * argument)
{
_mali_uk_release_ump_mem_s uk_args;
_mali_osk_errcode_t err_code;
/* validate input */
/* the session_data pointer was validated by caller */
MALI_CHECK_NON_NULL( argument, -EINVAL);
/* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_release_ump_mem_s)) )
{
return -EFAULT;
}
uk_args.ctx = session_data;
err_code = _mali_ukk_release_ump_mem( &uk_args );
/* Return the error that _mali_ukk_free_big_block produced */
return map_errcode(err_code);
}
int mem_attach_ump_wrapper(struct mali_session_data *session_data, _mali_uk_attach_ump_mem_s __user * argument)
{
_mali_uk_attach_ump_mem_s uk_args;
_mali_osk_errcode_t err_code;
/* validate input */
/* the session_data pointer was validated by caller */
MALI_CHECK_NON_NULL( argument, -EINVAL);
/* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */
if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_attach_ump_mem_s)) )
{
return -EFAULT;
}
uk_args.ctx = session_data;
err_code = _mali_ukk_attach_ump_mem( &uk_args );
if (0 != put_user(uk_args.cookie, &argument->cookie))
{
if (_MALI_OSK_ERR_OK == err_code)
{
/* Rollback */
_mali_uk_release_ump_mem_s uk_args_unmap;
uk_args_unmap.ctx = session_data;
uk_args_unmap.cookie = uk_args.cookie;
err_code = _mali_ukk_release_ump_mem( &uk_args_unmap );
if (_MALI_OSK_ERR_OK != err_code)
{
MALI_DEBUG_PRINT(4, ("reverting _mali_ukk_attach_mem, as a result of failing put_user(), failed\n"));
}
}
return -EFAULT;
}
/* Return the error that _mali_ukk_map_external_ump_mem produced */
return map_errcode(err_code);
}
#endif /* CONFIG_MALI400_UMP */
int mem_query_mmu_page_table_dump_size_wrapper(struct mali_session_data *session_data, _mali_uk_query_mmu_page_table_dump_size_s __user * uargs)
{
_mali_uk_query_mmu_page_table_dump_size_s kargs;
_mali_osk_errcode_t err;
MALI_CHECK_NON_NULL(uargs, -EINVAL);
MALI_CHECK_NON_NULL(session_data, -EINVAL);
kargs.ctx = session_data;
err = _mali_ukk_query_mmu_page_table_dump_size(&kargs);
if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
if (0 != put_user(kargs.size, &uargs->size)) return -EFAULT;
return 0;
}
int mem_dump_mmu_page_table_wrapper(struct mali_session_data *session_data, _mali_uk_dump_mmu_page_table_s __user * uargs)
{
_mali_uk_dump_mmu_page_table_s kargs;
_mali_osk_errcode_t err;
void *buffer;
int rc = -EFAULT;
/* validate input */
MALI_CHECK_NON_NULL(uargs, -EINVAL);
/* the session_data pointer was validated by caller */
kargs.buffer = NULL;
/* get location of user buffer */
if (0 != get_user(buffer, &uargs->buffer)) goto err_exit;
/* get size of mmu page table info buffer from user space */
if ( 0 != get_user(kargs.size, &uargs->size) ) goto err_exit;
/* verify we can access the whole of the user buffer */
if (!access_ok(VERIFY_WRITE, buffer, kargs.size)) goto err_exit;
/* allocate temporary buffer (kernel side) to store mmu page table info */
MALI_CHECK(kargs.size > 0, -ENOMEM);
kargs.buffer = _mali_osk_valloc(kargs.size);
if (NULL == kargs.buffer)
{
rc = -ENOMEM;
goto err_exit;
}
kargs.ctx = session_data;
err = _mali_ukk_dump_mmu_page_table(&kargs);
if (_MALI_OSK_ERR_OK != err)
{
rc = map_errcode(err);
goto err_exit;
}
/* copy mmu page table info back to user space and update pointers */
if (0 != copy_to_user(uargs->buffer, kargs.buffer, kargs.size) ) goto err_exit;
if (0 != put_user((kargs.register_writes - (u32 *)kargs.buffer) + (u32 *)uargs->buffer, &uargs->register_writes)) goto err_exit;
if (0 != put_user((kargs.page_table_dump - (u32 *)kargs.buffer) + (u32 *)uargs->buffer, &uargs->page_table_dump)) goto err_exit;
if (0 != put_user(kargs.register_writes_size, &uargs->register_writes_size)) goto err_exit;
if (0 != put_user(kargs.page_table_dump_size, &uargs->page_table_dump_size)) goto err_exit;
rc = 0;
err_exit:
if (kargs.buffer) _mali_osk_vfree(kargs.buffer);
return rc;
}