/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 1995 , 1996 , 1997 , 2000 , 2001 , 05 by Ralf Baechle
* Copyright ( C ) 1999 , 2000 Silicon Graphics , Inc .
* Copyright ( C ) 2001 MIPS Technologies , Inc .
*/
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/fs.h>
#include <linux/smp.h>
#include <linux/ptrace.h>
#include <linux/string.h>
#include <linux/syscalls.h>
#include <linux/file.h>
#include <linux/utsname.h>
#include <linux/unistd.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/compiler.h>
#include <linux/ipc.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/elf.h>
#include <linux/sched/task_stack.h>
#include <asm /asm .h>
#include <asm /asm -eva.h>
#include <asm /branch.h>
#include <asm /cachectl.h>
#include <asm /cacheflush.h>
#include <asm /asm -offsets.h>
#include <asm /signal.h>
#include <asm /sim.h>
#include <asm /shmparam.h>
#include <asm /sync.h>
#include <asm /sysmips.h>
#include <asm /syscalls.h>
#include <asm /switch_to.h>
/*
* For historic reasons the pipe ( 2 ) syscall on MIPS has an unusual calling
* convention . It returns results in registers $ v0 / $ v1 which means there
* is no need for it to do verify the validity of a userspace pointer
* argument . Historically that used to be expensive in Linux . These days
* the performance advantage is negligible .
*/
asmlinkage int sysm_pipe(void )
{
int fd[2 ];
int error = do_pipe_flags(fd, 0 );
if (error)
return error;
current_pt_regs()->regs[3 ] = fd[1 ];
return fd[0 ];
}
SYSCALL_DEFINE6(mips_mmap, unsigned long , addr, unsigned long , len,
unsigned long , prot, unsigned long , flags, unsigned long ,
fd, off_t, offset)
{
if (offset & ~PAGE_MASK)
return -EINVAL;
return ksys_mmap_pgoff(addr, len, prot, flags, fd,
offset >> PAGE_SHIFT);
}
SYSCALL_DEFINE6(mips_mmap2, unsigned long , addr, unsigned long , len,
unsigned long , prot, unsigned long , flags, unsigned long , fd,
unsigned long , pgoff)
{
if (pgoff & (~PAGE_MASK >> 12 ))
return -EINVAL;
return ksys_mmap_pgoff(addr, len, prot, flags, fd,
pgoff >> (PAGE_SHIFT - 12 ));
}
save_static_function(sys_fork);
save_static_function(sys_clone);
save_static_function(sys_clone3);
SYSCALL_DEFINE1(set_thread_area, unsigned long , addr)
{
struct thread_info *ti = task_thread_info(current);
ti->tp_value = addr;
if (cpu_has_userlocal)
write_c0_userlocal(addr);
return 0 ;
}
static inline int mips_atomic_set(unsigned long addr, unsigned long new )
{
unsigned long old, tmp;
struct pt_regs *regs;
unsigned int err;
if (unlikely(addr & 3 ))
return -EINVAL;
if (unlikely(!access_ok((const void __user *)addr, 4 )))
return -EINVAL;
if (cpu_has_llsc && IS_ENABLED(CONFIG_WAR_R10000_LLSC)) {
__asm__ __volatile__ (
" .set push \n"
" .set arch=r4000 \n"
" li %[err], 0 \n"
"1: ll %[old], (%[addr]) \n"
" move %[tmp], %[new] \n"
"2: sc %[tmp], (%[addr]) \n"
" beqzl %[tmp], 1b \n"
"3: \n"
" .insn \n"
" .section .fixup,\" ax\" \n"
"4: li %[err], %[efault] \n"
" j 3b \n"
" .previous \n"
" .section __ex_table,\" a\" \n"
" " STR(PTR_WD)" 1b, 4b \n"
" " STR(PTR_WD)" 2b, 4b \n"
" .previous \n"
" .set pop \n"
: [old] "=&r" (old),
[err] "=&r" (err),
[tmp] "=&r" (tmp)
: [addr] "r" (addr),
[new ] "r" (new ),
[efault] "i" (-EFAULT)
: "memory" );
} else if (cpu_has_llsc) {
__asm__ __volatile__ (
" .set push \n"
" .set " MIPS_ISA_ARCH_LEVEL" \n"
" li %[err], 0 \n"
"1: \n"
" " __SYNC(full, loongson3_war) " \n"
user_ll("%[old]" , "(%[addr])" )
" move %[tmp], %[new] \n"
"2: \n"
user_sc("%[tmp]" , "(%[addr])" )
" beqz %[tmp], 1b \n"
"3: \n"
" .insn \n"
" .section .fixup,\" ax\" \n"
"5: li %[err], %[efault] \n"
" j 3b \n"
" .previous \n"
" .section __ex_table,\" a\" \n"
" " STR(PTR_WD)" 1b, 5b \n"
" " STR(PTR_WD)" 2b, 5b \n"
" .previous \n"
" .set pop \n"
: [old] "=&r" (old),
[err] "=&r" (err),
[tmp] "=&r" (tmp)
: [addr] "r" (addr),
[new ] "r" (new ),
[efault] "i" (-EFAULT)
: "memory" );
} else {
do {
preempt_disable();
ll_bit = 1 ;
ll_task = current;
preempt_enable();
err = __get_user(old, (unsigned int *) addr);
err |= __put_user(new , (unsigned int *) addr);
if (err)
break ;
rmb();
} while (!ll_bit);
}
if (unlikely(err))
return err;
regs = current_pt_regs();
regs->regs[2 ] = old;
regs->regs[7 ] = 0 ; /* No error */
/*
* Don ' t let your children do this . . .
*/
__asm__ __volatile__(
" move $29, %0 \n"
" j syscall_exit \n"
: /* no outputs */
: "r" (regs));
/* unreached. Honestly. */
unreachable();
}
/*
* mips_atomic_set ( ) normally returns directly via syscall_exit potentially
* clobbering static registers , so be sure to preserve them .
*/
save_static_function(sys_sysmips);
SYSCALL_DEFINE3(sysmips, long , cmd, long , arg1, long , arg2)
{
switch (cmd) {
case MIPS_ATOMIC_SET:
return mips_atomic_set(arg1, arg2);
case MIPS_FIXADE:
if (arg1 & ~3 )
return -EINVAL;
if (arg1 & 1 )
set_thread_flag(TIF_FIXADE);
else
clear_thread_flag(TIF_FIXADE);
if (arg1 & 2 )
set_thread_flag(TIF_LOGADE);
else
clear_thread_flag(TIF_LOGADE);
return 0 ;
case FLUSH_CACHE:
__flush_cache_all();
return 0 ;
}
return -EINVAL;
}
/*
* No implemented yet . . .
*/
SYSCALL_DEFINE3(cachectl, char *, addr, int , nbytes, int , op)
{
return -ENOSYS;
}
Messung V0.5 in Prozent C=95 H=93 G=93
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland