示例#1
0
文件: cpu.c 项目: m943040028/prex
int
copyinstr(const void *uaddr, void *kaddr, size_t len)
{

	if (user_area(uaddr) && user_area((u_char *)uaddr + len)) {
		strlcpy(kaddr, uaddr, len);
		return 0;
	}
	return EFAULT;
}
示例#2
0
文件: cpu.c 项目: m943040028/prex
int
copyout(const void *kaddr, void *uaddr, size_t len)
{

	if (user_area(uaddr) && user_area((u_char *)uaddr + len)) {
		memcpy(uaddr, kaddr, len);
		return 0;
	}
	return EFAULT;
}
示例#3
0
文件: vm_nommu.c 项目: AndrewD/prex
/**
 * vm_allocate - allocate zero-filled memory for specified address
 *
 * If "anywhere" argument is true, the "addr" argument will be
 * ignored.  In this case, the address of free space will be
 * found automatically.
 *
 * The allocated area has writable, user-access attribute by
 * default.  The "addr" and "size" argument will be adjusted
 * to page boundary.
 */
int
vm_allocate(task_t task, void **addr, size_t size, int anywhere)
{
	int err;
	void *uaddr;

	sched_lock();

	if (!task_valid(task)) {
		err = ESRCH;
		goto out;
	}
	if (task != cur_task() && !task_capable(CAP_MEMORY)) {
		err = EPERM;
		goto out;
	}
	if (umem_copyin(addr, &uaddr, sizeof(*addr))) {
		err = EFAULT;
		goto out;
	}
	if (anywhere == 0 && !user_area(*addr)) {
		err = EACCES;
		goto out;
	}

	err = do_allocate(task->map, &uaddr, size, anywhere);
	if (err == 0) {
		if (umem_copyout(&uaddr, addr, sizeof(uaddr)))
			err = EFAULT;
	}
 out:
	sched_unlock();
	return err;
}
示例#4
0
文件: vm_nommu.c 项目: AndrewD/prex
/*
 * Change attribute of specified virtual address.
 *
 * The "addr" argument points to a memory region previously
 * allocated through a call to vm_allocate(). The attribute
 * type can be chosen a combination of VMA_READ, VMA_WRITE.
 * Note: VMA_EXEC is not supported, yet.
 */
int
vm_attribute(task_t task, void *addr, int attr)
{
	int err;

	sched_lock();
	if (attr == 0 || attr & ~(VMA_READ | VMA_WRITE)) {
		err = EINVAL;
		goto out;
	}
	if (!task_valid(task)) {
		err = ESRCH;
		goto out;
	}
	if (task != cur_task() && !task_capable(CAP_MEMORY)) {
		err = EPERM;
		goto out;
	}
	if (!user_area(addr)) {
		err = EFAULT;
		goto out;
	}

	err = do_attribute(task->map, addr, attr);
 out:
	sched_unlock();
	return err;
}
示例#5
0
文件: vm_nommu.c 项目: AndrewD/prex
/**
 * vm_map - map another task's memory to current task.
 *
 * Note: This routine does not support mapping to the specific
 * address.
 */
int
vm_map(task_t target, void *addr, size_t size, void **alloc)
{
	int err;

	sched_lock();
	if (!task_valid(target)) {
		err = ESRCH;
		goto out;
	}
	if (target == cur_task()) {
		err = EINVAL;
		goto out;
	}
	if (!task_capable(CAP_MEMORY)) {
		err = EPERM;
		goto out;
	}
	if (!user_area(addr)) {
		err = EFAULT;
		goto out;
	}

	err = do_map(target->map, addr, size, alloc);
 out:
	sched_unlock();
	return err;
}
示例#6
0
文件: exception.c 项目: AndrewD/prex
/*
 * Install an exception handler for the current task.
 *
 * NULL can be specified as handler to remove current handler.
 * If handler is removed, all pending exceptions are discarded
 * immediately. In this case, all threads blocked in
 * exception_wait() are unblocked.
 *
 * Only one exception handler can be set per task. If the
 * previous handler exists in task, exception_setup() just
 * override that handler.
 */
int
exception_setup(void (*handler)(int))
{
	task_t self = cur_task();
	list_t head, n;
	thread_t th;

	if (handler != NULL && !user_area(handler))
		return EFAULT;

	sched_lock();
	if (self->handler && handler == NULL) {
		/*
		 * Remove existing exception handler. Do clean up
		 * job for all threads in the target task.
		 */
		head = &self->threads;
		for (n = list_first(head); n != head; n = list_next(n)) {
			/*
			 * Clear pending exceptions.
			 */
			th = list_entry(n, struct thread, task_link);
			irq_lock();
			th->excbits = 0;
			irq_unlock();

			/*
			 * If the thread is waiting for an exception,
			 * cancel it.
			 */
			if (th->slpevt == &exception_event)
				sched_unsleep(th, SLP_BREAK);
		}
	}
示例#7
0
文件: system.c 项目: AndrewD/prex
/*
 * Get system information
 */
int
sys_info(int type, void *buf)
{
    struct info_memory infomem;
    struct info_timer infotmr;
    struct info_thread infothr;
    struct info_device infodev;
    int err = 0;

    if (buf == NULL || !user_area(buf))
        return EFAULT;

    sched_lock();

    switch (type) {
    case INFO_KERNEL:
        err = umem_copyout(&infokern, buf, sizeof(infokern));
        break;

    case INFO_MEMORY:
        page_info(&infomem);
        kpage_info(&infomem);
        err = umem_copyout(&infomem, buf, sizeof(infomem));
        break;

    case INFO_THREAD:
        if (umem_copyin(buf, &infothr, sizeof(infothr))) {
            err = EFAULT;
            break;
        }
        if ((err = thread_info(&infothr)))
            break;
        infothr.cookie++;
        err = umem_copyout(&infothr, buf, sizeof(infothr));
        break;

    case INFO_DEVICE:
        if (umem_copyin(buf, &infodev, sizeof(infodev))) {
            err = EFAULT;
            break;
        }
        if ((err = device_info(&infodev)))
            break;
        infodev.cookie++;
        err = umem_copyout(&infodev, buf, sizeof(infodev));
        break;

    case INFO_TIMER:
        timer_info(&infotmr);
        err = umem_copyout(&infotmr, buf, sizeof(infotmr));
        break;

    default:
        err = EINVAL;
        break;
    }
    sched_unlock();
    return err;
}
示例#8
0
文件: msg.c 项目: uiv/Lerdu
/*
 * Send a reply message.
 *
 * The target object must be the object that we are receiving.
 * Otherwise, this function will be failed.
 */
int
msg_reply(object_t obj, void *msg, size_t size)
{
	thread_t t;
	size_t len;

	if (!user_area(msg))
		return EFAULT;

	sched_lock();

	if (!object_valid(obj) || obj != curthread->recvobj) {
		sched_unlock();
		return EINVAL;
	}
	/*
	 * Check if sender still exists
	 */
	if (curthread->sender == NULL) {
		/* Clear receive state */
		curthread->recvobj = NULL;
		sched_unlock();
		return EINVAL;
	}
	/*
	 * Copy a message to the sender's buffer.
	 */
	t = curthread->sender;
	len = MIN(size, t->msgsize);
	if (len > 0) {
		if (copyin(msg, t->msgaddr, len)) {
			sched_unlock();
			return EFAULT;
		}
	}
	/*
	 * Wakeup sender with no error.
	 */
	sched_unsleep(t, 0);
	t->receiver = NULL;

	/* Clear transmit state */
	curthread->sender = NULL;
	curthread->recvobj = NULL;

	sched_unlock();
	return 0;
}
示例#9
0
文件: msg.c 项目: AndrewD/prex
/*
 * Send a reply message.
 *
 * The target object must be an appropriate object that current
 * thread has been received from. Otherwise, this function will
 * be failed.
 *
 * Since the target object may already be deleted, we can not
 * access the data of the object within this routine.
 */
int
msg_reply(object_t obj, void *msg, size_t size)
{
	thread_t th;
	size_t len;
	int err = 0;

	if (!user_area(msg))
		return EFAULT;

	sched_lock();

	if (!object_valid(obj) || obj != cur_thread->recvobj) {
		sched_unlock();
		return EINVAL;
	}
	/*
	 * Check if sender still exists
	 */
	if (cur_thread->sender == NULL) {
		err = EINVAL;
		goto out;
	}
	/*
	 * Copy message to the sender's buffer.
	 */
	th = cur_thread->sender;
	len = min(size, th->msgsize);
	if (len > 0) {
		if (umem_copyin(msg, th->msgaddr, len)) {
			sched_unlock();
			return EFAULT;
		}
	}
	/*
	 * Wakeup sender with no error.
	 */
	sched_unsleep(th, 0);
	th->receiver = NULL;
 out:
	/* Clear transmit state */
	cur_thread->sender = NULL;
	cur_thread->recvobj = NULL;

	sched_unlock();
	return err;
}
示例#10
0
/*
 * Install an exception handler for the current task.
 *
 * EXC_DFL can be specified as handler to remove the current handler.
 * If handler is removed, all pending exceptions are discarded
 * immediately. At this time, all threads blocked in exception_wait()
 * are automatically unblocked.
 *
 * We allow only one exception handler per task. If the handler
 * has already been set in task, exception_setup() just override
 * the previous handler.
 */
int
exception_setup(void (*handler)(int))
{
	task_t self = curtask;
	list_t head, n;
	thread_t t;
	int s;

	if (handler != EXC_DFL && !user_area(handler))
		return EFAULT;
	if (handler == NULL)
		return EINVAL;

	sched_lock();
	if (self->handler != EXC_DFL && handler == EXC_DFL) {
		/*
		 * Remove existing exception handler. Do clean up
		 * job for all threads in the target task.
		 */
		head = &self->threads;
		for (n = list_first(head); n != head; n = list_next(n)) {

			/*
			 * Clear pending exceptions.
			 */
			s = splhigh();
			t = list_entry(n, struct thread, task_link);
			t->excbits = 0;
			splx(s);

			/*
			 * If the thread is waiting for an exception,
			 * cancel it.
			 */
			if (t->slpevt == &exception_event) {
				DPRINTF(("Exception cancelled task=%s\n",
					 self->name));
				sched_unsleep(t, SLP_BREAK);
			}
		}
	}
示例#11
0
文件: vm_nommu.c 项目: AndrewD/prex
/*
 * Deallocate memory region for specified address.
 *
 * The "addr" argument points to a memory region previously
 * allocated through a call to vm_allocate() or vm_map(). The
 * number of bytes freed is the number of bytes of the
 * allocated region.  If one of the region of previous and
 * next are free, it combines with them, and larger free
 * region is created.
 */
int
vm_free(task_t task, void *addr)
{
	int err;

	sched_lock();
	if (!task_valid(task)) {
		err = ESRCH;
		goto out;
	}
	if (task != cur_task() && !task_capable(CAP_MEMORY)) {
		err = EPERM;
		goto out;
	}
	if (!user_area(addr)) {
		err = EFAULT;
		goto out;
	}

	err = do_free(task->map, addr);
 out:
	sched_unlock();
	return err;
}
示例#12
0
文件: msg.c 项目: uiv/Lerdu
/*
 * Send a message.
 *
 * The current thread will be blocked until any other thread
 * receives and reply the message.  A thread can send a
 * message to any object if it knows the object id.
 */
int
msg_send(object_t obj, void *msg, size_t size)
{
	struct msg_header *hdr;
	thread_t t;
	void *kmsg;
	int rc;

	if (!user_area(msg))
		return EFAULT;

	if (size < sizeof(struct msg_header))
		return EINVAL;

	sched_lock();

	if (!object_valid(obj)) {
		sched_unlock();
		return EINVAL;
	}
	/*
	 * A thread can not send a message when it is
	 * already receiving from the target object.
	 * It will obviously cause a deadlock.
	 */
	if (obj == curthread->recvobj) {
		sched_unlock();
		return EDEADLK;
	}
	/*
	 * Translate message address to the kernel linear
	 * address.  So that a receiver thread can access
	 * the message via kernel pointer. We can catch
	 * the page fault here.
	 */
	if ((kmsg = kmem_map(msg, size)) == NULL) {
		sched_unlock();
		return EFAULT;
	}
	curthread->msgaddr = kmsg;
	curthread->msgsize = size;

	/*
	 * The sender ID is filled in the message header
	 * by the kernel. So, the receiver can trust it.
	 */
	hdr = (struct msg_header *)kmsg;
	hdr->task = curtask;

	/*
	 * If receiver already exists, wake it up.
	 * The highest priority thread can get the message.
	 */
	if (!queue_empty(&obj->recvq)) {
		t = msg_dequeue(&obj->recvq);
		sched_unsleep(t, 0);
	}
	/*
	 * Sleep until we get a reply message.
	 * Note: Do not touch any data in the object
	 * structure after we wakeup. This is because the
	 * target object may be deleted while we are sleeping.
	 */
	curthread->sendobj = obj;
	msg_enqueue(&obj->sendq, curthread);
	rc = sched_sleep(&ipc_event);
	if (rc == SLP_INTR)
		queue_remove(&curthread->ipc_link);
	curthread->sendobj = NULL;

	sched_unlock();

	/*
	 * Check sleep result.
	 */
	switch (rc) {
	case SLP_BREAK:
		return EAGAIN;	/* Receiver has been terminated */
	case SLP_INVAL:
		return EINVAL;	/* Object has been deleted */
	case SLP_INTR:
		return EINTR;	/* Exception */
	default:
		/* DO NOTHING */
		break;
	}
	return 0;
}
示例#13
0
文件: msg.c 项目: uiv/Lerdu
/*
 * Receive a message.
 *
 * A thread can receive a message from the object which was
 * created by any thread belongs to same task. If the message
 * has not reached yet, it blocks until any message comes in.
 *
 * The size argument specifies the "maximum" size of the message
 * buffer to receive. If the sent message is larger than this
 * size, the kernel will automatically clip the message to this
 * maximum buffer size.
 *
 * When a message is received, the sender thread is removed from
 * object's send queue. So, another thread can receive the
 * subsequent message from that object. This is important for
 * the multi-thread server which must receive multiple messages
 * simultaneously.
 */
int
msg_receive(object_t obj, void *msg, size_t size)
{
	thread_t t;
	size_t len;
	int rc, error = 0;

	if (!user_area(msg))
		return EFAULT;

	sched_lock();

	if (!object_valid(obj)) {
		sched_unlock();
		return EINVAL;
	}
	if (obj->owner != curtask) {
		sched_unlock();
		return EACCES;
	}
	/*
	 * Check if this thread finished previous receive
	 * operation.  A thread can not receive different
	 * messages at once.
	 */
	if (curthread->recvobj) {
		sched_unlock();
		return EBUSY;
	}
	curthread->recvobj = obj;

	/*
	 * If no message exists, wait until message arrives.
	 */
	while (queue_empty(&obj->sendq)) {
		/*
		 * Block until someone sends a message.
		 */
		msg_enqueue(&obj->recvq, curthread);
		rc = sched_sleep(&ipc_event);
		if (rc != 0) {
			/*
			 * Receive is failed due to some reasons.
			 */
			switch (rc) {
			case SLP_INVAL:
				error = EINVAL;	/* Object has been deleted */
				break;
			case SLP_INTR:
				queue_remove(&curthread->ipc_link);
				error = EINTR;	/* Got exception */
				break;
			default:
				panic("msg_receive");
				break;
			}
			curthread->recvobj = NULL;
			sched_unlock();
			return error;
		}

		/*
		 * Check the existence of the sender thread again.
		 * Even if this thread is woken by the sender thread,
		 * the message may be received by another thread.
		 * This may happen when another high priority thread
		 * becomes runnable before we receive the message.
		 */
	}

	t = msg_dequeue(&obj->sendq);

	/*
	 * Copy out the message to the user-space.
	 */
	len = MIN(size, t->msgsize);
	if (len > 0) {
		if (copyout(t->msgaddr, msg, len)) {
			msg_enqueue(&obj->sendq, t);
			curthread->recvobj = NULL;
			sched_unlock();
			return EFAULT;
		}
	}
	/*
	 * Detach the message from the target object.
	 */
	curthread->sender = t;
	t->receiver = curthread;

	sched_unlock();
	return error;
}
示例#14
0
文件: msg.c 项目: AndrewD/prex
/*
 * Send a message.
 *
 * The current thread will be blocked until any other thread
 * receives the message and calls msg_reply() for the target
 * object. When new message has been reached to the object, it
 * will be received by highest priority thread waiting for
 * that message. A thread can send a message to any object if
 * it knows the object id.
 */
int
msg_send(object_t obj, void *msg, size_t size, u_long timeout)
{
	struct msg_header *hdr;
	thread_t th;
	void *kmsg;
	int rc;

	if (!user_area(msg))
		return EFAULT;

	if (size < sizeof(struct msg_header))
		return EINVAL;

	sched_lock();

	if (!object_valid(obj)) {
		sched_unlock();
		return EINVAL;
	}
	if (obj->owner != cur_task() && !task_capable(CAP_IPC)) {
		sched_unlock();
		return EPERM;
	}
	/*
	 * A thread can not send a message when the
	 * thread is already receiving from the target
	 * object. This will obviously cause a deadlock.
	 */
	if (obj == cur_thread->recvobj) {
		sched_unlock();
		return EDEADLK;
	}
	/*
	 * Translate message address to the kernel linear
	 * address.  So that a receiver thread can access
	 * the message via kernel pointer. We can catch
	 * the page fault here.
	 */
	if ((kmsg = kmem_map(msg, size)) == NULL) {
		/* Error - no physical address for the message */
		sched_unlock();
		return EFAULT;
	}
	/*
	 * The sender ID in the message header is filled
	 * by the kernel. So, the receiver can trust it.
	 */
	hdr = (struct msg_header *)kmsg;
	hdr->task = cur_task();

	/* Save information about the message block. */
	cur_thread->msgaddr = kmsg;
	cur_thread->msgsize = size;

	/*
	 * If receiver already exists, wake it up.
	 * Highest priority thread will get this message.
	 */
	if (!queue_empty(&obj->recvq)) {
		th = msg_dequeue(&obj->recvq);
		sched_unsleep(th, 0);
	}
	/*
	 * Sleep until we get a reply message.
	 * Note: Do not touch any data in the object
	 * structure after we wakeup. This is because the
	 * target object may be deleted during we were
	 * sleeping.
	 */
	cur_thread->sendobj = obj;
	msg_enqueue(&obj->sendq, cur_thread);
	rc = sched_tsleep(&ipc_event, timeout);
	if (rc == SLP_INTR)
		queue_remove(&cur_thread->ipc_link);
	cur_thread->sendobj = NULL;

	sched_unlock();

	/*
	 * Check sleep result.
	 */
	switch (rc) {
	case SLP_BREAK:
		return EAGAIN;	/* Receiver has been terminated */
	case SLP_INVAL:
		return EINVAL;	/* Object has been deleted */
	case SLP_INTR:
		return EINTR;	/* Exception */
	case SLP_TIMEOUT:
		return ETIMEDOUT;	/* Timeout */
	default:
		/* DO NOTHING */
		break;
	}
	return 0;
}
示例#15
0
文件: msg.c 项目: AndrewD/prex
/*
 * Receive a message.
 *
 * A thread can receive a message from the object which was
 * created by any thread belongs to same task. If the message
 * has not arrived yet, it blocks until any message comes in.
 *
 * The size argument specifies the "maximum" size of the message
 * buffer to receive. If the sent message is larger than this
 * size, the kernel will automatically clip the message to the
 * receive buffer size.
 *
 * When message is received, the sender thread is removed from
 * object's send queue. So, another thread can receive the
 * subsequent message from that object. This is important for
 * the multi-thread server which receives some messages
 * simultaneously.
 */
int
msg_receive(object_t obj, void *msg, size_t size, u_long timeout)
{
	thread_t th;
	size_t len;
	int rc, err = 0;

	if (!user_area(msg))
		return EFAULT;

	sched_lock();

	if (!object_valid(obj)) {
		err = EINVAL;
		goto out;
	}
	if (obj->owner != cur_task()) {
		err = EACCES;
		goto out;
	}
	/*
	 * Check if this thread finished previous receive
	 * operation.  A thread can not receive different
	 * messages at once.
	 */
	if (cur_thread->recvobj) {
		err = EBUSY;
		goto out;
	}
	cur_thread->recvobj = obj;

	/*
	 * If no message exists, wait until message arrives.
	 */
	while (queue_empty(&obj->sendq)) {
		/*
		 * Block until someone sends the message.
		 */
		msg_enqueue(&obj->recvq, cur_thread);
		rc = sched_tsleep(&ipc_event, timeout);
		if (rc != 0) {
			/*
			 * Receive is failed due to some reasons.
			 */
			switch (rc) {
			case SLP_INVAL:
				err = EINVAL;	/* Object has been deleted */
				break;
			case SLP_INTR:
				queue_remove(&cur_thread->ipc_link);
				err = EINTR;	/* Got exception */
				break;
			case SLP_TIMEOUT:
				err = ETIMEDOUT;	/* Timeout */
				break;
			default:
				panic("msg_receive");
				break;
			}
			cur_thread->recvobj = NULL;
			goto out;
		}

		/*
		 * Even if this thread is woken by the sender thread,
		 * the message may be received by another thread
		 * before this thread runs. This can occur when
		 * higher priority thread becomes runnable at that
		 * time. So, it is necessary to check the existence
		 * of the sender, again.
		 */
	}

	th = msg_dequeue(&obj->sendq);

	/*
	 * Copy out the message to the user-space.
	 * The smaller buffer size is used as copy length
	 * between sender and receiver thread.
	 */
	len = min(size, th->msgsize);
	if (len > 0) {
		if (umem_copyout(th->msgaddr, msg, len)) {
			msg_enqueue(&obj->sendq, th);
			cur_thread->recvobj = NULL;
			err = EFAULT;
			goto out;
		}
	}
	/*
	 * Detach the message from the target object.
	 */
	cur_thread->sender = th;
	th->receiver = cur_thread;
 out:
	sched_unlock();
	return err;
}