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

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

unix.superglobalmegacorp.com

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