xref: /minix3/minix/servers/vm/rs.c (revision fb6bd596bf41ca2d95a06bd463dc3aeed822b3d4)
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>
17a1760b57SCristiano Giuffrida #include <minix/rs.h>
18433d6423SLionel Sambuc 
1963483e02SCristiano Giuffrida #include <sys/mman.h>
2063483e02SCristiano Giuffrida 
21433d6423SLionel Sambuc #include <errno.h>
22433d6423SLionel Sambuc #include <string.h>
23433d6423SLionel Sambuc #include <env.h>
24433d6423SLionel Sambuc #include <stdio.h>
25433d6423SLionel Sambuc #include <assert.h>
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc #include "glo.h"
28433d6423SLionel Sambuc #include "proto.h"
29433d6423SLionel Sambuc #include "util.h"
30433d6423SLionel Sambuc #include "region.h"
31433d6423SLionel Sambuc 
32433d6423SLionel Sambuc /*===========================================================================*
33433d6423SLionel Sambuc  *				do_rs_set_priv				     *
34433d6423SLionel Sambuc  *===========================================================================*/
35433d6423SLionel Sambuc int do_rs_set_priv(message *m)
36433d6423SLionel Sambuc {
37433d6423SLionel Sambuc 	int r, n, nr;
38433d6423SLionel Sambuc 	struct vmproc *vmp;
39433d6423SLionel Sambuc 	bitchunk_t call_mask[VM_CALL_MASK_SIZE], *call_mask_p;
40433d6423SLionel Sambuc 
41433d6423SLionel Sambuc 	nr = m->VM_RS_NR;
42433d6423SLionel Sambuc 
43433d6423SLionel Sambuc 	if ((r = vm_isokendpt(nr, &n)) != OK) {
44433d6423SLionel Sambuc 		printf("do_rs_set_priv: bad endpoint %d\n", nr);
45433d6423SLionel Sambuc 		return EINVAL;
46433d6423SLionel Sambuc 	}
47433d6423SLionel Sambuc 
48433d6423SLionel Sambuc 	vmp = &vmproc[n];
49433d6423SLionel Sambuc 
50433d6423SLionel Sambuc 	if (m->VM_RS_BUF) {
51433d6423SLionel Sambuc 		r = sys_datacopy(m->m_source, (vir_bytes) m->VM_RS_BUF, SELF,
52433d6423SLionel Sambuc 			(vir_bytes) call_mask, sizeof(call_mask));
53433d6423SLionel Sambuc 		if (r != OK)
54433d6423SLionel Sambuc 			return r;
55433d6423SLionel Sambuc 		call_mask_p = call_mask;
56433d6423SLionel Sambuc 	} else {
57433d6423SLionel Sambuc 		if (m->VM_RS_SYS) {
58433d6423SLionel Sambuc 			printf("VM: do_rs_set_priv: sys procs don't share!\n");
59433d6423SLionel Sambuc 			return EINVAL;
60433d6423SLionel Sambuc 		}
61433d6423SLionel Sambuc 		call_mask_p = NULL;
62433d6423SLionel Sambuc 	}
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc 	acl_set(vmp, call_mask_p, m->VM_RS_SYS);
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc 	return OK;
67433d6423SLionel Sambuc }
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc /*===========================================================================*
70433d6423SLionel Sambuc  *				do_rs_update	     			     *
71433d6423SLionel Sambuc  *===========================================================================*/
72433d6423SLionel Sambuc int do_rs_update(message *m_ptr)
73433d6423SLionel Sambuc {
74433d6423SLionel Sambuc 	endpoint_t src_e, dst_e, reply_e;
75433d6423SLionel Sambuc 	int src_p, dst_p;
76433d6423SLionel Sambuc 	struct vmproc *src_vmp, *dst_vmp;
77a1760b57SCristiano Giuffrida 	int r, sys_upd_flags;
78433d6423SLionel Sambuc 
79433d6423SLionel Sambuc 	src_e = m_ptr->m_lsys_vm_update.src;
80433d6423SLionel Sambuc 	dst_e = m_ptr->m_lsys_vm_update.dst;
81a1760b57SCristiano Giuffrida         sys_upd_flags = m_ptr->m_lsys_vm_update.flags;
8263483e02SCristiano Giuffrida         reply_e = m_ptr->m_source;
83433d6423SLionel Sambuc 
84433d6423SLionel Sambuc 	/* Lookup slots for source and destination process. */
85433d6423SLionel Sambuc 	if(vm_isokendpt(src_e, &src_p) != OK) {
86433d6423SLionel Sambuc 		printf("do_rs_update: bad src endpoint %d\n", src_e);
87433d6423SLionel Sambuc 		return EINVAL;
88433d6423SLionel Sambuc 	}
89433d6423SLionel Sambuc 	src_vmp = &vmproc[src_p];
90433d6423SLionel Sambuc 	if(vm_isokendpt(dst_e, &dst_p) != OK) {
91433d6423SLionel Sambuc 		printf("do_rs_update: bad dst endpoint %d\n", dst_e);
92433d6423SLionel Sambuc 		return EINVAL;
93433d6423SLionel Sambuc 	}
94433d6423SLionel Sambuc 	dst_vmp = &vmproc[dst_p];
95433d6423SLionel Sambuc 
9663483e02SCristiano Giuffrida 	/* Check flags. */
9763483e02SCristiano Giuffrida 	if((sys_upd_flags & (SF_VM_ROLLBACK|SF_VM_NOMMAP)) == 0) {
9863483e02SCristiano Giuffrida 	        /* Can't preallocate when transfering mmapped regions. */
9963483e02SCristiano Giuffrida 	        if(map_region_lookup_type(dst_vmp, VR_PREALLOC_MAP)) {
10063483e02SCristiano Giuffrida 			return ENOSYS;
10163483e02SCristiano Giuffrida 	        }
10263483e02SCristiano Giuffrida 	}
10363483e02SCristiano Giuffrida 
104433d6423SLionel Sambuc 	/* Let the kernel do the update first. */
105a1760b57SCristiano Giuffrida 	r = sys_update(src_e, dst_e,
106a1760b57SCristiano Giuffrida 	    sys_upd_flags & SF_VM_ROLLBACK ? SYS_UPD_ROLLBACK : 0);
107433d6423SLionel Sambuc 	if(r != OK) {
108433d6423SLionel Sambuc 		return r;
109433d6423SLionel Sambuc 	}
110433d6423SLionel Sambuc 
111433d6423SLionel Sambuc 	/* Do the update in VM now. */
112433d6423SLionel Sambuc 	r = swap_proc_slot(src_vmp, dst_vmp);
113433d6423SLionel Sambuc 	if(r != OK) {
114433d6423SLionel Sambuc 		return r;
115433d6423SLionel Sambuc 	}
11663483e02SCristiano Giuffrida 	r = swap_proc_dyn_data(src_vmp, dst_vmp, sys_upd_flags);
117433d6423SLionel Sambuc 	if(r != OK) {
118433d6423SLionel Sambuc 		return r;
119433d6423SLionel Sambuc 	}
120433d6423SLionel Sambuc 	pt_bind(&src_vmp->vm_pt, src_vmp);
121433d6423SLionel Sambuc 	pt_bind(&dst_vmp->vm_pt, dst_vmp);
122433d6423SLionel Sambuc 
12363483e02SCristiano Giuffrida 	/* Reply in case of external request, update-aware. */
12463483e02SCristiano Giuffrida 	if(reply_e != VM_PROC_NR) {
125433d6423SLionel Sambuc             if(reply_e == src_e) reply_e = dst_e;
126433d6423SLionel Sambuc             else if(reply_e == dst_e) reply_e = src_e;
127433d6423SLionel Sambuc             m_ptr->m_type = OK;
128433d6423SLionel Sambuc             r = ipc_send(reply_e, m_ptr);
129433d6423SLionel Sambuc             if(r != OK) {
130433d6423SLionel Sambuc                     panic("ipc_send() error");
131433d6423SLionel Sambuc             }
13263483e02SCristiano Giuffrida 	}
133433d6423SLionel Sambuc 
134433d6423SLionel Sambuc 	return SUSPEND;
135433d6423SLionel Sambuc }
136433d6423SLionel Sambuc 
137433d6423SLionel Sambuc /*===========================================================================*
138433d6423SLionel Sambuc  *		           rs_memctl_make_vm_instance			     *
139433d6423SLionel Sambuc  *===========================================================================*/
140433d6423SLionel Sambuc static int rs_memctl_make_vm_instance(struct vmproc *new_vm_vmp)
141433d6423SLionel Sambuc {
142433d6423SLionel Sambuc 	int r;
143433d6423SLionel Sambuc 	u32_t flags;
144433d6423SLionel Sambuc 	int verify;
145433d6423SLionel Sambuc 	struct vmproc *this_vm_vmp;
146433d6423SLionel Sambuc 
147433d6423SLionel Sambuc 	this_vm_vmp = &vmproc[VM_PROC_NR];
148433d6423SLionel Sambuc 
14963483e02SCristiano Giuffrida 	/* Check if the operation is allowed. */
15063483e02SCristiano Giuffrida 	assert(num_vm_instances == 1 || num_vm_instances == 2);
15163483e02SCristiano Giuffrida 	if(num_vm_instances == 2) {
15263483e02SCristiano Giuffrida 		printf("VM can currently support no more than 2 VM instances at the time.");
15363483e02SCristiano Giuffrida 		return EPERM;
15463483e02SCristiano Giuffrida 	}
15563483e02SCristiano Giuffrida 
15663483e02SCristiano Giuffrida 	/* Copy settings from current VM. */
15763483e02SCristiano Giuffrida 	new_vm_vmp->vm_flags |= VMF_VM_INSTANCE;
15863483e02SCristiano Giuffrida 	num_vm_instances++;
15963483e02SCristiano Giuffrida 
160433d6423SLionel Sambuc 	/* Pin memory for the new VM instance. */
161433d6423SLionel Sambuc 	r = map_pin_memory(new_vm_vmp);
162433d6423SLionel Sambuc 	if(r != OK) {
163433d6423SLionel Sambuc 		return r;
164433d6423SLionel Sambuc 	}
165433d6423SLionel Sambuc 
166433d6423SLionel Sambuc 	/* Preallocate page tables for the entire address space for both
167433d6423SLionel Sambuc 	 * VM and the new VM instance.
168433d6423SLionel Sambuc 	 */
169433d6423SLionel Sambuc 	flags = 0;
170433d6423SLionel Sambuc 	verify = FALSE;
171433d6423SLionel Sambuc 	r = pt_ptalloc_in_range(&this_vm_vmp->vm_pt, 0, 0, flags, verify);
172433d6423SLionel Sambuc 	if(r != OK) {
173433d6423SLionel Sambuc 		return r;
174433d6423SLionel Sambuc 	}
175433d6423SLionel Sambuc 	r = pt_ptalloc_in_range(&new_vm_vmp->vm_pt, 0, 0, flags, verify);
176433d6423SLionel Sambuc 	if(r != OK) {
177433d6423SLionel Sambuc 		return r;
178433d6423SLionel Sambuc 	}
179433d6423SLionel Sambuc 
180433d6423SLionel Sambuc 	/* Let the new VM instance map VM's page tables and its own. */
181433d6423SLionel Sambuc 	r = pt_ptmap(this_vm_vmp, new_vm_vmp);
182433d6423SLionel Sambuc 	if(r != OK) {
183433d6423SLionel Sambuc 		return r;
184433d6423SLionel Sambuc 	}
185433d6423SLionel Sambuc 	r = pt_ptmap(new_vm_vmp, new_vm_vmp);
186433d6423SLionel Sambuc 	if(r != OK) {
187433d6423SLionel Sambuc 		return r;
188433d6423SLionel Sambuc 	}
189433d6423SLionel Sambuc 
190433d6423SLionel Sambuc 	return OK;
191433d6423SLionel Sambuc }
192433d6423SLionel Sambuc 
193433d6423SLionel Sambuc /*===========================================================================*
19448f446ecSCristiano Giuffrida  *		           rs_memctl_heap_prealloc			     *
19548f446ecSCristiano Giuffrida  *===========================================================================*/
19648f446ecSCristiano Giuffrida static int rs_memctl_heap_prealloc(struct vmproc *vmp,
19748f446ecSCristiano Giuffrida 	vir_bytes *addr, size_t *len)
19848f446ecSCristiano Giuffrida {
19948f446ecSCristiano Giuffrida 
20048f446ecSCristiano Giuffrida 	/*
20148f446ecSCristiano Giuffrida 	 * XXX: Is this still needed?
20248f446ecSCristiano Giuffrida 	 */
20348f446ecSCristiano Giuffrida 
20448f446ecSCristiano Giuffrida 	return OK;
20548f446ecSCristiano Giuffrida }
20648f446ecSCristiano Giuffrida 
20748f446ecSCristiano Giuffrida /*===========================================================================*
20848f446ecSCristiano Giuffrida  *		           rs_memctl_map_prealloc			     *
20948f446ecSCristiano Giuffrida  *===========================================================================*/
21048f446ecSCristiano Giuffrida static int rs_memctl_map_prealloc(struct vmproc *vmp,
21148f446ecSCristiano Giuffrida 	vir_bytes *addr, size_t *len)
21248f446ecSCristiano Giuffrida {
21348f446ecSCristiano Giuffrida 	struct vir_region *vr;
21463483e02SCristiano Giuffrida 	vir_bytes base, top;
21563483e02SCristiano Giuffrida 	int is_vm;
21663483e02SCristiano Giuffrida 
21748f446ecSCristiano Giuffrida 	if(*len <= 0) {
21848f446ecSCristiano Giuffrida 		return EINVAL;
21948f446ecSCristiano Giuffrida 	}
22048f446ecSCristiano Giuffrida 	*len = CLICK_CEIL(*len);
22148f446ecSCristiano Giuffrida 
22263483e02SCristiano Giuffrida 	is_vm = (vmp->vm_endpoint == VM_PROC_NR);
22363483e02SCristiano Giuffrida 	base = is_vm ? VM_OWN_MMAPBASE : VM_MMAPBASE;
22463483e02SCristiano Giuffrida 	top = is_vm ? VM_OWN_MMAPTOP : VM_MMAPTOP;
22563483e02SCristiano Giuffrida 
22663483e02SCristiano Giuffrida 	if (!(vr = map_page_region(vmp, base, top, *len,
22763483e02SCristiano Giuffrida 	    VR_ANON|VR_WRITABLE|VR_UNINITIALIZED, MF_PREALLOC,
22863483e02SCristiano Giuffrida 	    &mem_type_anon))) {
22948f446ecSCristiano Giuffrida 		return ENOMEM;
23048f446ecSCristiano Giuffrida 	}
23163483e02SCristiano Giuffrida 	vr->flags |= VR_PREALLOC_MAP;
23263483e02SCristiano Giuffrida 	*addr = vr->vaddr;
23348f446ecSCristiano Giuffrida 	return OK;
23448f446ecSCristiano Giuffrida }
23548f446ecSCristiano Giuffrida 
23648f446ecSCristiano Giuffrida /*===========================================================================*
23748f446ecSCristiano Giuffrida  *		         rs_memctl_get_prealloc_map			     *
23848f446ecSCristiano Giuffrida  *===========================================================================*/
23948f446ecSCristiano Giuffrida static int rs_memctl_get_prealloc_map(struct vmproc *vmp,
24048f446ecSCristiano Giuffrida 	vir_bytes *addr, size_t *len)
24148f446ecSCristiano Giuffrida {
24248f446ecSCristiano Giuffrida 	struct vir_region *vr;
24348f446ecSCristiano Giuffrida 
24463483e02SCristiano Giuffrida 	vr = map_region_lookup_type(vmp, VR_PREALLOC_MAP);
24548f446ecSCristiano Giuffrida 	if(!vr) {
24648f446ecSCristiano Giuffrida 		*addr = 0;
24748f446ecSCristiano Giuffrida 		*len = 0;
24848f446ecSCristiano Giuffrida 	}
24948f446ecSCristiano Giuffrida 	else {
25063483e02SCristiano Giuffrida 		*addr = vr->vaddr;
25148f446ecSCristiano Giuffrida 		*len = vr->length;
25248f446ecSCristiano Giuffrida 	}
25348f446ecSCristiano Giuffrida 	return OK;
25448f446ecSCristiano Giuffrida }
25548f446ecSCristiano Giuffrida 
25648f446ecSCristiano Giuffrida /*===========================================================================*
257433d6423SLionel Sambuc  *				do_rs_memctl	     			     *
258433d6423SLionel Sambuc  *===========================================================================*/
259433d6423SLionel Sambuc int do_rs_memctl(message *m_ptr)
260433d6423SLionel Sambuc {
261433d6423SLionel Sambuc 	endpoint_t ep;
262433d6423SLionel Sambuc 	int req, r, proc_nr;
263433d6423SLionel Sambuc 	struct vmproc *vmp;
264433d6423SLionel Sambuc 
265433d6423SLionel Sambuc 	ep = m_ptr->VM_RS_CTL_ENDPT;
266433d6423SLionel Sambuc 	req = m_ptr->VM_RS_CTL_REQ;
267433d6423SLionel Sambuc 
268433d6423SLionel Sambuc 	/* Lookup endpoint. */
269433d6423SLionel Sambuc 	if ((r = vm_isokendpt(ep, &proc_nr)) != OK) {
270433d6423SLionel Sambuc 		printf("do_rs_memctl: bad endpoint %d\n", ep);
271433d6423SLionel Sambuc 		return EINVAL;
272433d6423SLionel Sambuc 	}
273433d6423SLionel Sambuc 	vmp = &vmproc[proc_nr];
274433d6423SLionel Sambuc 
275433d6423SLionel Sambuc 	/* Process request. */
276433d6423SLionel Sambuc 	switch(req)
277433d6423SLionel Sambuc 	{
278433d6423SLionel Sambuc 	case VM_RS_MEM_PIN:
279*fb6bd596SCristiano Giuffrida 		/* Only actually pin RS memory if VM can recover from crashes (saves memory). */
280*fb6bd596SCristiano Giuffrida 		if (num_vm_instances <= 1)
281*fb6bd596SCristiano Giuffrida 			return OK;
282433d6423SLionel Sambuc 		r = map_pin_memory(vmp);
283433d6423SLionel Sambuc 		return r;
284433d6423SLionel Sambuc 	case VM_RS_MEM_MAKE_VM:
285433d6423SLionel Sambuc 		r = rs_memctl_make_vm_instance(vmp);
286433d6423SLionel Sambuc 		return r;
28748f446ecSCristiano Giuffrida 	case VM_RS_MEM_HEAP_PREALLOC:
28848f446ecSCristiano Giuffrida 		r = rs_memctl_heap_prealloc(vmp, (vir_bytes*) &m_ptr->VM_RS_CTL_ADDR, (size_t*) &m_ptr->VM_RS_CTL_LEN);
28948f446ecSCristiano Giuffrida 		return r;
29048f446ecSCristiano Giuffrida 	case VM_RS_MEM_MAP_PREALLOC:
29148f446ecSCristiano Giuffrida 		r = rs_memctl_map_prealloc(vmp, (vir_bytes*) &m_ptr->VM_RS_CTL_ADDR, (size_t*) &m_ptr->VM_RS_CTL_LEN);
29248f446ecSCristiano Giuffrida 		return r;
29348f446ecSCristiano Giuffrida 	case VM_RS_MEM_GET_PREALLOC_MAP:
29448f446ecSCristiano Giuffrida 		r = rs_memctl_get_prealloc_map(vmp, (vir_bytes*) &m_ptr->VM_RS_CTL_ADDR, (size_t*) &m_ptr->VM_RS_CTL_LEN);
29548f446ecSCristiano Giuffrida 		return r;
296433d6423SLionel Sambuc 	default:
297433d6423SLionel Sambuc 		printf("do_rs_memctl: bad request %d\n", req);
298433d6423SLionel Sambuc 		return EINVAL;
299433d6423SLionel Sambuc 	}
300433d6423SLionel Sambuc }
301433d6423SLionel Sambuc 
302