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>
36 /*===========================================================================*
38 *===========================================================================*/
39 int do_mmap(message
*m
)
45 struct vir_region
*vr
= NULL
;
48 /* RS and VFS can do slightly more special mmap() things */
49 if(m
->m_source
== VFS_PROC_NR
|| m
->m_source
== RS_PROC_NR
)
52 if(m
->VMM_FLAGS
& MAP_THIRDPARTY
) {
53 if(!execpriv
) return EPERM
;
54 if((r
=vm_isokendpt(m
->VMM_FORWHOM
, &n
)) != OK
)
57 /* regular mmap, i.e. for caller */
58 if((r
=vm_isokendpt(m
->m_source
, &n
)) != OK
) {
59 panic("do_mmap: message from strange source: %d",
66 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_IPC_SHARED
) {
89 /* Shared memory has to be preallocated. */
90 if((m
->VMM_FLAGS
& (MAP_PREALLOC
|MAP_ANON
)) !=
91 (MAP_PREALLOC
|MAP_ANON
)) {
95 if(m
->VMM_FLAGS
& MAP_CONTIG
) vrflags
|= VR_CONTIG
;
97 if(len
% VM_PAGE_SIZE
)
98 len
+= VM_PAGE_SIZE
- (len
% VM_PAGE_SIZE
);
101 if (m
->VMM_ADDR
|| (m
->VMM_FLAGS
& MAP_FIXED
)) {
102 /* An address is given, first try at that address. */
104 vr
= map_page_region(vmp
, addr
, 0, len
, MAP_NONE
,
106 if(!vr
&& (m
->VMM_FLAGS
& MAP_FIXED
))
110 /* No address given or address already in use. */
111 vr
= map_page_region(vmp
, 0, VM_DATATOP
, len
,
112 MAP_NONE
, vrflags
, mfflags
);
121 /* Return mapping, as seen from process. */
123 m
->VMM_RETADDR
= vr
->vaddr
;
129 /*===========================================================================*
131 *===========================================================================*/
132 int map_perm_check(endpoint_t caller
, endpoint_t target
,
133 phys_bytes physaddr
, phys_bytes len
)
137 /* TTY and memory are allowed to do anything.
138 * They have to be special cases as they have to be able to do
139 * anything; TTY even on behalf of anyone for the TIOCMAPMEM
140 * ioctl. MEM just for itself.
142 if(caller
== TTY_PROC_NR
)
146 if(caller
== MEM_PROC_NR
)
149 /* Anyone else needs explicit permission from the kernel (ultimately
152 r
= sys_privquery_mem(caller
, physaddr
, len
);
157 /*===========================================================================*
159 *===========================================================================*/
160 int do_map_phys(message
*m
)
165 struct vir_region
*vr
;
167 phys_bytes startaddr
;
173 if (len
<= 0) return EINVAL
;
176 target
= m
->m_source
;
178 if((r
=vm_isokendpt(target
, &n
)) != OK
)
181 startaddr
= (vir_bytes
)m
->VMMP_PHADDR
;
183 /* First check permission, then round range down/up. Caller can't
184 * help it if we can't map in lower than page granularity.
186 if(map_perm_check(m
->m_source
, target
, startaddr
, len
) != OK
) {
187 printf("VM: unauthorized mapping of 0x%lx by %d\n",
188 startaddr
, m
->m_source
);
194 offset
= startaddr
% VM_PAGE_SIZE
;
198 if(len
% VM_PAGE_SIZE
)
199 len
+= VM_PAGE_SIZE
- (len
% VM_PAGE_SIZE
);
201 if(!(vr
= map_page_region(vmp
, 0, VM_DATATOP
, len
, startaddr
,
202 VR_DIRECT
| VR_NOPF
| VR_WRITABLE
, 0))) {
206 m
->VMMP_VADDR_REPLY
= (void *) (vr
->vaddr
+ offset
);
211 /*===========================================================================*
213 *===========================================================================*/
214 int do_unmap_phys(message
*m
)
219 struct vir_region
*region
;
223 target
= m
->m_source
;
225 if((r
=vm_isokendpt(target
, &n
)) != OK
)
230 if(!(region
= map_lookup(vmp
, (vir_bytes
) m
->VMUM_ADDR
, NULL
))) {
234 if(!(region
->flags
& VR_DIRECT
)) {
238 if(map_unmap_region(vmp
, region
, 0, region
->length
) != OK
) {
245 /*===========================================================================*
247 *===========================================================================*/
248 int do_remap(message
*m
)
251 vir_bytes da
, sa
, startv
;
253 struct vir_region
*region
;
254 struct vmproc
*dvmp
, *svmp
;
258 if(m
->m_type
== VM_REMAP
)
260 else if(m
->m_type
== VM_REMAP_RO
)
262 else panic("do_remap: can't be");
264 da
= (vir_bytes
) m
->VMRE_DA
;
265 sa
= (vir_bytes
) m
->VMRE_SA
;
268 if (size
<= 0) return EINVAL
;
270 if ((r
= vm_isokendpt((endpoint_t
) m
->VMRE_D
, &dn
)) != OK
)
272 if ((r
= vm_isokendpt((endpoint_t
) m
->VMRE_S
, &sn
)) != OK
)
278 /* da is not translated by arch_vir2map(),
279 * it's handled a little differently,
280 * since in map_remap(), we have to know
281 * about whether the user needs to bind to
282 * THAT address or be chosen by the system.
284 if (!(region
= map_lookup(svmp
, sa
, NULL
)))
287 if(region
->vaddr
!= sa
) {
288 printf("VM: do_remap: not start of region.\n");
292 if(!(region
->flags
& VR_SHARED
)) {
293 printf("VM: do_remap: not shared.\n");
297 if (size
% VM_PAGE_SIZE
)
298 size
+= VM_PAGE_SIZE
- size
% VM_PAGE_SIZE
;
300 if(size
!= region
->length
) {
301 printf("VM: do_remap: not size of region.\n");
305 if ((r
= map_remap(dvmp
, da
, size
, region
, &startv
, readonly
)) != OK
)
308 m
->VMRE_RETA
= (char *) startv
;
312 /*===========================================================================*
314 *===========================================================================*/
315 int do_shared_unmap(message
*m
)
320 struct vir_region
*vr
;
323 target
= m
->VMUN_ENDPT
;
325 target
= m
->m_source
;
327 if ((r
= vm_isokendpt(target
, &n
)) != OK
)
334 if(!(vr
= map_lookup(vmp
, addr
, NULL
))) {
335 printf("VM: addr 0x%lx not found.\n", m
->VMUN_ADDR
);
339 if(vr
->vaddr
!= addr
) {
340 printf("VM: wrong address for shared_unmap.\n");
344 if(!(vr
->flags
& VR_SHARED
)) {
345 printf("VM: address does not point to shared region.\n");
349 if(map_unmap_region(vmp
, vr
, 0, vr
->length
) != OK
)
350 panic("do_shared_unmap: map_unmap_region failed");
355 /*===========================================================================*
357 *===========================================================================*/
358 int do_get_phys(message
*m
)
366 target
= m
->VMPHYS_ENDPT
;
367 addr
= m
->VMPHYS_ADDR
;
369 if ((r
= vm_isokendpt(target
, &n
)) != OK
)
374 r
= map_get_phys(vmp
, addr
, &ret
);
376 m
->VMPHYS_RETA
= ret
;
380 /*===========================================================================*
382 *===========================================================================*/
383 int do_get_refcount(message
*m
)
391 target
= m
->VMREFCNT_ENDPT
;
392 addr
= m
->VMREFCNT_ADDR
;
394 if ((r
= vm_isokendpt(target
, &n
)) != OK
)
399 r
= map_get_ref(vmp
, addr
, &cnt
);
401 m
->VMREFCNT_RETC
= cnt
;
405 /*===========================================================================*
407 *===========================================================================*/
408 int do_munmap(message
*m
)
412 vir_bytes addr
, len
, offset
;
413 struct vir_region
*vr
;
415 if((r
=vm_isokendpt(m
->m_source
, &n
)) != OK
) {
416 panic("do_mmap: message from strange source: %d", m
->m_source
);
421 assert(m
->m_type
== VM_MUNMAP
);
422 addr
= (vir_bytes
) (vir_bytes
) m
->VMUM_ADDR
;
424 if(!(vr
= map_lookup(vmp
, addr
, NULL
))) {
425 printf("VM: unmap: virtual address %p not found in %d\n",
426 m
->VMUM_ADDR
, vmp
->vm_endpoint
);
430 if(addr
% VM_PAGE_SIZE
)
433 len
= roundup(m
->VMUM_LEN
, VM_PAGE_SIZE
);
435 offset
= addr
- vr
->vaddr
;
437 if(offset
+ len
> vr
->length
) {
438 printf("munmap: addr 0x%lx len 0x%lx spills out of region\n",
443 if(map_unmap_region(vmp
, vr
, offset
, len
) != OK
)
444 panic("do_munmap: map_unmap_region failed");