165 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			165 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* The kernel call implemented in this file:
 | 
						|
 *   m_type:	SYS_VMCTL
 | 
						|
 *
 | 
						|
 * The parameters for this kernel call are:
 | 
						|
 *   	SVMCTL_WHO	which process
 | 
						|
 *    	SVMCTL_PARAM	set this setting (VMCTL_*)
 | 
						|
 *    	SVMCTL_VALUE	to this value
 | 
						|
 */
 | 
						|
 | 
						|
#include "kernel/system.h"
 | 
						|
#include "kernel/vm.h"
 | 
						|
#include "kernel/debug.h"
 | 
						|
#include <assert.h>
 | 
						|
#include <minix/type.h>
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				do_vmctl				     *
 | 
						|
 *===========================================================================*/
 | 
						|
int do_vmctl(struct proc * caller, message * m_ptr)
 | 
						|
{
 | 
						|
  int proc_nr;
 | 
						|
  endpoint_t ep = m_ptr->SVMCTL_WHO;
 | 
						|
  struct proc *p, *rp, *target;
 | 
						|
 | 
						|
  if(ep == SELF) { ep = caller->p_endpoint; }
 | 
						|
 | 
						|
  if(!isokendpt(ep, &proc_nr)) {
 | 
						|
	printf("do_vmctl: unexpected endpoint %d from VM\n", ep);
 | 
						|
	return EINVAL;
 | 
						|
  }
 | 
						|
 | 
						|
  p = proc_addr(proc_nr);
 | 
						|
 | 
						|
  switch(m_ptr->SVMCTL_PARAM) {
 | 
						|
	case VMCTL_CLEAR_PAGEFAULT:
 | 
						|
		assert(RTS_ISSET(p,RTS_PAGEFAULT));
 | 
						|
		RTS_UNSET(p, RTS_PAGEFAULT);
 | 
						|
		return OK;
 | 
						|
	case VMCTL_MEMREQ_GET:
 | 
						|
		/* Send VM the information about the memory request.  */
 | 
						|
		if(!(rp = vmrequest))
 | 
						|
			return ESRCH;
 | 
						|
		assert(RTS_ISSET(rp, RTS_VMREQUEST));
 | 
						|
 | 
						|
		okendpt(rp->p_vmrequest.target, &proc_nr);
 | 
						|
		target = proc_addr(proc_nr);
 | 
						|
 | 
						|
		/* Reply with request fields. */
 | 
						|
		switch(rp->p_vmrequest.req_type) {
 | 
						|
		case VMPTYPE_CHECK:
 | 
						|
			m_ptr->SVMCTL_MRG_TARGET	=
 | 
						|
				rp->p_vmrequest.target;
 | 
						|
			m_ptr->SVMCTL_MRG_ADDR		=
 | 
						|
				rp->p_vmrequest.params.check.start;
 | 
						|
			m_ptr->SVMCTL_MRG_LENGTH	=
 | 
						|
				rp->p_vmrequest.params.check.length;
 | 
						|
			m_ptr->SVMCTL_MRG_FLAG		=
 | 
						|
				rp->p_vmrequest.params.check.writeflag;
 | 
						|
			m_ptr->SVMCTL_MRG_REQUESTOR	=
 | 
						|
				(void *) rp->p_endpoint;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			panic("VMREQUEST wrong type");
 | 
						|
		}
 | 
						|
 | 
						|
		rp->p_vmrequest.vmresult = VMSUSPEND;
 | 
						|
 | 
						|
		/* Remove from request chain. */
 | 
						|
		vmrequest = vmrequest->p_vmrequest.nextrequestor;
 | 
						|
 | 
						|
		return rp->p_vmrequest.req_type;
 | 
						|
	case VMCTL_MEMREQ_REPLY:
 | 
						|
		assert(RTS_ISSET(p, RTS_VMREQUEST));
 | 
						|
		assert(p->p_vmrequest.vmresult == VMSUSPEND);
 | 
						|
  		okendpt(p->p_vmrequest.target, &proc_nr);
 | 
						|
		target = proc_addr(proc_nr);
 | 
						|
		p->p_vmrequest.vmresult = m_ptr->SVMCTL_VALUE;
 | 
						|
		assert(p->p_vmrequest.vmresult != VMSUSPEND);
 | 
						|
 | 
						|
		switch(p->p_vmrequest.type) {
 | 
						|
		case VMSTYPE_KERNELCALL:
 | 
						|
			/*
 | 
						|
			 * we will have to resume execution of the kernel call
 | 
						|
			 * as soon the scheduler picks up this process again
 | 
						|
			 */
 | 
						|
			p->p_misc_flags |= MF_KCALL_RESUME;
 | 
						|
			break;
 | 
						|
		case VMSTYPE_DELIVERMSG:
 | 
						|
			assert(p->p_misc_flags & MF_DELIVERMSG);
 | 
						|
			assert(p == target);
 | 
						|
			assert(RTS_ISSET(p, RTS_VMREQUEST));
 | 
						|
			break;
 | 
						|
		case VMSTYPE_MAP:
 | 
						|
			assert(RTS_ISSET(p, RTS_VMREQUEST));
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			panic("strange request type: %d",p->p_vmrequest.type);
 | 
						|
		}
 | 
						|
 | 
						|
		RTS_UNSET(p, RTS_VMREQUEST);
 | 
						|
		return OK;
 | 
						|
 | 
						|
	case VMCTL_KERN_PHYSMAP:
 | 
						|
	{
 | 
						|
		int i = m_ptr->SVMCTL_VALUE;
 | 
						|
		return arch_phys_map(i,
 | 
						|
			(phys_bytes *) &m_ptr->SVMCTL_MAP_PHYS_ADDR,
 | 
						|
			(phys_bytes *) &m_ptr->SVMCTL_MAP_PHYS_LEN,
 | 
						|
			&m_ptr->SVMCTL_MAP_FLAGS);
 | 
						|
	}
 | 
						|
	case VMCTL_KERN_MAP_REPLY:
 | 
						|
	{
 | 
						|
		return arch_phys_map_reply(m_ptr->SVMCTL_VALUE,
 | 
						|
			(vir_bytes) m_ptr->SVMCTL_MAP_VIR_ADDR);
 | 
						|
	}
 | 
						|
	case VMCTL_VMINHIBIT_SET:
 | 
						|
		/* check if we must stop a process on a different CPU */
 | 
						|
#if CONFIG_SMP
 | 
						|
		if (p->p_cpu != cpuid) {
 | 
						|
			smp_schedule_vminhibit(p);
 | 
						|
		} else
 | 
						|
#endif
 | 
						|
			RTS_SET(p, RTS_VMINHIBIT);
 | 
						|
#if CONFIG_SMP
 | 
						|
		p->p_misc_flags |= MF_FLUSH_TLB;
 | 
						|
#endif
 | 
						|
		return OK;
 | 
						|
	case VMCTL_VMINHIBIT_CLEAR:
 | 
						|
		assert(RTS_ISSET(p, RTS_VMINHIBIT));
 | 
						|
		/*
 | 
						|
		 * the processes is certainly not runnable, no need to tell its
 | 
						|
		 * cpu
 | 
						|
		 */
 | 
						|
		RTS_UNSET(p, RTS_VMINHIBIT);
 | 
						|
#ifdef CONFIG_SMP
 | 
						|
		if (p->p_misc_flags & MF_SENDA_VM_MISS) {
 | 
						|
			struct priv *privp;
 | 
						|
			p->p_misc_flags &= ~MF_SENDA_VM_MISS;
 | 
						|
			privp = priv(p);
 | 
						|
			try_deliver_senda(p, (asynmsg_t *) privp->s_asyntab,
 | 
						|
							privp->s_asynsize);
 | 
						|
		}
 | 
						|
		/*
 | 
						|
		 * We don't know whether kernel has the changed mapping
 | 
						|
		 * installed to access userspace memory. And if so, on what CPU.
 | 
						|
		 * More over we don't know what mapping has changed and how and
 | 
						|
		 * therefore we must invalidate all mappings we have anywhere.
 | 
						|
		 * Next time we map memory, we map it fresh.
 | 
						|
		 */
 | 
						|
		bits_fill(p->p_stale_tlb, CONFIG_MAX_CPUS);
 | 
						|
#endif
 | 
						|
		return OK;
 | 
						|
	case VMCTL_CLEARMAPCACHE:
 | 
						|
		/* VM says: forget about old mappings we have cached. */
 | 
						|
		mem_clear_mapcache();
 | 
						|
		return OK;
 | 
						|
	case VMCTL_BOOTINHIBIT_CLEAR:
 | 
						|
		RTS_UNSET(p, RTS_BOOTINHIBIT);
 | 
						|
		return OK;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Try architecture-specific vmctls. */
 | 
						|
  return arch_do_vmctl(m_ptr, p);
 | 
						|
}
 |