Annotation of linux/mm/mmap.c, revision 1.1.1.5

1.1       root        1: /*
                      2:  *     linux/mm/mmap.c
                      3:  *
                      4:  * Written by obz.
                      5:  */
1.1.1.2   root        6: #include <linux/stat.h>
1.1       root        7: #include <linux/sched.h>
                      8: #include <linux/kernel.h>
1.1.1.3   root        9: #include <linux/mm.h>
1.1.1.4   root       10: #include <linux/errno.h>
1.1.1.5 ! root       11: #include <linux/mman.h>
1.1.1.4   root       12: 
1.1       root       13: #include <asm/segment.h>
                     14: #include <asm/system.h>
1.1.1.4   root       15: 
1.1       root       16: /*
                     17:  * description of effects of mapping type and prot in current implementation.
                     18:  * this is due to the current handling of page faults in memory.c. the expected
                     19:  * behavior is in parens:
                     20:  *
                     21:  * map_type    prot
                     22:  *             PROT_NONE       PROT_READ       PROT_WRITE      PROT_EXEC
                     23:  * MAP_SHARED  r: (no) yes     r: (yes) yes    r: (no) yes     r: (no) no
                     24:  *             w: (no) yes     w: (no) copy    w: (yes) yes    w: (no) no
                     25:  *             x: (no) no      x: (no) no      x: (no) no      x: (yes) no
                     26:  *             
                     27:  * MAP_PRIVATE r: (no) yes     r: (yes) yes    r: (no) yes     r: (no) no
                     28:  *             w: (no) copy    w: (no) copy    w: (copy) copy  w: (no) no
                     29:  *             x: (no) no      x: (no) no      x: (no) no      x: (yes) no
                     30:  *
                     31:  * the permissions are encoded as cxwr (copy,exec,write,read)
                     32:  */
                     33: #define MTYP(T) ((T) & MAP_TYPE)
                     34: #define PREAD(T,P) (((P) & PROT_READ) ? 1 : 0)
                     35: #define PWRITE(T,P) (((P) & PROT_WRITE) ? (MTYP(T) == MAP_SHARED ? 2 : 10) : 0)
                     36: #define PEXEC(T,P) (((P) & PROT_EXEC) ? 4 : 0)
                     37: #define PERMISS(T,P) (PREAD(T,P)|PWRITE(T,P)|PEXEC(T,P))
                     38: 
                     39: #define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
                     40:                          current->start_code + current->end_code)
                     41: 
                     42: static caddr_t
                     43: mmap_chr(unsigned long addr, size_t len, int prot, int flags,
                     44:         struct inode *inode, unsigned long off)
                     45: {
                     46:        int major, minor;
                     47: 
                     48:        major = MAJOR(inode->i_rdev);
                     49:        minor = MINOR(inode->i_rdev);
                     50: 
                     51:        /*
1.1.1.5 ! root       52:         * for character devices, only /dev/[k]mem may be mapped. when the
1.1       root       53:         * swapping code is modified to allow arbitrary sources of pages,
                     54:         * then we can open it up to regular files.
                     55:         */
                     56: 
1.1.1.5 ! root       57:        if (major != 1 || (minor != 1 && minor != 2))
1.1       root       58:                return (caddr_t)-ENODEV;
                     59: 
                     60:        /*
1.1.1.4   root       61:         * we only allow mappings from address 0 to high_memory, since thats
1.1       root       62:         * the range of our memory [actually this is a lie. the buffer cache
                     63:         * and ramdisk occupy higher memory, but the paging stuff won't
                     64:         * let us map to it anyway, so we break it here].
                     65:         *
                     66:         * this call is very dangerous! because of the lack of adequate
                     67:         * tagging of frames, it is possible to mmap over a frame belonging
                     68:         * to another (innocent) process. with MAP_SHARED|MAP_WRITE, this
                     69:         * rogue process can trample over the other's data! we ignore this :{
                     70:         * for now, we hope people will malloc the required amount of space,
                     71:         * then mmap over it. the mm needs serious work before this can be
                     72:         * truly useful.
                     73:         */
                     74: 
1.1.1.4   root       75:        if (len > high_memory || off > high_memory - len) /* avoid overflow */
1.1       root       76:                return (caddr_t)-ENXIO;
                     77: 
                     78:        if (remap_page_range(addr, off, len, PERMISS(flags, prot)))
                     79:                return (caddr_t)-EAGAIN;
                     80:        
                     81:        return (caddr_t)addr;
                     82: }
                     83: 
                     84: caddr_t
                     85: sys_mmap(unsigned long *buffer)
                     86: {
                     87:        unsigned long base, addr;
                     88:        unsigned long len, limit, off;
                     89:        int prot, flags, fd;
                     90:        struct file *file;
                     91:        struct inode *inode;
                     92: 
                     93:        addr = (unsigned long)  get_fs_long(buffer);    /* user address space*/
                     94:        len = (size_t)          get_fs_long(buffer+1);  /* nbytes of mapping */
                     95:        prot = (int)            get_fs_long(buffer+2);  /* protection */
                     96:        flags = (int)           get_fs_long(buffer+3);  /* mapping type */
                     97:        fd = (int)              get_fs_long(buffer+4);  /* object to map */
                     98:        off = (unsigned long)   get_fs_long(buffer+5);  /* offset in object */
                     99: 
                    100:        if (fd >= NR_OPEN || fd < 0 || !(file = current->filp[fd]))
                    101:                return (caddr_t) -EBADF;
                    102:        if (addr > TASK_SIZE || (addr+(unsigned long) len) > TASK_SIZE)
                    103:                return (caddr_t) -EINVAL;
                    104:        inode = file->f_inode;
                    105: 
                    106:        /*
                    107:         * do simple checking here so the lower-level routines won't have
                    108:         * to. we assume access permissions have been handled by the open
                    109:         * of the memory object, so we don't do any here.
                    110:         */
                    111: 
                    112:        switch (flags & MAP_TYPE) {
                    113:        case MAP_SHARED:
                    114:                if ((prot & PROT_WRITE) && !(file->f_mode & 2))
                    115:                        return (caddr_t)-EINVAL;
                    116:                /* fall through */
                    117:        case MAP_PRIVATE:
                    118:                if (!(file->f_mode & 1))
                    119:                        return (caddr_t)-EINVAL;
                    120:                break;
                    121: 
                    122:        default:
                    123:                return (caddr_t)-EINVAL;
                    124:        }
                    125: 
                    126:        /*
                    127:         * obtain the address to map to. we verify (or select) it and ensure
                    128:         * that it represents a valid section of the address space. we assume
                    129:         * that if PROT_EXEC is specified this should be in the code segment.
                    130:         */
                    131:        if (prot & PROT_EXEC) {
                    132:                base = get_base(current->ldt[1]);       /* cs */
                    133:                limit = get_limit(0x0f);                /* cs limit */
                    134:        } else {
                    135:                base = get_base(current->ldt[2]);       /* ds */
                    136:                limit = get_limit(0x17);                /* ds limit */
                    137:        }
                    138: 
                    139:        if (flags & MAP_FIXED) {
                    140:                /*
                    141:                 * if MAP_FIXED is specified, we have to map exactly at this
                    142:                 * address. it must be page aligned and not ambiguous.
                    143:                 */
                    144:                if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 ||
                    145:                    (off & 0xfff))
                    146:                        return (caddr_t)-EINVAL;
                    147:                if (addr + len > limit)
                    148:                        return (caddr_t)-ENOMEM;
                    149:        } else {
                    150:                /*
                    151:                 * we're given a hint as to where to put the address.
                    152:                 * that we still need to search for a range of pages which
                    153:                 * are not mapped and which won't impact the stack or data
                    154:                 * segment.
                    155:                 * in linux, we only have a code segment and data segment.
                    156:                 * since data grows up and stack grows down, we're sort of
                    157:                 * stuck. placing above the data will break malloc, below
                    158:                 * the stack will cause stack overflow. because of this
                    159:                 * we don't allow nonspecified mappings...
                    160:                 */
                    161:                return (caddr_t)-ENOMEM;
                    162:        }
                    163: 
                    164:        /*
                    165:         * determine the object being mapped and call the appropriate
                    166:         * specific mapper. the address has already been validated, but
                    167:         * not unmapped
                    168:         */
                    169:        if (S_ISCHR(inode->i_mode))
                    170:                addr = (unsigned long)mmap_chr(base + addr, len, prot, flags,
                    171:                                               inode, off);
                    172:        else
                    173:                addr = (unsigned long)-ENODEV;
                    174:        if ((long)addr > 0)
                    175:                addr -= base;
                    176: 
                    177:        return (caddr_t)addr;
                    178: }
                    179: 
                    180: int sys_munmap(unsigned long addr, size_t len)
                    181: {
                    182:        unsigned long base, limit;
                    183: 
                    184:        base = get_base(current->ldt[2]);       /* map into ds */
                    185:        limit = get_limit(0x17);                /* ds limit */
                    186: 
                    187:        if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 ||
                    188:            addr + len > limit)
                    189:                return -EINVAL;
                    190:        if (unmap_page_range(base + addr, len))
                    191:                return -EAGAIN; /* should never happen */
                    192:        return 0;
                    193: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.