xref: /minix3/minix/kernel/system/do_vmctl.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* The kernel call implemented in this file:
2*433d6423SLionel Sambuc  *   m_type:	SYS_VMCTL
3*433d6423SLionel Sambuc  *
4*433d6423SLionel Sambuc  * The parameters for this kernel call are:
5*433d6423SLionel Sambuc  *   	SVMCTL_WHO	which process
6*433d6423SLionel Sambuc  *    	SVMCTL_PARAM	set this setting (VMCTL_*)
7*433d6423SLionel Sambuc  *    	SVMCTL_VALUE	to this value
8*433d6423SLionel Sambuc  */
9*433d6423SLionel Sambuc 
10*433d6423SLionel Sambuc #include "kernel/system.h"
11*433d6423SLionel Sambuc #include "kernel/vm.h"
12*433d6423SLionel Sambuc #include "kernel/debug.h"
13*433d6423SLionel Sambuc #include <assert.h>
14*433d6423SLionel Sambuc #include <minix/type.h>
15*433d6423SLionel Sambuc 
16*433d6423SLionel Sambuc /*===========================================================================*
17*433d6423SLionel Sambuc  *				do_vmctl				     *
18*433d6423SLionel Sambuc  *===========================================================================*/
19*433d6423SLionel Sambuc int do_vmctl(struct proc * caller, message * m_ptr)
20*433d6423SLionel Sambuc {
21*433d6423SLionel Sambuc   int proc_nr;
22*433d6423SLionel Sambuc   endpoint_t ep = m_ptr->SVMCTL_WHO;
23*433d6423SLionel Sambuc   struct proc *p, *rp, *target;
24*433d6423SLionel Sambuc 
25*433d6423SLionel Sambuc   if(ep == SELF) { ep = caller->p_endpoint; }
26*433d6423SLionel Sambuc 
27*433d6423SLionel Sambuc   if(!isokendpt(ep, &proc_nr)) {
28*433d6423SLionel Sambuc 	printf("do_vmctl: unexpected endpoint %d from VM\n", ep);
29*433d6423SLionel Sambuc 	return EINVAL;
30*433d6423SLionel Sambuc   }
31*433d6423SLionel Sambuc 
32*433d6423SLionel Sambuc   p = proc_addr(proc_nr);
33*433d6423SLionel Sambuc 
34*433d6423SLionel Sambuc   switch(m_ptr->SVMCTL_PARAM) {
35*433d6423SLionel Sambuc 	case VMCTL_CLEAR_PAGEFAULT:
36*433d6423SLionel Sambuc 		assert(RTS_ISSET(p,RTS_PAGEFAULT));
37*433d6423SLionel Sambuc 		RTS_UNSET(p, RTS_PAGEFAULT);
38*433d6423SLionel Sambuc 		return OK;
39*433d6423SLionel Sambuc 	case VMCTL_MEMREQ_GET:
40*433d6423SLionel Sambuc 		/* Send VM the information about the memory request.  */
41*433d6423SLionel Sambuc 		if(!(rp = vmrequest))
42*433d6423SLionel Sambuc 			return ESRCH;
43*433d6423SLionel Sambuc 		assert(RTS_ISSET(rp, RTS_VMREQUEST));
44*433d6423SLionel Sambuc 
45*433d6423SLionel Sambuc 		okendpt(rp->p_vmrequest.target, &proc_nr);
46*433d6423SLionel Sambuc 		target = proc_addr(proc_nr);
47*433d6423SLionel Sambuc 
48*433d6423SLionel Sambuc 		/* Reply with request fields. */
49*433d6423SLionel Sambuc 		switch(rp->p_vmrequest.req_type) {
50*433d6423SLionel Sambuc 		case VMPTYPE_CHECK:
51*433d6423SLionel Sambuc 			m_ptr->SVMCTL_MRG_TARGET	=
52*433d6423SLionel Sambuc 				rp->p_vmrequest.target;
53*433d6423SLionel Sambuc 			m_ptr->SVMCTL_MRG_ADDR		=
54*433d6423SLionel Sambuc 				rp->p_vmrequest.params.check.start;
55*433d6423SLionel Sambuc 			m_ptr->SVMCTL_MRG_LENGTH	=
56*433d6423SLionel Sambuc 				rp->p_vmrequest.params.check.length;
57*433d6423SLionel Sambuc 			m_ptr->SVMCTL_MRG_FLAG		=
58*433d6423SLionel Sambuc 				rp->p_vmrequest.params.check.writeflag;
59*433d6423SLionel Sambuc 			m_ptr->SVMCTL_MRG_REQUESTOR	=
60*433d6423SLionel Sambuc 				(void *) rp->p_endpoint;
61*433d6423SLionel Sambuc 			break;
62*433d6423SLionel Sambuc 		default:
63*433d6423SLionel Sambuc 			panic("VMREQUEST wrong type");
64*433d6423SLionel Sambuc 		}
65*433d6423SLionel Sambuc 
66*433d6423SLionel Sambuc 		rp->p_vmrequest.vmresult = VMSUSPEND;
67*433d6423SLionel Sambuc 
68*433d6423SLionel Sambuc 		/* Remove from request chain. */
69*433d6423SLionel Sambuc 		vmrequest = vmrequest->p_vmrequest.nextrequestor;
70*433d6423SLionel Sambuc 
71*433d6423SLionel Sambuc 		return rp->p_vmrequest.req_type;
72*433d6423SLionel Sambuc 	case VMCTL_MEMREQ_REPLY:
73*433d6423SLionel Sambuc 		assert(RTS_ISSET(p, RTS_VMREQUEST));
74*433d6423SLionel Sambuc 		assert(p->p_vmrequest.vmresult == VMSUSPEND);
75*433d6423SLionel Sambuc   		okendpt(p->p_vmrequest.target, &proc_nr);
76*433d6423SLionel Sambuc 		target = proc_addr(proc_nr);
77*433d6423SLionel Sambuc 		p->p_vmrequest.vmresult = m_ptr->SVMCTL_VALUE;
78*433d6423SLionel Sambuc 		assert(p->p_vmrequest.vmresult != VMSUSPEND);
79*433d6423SLionel Sambuc 
80*433d6423SLionel Sambuc 		switch(p->p_vmrequest.type) {
81*433d6423SLionel Sambuc 		case VMSTYPE_KERNELCALL:
82*433d6423SLionel Sambuc 			/*
83*433d6423SLionel Sambuc 			 * we will have to resume execution of the kernel call
84*433d6423SLionel Sambuc 			 * as soon the scheduler picks up this process again
85*433d6423SLionel Sambuc 			 */
86*433d6423SLionel Sambuc 			p->p_misc_flags |= MF_KCALL_RESUME;
87*433d6423SLionel Sambuc 			break;
88*433d6423SLionel Sambuc 		case VMSTYPE_DELIVERMSG:
89*433d6423SLionel Sambuc 			assert(p->p_misc_flags & MF_DELIVERMSG);
90*433d6423SLionel Sambuc 			assert(p == target);
91*433d6423SLionel Sambuc 			assert(RTS_ISSET(p, RTS_VMREQUEST));
92*433d6423SLionel Sambuc 			break;
93*433d6423SLionel Sambuc 		case VMSTYPE_MAP:
94*433d6423SLionel Sambuc 			assert(RTS_ISSET(p, RTS_VMREQUEST));
95*433d6423SLionel Sambuc 			break;
96*433d6423SLionel Sambuc 		default:
97*433d6423SLionel Sambuc 			panic("strange request type: %d",p->p_vmrequest.type);
98*433d6423SLionel Sambuc 		}
99*433d6423SLionel Sambuc 
100*433d6423SLionel Sambuc 		RTS_UNSET(p, RTS_VMREQUEST);
101*433d6423SLionel Sambuc 		return OK;
102*433d6423SLionel Sambuc 
103*433d6423SLionel Sambuc 	case VMCTL_KERN_PHYSMAP:
104*433d6423SLionel Sambuc 	{
105*433d6423SLionel Sambuc 		int i = m_ptr->SVMCTL_VALUE;
106*433d6423SLionel Sambuc 		return arch_phys_map(i,
107*433d6423SLionel Sambuc 			(phys_bytes *) &m_ptr->SVMCTL_MAP_PHYS_ADDR,
108*433d6423SLionel Sambuc 			(phys_bytes *) &m_ptr->SVMCTL_MAP_PHYS_LEN,
109*433d6423SLionel Sambuc 			&m_ptr->SVMCTL_MAP_FLAGS);
110*433d6423SLionel Sambuc 	}
111*433d6423SLionel Sambuc 	case VMCTL_KERN_MAP_REPLY:
112*433d6423SLionel Sambuc 	{
113*433d6423SLionel Sambuc 		return arch_phys_map_reply(m_ptr->SVMCTL_VALUE,
114*433d6423SLionel Sambuc 			(vir_bytes) m_ptr->SVMCTL_MAP_VIR_ADDR);
115*433d6423SLionel Sambuc 	}
116*433d6423SLionel Sambuc 	case VMCTL_VMINHIBIT_SET:
117*433d6423SLionel Sambuc 		/* check if we must stop a process on a different CPU */
118*433d6423SLionel Sambuc #if CONFIG_SMP
119*433d6423SLionel Sambuc 		if (p->p_cpu != cpuid) {
120*433d6423SLionel Sambuc 			smp_schedule_vminhibit(p);
121*433d6423SLionel Sambuc 		} else
122*433d6423SLionel Sambuc #endif
123*433d6423SLionel Sambuc 			RTS_SET(p, RTS_VMINHIBIT);
124*433d6423SLionel Sambuc #if CONFIG_SMP
125*433d6423SLionel Sambuc 		p->p_misc_flags |= MF_FLUSH_TLB;
126*433d6423SLionel Sambuc #endif
127*433d6423SLionel Sambuc 		return OK;
128*433d6423SLionel Sambuc 	case VMCTL_VMINHIBIT_CLEAR:
129*433d6423SLionel Sambuc 		assert(RTS_ISSET(p, RTS_VMINHIBIT));
130*433d6423SLionel Sambuc 		/*
131*433d6423SLionel Sambuc 		 * the processes is certainly not runnable, no need to tell its
132*433d6423SLionel Sambuc 		 * cpu
133*433d6423SLionel Sambuc 		 */
134*433d6423SLionel Sambuc 		RTS_UNSET(p, RTS_VMINHIBIT);
135*433d6423SLionel Sambuc #ifdef CONFIG_SMP
136*433d6423SLionel Sambuc 		if (p->p_misc_flags & MF_SENDA_VM_MISS) {
137*433d6423SLionel Sambuc 			struct priv *privp;
138*433d6423SLionel Sambuc 			p->p_misc_flags &= ~MF_SENDA_VM_MISS;
139*433d6423SLionel Sambuc 			privp = priv(p);
140*433d6423SLionel Sambuc 			try_deliver_senda(p, (asynmsg_t *) privp->s_asyntab,
141*433d6423SLionel Sambuc 							privp->s_asynsize);
142*433d6423SLionel Sambuc 		}
143*433d6423SLionel Sambuc 		/*
144*433d6423SLionel Sambuc 		 * We don't know whether kernel has the changed mapping
145*433d6423SLionel Sambuc 		 * installed to access userspace memory. And if so, on what CPU.
146*433d6423SLionel Sambuc 		 * More over we don't know what mapping has changed and how and
147*433d6423SLionel Sambuc 		 * therefore we must invalidate all mappings we have anywhere.
148*433d6423SLionel Sambuc 		 * Next time we map memory, we map it fresh.
149*433d6423SLionel Sambuc 		 */
150*433d6423SLionel Sambuc 		bits_fill(p->p_stale_tlb, CONFIG_MAX_CPUS);
151*433d6423SLionel Sambuc #endif
152*433d6423SLionel Sambuc 		return OK;
153*433d6423SLionel Sambuc 	case VMCTL_CLEARMAPCACHE:
154*433d6423SLionel Sambuc 		/* VM says: forget about old mappings we have cached. */
155*433d6423SLionel Sambuc 		mem_clear_mapcache();
156*433d6423SLionel Sambuc 		return OK;
157*433d6423SLionel Sambuc 	case VMCTL_BOOTINHIBIT_CLEAR:
158*433d6423SLionel Sambuc 		RTS_UNSET(p, RTS_BOOTINHIBIT);
159*433d6423SLionel Sambuc 		return OK;
160*433d6423SLionel Sambuc   }
161*433d6423SLionel Sambuc 
162*433d6423SLionel Sambuc   /* Try architecture-specific vmctls. */
163*433d6423SLionel Sambuc   return arch_do_vmctl(m_ptr, p);
164*433d6423SLionel Sambuc }
165