blob: 767c5371cf39fcb8f5eddd23f5fbde45be714c8f [file] [log] [blame]
/*
* AArch64 alt-syscall implementation
*
* Copyright (C) 2015 Google, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/alt-syscall.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <asm/syscall.h>
int arch_dup_sys_call_table(struct alt_sys_call_table *entry)
{
int err;
if (!entry)
return -EINVAL;
if (entry->table)
return -EINVAL;
#ifdef CONFIG_COMPAT
if (entry->compat_table)
return -EINVAL;
#endif
entry->size = __NR_syscalls;
entry->table = kcalloc(entry->size, sizeof(sys_call_ptr_t), GFP_KERNEL);
if (!entry->table) {
err = -ENOMEM;
goto failed;
}
memcpy(entry->table, sys_call_table,
entry->size * sizeof(sys_call_ptr_t));
#ifdef CONFIG_COMPAT
entry->compat_size = __NR_compat_syscalls;
entry->compat_table = kcalloc(entry->compat_size,
sizeof(sys_call_ptr_t), GFP_KERNEL);
if (!entry->compat_table) {
err = -ENOMEM;
goto compat_failed;
}
memcpy(entry->compat_table, compat_sys_call_table,
entry->compat_size * sizeof(sys_call_ptr_t));
#endif
return 0;
#ifdef CONFIG_COMPAT
compat_failed:
entry->compat_size = 0;
kfree(entry->table);
entry->table = NULL;
#endif
failed:
entry->size = 0;
return err;
}
int arch_set_sys_call_table(struct alt_sys_call_table *entry)
{
if (!entry)
return -EINVAL;
current_thread_info()->nr_syscalls = entry->size;
current_thread_info()->sys_call_table = entry->table;
#ifdef CONFIG_COMPAT
current_thread_info()->compat_nr_syscalls = entry->compat_size;
current_thread_info()->compat_sys_call_table = entry->compat_table;
#endif
return 0;
}