xref: /minix3/minix/servers/vm/mmap.c (revision 5f6c420586374d552d4a81aa129ada5aa46b797d)
1433d6423SLionel Sambuc 
2433d6423SLionel Sambuc #define _SYSTEM 1
3433d6423SLionel Sambuc 
4433d6423SLionel Sambuc #include <minix/callnr.h>
5433d6423SLionel Sambuc #include <minix/com.h>
6433d6423SLionel Sambuc #include <minix/config.h>
7433d6423SLionel Sambuc #include <minix/const.h>
8433d6423SLionel Sambuc #include <minix/ds.h>
9433d6423SLionel Sambuc #include <minix/endpoint.h>
10433d6423SLionel Sambuc #include <minix/minlib.h>
11433d6423SLionel Sambuc #include <minix/type.h>
12433d6423SLionel Sambuc #include <minix/ipc.h>
13433d6423SLionel Sambuc #include <minix/sysutil.h>
14433d6423SLionel Sambuc #include <minix/syslib.h>
15433d6423SLionel Sambuc #include <minix/safecopies.h>
16433d6423SLionel Sambuc #include <minix/bitmap.h>
17433d6423SLionel Sambuc #include <minix/debug.h>
18433d6423SLionel Sambuc 
19433d6423SLionel Sambuc #include <machine/vmparam.h>
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc #include <sys/mman.h>
22433d6423SLionel Sambuc #include <sys/param.h>
23433d6423SLionel Sambuc 
24433d6423SLionel Sambuc #include <errno.h>
25433d6423SLionel Sambuc #include <assert.h>
26433d6423SLionel Sambuc #include <string.h>
27433d6423SLionel Sambuc #include <stdio.h>
28433d6423SLionel Sambuc #include <fcntl.h>
29433d6423SLionel Sambuc 
30433d6423SLionel Sambuc #include "glo.h"
31433d6423SLionel Sambuc #include "proto.h"
32433d6423SLionel Sambuc #include "util.h"
33433d6423SLionel Sambuc #include "region.h"
34433d6423SLionel Sambuc 
35433d6423SLionel Sambuc 
mmap_region(struct vmproc * vmp,vir_bytes addr,u32_t vmm_flags,size_t len,u32_t vrflags,mem_type_t * mt,int execpriv)36433d6423SLionel Sambuc static struct vir_region *mmap_region(struct vmproc *vmp, vir_bytes addr,
37433d6423SLionel Sambuc 	u32_t vmm_flags, size_t len, u32_t vrflags,
38433d6423SLionel Sambuc 	mem_type_t *mt, int execpriv)
39433d6423SLionel Sambuc {
40433d6423SLionel Sambuc 	u32_t mfflags = 0;
41433d6423SLionel Sambuc 	struct vir_region *vr = NULL;
42433d6423SLionel Sambuc 
43433d6423SLionel Sambuc 	if(vmm_flags & MAP_LOWER16M) vrflags |= VR_LOWER16MB;
44433d6423SLionel Sambuc 	if(vmm_flags & MAP_LOWER1M)  vrflags |= VR_LOWER1MB;
45433d6423SLionel Sambuc 	if(vmm_flags & MAP_ALIGNMENT_64KB) vrflags |= VR_PHYS64K;
46433d6423SLionel Sambuc 	if(vmm_flags & MAP_PREALLOC) mfflags |= MF_PREALLOC;
47433d6423SLionel Sambuc 	if(vmm_flags & MAP_UNINITIALIZED) {
48433d6423SLionel Sambuc 		if(!execpriv) return NULL;
49433d6423SLionel Sambuc 		vrflags |= VR_UNINITIALIZED;
50433d6423SLionel Sambuc 	}
51433d6423SLionel Sambuc 
52433d6423SLionel Sambuc 	if(len <= 0) {
53433d6423SLionel Sambuc 		return NULL;
54433d6423SLionel Sambuc 	}
55433d6423SLionel Sambuc 
56433d6423SLionel Sambuc 	if(len % VM_PAGE_SIZE)
57433d6423SLionel Sambuc 		len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE);
58433d6423SLionel Sambuc 
59433d6423SLionel Sambuc 	if (addr && (vmm_flags & MAP_FIXED)) {
60433d6423SLionel Sambuc 		int r = map_unmap_range(vmp, addr, len);
61433d6423SLionel Sambuc 		if(r != OK) {
62433d6423SLionel Sambuc 			printf("mmap_region: map_unmap_range failed (%d)\n", r);
63433d6423SLionel Sambuc 			return NULL;
64433d6423SLionel Sambuc 		}
65433d6423SLionel Sambuc 	}
66433d6423SLionel Sambuc 
67433d6423SLionel Sambuc 	if (addr || (vmm_flags & MAP_FIXED)) {
68433d6423SLionel Sambuc 		/* An address is given, first try at that address. */
69433d6423SLionel Sambuc 		vr = map_page_region(vmp, addr, 0, len,
70433d6423SLionel Sambuc 			vrflags, mfflags, mt);
71433d6423SLionel Sambuc 		if(!vr && (vmm_flags & MAP_FIXED))
72433d6423SLionel Sambuc 			return NULL;
73433d6423SLionel Sambuc 	}
74433d6423SLionel Sambuc 
75433d6423SLionel Sambuc 	if (!vr) {
76433d6423SLionel Sambuc 		/* No address given or address already in use. */
7753398d73SCristiano Giuffrida 		vr = map_page_region(vmp, VM_MMAPBASE, VM_MMAPTOP, len,
78433d6423SLionel Sambuc 			vrflags, mfflags, mt);
79433d6423SLionel Sambuc 	}
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc 	return vr;
82433d6423SLionel Sambuc }
83433d6423SLionel Sambuc 
mmap_file(struct vmproc * vmp,int vmfd,off_t file_offset,int flags,ino_t ino,dev_t dev,u64_t filesize,vir_bytes addr,vir_bytes len,vir_bytes * retaddr,u16_t clearend,int writable,int mayclosefd)84433d6423SLionel Sambuc static int mmap_file(struct vmproc *vmp,
85433d6423SLionel Sambuc 	int vmfd, off_t file_offset, int flags,
86433d6423SLionel Sambuc 	ino_t ino, dev_t dev, u64_t filesize, vir_bytes addr, vir_bytes len,
87433d6423SLionel Sambuc 	vir_bytes *retaddr, u16_t clearend, int writable, int mayclosefd)
88433d6423SLionel Sambuc {
89433d6423SLionel Sambuc /* VFS has replied to a VMVFSREQ_FDLOOKUP request. */
90433d6423SLionel Sambuc 	struct vir_region *vr;
91433d6423SLionel Sambuc 	u64_t page_offset;
92433d6423SLionel Sambuc 	int result = OK;
93433d6423SLionel Sambuc 	u32_t vrflags = 0;
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc 	if(writable) vrflags |= VR_WRITABLE;
96433d6423SLionel Sambuc 
97433d6423SLionel Sambuc 	/* Do some page alignments. */
98433d6423SLionel Sambuc 	if((page_offset = (file_offset % VM_PAGE_SIZE))) {
99433d6423SLionel Sambuc 		file_offset -= page_offset;
100433d6423SLionel Sambuc 		len += page_offset;
101433d6423SLionel Sambuc 	}
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc 	len = roundup(len, VM_PAGE_SIZE);
104433d6423SLionel Sambuc 
105433d6423SLionel Sambuc 	/* All numbers should be page-aligned now. */
106433d6423SLionel Sambuc 	assert(!(len % VM_PAGE_SIZE));
107433d6423SLionel Sambuc 	assert(!(filesize % VM_PAGE_SIZE));
108433d6423SLionel Sambuc 	assert(!(file_offset % VM_PAGE_SIZE));
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc #if 0
111433d6423SLionel Sambuc 	/* XXX ld.so relies on longer-than-file mapping */
112433d6423SLionel Sambuc 	if((u64_t) len + file_offset > filesize) {
113433d6423SLionel Sambuc 		printf("VM: truncating mmap dev 0x%x ino %d beyond file size in %d; offset %llu, len %lu, size %llu; ",
114433d6423SLionel Sambuc 			dev, ino, vmp->vm_endpoint,
115433d6423SLionel Sambuc 			file_offset, len, filesize);
116433d6423SLionel Sambuc 		len = filesize - file_offset;
117433d6423SLionel Sambuc 		return EINVAL;
118433d6423SLionel Sambuc 	}
119433d6423SLionel Sambuc #endif
120433d6423SLionel Sambuc 
121433d6423SLionel Sambuc 	if(!(vr = mmap_region(vmp, addr, flags, len,
122433d6423SLionel Sambuc 		vrflags, &mem_type_mappedfile, 0))) {
123433d6423SLionel Sambuc 		result = ENOMEM;
124433d6423SLionel Sambuc 	} else {
125433d6423SLionel Sambuc 		*retaddr = vr->vaddr + page_offset;
126433d6423SLionel Sambuc 		result = OK;
127433d6423SLionel Sambuc 
128433d6423SLionel Sambuc 		mappedfile_setfile(vmp, vr, vmfd,
129433d6423SLionel Sambuc 			file_offset, dev, ino, clearend, 1, mayclosefd);
130433d6423SLionel Sambuc 	}
131433d6423SLionel Sambuc 
132433d6423SLionel Sambuc 	return result;
133433d6423SLionel Sambuc }
134433d6423SLionel Sambuc 
do_vfs_mmap(message * m)135433d6423SLionel Sambuc int do_vfs_mmap(message *m)
136433d6423SLionel Sambuc {
137433d6423SLionel Sambuc 	vir_bytes v;
138433d6423SLionel Sambuc 	struct vmproc *vmp;
139433d6423SLionel Sambuc 	int r, n;
140433d6423SLionel Sambuc 	u16_t clearend, flags = 0;
141433d6423SLionel Sambuc 
142433d6423SLionel Sambuc 	/* It might be disabled */
143433d6423SLionel Sambuc 	if(!enable_filemap) return ENXIO;
144433d6423SLionel Sambuc 
145433d6423SLionel Sambuc 	clearend = m->m_vm_vfs_mmap.clearend;
146433d6423SLionel Sambuc 	flags = m->m_vm_vfs_mmap.flags;
147433d6423SLionel Sambuc 
148433d6423SLionel Sambuc 	if((r=vm_isokendpt(m->m_vm_vfs_mmap.who, &n)) != OK)
149433d6423SLionel Sambuc 		panic("bad ep %d from vfs", m->m_vm_vfs_mmap.who);
150433d6423SLionel Sambuc 	vmp = &vmproc[n];
151433d6423SLionel Sambuc 
152433d6423SLionel Sambuc 	return mmap_file(vmp, m->m_vm_vfs_mmap.fd, m->m_vm_vfs_mmap.offset,
153433d6423SLionel Sambuc 		MAP_PRIVATE | MAP_FIXED,
154433d6423SLionel Sambuc 		m->m_vm_vfs_mmap.ino, m->m_vm_vfs_mmap.dev,
155433d6423SLionel Sambuc 		(u64_t) LONG_MAX * VM_PAGE_SIZE,
156433d6423SLionel Sambuc 		m->m_vm_vfs_mmap.vaddr, m->m_vm_vfs_mmap.len, &v,
157433d6423SLionel Sambuc 		clearend, flags, 0);
158433d6423SLionel Sambuc }
159433d6423SLionel Sambuc 
mmap_file_cont(struct vmproc * vmp,message * replymsg,void * cbarg,void * origmsg_v)160433d6423SLionel Sambuc static void mmap_file_cont(struct vmproc *vmp, message *replymsg, void *cbarg,
161433d6423SLionel Sambuc 	void *origmsg_v)
162433d6423SLionel Sambuc {
163433d6423SLionel Sambuc 	message *origmsg = (message *) origmsg_v;
164433d6423SLionel Sambuc 	message mmap_reply;
165433d6423SLionel Sambuc 	int result;
166433d6423SLionel Sambuc 	int writable = 0;
167433d6423SLionel Sambuc 	vir_bytes v = (vir_bytes) MAP_FAILED;
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc 	if(origmsg->m_mmap.prot & PROT_WRITE)
170433d6423SLionel Sambuc 		writable = 1;
171433d6423SLionel Sambuc 
172433d6423SLionel Sambuc 	if(replymsg->VMV_RESULT != OK) {
173433d6423SLionel Sambuc #if 0   /* Noisy diagnostic for mmap() by ld.so */
174433d6423SLionel Sambuc 		printf("VM: VFS reply failed (%d)\n", replymsg->VMV_RESULT);
175433d6423SLionel Sambuc 		sys_diagctl_stacktrace(vmp->vm_endpoint);
176433d6423SLionel Sambuc #endif
177cb3a6387SDavid van Moolenbroek 		result = replymsg->VMV_RESULT;
178433d6423SLionel Sambuc 	} else {
179433d6423SLionel Sambuc 		/* Finish mmap */
180433d6423SLionel Sambuc 		result = mmap_file(vmp, replymsg->VMV_FD, origmsg->m_mmap.offset,
181433d6423SLionel Sambuc 			origmsg->m_mmap.flags,
182433d6423SLionel Sambuc 			replymsg->VMV_INO, replymsg->VMV_DEV,
183433d6423SLionel Sambuc 			(u64_t) replymsg->VMV_SIZE_PAGES*PAGE_SIZE,
184433d6423SLionel Sambuc 			(vir_bytes) origmsg->m_mmap.addr,
185433d6423SLionel Sambuc 			origmsg->m_mmap.len, &v, 0, writable, 1);
186433d6423SLionel Sambuc 	}
187433d6423SLionel Sambuc 
188433d6423SLionel Sambuc 	/* Unblock requesting process. */
189433d6423SLionel Sambuc 	memset(&mmap_reply, 0, sizeof(mmap_reply));
190433d6423SLionel Sambuc 	mmap_reply.m_type = result;
191433d6423SLionel Sambuc 	mmap_reply.m_mmap.retaddr = (void *) v;
192433d6423SLionel Sambuc 
193433d6423SLionel Sambuc 	if(ipc_send(vmp->vm_endpoint, &mmap_reply) != OK)
194433d6423SLionel Sambuc 		panic("VM: mmap_file_cont: ipc_send() failed");
195433d6423SLionel Sambuc }
196433d6423SLionel Sambuc 
197433d6423SLionel Sambuc /*===========================================================================*
198433d6423SLionel Sambuc  *				do_mmap			     		     *
199433d6423SLionel Sambuc  *===========================================================================*/
do_mmap(message * m)200433d6423SLionel Sambuc int do_mmap(message *m)
201433d6423SLionel Sambuc {
202433d6423SLionel Sambuc 	int r, n;
203433d6423SLionel Sambuc 	struct vmproc *vmp;
204433d6423SLionel Sambuc 	vir_bytes addr = (vir_bytes) m->m_mmap.addr;
205433d6423SLionel Sambuc 	struct vir_region *vr = NULL;
206433d6423SLionel Sambuc 	int execpriv = 0;
207433d6423SLionel Sambuc 	size_t len = (vir_bytes) m->m_mmap.len;
208433d6423SLionel Sambuc 
209433d6423SLionel Sambuc 	/* RS and VFS can do slightly more special mmap() things */
210433d6423SLionel Sambuc 	if(m->m_source == VFS_PROC_NR || m->m_source == RS_PROC_NR)
211433d6423SLionel Sambuc 		execpriv = 1;
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc 	if(m->m_mmap.flags & MAP_THIRDPARTY) {
214433d6423SLionel Sambuc 		if(!execpriv) return EPERM;
215433d6423SLionel Sambuc 		if((r=vm_isokendpt(m->m_mmap.forwhom, &n)) != OK)
216433d6423SLionel Sambuc 			return ESRCH;
217433d6423SLionel Sambuc 	} else {
218433d6423SLionel Sambuc 		/* regular mmap, i.e. for caller */
219433d6423SLionel Sambuc 		if((r=vm_isokendpt(m->m_source, &n)) != OK) {
220433d6423SLionel Sambuc 			panic("do_mmap: message from strange source: %d",
221433d6423SLionel Sambuc 				m->m_source);
222433d6423SLionel Sambuc 		}
223433d6423SLionel Sambuc 	}
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc 	vmp = &vmproc[n];
226433d6423SLionel Sambuc 
227433d6423SLionel Sambuc 	/* "SUSv3 specifies that mmap() should fail if length is 0" */
228433d6423SLionel Sambuc 	if(len <= 0) {
229433d6423SLionel Sambuc 		return EINVAL;
230433d6423SLionel Sambuc 	}
231433d6423SLionel Sambuc 
232433d6423SLionel Sambuc 	if(m->m_mmap.fd == -1 || (m->m_mmap.flags & MAP_ANON)) {
233433d6423SLionel Sambuc 		/* actual memory in some form */
234433d6423SLionel Sambuc 		mem_type_t *mt = NULL;
235433d6423SLionel Sambuc 
236433d6423SLionel Sambuc 		if(m->m_mmap.fd != -1) {
2373c8950ccSBen Gras 			printf("VM: mmap: fd %d, len 0x%zx\n", m->m_mmap.fd, len);
238433d6423SLionel Sambuc 			return EINVAL;
239433d6423SLionel Sambuc 		}
240433d6423SLionel Sambuc 
241433d6423SLionel Sambuc 		/* Contiguous phys memory has to be preallocated. */
242433d6423SLionel Sambuc 		if((m->m_mmap.flags & (MAP_CONTIG|MAP_PREALLOC)) == MAP_CONTIG) {
243433d6423SLionel Sambuc 			return EINVAL;
244433d6423SLionel Sambuc 		}
245433d6423SLionel Sambuc 
246433d6423SLionel Sambuc 		if(m->m_mmap.flags & MAP_CONTIG) {
247433d6423SLionel Sambuc 			mt = &mem_type_anon_contig;
248433d6423SLionel Sambuc 		} else	mt = &mem_type_anon;
249433d6423SLionel Sambuc 
250433d6423SLionel Sambuc 		if(!(vr = mmap_region(vmp, addr, m->m_mmap.flags, len,
251433d6423SLionel Sambuc 			VR_WRITABLE | VR_ANON, mt, execpriv))) {
252433d6423SLionel Sambuc 			return ENOMEM;
253433d6423SLionel Sambuc 		}
254433d6423SLionel Sambuc 	} else {
255433d6423SLionel Sambuc 		/* File mapping might be disabled */
256433d6423SLionel Sambuc 		if(!enable_filemap) return ENXIO;
257433d6423SLionel Sambuc 
258433d6423SLionel Sambuc 		/* For files, we only can't accept writable MAP_SHARED
259433d6423SLionel Sambuc 		 * mappings.
260433d6423SLionel Sambuc 		 */
261433d6423SLionel Sambuc 		if((m->m_mmap.flags & MAP_SHARED) && (m->m_mmap.prot & PROT_WRITE)) {
262433d6423SLionel Sambuc 			return ENXIO;
263433d6423SLionel Sambuc 		}
264433d6423SLionel Sambuc 
265433d6423SLionel Sambuc 		if(vfs_request(VMVFSREQ_FDLOOKUP, m->m_mmap.fd, vmp, 0, 0,
266433d6423SLionel Sambuc 			mmap_file_cont, NULL, m, sizeof(*m)) != OK) {
267433d6423SLionel Sambuc 			printf("VM: vfs_request for mmap failed\n");
268433d6423SLionel Sambuc 			return ENXIO;
269433d6423SLionel Sambuc 		}
270433d6423SLionel Sambuc 
271433d6423SLionel Sambuc 		/* request queued; don't reply. */
272433d6423SLionel Sambuc 		return SUSPEND;
273433d6423SLionel Sambuc 	}
274433d6423SLionel Sambuc 
275433d6423SLionel Sambuc 	/* Return mapping, as seen from process. */
276433d6423SLionel Sambuc 	m->m_mmap.retaddr = (void *) vr->vaddr;
277433d6423SLionel Sambuc 
278433d6423SLionel Sambuc 	return OK;
279433d6423SLionel Sambuc }
280433d6423SLionel Sambuc 
281433d6423SLionel Sambuc /*===========================================================================*
282433d6423SLionel Sambuc  *				map_perm_check		     		     *
283433d6423SLionel Sambuc  *===========================================================================*/
map_perm_check(endpoint_t caller,endpoint_t target,phys_bytes physaddr,phys_bytes len)284433d6423SLionel Sambuc static int map_perm_check(endpoint_t caller, endpoint_t target,
285433d6423SLionel Sambuc 	phys_bytes physaddr, phys_bytes len)
286433d6423SLionel Sambuc {
287433d6423SLionel Sambuc 	int r;
288433d6423SLionel Sambuc 
289433d6423SLionel Sambuc 	/* TTY and memory are allowed to do anything.
290433d6423SLionel Sambuc 	 * They have to be special cases as they have to be able to do
291433d6423SLionel Sambuc 	 * anything; TTY even on behalf of anyone for the TIOCMAPMEM
292433d6423SLionel Sambuc 	 * ioctl. MEM just for itself.
293433d6423SLionel Sambuc 	 */
294433d6423SLionel Sambuc 	if(caller == TTY_PROC_NR)
295433d6423SLionel Sambuc 		return OK;
296433d6423SLionel Sambuc 	if(caller == MEM_PROC_NR)
297433d6423SLionel Sambuc 		return OK;
298433d6423SLionel Sambuc 
299433d6423SLionel Sambuc 	/* Anyone else needs explicit permission from the kernel (ultimately
300433d6423SLionel Sambuc 	 * set by PCI).
301433d6423SLionel Sambuc 	 */
3025d831176SLionel Sambuc 	r = sys_privquery_mem(target, physaddr, len);
303433d6423SLionel Sambuc 
304433d6423SLionel Sambuc 	return r;
305433d6423SLionel Sambuc }
306433d6423SLionel Sambuc 
307433d6423SLionel Sambuc /*===========================================================================*
308433d6423SLionel Sambuc  *				do_map_phys		     		     *
309433d6423SLionel Sambuc  *===========================================================================*/
do_map_phys(message * m)310433d6423SLionel Sambuc int do_map_phys(message *m)
311433d6423SLionel Sambuc {
312433d6423SLionel Sambuc 	int r, n;
313433d6423SLionel Sambuc 	struct vmproc *vmp;
314433d6423SLionel Sambuc 	endpoint_t target;
315433d6423SLionel Sambuc 	struct vir_region *vr;
316433d6423SLionel Sambuc 	vir_bytes len;
317433d6423SLionel Sambuc 	phys_bytes startaddr;
318433d6423SLionel Sambuc 	size_t offset;
319433d6423SLionel Sambuc 
320433d6423SLionel Sambuc 	target = m->m_lsys_vm_map_phys.ep;
321433d6423SLionel Sambuc 	len = m->m_lsys_vm_map_phys.len;
322433d6423SLionel Sambuc 
323433d6423SLionel Sambuc 	if (len <= 0) return EINVAL;
324433d6423SLionel Sambuc 
325433d6423SLionel Sambuc 	if(target == SELF)
326433d6423SLionel Sambuc 		target = m->m_source;
327433d6423SLionel Sambuc 
328433d6423SLionel Sambuc 	if((r=vm_isokendpt(target, &n)) != OK)
329433d6423SLionel Sambuc 		return EINVAL;
330433d6423SLionel Sambuc 
331433d6423SLionel Sambuc 	startaddr = (vir_bytes)m->m_lsys_vm_map_phys.phaddr;
332433d6423SLionel Sambuc 
333433d6423SLionel Sambuc 	/* First check permission, then round range down/up. Caller can't
334433d6423SLionel Sambuc 	 * help it if we can't map in lower than page granularity.
335433d6423SLionel Sambuc 	 */
336433d6423SLionel Sambuc 	if(map_perm_check(m->m_source, target, startaddr, len) != OK) {
3375d831176SLionel Sambuc 		printf("VM: unauthorized mapping of 0x%lx by %d for %d\n",
3385d831176SLionel Sambuc 			startaddr, m->m_source, target);
339433d6423SLionel Sambuc 		return EPERM;
340433d6423SLionel Sambuc 	}
341433d6423SLionel Sambuc 
342433d6423SLionel Sambuc 	vmp = &vmproc[n];
343433d6423SLionel Sambuc 
344433d6423SLionel Sambuc 	offset = startaddr % VM_PAGE_SIZE;
345433d6423SLionel Sambuc 	len += offset;
346433d6423SLionel Sambuc 	startaddr -= offset;
347433d6423SLionel Sambuc 
348433d6423SLionel Sambuc 	if(len % VM_PAGE_SIZE)
349433d6423SLionel Sambuc 		len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE);
350433d6423SLionel Sambuc 
35153398d73SCristiano Giuffrida 	if(!(vr = map_page_region(vmp, VM_MMAPBASE, VM_MMAPTOP, len,
352433d6423SLionel Sambuc 		VR_DIRECT | VR_WRITABLE, 0, &mem_type_directphys))) {
353433d6423SLionel Sambuc 		return ENOMEM;
354433d6423SLionel Sambuc 	}
355433d6423SLionel Sambuc 
356433d6423SLionel Sambuc 	phys_setphys(vr, startaddr);
357433d6423SLionel Sambuc 
358433d6423SLionel Sambuc 	m->m_lsys_vm_map_phys.reply = (void *) (vr->vaddr + offset);
359433d6423SLionel Sambuc 
360433d6423SLionel Sambuc 	return OK;
361433d6423SLionel Sambuc }
362433d6423SLionel Sambuc 
363433d6423SLionel Sambuc /*===========================================================================*
364433d6423SLionel Sambuc  *				do_remap		     		     *
365433d6423SLionel Sambuc  *===========================================================================*/
do_remap(message * m)366433d6423SLionel Sambuc int do_remap(message *m)
367433d6423SLionel Sambuc {
368433d6423SLionel Sambuc 	int dn, sn;
369433d6423SLionel Sambuc 	vir_bytes da, sa;
370433d6423SLionel Sambuc 	size_t size;
371433d6423SLionel Sambuc 	u32_t flags;
372433d6423SLionel Sambuc 	struct vir_region *src_region, *vr;
373433d6423SLionel Sambuc 	struct vmproc *dvmp, *svmp;
374433d6423SLionel Sambuc 	int r;
375433d6423SLionel Sambuc 	int readonly;
376433d6423SLionel Sambuc 
377433d6423SLionel Sambuc 	if(m->m_type == VM_REMAP)
378433d6423SLionel Sambuc 		readonly = 0;
379433d6423SLionel Sambuc 	else if(m->m_type == VM_REMAP_RO)
380433d6423SLionel Sambuc 		readonly = 1;
381433d6423SLionel Sambuc 	else panic("do_remap: can't be");
382433d6423SLionel Sambuc 
383433d6423SLionel Sambuc 	da = (vir_bytes) m->m_lsys_vm_vmremap.dest_addr;
384433d6423SLionel Sambuc 	sa = (vir_bytes) m->m_lsys_vm_vmremap.src_addr;
385433d6423SLionel Sambuc 	size = m->m_lsys_vm_vmremap.size;
386433d6423SLionel Sambuc 
387433d6423SLionel Sambuc 	if (size <= 0) return EINVAL;
388433d6423SLionel Sambuc 
389433d6423SLionel Sambuc 	if ((r = vm_isokendpt((endpoint_t) m->m_lsys_vm_vmremap.destination, &dn)) != OK)
390433d6423SLionel Sambuc 		return EINVAL;
391433d6423SLionel Sambuc 	if ((r = vm_isokendpt((endpoint_t) m->m_lsys_vm_vmremap.source, &sn)) != OK)
392433d6423SLionel Sambuc 		return EINVAL;
393433d6423SLionel Sambuc 
394433d6423SLionel Sambuc 	dvmp = &vmproc[dn];
395433d6423SLionel Sambuc 	svmp = &vmproc[sn];
396433d6423SLionel Sambuc 
397433d6423SLionel Sambuc 	if (!(src_region = map_lookup(svmp, sa, NULL)))
398433d6423SLionel Sambuc 		return EINVAL;
399433d6423SLionel Sambuc 
400433d6423SLionel Sambuc 	if(src_region->vaddr != sa) {
401433d6423SLionel Sambuc 		printf("VM: do_remap: not start of region.\n");
402433d6423SLionel Sambuc 		return EFAULT;
403433d6423SLionel Sambuc 	}
404433d6423SLionel Sambuc 
405433d6423SLionel Sambuc 	if (size % VM_PAGE_SIZE)
406433d6423SLionel Sambuc 		size += VM_PAGE_SIZE - size % VM_PAGE_SIZE;
407433d6423SLionel Sambuc 
408433d6423SLionel Sambuc 	if(size != src_region->length) {
409433d6423SLionel Sambuc 		printf("VM: do_remap: not size of region.\n");
410433d6423SLionel Sambuc 		return EFAULT;
411433d6423SLionel Sambuc 	}
412433d6423SLionel Sambuc 
413433d6423SLionel Sambuc 	flags = VR_SHARED;
414433d6423SLionel Sambuc 	if(!readonly)
415433d6423SLionel Sambuc 		flags |= VR_WRITABLE;
416433d6423SLionel Sambuc 
417433d6423SLionel Sambuc 	if(da)
418433d6423SLionel Sambuc 		vr = map_page_region(dvmp, da, 0, size, flags, 0,
419433d6423SLionel Sambuc 			&mem_type_shared);
420433d6423SLionel Sambuc 	else
42153398d73SCristiano Giuffrida 		vr = map_page_region(dvmp, VM_MMAPBASE, VM_MMAPTOP, size,
42253398d73SCristiano Giuffrida 			flags, 0, &mem_type_shared);
423433d6423SLionel Sambuc 
424433d6423SLionel Sambuc 	if(!vr) {
425433d6423SLionel Sambuc 		printf("VM: re-map of shared area failed\n");
426433d6423SLionel Sambuc 		return ENOMEM;
427433d6423SLionel Sambuc 	}
428433d6423SLionel Sambuc 
429433d6423SLionel Sambuc 	shared_setsource(vr, svmp->vm_endpoint, src_region);
430433d6423SLionel Sambuc 
431433d6423SLionel Sambuc 	m->m_lsys_vm_vmremap.ret_addr = (void *) vr->vaddr;
432433d6423SLionel Sambuc 	return OK;
433433d6423SLionel Sambuc }
434433d6423SLionel Sambuc 
435433d6423SLionel Sambuc /*===========================================================================*
436433d6423SLionel Sambuc  *				do_get_phys		     		     *
437433d6423SLionel Sambuc  *===========================================================================*/
do_get_phys(message * m)438433d6423SLionel Sambuc int do_get_phys(message *m)
439433d6423SLionel Sambuc {
440433d6423SLionel Sambuc 	int r, n;
441433d6423SLionel Sambuc 	struct vmproc *vmp;
442433d6423SLionel Sambuc 	endpoint_t target;
443433d6423SLionel Sambuc 	phys_bytes ret;
444433d6423SLionel Sambuc 	vir_bytes addr;
445433d6423SLionel Sambuc 
446433d6423SLionel Sambuc 	target = m->m_lc_vm_getphys.endpt;
447433d6423SLionel Sambuc 	addr = (vir_bytes) m->m_lc_vm_getphys.addr;
448433d6423SLionel Sambuc 
449433d6423SLionel Sambuc 	if ((r = vm_isokendpt(target, &n)) != OK)
450433d6423SLionel Sambuc 		return EINVAL;
451433d6423SLionel Sambuc 
452433d6423SLionel Sambuc 	vmp = &vmproc[n];
453433d6423SLionel Sambuc 
454433d6423SLionel Sambuc 	r = map_get_phys(vmp, addr, &ret);
455433d6423SLionel Sambuc 
456433d6423SLionel Sambuc 	m->m_lc_vm_getphys.ret_addr = (void *) ret;
457433d6423SLionel Sambuc 	return r;
458433d6423SLionel Sambuc }
459433d6423SLionel Sambuc 
460433d6423SLionel Sambuc /*===========================================================================*
461433d6423SLionel Sambuc  *				do_get_refcount		     		     *
462433d6423SLionel Sambuc  *===========================================================================*/
do_get_refcount(message * m)463433d6423SLionel Sambuc int do_get_refcount(message *m)
464433d6423SLionel Sambuc {
465433d6423SLionel Sambuc 	int r, n;
466433d6423SLionel Sambuc 	struct vmproc *vmp;
467433d6423SLionel Sambuc 	endpoint_t target;
468433d6423SLionel Sambuc 	u8_t cnt;
469433d6423SLionel Sambuc 	vir_bytes addr;
470433d6423SLionel Sambuc 
471433d6423SLionel Sambuc 	target = m->m_lsys_vm_getref.endpt;
472433d6423SLionel Sambuc 	addr = (vir_bytes) m->m_lsys_vm_getref.addr;
473433d6423SLionel Sambuc 
474433d6423SLionel Sambuc 	if ((r = vm_isokendpt(target, &n)) != OK)
475433d6423SLionel Sambuc 		return EINVAL;
476433d6423SLionel Sambuc 
477433d6423SLionel Sambuc 	vmp = &vmproc[n];
478433d6423SLionel Sambuc 
479433d6423SLionel Sambuc 	r = map_get_ref(vmp, addr, &cnt);
480433d6423SLionel Sambuc 
481433d6423SLionel Sambuc 	m->m_lsys_vm_getref.retc = cnt;
482433d6423SLionel Sambuc 	return r;
483433d6423SLionel Sambuc }
484433d6423SLionel Sambuc 
485433d6423SLionel Sambuc /*===========================================================================*
486*65b4b952SCristiano Giuffrida  *                             munmap_vm_lin                                 *
487*65b4b952SCristiano Giuffrida  *===========================================================================*/
munmap_vm_lin(vir_bytes addr,size_t len)488*65b4b952SCristiano Giuffrida int munmap_vm_lin(vir_bytes addr, size_t len)
489*65b4b952SCristiano Giuffrida {
490*65b4b952SCristiano Giuffrida 	if(addr % VM_PAGE_SIZE) {
491*65b4b952SCristiano Giuffrida 		printf("munmap_vm_lin: offset not page aligned\n");
492*65b4b952SCristiano Giuffrida 		return EFAULT;
493*65b4b952SCristiano Giuffrida 	}
494*65b4b952SCristiano Giuffrida 
495*65b4b952SCristiano Giuffrida 	if(len % VM_PAGE_SIZE) {
496*65b4b952SCristiano Giuffrida 		printf("munmap_vm_lin: len not page aligned\n");
497*65b4b952SCristiano Giuffrida 		return EFAULT;
498*65b4b952SCristiano Giuffrida 	}
499*65b4b952SCristiano Giuffrida 
500*65b4b952SCristiano Giuffrida 	if(pt_writemap(NULL, &vmproc[VM_PROC_NR].vm_pt, addr, MAP_NONE, len, 0,
501*65b4b952SCristiano Giuffrida 		WMF_OVERWRITE | WMF_FREE) != OK) {
502*65b4b952SCristiano Giuffrida 		printf("munmap_vm_lin: pt_writemap failed\n");
503*65b4b952SCristiano Giuffrida 		return EFAULT;
504*65b4b952SCristiano Giuffrida 	}
505*65b4b952SCristiano Giuffrida 
506*65b4b952SCristiano Giuffrida 	return OK;
507*65b4b952SCristiano Giuffrida }
508*65b4b952SCristiano Giuffrida 
509*65b4b952SCristiano Giuffrida /*===========================================================================*
510433d6423SLionel Sambuc  *                              do_munmap                                    *
511433d6423SLionel Sambuc  *===========================================================================*/
do_munmap(message * m)512433d6423SLionel Sambuc int do_munmap(message *m)
513433d6423SLionel Sambuc {
514433d6423SLionel Sambuc         int r, n;
515433d6423SLionel Sambuc         struct vmproc *vmp;
516*65b4b952SCristiano Giuffrida 	struct vir_region *vr;
517433d6423SLionel Sambuc         vir_bytes addr, len;
518433d6423SLionel Sambuc 	endpoint_t target = SELF;
519433d6423SLionel Sambuc 
520433d6423SLionel Sambuc 	if(m->m_type == VM_UNMAP_PHYS) {
521433d6423SLionel Sambuc 		target = m->m_lsys_vm_unmap_phys.ep;
522433d6423SLionel Sambuc 	} else if(m->m_type == VM_SHM_UNMAP) {
523433d6423SLionel Sambuc 		target = m->m_lc_vm_shm_unmap.forwhom;
524433d6423SLionel Sambuc 	}
525433d6423SLionel Sambuc 
526433d6423SLionel Sambuc 	if(target == SELF)
527433d6423SLionel Sambuc 		target = m->m_source;
528433d6423SLionel Sambuc 
529433d6423SLionel Sambuc         if((r=vm_isokendpt(target, &n)) != OK) {
530433d6423SLionel Sambuc                 panic("do_mmap: message from strange source: %d", m->m_source);
531433d6423SLionel Sambuc         }
532433d6423SLionel Sambuc 
533433d6423SLionel Sambuc         vmp = &vmproc[n];
534433d6423SLionel Sambuc 
535*65b4b952SCristiano Giuffrida 	if(m->m_source == VM_PROC_NR) {
536*65b4b952SCristiano Giuffrida 		/* VM munmap is a special case, the region we want to
537*65b4b952SCristiano Giuffrida 		 * munmap may or may not be there in our data structures,
538*65b4b952SCristiano Giuffrida 		 * depending on whether this is an updated VM instance or not.
539*65b4b952SCristiano Giuffrida 		 */
540*65b4b952SCristiano Giuffrida 		if(!region_search_root(&vmp->vm_regions_avl)) {
541*65b4b952SCristiano Giuffrida 			munmap_vm_lin(addr, m->VMUM_LEN);
542*65b4b952SCristiano Giuffrida 		}
543*65b4b952SCristiano Giuffrida 		else if((vr = map_lookup(vmp, addr, NULL))) {
544*65b4b952SCristiano Giuffrida 			if(map_unmap_region(vmp, vr, 0, m->VMUM_LEN) != OK) {
545*65b4b952SCristiano Giuffrida 				printf("VM: self map_unmap_region failed\n");
546*65b4b952SCristiano Giuffrida 			}
547*65b4b952SCristiano Giuffrida 		}
548*65b4b952SCristiano Giuffrida 		return SUSPEND;
549*65b4b952SCristiano Giuffrida 	}
550*65b4b952SCristiano Giuffrida 
551433d6423SLionel Sambuc 	if(m->m_type == VM_UNMAP_PHYS) {
552433d6423SLionel Sambuc 		addr = (vir_bytes) m->m_lsys_vm_unmap_phys.vaddr;
553433d6423SLionel Sambuc 	} else if(m->m_type == VM_SHM_UNMAP) {
554433d6423SLionel Sambuc 		addr = (vir_bytes) m->m_lc_vm_shm_unmap.addr;
555433d6423SLionel Sambuc 	} else	addr = (vir_bytes) m->VMUM_ADDR;
556433d6423SLionel Sambuc 
557433d6423SLionel Sambuc 	if(addr % VM_PAGE_SIZE)
558433d6423SLionel Sambuc 		return EFAULT;
559433d6423SLionel Sambuc 
560433d6423SLionel Sambuc 	if(m->m_type == VM_UNMAP_PHYS || m->m_type == VM_SHM_UNMAP) {
561433d6423SLionel Sambuc 		struct vir_region *vr;
562433d6423SLionel Sambuc 	        if(!(vr = map_lookup(vmp, addr, NULL))) {
563433d6423SLionel Sambuc 			printf("VM: unmap: address 0x%lx not found in %d\n",
564433d6423SLionel Sambuc 	                       addr, target);
565433d6423SLionel Sambuc 			sys_diagctl_stacktrace(target);
566433d6423SLionel Sambuc 	                return EFAULT;
567433d6423SLionel Sambuc 		}
568433d6423SLionel Sambuc 		len = vr->length;
569433d6423SLionel Sambuc 	} else len = roundup(m->VMUM_LEN, VM_PAGE_SIZE);
570433d6423SLionel Sambuc 
571433d6423SLionel Sambuc 	return map_unmap_range(vmp, addr, len);
572433d6423SLionel Sambuc }
573433d6423SLionel Sambuc 
574