home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / fs / proc / mem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-20  |  6.7 KB  |  305 lines

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