xref: /minix3/minix/kernel/system/do_vmctl.c (revision 9624407e7addfd8b88486acfe3a0e056e2b92ee3)
1433d6423SLionel Sambuc /* The kernel call implemented in this file:
2433d6423SLionel Sambuc  *   m_type:	SYS_VMCTL
3433d6423SLionel Sambuc  *
4433d6423SLionel Sambuc  * The parameters for this kernel call are:
5433d6423SLionel Sambuc  *   	SVMCTL_WHO	which process
6433d6423SLionel Sambuc  *    	SVMCTL_PARAM	set this setting (VMCTL_*)
7433d6423SLionel Sambuc  *    	SVMCTL_VALUE	to this value
8433d6423SLionel Sambuc  */
9433d6423SLionel Sambuc 
10433d6423SLionel Sambuc #include "kernel/system.h"
11433d6423SLionel Sambuc #include "kernel/vm.h"
12433d6423SLionel Sambuc #include <assert.h>
13433d6423SLionel Sambuc 
14433d6423SLionel Sambuc /*===========================================================================*
15433d6423SLionel Sambuc  *				do_vmctl				     *
16433d6423SLionel Sambuc  *===========================================================================*/
do_vmctl(struct proc * caller,message * m_ptr)17433d6423SLionel Sambuc int do_vmctl(struct proc * caller, message * m_ptr)
18433d6423SLionel Sambuc {
19433d6423SLionel Sambuc   int proc_nr;
20433d6423SLionel Sambuc   endpoint_t ep = m_ptr->SVMCTL_WHO;
21*3779ed93SDavid van Moolenbroek   struct proc *p, *rp, **rpp, *target;
22433d6423SLionel Sambuc 
23433d6423SLionel Sambuc   if(ep == SELF) { ep = caller->p_endpoint; }
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc   if(!isokendpt(ep, &proc_nr)) {
26433d6423SLionel Sambuc 	printf("do_vmctl: unexpected endpoint %d from VM\n", ep);
27433d6423SLionel Sambuc 	return EINVAL;
28433d6423SLionel Sambuc   }
29433d6423SLionel Sambuc 
30433d6423SLionel Sambuc   p = proc_addr(proc_nr);
31433d6423SLionel Sambuc 
32433d6423SLionel Sambuc   switch(m_ptr->SVMCTL_PARAM) {
33433d6423SLionel Sambuc 	case VMCTL_CLEAR_PAGEFAULT:
34433d6423SLionel Sambuc 		assert(RTS_ISSET(p,RTS_PAGEFAULT));
35433d6423SLionel Sambuc 		RTS_UNSET(p, RTS_PAGEFAULT);
36433d6423SLionel Sambuc 		return OK;
37433d6423SLionel Sambuc 	case VMCTL_MEMREQ_GET:
38*3779ed93SDavid van Moolenbroek 		/* Send VM the information about the memory request. We can
39*3779ed93SDavid van Moolenbroek 		 * not simply send the first request on the list, because IPC
40*3779ed93SDavid van Moolenbroek 		 * filters may forbid VM from getting requests for particular
41*3779ed93SDavid van Moolenbroek 		 * sources. However, IPC filters are used only in rare cases.
42*3779ed93SDavid van Moolenbroek 		 */
43*3779ed93SDavid van Moolenbroek 		for (rpp = &vmrequest; *rpp != NULL;
44*3779ed93SDavid van Moolenbroek 		    rpp = &(*rpp)->p_vmrequest.nextrequestor) {
45*3779ed93SDavid van Moolenbroek 			rp = *rpp;
46*3779ed93SDavid van Moolenbroek 
47433d6423SLionel Sambuc 			assert(RTS_ISSET(rp, RTS_VMREQUEST));
48433d6423SLionel Sambuc 
49433d6423SLionel Sambuc 			okendpt(rp->p_vmrequest.target, &proc_nr);
50433d6423SLionel Sambuc 			target = proc_addr(proc_nr);
51433d6423SLionel Sambuc 
52*3779ed93SDavid van Moolenbroek 			/* Check against IPC filters. */
53*3779ed93SDavid van Moolenbroek 			if (!allow_ipc_filtered_memreq(rp, target))
54*3779ed93SDavid van Moolenbroek 				continue;
55*3779ed93SDavid van Moolenbroek 
56433d6423SLionel Sambuc 			/* Reply with request fields. */
57*3779ed93SDavid van Moolenbroek 			if (rp->p_vmrequest.req_type != VMPTYPE_CHECK)
58*3779ed93SDavid van Moolenbroek 				panic("VMREQUEST wrong type");
59*3779ed93SDavid van Moolenbroek 
60433d6423SLionel Sambuc 			m_ptr->SVMCTL_MRG_TARGET	=
61433d6423SLionel Sambuc 				rp->p_vmrequest.target;
62433d6423SLionel Sambuc 			m_ptr->SVMCTL_MRG_ADDR		=
63433d6423SLionel Sambuc 				rp->p_vmrequest.params.check.start;
64433d6423SLionel Sambuc 			m_ptr->SVMCTL_MRG_LENGTH	=
65433d6423SLionel Sambuc 				rp->p_vmrequest.params.check.length;
66433d6423SLionel Sambuc 			m_ptr->SVMCTL_MRG_FLAG		=
67433d6423SLionel Sambuc 				rp->p_vmrequest.params.check.writeflag;
68433d6423SLionel Sambuc 			m_ptr->SVMCTL_MRG_REQUESTOR	=
69433d6423SLionel Sambuc 				(void *) rp->p_endpoint;
70433d6423SLionel Sambuc 
71433d6423SLionel Sambuc 			rp->p_vmrequest.vmresult = VMSUSPEND;
72433d6423SLionel Sambuc 
73433d6423SLionel Sambuc 			/* Remove from request chain. */
74*3779ed93SDavid van Moolenbroek 			*rpp = rp->p_vmrequest.nextrequestor;
75433d6423SLionel Sambuc 
76433d6423SLionel Sambuc 			return rp->p_vmrequest.req_type;
77*3779ed93SDavid van Moolenbroek 		}
78*3779ed93SDavid van Moolenbroek 
79*3779ed93SDavid van Moolenbroek 		return ENOENT;
80*3779ed93SDavid van Moolenbroek 
81433d6423SLionel Sambuc 	case VMCTL_MEMREQ_REPLY:
82433d6423SLionel Sambuc 		assert(RTS_ISSET(p, RTS_VMREQUEST));
83433d6423SLionel Sambuc 		assert(p->p_vmrequest.vmresult == VMSUSPEND);
84433d6423SLionel Sambuc   		okendpt(p->p_vmrequest.target, &proc_nr);
85433d6423SLionel Sambuc 		target = proc_addr(proc_nr);
86433d6423SLionel Sambuc 		p->p_vmrequest.vmresult = m_ptr->SVMCTL_VALUE;
87433d6423SLionel Sambuc 		assert(p->p_vmrequest.vmresult != VMSUSPEND);
88433d6423SLionel Sambuc 
89433d6423SLionel Sambuc 		switch(p->p_vmrequest.type) {
90433d6423SLionel Sambuc 		case VMSTYPE_KERNELCALL:
91433d6423SLionel Sambuc 			/*
92433d6423SLionel Sambuc 			 * we will have to resume execution of the kernel call
93433d6423SLionel Sambuc 			 * as soon the scheduler picks up this process again
94433d6423SLionel Sambuc 			 */
95433d6423SLionel Sambuc 			p->p_misc_flags |= MF_KCALL_RESUME;
96433d6423SLionel Sambuc 			break;
97433d6423SLionel Sambuc 		case VMSTYPE_DELIVERMSG:
98433d6423SLionel Sambuc 			assert(p->p_misc_flags & MF_DELIVERMSG);
99433d6423SLionel Sambuc 			assert(p == target);
100433d6423SLionel Sambuc 			assert(RTS_ISSET(p, RTS_VMREQUEST));
101433d6423SLionel Sambuc 			break;
102433d6423SLionel Sambuc 		case VMSTYPE_MAP:
103433d6423SLionel Sambuc 			assert(RTS_ISSET(p, RTS_VMREQUEST));
104433d6423SLionel Sambuc 			break;
105433d6423SLionel Sambuc 		default:
106433d6423SLionel Sambuc 			panic("strange request type: %d",p->p_vmrequest.type);
107433d6423SLionel Sambuc 		}
108433d6423SLionel Sambuc 
109433d6423SLionel Sambuc 		RTS_UNSET(p, RTS_VMREQUEST);
110433d6423SLionel Sambuc 		return OK;
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc 	case VMCTL_KERN_PHYSMAP:
113433d6423SLionel Sambuc 	{
114433d6423SLionel Sambuc 		int i = m_ptr->SVMCTL_VALUE;
115433d6423SLionel Sambuc 		return arch_phys_map(i,
116433d6423SLionel Sambuc 			(phys_bytes *) &m_ptr->SVMCTL_MAP_PHYS_ADDR,
117433d6423SLionel Sambuc 			(phys_bytes *) &m_ptr->SVMCTL_MAP_PHYS_LEN,
118433d6423SLionel Sambuc 			&m_ptr->SVMCTL_MAP_FLAGS);
119433d6423SLionel Sambuc 	}
120433d6423SLionel Sambuc 	case VMCTL_KERN_MAP_REPLY:
121433d6423SLionel Sambuc 	{
122433d6423SLionel Sambuc 		return arch_phys_map_reply(m_ptr->SVMCTL_VALUE,
123433d6423SLionel Sambuc 			(vir_bytes) m_ptr->SVMCTL_MAP_VIR_ADDR);
124433d6423SLionel Sambuc 	}
125433d6423SLionel Sambuc 	case VMCTL_VMINHIBIT_SET:
126433d6423SLionel Sambuc 		/* check if we must stop a process on a different CPU */
127433d6423SLionel Sambuc #if CONFIG_SMP
128433d6423SLionel Sambuc 		if (p->p_cpu != cpuid) {
129433d6423SLionel Sambuc 			smp_schedule_vminhibit(p);
130433d6423SLionel Sambuc 		} else
131433d6423SLionel Sambuc #endif
132433d6423SLionel Sambuc 			RTS_SET(p, RTS_VMINHIBIT);
133433d6423SLionel Sambuc #if CONFIG_SMP
134433d6423SLionel Sambuc 		p->p_misc_flags |= MF_FLUSH_TLB;
135433d6423SLionel Sambuc #endif
136433d6423SLionel Sambuc 		return OK;
137433d6423SLionel Sambuc 	case VMCTL_VMINHIBIT_CLEAR:
138433d6423SLionel Sambuc 		assert(RTS_ISSET(p, RTS_VMINHIBIT));
139433d6423SLionel Sambuc 		/*
140433d6423SLionel Sambuc 		 * the processes is certainly not runnable, no need to tell its
141433d6423SLionel Sambuc 		 * cpu
142433d6423SLionel Sambuc 		 */
143433d6423SLionel Sambuc 		RTS_UNSET(p, RTS_VMINHIBIT);
144433d6423SLionel Sambuc #ifdef CONFIG_SMP
145433d6423SLionel Sambuc 		if (p->p_misc_flags & MF_SENDA_VM_MISS) {
146433d6423SLionel Sambuc 			struct priv *privp;
147433d6423SLionel Sambuc 			p->p_misc_flags &= ~MF_SENDA_VM_MISS;
148433d6423SLionel Sambuc 			privp = priv(p);
149433d6423SLionel Sambuc 			try_deliver_senda(p, (asynmsg_t *) privp->s_asyntab,
150433d6423SLionel Sambuc 							privp->s_asynsize);
151433d6423SLionel Sambuc 		}
152433d6423SLionel Sambuc 		/*
153433d6423SLionel Sambuc 		 * We don't know whether kernel has the changed mapping
154433d6423SLionel Sambuc 		 * installed to access userspace memory. And if so, on what CPU.
155433d6423SLionel Sambuc 		 * More over we don't know what mapping has changed and how and
156433d6423SLionel Sambuc 		 * therefore we must invalidate all mappings we have anywhere.
157433d6423SLionel Sambuc 		 * Next time we map memory, we map it fresh.
158433d6423SLionel Sambuc 		 */
159433d6423SLionel Sambuc 		bits_fill(p->p_stale_tlb, CONFIG_MAX_CPUS);
160433d6423SLionel Sambuc #endif
161433d6423SLionel Sambuc 		return OK;
162433d6423SLionel Sambuc 	case VMCTL_CLEARMAPCACHE:
163433d6423SLionel Sambuc 		/* VM says: forget about old mappings we have cached. */
164433d6423SLionel Sambuc 		mem_clear_mapcache();
165433d6423SLionel Sambuc 		return OK;
166433d6423SLionel Sambuc 	case VMCTL_BOOTINHIBIT_CLEAR:
167433d6423SLionel Sambuc 		RTS_UNSET(p, RTS_BOOTINHIBIT);
168433d6423SLionel Sambuc 		return OK;
169433d6423SLionel Sambuc   }
170433d6423SLionel Sambuc 
171433d6423SLionel Sambuc   /* Try architecture-specific vmctls. */
172433d6423SLionel Sambuc   return arch_do_vmctl(m_ptr, p);
173433d6423SLionel Sambuc }
174