root/mm/mmap.c

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

DEFINITIONS

This source file includes following definitions.
  1. sys_mmap
  2. sys_munmap

   1 /*
   2  *      linux/mm/mmap.c
   3  *
   4  * Written by obz.
   5  */
   6 #include <linux/stat.h>
   7 #include <linux/sched.h>
   8 #include <linux/kernel.h>
   9 #include <linux/mm.h>
  10 #include <linux/errno.h>
  11 #include <linux/mman.h>
  12 #include <linux/string.h>
  13 
  14 #include <asm/segment.h>
  15 #include <asm/system.h>
  16 
  17 /*
  18  * description of effects of mapping type and prot in current implementation.
  19  * this is due to the current handling of page faults in memory.c. the expected
  20  * behavior is in parens:
  21  *
  22  * map_type     prot
  23  *              PROT_NONE       PROT_READ       PROT_WRITE      PROT_EXEC
  24  * MAP_SHARED   r: (no) yes     r: (yes) yes    r: (no) yes     r: (no) no
  25  *              w: (no) yes     w: (no) copy    w: (yes) yes    w: (no) no
  26  *              x: (no) no      x: (no) no      x: (no) no      x: (yes) no
  27  *              
  28  * MAP_PRIVATE  r: (no) yes     r: (yes) yes    r: (no) yes     r: (no) no
  29  *              w: (no) copy    w: (no) copy    w: (copy) copy  w: (no) no
  30  *              x: (no) no      x: (no) no      x: (no) no      x: (yes) no
  31  *
  32  */
  33 
  34 #define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
  35                           current->start_code + current->end_code)
  36 
  37 int sys_mmap(unsigned long *buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
  38 {
  39         unsigned long base, addr;
  40         unsigned long len, limit, off;
  41         int prot, flags, mask, fd, error;
  42         struct file *file;
  43 
  44         addr = (unsigned long)  get_fs_long(buffer);    /* user address space*/
  45         len = (size_t)          get_fs_long(buffer+1);  /* nbytes of mapping */
  46         prot = (int)            get_fs_long(buffer+2);  /* protection */
  47         flags = (int)           get_fs_long(buffer+3);  /* mapping type */
  48         fd = (int)              get_fs_long(buffer+4);  /* object to map */
  49         off = (unsigned long)   get_fs_long(buffer+5);  /* offset in object */
  50 
  51         if (fd >= NR_OPEN || fd < 0 || !(file = current->filp[fd]))
  52                 return -EBADF;
  53         if (addr > TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE-len)
  54                 return -EINVAL;
  55 
  56         /*
  57          * do simple checking here so the lower-level routines won't have
  58          * to. we assume access permissions have been handled by the open
  59          * of the memory object, so we don't do any here.
  60          */
  61 
  62         switch (flags & MAP_TYPE) {
  63         case MAP_SHARED:
  64                 if ((prot & PROT_WRITE) && !(file->f_mode & 2))
  65                         return -EINVAL;
  66                 /* fall through */
  67         case MAP_PRIVATE:
  68                 if (!(file->f_mode & 1))
  69                         return -EINVAL;
  70                 break;
  71 
  72         default:
  73                 return -EINVAL;
  74         }
  75 
  76         /*
  77          * obtain the address to map to. we verify (or select) it and ensure
  78          * that it represents a valid section of the address space. we assume
  79          * that if PROT_EXEC is specified this should be in the code segment.
  80          */
  81         base = 0;
  82         limit = TASK_SIZE;
  83 
  84         if (flags & MAP_FIXED) {
  85                 /*
  86                  * if MAP_FIXED is specified, we have to map exactly at this
  87                  * address. it must be page aligned and not ambiguous.
  88                  */
  89                 if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 ||
  90                     (off & 0xfff))
  91                         return -EINVAL;
  92                 if (addr + len > limit)
  93                         return -ENOMEM;
  94         } else {
  95                 /*
  96                  * we're given a hint as to where to put the address.
  97                  * that we still need to search for a range of pages which
  98                  * are not mapped and which won't impact the stack or data
  99                  * segment.
 100                  * in linux, we only have a code segment and data segment.
 101                  * since data grows up and stack grows down, we're sort of
 102                  * stuck. placing above the data will break malloc, below
 103                  * the stack will cause stack overflow. because of this
 104                  * we don't allow nonspecified mappings...
 105                  */
 106                 return -ENOMEM;
 107         }
 108 
 109         /*
 110          * determine the object being mapped and call the appropriate
 111          * specific mapper. the address has already been validated, but
 112          * not unmapped
 113          */
 114         if (!file->f_op || !file->f_op->mmap)
 115                 return -ENODEV;
 116         mask = 0;
 117         if (prot & (PROT_READ | PROT_EXEC))
 118                 mask |= PAGE_READONLY;
 119         if (prot & PROT_WRITE)
 120                 mask |= PAGE_RW;
 121         if (!mask)
 122                 return -EINVAL;
 123         if ((flags & MAP_TYPE) == MAP_PRIVATE) {
 124                 mask |= PAGE_COW;
 125                 mask &= ~PAGE_RW;
 126         }
 127         error = file->f_op->mmap(file->f_inode, file, base + addr, len, mask, off);
 128         if (error)
 129                 return error;
 130         return addr;
 131 }
 132 
 133 int sys_munmap(unsigned long addr, size_t len)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135         unsigned long base, limit;
 136 
 137         base = 0;
 138         limit = TASK_SIZE;
 139 
 140         if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 ||
 141             addr + len > limit)
 142                 return -EINVAL;
 143         if (unmap_page_range(base + addr, len))
 144                 return -EAGAIN; /* should never happen */
 145         return 0;
 146 }

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