chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / sysdeps / mach / hurd / mmap.c
1 /* Copyright (C) 1994,1995,1996,1997,1999,2002,2003,2004
2         Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <sys/types.h>
21 #include <sys/mman.h>
22 #include <errno.h>
23 #include <hurd.h>
24 #include <hurd/fd.h>
25
26 /* Map addresses starting near ADDR and extending for LEN bytes.  from
27    OFFSET into the file FD describes according to PROT and FLAGS.  If ADDR
28    is nonzero, it is the desired mapping address.  If the MAP_FIXED bit is
29    set in FLAGS, the mapping will be at ADDR exactly (which must be
30    page-aligned); otherwise the system chooses a convenient nearby address.
31    The return value is the actual mapping address chosen or (__ptr_t) -1
32    for errors (in which case `errno' is set).  A successful `mmap' call
33    deallocates any previous mapping for the affected region.  */
34
35 __ptr_t
36 __mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
37 {
38   error_t err;
39   vm_prot_t vmprot;
40   memory_object_t memobj;
41   vm_address_t mapaddr;
42
43   mapaddr = (vm_address_t) addr;
44
45   /* ADDR and OFFSET must be page-aligned.  */
46   if ((mapaddr & (vm_page_size - 1)) || (offset & (vm_page_size - 1)))
47     return (__ptr_t) (long int) __hurd_fail (EINVAL);
48
49   if ((flags & (MAP_TYPE|MAP_INHERIT)) == MAP_ANON
50       && prot == (PROT_READ|PROT_WRITE)) /* cf VM_PROT_DEFAULT */
51     {
52       /* vm_allocate has (a little) less overhead in the kernel too.  */
53       err = __vm_allocate (__mach_task_self (), &mapaddr, len,
54                            !(flags & MAP_FIXED));
55
56       if (err == KERN_NO_SPACE && (flags & MAP_FIXED))
57         {
58           /* XXX this is not atomic as it is in unix! */
59           /* The region is already allocated; deallocate it first.  */
60           err = __vm_deallocate (__mach_task_self (), mapaddr, len);
61           if (!err)
62             err = __vm_allocate (__mach_task_self (), &mapaddr, len, 0);
63         }
64
65       return err ? (__ptr_t) (long int) __hurd_fail (err) : (__ptr_t) mapaddr;
66     }
67
68   vmprot = VM_PROT_NONE;
69   if (prot & PROT_READ)
70     vmprot |= VM_PROT_READ;
71   if (prot & PROT_WRITE)
72     vmprot |= VM_PROT_WRITE;
73   if (prot & PROT_EXEC)
74     vmprot |= VM_PROT_EXECUTE;
75
76   switch (flags & MAP_TYPE)
77     {
78     default:
79       return (__ptr_t) (long int) __hurd_fail (EINVAL);
80
81     case MAP_ANON:
82       memobj = MACH_PORT_NULL;
83       break;
84
85     case MAP_FILE:
86     case 0:                     /* Allow, e.g., just MAP_SHARED.  */
87       {
88         mach_port_t robj, wobj;
89         if (err = HURD_DPORT_USE (fd, __io_map (port, &robj, &wobj)))
90           {
91             if (err == MIG_BAD_ID || err == EOPNOTSUPP || err == ENOSYS)
92               err = ENODEV;     /* File descriptor doesn't support mmap.  */
93             return (__ptr_t) (long int) __hurd_dfail (fd, err);
94           }
95         switch (prot & (PROT_READ|PROT_WRITE))
96           {
97           case PROT_READ:
98             memobj = robj;
99             if (wobj != MACH_PORT_NULL)
100               __mach_port_deallocate (__mach_task_self (), wobj);
101             break;
102           case PROT_WRITE:
103             memobj = wobj;
104             if (robj != MACH_PORT_NULL)
105               __mach_port_deallocate (__mach_task_self (), robj);
106             break;
107           case PROT_READ|PROT_WRITE:
108             if (robj == wobj)
109               {
110                 memobj = wobj;
111                 /* Remove extra reference.  */
112                 __mach_port_deallocate (__mach_task_self (), memobj);
113               }
114             else if (wobj == MACH_PORT_NULL && /* Not writable by mapping.  */
115                      !(flags & MAP_SHARED))
116               /* The file can only be mapped for reading.  Since we are
117                  making a private mapping, we will never try to write the
118                  object anyway, so we don't care.  */
119               memobj = robj;
120             else
121               {
122                 __mach_port_deallocate (__mach_task_self (), wobj);
123                 return (__ptr_t) (long int) __hurd_fail (EACCES);
124               }
125             break;
126           default:              /* impossible */
127             return 0;
128           }
129         break;
130         /* XXX handle MAP_NOEXTEND */
131       }
132     }
133
134   /* XXX handle MAP_INHERIT */
135
136   err = __vm_map (__mach_task_self (),
137                   &mapaddr, (vm_size_t) len, (vm_address_t) 0,
138                   ! (flags & MAP_FIXED),
139                   memobj, (vm_offset_t) offset,
140                   ! (flags & MAP_SHARED),
141                   vmprot, VM_PROT_ALL,
142                   (flags & MAP_SHARED) ? VM_INHERIT_SHARE : VM_INHERIT_COPY);
143
144   if (err == KERN_NO_SPACE && (flags & MAP_FIXED))
145     {
146       /* XXX this is not atomic as it is in unix! */
147       /* The region is already allocated; deallocate it first.  */
148       err = __vm_deallocate (__mach_task_self (), mapaddr, len);
149       if (! err)
150         err = __vm_map (__mach_task_self (),
151                         &mapaddr, (vm_size_t) len, (vm_address_t) 0,
152                         0, memobj, (vm_offset_t) offset,
153                         ! (flags & MAP_SHARED),
154                         vmprot, VM_PROT_ALL,
155                         (flags & MAP_SHARED) ? VM_INHERIT_SHARE
156                         : VM_INHERIT_COPY);
157     }
158
159   if (memobj != MACH_PORT_NULL)
160     __mach_port_deallocate (__mach_task_self (), memobj);
161
162   if (err)
163     return (__ptr_t) (long int) __hurd_fail (err);
164
165   return (__ptr_t) mapaddr;
166 }
167
168 weak_alias (__mmap, mmap)