Skip to content

Commit

Permalink
metag: System Calls
Browse files Browse the repository at this point in the history
Add metag system call and gateway page interfaces. The metag
architecture port uses the generic system call numbers from
asm-generic/unistd.h, as well as a user gateway page mapped at
0x6ffff000 which contains fast atomic primitives (depending on SMP) and
a fast method of accessing TLS data.

System calls use the SWITCH instruction with the immediate 0x440001 to
signal a system call.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
  • Loading branch information
James Hogan committed Mar 2, 2013
1 parent 5698c50 commit 26025bb
Show file tree
Hide file tree
Showing 8 changed files with 508 additions and 0 deletions.
11 changes: 11 additions & 0 deletions arch/metag/include/asm/mman.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef __METAG_MMAN_H__
#define __METAG_MMAN_H__

#include <uapi/asm/mman.h>

#ifndef __ASSEMBLY__
#define arch_mmap_check metag_mmap_check
int metag_mmap_check(unsigned long addr, unsigned long len,
unsigned long flags);
#endif
#endif /* __METAG_MMAN_H__ */
104 changes: 104 additions & 0 deletions arch/metag/include/asm/syscall.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Access to user system call parameters and results
*
* Copyright (C) 2008 Imagination Technologies Ltd.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* See asm-generic/syscall.h for descriptions of what we must do here.
*/

#ifndef _ASM_METAG_SYSCALL_H
#define _ASM_METAG_SYSCALL_H

#include <linux/sched.h>
#include <linux/err.h>
#include <linux/uaccess.h>

#include <asm/switch.h>

static inline long syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
{
unsigned long insn;

/*
* FIXME there's no way to find out how we got here other than to
* examine the memory at the PC to see if it is a syscall
* SWITCH instruction.
*/
if (get_user(insn, (unsigned long *)(regs->ctx.CurrPC - 4)))
return -1;

if (insn == __METAG_SW_ENCODING(SYS))
return regs->ctx.DX[0].U1;
else
return -1L;
}

static inline void syscall_rollback(struct task_struct *task,
struct pt_regs *regs)
{
/* do nothing */
}

static inline long syscall_get_error(struct task_struct *task,
struct pt_regs *regs)
{
unsigned long error = regs->ctx.DX[0].U0;
return IS_ERR_VALUE(error) ? error : 0;
}

static inline long syscall_get_return_value(struct task_struct *task,
struct pt_regs *regs)
{
return regs->ctx.DX[0].U0;
}

static inline void syscall_set_return_value(struct task_struct *task,
struct pt_regs *regs,
int error, long val)
{
regs->ctx.DX[0].U0 = (long) error ?: val;
}

static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned int i, unsigned int n,
unsigned long *args)
{
unsigned int reg, j;
BUG_ON(i + n > 6);

for (j = i, reg = 6 - i; j < (i + n); j++, reg--) {
if (reg % 2)
args[j] = regs->ctx.DX[(reg + 1) / 2].U0;
else
args[j] = regs->ctx.DX[reg / 2].U1;
}
}

static inline void syscall_set_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned int i, unsigned int n,
const unsigned long *args)
{
unsigned int reg;
BUG_ON(i + n > 6);

for (reg = 6 - i; i < (i + n); i++, reg--) {
if (reg % 2)
regs->ctx.DX[(reg + 1) / 2].U0 = args[i];
else
regs->ctx.DX[reg / 2].U1 = args[i];
}
}

#define NR_syscalls __NR_syscalls

/* generic syscall table */
extern const void *sys_call_table[];

#endif /* _ASM_METAG_SYSCALL_H */
39 changes: 39 additions & 0 deletions arch/metag/include/asm/syscalls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#ifndef _ASM_METAG_SYSCALLS_H
#define _ASM_METAG_SYSCALLS_H

#include <linux/compiler.h>
#include <linux/linkage.h>
#include <linux/types.h>
#include <linux/signal.h>

/* kernel/signal.c */
#define sys_rt_sigreturn sys_rt_sigreturn
asmlinkage long sys_rt_sigreturn(void);

#include <asm-generic/syscalls.h>

/* kernel/sys_metag.c */
asmlinkage int sys_metag_setglobalbit(char __user *, int);
asmlinkage void sys_metag_set_fpu_flags(unsigned int);
asmlinkage int sys_metag_set_tls(void __user *);
asmlinkage void *sys_metag_get_tls(void);

asmlinkage long sys_truncate64_metag(const char __user *, unsigned long,
unsigned long);
asmlinkage long sys_ftruncate64_metag(unsigned int, unsigned long,
unsigned long);
asmlinkage long sys_fadvise64_64_metag(int, unsigned long, unsigned long,
unsigned long, unsigned long, int);
asmlinkage long sys_readahead_metag(int, unsigned long, unsigned long, size_t);
asmlinkage ssize_t sys_pread64_metag(unsigned long, char __user *, size_t,
unsigned long, unsigned long);
asmlinkage ssize_t sys_pwrite64_metag(unsigned long, char __user *, size_t,
unsigned long, unsigned long);
asmlinkage long sys_sync_file_range_metag(int, unsigned long, unsigned long,
unsigned long, unsigned long,
unsigned int);

int do_work_pending(struct pt_regs *regs, unsigned int thread_flags,
int syscall);

#endif /* _ASM_METAG_SYSCALLS_H */
12 changes: 12 additions & 0 deletions arch/metag/include/asm/unistd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright (C) 2012 Imagination Technologies Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/

#include <uapi/asm/unistd.h>

#define __ARCH_WANT_SYS_CLONE
44 changes: 44 additions & 0 deletions arch/metag/include/asm/user_gateway.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2010 Imagination Technologies
*/

#ifndef __ASM_METAG_USER_GATEWAY_H
#define __ASM_METAG_USER_GATEWAY_H

#include <asm/page.h>

/* Page of kernel code accessible to userspace. */
#define USER_GATEWAY_PAGE 0x6ffff000
/* Offset of TLS pointer array in gateway page. */
#define USER_GATEWAY_TLS 0x100

#ifndef __ASSEMBLY__

extern char __user_gateway_start;
extern char __user_gateway_end;

/* Kernel mapping of the gateway page. */
extern void *gateway_page;

static inline void set_gateway_tls(void __user *tls_ptr)
{
void **gateway_tls = (void **)(gateway_page + USER_GATEWAY_TLS +
hard_processor_id() * 4);

*gateway_tls = (__force void *)tls_ptr;
#ifdef CONFIG_METAG_META12
/* Avoid cache aliases on virtually tagged cache. */
__builtin_dcache_flush((void *)USER_GATEWAY_PAGE + USER_GATEWAY_TLS +
hard_processor_id() * sizeof(void *));
#endif
}

extern int __kuser_get_tls(void);
extern char *__kuser_get_tls_end[];

extern int __kuser_cmpxchg(int, int, unsigned long *);
extern char *__kuser_cmpxchg_end[];

#endif

#endif
21 changes: 21 additions & 0 deletions arch/metag/include/uapi/asm/unistd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2012 Imagination Technologies Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/

/* Use the standard ABI for syscalls. */
#include <asm-generic/unistd.h>

/* metag-specific syscalls. */
#define __NR_metag_setglobalbit (__NR_arch_specific_syscall + 1)
__SYSCALL(__NR_metag_setglobalbit, sys_metag_setglobalbit)
#define __NR_metag_set_fpu_flags (__NR_arch_specific_syscall + 2)
__SYSCALL(__NR_metag_set_fpu_flags, sys_metag_set_fpu_flags)
#define __NR_metag_set_tls (__NR_arch_specific_syscall + 3)
__SYSCALL(__NR_metag_set_tls, sys_metag_set_tls)
#define __NR_metag_get_tls (__NR_arch_specific_syscall + 4)
__SYSCALL(__NR_metag_get_tls, sys_metag_get_tls)
Loading

0 comments on commit 26025bb

Please sign in to comment.