Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  3  * Copyright 2003 PathScale, Inc.
  4  *
  5  * Licensed under the GPL
  6  */
  7 
  8 #include "linux/linkage.h"
  9 #include "linux/personality.h"
 10 #include "linux/utsname.h"
 11 #include "asm/prctl.h" /* XXX This should get the constants from libc */
 12 #include "asm/uaccess.h"
 13 #include "os.h"
 14 
 15 asmlinkage long sys_uname64(struct new_utsname __user * name)
 16 {
 17         int err;
 18 
 19         down_read(&uts_sem);
 20         err = copy_to_user(name, utsname(), sizeof (*name));
 21         up_read(&uts_sem);
 22 
 23         if (personality(current->personality) == PER_LINUX32)
 24                 err |= copy_to_user(&name->machine, "i686", 5);
 25 
 26         return err ? -EFAULT : 0;
 27 }
 28 
 29 long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr)
 30 {
 31         unsigned long *ptr = addr, tmp;
 32         long ret;
 33         int pid = task->mm->context.id.u.pid;
 34 
 35         /*
 36          * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to
 37          * be safe), we need to call arch_prctl on the host because
 38          * setting %fs may result in something else happening (like a
 39          * GDT or thread.fs being set instead).  So, we let the host
 40          * fiddle the registers and thread struct and restore the
 41          * registers afterwards.
 42          *
 43          * So, the saved registers are stored to the process (this
 44          * needed because a stub may have been the last thing to run),
 45          * arch_prctl is run on the host, then the registers are read
 46          * back.
 47          */
 48         switch (code) {
 49         case ARCH_SET_FS:
 50         case ARCH_SET_GS:
 51                 ret = restore_registers(pid, &current->thread.regs.regs);
 52                 if (ret)
 53                         return ret;
 54                 break;
 55         case ARCH_GET_FS:
 56         case ARCH_GET_GS:
 57                 /*
 58                  * With these two, we read to a local pointer and
 59                  * put_user it to the userspace pointer that we were
 60                  * given.  If addr isn't valid (because it hasn't been
 61                  * faulted in or is just bogus), we want put_user to
 62                  * fault it in (or return -EFAULT) instead of having
 63                  * the host return -EFAULT.
 64                  */
 65                 ptr = &tmp;
 66         }
 67 
 68         ret = os_arch_prctl(pid, code, ptr);
 69         if (ret)
 70                 return ret;
 71 
 72         switch (code) {
 73         case ARCH_SET_FS:
 74                 current->thread.arch.fs = (unsigned long) ptr;
 75                 ret = save_registers(pid, &current->thread.regs.regs);
 76                 break;
 77         case ARCH_SET_GS:
 78                 ret = save_registers(pid, &current->thread.regs.regs);
 79                 break;
 80         case ARCH_GET_FS:
 81                 ret = put_user(tmp, addr);
 82                 break;
 83         case ARCH_GET_GS:
 84                 ret = put_user(tmp, addr);
 85                 break;
 86         }
 87 
 88         return ret;
 89 }
 90 
 91 long sys_arch_prctl(int code, unsigned long addr)
 92 {
 93         return arch_prctl(current, code, (unsigned long __user *) addr);
 94 }
 95 
 96 long sys_clone(unsigned long clone_flags, unsigned long newsp,
 97                void __user *parent_tid, void __user *child_tid)
 98 {
 99         long ret;
100 
101         if (!newsp)
102                 newsp = UPT_SP(&current->thread.regs.regs);
103         current->thread.forking = 1;
104         ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
105                       child_tid);
106         current->thread.forking = 0;
107         return ret;
108 }
109 
110 void arch_switch_to(struct task_struct *to)
111 {
112         if ((to->thread.arch.fs == 0) || (to->mm == NULL))
113                 return;
114 
115         arch_prctl(to, ARCH_SET_FS, (void __user *) to->thread.arch.fs);
116 }
117 
  This page was automatically generated by the LXR engine.