root/fs/proc/mem.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mem_read
  2. mem_write
  3. mem_lseek
  4. mem_mmap

   1 /*
   2  *  linux/fs/proc/mem.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/types.h>
   8 #include <linux/errno.h>
   9 #include <linux/sched.h>
  10 #include <linux/kernel.h>
  11 #include <linux/mm.h>
  12 #include <linux/page.h>
  13 
  14 #include <asm/segment.h>
  15 #include <asm/io.h>
  16 
  17 /*
  18  * mem_write isn't really a good idea right now. It needs
  19  * to check a lot more: if the process we try to write to 
  20  * dies in the middle right now, mem_write will overwrite
  21  * kernel memory.. This disables it altogether.
  22  */
  23 #define mem_write NULL
  24 
  25 static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  26 {
  27         unsigned long addr, pid, cr3;
  28         char *tmp;
  29         unsigned long pte, page;
  30         int i;
  31 
  32         if (count < 0)
  33                 return -EINVAL;
  34         pid = inode->i_ino;
  35         pid >>= 16;
  36         cr3 = 0;
  37         for (i = 1 ; i < NR_TASKS ; i++)
  38                 if (task[i] && task[i]->pid == pid) {
  39                         cr3 = task[i]->tss.cr3;
  40                         break;
  41                 }
  42         if (!cr3)
  43                 return -EACCES;
  44         addr = file->f_pos;
  45         tmp = buf;
  46         while (count > 0) {
  47                 if (current->signal & ~current->blocked)
  48                         break;
  49                 pte = *PAGE_DIR_OFFSET(cr3,addr);
  50                 if (!(pte & PAGE_PRESENT))
  51                         break;
  52                 pte &= PAGE_MASK;
  53                 pte += PAGE_PTR(addr);
  54                 page = *(unsigned long *) pte;
  55                 if (!(page & 1))
  56                         break;
  57                 page &= PAGE_MASK;
  58                 page += addr & ~PAGE_MASK;
  59                 i = PAGE_SIZE-(addr & ~PAGE_MASK);
  60                 if (i > count)
  61                         i = count;
  62                 memcpy_tofs(tmp,(void *) page,i);
  63                 addr += i;
  64                 tmp += i;
  65                 count -= i;
  66         }
  67         file->f_pos = addr;
  68         return tmp-buf;
  69 }
  70 
  71 #ifndef mem_write
  72 
  73 static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75         unsigned long addr, pid, cr3;
  76         char *tmp;
  77         unsigned long pte, page;
  78         int i;
  79 
  80         if (count < 0)
  81                 return -EINVAL;
  82         addr = file->f_pos;
  83         pid = inode->i_ino;
  84         pid >>= 16;
  85         cr3 = 0;
  86         for (i = 1 ; i < NR_TASKS ; i++)
  87                 if (task[i] && task[i]->pid == pid) {
  88                         cr3 = task[i]->tss.cr3;
  89                         break;
  90                 }
  91         if (!cr3)
  92                 return -EACCES;
  93         tmp = buf;
  94         while (count > 0) {
  95                 if (current->signal & ~current->blocked)
  96                         break;
  97                 pte = *PAGE_DIR_OFFSET(cr3,addr);
  98                 if (!(pte & PAGE_PRESENT))
  99                         break;
 100                 pte &= PAGE_MASK;
 101                 pte += PAGE_PTR(addr);
 102                 page = *(unsigned long *) pte;
 103                 if (!(page & PAGE_PRESENT))
 104                         break;
 105                 if (!(page & 2)) {
 106                         do_wp_page(0,addr,current,0);
 107                         continue;
 108                 }
 109                 page &= PAGE_MASK;
 110                 page += addr & ~PAGE_MASK;
 111                 i = PAGE_SIZE-(addr & ~PAGE_MASK);
 112                 if (i > count)
 113                         i = count;
 114                 memcpy_fromfs((void *) page,tmp,i);
 115                 addr += i;
 116                 tmp += i;
 117                 count -= i;
 118         }
 119         file->f_pos = addr;
 120         if (tmp != buf)
 121                 return tmp-buf;
 122         if (current->signal & ~current->blocked)
 123                 return -ERESTARTSYS;
 124         return 0;
 125 }
 126 
 127 #endif
 128 
 129 static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
     /* [previous][next][first][last][top][bottom][index][help] */
 130 {
 131         switch (orig) {
 132                 case 0:
 133                         file->f_pos = offset;
 134                         return file->f_pos;
 135                 case 1:
 136                         file->f_pos += offset;
 137                         return file->f_pos;
 138                 default:
 139                         return -EINVAL;
 140         }
 141 }
 142 
 143 int
 144 mem_mmap(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 145              struct vm_area_struct * vma)
 146 {
 147   unsigned long *src_table, *dest_table, stmp, dtmp, cr3;
 148   struct vm_area_struct *src_vma = 0;
 149   int i;
 150 
 151   /* Get the source's task information */
 152 
 153   cr3 = 0;
 154   for (i = 1 ; i < NR_TASKS ; i++)
 155     if (task[i] && task[i]->pid == (inode->i_ino >> 16)) {
 156       cr3     = task[i]->tss.cr3;
 157       src_vma = task[i]->mm->mmap;
 158       break;
 159     }
 160 
 161   if (!cr3)
 162     return -EACCES;
 163 
 164 /* Ensure that we have a valid source area.  (Has to be mmap'ed and
 165    have valid page information.)  We can't map shared memory at the
 166    moment because working out the vm_area_struct & nattach stuff isn't
 167    worth it. */
 168 
 169   stmp = vma->vm_offset;
 170   while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
 171     while (src_vma && stmp > src_vma->vm_end)
 172       src_vma = src_vma->vm_next;
 173     if (!src_vma || (src_vma->vm_flags & VM_SHM))
 174       return -EINVAL;
 175 
 176     src_table = PAGE_DIR_OFFSET(cr3, stmp);
 177     if (!*src_table)
 178       return -EINVAL;
 179     src_table = (unsigned long *)((*src_table & PAGE_MASK) + PAGE_PTR(stmp));
 180     if (!*src_table)
 181       return -EINVAL;
 182 
 183     if (stmp < src_vma->vm_start) {
 184       if (!(src_vma->vm_flags & VM_GROWSDOWN))
 185         return -EINVAL;
 186       if (src_vma->vm_end - stmp > current->rlim[RLIMIT_STACK].rlim_cur)
 187         return -EINVAL;
 188     }
 189     stmp += PAGE_SIZE;
 190   }
 191 
 192   src_vma = task[i]->mm->mmap;
 193   stmp    = vma->vm_offset;
 194   dtmp    = vma->vm_start;
 195 
 196   while (dtmp < vma->vm_end) {
 197     while (src_vma && stmp > src_vma->vm_end)
 198       src_vma = src_vma->vm_next;
 199 
 200     src_table = PAGE_DIR_OFFSET(cr3, stmp);
 201     src_table = (unsigned long *)((*src_table & PAGE_MASK) + PAGE_PTR(stmp));
 202 
 203     dest_table = PAGE_DIR_OFFSET(current->tss.cr3, dtmp);
 204 
 205     if (!*dest_table) {
 206       *dest_table = get_free_page(GFP_KERNEL);
 207       if (!*dest_table) { oom(current); *dest_table=BAD_PAGE; }
 208       else *dest_table |= PAGE_TABLE;
 209     }
 210     
 211     dest_table = (unsigned long *)((*dest_table & PAGE_MASK) + PAGE_PTR(dtmp));
 212 
 213     if (!(*src_table & PAGE_PRESENT)) 
 214       do_no_page(src_vma, stmp, PAGE_PRESENT);
 215 
 216     if ((vma->vm_flags & VM_WRITE) && !(*src_table & PAGE_RW))
 217       do_wp_page(src_vma, stmp, PAGE_RW | PAGE_PRESENT);
 218 
 219     *src_table |= PAGE_DIRTY;
 220     *dest_table = *src_table;
 221     mem_map[MAP_NR(*src_table)]++;
 222 
 223     stmp += PAGE_SIZE;
 224     dtmp += PAGE_SIZE;
 225   }
 226 
 227   invalidate();
 228   return 0;
 229 }
 230 
 231 static struct file_operations proc_mem_operations = {
 232         mem_lseek,
 233         mem_read,
 234         mem_write,
 235         NULL,           /* mem_readdir */
 236         NULL,           /* mem_select */
 237         NULL,           /* mem_ioctl */
 238         mem_mmap,       /* mmap */
 239         NULL,           /* no special open code */
 240         NULL,           /* no special release code */
 241         NULL            /* can't fsync */
 242 };
 243 
 244 struct inode_operations proc_mem_inode_operations = {
 245         &proc_mem_operations,   /* default base directory file-ops */
 246         NULL,                   /* create */
 247         NULL,                   /* lookup */
 248         NULL,                   /* link */
 249         NULL,                   /* unlink */
 250         NULL,                   /* symlink */
 251         NULL,                   /* mkdir */
 252         NULL,                   /* rmdir */
 253         NULL,                   /* mknod */
 254         NULL,                   /* rename */
 255         NULL,                   /* readlink */
 256         NULL,                   /* follow_link */
 257         NULL,                   /* bmap */
 258         NULL,                   /* truncate */
 259         NULL                    /* permission */
 260 };

/* [previous][next][first][last][top][bottom][index][help] */