Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 1287 → Rev 1288

//kernel/trunk/generic/include/proc/thread.h
91,6 → 91,12
timeout_t sleep_timeout; /**< Timeout used for timeoutable sleeping. */
volatile int timeout_pending; /**< Flag signalling sleep timeout in progress. */
 
/** True if this thread is executing copy_from_uspace(). False otherwise. */
bool in_copy_from_uspace;
/** True if this thread is executing copy_to_uspace(). False otherwise. */
bool in_copy_to_uspace;
 
 
fpu_context_t *saved_fpu_context;
int fpu_context_exists;
 
//kernel/trunk/generic/include/interrupt.h
31,6 → 31,7
 
#include <arch/interrupt.h>
#include <typedefs.h>
#include <arch/types.h>
 
#ifndef IVT_ITEMS
# define IVT_ITEMS 0
//kernel/trunk/generic/include/mm/page.h
60,17 → 60,6
 
#define PAGE_GLOBAL (1<<PAGE_GLOBAL_SHIFT)
 
/* TODO - check that userspace is OK, platform specific functions etc */
static inline void copy_to_uspace(void *dst, void *src, count_t cnt)
{
memcpy(dst, src, cnt);
}
 
static inline void copy_from_uspace(void *dst, void *src, count_t cnt)
{
memcpy(dst, src, cnt);
}
 
/** Operations to manipulate page mappings. */
struct page_mapping_operations {
void (* mapping_insert)(as_t *as, __address page, __address frame, int flags);
//kernel/trunk/generic/include/mm/as.h
63,6 → 63,10
#define AS_AREA_ATTR_NONE 0
#define AS_AREA_ATTR_PARTIAL 1 /* Not fully initialized area. */
 
#define AS_PF_FAULT 0 /**< The page fault was not resolved by asp_page_fault(). */
#define AS_PF_OK 1 /**< The page fault was resolved by as_page_fault(). */
#define AS_PF_DEFER 2 /**< The page fault was caused by memcpy_from_uspace(). */
 
/** Address space area structure.
*
* Each as_area_t structure describes one contiguous area of virtual memory.
121,7 → 125,7
extern __address as_area_resize(as_t *as, __address address, size_t size, int flags);
int as_area_send(task_id_t dst_id, __address base);
extern void as_set_mapping(as_t *as, __address page, __address frame);
extern int as_page_fault(__address page);
extern int as_page_fault(__address page, istate_t *istate);
extern void as_switch(as_t *old, as_t *new);
extern void as_free(as_t *as);
 
//kernel/trunk/generic/include/syscall/copy.h
0,0 → 1,49
/*
* Copyright (C) 2006 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
#ifndef __COPY_H__
#define __COPY_H__
 
#include <typedefs.h>
 
/** Label within memcpy_from_uspace() that contains return -1. */
extern char memcpy_from_uspace_failover_address;
 
/** Label within memcpy_to_uspace() that contains return -1. */
extern char memcpy_to_uspace_failover_address;
 
extern int copy_from_uspace(void *dst, void *uspace_src, size_t size);
extern int copy_to_uspace(void *dst_uspace, void *src, size_t size);
 
/*
* This interface must be implemented by each architecture.
*/
extern int memcpy_from_uspace(void *dst, void *uspace_src, size_t size);
extern int memcpy_to_uspace(void *uspace_dst, void *src, size_t size);
 
#endif
//kernel/trunk/generic/src/synch/waitq.c
30,7 → 30,7
* @file waitq.c
* @brief Wait queue.
*
* Wait queue is the basic synchronization primitive upon all
* Wait queue is the basic synchronization primitive upon which all
* other synchronization primitives build.
*
* It allows threads to wait for an event in first-come, first-served
//kernel/trunk/generic/src/smp/ipi.c
43,10 → 43,10
*
* @param ipi Message to broadcast.
*
* @bugs The decision whether to actually send the IPI must be based
* on a different criterion. The current version has
* problems when some of the detected CPUs are marked
* disabled in machine configuration.
* @bug The decision whether to actually send the IPI must be based
* on a different criterion. The current version has
* problems when some of the detected CPUs are marked
* disabled in machine configuration.
*/
void ipi_broadcast(int ipi)
{
//kernel/trunk/generic/src/ddi/ddi.c
40,9 → 40,9
#include <proc/task.h>
#include <security/cap.h>
#include <mm/frame.h>
#include <mm/page.h>
#include <mm/as.h>
#include <synch/spinlock.h>
#include <syscall/copy.h>
#include <arch.h>
#include <align.h>
#include <errno.h>
183,8 → 183,12
__native sys_physmem_map(ddi_memarg_t *uspace_mem_arg)
{
ddi_memarg_t arg;
int rc;
copy_from_uspace(&arg, uspace_mem_arg, sizeof(ddi_memarg_t));
rc = copy_from_uspace(&arg, uspace_mem_arg, sizeof(ddi_memarg_t));
if (rc != 0)
return (__native) rc;
return (__native) ddi_physmem_map((task_id_t) arg.task_id, ALIGN_DOWN((__address) arg.phys_base, FRAME_SIZE),
ALIGN_DOWN((__address) arg.virt_base, PAGE_SIZE), (count_t) arg.pages,
(bool) arg.writable);
199,7 → 203,11
__native sys_iospace_enable(ddi_ioarg_t *uspace_io_arg)
{
ddi_ioarg_t arg;
int rc;
copy_from_uspace(&arg, uspace_io_arg, sizeof(ddi_ioarg_t));
rc = copy_from_uspace(&arg, uspace_io_arg, sizeof(ddi_ioarg_t));
if (rc != 0)
return (__native) rc;
return (__native) ddi_iospace_enable((task_id_t) arg.task_id, (__address) arg.ioaddr, (size_t) arg.size);
}
//kernel/trunk/generic/src/printf/vsnprintf.c
39,9 → 39,9
int vsnprintf_write(const char *str, size_t count, struct vsnprintf_data *data);
 
/** Write string to given buffer.
* Write at most data->size characters including trailing zero. According to C99 has snprintf to return number
* Write at most data->size characters including trailing zero. According to C99, snprintf() has to return number
* of characters that would have been written if enough space had been available. Hence the return value is not
* number of really printed characters but size of input string. Number of really used characters
* number of really printed characters but size of the input string. Number of really used characters
* is stored in data->len.
* @param str source string to print
* @param count size of source string
90,5 → 90,3
/* vsnprintf_write ensures that str will be terminated by zero. */
return printf_core(fmt, &ps, ap);
}
 
 
//kernel/trunk/generic/src/proc/task.c
48,8 → 48,8
#include <memstr.h>
#include <print.h>
#include <elf.h>
#include <syscall/copy.h>
 
 
#ifndef LOADED_PROG_STACK_PAGES_NO
#define LOADED_PROG_STACK_PAGES_NO 1
#endif
170,7 → 170,7
*
* @param uspace_task_id Userspace address of 8-byte buffer where to store current task ID.
*
* @return Always returns 0.
* @return 0 on success or an error code from @ref errno.h.
*/
__native sys_task_get_id(task_id_t *uspace_task_id)
{
178,9 → 178,7
* No need to acquire lock on TASK because taskid
* remains constant for the lifespan of the task.
*/
copy_to_uspace(uspace_task_id, &TASK->taskid, sizeof(TASK->taskid));
 
return 0;
return (__native) copy_to_uspace(uspace_task_id, &TASK->taskid, sizeof(TASK->taskid));
}
 
/** Find task structure corresponding to task ID.
//kernel/trunk/generic/src/proc/thread.c
60,6 → 60,8
#include <mm/slab.h>
#include <debug.h>
#include <main/uinit.h>
#include <syscall/copy.h>
#include <errno.h>
 
char *thread_states[] = {"Invalid", "Running", "Sleeping", "Ready", "Entering", "Exiting"}; /**< Thread states */
 
303,6 → 305,9
timeout_initialize(&t->sleep_timeout);
t->sleep_queue = NULL;
t->timeout_pending = 0;
 
t->in_copy_from_uspace = false;
t->in_copy_to_uspace = false;
t->rwlock_holder_type = RWLOCK_NONE;
462,11 → 467,18
char namebuf[THREAD_NAME_BUFLEN];
uspace_arg_t *kernel_uarg;
__u32 tid;
int rc;
 
copy_from_uspace(namebuf, uspace_name, THREAD_NAME_BUFLEN);
rc = copy_from_uspace(namebuf, uspace_name, THREAD_NAME_BUFLEN);
if (rc != 0)
return (__native) rc;
 
kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
copy_from_uspace(kernel_uarg, uspace_uarg, sizeof(uspace_arg_t));
rc = copy_from_uspace(kernel_uarg, uspace_uarg, sizeof(uspace_arg_t));
if (rc != 0) {
free(kernel_uarg);
return (__native) rc;
}
 
if ((t = thread_create(uinit, kernel_uarg, TASK, 0, namebuf))) {
tid = t->tid;
476,7 → 488,7
free(kernel_uarg);
}
 
return (__native) -1;
return (__native) ENOMEM;
}
 
/** Process syscall to terminate thread.
//kernel/trunk/generic/src/mm/slab.c
175,7 → 175,7
fsize = (PAGE_SIZE << cache->order);
slab = data + fsize - sizeof(*slab);
}
/* Fill in slab structures */
for (i=0; i < (1 << cache->order); i++)
frame_set_parent(pfn+i, slab, zone);
277,8 → 277,8
if (list_empty(&cache->partial_slabs)) {
/* Allow recursion and reclaiming
* - this should work, as the slab control structures
* are small and do not need to allocte with anything
* other ten frame_alloc when they are allocating,
* are small and do not need to allocate with anything
* other than frame_alloc when they are allocating,
* that's why we should get recursion at most 1-level deep
*/
spinlock_unlock(&cache->slablock);
879,7 → 879,7
int idx;
 
ASSERT(_slab_initialized);
ASSERT( size && size <= (1 << SLAB_MAX_MALLOC_W));
ASSERT(size && size <= (1 << SLAB_MAX_MALLOC_W));
if (size < (1 << SLAB_MIN_MALLOC_W))
size = (1 << SLAB_MIN_MALLOC_W);
889,7 → 889,6
return slab_alloc(malloc_caches[idx], flags);
}
 
 
void free(void *obj)
{
slab_t *slab;
//kernel/trunk/generic/src/mm/as.c
57,6 → 57,7
#include <adt/list.h>
#include <adt/btree.h>
#include <proc/task.h>
#include <proc/thread.h>
#include <arch/asm.h>
#include <panic.h>
#include <debug.h>
68,6 → 69,8
#include <config.h>
#include <arch/types.h>
#include <typedefs.h>
#include <syscall/copy.h>
#include <arch/interrupt.h>
 
as_operations_t *as_operations = NULL;
 
477,10 → 480,11
* Interrupts are assumed disabled.
*
* @param page Faulting page.
* @param istate Pointer to interrupted state.
*
* @return 0 on page fault, 1 on success.
* @return 0 on page fault, 1 on success or 2 if the fault was caused by copy_to_uspace() or copy_from_uspace().
*/
int as_page_fault(__address page)
int as_page_fault(__address page, istate_t *istate)
{
pte_t *pte;
as_area_t *area;
496,7 → 500,7
* Signal page fault to low-level handler.
*/
spinlock_unlock(&AS->lock);
return 0;
goto page_fault;
}
 
if (area->attributes & AS_AREA_ATTR_PARTIAL) {
506,7 → 510,7
*/
spinlock_unlock(&area->lock);
spinlock_unlock(&AS->lock);
return 0;
goto page_fault;
}
 
ASSERT(!(area->flags & AS_AREA_DEVICE));
554,7 → 558,23
spinlock_unlock(&area->lock);
spinlock_unlock(&AS->lock);
return 1;
return AS_PF_OK;
 
page_fault:
if (!THREAD)
return AS_PF_FAULT;
if (THREAD->in_copy_from_uspace) {
THREAD->in_copy_from_uspace = false;
istate_set_retaddr(istate, (__address) &memcpy_from_uspace_failover_address);
} else if (THREAD->in_copy_to_uspace) {
THREAD->in_copy_to_uspace = false;
istate_set_retaddr(istate, (__address) &memcpy_to_uspace_failover_address);
} else {
return AS_PF_FAULT;
}
 
return AS_PF_DEFER;
}
 
/** Switch address spaces.
884,8 → 904,11
__native sys_as_area_accept(as_area_acptsnd_arg_t *uspace_accept_arg)
{
as_area_acptsnd_arg_t arg;
int rc;
copy_from_uspace(&arg, uspace_accept_arg, sizeof(as_area_acptsnd_arg_t));
rc = copy_from_uspace(&arg, uspace_accept_arg, sizeof(as_area_acptsnd_arg_t));
if (rc != 0)
return rc;
if (!arg.size)
return (__native) EPERM;
906,8 → 929,11
__native sys_as_area_send(as_area_acptsnd_arg_t *uspace_send_arg)
{
as_area_acptsnd_arg_t arg;
int rc;
copy_from_uspace(&arg, uspace_send_arg, sizeof(as_area_acptsnd_arg_t));
rc = copy_from_uspace(&arg, uspace_send_arg, sizeof(as_area_acptsnd_arg_t));
if (rc != 0)
return rc;
 
if (!arg.size)
return (__native) EPERM;
//kernel/trunk/generic/src/syscall/copy.c
0,0 → 1,125
/*
* Copyright (C) 2006 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
/**
* @file copy.c
* @brief Copying between kernel and userspace.
*
* This file contains sanitized functions for copying data
* between kernel and userspace.
*/
 
#include <syscall/copy.h>
#include <proc/thread.h>
#include <mm/as.h>
#include <macros.h>
#include <arch.h>
#include <errno.h>
#include <typedefs.h>
 
/** Copy data from userspace to kernel.
*
* Provisions are made to return value even after page fault.
*
* This function can be called only from syscall.
*
* @param dst Destination kernel address.
* @param uspace_src Source userspace address.
* @param size Size of the data to be copied.
*
* @return 0 on success or error code from @ref errno.h.
*/
int copy_from_uspace(void *dst, void *uspace_src, size_t size)
{
ipl_t ipl;
int rc;
ASSERT(THREAD);
ASSERT(!THREAD->in_copy_from_uspace);
if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
if (overlaps((__address) uspace_src, size,
KERNEL_ADDRESS_SPACE_START, KERNEL_ADDRESS_SPACE_END-KERNEL_ADDRESS_SPACE_START)) {
/*
* The userspace source block conflicts with kernel address space.
*/
return EPERM;
}
}
ipl = interrupts_disable();
THREAD->in_copy_from_uspace = true;
rc = memcpy_from_uspace(dst, uspace_src, size);
 
THREAD->in_copy_from_uspace = false;
 
interrupts_restore(ipl);
return !rc ? EPERM : 0;
}
 
/** Copy data from kernel to userspace.
*
* Provisions are made to return value even after page fault.
*
* This function can be called only from syscall.
*
* @param uspace_dst Destination userspace address.
* @param uspace_src Source kernel address.
* @param size Size of the data to be copied.
*
* @return 0 on success or error code from @ref errno.h.
*/
int copy_to_uspace(void *uspace_dst, void *src, size_t size)
{
ipl_t ipl;
int rc;
ASSERT(THREAD);
ASSERT(!THREAD->in_copy_from_uspace);
if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
if (overlaps((__address) uspace_dst, size,
KERNEL_ADDRESS_SPACE_START, KERNEL_ADDRESS_SPACE_END-KERNEL_ADDRESS_SPACE_START)) {
/*
* The userspace destination block conflicts with kernel address space.
*/
return EPERM;
}
}
ipl = interrupts_disable();
THREAD->in_copy_from_uspace = true;
rc = memcpy_to_uspace(uspace_dst, src, size);
 
THREAD->in_copy_from_uspace = false;
 
interrupts_restore(ipl);
return !rc ? EPERM : 0;
}
//kernel/trunk/generic/src/ipc/sysipc.c
28,9 → 28,8
 
#include <arch.h>
#include <proc/task.h>
 
#include <proc/thread.h>
#include <errno.h>
#include <mm/page.h>
#include <memstr.h>
#include <debug.h>
#include <ipc/ipc.h>
38,10 → 37,8
#include <ipc/irq.h>
#include <ipc/ipcrsc.h>
#include <arch/interrupt.h>
 
#include <print.h>
#include <arch.h>
#include <proc/thread.h>
#include <syscall/copy.h>
 
#define GET_CHECK_PHONE(phone,phoneid,err) { \
if (phoneid > IPC_MAX_PHONES) { err; } \
228,9 → 225,12
call_t call;
phone_t *phone;
int res;
int rc;
 
ipc_call_static_init(&call);
copy_from_uspace(&call.data.args, &question->args, sizeof(call.data.args));
rc = copy_from_uspace(&call.data.args, &question->args, sizeof(call.data.args));
if (rc != 0)
return (__native) rc;
 
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
240,7 → 240,9
} else
IPC_SET_RETVAL(call.data, res);
 
STRUCT_TO_USPACE(&reply->args, &call.data.args);
rc = STRUCT_TO_USPACE(&reply->args, &call.data.args);
if (rc != 0)
return rc;
 
return 0;
}
297,6 → 299,7
call_t *call;
phone_t *phone;
int res;
int rc;
 
if (check_call_limit())
return IPC_CALLRET_TEMPORARY;
304,7 → 307,9
GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
 
call = ipc_call_alloc(0);
copy_from_uspace(&call->data.args, &data->args, sizeof(call->data.args));
rc = copy_from_uspace(&call->data.args, &data->args, sizeof(call->data.args));
if (rc != 0)
return (__native) rc;
if (!(res=request_preprocess(call)))
ipc_call(phone, call);
else
393,6 → 398,7
call_t *call;
ipc_data_t saved_data;
int saveddata = 0;
int rc;
 
call = get_call(callid);
if (!call)
402,8 → 408,10
memcpy(&saved_data, &call->data, sizeof(call->data));
saveddata = 1;
}
copy_from_uspace(&call->data.args, &data->args,
rc = copy_from_uspace(&call->data.args, &data->args,
sizeof(call->data.args));
if (rc != 0)
return rc;
 
answer_preprocess(call, saveddata ? &saved_data : NULL);
//kernel/trunk/generic/src/ipc/irq.c
47,6 → 47,7
#include <ipc/ipc.h>
#include <ipc/irq.h>
#include <atomic.h>
#include <syscall/copy.h>
 
typedef struct {
SPINLOCK_DECLARE(lock);
120,9 → 121,14
{
irq_code_t *code;
irq_cmd_t *ucmds;
int rc;
 
code = malloc(sizeof(*code), 0);
copy_from_uspace(code, ucode, sizeof(*code));
rc = copy_from_uspace(code, ucode, sizeof(*code));
if (rc != 0) {
free(code);
return NULL;
}
if (code->cmdcount > IRQ_MAX_PROG_SIZE) {
free(code);
130,7 → 136,12
}
ucmds = code->cmds;
code->cmds = malloc(sizeof(code->cmds[0]) * (code->cmdcount), 0);
copy_from_uspace(code->cmds, ucmds, sizeof(code->cmds[0]) * (code->cmdcount));
rc = copy_from_uspace(code->cmds, ucmds, sizeof(code->cmds[0]) * (code->cmdcount));
if (rc != 0) {
free(code->cmds);
free(code);
return NULL;
}
 
return code;
}