4 #include <minix/callnr.h>
6 #include <minix/config.h>
7 #include <minix/const.h>
9 #include <minix/endpoint.h>
10 #include <minix/minlib.h>
11 #include <minix/type.h>
12 #include <minix/ipc.h>
13 #include <minix/sysutil.h>
14 #include <minix/syslib.h>
15 #include <minix/safecopies.h>
16 #include <minix/bitmap.h>
17 #include <minix/debug.h>
19 #include <machine/vmparam.h>
22 #include <sys/param.h>
36 static struct vir_region
*mmap_region(struct vmproc
*vmp
, vir_bytes addr
,
37 u32_t vmm_flags
, size_t len
, u32_t vrflags
,
38 mem_type_t
*mt
, int execpriv
)
41 struct vir_region
*vr
= NULL
;
43 if(vmm_flags
& MAP_LOWER16M
) vrflags
|= VR_LOWER16MB
;
44 if(vmm_flags
& MAP_LOWER1M
) vrflags
|= VR_LOWER1MB
;
45 if(vmm_flags
& MAP_ALIGNMENT_64KB
) vrflags
|= VR_PHYS64K
;
46 if(vmm_flags
& MAP_PREALLOC
) mfflags
|= MF_PREALLOC
;
47 if(vmm_flags
& MAP_UNINITIALIZED
) {
48 if(!execpriv
) return NULL
;
49 vrflags
|= VR_UNINITIALIZED
;
56 if(len
% VM_PAGE_SIZE
)
57 len
+= VM_PAGE_SIZE
- (len
% VM_PAGE_SIZE
);
59 if (addr
&& (vmm_flags
& MAP_FIXED
)) {
60 int r
= map_unmap_range(vmp
, addr
, len
);
62 printf("mmap_region: map_unmap_range failed (%d)\n", r
);
67 if (addr
|| (vmm_flags
& MAP_FIXED
)) {
68 /* An address is given, first try at that address. */
69 vr
= map_page_region(vmp
, addr
, 0, len
,
70 vrflags
, mfflags
, mt
);
71 if(!vr
&& (vmm_flags
& MAP_FIXED
))
76 /* No address given or address already in use. */
77 vr
= map_page_region(vmp
, VM_MMAPBASE
, VM_MMAPTOP
, len
,
78 vrflags
, mfflags
, mt
);
84 static int mmap_file(struct vmproc
*vmp
,
85 int vmfd
, off_t file_offset
, int flags
,
86 ino_t ino
, dev_t dev
, u64_t filesize
, vir_bytes addr
, vir_bytes len
,
87 vir_bytes
*retaddr
, u16_t clearend
, int writable
, int mayclosefd
)
89 /* VFS has replied to a VMVFSREQ_FDLOOKUP request. */
90 struct vir_region
*vr
;
95 if(writable
) vrflags
|= VR_WRITABLE
;
97 /* Do some page alignments. */
98 if((page_offset
= (file_offset
% VM_PAGE_SIZE
))) {
99 file_offset
-= page_offset
;
103 len
= roundup(len
, VM_PAGE_SIZE
);
105 /* All numbers should be page-aligned now. */
106 assert(!(len
% VM_PAGE_SIZE
));
107 assert(!(filesize
% VM_PAGE_SIZE
));
108 assert(!(file_offset
% VM_PAGE_SIZE
));
111 /* XXX ld.so relies on longer-than-file mapping */
112 if((u64_t
) len
+ file_offset
> filesize
) {
113 printf("VM: truncating mmap dev 0x%x ino %d beyond file size in %d; offset %llu, len %lu, size %llu; ",
114 dev
, ino
, vmp
->vm_endpoint
,
115 file_offset
, len
, filesize
);
116 len
= filesize
- file_offset
;
121 if(!(vr
= mmap_region(vmp
, addr
, flags
, len
,
122 vrflags
, &mem_type_mappedfile
, 0))) {
125 *retaddr
= vr
->vaddr
+ page_offset
;
128 mappedfile_setfile(vmp
, vr
, vmfd
,
129 file_offset
, dev
, ino
, clearend
, 1, mayclosefd
);
135 int do_vfs_mmap(message
*m
)
140 u16_t clearend
, flags
= 0;
142 /* It might be disabled */
143 if(!enable_filemap
) return ENXIO
;
145 clearend
= m
->m_vm_vfs_mmap
.clearend
;
146 flags
= m
->m_vm_vfs_mmap
.flags
;
148 if((r
=vm_isokendpt(m
->m_vm_vfs_mmap
.who
, &n
)) != OK
)
149 panic("bad ep %d from vfs", m
->m_vm_vfs_mmap
.who
);
152 return mmap_file(vmp
, m
->m_vm_vfs_mmap
.fd
, m
->m_vm_vfs_mmap
.offset
,
153 MAP_PRIVATE
| MAP_FIXED
,
154 m
->m_vm_vfs_mmap
.ino
, m
->m_vm_vfs_mmap
.dev
,
155 (u64_t
) LONG_MAX
* VM_PAGE_SIZE
,
156 m
->m_vm_vfs_mmap
.vaddr
, m
->m_vm_vfs_mmap
.len
, &v
,
160 static void mmap_file_cont(struct vmproc
*vmp
, message
*replymsg
, void *cbarg
,
163 message
*origmsg
= (message
*) origmsg_v
;
167 vir_bytes v
= (vir_bytes
) MAP_FAILED
;
169 if(origmsg
->m_mmap
.prot
& PROT_WRITE
)
172 if(replymsg
->VMV_RESULT
!= OK
) {
173 #if 0 /* Noisy diagnostic for mmap() by ld.so */
174 printf("VM: VFS reply failed (%d)\n", replymsg
->VMV_RESULT
);
175 sys_diagctl_stacktrace(vmp
->vm_endpoint
);
177 result
= replymsg
->VMV_RESULT
;
180 result
= mmap_file(vmp
, replymsg
->VMV_FD
, origmsg
->m_mmap
.offset
,
181 origmsg
->m_mmap
.flags
,
182 replymsg
->VMV_INO
, replymsg
->VMV_DEV
,
183 (u64_t
) replymsg
->VMV_SIZE_PAGES
*PAGE_SIZE
,
184 (vir_bytes
) origmsg
->m_mmap
.addr
,
185 origmsg
->m_mmap
.len
, &v
, 0, writable
, 1);
188 /* Unblock requesting process. */
189 memset(&mmap_reply
, 0, sizeof(mmap_reply
));
190 mmap_reply
.m_type
= result
;
191 mmap_reply
.m_mmap
.retaddr
= (void *) v
;
193 if(ipc_send(vmp
->vm_endpoint
, &mmap_reply
) != OK
)
194 panic("VM: mmap_file_cont: ipc_send() failed");
197 /*===========================================================================*
199 *===========================================================================*/
200 int do_mmap(message
*m
)
204 vir_bytes addr
= (vir_bytes
) m
->m_mmap
.addr
;
205 struct vir_region
*vr
= NULL
;
207 size_t len
= (vir_bytes
) m
->m_mmap
.len
;
209 /* RS and VFS can do slightly more special mmap() things */
210 if(m
->m_source
== VFS_PROC_NR
|| m
->m_source
== RS_PROC_NR
)
213 if(m
->m_mmap
.flags
& MAP_THIRDPARTY
) {
214 if(!execpriv
) return EPERM
;
215 if((r
=vm_isokendpt(m
->m_mmap
.forwhom
, &n
)) != OK
)
218 /* regular mmap, i.e. for caller */
219 if((r
=vm_isokendpt(m
->m_source
, &n
)) != OK
) {
220 panic("do_mmap: message from strange source: %d",
227 /* "SUSv3 specifies that mmap() should fail if length is 0" */
232 if(m
->m_mmap
.fd
== -1 || (m
->m_mmap
.flags
& MAP_ANON
)) {
233 /* actual memory in some form */
234 mem_type_t
*mt
= NULL
;
236 if(m
->m_mmap
.fd
!= -1) {
237 printf("VM: mmap: fd %d, len 0x%zx\n", m
->m_mmap
.fd
, len
);
241 /* Contiguous phys memory has to be preallocated. */
242 if((m
->m_mmap
.flags
& (MAP_CONTIG
|MAP_PREALLOC
)) == MAP_CONTIG
) {
246 if(m
->m_mmap
.flags
& MAP_CONTIG
) {
247 mt
= &mem_type_anon_contig
;
248 } else mt
= &mem_type_anon
;
250 if(!(vr
= mmap_region(vmp
, addr
, m
->m_mmap
.flags
, len
,
251 VR_WRITABLE
| VR_ANON
, mt
, execpriv
))) {
255 /* File mapping might be disabled */
256 if(!enable_filemap
) return ENXIO
;
258 /* For files, we only can't accept writable MAP_SHARED
261 if((m
->m_mmap
.flags
& MAP_SHARED
) && (m
->m_mmap
.prot
& PROT_WRITE
)) {
265 if(vfs_request(VMVFSREQ_FDLOOKUP
, m
->m_mmap
.fd
, vmp
, 0, 0,
266 mmap_file_cont
, NULL
, m
, sizeof(*m
)) != OK
) {
267 printf("VM: vfs_request for mmap failed\n");
271 /* request queued; don't reply. */
275 /* Return mapping, as seen from process. */
276 m
->m_mmap
.retaddr
= (void *) vr
->vaddr
;
281 /*===========================================================================*
283 *===========================================================================*/
284 static int map_perm_check(endpoint_t caller
, endpoint_t target
,
285 phys_bytes physaddr
, phys_bytes len
)
289 /* TTY and memory are allowed to do anything.
290 * They have to be special cases as they have to be able to do
291 * anything; TTY even on behalf of anyone for the TIOCMAPMEM
292 * ioctl. MEM just for itself.
294 if(caller
== TTY_PROC_NR
)
296 if(caller
== MEM_PROC_NR
)
299 /* Anyone else needs explicit permission from the kernel (ultimately
302 r
= sys_privquery_mem(target
, physaddr
, len
);
307 /*===========================================================================*
309 *===========================================================================*/
310 int do_map_phys(message
*m
)
315 struct vir_region
*vr
;
317 phys_bytes startaddr
;
320 target
= m
->m_lsys_vm_map_phys
.ep
;
321 len
= m
->m_lsys_vm_map_phys
.len
;
323 if (len
<= 0) return EINVAL
;
326 target
= m
->m_source
;
328 if((r
=vm_isokendpt(target
, &n
)) != OK
)
331 startaddr
= (vir_bytes
)m
->m_lsys_vm_map_phys
.phaddr
;
333 /* First check permission, then round range down/up. Caller can't
334 * help it if we can't map in lower than page granularity.
336 if(map_perm_check(m
->m_source
, target
, startaddr
, len
) != OK
) {
337 printf("VM: unauthorized mapping of 0x%lx by %d for %d\n",
338 startaddr
, m
->m_source
, target
);
344 offset
= startaddr
% VM_PAGE_SIZE
;
348 if(len
% VM_PAGE_SIZE
)
349 len
+= VM_PAGE_SIZE
- (len
% VM_PAGE_SIZE
);
351 if(!(vr
= map_page_region(vmp
, VM_MMAPBASE
, VM_MMAPTOP
, len
,
352 VR_DIRECT
| VR_WRITABLE
, 0, &mem_type_directphys
))) {
356 phys_setphys(vr
, startaddr
);
358 m
->m_lsys_vm_map_phys
.reply
= (void *) (vr
->vaddr
+ offset
);
363 /*===========================================================================*
365 *===========================================================================*/
366 int do_remap(message
*m
)
372 struct vir_region
*src_region
, *vr
;
373 struct vmproc
*dvmp
, *svmp
;
377 if(m
->m_type
== VM_REMAP
)
379 else if(m
->m_type
== VM_REMAP_RO
)
381 else panic("do_remap: can't be");
383 da
= (vir_bytes
) m
->m_lsys_vm_vmremap
.dest_addr
;
384 sa
= (vir_bytes
) m
->m_lsys_vm_vmremap
.src_addr
;
385 size
= m
->m_lsys_vm_vmremap
.size
;
387 if (size
<= 0) return EINVAL
;
389 if ((r
= vm_isokendpt((endpoint_t
) m
->m_lsys_vm_vmremap
.destination
, &dn
)) != OK
)
391 if ((r
= vm_isokendpt((endpoint_t
) m
->m_lsys_vm_vmremap
.source
, &sn
)) != OK
)
397 if (!(src_region
= map_lookup(svmp
, sa
, NULL
)))
400 if(src_region
->vaddr
!= sa
) {
401 printf("VM: do_remap: not start of region.\n");
405 if (size
% VM_PAGE_SIZE
)
406 size
+= VM_PAGE_SIZE
- size
% VM_PAGE_SIZE
;
408 if(size
!= src_region
->length
) {
409 printf("VM: do_remap: not size of region.\n");
415 flags
|= VR_WRITABLE
;
418 vr
= map_page_region(dvmp
, da
, 0, size
, flags
, 0,
421 vr
= map_page_region(dvmp
, VM_MMAPBASE
, VM_MMAPTOP
, size
,
422 flags
, 0, &mem_type_shared
);
425 printf("VM: re-map of shared area failed\n");
429 shared_setsource(vr
, svmp
->vm_endpoint
, src_region
);
431 m
->m_lsys_vm_vmremap
.ret_addr
= (void *) vr
->vaddr
;
435 /*===========================================================================*
437 *===========================================================================*/
438 int do_get_phys(message
*m
)
446 target
= m
->m_lc_vm_getphys
.endpt
;
447 addr
= (vir_bytes
) m
->m_lc_vm_getphys
.addr
;
449 if ((r
= vm_isokendpt(target
, &n
)) != OK
)
454 r
= map_get_phys(vmp
, addr
, &ret
);
456 m
->m_lc_vm_getphys
.ret_addr
= (void *) ret
;
460 /*===========================================================================*
462 *===========================================================================*/
463 int do_get_refcount(message
*m
)
471 target
= m
->m_lsys_vm_getref
.endpt
;
472 addr
= (vir_bytes
) m
->m_lsys_vm_getref
.addr
;
474 if ((r
= vm_isokendpt(target
, &n
)) != OK
)
479 r
= map_get_ref(vmp
, addr
, &cnt
);
481 m
->m_lsys_vm_getref
.retc
= cnt
;
485 /*===========================================================================*
487 *===========================================================================*/
488 int munmap_vm_lin(vir_bytes addr
, size_t len
)
490 if(addr
% VM_PAGE_SIZE
) {
491 printf("munmap_vm_lin: offset not page aligned\n");
495 if(len
% VM_PAGE_SIZE
) {
496 printf("munmap_vm_lin: len not page aligned\n");
500 if(pt_writemap(NULL
, &vmproc
[VM_PROC_NR
].vm_pt
, addr
, MAP_NONE
, len
, 0,
501 WMF_OVERWRITE
| WMF_FREE
) != OK
) {
502 printf("munmap_vm_lin: pt_writemap failed\n");
509 /*===========================================================================*
511 *===========================================================================*/
512 int do_munmap(message
*m
)
516 struct vir_region
*vr
;
518 endpoint_t target
= SELF
;
520 if(m
->m_type
== VM_UNMAP_PHYS
) {
521 target
= m
->m_lsys_vm_unmap_phys
.ep
;
522 } else if(m
->m_type
== VM_SHM_UNMAP
) {
523 target
= m
->m_lc_vm_shm_unmap
.forwhom
;
527 target
= m
->m_source
;
529 if((r
=vm_isokendpt(target
, &n
)) != OK
) {
530 panic("do_mmap: message from strange source: %d", m
->m_source
);
535 if(m
->m_source
== VM_PROC_NR
) {
536 /* VM munmap is a special case, the region we want to
537 * munmap may or may not be there in our data structures,
538 * depending on whether this is an updated VM instance or not.
540 if(!region_search_root(&vmp
->vm_regions_avl
)) {
541 munmap_vm_lin(addr
, m
->VMUM_LEN
);
543 else if((vr
= map_lookup(vmp
, addr
, NULL
))) {
544 if(map_unmap_region(vmp
, vr
, 0, m
->VMUM_LEN
) != OK
) {
545 printf("VM: self map_unmap_region failed\n");
551 if(m
->m_type
== VM_UNMAP_PHYS
) {
552 addr
= (vir_bytes
) m
->m_lsys_vm_unmap_phys
.vaddr
;
553 } else if(m
->m_type
== VM_SHM_UNMAP
) {
554 addr
= (vir_bytes
) m
->m_lc_vm_shm_unmap
.addr
;
555 } else addr
= (vir_bytes
) m
->VMUM_ADDR
;
557 if(addr
% VM_PAGE_SIZE
)
560 if(m
->m_type
== VM_UNMAP_PHYS
|| m
->m_type
== VM_SHM_UNMAP
) {
561 struct vir_region
*vr
;
562 if(!(vr
= map_lookup(vmp
, addr
, NULL
))) {
563 printf("VM: unmap: address 0x%lx not found in %d\n",
565 sys_diagctl_stacktrace(target
);
569 } else len
= roundup(m
->VMUM_LEN
, VM_PAGE_SIZE
);
571 return map_unmap_range(vmp
, addr
, len
);