4 #include <minix/callnr.h>
6 #include <minix/config.h>
7 #include <minix/const.h>
9 #include <minix/endpoint.h>
10 #include <minix/keymap.h>
11 #include <minix/minlib.h>
12 #include <minix/type.h>
13 #include <minix/ipc.h>
14 #include <minix/sysutil.h>
15 #include <minix/syslib.h>
16 #include <minix/safecopies.h>
17 #include <minix/bitmap.h>
18 #include <minix/debug.h>
21 #include <sys/param.h>
35 /*===========================================================================*
37 *===========================================================================*/
38 int do_mmap(message
*m
)
44 struct vir_region
*vr
= NULL
;
47 /* RS and VFS can do slightly more special mmap() things */
48 if(m
->m_source
== VFS_PROC_NR
|| m
->m_source
== RS_PROC_NR
)
51 if(m
->VMM_FLAGS
& MAP_THIRDPARTY
) {
52 if(!execpriv
) return EPERM
;
53 if((r
=vm_isokendpt(m
->VMM_FORWHOM
, &n
)) != OK
)
56 /* regular mmap, i.e. for caller */
57 if((r
=vm_isokendpt(m
->m_source
, &n
)) != OK
) {
58 panic("do_mmap: message from strange source: %d",
65 if(m
->VMM_FD
== -1 || (m
->VMM_FLAGS
& MAP_ANON
)) {
67 u32_t vrflags
= VR_ANON
| VR_WRITABLE
;
68 size_t len
= (vir_bytes
) m
->VMM_LEN
;
70 if(m
->VMM_FD
!= -1 || len
<= 0) {
74 /* Contiguous phys memory has to be preallocated. */
75 if((m
->VMM_FLAGS
& (MAP_CONTIG
|MAP_PREALLOC
)) == MAP_CONTIG
) {
79 if(m
->VMM_FLAGS
& MAP_PREALLOC
) mfflags
|= MF_PREALLOC
;
80 if(m
->VMM_FLAGS
& MAP_LOWER16M
) vrflags
|= VR_LOWER16MB
;
81 if(m
->VMM_FLAGS
& MAP_LOWER1M
) vrflags
|= VR_LOWER1MB
;
82 if(m
->VMM_FLAGS
& MAP_ALIGN64K
) vrflags
|= VR_PHYS64K
;
83 if(m
->VMM_FLAGS
& MAP_UNINITIALIZED
) {
84 if(!execpriv
) return EPERM
;
85 vrflags
|= VR_UNINITIALIZED
;
87 if(m
->VMM_FLAGS
& MAP_CONTIG
) {
89 mt
= &mem_type_anon_contig
;
90 } else mt
= &mem_type_anon
;
92 if(len
% VM_PAGE_SIZE
)
93 len
+= VM_PAGE_SIZE
- (len
% VM_PAGE_SIZE
);
96 if (m
->VMM_ADDR
|| (m
->VMM_FLAGS
& MAP_FIXED
)) {
97 /* An address is given, first try at that address. */
99 vr
= map_page_region(vmp
, addr
, 0, len
,
100 vrflags
, mfflags
, mt
);
101 if(!vr
&& (m
->VMM_FLAGS
& MAP_FIXED
))
105 /* No address given or address already in use. */
106 vr
= map_page_region(vmp
, 0, VM_DATATOP
, len
,
107 vrflags
, mfflags
, mt
);
116 /* Return mapping, as seen from process. */
118 m
->VMM_RETADDR
= vr
->vaddr
;
124 /*===========================================================================*
126 *===========================================================================*/
127 int map_perm_check(endpoint_t caller
, endpoint_t target
,
128 phys_bytes physaddr
, phys_bytes len
)
132 /* TTY and memory are allowed to do anything.
133 * They have to be special cases as they have to be able to do
134 * anything; TTY even on behalf of anyone for the TIOCMAPMEM
135 * ioctl. MEM just for itself.
137 if(caller
== TTY_PROC_NR
)
141 if(caller
== MEM_PROC_NR
)
144 /* Anyone else needs explicit permission from the kernel (ultimately
147 r
= sys_privquery_mem(caller
, physaddr
, len
);
152 /*===========================================================================*
154 *===========================================================================*/
155 int do_map_phys(message
*m
)
160 struct vir_region
*vr
;
162 phys_bytes startaddr
;
168 if (len
<= 0) return EINVAL
;
171 target
= m
->m_source
;
173 if((r
=vm_isokendpt(target
, &n
)) != OK
)
176 startaddr
= (vir_bytes
)m
->VMMP_PHADDR
;
178 /* First check permission, then round range down/up. Caller can't
179 * help it if we can't map in lower than page granularity.
181 if(map_perm_check(m
->m_source
, target
, startaddr
, len
) != OK
) {
182 printf("VM: unauthorized mapping of 0x%lx by %d\n",
183 startaddr
, m
->m_source
);
189 offset
= startaddr
% VM_PAGE_SIZE
;
193 if(len
% VM_PAGE_SIZE
)
194 len
+= VM_PAGE_SIZE
- (len
% VM_PAGE_SIZE
);
196 if(!(vr
= map_page_region(vmp
, 0, VM_DATATOP
, len
,
197 VR_DIRECT
| VR_WRITABLE
, 0, &mem_type_directphys
))) {
201 phys_setphys(vr
, startaddr
);
203 m
->VMMP_VADDR_REPLY
= (void *) (vr
->vaddr
+ offset
);
208 /*===========================================================================*
210 *===========================================================================*/
211 int do_remap(message
*m
)
217 struct vir_region
*src_region
, *vr
;
218 struct vmproc
*dvmp
, *svmp
;
222 if(m
->m_type
== VM_REMAP
)
224 else if(m
->m_type
== VM_REMAP_RO
)
226 else panic("do_remap: can't be");
228 da
= (vir_bytes
) m
->VMRE_DA
;
229 sa
= (vir_bytes
) m
->VMRE_SA
;
232 if (size
<= 0) return EINVAL
;
234 if ((r
= vm_isokendpt((endpoint_t
) m
->VMRE_D
, &dn
)) != OK
)
236 if ((r
= vm_isokendpt((endpoint_t
) m
->VMRE_S
, &sn
)) != OK
)
242 if (!(src_region
= map_lookup(svmp
, sa
, NULL
)))
245 if(src_region
->vaddr
!= sa
) {
246 printf("VM: do_remap: not start of region.\n");
250 if (size
% VM_PAGE_SIZE
)
251 size
+= VM_PAGE_SIZE
- size
% VM_PAGE_SIZE
;
253 if(size
!= src_region
->length
) {
254 printf("VM: do_remap: not size of region.\n");
260 flags
|= VR_WRITABLE
;
263 vr
= map_page_region(dvmp
, da
, 0, size
, flags
, 0,
266 vr
= map_page_region(dvmp
, 0, VM_DATATOP
, size
, flags
, 0,
270 printf("VM: re-map of shared area failed\n");
274 shared_setsource(vr
, svmp
->vm_endpoint
, src_region
);
276 m
->VMRE_RETA
= (char *) vr
->vaddr
;
280 /*===========================================================================*
282 *===========================================================================*/
283 int do_get_phys(message
*m
)
291 target
= m
->VMPHYS_ENDPT
;
292 addr
= m
->VMPHYS_ADDR
;
294 if ((r
= vm_isokendpt(target
, &n
)) != OK
)
299 r
= map_get_phys(vmp
, addr
, &ret
);
301 m
->VMPHYS_RETA
= ret
;
305 /*===========================================================================*
307 *===========================================================================*/
308 int do_get_refcount(message
*m
)
316 target
= m
->VMREFCNT_ENDPT
;
317 addr
= m
->VMREFCNT_ADDR
;
319 if ((r
= vm_isokendpt(target
, &n
)) != OK
)
324 r
= map_get_ref(vmp
, addr
, &cnt
);
326 m
->VMREFCNT_RETC
= cnt
;
330 /*===========================================================================*
332 *===========================================================================*/
333 int do_munmap(message
*m
)
337 vir_bytes addr
, len
, offset
;
338 struct vir_region
*vr
;
339 endpoint_t target
= SELF
;
341 if(m
->m_type
== VM_UNMAP_PHYS
) {
343 } else if(m
->m_type
== VM_SHM_UNMAP
) {
344 target
= m
->VMUN_ENDPT
;
348 target
= m
->m_source
;
350 if((r
=vm_isokendpt(target
, &n
)) != OK
) {
351 panic("do_mmap: message from strange source: %d", m
->m_source
);
356 if(m
->m_type
== VM_UNMAP_PHYS
) {
357 addr
= (vir_bytes
) m
->VMUP_VADDR
;
358 } else if(m
->m_type
== VM_SHM_UNMAP
) {
359 addr
= (vir_bytes
) m
->VMUN_ADDR
;
360 } else addr
= (vir_bytes
) m
->VMUM_ADDR
;
362 if(!(vr
= map_lookup(vmp
, addr
, NULL
))) {
363 printf("VM: unmap: virtual address 0x%lx not found in %d\n",
368 if(addr
% VM_PAGE_SIZE
)
371 if(m
->m_type
== VM_UNMAP_PHYS
|| m
->m_type
== VM_SHM_UNMAP
) {
373 } else len
= roundup(m
->VMUM_LEN
, VM_PAGE_SIZE
);
375 offset
= addr
- vr
->vaddr
;
377 if(offset
+ len
> vr
->length
) {
378 printf("munmap: addr 0x%lx len 0x%lx spills out of region\n",
383 if(map_unmap_region(vmp
, vr
, offset
, len
) != OK
)
384 panic("do_munmap: map_unmap_region failed");