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