Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3447 → Rev 3448

/branches/dynload/kernel/kernel.config
144,6 → 144,8
# Virtually indexed D-cache support
! [ARCH=sparc64] CONFIG_VIRT_IDX_DCACHE (y/n)
 
# Support for userspace debuggers
! CONFIG_UDEBUG (n/y)
 
## Debugging configuration directives
 
/branches/dynload/kernel/generic/include/proc/task.h
52,6 → 52,7
#include <arch/cpu.h>
#include <mm/tlb.h>
#include <proc/scheduler.h>
#include <udebug/udebug.h>
 
struct thread;
 
93,6 → 94,20
* certain extent.
*/
atomic_t active_calls;
 
#ifdef CONFIG_UDEBUG
/** Debugging stuff */
udebug_task_t udebug;
 
/** Kernel answerbox */
answerbox_t kernel_box;
/** Thread used to service kernel answerbox */
struct thread *kb_thread;
/** Kbox thread creation vs. begin of cleanup mutual exclusion */
mutex_t kb_cleanup_lock;
/** True if cleanup of kbox has already started */
bool kb_finished;
#endif
/** Architecture specific task data. */
task_arch_t arch;
/branches/dynload/kernel/generic/include/proc/thread.h
46,6 → 46,7
#include <arch/cpu.h>
#include <mm/tlb.h>
#include <proc/uarg.h>
#include <udebug/udebug.h>
 
#define THREAD_STACK_SIZE STACK_SIZE
#define THREAD_NAME_BUFLEN 20
203,6 → 204,12
 
/** Thread's kernel stack. */
uint8_t *kstack;
 
#ifdef CONFIG_UDEBUG
/** Debugging stuff */
udebug_thread_t udebug;
#endif
 
} thread_t;
 
/** Thread list lock.
/branches/dynload/kernel/generic/include/udebug/udebug.h
0,0 → 1,218
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup generic
* @{
*/
/** @file
*/
 
#ifndef KERN_UDEBUG_H_
#define KERN_UDEBUG_H_
 
#include <ipc/ipc.h>
 
typedef enum { /* udebug_method_t */
 
/** Start debugging the recipient.
* Causes all threads in the receiving task to stop. When they
* are all stoped, an answer with retval 0 is generated.
*/
UDEBUG_M_BEGIN = 1,
 
/** Finish debugging the recipient.
* Answers all pending GO and GUARD messages.
*/
UDEBUG_M_END,
 
/** Set which events should be captured.
*/
UDEBUG_M_SET_EVMASK,
 
/** Make sure the debugged task is still there.
* This message is answered when the debugged task dies
* or the debugging session ends.
*/
UDEBUG_M_GUARD,
 
/** Run a thread until a debugging event occurs.
* This message is answered when the thread stops
* in a debugging event.
*
* - ARG2 - id of the thread to run
*/
UDEBUG_M_GO,
 
/** Stop a thread being debugged.
* Creates a special STOP event in the thread, causing
* it to answer a pending GO message (if any).
*/
UDEBUG_M_STOP,
 
/** Read arguments of a syscall.
*
* - ARG2 - thread identification
* - ARG3 - destination address in the caller's address space
*
*/
UDEBUG_M_ARGS_READ,
 
/** Read the list of the debugged tasks's threads.
*
* - ARG2 - destination address in the caller's address space
* - ARG3 - size of receiving buffer in bytes
*
* The kernel fills the buffer with a series of sysarg_t values
* (thread ids). On answer, the kernel will set:
*
* - ARG2 - number of bytes that were actually copied
* - ARG3 - number of bytes of the complete data
*
*/
UDEBUG_M_THREAD_READ,
 
/** Read the debugged tasks's memory.
*
* - ARG2 - destination address in the caller's address space
* - ARG3 - source address in the recipient's address space
* - ARG4 - size of receiving buffer in bytes
*
*/
UDEBUG_M_MEM_READ,
 
} udebug_method_t;
 
typedef enum {
UDEBUG_EVENT_FINISHED = 1, /**< Debuging session has finished */
UDEBUG_EVENT_STOP, /**< Stopped on DEBUG_STOP request */
UDEBUG_EVENT_SYSCALL_B, /**< Before beginning syscall execution */
UDEBUG_EVENT_SYSCALL_E, /**< After finishing syscall execution */
UDEBUG_EVENT_THREAD_B, /**< The task created a new thread */
UDEBUG_EVENT_THREAD_E /**< A thread exited */
} udebug_event_t;
 
#define UDEBUG_EVMASK(event) (1 << ((event) - 1))
 
typedef enum {
UDEBUG_EM_FINISHED = UDEBUG_EVMASK(UDEBUG_EVENT_FINISHED),
UDEBUG_EM_STOP = UDEBUG_EVMASK(UDEBUG_EVENT_STOP),
UDEBUG_EM_SYSCALL_B = UDEBUG_EVMASK(UDEBUG_EVENT_SYSCALL_B),
UDEBUG_EM_SYSCALL_E = UDEBUG_EVMASK(UDEBUG_EVENT_SYSCALL_E),
UDEBUG_EM_THREAD_B = UDEBUG_EVMASK(UDEBUG_EVENT_THREAD_B),
UDEBUG_EM_THREAD_E = UDEBUG_EVMASK(UDEBUG_EVENT_THREAD_E),
UDEBUG_EM_ALL =
UDEBUG_EVMASK(UDEBUG_EVENT_FINISHED) |
UDEBUG_EVMASK(UDEBUG_EVENT_STOP) |
UDEBUG_EVMASK(UDEBUG_EVENT_SYSCALL_B) |
UDEBUG_EVMASK(UDEBUG_EVENT_SYSCALL_E) |
UDEBUG_EVMASK(UDEBUG_EVENT_THREAD_B) |
UDEBUG_EVMASK(UDEBUG_EVENT_THREAD_E)
} udebug_evmask_t;
 
#ifdef KERNEL
 
#include <synch/mutex.h>
#include <arch/interrupt.h>
#include <atomic.h>
 
typedef enum {
/** Task is not being debugged */
UDEBUG_TS_INACTIVE,
/** BEGIN operation in progress (waiting for threads to stop) */
UDEBUG_TS_BEGINNING,
/** Debugger fully connected */
UDEBUG_TS_ACTIVE,
/** Task is shutting down, no more debug activities allowed */
UDEBUG_TS_SHUTDOWN
} udebug_task_state_t;
 
/** Debugging part of task_t structure.
*/
typedef struct {
/** Synchronize debug ops on this task / access to this structure */
mutex_t lock;
char *lock_owner;
 
udebug_task_state_t dt_state;
call_t *begin_call;
int not_stoppable_count;
struct task *debugger;
udebug_evmask_t evmask;
} udebug_task_t;
 
/** Debugging part of thread_t structure.
*/
typedef struct {
/**
* Prevent deadlock with udebug_before_thread_runs() in interrupt
* handler, without actually disabling interrupts.
* ==0 means "unlocked", >0 means "locked"
*/
atomic_t int_lock;
 
/** Synchronize debug ops on this thread / access to this structure */
mutex_t lock;
 
waitq_t go_wq;
call_t *go_call;
unative_t syscall_args[6];
 
/** What type of event are we stopped in or 0 if none */
udebug_event_t cur_event;
bool stop;
bool stoppable;
bool debug_active; /**< In a debugging session */
} udebug_thread_t;
 
struct task;
struct thread;
 
void udebug_task_init(udebug_task_t *ut);
void udebug_thread_initialize(udebug_thread_t *ut);
 
void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc,
bool end_variant);
 
void udebug_thread_b_event(struct thread *t);
void udebug_thread_e_event(void);
 
void udebug_stoppable_begin(void);
void udebug_stoppable_end(void);
 
void udebug_before_thread_runs(void);
 
int udebug_task_cleanup(struct task *ta);
 
#endif
 
#endif
 
/** @}
*/
/branches/dynload/kernel/generic/include/udebug/udebug_ops.h
0,0 → 1,55
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup generic
* @{
*/
/** @file
*/
 
#ifndef KERN_UDEBUG_OPS_H_
#define KERN_UDEBUG_OPS_H_
 
#include <ipc/ipc.h>
 
int udebug_begin(call_t *call);
int udebug_end(void);
int udebug_set_evmask(udebug_evmask_t mask);
 
int udebug_go(thread_t *t, call_t *call);
int udebug_stop(thread_t *t, call_t *call);
 
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n);
int udebug_args_read(thread_t *t, void **buffer);
 
int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer);
 
#endif
 
/** @}
*/
/branches/dynload/kernel/generic/include/udebug/udebug_ipc.h
0,0 → 1,47
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup generic
* @{
*/
/** @file
*/
 
#ifndef KERN_UDEBUG_IPC_H_
#define KERN_UDEBUG_IPC_H_
 
#include <ipc/ipc.h>
 
int udebug_request_preprocess(call_t *call, phone_t *phone);
void udebug_call_receive(call_t *call);
 
 
#endif
 
/** @}
*/
/branches/dynload/kernel/generic/include/syscall/syscall.h
79,7 → 79,7
 
SYS_DEBUG_PUTINT,
SYS_DEBUG_ENABLE_CONSOLE,
 
SYS_IPC_CONNECT_KBOX,
SYSCALL_END
} syscall_t;
 
/branches/dynload/kernel/generic/include/ipc/sysipc.h
57,6 → 57,7
unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method,
irq_code_t *ucode);
unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno);
unative_t sys_ipc_connect_kbox(sysarg64_t *task_id);
 
#endif
 
/branches/dynload/kernel/generic/include/ipc/ipc.h
195,6 → 195,12
*/
#define IPC_M_DATA_READ 7
 
/** Debug the recipient.
* - ARG1 - specifies the debug method (from udebug_method_t)
* - other arguments are specific to the debug method
*/
#define IPC_M_DEBUG_ALL 8
 
/* Well-known methods */
#define IPC_M_LAST_SYSTEM 511
#define IPC_M_PING 512
307,6 → 313,8
extern int ipc_phone_hangup(phone_t *);
extern void ipc_backsend_err(phone_t *, call_t *, unative_t);
extern void ipc_print_task(task_id_t);
extern void ipc_answerbox_slam_phones(answerbox_t *, bool);
extern void ipc_cleanup_call_list(link_t *);
 
extern answerbox_t *ipc_phone_0;
 
/branches/dynload/kernel/generic/include/ipc/kbox.h
0,0 → 1,46
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup genericipc
* @{
*/
/** @file
*/
 
#ifndef KERN_IPC_KBOX_H_
#define KERN_IPC_KBOX_H_
 
#include <typedefs.h>
 
extern int ipc_connect_kbox(task_id_t);
extern void ipc_kbox_cleanup(void);
 
#endif
 
/** @}
*/
/branches/dynload/kernel/generic/src/main/uinit.c
46,7 → 46,9
#include <userspace.h>
#include <mm/slab.h>
#include <arch.h>
#include <udebug/udebug.h>
 
 
/** Thread used to bring up userspace thread.
*
* @param arg Pointer to structure containing userspace entry and stack
65,6 → 67,10
* deployed for the event of forceful task termination.
*/
thread_detach(THREAD);
 
#ifdef CONFIG_UDEBUG
udebug_stoppable_end();
#endif
uarg.uspace_entry = ((uspace_arg_t *) arg)->uspace_entry;
uarg.uspace_stack = ((uspace_arg_t *) arg)->uspace_stack;
/branches/dynload/kernel/generic/src/proc/task.c
155,7 → 155,18
 
ta->capabilities = 0;
ta->cycles = 0;
 
#ifdef CONFIG_UDEBUG
/* Init debugging stuff */
udebug_task_init(&ta->udebug);
 
/* Init kbox stuff */
ipc_answerbox_init(&ta->kernel_box, ta);
ta->kb_thread = NULL;
mutex_initialize(&ta->kb_cleanup_lock, MUTEX_PASSIVE);
ta->kb_finished = false;
#endif
 
ipc_answerbox_init(&ta->answerbox, ta);
for (i = 0; i < IPC_MAX_PHONES; i++)
ipc_phone_init(&ta->phones[i]);
/branches/dynload/kernel/generic/src/proc/thread.c
180,6 → 180,10
return -1;
}
 
#ifdef CONFIG_UDEBUG
mutex_initialize(&t->udebug.lock, MUTEX_PASSIVE);
#endif
 
return 0;
}
 
347,6 → 351,11
avltree_node_initialize(&t->threads_tree_node);
t->threads_tree_node.key = (uintptr_t) t;
 
#ifdef CONFIG_UDEBUG
/* Init debugging stuff */
udebug_thread_initialize(&t->udebug);
#endif
 
/* might depend on previous initialization */
thread_create_arch(t);
 
409,12 → 418,17
ipl_t ipl;
 
/*
* Attach to the current task.
* Attach to the specified task.
*/
ipl = interrupts_disable();
spinlock_lock(&task->lock);
 
atomic_inc(&task->refcount);
atomic_inc(&task->lifecount);
 
/* Must not count kbox thread into lifecount */
if (t->flags & THREAD_FLAG_USPACE)
atomic_inc(&task->lifecount);
 
list_append(&t->th_link, &task->th_head);
spinlock_unlock(&task->lock);
 
437,14 → 451,19
{
ipl_t ipl;
 
if (atomic_predec(&TASK->lifecount) == 0) {
/*
* We are the last thread in the task that still has not exited.
* With the exception of the moment the task was created, new
* threads can only be created by threads of the same task.
* We are safe to perform cleanup.
*/
if (THREAD->flags & THREAD_FLAG_USPACE) {
if (THREAD->flags & THREAD_FLAG_USPACE) {
#ifdef CONFIG_UDEBUG
/* Generate udebug THREAD_E event */
udebug_thread_e_event();
#endif
if (atomic_predec(&TASK->lifecount) == 0) {
/*
* We are the last userspace thread in the task that
* still has not exited. With the exception of the
* moment the task was created, new userspace threads
* can only be created by threads of the same task.
* We are safe to perform cleanup.
*/
ipc_cleanup();
futex_cleanup();
LOG("Cleanup of task %" PRIu64" completed.", TASK->taskid);
741,6 → 760,11
thread_attach(t, TASK);
thread_ready(t);
 
#ifdef CONFIG_UDEBUG
/* Generate udebug THREAD_B event */
udebug_thread_b_event(t);
#endif
 
return 0;
} else
free(kernel_uarg);
/branches/dynload/kernel/generic/src/mm/as.c
385,7 → 385,7
if (pages < area->pages) {
bool cond;
uintptr_t start_free = area->base + pages*PAGE_SIZE;
uintptr_t start_free = area->base + pages * PAGE_SIZE;
 
/*
* Shrinking the area.
395,7 → 395,7
/*
* Start TLB shootdown sequence.
*/
tlb_shootdown_start(TLB_INVL_PAGES, AS->asid, area->base +
tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base +
pages * PAGE_SIZE, area->pages - pages);
 
/*
/branches/dynload/kernel/generic/src/syscall/syscall.c
53,6 → 53,7
#include <syscall/copy.h>
#include <sysinfo/sysinfo.h>
#include <console/console.h>
#include <udebug/udebug.h>
 
/** Print using kernel facility
*
108,9 → 109,16
{
unative_t rc;
 
if (id < SYSCALL_END)
#ifdef CONFIG_UDEBUG
udebug_syscall_event(a1, a2, a3, a4, a5, a6, id, 0, false);
#endif
 
if (id < SYSCALL_END) {
#ifdef CONFIG_UDEBUG
udebug_stoppable_begin();
#endif
rc = syscall_table[id](a1, a2, a3, a4, a5, a6);
else {
} else {
printf("Task %" PRIu64": Unknown syscall %#" PRIxn, TASK->taskid, id);
task_kill(TASK->taskid);
thread_exit();
118,6 → 126,11
if (THREAD->interrupted)
thread_exit();
 
#ifdef CONFIG_UDEBUG
udebug_syscall_event(a1, a2, a3, a4, a5, a6, id, rc, true);
udebug_stoppable_end();
#endif
return rc;
}
173,7 → 186,9
/* Debug calls */
(syshandler_t) sys_debug_putint,
(syshandler_t) sys_debug_enable_console
(syshandler_t) sys_debug_enable_console,
 
(syshandler_t) sys_ipc_connect_kbox
};
 
/** @}
/branches/dynload/kernel/generic/src/ipc/kbox.c
0,0 → 1,220
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup genericipc
* @{
*/
/** @file
*/
 
#include <synch/synch.h>
#include <synch/spinlock.h>
#include <synch/mutex.h>
#include <ipc/ipc.h>
#include <ipc/ipcrsc.h>
#include <arch.h>
#include <errno.h>
#include <debug.h>
#include <udebug/udebug_ipc.h>
#include <ipc/kbox.h>
 
void ipc_kbox_cleanup(void)
{
bool have_kb_thread;
 
/* Only hold kb_cleanup_lock while setting kb_finished - this is enough */
mutex_lock(&TASK->kb_cleanup_lock);
TASK->kb_finished = true;
mutex_unlock(&TASK->kb_cleanup_lock);
 
have_kb_thread = (TASK->kb_thread != NULL);
 
/* From now on nobody will try to connect phones or attach kbox threads */
 
/*
* Disconnect all phones connected to our kbox. Passing true for
* notify_box causes a HANGUP message to be inserted for each
* disconnected phone. This ensures the kbox thread is going to
* wake up and terminate.
*/
ipc_answerbox_slam_phones(&TASK->kernel_box, have_kb_thread);
if (have_kb_thread) {
LOG("join kb_thread..\n");
thread_join(TASK->kb_thread);
thread_detach(TASK->kb_thread);
LOG("join done\n");
TASK->kb_thread = NULL;
}
 
/* Answer all messages in 'calls' and 'dispatched_calls' queues */
spinlock_lock(&TASK->kernel_box.lock);
ipc_cleanup_call_list(&TASK->kernel_box.dispatched_calls);
ipc_cleanup_call_list(&TASK->kernel_box.calls);
spinlock_unlock(&TASK->kernel_box.lock);
}
 
 
static void kbox_thread_proc(void *arg)
{
call_t *call;
int method;
bool done;
ipl_t ipl;
 
(void)arg;
LOG("kbox_thread_proc()\n");
done = false;
 
while (!done) {
call = ipc_wait_for_call(&TASK->kernel_box, SYNCH_NO_TIMEOUT,
SYNCH_FLAGS_NONE);
 
if (call != NULL) {
method = IPC_GET_METHOD(call->data);
 
if (method == IPC_M_DEBUG_ALL) {
udebug_call_receive(call);
}
 
if (method == IPC_M_PHONE_HUNGUP) {
LOG("kbox: handle hangup message\n");
 
/* Was it our debugger, who hung up? */
if (call->sender == TASK->udebug.debugger) {
/* Terminate debugging session (if any) */
LOG("kbox: terminate debug session\n");
ipl = interrupts_disable();
spinlock_lock(&TASK->lock);
udebug_task_cleanup(TASK);
spinlock_unlock(&TASK->lock);
interrupts_restore(ipl);
} else {
LOG("kbox: was not debugger\n");
}
 
LOG("kbox: continue with hangup message\n");
IPC_SET_RETVAL(call->data, 0);
ipc_answer(&TASK->kernel_box, call);
 
ipl = interrupts_disable();
spinlock_lock(&TASK->lock);
spinlock_lock(&TASK->answerbox.lock);
if (list_empty(&TASK->answerbox.connected_phones)) {
/* Last phone has been disconnected */
TASK->kb_thread = NULL;
done = true;
LOG("phone list is empty\n");
}
spinlock_unlock(&TASK->answerbox.lock);
spinlock_unlock(&TASK->lock);
interrupts_restore(ipl);
}
}
}
 
LOG("kbox: finished\n");
}
 
 
/**
* Connect phone to a task kernel-box specified by id.
*
* Note that this is not completely atomic. For optimisation reasons,
* The task might start cleaning up kbox after the phone has been connected
* and before a kbox thread has been created. This must be taken into account
* in the cleanup code.
*
* @return Phone id on success, or negative error code.
*/
int ipc_connect_kbox(task_id_t taskid)
{
int newphid;
task_t *ta;
thread_t *kb_thread;
ipl_t ipl;
 
ipl = interrupts_disable();
spinlock_lock(&tasks_lock);
 
ta = task_find_by_id(taskid);
if (ta == NULL) {
spinlock_unlock(&tasks_lock);
interrupts_restore(ipl);
return ENOENT;
}
 
atomic_inc(&ta->refcount);
 
spinlock_unlock(&tasks_lock);
interrupts_restore(ipl);
 
mutex_lock(&ta->kb_cleanup_lock);
 
if (atomic_predec(&ta->refcount) == 0) {
mutex_unlock(&ta->kb_cleanup_lock);
task_destroy(ta);
return ENOENT;
}
 
if (ta->kb_finished != false) {
mutex_unlock(&ta->kb_cleanup_lock);
return EINVAL;
}
 
newphid = phone_alloc();
if (newphid < 0) {
mutex_unlock(&ta->kb_cleanup_lock);
return ELIMIT;
}
 
/* Connect the newly allocated phone to the kbox */
ipc_phone_connect(&TASK->phones[newphid], &ta->kernel_box);
 
if (ta->kb_thread != NULL) {
mutex_unlock(&ta->kb_cleanup_lock);
return newphid;
}
 
/* Create a kbox thread */
kb_thread = thread_create(kbox_thread_proc, NULL, ta, 0, "kbox", false);
if (!kb_thread) {
mutex_unlock(&ta->kb_cleanup_lock);
return ENOMEM;
}
 
ta->kb_thread = kb_thread;
thread_ready(kb_thread);
 
mutex_unlock(&ta->kb_cleanup_lock);
 
return newphid;
}
 
/** @}
*/
/branches/dynload/kernel/generic/src/ipc/sysipc.c
42,8 → 42,9
#include <ipc/sysipc.h>
#include <ipc/irq.h>
#include <ipc/ipcrsc.h>
#include <ipc/kbox.h>
#include <udebug/udebug_ipc.h>
#include <arch/interrupt.h>
#include <print.h>
#include <syscall/copy.h>
#include <security/cap.h>
#include <mm/as.h>
295,10 → 296,11
/** Called before the request is sent.
*
* @param call Call structure with the request.
* @param phone Phone that the call will be sent through.
*
* @return Return 0 on success, ELIMIT or EPERM on error.
*/
static int request_preprocess(call_t *call)
static int request_preprocess(call_t *call, phone_t *phone)
{
int newphid;
size_t size;
340,6 → 342,10
return rc;
}
break;
#ifdef CONFIG_UDEBUG
case IPC_M_DEBUG_ALL:
return udebug_request_preprocess(call, phone);
#endif
default:
break;
}
369,6 → 375,7
 
if (call->buffer) {
/* This must be an affirmative answer to IPC_M_DATA_READ. */
/* or IPC_M_DEBUG_ALL/UDEBUG_M_MEM_READ... */
uintptr_t dst = IPC_GET_ARG1(call->data);
size_t size = IPC_GET_ARG2(call->data);
int rc = copy_to_uspace((void *) dst, call->buffer, size);
399,7 → 406,13
return -1;
}
IPC_SET_ARG5(call->data, phoneid);
}
}
switch (IPC_GET_METHOD(call->data)) {
case IPC_M_DEBUG_ALL:
return -1;
default:
break;
}
return 0;
}
 
441,7 → 454,7
IPC_SET_ARG4(call.data, 0);
IPC_SET_ARG5(call.data, 0);
 
if (!(res = request_preprocess(&call))) {
if (!(res = request_preprocess(&call, phone))) {
rc = ipc_call_sync(phone, &call);
if (rc != EOK)
return rc;
481,7 → 494,7
 
GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
if (!(res = request_preprocess(&call))) {
if (!(res = request_preprocess(&call, phone))) {
rc = ipc_call_sync(phone, &call);
if (rc != EOK)
return rc;
550,7 → 563,7
*/
IPC_SET_ARG5(call->data, 0);
 
if (!(res = request_preprocess(call)))
if (!(res = request_preprocess(call, phone)))
ipc_call(phone, call);
else
ipc_backsend_err(phone, call, res);
584,7 → 597,7
ipc_call_free(call);
return (unative_t) rc;
}
if (!(res = request_preprocess(call)))
if (!(res = request_preprocess(call, phone)))
ipc_call(phone, call);
else
ipc_backsend_err(phone, call, res);
868,5 → 881,30
return 0;
}
 
#include <console/console.h>
 
/**
* Syscall connect to a task by id.
*
* @return Phone id on success, or negative error code.
*/
unative_t sys_ipc_connect_kbox(sysarg64_t *uspace_taskid_arg)
{
#ifdef CONFIG_UDEBUG
sysarg64_t taskid_arg;
int rc;
rc = copy_from_uspace(&taskid_arg, uspace_taskid_arg, sizeof(sysarg64_t));
if (rc != 0)
return (unative_t) rc;
 
LOG("sys_ipc_connect_kbox(%" PRIu64 ")\n", taskid_arg.value);
 
return ipc_connect_kbox(taskid_arg.value);
#else
return (unative_t) ENOTSUP;
#endif
}
 
/** @}
*/
/branches/dynload/kernel/generic/src/ipc/ipc.c
43,6 → 43,7
#include <synch/waitq.h>
#include <synch/synch.h>
#include <ipc/ipc.h>
#include <ipc/kbox.h>
#include <errno.h>
#include <mm/slab.h>
#include <arch.h>
51,6 → 52,7
#include <debug.h>
 
#include <print.h>
#include <console/console.h>
#include <proc/thread.h>
#include <arch/interrupt.h>
#include <ipc/irq.h>
427,7 → 429,7
*
* @param lst Head of the list to be cleaned up.
*/
static void ipc_cleanup_call_list(link_t *lst)
void ipc_cleanup_call_list(link_t *lst)
{
call_t *call;
 
442,33 → 444,31
}
}
 
/** Cleans up all IPC communication of the current task.
/** Disconnects all phones connected to an answerbox.
*
* Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
* have to change it as well if you want to cleanup other tasks than TASK.
* @param box Answerbox to disconnect phones from.
* @param notify_box If true, the answerbox will get a hangup message for
* each disconnected phone.
*/
void ipc_cleanup(void)
void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box)
{
int i;
call_t *call;
phone_t *phone;
DEADLOCK_PROBE_INIT(p_phonelck);
ipl_t ipl;
call_t *call;
 
/* Disconnect all our phones ('ipc_phone_hangup') */
for (i = 0; i < IPC_MAX_PHONES; i++)
ipc_phone_hangup(&TASK->phones[i]);
call = notify_box ? ipc_call_alloc(0) : NULL;
 
/* Disconnect all connected irqs */
ipc_irq_cleanup(&TASK->answerbox);
 
/* Disconnect all phones connected to our answerbox */
restart_phones:
spinlock_lock(&TASK->answerbox.lock);
while (!list_empty(&TASK->answerbox.connected_phones)) {
phone = list_get_instance(TASK->answerbox.connected_phones.next,
ipl = interrupts_disable();
spinlock_lock(&box->lock);
while (!list_empty(&box->connected_phones)) {
phone = list_get_instance(box->connected_phones.next,
phone_t, link);
if (SYNCH_FAILED(mutex_trylock(&phone->lock))) {
spinlock_unlock(&TASK->answerbox.lock);
spinlock_unlock(&box->lock);
interrupts_restore(ipl);
DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD);
goto restart_phones;
}
475,13 → 475,69
/* Disconnect phone */
ASSERT(phone->state == IPC_PHONE_CONNECTED);
 
list_remove(&phone->link);
phone->state = IPC_PHONE_SLAMMED;
list_remove(&phone->link);
 
if (notify_box) {
mutex_unlock(&phone->lock);
spinlock_unlock(&box->lock);
interrupts_restore(ipl);
 
/*
* Send one message to the answerbox for each
* phone. Used to make sure the kbox thread
* wakes up after the last phone has been
* disconnected.
*/
IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
call->flags |= IPC_CALL_DISCARD_ANSWER;
_ipc_call(phone, box, call);
 
/* Allocate another call in advance */
call = ipc_call_alloc(0);
 
/* Must start again */
goto restart_phones;
}
 
mutex_unlock(&phone->lock);
}
 
spinlock_unlock(&box->lock);
interrupts_restore(ipl);
 
/* Free unused call */
if (call) ipc_call_free(call);
}
 
/** Cleans up all IPC communication of the current task.
*
* Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
* have to change it as well if you want to cleanup other tasks than TASK.
*/
void ipc_cleanup(void)
{
int i;
call_t *call;
 
/* Disconnect all our phones ('ipc_phone_hangup') */
for (i = 0; i < IPC_MAX_PHONES; i++)
ipc_phone_hangup(&TASK->phones[i]);
 
/* Disconnect all connected irqs */
ipc_irq_cleanup(&TASK->answerbox);
 
/* Disconnect all phones connected to our regular answerbox */
ipc_answerbox_slam_phones(&TASK->answerbox, false);
 
#ifdef CONFIG_UDEBUG
/* Clean up kbox thread and communications */
ipc_kbox_cleanup();
#endif
 
/* Answer all messages in 'calls' and 'dispatched_calls' queues */
spinlock_lock(&TASK->answerbox.lock);
ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
ipc_cleanup_call_list(&TASK->answerbox.calls);
spinlock_unlock(&TASK->answerbox.lock);
/branches/dynload/kernel/generic/src/udebug/udebug_ipc.c
0,0 → 1,294
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup generic
* @{
*/
 
/**
* @file
* @brief Udebug IPC message handling.
*/
#include <proc/task.h>
#include <proc/thread.h>
#include <arch.h>
#include <errno.h>
#include <ipc/ipc.h>
#include <syscall/copy.h>
#include <udebug/udebug.h>
#include <udebug/udebug_ops.h>
#include <udebug/udebug_ipc.h>
 
int udebug_request_preprocess(call_t *call, phone_t *phone)
{
switch (IPC_GET_ARG1(call->data)) {
/* future UDEBUG_M_REGS_WRITE, UDEBUG_M_MEM_WRITE: */
default:
break;
}
 
return 0;
}
 
static void udebug_receive_begin(call_t *call)
{
int rc;
 
rc = udebug_begin(call);
if (rc < 0) {
IPC_SET_RETVAL(call->data, rc);
ipc_answer(&TASK->kernel_box, call);
return;
}
 
if (rc != 0) {
IPC_SET_RETVAL(call->data, 0);
ipc_answer(&TASK->kernel_box, call);
}
}
 
static void udebug_receive_end(call_t *call)
{
int rc;
 
rc = udebug_end();
 
IPC_SET_RETVAL(call->data, rc);
ipc_answer(&TASK->kernel_box, call);
}
 
static void udebug_receive_set_evmask(call_t *call)
{
int rc;
udebug_evmask_t mask;
 
mask = IPC_GET_ARG2(call->data);
rc = udebug_set_evmask(mask);
 
IPC_SET_RETVAL(call->data, rc);
ipc_answer(&TASK->kernel_box, call);
}
 
 
static void udebug_receive_go(call_t *call)
{
thread_t *t;
int rc;
 
t = (thread_t *)IPC_GET_ARG2(call->data);
 
rc = udebug_go(t, call);
if (rc < 0) {
IPC_SET_RETVAL(call->data, rc);
ipc_answer(&TASK->kernel_box, call);
return;
}
}
 
static void udebug_receive_stop(call_t *call)
{
thread_t *t;
int rc;
 
t = (thread_t *)IPC_GET_ARG2(call->data);
 
rc = udebug_stop(t, call);
IPC_SET_RETVAL(call->data, rc);
ipc_answer(&TASK->kernel_box, call);
}
 
static void udebug_receive_thread_read(call_t *call)
{
unative_t uspace_addr;
unative_t to_copy;
unsigned total_bytes;
unsigned buf_size;
void *buffer;
size_t n;
int rc;
 
uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */
 
/*
* Read thread list. Variable n will be filled with actual number
* of threads times thread-id size.
*/
rc = udebug_thread_read(&buffer, buf_size, &n);
if (rc < 0) {
IPC_SET_RETVAL(call->data, rc);
ipc_answer(&TASK->kernel_box, call);
return;
}
 
total_bytes = n;
 
/* Copy MAX(buf_size, total_bytes) bytes */
 
if (buf_size > total_bytes)
to_copy = total_bytes;
else
to_copy = buf_size;
 
/*
* Make use of call->buffer to transfer data to caller's userspace
*/
 
IPC_SET_RETVAL(call->data, 0);
/* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
same code in process_answer() can be used
(no way to distinguish method in answer) */
IPC_SET_ARG1(call->data, uspace_addr);
IPC_SET_ARG2(call->data, to_copy);
 
IPC_SET_ARG3(call->data, total_bytes);
call->buffer = buffer;
 
ipc_answer(&TASK->kernel_box, call);
}
 
static void udebug_receive_args_read(call_t *call)
{
thread_t *t;
unative_t uspace_addr;
int rc;
void *buffer;
 
t = (thread_t *)IPC_GET_ARG2(call->data);
 
rc = udebug_args_read(t, &buffer);
if (rc != EOK) {
IPC_SET_RETVAL(call->data, rc);
ipc_answer(&TASK->kernel_box, call);
return;
}
 
/*
* Make use of call->buffer to transfer data to caller's userspace
*/
 
uspace_addr = IPC_GET_ARG3(call->data);
 
IPC_SET_RETVAL(call->data, 0);
/* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
same code in process_answer() can be used
(no way to distinguish method in answer) */
IPC_SET_ARG1(call->data, uspace_addr);
IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
call->buffer = buffer;
 
ipc_answer(&TASK->kernel_box, call);
}
 
static void udebug_receive_mem_read(call_t *call)
{
unative_t uspace_dst;
unative_t uspace_src;
unsigned size;
void *buffer;
int rc;
 
uspace_dst = IPC_GET_ARG2(call->data);
uspace_src = IPC_GET_ARG3(call->data);
size = IPC_GET_ARG4(call->data);
 
rc = udebug_mem_read(uspace_src, size, &buffer);
if (rc < 0) {
IPC_SET_RETVAL(call->data, rc);
ipc_answer(&TASK->kernel_box, call);
return;
}
 
IPC_SET_RETVAL(call->data, 0);
/* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
same code in process_answer() can be used
(no way to distinguish method in answer) */
IPC_SET_ARG1(call->data, uspace_dst);
IPC_SET_ARG2(call->data, size);
call->buffer = buffer;
 
ipc_answer(&TASK->kernel_box, call);
}
 
/**
* Handle a debug call received on the kernel answerbox.
*
* This is called by the kbox servicing thread.
*/
void udebug_call_receive(call_t *call)
{
int debug_method;
 
debug_method = IPC_GET_ARG1(call->data);
 
if (debug_method != UDEBUG_M_BEGIN) {
/*
* Verify that the sender is this task's debugger.
* Note that this is the only thread that could change
* TASK->debugger. Therefore no locking is necessary
* and the sender can be safely considered valid until
* control exits this function.
*/
if (TASK->udebug.debugger != call->sender) {
IPC_SET_RETVAL(call->data, EINVAL);
ipc_answer(&TASK->kernel_box, call);
return;
}
}
 
switch (debug_method) {
case UDEBUG_M_BEGIN:
udebug_receive_begin(call);
break;
case UDEBUG_M_END:
udebug_receive_end(call);
break;
case UDEBUG_M_SET_EVMASK:
udebug_receive_set_evmask(call);
break;
case UDEBUG_M_GO:
udebug_receive_go(call);
break;
case UDEBUG_M_STOP:
udebug_receive_stop(call);
break;
case UDEBUG_M_THREAD_READ:
udebug_receive_thread_read(call);
break;
case UDEBUG_M_ARGS_READ:
udebug_receive_args_read(call);
break;
case UDEBUG_M_MEM_READ:
udebug_receive_mem_read(call);
break;
}
}
 
/** @}
*/
/branches/dynload/kernel/generic/src/udebug/udebug.c
0,0 → 1,502
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup generic
* @{
*/
 
/**
* @file
* @brief Udebug.
*
* Functions in this file are executed directly in each thread, which
* may or may not be the subject of debugging. The udebug_stoppable_begin/end()
* functions are also executed in the clock interrupt handler. To avoid
* deadlock, functions in this file are protected from the interrupt
* by locking the recursive lock THREAD->udebug.int_lock (just an atomic
* variable). This prevents udebug_stoppable_begin/end() from being
* executed in the interrupt handler (they are skipped).
*
* Functions in udebug_ops.c and udebug_ipc.c execute in different threads,
* so they needn't be protected from the (preemptible) interrupt-initiated
* code.
*/
#include <synch/waitq.h>
#include <debug.h>
#include <udebug/udebug.h>
#include <errno.h>
#include <arch.h>
 
static inline void udebug_int_lock(void)
{
atomic_inc(&THREAD->udebug.int_lock);
}
 
static inline void udebug_int_unlock(void)
{
atomic_dec(&THREAD->udebug.int_lock);
}
 
void udebug_task_init(udebug_task_t *ut)
{
mutex_initialize(&ut->lock, MUTEX_PASSIVE);
ut->dt_state = UDEBUG_TS_INACTIVE;
ut->begin_call = NULL;
ut->not_stoppable_count = 0;
ut->evmask = 0;
}
 
void udebug_thread_initialize(udebug_thread_t *ut)
{
mutex_initialize(&ut->lock, MUTEX_PASSIVE);
waitq_initialize(&ut->go_wq);
 
/*
* At the beginning the thread is stoppable, so int_lock be set, too.
*/
atomic_set(&ut->int_lock, 1);
 
ut->go_call = NULL;
ut->stop = true;
ut->stoppable = true;
ut->debug_active = false;
ut->cur_event = 0; /* none */
}
 
static void udebug_wait_for_go(waitq_t *wq)
{
int rc;
ipl_t ipl;
 
ipl = waitq_sleep_prepare(wq);
 
wq->missed_wakeups = 0; /* Enforce blocking. */
rc = waitq_sleep_timeout_unsafe(wq, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
 
waitq_sleep_finish(wq, rc, ipl);
}
 
/** Do a preliminary check that a debugging session is in progress.
*
* This only requires the THREAD->udebug.lock mutex (and not
* TASK->udebug.lock mutex). For an undebugged task, this will
* never block (while there could be collisions by different threads
* on the TASK mutex), thus improving SMP perormance for undebugged tasks.
*/
static bool udebug_thread_precheck(void)
{
bool res;
 
mutex_lock(&THREAD->udebug.lock);
res = THREAD->udebug.debug_active;
mutex_unlock(&THREAD->udebug.lock);
 
return res;
}
 
void udebug_stoppable_begin(void)
{
int nsc;
call_t *db_call, *go_call;
 
ASSERT(THREAD);
ASSERT(TASK);
 
udebug_int_lock();
 
/* Early check for undebugged tasks */
if (!udebug_thread_precheck()) {
udebug_int_unlock();
return;
}
 
mutex_lock(&TASK->udebug.lock);
 
nsc = --TASK->udebug.not_stoppable_count;
 
/* Lock order OK, THREAD->udebug.lock is after TASK->udebug.lock */
mutex_lock(&THREAD->udebug.lock);
ASSERT(THREAD->udebug.stoppable == false);
THREAD->udebug.stoppable = true;
 
if (TASK->udebug.dt_state == UDEBUG_TS_BEGINNING && nsc == 0) {
/*
* This was the last non-stoppable thread. Reply to
* DEBUG_BEGIN call.
*/
 
db_call = TASK->udebug.begin_call;
ASSERT(db_call);
 
TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
TASK->udebug.begin_call = NULL;
 
IPC_SET_RETVAL(db_call->data, 0);
ipc_answer(&TASK->answerbox, db_call);
 
} else if (TASK->udebug.dt_state == UDEBUG_TS_ACTIVE) {
/*
* Active debugging session
*/
 
if (THREAD->udebug.debug_active && THREAD->udebug.stop) {
/*
* Thread was requested to stop - answer go call
*/
 
/* Make sure nobody takes this call away from us */
go_call = THREAD->udebug.go_call;
THREAD->udebug.go_call = NULL;
ASSERT(go_call);
 
IPC_SET_RETVAL(go_call->data, 0);
IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP);
 
THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
 
ipc_answer(&TASK->answerbox, go_call);
}
}
 
mutex_unlock(&THREAD->udebug.lock);
mutex_unlock(&TASK->udebug.lock);
}
 
void udebug_stoppable_end(void)
{
/* Early check for undebugged tasks */
if (!udebug_thread_precheck()) {
udebug_int_unlock();
return;
}
 
restart:
mutex_lock(&TASK->udebug.lock);
mutex_lock(&THREAD->udebug.lock);
 
if (THREAD->udebug.debug_active &&
THREAD->udebug.stop == true) {
TASK->udebug.begin_call = NULL;
mutex_unlock(&THREAD->udebug.lock);
mutex_unlock(&TASK->udebug.lock);
 
udebug_wait_for_go(&THREAD->udebug.go_wq);
 
goto restart;
/* must try again - have to lose stoppability atomically */
} else {
++TASK->udebug.not_stoppable_count;
ASSERT(THREAD->udebug.stoppable == true);
THREAD->udebug.stoppable = false;
 
mutex_unlock(&THREAD->udebug.lock);
mutex_unlock(&TASK->udebug.lock);
}
 
udebug_int_unlock();
}
 
/** Upon being scheduled to run, check if the current thread should stop.
*
* This function is called from clock(). Preemption is enabled.
* interrupts are disabled, but since this is called after
* being scheduled-in, we can enable them, if we're careful enough
* not to allow arbitrary recursion or deadlock with the thread context.
*/
void udebug_before_thread_runs(void)
{
ipl_t ipl;
 
return;
ASSERT(!PREEMPTION_DISABLED);
 
/*
* Prevent agains re-entering, such as when preempted inside this
* function.
*/
if (atomic_get(&THREAD->udebug.int_lock) != 0)
return;
 
udebug_int_lock();
 
ipl = interrupts_enable();
 
/* Now we're free to do whatever we need (lock mutexes, sleep, etc.) */
 
/* Check if we're supposed to stop */
udebug_stoppable_begin();
udebug_stoppable_end();
 
interrupts_restore(ipl);
 
udebug_int_unlock();
}
 
void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc,
bool end_variant)
{
call_t *call;
udebug_event_t etype;
 
etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B;
 
udebug_int_lock();
 
/* Early check for undebugged tasks */
if (!udebug_thread_precheck()) {
udebug_int_unlock();
return;
}
 
mutex_lock(&TASK->udebug.lock);
mutex_lock(&THREAD->udebug.lock);
 
/* Must only generate events when in debugging session and have go */
if (THREAD->udebug.debug_active != true ||
THREAD->udebug.stop == true ||
(TASK->udebug.evmask & UDEBUG_EVMASK(etype)) == 0) {
mutex_unlock(&THREAD->udebug.lock);
mutex_unlock(&TASK->udebug.lock);
return;
}
 
//printf("udebug_syscall_event\n");
call = THREAD->udebug.go_call;
THREAD->udebug.go_call = NULL;
 
IPC_SET_RETVAL(call->data, 0);
IPC_SET_ARG1(call->data, etype);
IPC_SET_ARG2(call->data, id);
IPC_SET_ARG3(call->data, rc);
//printf("udebug_syscall_event/ipc_answer\n");
 
THREAD->udebug.syscall_args[0] = a1;
THREAD->udebug.syscall_args[1] = a2;
THREAD->udebug.syscall_args[2] = a3;
THREAD->udebug.syscall_args[3] = a4;
THREAD->udebug.syscall_args[4] = a5;
THREAD->udebug.syscall_args[5] = a6;
 
/*
* Make sure udebug.stop is true when going to sleep
* in case we get woken up by DEBUG_END. (At which
* point it must be back to the initial true value).
*/
THREAD->udebug.stop = true;
THREAD->udebug.cur_event = etype;
 
ipc_answer(&TASK->answerbox, call);
 
mutex_unlock(&THREAD->udebug.lock);
mutex_unlock(&TASK->udebug.lock);
 
udebug_wait_for_go(&THREAD->udebug.go_wq);
 
udebug_int_unlock();
}
 
void udebug_thread_b_event(struct thread *t)
{
call_t *call;
 
udebug_int_lock();
 
mutex_lock(&TASK->udebug.lock);
mutex_lock(&THREAD->udebug.lock);
 
LOG("udebug_thread_b_event\n");
LOG("- check state\n");
 
/* Must only generate events when in debugging session */
if (THREAD->udebug.debug_active != true) {
LOG("- debug_active: %s, udebug.stop: %s\n",
THREAD->udebug.debug_active ? "yes(+)" : "no(-)",
THREAD->udebug.stop ? "yes(-)" : "no(+)");
mutex_unlock(&THREAD->udebug.lock);
mutex_unlock(&TASK->udebug.lock);
return;
}
 
LOG("- trigger event\n");
 
call = THREAD->udebug.go_call;
THREAD->udebug.go_call = NULL;
IPC_SET_RETVAL(call->data, 0);
IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_B);
IPC_SET_ARG2(call->data, (unative_t)t);
 
/*
* Make sure udebug.stop is true when going to sleep
* in case we get woken up by DEBUG_END. (At which
* point it must be back to the initial true value).
*/
THREAD->udebug.stop = true;
THREAD->udebug.cur_event = UDEBUG_EVENT_THREAD_B;
 
ipc_answer(&TASK->answerbox, call);
 
mutex_unlock(&THREAD->udebug.lock);
mutex_unlock(&TASK->udebug.lock);
 
LOG("- sleep\n");
udebug_wait_for_go(&THREAD->udebug.go_wq);
 
udebug_int_unlock();
}
 
void udebug_thread_e_event(void)
{
call_t *call;
 
udebug_int_lock();
 
mutex_lock(&TASK->udebug.lock);
mutex_lock(&THREAD->udebug.lock);
 
LOG("udebug_thread_e_event\n");
LOG("- check state\n");
 
/* Must only generate events when in debugging session */
if (THREAD->udebug.debug_active != true) {
/* printf("- debug_active: %s, udebug.stop: %s\n",
THREAD->udebug.debug_active ? "yes(+)" : "no(-)",
THREAD->udebug.stop ? "yes(-)" : "no(+)");*/
mutex_unlock(&THREAD->udebug.lock);
mutex_unlock(&TASK->udebug.lock);
return;
}
 
LOG("- trigger event\n");
 
call = THREAD->udebug.go_call;
THREAD->udebug.go_call = NULL;
IPC_SET_RETVAL(call->data, 0);
IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_E);
 
/* Prevent any further debug activity in thread */
THREAD->udebug.debug_active = false;
THREAD->udebug.cur_event = 0; /* none */
THREAD->udebug.stop = true; /* set to initial value */
 
ipc_answer(&TASK->answerbox, call);
 
mutex_unlock(&THREAD->udebug.lock);
mutex_unlock(&TASK->udebug.lock);
 
/* Leave int_lock enabled */
/* This event does not sleep - debugging has finished in this thread */
}
 
/**
* Terminate task debugging session.
*
* \param ta->udebug.lock must be already locked.
* \return Zero on success or negative error code.
*/
int udebug_task_cleanup(struct task *ta)
{
thread_t *t;
link_t *cur;
int flags;
ipl_t ipl;
 
LOG("udebug_task_cleanup()\n");
LOG("task %" PRIu64 "\n", ta->taskid);
 
udebug_int_lock();
 
if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING &&
ta->udebug.dt_state != UDEBUG_TS_ACTIVE) {
LOG("udebug_task_cleanup(): task not being debugged\n");
return EINVAL;
}
 
/* Finish debugging of all userspace threads */
for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
t = list_get_instance(cur, thread_t, th_link);
 
mutex_lock(&t->udebug.lock);
 
ipl = interrupts_disable();
spinlock_lock(&t->lock);
 
flags = t->flags;
 
spinlock_unlock(&t->lock);
interrupts_restore(ipl);
 
/* Only process userspace threads */
if ((flags & THREAD_FLAG_USPACE) != 0) {
/* Prevent any further debug activity in thread */
t->udebug.debug_active = false;
t->udebug.cur_event = 0; /* none */
 
/* Still has go? */
if (t->udebug.stop == false) {
/*
* Yes, so clear go. As debug_active == false,
* this doesn't affect anything.
*/
t->udebug.stop = true;
 
/* Answer GO call */
LOG("answer GO call with EVENT_FINISHED\n");
IPC_SET_RETVAL(t->udebug.go_call->data, 0);
IPC_SET_ARG1(t->udebug.go_call->data, UDEBUG_EVENT_FINISHED);
 
ipc_answer(&ta->answerbox, t->udebug.go_call);
t->udebug.go_call = NULL;
} else {
/*
* Debug_stop is already at initial value.
* Yet this means the thread needs waking up.
*/
 
/*
* t's lock must not be held when calling
* waitq_wakeup.
*/
waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
}
}
mutex_unlock(&t->udebug.lock);
}
 
ta->udebug.dt_state = UDEBUG_TS_INACTIVE;
ta->udebug.debugger = NULL;
 
udebug_int_unlock();
 
return 0;
}
 
 
/** @}
*/
/branches/dynload/kernel/generic/src/udebug/udebug_ops.c
0,0 → 1,436
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup generic
* @{
*/
 
/**
* @file
* @brief Udebug operations.
*/
#include <debug.h>
#include <proc/task.h>
#include <proc/thread.h>
#include <arch.h>
#include <errno.h>
#include <syscall/copy.h>
#include <ipc/ipc.h>
#include <udebug/udebug.h>
#include <udebug/udebug_ops.h>
 
/**
* Prepare a thread for a debugging operation.
*
* Simply put, return thread t with t->udebug.lock held,
* but only if it verifies all conditions.
*
* Specifically, verifies that thread t exists, is a userspace thread,
* and belongs to the current task (TASK). Verifies, that the thread
* has (or hasn't) go according to having_go (typically false).
* It also locks t->udebug.lock, making sure that t->udebug.debug_active
* is true - that the thread is in a valid debugging session.
*
* With this verified and the t->udebug.lock mutex held, it is ensured
* that the thread cannot leave the debugging session, let alone cease
* to exist.
*
* In this function, holding the TASK->udebug.lock mutex prevents the
* thread from leaving the debugging session, while relaxing from
* the t->lock spinlock to the t->udebug.lock mutex.
*
* Returns EOK if all went well, or an error code otherwise.
*/
static int _thread_op_begin(thread_t *t, bool having_go)
{
task_id_t taskid;
ipl_t ipl;
 
taskid = TASK->taskid;
 
mutex_lock(&TASK->udebug.lock);
 
/* thread_exists() must be called with threads_lock held */
ipl = interrupts_disable();
spinlock_lock(&threads_lock);
 
if (!thread_exists(t)) {
spinlock_unlock(&threads_lock);
interrupts_restore(ipl);
mutex_unlock(&TASK->udebug.lock);
return ENOENT;
}
 
/* t->lock is enough to ensure the thread's existence */
spinlock_lock(&t->lock);
spinlock_unlock(&threads_lock);
 
/* Verify that 't' is a userspace thread */
if ((t->flags & THREAD_FLAG_USPACE) == 0) {
/* It's not, deny its existence */
spinlock_unlock(&t->lock);
interrupts_restore(ipl);
mutex_unlock(&TASK->udebug.lock);
return ENOENT;
}
 
/* Verify debugging state */
if (t->udebug.debug_active != true) {
/* Not in debugging session or undesired GO state */
spinlock_unlock(&t->lock);
interrupts_restore(ipl);
mutex_unlock(&TASK->udebug.lock);
return ENOENT;
}
 
/*
* Since the thread has debug_active == true, TASK->udebug.lock
* is enough to ensure its existence and that debug_active remains
* true.
*/
spinlock_unlock(&t->lock);
interrupts_restore(ipl);
 
/* Only mutex TASK->udebug.lock left */
/* Now verify that the thread belongs to the current task */
if (t->task != TASK) {
/* No such thread belonging this task*/
mutex_unlock(&TASK->udebug.lock);
return ENOENT;
}
 
/*
* Now we need to grab the thread's debug lock for synchronization
* of the threads stoppability/stop state.
*/
mutex_lock(&t->udebug.lock);
 
/* The big task mutex is no longer needed */
mutex_unlock(&TASK->udebug.lock);
 
if (!t->udebug.stop != having_go) {
/* Not in debugging session or undesired GO state */
mutex_unlock(&t->udebug.lock);
return EINVAL;
}
 
/* Only t->udebug.lock left */
 
return EOK; /* All went well */
}
 
 
static void _thread_op_end(thread_t *t)
{
mutex_unlock(&t->udebug.lock);
}
 
/**
* \return 0 (ok, but not done yet), 1 (done) or negative error code.
*/
int udebug_begin(call_t *call)
{
int reply;
 
thread_t *t;
link_t *cur;
 
LOG("udebug_begin()\n");
 
mutex_lock(&TASK->udebug.lock);
LOG("debugging task %llu\n", TASK->taskid);
 
if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
mutex_unlock(&TASK->udebug.lock);
LOG("udebug_begin(): busy error\n");
 
return EBUSY;
}
 
TASK->udebug.dt_state = UDEBUG_TS_BEGINNING;
TASK->udebug.begin_call = call;
TASK->udebug.debugger = call->sender;
 
if (TASK->udebug.not_stoppable_count == 0) {
TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
TASK->udebug.begin_call = NULL;
reply = 1; /* immediate reply */
} else {
reply = 0; /* no reply */
}
/* Set udebug.debug_active on all of the task's userspace threads */
 
for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
t = list_get_instance(cur, thread_t, th_link);
 
mutex_lock(&t->udebug.lock);
if ((t->flags & THREAD_FLAG_USPACE) != 0)
t->udebug.debug_active = true;
mutex_unlock(&t->udebug.lock);
}
 
mutex_unlock(&TASK->udebug.lock);
 
LOG("udebug_begin() done (%s)\n",
reply ? "reply" : "stoppability wait");
 
return reply;
}
 
int udebug_end(void)
{
int rc;
 
LOG("udebug_end()\n");
 
mutex_lock(&TASK->udebug.lock);
LOG("task %" PRIu64 "\n", TASK->taskid);
 
rc = udebug_task_cleanup(TASK);
 
mutex_unlock(&TASK->udebug.lock);
 
return rc;
}
 
int udebug_set_evmask(udebug_evmask_t mask)
{
LOG("udebug_set_mask()\n");
 
mutex_lock(&TASK->udebug.lock);
 
if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
mutex_unlock(&TASK->udebug.lock);
LOG("udebug_set_mask(): not active debuging session\n");
 
return EINVAL;
}
 
TASK->udebug.evmask = mask;
 
mutex_unlock(&TASK->udebug.lock);
 
return 0;
}
 
 
int udebug_go(thread_t *t, call_t *call)
{
int rc;
 
/* On success, this will lock t->udebug.lock */
rc = _thread_op_begin(t, false);
if (rc != EOK) {
return rc;
}
 
t->udebug.go_call = call;
t->udebug.stop = false;
t->udebug.cur_event = 0; /* none */
 
/*
* Neither t's lock nor threads_lock may be held during wakeup
*/
waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
 
_thread_op_end(t);
 
return 0;
}
 
int udebug_stop(thread_t *t, call_t *call)
{
int rc;
 
LOG("udebug_stop()\n");
mutex_lock(&TASK->udebug.lock);
 
/*
* On success, this will lock t->udebug.lock. Note that this makes sure
* the thread is not stopped.
*/
rc = _thread_op_begin(t, true);
if (rc != EOK) {
return rc;
}
 
/* Take GO away from the thread */
t->udebug.stop = true;
 
if (!t->udebug.stoppable) {
/* Answer will be sent when the thread becomes stoppable */
_thread_op_end(t);
return 0;
}
 
/*
* Answer GO call
*/
LOG("udebug_stop - answering go call\n");
 
/* Make sure nobody takes this call away from us */
call = t->udebug.go_call;
t->udebug.go_call = NULL;
 
IPC_SET_RETVAL(call->data, 0);
IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
LOG("udebug_stop/ipc_answer\n");
 
THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
 
_thread_op_end(t);
 
ipc_answer(&TASK->answerbox, call);
mutex_unlock(&TASK->udebug.lock);
 
LOG("udebog_stop/done\n");
return 0;
}
 
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n)
{
thread_t *t;
link_t *cur;
unative_t tid;
unsigned copied_ids;
ipl_t ipl;
unative_t *id_buffer;
int flags;
size_t max_ids;
 
LOG("udebug_thread_read()\n");
 
/* Allocate a buffer to hold thread IDs */
id_buffer = malloc(buf_size, 0);
 
mutex_lock(&TASK->udebug.lock);
 
/* Verify task state */
if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
mutex_unlock(&TASK->udebug.lock);
return EINVAL;
}
 
ipl = interrupts_disable();
spinlock_lock(&TASK->lock);
/* Copy down the thread IDs */
 
max_ids = buf_size / sizeof(unative_t);
copied_ids = 0;
 
/* FIXME: make sure the thread isn't past debug shutdown... */
for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
/* Do not write past end of buffer */
if (copied_ids >= max_ids) break;
 
t = list_get_instance(cur, thread_t, th_link);
 
spinlock_lock(&t->lock);
flags = t->flags;
spinlock_unlock(&t->lock);
 
/* Not interested in kernel threads */
if ((flags & THREAD_FLAG_USPACE) != 0) {
/* Using thread struct pointer as identification hash */
tid = (unative_t) t;
id_buffer[copied_ids++] = tid;
}
}
 
spinlock_unlock(&TASK->lock);
interrupts_restore(ipl);
 
mutex_unlock(&TASK->udebug.lock);
 
*buffer = id_buffer;
*n = copied_ids * sizeof(unative_t);
 
return 0;
}
 
int udebug_args_read(thread_t *t, void **buffer)
{
int rc;
unative_t *arg_buffer;
 
/* Prepare a buffer to hold the arguments */
arg_buffer = malloc(6 * sizeof(unative_t), 0);
 
/* On success, this will lock t->udebug.lock */
rc = _thread_op_begin(t, false);
if (rc != EOK) {
return rc;
}
 
/* Additionally we need to verify that we are inside a syscall */
if (t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B &&
t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E) {
_thread_op_end(t);
return EINVAL;
}
 
/* Copy to a local buffer before releasing the lock */
memcpy(arg_buffer, t->udebug.syscall_args, 6 * sizeof(unative_t));
 
_thread_op_end(t);
 
*buffer = arg_buffer;
return 0;
}
 
int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer)
{
void *data_buffer;
int rc;
 
/* Verify task state */
mutex_lock(&TASK->udebug.lock);
 
if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
mutex_unlock(&TASK->udebug.lock);
return EBUSY;
}
 
data_buffer = malloc(n, 0);
 
/* NOTE: this is not strictly from a syscall... but that shouldn't
* be a problem */
rc = copy_from_uspace(data_buffer, (void *)uspace_addr, n);
mutex_unlock(&TASK->udebug.lock);
 
if (rc != 0) return rc;
 
*buffer = data_buffer;
return 0;
}
 
/** @}
*/
/branches/dynload/kernel/Makefile
150,6 → 150,10
endif
endif
 
ifeq ($(CONFIG_UDEBUG),y)
DEFS += -DCONFIG_UDEBUG
endif
 
## Simple detection for the type of the host system
#
HOST = $(shell uname)
283,6 → 287,17
generic/src/security/cap.c \
generic/src/sysinfo/sysinfo.c
 
## Udebug interface sources
#
 
ifeq ($(CONFIG_UDEBUG),y)
GENERIC_SOURCES += \
generic/src/ipc/kbox.c \
generic/src/udebug/udebug.c \
generic/src/udebug/udebug_ops.c \
generic/src/udebug/udebug_ipc.c
endif
 
## Test sources
#
 
/branches/dynload/kernel/arch/arm32/include/interrupt.h
37,6 → 37,7
#define KERN_arm32_INTERRUPT_H_
 
#include <arch/types.h>
#include <arch/exception.h>
 
/** Initial size of exception dispatch table. */
#define IVT_ITEMS 6
/branches/dynload/uspace/app/bdsh/cmds/mknewcmd
120,8 → 120,8
EOF
[ "${CMDTYPE}" = "module" ] && cat << EOF >> ${OUTDIR}/entry.h
/* Entry points for the ${CMDNAME} command */
extern int * ${CMDENTRY}(char **);
extern void * ${HELPENTRY}(unsigned int);
extern int ${CMDENTRY}(char **);
extern void ${HELPENTRY}(unsigned int);
 
#endif /* ${defname}_ENTRY_H */
 
170,22 → 170,22
static char *cmdname = "${CMDNAME}";
 
/* Dispays help for ${CMDNAME} in various levels */
void * ${HELPENTRY}(unsigned int level)
void ${HELPENTRY}(unsigned int level)
{
printf("This is the %s help for '%s'.\n",
level ? EXT_HELP : SHORT_HELP, cmdname);
return CMD_VOID;
return;
}
 
EOF
[ "${CMDTYPE}" = "module" ] && cat << EOF >> ${OUTDIR}/${CMDNAME}.c
/* Main entry point for ${CMDNAME}, accepts an array of arguments */
int * ${CMDENTRY}(char **argv)
int ${CMDENTRY}(char **argv)
EOF
[ "${CMDTYPE}" = "builtin" ] && cat << EOF >> ${OUTDIR}/${CMDNAME}.c
/* Main entry point for ${CMDNAME}, accepts an array of arguments and a
* pointer to the cliuser_t structure */
int * ${CMDENTRY}(char **argv, cliuser_t *usr)
int ${CMDENTRY}(char **argv, cliuser_t *usr)
EOF
cat << EOF >> ${OUTDIR}/${CMDNAME}.c
{
/branches/dynload/uspace/app/bdsh/cmds/modules/quit/quit.c
39,15 → 39,15
extern volatile unsigned int cli_quit;
extern const char *progname;
 
void * help_cmd_quit(unsigned int level)
void help_cmd_quit(unsigned int level)
{
printf("Type `%s' to exit %s\n", cmdname, progname);
return CMD_VOID;
return;
}
 
/* Quits the program and returns the status of whatever command
* came before invoking 'quit' */
int * cmd_quit(char *argv[])
int cmd_quit(char *argv[])
{
/* Inform that we're outta here */
cli_quit = 1;
/branches/dynload/uspace/app/bdsh/cmds/modules/quit/entry.h
2,8 → 2,8
#define QUIT_ENTRY_H_
 
/* Entry points for the quit command */
extern void * help_cmd_quit(unsigned int);
extern int * cmd_quit(char *[]);
extern void help_cmd_quit(unsigned int);
extern int cmd_quit(char *[]);
 
#endif
 
/branches/dynload/uspace/app/bdsh/cmds/modules/touch/touch.c
48,7 → 48,7
static char *cmdname = "touch";
 
/* Dispays help for touch in various levels */
void * help_cmd_touch(unsigned int level)
void help_cmd_touch(unsigned int level)
{
if (level == HELP_SHORT) {
printf("`%s' updates access times for files\n", cmdname);
58,11 → 58,11
"created\n", cmdname);
}
 
return CMD_VOID;
return;
}
 
/* Main entry point for touch, accepts an array of arguments */
int * cmd_touch(char **argv)
int cmd_touch(char **argv)
{
unsigned int argc, i = 0, ret = 0;
int fd;
/branches/dynload/uspace/app/bdsh/cmds/modules/touch/entry.h
2,8 → 2,8
#define TOUCH_ENTRY_H
 
/* Entry points for the touch command */
extern int * cmd_touch(char **);
extern void * help_cmd_touch(unsigned int);
extern int cmd_touch(char **);
extern void help_cmd_touch(unsigned int);
 
#endif /* TOUCH_ENTRY_H */
 
/branches/dynload/uspace/app/bdsh/cmds/modules/cp/cp.c
0,0 → 1,73
/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
* 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.
*
* Neither the name of the original program's authors nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "util.h"
#include "errors.h"
#include "entry.h"
#include "cp.h"
#include "cmds.h"
 
static char *cmdname = "cp";
 
/* Dispays help for cp in various levels */
void help_cmd_cp(unsigned int level)
{
printf("This is the %s help for '%s'.\n",
level ? EXT_HELP : SHORT_HELP, cmdname);
return;
}
 
/* Main entry point for cp, accepts an array of arguments */
int cmd_cp(char **argv)
{
unsigned int argc;
unsigned int i;
 
/* Count the arguments */
for (argc = 0; argv[argc] != NULL; argc ++);
 
printf("%s %s\n", TEST_ANNOUNCE, cmdname);
printf("%d arguments passed to %s", argc - 1, cmdname);
 
if (argc < 2) {
printf("\n");
return CMD_SUCCESS;
}
 
printf(":\n");
for (i = 1; i < argc; i++)
printf("[%d] -> %s\n", i, argv[i]);
 
return CMD_SUCCESS;
}
 
/branches/dynload/uspace/app/bdsh/cmds/modules/cp/cp_def.h
0,0 → 1,8
{
"cp",
"Copy files and directories",
&cmd_cp,
&help_cmd_cp,
0
},
 
/branches/dynload/uspace/app/bdsh/cmds/modules/cp/entry.h
0,0 → 1,9
#ifndef CP_ENTRY_H
#define CP_ENTRY_H
 
/* Entry points for the cp command */
extern int cmd_cp(char **);
extern void help_cmd_cp(unsigned int);
 
#endif /* CP_ENTRY_H */
 
/branches/dynload/uspace/app/bdsh/cmds/modules/cp/cp.h
0,0 → 1,8
#ifndef CP_H
#define CP_H
 
/* Prototypes for the cp command, excluding entry points */
 
 
#endif /* CP_H */
 
/branches/dynload/uspace/app/bdsh/cmds/modules/mkdir/entry.h
2,8 → 2,8
#define MKDIR_ENTRY_H
 
/* Entry points for the mkdir command */
extern int * cmd_mkdir(char **);
extern void * help_cmd_mkdir(unsigned int);
extern int cmd_mkdir(char **);
extern void help_cmd_mkdir(unsigned int);
 
#endif /* MKDIR_ENTRY_H */
 
/branches/dynload/uspace/app/bdsh/cmds/modules/mkdir/mkdir.c
60,7 → 60,7
};
 
 
void * help_cmd_mkdir(unsigned int level)
void help_cmd_mkdir(unsigned int level)
{
if (level == HELP_SHORT) {
printf("`%s' creates a new directory\n", cmdname);
79,7 → 79,7
cmdname, cmdname);
}
 
return CMD_VOID;
return;
}
 
/* This is kind of clunky, but effective for now */
181,7 → 181,7
return ret;
}
 
int * cmd_mkdir(char **argv)
int cmd_mkdir(char **argv)
{
unsigned int argc, create_parents = 0, i, ret = 0, follow = 0;
unsigned int verbose = 0;
/branches/dynload/uspace/app/bdsh/cmds/modules/cat/entry.h
2,8 → 2,8
#define CAT_ENTRY_H
 
/* Entry points for the cat command */
extern int * cmd_cat(char **);
extern void * help_cmd_cat(unsigned int);
extern int cmd_cat(char **);
extern void help_cmd_cat(unsigned int);
 
#endif /* CAT_ENTRY_H */
 
/branches/dynload/uspace/app/bdsh/cmds/modules/cat/cat.c
59,7 → 59,7
};
 
/* Dispays help for cat in various levels */
void * help_cmd_cat(unsigned int level)
void help_cmd_cat(unsigned int level)
{
if (level == HELP_SHORT) {
printf("`%s' shows the contents of files\n", cmdname);
78,7 → 78,7
cmdname, cmdname);
}
 
return CMD_VOID;
return;
}
 
static unsigned int cat_file(const char *fname, size_t blen)
121,12 → 121,6
return 1;
}
 
/* Debug stuff, newline not added purposefully */
printf("** %s is a file with the size of %ld bytes\n",
fname, total);
printf( "** %d bytes were read in a buffer of %d bytes in %d reads\n",
count, blen, reads);
printf("** Read %s\n", count == total ? "Succeeded" : "Failed");
free(buff);
 
return 0;
133,7 → 127,7
}
 
/* Main entry point for cat, accepts an array of arguments */
int * cmd_cat(char **argv)
int cmd_cat(char **argv)
{
unsigned int argc, i, ret = 0, buffer = 0;
int c, opt_ind;
/branches/dynload/uspace/app/bdsh/cmds/modules/help/entry.h
2,7 → 2,7
#define HELP_ENTRY_H_
 
/* Entry points for the help command */
extern void * help_cmd_help(unsigned int);
extern int * cmd_help(char *[]);
extern void help_cmd_help(unsigned int);
extern int cmd_help(char *[]);
 
#endif
/branches/dynload/uspace/app/bdsh/cmds/modules/help/help.c
69,7 → 69,7
return HELP_IS_RUBBISH;
}
 
void *help_cmd_help(unsigned int level)
void help_cmd_help(unsigned int level)
{
if (level == HELP_SHORT) {
printf(
86,10 → 86,10
cmdname, cmdname, cmdname, cmdname);
}
 
return CMD_VOID;
return;
}
 
int *cmd_help(char *argv[])
int cmd_help(char *argv[])
{
module_t *mod;
builtin_t *cmd;
/branches/dynload/uspace/app/bdsh/cmds/modules/sleep/entry.h
0,0 → 1,9
#ifndef SLEEP_ENTRY_H
#define SLEEP_ENTRY_H
 
/* Entry points for the sleep command */
extern int cmd_sleep(char **);
extern void help_cmd_sleep(unsigned int);
 
#endif /* SLEEP_ENTRY_H */
 
/branches/dynload/uspace/app/bdsh/cmds/modules/sleep/sleep.c
0,0 → 1,73
/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
* 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.
*
* Neither the name of the original program's authors nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "util.h"
#include "errors.h"
#include "entry.h"
#include "sleep.h"
#include "cmds.h"
 
static char *cmdname = "sleep";
 
/* Dispays help for sleep in various levels */
void help_cmd_sleep(unsigned int level)
{
printf("This is the %s help for '%s'.\n",
level ? EXT_HELP : SHORT_HELP, cmdname);
return;
}
 
/* Main entry point for sleep, accepts an array of arguments */
int cmd_sleep(char **argv)
{
unsigned int argc;
unsigned int i;
 
/* Count the arguments */
for (argc = 0; argv[argc] != NULL; argc ++);
 
printf("%s %s\n", TEST_ANNOUNCE, cmdname);
printf("%d arguments passed to %s", argc - 1, cmdname);
 
if (argc < 2) {
printf("\n");
return CMD_SUCCESS;
}
 
printf(":\n");
for (i = 1; i < argc; i++)
printf("[%d] -> %s\n", i, argv[i]);
 
return CMD_SUCCESS;
}
 
/branches/dynload/uspace/app/bdsh/cmds/modules/sleep/sleep_def.h
0,0 → 1,8
{
"sleep",
"Pause for given time interval (in seconds)",
&cmd_sleep,
&help_cmd_sleep,
0
},
 
/branches/dynload/uspace/app/bdsh/cmds/modules/sleep/sleep.h
0,0 → 1,8
#ifndef SLEEP_H
#define SLEEP_H
 
/* Prototypes for the sleep command, excluding entry points */
 
 
#endif /* SLEEP_H */
 
/branches/dynload/uspace/app/bdsh/cmds/modules/pwd/entry.h
4,8 → 4,8
#include "scli.h"
 
/* Entry points for the pwd command */
extern void * help_cmd_pwd(unsigned int);
extern int * cmd_pwd(char **);
extern void help_cmd_pwd(unsigned int);
extern int cmd_pwd(char **);
 
#endif
 
/branches/dynload/uspace/app/bdsh/cmds/modules/pwd/pwd.c
39,13 → 39,13
 
static char * cmdname = "pwd";
 
void * help_cmd_pwd(unsigned int level)
void help_cmd_pwd(unsigned int level)
{
printf("`%s' prints your current working directory.\n", cmdname);
return CMD_VOID;
return;
}
 
int * cmd_pwd(char *argv[])
int cmd_pwd(char *argv[])
{
char *buff;
 
/branches/dynload/uspace/app/bdsh/cmds/modules/ls/ls.c
132,7 → 132,7
return;
}
 
void * help_cmd_ls(unsigned int level)
void help_cmd_ls(unsigned int level)
{
if (level == HELP_SHORT) {
printf("`%s' lists files and directories.\n", cmdname);
142,10 → 142,10
"working directory is used.\n", cmdname);
}
 
return CMD_VOID;
return;
}
 
int * cmd_ls(char **argv)
int cmd_ls(char **argv)
{
unsigned int argc;
unsigned int scope;
/branches/dynload/uspace/app/bdsh/cmds/modules/ls/entry.h
2,8 → 2,8
#define LS_ENTRY_H
 
/* Entry points for the ls command */
extern int * cmd_ls(char **);
extern void * help_cmd_ls(unsigned int);
extern int cmd_ls(char **);
extern void help_cmd_ls(unsigned int);
 
#endif /* LS_ENTRY_H */
 
/branches/dynload/uspace/app/bdsh/cmds/modules/modules.h
25,6 → 25,8
#include "touch/entry.h"
#include "ls/entry.h"
#include "pwd/entry.h"
#include "sleep/entry.h"
#include "cp/entry.h"
 
/* Each .def function fills the module_t struct with the individual name, entry
* point, help entry point, etc. You can use config.h to control what modules
39,6 → 41,8
#include "touch/touch_def.h"
#include "ls/ls_def.h"
#include "pwd/pwd_def.h"
#include "sleep/sleep_def.h"
#include "cp/cp_def.h"
{NULL, NULL, NULL, NULL}
};
 
/branches/dynload/uspace/app/bdsh/cmds/modules/rm/rm.c
144,7 → 144,7
}
 
/* Dispays help for rm in various levels */
void * help_cmd_rm(unsigned int level)
void help_cmd_rm(unsigned int level)
{
if (level == HELP_SHORT) {
printf("`%s' removes files and directories.\n", cmdname);
161,11 → 161,11
"Currently, %s is under development, some options don't work.\n",
cmdname, cmdname);
}
return CMD_VOID;
return;
}
 
/* Main entry point for rm, accepts an array of arguments */
int * cmd_rm(char **argv)
int cmd_rm(char **argv)
{
unsigned int argc;
unsigned int i, scope, ret = 0;
/branches/dynload/uspace/app/bdsh/cmds/modules/rm/entry.h
2,8 → 2,8
#define RM_ENTRY_H
 
/* Entry points for the rm command */
extern int * cmd_rm(char **);
extern void * help_cmd_rm(unsigned int);
extern int cmd_rm(char **);
extern void help_cmd_rm(unsigned int);
 
#endif /* RM_ENTRY_H */
 
/branches/dynload/uspace/app/bdsh/cmds/builtins/cd/cd.c
42,7 → 42,7
 
static char * cmdname = "cd";
 
void * help_cmd_cd(unsigned int level)
void help_cmd_cd(unsigned int level)
{
if (level == HELP_SHORT) {
printf("`%s' changes the current working directory.\n", cmdname);
53,12 → 53,12
cmdname, cmdname);
}
 
return CMD_VOID;
return;
}
 
/* This is a very rudamentary 'cd' command. It is not 'link smart' (yet) */
 
int * cmd_cd(char **argv, cliuser_t *usr)
int cmd_cd(char **argv, cliuser_t *usr)
{
int argc, rc = 0;
 
/branches/dynload/uspace/app/bdsh/cmds/builtins/cd/entry.h
4,8 → 4,8
#include "scli.h"
 
/* Entry points for the cd command */
extern void * help_cmd_cd(unsigned int);
extern int * cmd_cd(char **, cliuser_t *);
extern void help_cmd_cd(unsigned int);
extern int cmd_cd(char **, cliuser_t *);
 
#endif
 
/branches/dynload/uspace/app/bdsh/cmds/cmds.h
19,17 → 19,16
#define BUFF_SMALL 255
 
/* Return macros for int type entry points */
#define CMD_FAILURE (int*)1
#define CMD_FAILURE 1
#define CMD_SUCCESS 0
#define CMD_VOID (void *)NULL
 
/* Types for module command entry and help */
typedef int * (* mod_entry_t)(char **);
typedef void * (* mod_help_t)(unsigned int);
typedef int (* mod_entry_t)(char **);
typedef void (* mod_help_t)(unsigned int);
 
/* Built-in commands need to be able to modify cliuser_t */
typedef int * (* builtin_entry_t)(char **, cliuser_t *);
typedef void * (* builtin_help_t)(unsigned int);
typedef int (* builtin_entry_t)(char **, cliuser_t *);
typedef void (* builtin_help_t)(unsigned int);
 
/* Module structure */
typedef struct {
/branches/dynload/uspace/app/bdsh/config.h
1,15 → 1,18
/* Various things that are used in many files
* Various temporary port work-arounds are addressed in __HELENOS__ , this
* serves as a convenience and later as a guide to make "phony.h" for future
* ports */
/* Various things that are used in many places including a few
* tidbits left over from autoconf prior to the HelenOS port */
 
/* Specific port work-arounds : */
#ifndef PATH_MAX
#define PATH_MAX 255
#endif
 
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 0
#define EXIT_FAILURE 1
#endif
 
/* Work around for getenv() */
#define PATH "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
#define PATH "/srv:/app"
#define PATH_DELIM ":"
 
/* Used in many places */
26,7 → 29,7
#define PACKAGE_BUGREPORT "echo@echoreply.us"
#define PACKAGE_NAME "bdsh"
#define PACKAGE_STRING "The brain dead shell"
#define PACKAGE_TARNAME "scli"
#define PACKAGE_TARNAME "bdsh"
#define PACKAGE_VERSION "0.0.1"
 
 
/branches/dynload/uspace/app/bdsh/README
57,12 → 57,12
They are typed as such (from cmds.h):
 
/* Types for module command entry and help */
typedef int * (* mod_entry_t)(char **);
typedef void * (* mod_help_t)(unsigned int);
typedef int (* mod_entry_t)(char **);
typedef void (* mod_help_t)(unsigned int);
 
/* Built-in commands need to be able to modify cliuser_t */
typedef int * (* builtin_entry_t)(char **, cliuser_t *);
typedef void * (* builtin_help_t)(unsigned int);
typedef int (* builtin_entry_t)(char **, cliuser_t *);
typedef void (* builtin_help_t)(unsigned int);
 
As you can see, both modular and builtin commands expect an array of
arguments, however bulitins also expect to be pointed to cliuser_t.
153,9 → 153,7
 
2: Change your "usage()" command as shown:
-- void usage(...)
++ void * help_cmd_foo(unsigned int level)
-- return;
++ retrn CMD_VOID;
++ void help_cmd_foo(unsigned int level)
 
'level' is either 0 or 1, indicating the level of help requested.
If the help / usage function currently exits based on how it is
163,33 → 161,19
 
3: Change the programs "main()" as shown:
-- int main(int argc, char **argv)
++ int * cmd_foo(char **argv)
++ int cmd_foo(char **argv)
-- return 1;
++ return CMD_FAILURE;
-- return 0;
++ return CMD_SUCCESS;
 
If main() returns an int that is not 1 or 0 (e.g. 127), cast it as
such:
 
-- return 127;
++ return (int *) 127;
 
NOTE: _ONLY_ the main and help entry points need to return int * or
void *, respectively. Also take note that argc has changed. The type
for entry points may soon change.
 
NOTE: If main is void, you'll need to change it and ensure that its
expecting an array of arguments, even if they'll never be read or
used. I.e.:
 
-- void main(void)
++ int * cmd_foo(char **argv)
++ int cmd_foo(char **argv)
 
Similararly, do not try to return CMD_VOID within the modules main
entry point. If somehow you escape the compiler yelling at you, you
will surely see pretty blue and yellow fireworks once its reached.
 
4: Don't expose more than the entry and help points:
-- void my_function(int n)
++ static void my_function(int n)
/branches/dynload/uspace/app/bdsh/util.c
273,7 → 273,7
if (NULL == usr->cwd)
snprintf(usr->cwd, PATH_MAX, "(unknown)");
 
if (1 < cli_psprintf(&usr->prompt, "%s # ", usr->cwd)) {
if (1 < cli_psprintf(&usr->prompt, "%s ", usr->cwd)) {
cli_error(cli_errno, "Failed to set prompt");
return 1;
}
/branches/dynload/uspace/app/bdsh/scli.c
53,8 → 53,8
const char *progname = PACKAGE_NAME;
 
/* These are not exposed, even to builtins */
static int cli_init(cliuser_t *usr);
static void cli_finit(cliuser_t *usr);
static int cli_init(cliuser_t *);
static void cli_finit(cliuser_t *);
 
/* Constructor */
static int cli_init(cliuser_t *usr)
/branches/dynload/uspace/app/bdsh/Makefile
64,6 → 64,8
cmds/modules/touch/ \
cmds/modules/ls/ \
cmds/modules/pwd/ \
cmds/modules/sleep/ \
cmds/modules/cp/ \
cmds/builtins/ \
cmds/builtins/cd/
 
76,6 → 78,8
cmds/modules/touch/touch.c \
cmds/modules/ls/ls.c \
cmds/modules/pwd/pwd.c \
cmds/modules/sleep/sleep.c \
cmds/modules/cp/cp.c \
cmds/builtins/cd/cd.c \
cmds/mod_cmds.c \
cmds/builtin_cmds.c \
/branches/dynload/uspace/app/init/init.c
108,17 → 108,15
return -1;
}
buf = malloc(BUF_SIZE);
// FIXME: spawn("/srv/pci");
spawn("/srv/fb");
spawn("/srv/kbd");
spawn("/srv/console");
// FIXME: spawn("/sbin/pci");
spawn("/sbin/fb");
spawn("/sbin/kbd");
spawn("/sbin/console");
console_wait();
version_print();
spawn("/sbin/bdsh");
spawn("/app/bdsh");
free(buf);
return 0;
/branches/dynload/uspace/app/tester/tester.c
133,7 → 133,7
if (c == 'a')
break;
if (c > 'a')
if (test->name == NULL)
printf("Unknown test\n\n");
else
run_test(test);
/branches/dynload/uspace/app/trace/trace.c
0,0 → 1,658
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup trace
* @{
*/
/** @file
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syscall.h>
#include <ipc/ipc.h>
#include <fibril.h>
#include <errno.h>
#include <udebug.h>
#include <async.h>
#include <task.h>
 
// Temporary: service and method names
#include "proto.h"
#include <ipc/services.h>
#include "../../srv/vfs/vfs.h"
#include "../../srv/console/console.h"
 
#include "syscalls.h"
#include "ipcp.h"
#include "errors.h"
#include "trace.h"
 
#define THBUF_SIZE 64
unsigned thread_hash_buf[THBUF_SIZE];
unsigned n_threads;
 
int next_thread_id;
 
int phoneid;
int abort_trace;
 
unsigned thash;
volatile int paused;
 
void thread_trace_start(unsigned thread_hash);
 
static proto_t *proto_console;
static task_id_t task_id;
 
/** Combination of events/data to print. */
display_mask_t display_mask;
 
static int task_connect(task_id_t task_id)
{
int rc;
 
rc = ipc_connect_kbox(task_id);
 
if (rc == ENOTSUP) {
printf("You do not have userspace debugging support "
"compiled in the kernel.\n");
printf("Compile kernel with 'Support for userspace debuggers' "
"(CONFIG_UDEBUG) enabled.\n");
return rc;
}
 
if (rc < 0) {
printf("Error connecting\n");
printf("ipc_connect_task(%lld) -> %d ", task_id, rc);
return rc;
}
 
phoneid = rc;
 
rc = udebug_begin(phoneid);
if (rc < 0) {
printf("udebug_begin() -> %d\n", rc);
return rc;
}
 
rc = udebug_set_evmask(phoneid, UDEBUG_EM_ALL);
if (rc < 0) {
printf("udebug_set_evmask(0x%x) -> %d\n ", UDEBUG_EM_ALL, rc);
return rc;
}
 
return 0;
}
 
static int get_thread_list(void)
{
int rc;
size_t tb_copied;
size_t tb_needed;
int i;
 
rc = udebug_thread_read(phoneid, thread_hash_buf,
THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
if (rc < 0) {
printf("udebug_thread_read() -> %d\n", rc);
return rc;
}
 
n_threads = tb_copied / sizeof(unsigned);
 
printf("Threads:");
for (i = 0; i < n_threads; i++) {
printf(" [%d] (hash 0x%x)", 1+i, thread_hash_buf[i]);
}
printf("\ntotal of %u threads\n", tb_needed/sizeof(unsigned));
 
return 0;
}
 
static void print_sc_retval(int retval, rv_type_t rv_type)
{
printf (" -> ");
if (rv_type == RV_INTEGER) {
printf("%d", retval);
} else if (rv_type == RV_HASH) {
printf("0x%08x", retval);
} else if (rv_type == RV_ERRNO) {
if (retval >= -15 && retval <= 0) {
printf("%d %s (%s)", retval,
err_desc[retval].name,
err_desc[retval].desc);
} else {
printf("%d", retval);
}
} else if (rv_type == RV_INT_ERRNO) {
if (retval >= -15 && retval < 0) {
printf("%d %s (%s)", retval,
err_desc[retval].name,
err_desc[retval].desc);
} else {
printf("%d", retval);
}
}
putchar('\n');
}
 
static void print_sc_args(unsigned *sc_args, int n)
{
int i;
 
putchar('(');
if (n > 0) printf("%d", sc_args[0]);
for (i=1; i<n; i++) {
printf(", %d", sc_args[i]);
}
putchar(')');
}
 
static void sc_ipc_call_async_fast(unsigned *sc_args, int sc_rc)
{
ipc_call_t call;
int phoneid;
if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY)
return;
 
phoneid = sc_args[0];
 
IPC_SET_METHOD(call, sc_args[1]);
IPC_SET_ARG1(call, sc_args[2]);
IPC_SET_ARG2(call, sc_args[3]);
IPC_SET_ARG3(call, sc_args[4]);
IPC_SET_ARG4(call, sc_args[5]);
IPC_SET_ARG5(call, 0);
 
ipcp_call_out(phoneid, &call, sc_rc);
}
 
static void sc_ipc_call_async_slow(unsigned *sc_args, int sc_rc)
{
ipc_call_t call;
int rc;
 
if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY)
return;
 
memset(&call, 0, sizeof(call));
rc = udebug_mem_read(phoneid, &call.args, sc_args[1], sizeof(call.args));
 
if (rc >= 0) {
ipcp_call_out(sc_args[0], &call, sc_rc);
}
}
 
static void sc_ipc_call_sync_fast(unsigned *sc_args)
{
ipc_call_t question, reply;
int rc;
int phoneidx;
 
// printf("sc_ipc_call_sync_fast()\n");
phoneidx = sc_args[0];
 
IPC_SET_METHOD(question, sc_args[1]);
IPC_SET_ARG1(question, sc_args[2]);
IPC_SET_ARG2(question, sc_args[3]);
IPC_SET_ARG3(question, sc_args[4]);
IPC_SET_ARG4(question, 0);
IPC_SET_ARG5(question, 0);
 
// printf("memset\n");
memset(&reply, 0, sizeof(reply));
// printf("udebug_mem_read(phone=%d, buffer_ptr=%u, src_addr=%d, n=%d\n",
// phoneid, &reply.args, sc_args[5], sizeof(reply.args));
rc = udebug_mem_read(phoneid, &reply.args, sc_args[5], sizeof(reply.args));
// printf("dmr->%d\n", rc);
if (rc < 0) return;
 
// printf("call ipc_call_sync\n");
ipcp_call_sync(phoneidx, &question, &reply);
}
 
static void sc_ipc_call_sync_slow(unsigned *sc_args)
{
ipc_call_t question, reply;
int rc;
 
memset(&question, 0, sizeof(question));
rc = udebug_mem_read(phoneid, &question.args, sc_args[1], sizeof(question.args));
printf("dmr->%d\n", rc);
if (rc < 0) return;
 
memset(&reply, 0, sizeof(reply));
rc = udebug_mem_read(phoneid, &reply.args, sc_args[2], sizeof(reply.args));
printf("dmr->%d\n", rc);
if (rc < 0) return;
 
ipcp_call_sync(sc_args[0], &question, &reply);
}
 
static void sc_ipc_wait(unsigned *sc_args, int sc_rc)
{
ipc_call_t call;
int rc;
 
if (sc_rc == 0) return;
 
memset(&call, 0, sizeof(call));
rc = udebug_mem_read(phoneid, &call, sc_args[0], sizeof(call));
// printf("udebug_mem_read(phone %d, dest %d, app-mem src %d, size %d -> %d\n",
// phoneid, (int)&call, sc_args[0], sizeof(call), rc);
 
if (rc >= 0) {
ipcp_call_in(&call, sc_rc);
}
}
 
static void event_syscall_b(unsigned thread_id, unsigned thread_hash, unsigned sc_id, int sc_rc)
{
unsigned sc_args[6];
int rc;
 
/* Read syscall arguments */
rc = udebug_args_read(phoneid, thread_hash, sc_args);
 
async_serialize_start();
 
// printf("[%d] ", thread_id);
 
if (rc < 0) {
printf("error\n");
async_serialize_end();
return;
}
 
if ((display_mask & DM_SYSCALL) != 0) {
/* Print syscall name and arguments */
printf("%s", syscall_desc[sc_id].name);
print_sc_args(sc_args, syscall_desc[sc_id].n_args);
}
 
async_serialize_end();
}
 
static void event_syscall_e(unsigned thread_id, unsigned thread_hash, unsigned sc_id, int sc_rc)
{
unsigned sc_args[6];
int rv_type;
int rc;
 
/* Read syscall arguments */
rc = udebug_args_read(phoneid, thread_hash, sc_args);
 
async_serialize_start();
 
// printf("[%d] ", thread_id);
 
if (rc < 0) {
printf("error\n");
async_serialize_end();
return;
}
 
if ((display_mask & DM_SYSCALL) != 0) {
/* Print syscall return value */
rv_type = syscall_desc[sc_id].rv_type;
print_sc_retval(sc_rc, rv_type);
}
 
switch (sc_id) {
case SYS_IPC_CALL_ASYNC_FAST:
sc_ipc_call_async_fast(sc_args, sc_rc);
break;
case SYS_IPC_CALL_ASYNC_SLOW:
sc_ipc_call_async_slow(sc_args, sc_rc);
break;
case SYS_IPC_CALL_SYNC_FAST:
sc_ipc_call_sync_fast(sc_args);
break;
case SYS_IPC_CALL_SYNC_SLOW:
sc_ipc_call_sync_slow(sc_args);
break;
case SYS_IPC_WAIT:
sc_ipc_wait(sc_args, sc_rc);
break;
default:
break;
}
 
async_serialize_end();
}
 
static void event_thread_b(unsigned hash)
{
async_serialize_start();
printf("New thread, hash 0x%x\n", hash);
async_serialize_end();
 
thread_trace_start(hash);
}
 
static int trace_loop(void *thread_hash_arg)
{
int rc;
unsigned ev_type;
unsigned thread_hash;
unsigned thread_id;
unsigned val0, val1;
 
thread_hash = (unsigned)thread_hash_arg;
thread_id = next_thread_id++;
 
printf("Start tracing thread [%d] (hash 0x%x)\n", thread_id, thread_hash);
 
while (!abort_trace) {
 
/* Run thread until an event occurs */
rc = udebug_go(phoneid, thread_hash,
&ev_type, &val0, &val1);
 
// printf("rc = %d, ev_type=%d\n", rc, ev_type);
if (ev_type == UDEBUG_EVENT_FINISHED) {
/* Done tracing this thread */
break;
}
 
if (rc >= 0) {
switch (ev_type) {
case UDEBUG_EVENT_SYSCALL_B:
event_syscall_b(thread_id, thread_hash, val0, (int)val1);
break;
case UDEBUG_EVENT_SYSCALL_E:
event_syscall_e(thread_id, thread_hash, val0, (int)val1);
break;
case UDEBUG_EVENT_STOP:
printf("Stop event\n");
printf("Waiting for resume\n");
while (paused) {
usleep(1000000);
fibril_yield();
printf(".");
}
printf("Resumed\n");
break;
case UDEBUG_EVENT_THREAD_B:
event_thread_b(val0);
break;
case UDEBUG_EVENT_THREAD_E:
printf("Thread 0x%x exited\n", val0);
abort_trace = 1;
break;
default:
printf("Unknown event type %d\n", ev_type);
break;
}
}
 
}
 
printf("Finished tracing thread [%d]\n", thread_id);
return 0;
}
 
void thread_trace_start(unsigned thread_hash)
{
fid_t fid;
 
thash = thread_hash;
 
fid = fibril_create(trace_loop, (void *)thread_hash);
if (fid == 0) {
printf("Warning: Failed creating fibril\n");
}
fibril_add_ready(fid);
}
 
static void trace_active_task(task_id_t task_id)
{
int i;
int rc;
int c;
 
rc = task_connect(task_id);
if (rc < 0) {
printf("Failed to connect to task %lld\n", task_id);
return;
}
 
printf("Connected to task %lld\n", task_id);
 
ipcp_init();
 
/*
* User apps now typically have console on phone 3.
* (Phones 1 and 2 are used by the loader).
*/
ipcp_connection_set(3, 0, proto_console);
 
rc = get_thread_list();
if (rc < 0) {
printf("Failed to get thread list (error %d)\n", rc);
return;
}
 
abort_trace = 0;
 
for (i = 0; i < n_threads; i++) {
thread_trace_start(thread_hash_buf[i]);
}
 
while(1) {
c = getchar();
if (c == 'q') break;
if (c == 'p') {
paused = 1;
rc = udebug_stop(phoneid, thash);
printf("stop -> %d\n", rc);
}
if (c == 'r') {
paused = 0;
}
}
 
printf("\nTerminate debugging session...\n");
abort_trace = 1;
udebug_end(phoneid);
ipc_hangup(phoneid);
 
ipcp_cleanup();
 
printf("Done\n");
return;
}
 
static void main_init(void)
{
proto_t *p;
oper_t *o;
 
next_thread_id = 1;
paused = 0;
 
proto_init();
 
p = proto_new("vfs");
o = oper_new("read");
proto_add_oper(p, VFS_READ, o);
o = oper_new("write");
proto_add_oper(p, VFS_WRITE, o);
o = oper_new("truncate");
proto_add_oper(p, VFS_TRUNCATE, o);
o = oper_new("mount");
proto_add_oper(p, VFS_MOUNT, o);
o = oper_new("unmount");
proto_add_oper(p, VFS_UNMOUNT, o);
 
proto_register(SERVICE_VFS, p);
 
p = proto_new("console");
o = oper_new("getchar");
proto_add_oper(p, CONSOLE_GETCHAR, o);
o = oper_new("putchar");
proto_add_oper(p, CONSOLE_PUTCHAR, o);
o = oper_new("clear");
proto_add_oper(p, CONSOLE_CLEAR, o);
o = oper_new("goto");
proto_add_oper(p, CONSOLE_GOTO, o);
o = oper_new("getsize");
proto_add_oper(p, CONSOLE_GETSIZE, o);
o = oper_new("flush");
proto_add_oper(p, CONSOLE_FLUSH, o);
o = oper_new("set_style");
proto_add_oper(p, CONSOLE_SET_STYLE, o);
o = oper_new("cursor_visibility");
proto_add_oper(p, CONSOLE_CURSOR_VISIBILITY, o);
o = oper_new("flush");
proto_add_oper(p, CONSOLE_FLUSH, o);
 
proto_console = p;
proto_register(SERVICE_CONSOLE, p);
}
 
static void print_syntax()
{
printf("Syntax:\n");
printf("\ttrace [+<events>] <executable> [<arg1> [...]]\n");
printf("or\ttrace [+<events>] -t <task_id>\n");
printf("Events: (default is +tp)\n");
printf("\n");
printf("\tt ... Thread creation and termination\n");
printf("\ts ... System calls\n");
printf("\ti ... Low-level IPC\n");
printf("\tp ... Protocol level\n");
printf("\n");
printf("Examples:\n");
printf("\ttrace +s /app/tetris\n");
printf("\ttrace +tsip -t 12\n");
}
 
static display_mask_t parse_display_mask(char *text)
{
display_mask_t dm;
char *c;
 
c = text;
 
while (*c) {
switch (*c) {
case 't': dm = dm | DM_THREAD; break;
case 's': dm = dm | DM_SYSCALL; break;
case 'i': dm = dm | DM_IPC; break;
case 'p': dm = dm | DM_SYSTEM | DM_USER; break;
default:
printf("Unexpected event type '%c'\n", *c);
exit(1);
}
 
++c;
}
 
return dm;
}
 
static int parse_args(int argc, char *argv[])
{
char *arg;
char *err_p;
 
task_id = 0;
 
--argc; ++argv;
 
while (argc > 0) {
arg = *argv;
if (arg[0] == '+') {
display_mask = parse_display_mask(&arg[1]);
} else if (arg[0] == '-') {
if (arg[1] == 't') {
/* Trace an already running task */
--argc; ++argv;
task_id = strtol(*argv, &err_p, 10);
if (*err_p) {
printf("Task ID syntax error\n");
print_syntax();
return -1;
}
} else {
printf("Uknown option '%s'\n", arg[0]);
print_syntax();
return -1;
}
} else {
break;
}
 
--argc; ++argv;
}
 
if (task_id != 0) {
if (argc == 0) return;
printf("Extra arguments\n");
print_syntax();
return -1;
}
 
if (argc < 1) {
printf("Missing argument\n");
print_syntax();
return -1;
}
 
/* Execute the specified command and trace the new task. */
printf("Spawning '%s' with arguments:\n", *argv);
{
char **cp = argv;
while (*cp) printf("'%s'\n", *cp++);
}
task_id = task_spawn(*argv, argv);
 
return 0;
}
 
int main(int argc, char *argv[])
{
printf("System Call / IPC Tracer\n");
 
display_mask = DM_THREAD | DM_SYSTEM | DM_USER;
 
if (parse_args(argc, argv) < 0)
return 1;
 
main_init();
trace_active_task(task_id);
 
return 0;
}
 
/** @}
*/
/branches/dynload/uspace/app/trace/trace.h
0,0 → 1,57
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup trace
* @{
*/
/** @file
*/
 
#ifndef TRACE_H_
#define TRACE_H_
 
/**
* Classes of events that can be displayed. Can be or-ed together.
*/
typedef enum {
DM_THREAD = 1, /**< Thread creation and termination events */
DM_SYSCALL = 2, /**< System calls */
DM_IPC = 4, /**< Low-level IPC */
DM_SYSTEM = 8, /**< Sysipc protocol */
DM_USER = 16 /**< User IPC protocols */
 
} display_mask_t;
 
/** Combination of events to print. */
extern display_mask_t display_mask;
 
#endif
 
/** @}
*/
/branches/dynload/uspace/app/trace/ipcp.c
0,0 → 1,334
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup trace
* @{
*/
/** @file
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <libadt/hash_table.h>
 
#include "ipc_desc.h"
#include "proto.h"
#include "trace.h"
#include "ipcp.h"
 
#define IPCP_CALLID_SYNC 0
 
typedef struct {
int phone_hash;
ipc_call_t question;
 
int call_hash;
 
link_t link;
} pending_call_t;
 
typedef struct {
int server;
proto_t *proto;
} connection_t;
 
#define MAX_PHONE 64
connection_t connections[MAX_PHONE];
int have_conn[MAX_PHONE];
 
#define PCALL_TABLE_CHAINS 32
hash_table_t pending_calls;
 
/*
* Pseudo-protocols
*/
proto_t *proto_system; /**< Protocol describing system IPC methods. */
proto_t *proto_unknown; /**< Protocol with no known methods. */
 
static hash_index_t pending_call_hash(unsigned long key[]);
static int pending_call_compare(unsigned long key[], hash_count_t keys,
link_t *item);
static void pending_call_remove_callback(link_t *item);
 
hash_table_operations_t pending_call_ops = {
.hash = pending_call_hash,
.compare = pending_call_compare,
.remove_callback = pending_call_remove_callback
};
 
 
static hash_index_t pending_call_hash(unsigned long key[])
{
// printf("pending_call_hash\n");
return key[0] % PCALL_TABLE_CHAINS;
}
 
static int pending_call_compare(unsigned long key[], hash_count_t keys,
link_t *item)
{
pending_call_t *hs;
 
// printf("pending_call_compare\n");
hs = hash_table_get_instance(item, pending_call_t, link);
 
return key[0] == hs->call_hash;
}
 
static void pending_call_remove_callback(link_t *item)
{
// printf("pending_call_remove_callback\n");
}
 
 
void ipcp_connection_set(int phone, int server, proto_t *proto)
{
if (phone <0 || phone >= MAX_PHONE) return;
connections[phone].server = server;
connections[phone].proto = proto;
have_conn[phone] = 1;
}
 
void ipcp_connection_clear(int phone)
{
have_conn[phone] = 0;
connections[phone].server = 0;
connections[phone].proto = NULL;
}
 
static void ipc_m_print(proto_t *proto, ipcarg_t method)
{
oper_t *oper;
 
/* Try system methods first */
oper = proto_get_oper(proto_system, method);
 
if (oper == NULL && proto != NULL) {
/* Not a system method, try the user protocol. */
oper = proto_get_oper(proto, method);
}
 
if (oper != NULL) {
printf("%s (%d)", oper->name, method);
return;
}
 
printf("%d", method);
}
 
void ipcp_init(void)
{
ipc_m_desc_t *desc;
oper_t *oper;
 
/*
* Create a pseudo-protocol 'unknown' that has no known methods.
*/
proto_unknown = proto_new("unknown");
 
/*
* Create a pseudo-protocol 'system' defining names of system IPC
* methods.
*/
proto_system = proto_new("system");
 
desc = ipc_methods;
while (desc->number != 0) {
oper = oper_new(desc->name);
proto_add_oper(proto_system, desc->number, oper);
 
++desc;
}
 
hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
}
 
void ipcp_cleanup(void)
{
proto_delete(proto_system);
hash_table_destroy(&pending_calls);
}
 
void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
{
pending_call_t *pcall;
proto_t *proto;
unsigned long key[1];
oper_t *oper;
 
if (have_conn[phone]) proto = connections[phone].proto;
else proto = NULL;
 
if ((display_mask & DM_IPC) != 0) {
printf("Call ID: 0x%x, phone: %d, proto: %s, method: ", hash,
phone, (proto ? proto->name : "n/a"));
ipc_m_print(proto, IPC_GET_METHOD(*call));
printf(" args: (%u, %u, %u, %u, %u)\n",
IPC_GET_ARG1(*call),
IPC_GET_ARG2(*call),
IPC_GET_ARG3(*call),
IPC_GET_ARG4(*call),
IPC_GET_ARG5(*call)
);
}
 
 
if ((display_mask & DM_USER) != 0) {
 
if (proto != NULL) {
oper = proto_get_oper(proto, IPC_GET_METHOD(*call));
} else {
oper = NULL;
}
 
if (oper != NULL) {
 
printf("%s(%d).%s", (proto ? proto->name : "n/a"),
phone, (oper ? oper->name : "unknown"));
 
printf("(%u, %u, %u, %u, %u)\n",
IPC_GET_ARG1(*call),
IPC_GET_ARG2(*call),
IPC_GET_ARG3(*call),
IPC_GET_ARG4(*call),
IPC_GET_ARG5(*call)
);
}
}
 
/* Store call in hash table for response matching */
 
pcall = malloc(sizeof(pending_call_t));
pcall->phone_hash = phone;
pcall->question = *call;
pcall->call_hash = hash;
 
key[0] = hash;
 
hash_table_insert(&pending_calls, key, &pcall->link);
}
 
static void parse_answer(ipc_callid_t hash, pending_call_t *pcall,
ipc_call_t *answer)
{
int phone;
ipcarg_t method;
ipcarg_t service;
int retval;
proto_t *proto;
int cphone;
 
// printf("parse_answer\n");
 
phone = pcall->phone_hash;
method = IPC_GET_METHOD(pcall->question);
retval = IPC_GET_RETVAL(*answer);
 
if ((display_mask & DM_IPC) != 0) {
printf("Response to 0x%x: retval=%d, args = (%u, %u, %u, %u, %u)\n",
hash, retval, IPC_GET_ARG1(*answer),
IPC_GET_ARG2(*answer), IPC_GET_ARG3(*answer),
IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer));
}
 
if ((display_mask & DM_USER) != 0) {
printf("-> %d\n", retval);
}
 
if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
/* Connected to a service (through NS) */
service = IPC_GET_ARG1(pcall->question);
proto = proto_get_by_srv(service);
if (proto == NULL) proto = proto_unknown;
 
cphone = IPC_GET_ARG5(*answer);
if ((display_mask & DM_SYSTEM) != 0) {
printf("Registering connection (phone %d, protocol: %s)\n", cphone,
proto->name);
}
ipcp_connection_set(cphone, 0, proto);
}
}
 
void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
{
link_t *item;
pending_call_t *pcall;
unsigned long key[1];
 
// printf("ipcp_call_in()\n");
/* printf("phone: %d, method: ", call->in_phone_hash);
ipc_m_print(IPC_GET_METHOD(*call));
printf(" args: (%u, %u, %u, %u, %u)\n",
IPC_GET_ARG1(*call),
IPC_GET_ARG2(*call),
IPC_GET_ARG3(*call),
IPC_GET_ARG4(*call),
IPC_GET_ARG5(*call)
);*/
 
if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
/* Not a response */
if ((display_mask & DM_IPC) != 0) {
printf("Not a response (hash %d)\n", hash);
}
return;
}
 
hash = hash & ~IPC_CALLID_ANSWERED;
key[0] = hash;
 
item = hash_table_find(&pending_calls, key);
if (item == NULL) return; // No matching question found
 
/*
* Response matched to question.
*/
pcall = hash_table_get_instance(item, pending_call_t, link);
hash_table_remove(&pending_calls, key, 1);
 
parse_answer(hash, pcall, call);
free(pcall);
}
 
void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
{
ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
ipcp_call_in(answer, IPCP_CALLID_SYNC);
}
 
void ipcp_hangup(int phone, int rc)
{
if ((display_mask & DM_SYSTEM) != 0) {
printf("Hang phone %d up -> %d\n", phone, rc);
ipcp_connection_clear(phone);
}
}
 
/** @}
*/
/branches/dynload/uspace/app/trace/proto.c
0,0 → 1,223
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup trace
* @{
*/
/** @file
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <ipc/ipc.h>
#include <libadt/hash_table.h>
 
#include "proto.h"
 
#define SRV_PROTO_TABLE_CHAINS 32
#define METHOD_OPER_TABLE_CHAINS 32
 
hash_table_t srv_proto;
 
typedef struct {
int srv;
proto_t *proto;
link_t link;
} srv_proto_t;
 
typedef struct {
ipcarg_t method;
oper_t *oper;
link_t link;
} method_oper_t;
 
static hash_index_t srv_proto_hash(unsigned long key[]);
static int srv_proto_compare(unsigned long key[], hash_count_t keys,
link_t *item);
static void srv_proto_remove_callback(link_t *item);
 
hash_table_operations_t srv_proto_ops = {
.hash = srv_proto_hash,
.compare = srv_proto_compare,
.remove_callback = srv_proto_remove_callback
};
 
static hash_index_t method_oper_hash(unsigned long key[]);
static int method_oper_compare(unsigned long key[], hash_count_t keys,
link_t *item);
static void method_oper_remove_callback(link_t *item);
 
hash_table_operations_t method_oper_ops = {
.hash = method_oper_hash,
.compare = method_oper_compare,
.remove_callback = method_oper_remove_callback
};
 
static hash_index_t srv_proto_hash(unsigned long key[])
{
return key[0] % SRV_PROTO_TABLE_CHAINS;
}
 
static int srv_proto_compare(unsigned long key[], hash_count_t keys,
link_t *item)
{
srv_proto_t *sp;
 
sp = hash_table_get_instance(item, srv_proto_t, link);
 
return key[0] == sp->srv;
}
 
static void srv_proto_remove_callback(link_t *item)
{
}
 
static hash_index_t method_oper_hash(unsigned long key[])
{
return key[0] % METHOD_OPER_TABLE_CHAINS;
}
 
static int method_oper_compare(unsigned long key[], hash_count_t keys,
link_t *item)
{
method_oper_t *mo;
 
mo = hash_table_get_instance(item, method_oper_t, link);
 
return key[0] == mo->method;
}
 
static void method_oper_remove_callback(link_t *item)
{
}
 
 
void proto_init(void)
{
hash_table_create(&srv_proto, SRV_PROTO_TABLE_CHAINS, 1,
&srv_proto_ops);
}
 
void proto_cleanup(void)
{
hash_table_destroy(&srv_proto);
}
 
void proto_register(int srv, proto_t *proto)
{
srv_proto_t *sp;
unsigned long key;
 
sp = malloc(sizeof(srv_proto_t));
sp->srv = srv;
sp->proto = proto;
key = srv;
 
hash_table_insert(&srv_proto, &key, &sp->link);
}
 
proto_t *proto_get_by_srv(int srv)
{
unsigned long key;
link_t *item;
srv_proto_t *sp;
 
key = srv;
item = hash_table_find(&srv_proto, &key);
if (item == NULL) return NULL;
 
sp = hash_table_get_instance(item, srv_proto_t, link);
return sp->proto;
}
 
static void proto_struct_init(proto_t *proto, char *name)
{
proto->name = name;
hash_table_create(&proto->method_oper, SRV_PROTO_TABLE_CHAINS, 1,
&method_oper_ops);
}
 
proto_t *proto_new(char *name)
{
proto_t *p;
 
p = malloc(sizeof(proto_t));
proto_struct_init(p, name);
 
return p;
}
 
void proto_delete(proto_t *proto)
{
free(proto);
}
 
void proto_add_oper(proto_t *proto, int method, oper_t *oper)
{
method_oper_t *mo;
unsigned long key;
 
mo = malloc(sizeof(method_oper_t));
mo->method = method;
mo->oper = oper;
key = method;
 
hash_table_insert(&proto->method_oper, &key, &mo->link);
}
 
oper_t *proto_get_oper(proto_t *proto, int method)
{
unsigned long key;
link_t *item;
method_oper_t *mo;
 
key = method;
item = hash_table_find(&proto->method_oper, &key);
if (item == NULL) return NULL;
 
mo = hash_table_get_instance(item, method_oper_t, link);
return mo->oper;
}
 
static void oper_struct_init(oper_t *oper, char *name)
{
oper->name = name;
}
 
oper_t *oper_new(char *name)
{
oper_t *o;
 
o = malloc(sizeof(oper_t));
oper_struct_init(o, name);
 
return o;
}
 
/** @}
*/
/branches/dynload/uspace/app/trace/proto.h
0,0 → 1,71
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup trace
* @{
*/
/** @file
*/
 
#ifndef PROTO_H_
#define PROTO_H_
 
#include <libadt/hash_table.h>
 
typedef struct {
char *name;
} oper_t;
 
typedef struct {
/** Protocol name */
char *name;
 
/** Maps method number to operation */
hash_table_t method_oper;
} proto_t;
 
/* Maps service number to protocol */
extern hash_table_t srv_proto;
 
void proto_init(void);
void proto_cleanup(void);
 
void proto_register(int srv, proto_t *proto);
proto_t *proto_get_by_srv(int srv);
proto_t *proto_new(char *name);
void proto_delete(proto_t *proto);
void proto_add_oper(proto_t *proto, int method, oper_t *oper);
oper_t *proto_get_oper(proto_t *proto, int method);
 
oper_t *oper_new(char *name);
 
 
#endif
 
/** @}
*/
/branches/dynload/uspace/app/trace/ipc_desc.h
0,0 → 1,48
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup trace
* @{
*/
/** @file
*/
 
#ifndef IPC_DESC_H_
#define IPC_DESC_H_
 
typedef struct {
int number;
char *name;
} ipc_m_desc_t;
 
extern ipc_m_desc_t ipc_methods[];
 
#endif
 
/** @}
*/
/branches/dynload/uspace/app/trace/ipcp.h
0,0 → 1,55
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup trace
* @{
*/
/** @file
*/
 
#ifndef IPCP_H_
#define IPCP_H_
 
#include <ipc/ipc.h>
#include "proto.h"
 
void ipcp_init(void);
void ipcp_cleanup(void);
 
void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash);
void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer);
void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash);
void ipcp_hangup(int phone, int rc);
 
void ipcp_connection_set(int phone, int server, proto_t *proto);
void ipcp_connection_clear(int phone);
 
#endif
 
/** @}
*/
/branches/dynload/uspace/app/trace/errors.h
0,0 → 1,48
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup trace
* @{
*/
/** @file
*/
 
#ifndef ERRORS_H_
#define ERRORS_H_
 
typedef struct {
char *name; /**< Error value name (Exx) */
char *desc; /**< Error description */
} err_desc_t;
 
extern const err_desc_t err_desc[];
 
#endif
 
/** @}
*/
/branches/dynload/uspace/app/trace/syscalls.h
0,0 → 1,56
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup trace
* @{
*/
/** @file
*/
 
#ifndef SYSCALLS_H_
#define SYSCALLS_H_
 
typedef enum {
RV_INTEGER,
RV_HASH,
RV_ERRNO,
RV_INT_ERRNO
} rv_type_t;
 
typedef struct {
char *name;
int n_args;
rv_type_t rv_type;
} sc_desc_t;
 
extern const sc_desc_t syscall_desc[];
 
#endif
 
/** @}
*/
/branches/dynload/uspace/app/trace/ipc_desc.c
0,0 → 1,58
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup trace
* @{
*/
/** @file
*/
 
#include <stdlib.h>
#include <ipc/ipc.h>
#include "ipc_desc.h"
 
ipc_m_desc_t ipc_methods[] = {
/* System methods */
{ IPC_M_CONNECT_TO_ME, "CONNECT_TO_ME" },
{ IPC_M_CONNECT_ME_TO, "CONNECT_ME_TO" },
{ IPC_M_PHONE_HUNGUP, "PHONE_HUNGUP" },
{ IPC_M_SHARE_OUT, "SHARE_OUT" },
{ IPC_M_SHARE_IN, "SHARE_IN" },
{ IPC_M_DATA_WRITE, "DATA_WRITE" },
{ IPC_M_DATA_READ, "DATA_READ" },
{ IPC_M_DEBUG_ALL, "DEBUG_ALL" },
 
/* Well-known methods */
{ IPC_M_PING, "PING" },
 
/* Terminating entry */
{ 0, NULL }
};
 
/** @}
*/
/branches/dynload/uspace/app/trace/Makefile
0,0 → 1,78
#
# Copyright (c) 2005 Martin Decky
# 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.
#
 
## Setup toolchain
#
 
LIBC_PREFIX = ../../lib/libc
SOFTINT_PREFIX = ../../lib/softint
include $(LIBC_PREFIX)/Makefile.toolchain
 
CFLAGS += -I../../srv/kbd/include
 
LIBS = $(LIBC_PREFIX)/libc.a
 
## Sources
#
 
OUTPUT = trace
SOURCES = trace.c \
syscalls.c \
ipcp.c \
ipc_desc.c \
proto.c \
errors.c
 
OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
 
.PHONY: all clean depend disasm
 
all: $(OUTPUT) disasm
 
-include Makefile.depend
 
clean:
-rm -f $(OUTPUT) $(OBJECTS) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend
 
depend:
$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
 
$(OUTPUT): $(OBJECTS) $(LIBS)
$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
 
disasm:
$(OBJDUMP) -d $(OUTPUT) >$(OUTPUT).disasm
 
%.o: %.S
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
 
%.o: %.s
$(AS) $(AFLAGS) $< -o $@
 
%.o: %.c
$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
/branches/dynload/uspace/app/trace/errors.c
0,0 → 1,61
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup trace
* @{
*/
/** @file
*/
 
#include <errno.h>
#include "errors.h"
 
const err_desc_t err_desc[] = {
[-EOK] = { "EOK", "No error" },
[-ENOENT] = { "ENOENT", "No such entry" },
[-ENOMEM] = { "ENOMEM", "Not enough memory" },
[-ELIMIT] = { "ELIMIT", "Limit exceeded" },
[-EREFUSED] = { "EREFUSED", "Connection refused" },
 
[-EFORWARD] = { "EFORWARD", "Forward error" },
[-EPERM] = { "EPERM", "Permission denied" },
[-EHANGUP] = { "EHANGUP", "Answerbox closed connection" },
[-EEXISTS] = { "EEXISTS", "Entry already exists" },
[-EBADMEM] = { "EBADMEM", "Bad memory pointer" },
 
[-ENOTSUP] = { "ENOTSUP", "Not supported" },
[-EADDRNOTAVAIL] = { "EADDRNOTAVAIL", "Address not available." },
[-ETIMEOUT] = { "ETIMEOUT", "Timeout expired" },
[-EINVAL] = { "EINVAL", "Invalid value" },
[-EBUSY] = { "EBUSY", "Resource is busy" },
 
[-EOVERFLOW] = { "EOVERFLOW", "The result does not fit its size." }
};
 
/** @}
*/
/branches/dynload/uspace/app/trace/syscalls.c
0,0 → 1,79
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup trace
* @{
*/
/** @file
*/
 
#include <kernel/syscall/syscall.h>
#include "syscalls.h"
 
const sc_desc_t syscall_desc[] = {
[SYS_KLOG] ={ "klog", 3, RV_INT_ERRNO },
[SYS_TLS_SET] = { "tls_set", 1, RV_ERRNO },
[SYS_THREAD_CREATE] = { "thread_create", 3, RV_ERRNO },
[SYS_THREAD_EXIT] = { "thread_exit", 1, RV_ERRNO },
[SYS_THREAD_GET_ID] = { "thread_get_id", 1, RV_ERRNO },
 
[SYS_TASK_GET_ID] = { "task_get_id", 1, RV_ERRNO },
[SYS_FUTEX_SLEEP] = { "futex_sleep_timeout", 3, RV_ERRNO },
[SYS_FUTEX_WAKEUP] = { "futex_wakeup", 1, RV_ERRNO },
 
[SYS_AS_AREA_CREATE] = { "as_area_create", 3, RV_ERRNO },
[SYS_AS_AREA_RESIZE] = { "as_area_resize", 3, RV_ERRNO },
[SYS_AS_AREA_DESTROY] = { "as_area_destroy", 1, RV_ERRNO },
 
[SYS_IPC_CALL_SYNC_FAST] = { "ipc_call_sync_fast", 6, RV_ERRNO },
[SYS_IPC_CALL_SYNC_SLOW] = { "ipc_call_sync_slow", 3, RV_ERRNO },
[SYS_IPC_CALL_ASYNC_FAST] = { "ipc_call_async_fast", 6, RV_HASH },
[SYS_IPC_CALL_ASYNC_SLOW] = { "ipc_call_async_slow", 2, RV_HASH },
 
[SYS_IPC_ANSWER_FAST] = { "ipc_answer_fast", 6, RV_ERRNO },
[SYS_IPC_ANSWER_SLOW] = { "ipc_answer_slow", 2, RV_ERRNO },
[SYS_IPC_FORWARD_FAST] = { "ipc_forward_fast", 6, RV_ERRNO },
[SYS_IPC_WAIT] = { "ipc_wait_for_call", 3, RV_HASH },
[SYS_IPC_HANGUP] = { "ipc_hangup", 1, RV_ERRNO },
[SYS_IPC_REGISTER_IRQ] = { "ipc_register_irq", 4, RV_ERRNO },
[SYS_IPC_UNREGISTER_IRQ] = { "ipc_unregister_irq", 2, RV_ERRNO },
 
[SYS_CAP_GRANT] = { "cap_grant", 2, RV_ERRNO },
[SYS_CAP_REVOKE] = { "cap_revoke", 2, RV_ERRNO },
[SYS_PHYSMEM_MAP] = { "physmem_map", 4, RV_ERRNO },
[SYS_IOSPACE_ENABLE] = { "iospace_enable", 1, RV_ERRNO },
[SYS_PREEMPT_CONTROL] = { "preempt_control", 1, RV_ERRNO },
 
[SYS_SYSINFO_VALID] = { "sysinfo_valid", 2, RV_HASH },
[SYS_SYSINFO_VALUE] = { "sysinfo_value", 2, RV_HASH },
[SYS_DEBUG_ENABLE_CONSOLE] = { "debug_enable_console", 0, RV_ERRNO },
[SYS_IPC_CONNECT_KBOX] = { "ipc_connect_kbox", 1, RV_ERRNO }
};
 
/** @}
*/
/branches/dynload/uspace/lib/libc/include/string.h
64,6 → 64,9
extern long int strtol(const char *, char **, int);
extern unsigned long strtoul(const char *, char **, int);
 
extern char * strtok_r(char *, const char *, char **);
extern char * strtok(char *, const char *);
 
#endif
 
/** @}
/branches/dynload/uspace/lib/libc/include/udebug.h
0,0 → 1,58
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
#ifndef LIBC_UDEBUG_H_
#define LIBC_UDEBUG_H_
 
#include <kernel/udebug/udebug.h>
#include <sys/types.h>
#include <libarch/types.h>
 
typedef sysarg_t thash_t;
 
int udebug_begin(int phoneid);
int udebug_end(int phoneid);
int udebug_set_evmask(int phoneid, udebug_evmask_t mask);
int udebug_thread_read(int phoneid, void *buffer, size_t n,
size_t *copied, size_t *needed);
int udebug_mem_read(int phoneid, void *buffer, uintptr_t addr, size_t n);
int udebug_args_read(int phoneid, thash_t tid, sysarg_t *buffer);
int udebug_go(int phoneid, thash_t tid, udebug_event_t *ev_type,
sysarg_t *val0, sysarg_t *val1);
int udebug_stop(int phoneid, thash_t tid);
 
#endif
 
/** @}
*/
/branches/dynload/uspace/lib/libc/include/ipc/ipc.h
288,6 → 288,10
extern int ipc_data_write_receive(ipc_callid_t *callid, size_t *size);
extern int ipc_data_write_finalize(ipc_callid_t callid, void *dst, size_t size);
 
#include <task.h>
 
extern int ipc_connect_kbox(task_id_t id);
 
#endif
 
/** @}
/branches/dynload/uspace/lib/libc/include/ipc/loader.h
39,6 → 39,7
 
typedef enum {
LOADER_HELLO = IPC_FIRST_USER_METHOD,
LOADER_GET_TASKID,
LOADER_SET_PATHNAME,
LOADER_SET_ARGS,
LOADER_RUN
/branches/dynload/uspace/lib/libc/generic/task.c
133,6 → 133,7
 
char *pa;
size_t pa_len;
task_id_t task_id;
 
pa = absolutize(path, &pa_len);
if (!pa)
151,6 → 152,18
if (rc != EOK)
return 0;
 
/* Get task ID. */
req = async_send_0(phone_id, LOADER_GET_TASKID, &answer);
rc = ipc_data_read_start(phone_id, &task_id, sizeof(task_id));
if (rc != EOK) {
async_wait_for(req, NULL);
goto error;
}
 
async_wait_for(req, &retval);
if (retval != EOK)
goto error;
 
/* Send program pathname */
req = async_send_0(phone_id, LOADER_SET_PATHNAME, &answer);
rc = ipc_data_write_start(phone_id, (void *)pa, pa_len);
175,7 → 188,7
 
/* Success */
ipc_hangup(phone_id);
return 1;
return task_id;
 
/* Error exit */
error:
/branches/dynload/uspace/lib/libc/generic/string.c
1,5 → 1,7
/*
* Copyright (c) 2005 Martin Decky
* Copyright (C) 1998 by Wes Peters <wes@softweyr.com>
* Copyright (c) 1988, 1993 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
396,5 → 398,52
return (char *) memcpy(ret, s1, len);
}
 
/* Ported from FBSD strtok.c 8.1 (Berkeley) 6/4/93 */
char * strtok_r(char *s, const char *delim, char **last)
{
char *spanp, *tok;
int c, sc;
 
if (s == NULL && (s = *last) == NULL)
return (NULL);
 
cont:
c = *s++;
for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
if (c == sc)
goto cont;
}
 
if (c == 0) { /* no non-delimiter characters */
*last = NULL;
return (NULL);
}
 
tok = s - 1;
 
for (;;) {
c = *s++;
spanp = (char *)delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = '\0';
*last = s;
return (tok);
}
} while (sc != 0);
}
}
 
/* Ported from FBSD strtok.c 8.1 (Berkeley) 6/4/93 */
char * strtok(char *s, const char *delim)
{
static char *last;
 
return (strtok_r(s, delim, &last));
}
 
/** @}
*/
/branches/dynload/uspace/lib/libc/generic/ipc.c
909,6 → 909,18
{
return ipc_answer_2(callid, EOK, (ipcarg_t) dst, (ipcarg_t) size);
}
 
#include <kernel/syscall/sysarg64.h>
/** Connect to a task specified by id.
*/
int ipc_connect_kbox(task_id_t id)
{
sysarg64_t arg;
 
arg.value = (unsigned long long) id;
 
return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) &arg);
}
/** @}
*/
/branches/dynload/uspace/lib/libc/generic/udebug.c
0,0 → 1,92
/*
* Copyright (c) 2008 Jiri Svoboda
* 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.
*/
 
/** @addtogroup libc
* @{
*/
/** @file
*/
 
#include <udebug.h>
#include <sys/types.h>
#include <syscall.h>
#include <ipc/ipc.h>
#include <async.h>
 
int udebug_begin(int phoneid)
{
return async_req_1_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_BEGIN);
}
 
int udebug_end(int phoneid)
{
return async_req_1_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_END);
}
 
int udebug_set_evmask(int phoneid, udebug_evmask_t mask)
{
return async_req_2_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_SET_EVMASK,
mask);
}
 
int udebug_thread_read(int phoneid, void *buffer, size_t n,
size_t *copied, size_t *needed)
{
unsigned dest_addr;
 
return async_req_3_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_THREAD_READ,
(sysarg_t)buffer, n, &dest_addr, copied, needed);
}
 
int udebug_mem_read(int phoneid, void *buffer, uintptr_t addr, size_t n)
{
return async_req_4_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_MEM_READ,
(sysarg_t)buffer, addr, n);
}
 
int udebug_args_read(int phoneid, thash_t tid, sysarg_t *buffer)
{
return async_req_3_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_ARGS_READ,
tid, (sysarg_t)buffer);
}
 
int udebug_go(int phoneid, thash_t tid, udebug_event_t *ev_type,
sysarg_t *val0, sysarg_t *val1)
{
return async_req_2_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_GO,
tid, (sysarg_t)ev_type, (sysarg_t)val0, (sysarg_t)val1);
}
 
int udebug_stop(int phoneid, thash_t tid)
{
return async_req_2_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_STOP,
tid);
}
 
/** @}
*/
/branches/dynload/uspace/lib/libc/Makefile
80,6 → 80,7
generic/err.c \
generic/stdlib.c \
generic/mman.c \
generic/udebug.c \
generic/vfs/vfs.c \
generic/vfs/canonify.c
 
/branches/dynload/uspace/srv/loader/main.c
77,6 → 77,27
/** Buffer holding all arguments */
static char *arg_buf = NULL;
 
static int loader_get_taskid(ipc_callid_t rid, ipc_call_t *request)
{
ipc_callid_t callid;
task_id_t task_id;
size_t len;
 
task_id = task_get_id();
 
if (!ipc_data_read_receive(&callid, &len)) {
ipc_answer_0(callid, EINVAL);
ipc_answer_0(rid, EINVAL);
return;
}
 
if (len > sizeof(task_id)) len = sizeof(task_id);
 
ipc_data_write_finalize(callid, &task_id, len);
ipc_answer_0(rid, EOK);
}
 
 
/** Receive a call setting pathname of the program to execute.
*
* @param rid
276,6 → 297,9
// printf("received call from phone %d, method=%d\n",
// call.in_phone_hash, IPC_GET_METHOD(call));
switch (IPC_GET_METHOD(call)) {
case LOADER_GET_TASKID:
loader_get_taskid(callid, &call);
continue;
case LOADER_SET_PATHNAME:
loader_set_pathname(callid, &call);
continue;
/branches/dynload/uspace/Makefile
51,6 → 51,7
app/tetris \
app/tester \
app/dltest \
app/trace \
app/klog \
app/init \
app/bdsh
/branches/dynload/boot/arch/sparc64/loader/Makefile
94,12 → 94,14
COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat
endif
 
RD_TASKS = \
RD_SRVS = \
$(USPACEDIR)/srv/fb/fb \
$(USPACEDIR)/srv/kbd/kbd \
$(USPACEDIR)/srv/console/console \
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
$(USPACEDIR)/srv/fs/fat/fat \
$(USPACEDIR)/srv/fs/fat/fat
 
RD_APPS = \
$(USPACEDIR)/app/tetris/tetris \
$(USPACEDIR)/app/tester/tester \
$(USPACEDIR)/app/bdsh/bdsh \
121,15 → 123,21
-makedepend $(DEFS) $(CFLAGS) -f - $(SOURCES) > Makefile.depend 2> /dev/null
 
clean:
-for task in $(RD_TASKS) ; do \
rm -f $(USPACEDIR)/dist/sbin/`basename $$task` ; \
-for file in $(RD_SRVS) ; do \
rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \
done
-for file in $(RD_APPS) ; do \
rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \
done
-rm -f _components.h _components.c _link.ld $(COMPONENT_OBJECTS) $(OBJECTS) initrd.img image.boot image.map image.disasm Makefile.depend
 
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) $(RD_TASKS) _link.ld.in
for task in $(RD_TASKS) ; do \
cp $$task $(USPACEDIR)/dist/sbin/ ; \
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) $(RD_SRVS) $(RD_APPS) _link.ld.in
for file in $(RD_SRVS) ; do \
cp $$file $(USPACEDIR)/dist/srv/ ; \
done
for file in $(RD_APPS) ; do \
cp $$file $(USPACEDIR)/dist/app/ ; \
done
ifeq ($(RDFMT),tmpfs)
../../../../tools/mktmpfs.py $(USPACEDIR)/dist/ initrd.fs
endif
/branches/dynload/boot/arch/ia64/loader/Makefile
98,6 → 98,7
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
$(USPACEDIR)/srv/devmap/devmap \
$(USPACEDIR)/app/cli/cli \
$(USPACEDIR)/app/trace/trace \
$(USPACEDIR)/app/klog/klog
 
OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
/branches/dynload/boot/arch/arm32/loader/Makefile
96,14 → 96,17
COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat
endif
 
RD_TASKS = \
RD_SRVS = \
$(USPACEDIR)/srv/fb/fb \
$(USPACEDIR)/srv/kbd/kbd \
$(USPACEDIR)/srv/console/console \
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
$(USPACEDIR)/srv/fs/fat/fat \
$(USPACEDIR)/srv/fs/fat/fat
 
RD_APPS = \
$(USPACEDIR)/app/tetris/tetris \
$(USPACEDIR)/app/tester/tester \
$(USPACEDIR)/app/trace/trace \
$(USPACEDIR)/app/klog/klog \
$(USPACEDIR)/app/bdsh/bdsh
 
123,15 → 126,21
-makedepend $(DEFS) $(CFLAGS) -f - $(SOURCES) > Makefile.depend 2> /dev/null
 
clean:
-for task in $(RD_TASKS) ; do \
rm -f $(USPACEDIR)/dist/sbin/`basename $$task` ; \
-for file in $(RD_SRVS) ; do \
rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \
done
-for file in $(RD_APPS) ; do \
rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \
done
-rm -f _components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o $(OBJECTS) initrd.img image.boot Makefile.depend
 
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) _link.ld.in
for task in $(RD_TASKS) ; do \
cp $$task $(USPACEDIR)/dist/sbin/ ; \
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) $(RD_SRVS) $(RD_APPS) _link.ld.in
for file in $(RD_SRVS) ; do \
cp $$file $(USPACEDIR)/dist/srv/ ; \
done
for file in $(RD_APPS) ; do \
cp $$file $(USPACEDIR)/dist/app/ ; \
done
ifeq ($(RDFMT),tmpfs)
../../../../tools/mktmpfs.py $(USPACEDIR)/dist/ initrd.fs
endif
/branches/dynload/boot/arch/ppc32/loader/Makefile
91,15 → 91,18
COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat
endif
 
RD_TASKS = \
RD_SRVS = \
$(USPACEDIR)/srv/fb/fb \
$(USPACEDIR)/srv/kbd/kbd \
$(USPACEDIR)/srv/console/console \
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
$(USPACEDIR)/srv/fs/fat/fat \
$(USPACEDIR)/srv/fs/fat/fat
 
RD_APPS = \
$(USPACEDIR)/app/tetris/tetris \
$(USPACEDIR)/app/tester/tester \
$(USPACEDIR)/app/dltest/dltest \
$(USPACEDIR)/app/trace/trace \
$(USPACEDIR)/app/klog/klog \
$(USPACEDIR)/app/bdsh/bdsh
 
123,21 → 126,27
-makedepend $(DEFS) $(CFLAGS) -f - $(SOURCES) > Makefile.depend 2> /dev/null
 
clean:
-for task in $(RD_TASKS) ; do \
rm -f $(USPACEDIR)/dist/sbin/`basename $$task` ; \
-for file in $(RD_SRVS) ; do \
rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \
done
-for lib in $(RD_LIBS) ; do \
rm -f $(USPACEDIR)/dist/lib/`basename $$lib` ; \
done
-for file in $(RD_APPS) ; do \
rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \
done
-rm -f _components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o $(OBJECTS) initrd.img image.boot Makefile.depend
 
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) $(RD_TASKS) $(RD_LIBS) _link.ld.in
for task in $(RD_TASKS) ; do \
cp $$task $(USPACEDIR)/dist/sbin/ ; \
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) $(RD_SRVS) $(RD_LIBS) $(RD_APPS) _link.ld.in
for file in $(RD_SRVS) ; do \
cp $$file $(USPACEDIR)/dist/srv/ ; \
done
for lib in $(RD_LIBS) ; do \
cp $$lib $(USPACEDIR)/dist/lib/ ; \
done
for file in $(RD_APPS) ; do \
cp $$file $(USPACEDIR)/dist/app/ ; \
done
ifeq ($(RDFMT),tmpfs)
../../../../tools/mktmpfs.py $(USPACEDIR)/dist/ initrd.fs
endif
/branches/dynload/boot/arch/amd64/Makefile.inc
40,21 → 40,24
INIT_TASKS += $(USPACEDIR)/srv/fs/fat/fat
endif
 
RD_TASKS = \
RD_SRVS = \
$(USPACEDIR)/srv/pci/pci \
$(USPACEDIR)/srv/fb/fb \
$(USPACEDIR)/srv/kbd/kbd \
$(USPACEDIR)/srv/console/console \
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
$(USPACEDIR)/srv/fs/fat/fat
 
RD_APPS = \
$(USPACEDIR)/app/tetris/tetris \
$(USPACEDIR)/app/tester/tester \
$(USPACEDIR)/app/trace/trace \
$(USPACEDIR)/app/klog/klog \
$(USPACEDIR)/app/bdsh/bdsh \
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
$(USPACEDIR)/srv/fs/fat/fat
$(USPACEDIR)/app/bdsh/bdsh
 
build: $(BASE)/image.iso
 
$(BASE)/image.iso: arch/$(ARCH)/grub/stage2_eltorito arch/$(ARCH)/grub/menu.lst $(KERNELDIR)/kernel.bin $(INIT_TASKS) $(RD_TASKS)
$(BASE)/image.iso: arch/$(ARCH)/grub/stage2_eltorito arch/$(ARCH)/grub/menu.lst $(KERNELDIR)/kernel.bin $(INIT_TASKS) $(RD_SRVS) $(RD_APPS)
mkdir -p arch/$(ARCH)/iso/boot/grub
cp arch/$(ARCH)/grub/stage2_eltorito arch/$(ARCH)/iso/boot/grub/
ifneq ($(RDFMT),tmpfs)
67,9 → 70,12
for task in $(INIT_TASKS) ; do \
cp $$task arch/$(ARCH)/iso/boot/ ; \
done
for task in $(RD_TASKS) ; do \
cp $$task $(USPACEDIR)/dist/sbin/ ; \
for file in $(RD_SRVS) ; do \
cp $$file $(USPACEDIR)/dist/srv/ ; \
done
for file in $(RD_APPS) ; do \
cp $$file $(USPACEDIR)/dist/app/ ; \
done
ifeq ($(RDFMT),tmpfs)
$(BASE)/tools/mktmpfs.py $(USPACEDIR)/dist/ arch/$(ARCH)/iso/boot/initrd.fs
endif
81,8 → 87,11
mkisofs -J -r -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -o $(BASE)/image.iso arch/$(ARCH)/iso/
 
clean:
-for task in $(RD_TASKS) ; do \
rm -f $(USPACEDIR)/dist/sbin/`basename $$task` ; \
-for file in $(RD_SRVS) ; do \
rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \
done
-for file in $(RD_APPS) ; do \
rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \
done
-rm -fr arch/$(ARCH)/iso
-rm -f $(BASE)/image.iso
/branches/dynload/boot/arch/ppc64/loader/Makefile
89,6 → 89,7
$(USPACEDIR)/app/init/init \
$(USPACEDIR)/app/tetris/tetris \
$(USPACEDIR)/app/tester/tester \
$(USPACEDIR)/app/trace/trace \
$(USPACEDIR)/app/klog/klog
 
OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
/branches/dynload/boot/arch/mips32/loader/Makefile
96,18 → 96,20
COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat
endif
 
RD_TASKS = \
RD_SRVS = \
$(USPACEDIR)/srv/fb/fb \
$(USPACEDIR)/srv/kbd/kbd \
$(USPACEDIR)/srv/console/console \
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
$(USPACEDIR)/srv/fs/fat/fat \
$(USPACEDIR)/srv/fs/fat/fat
 
RD_APPS = \
$(USPACEDIR)/app/tetris/tetris \
$(USPACEDIR)/app/tester/tester \
$(USPACEDIR)/app/trace/trace \
$(USPACEDIR)/app/bdsh/bdsh \
$(USPACEDIR)/app/klog/klog
 
 
OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
COMPONENT_OBJECTS := $(addsuffix .o,$(basename $(notdir $(COMPONENTS))))
 
124,15 → 126,21
-makedepend $(DEFS) $(CFLAGS) -f - $(SOURCES) > Makefile.depend 2> /dev/null
 
clean:
-for task in $(RD_TASKS) ; do \
rm -f $(USPACEDIR)/dist/sbin/`basename $$task` ; \
-for file in $(RD_SRVS) ; do \
rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \
done
-for file in $(RD_APPS) ; do \
rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \
done
-rm -f _components.h _components.c _link.ld _link.ld.in $(COMPONENT_OBJECTS) initrd.o $(OBJECTS) initrd.img image.boot Makefile.depend
 
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) _link.ld.in
for task in $(RD_TASKS) ; do \
cp $$task $(USPACEDIR)/dist/sbin/ ; \
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) $(RD_SRVS) $(RD_APPS) _link.ld.in
for file in $(RD_SRVS) ; do \
cp $$file $(USPACEDIR)/dist/srv/ ; \
done
for file in $(RD_APPS) ; do \
cp $$file $(USPACEDIR)/dist/app/ ; \
done
ifeq ($(RDFMT),tmpfs)
../../../../tools/mktmpfs.py $(USPACEDIR)/dist/ initrd.fs
endif
/branches/dynload/boot/arch/ia32/Makefile.inc
40,15 → 40,18
INIT_TASKS += $(USPACEDIR)/srv/fs/fat/fat
endif
 
RD_TASKS = \
RD_SRVS = \
$(USPACEDIR)/srv/pci/pci \
$(USPACEDIR)/srv/fb/fb \
$(USPACEDIR)/srv/kbd/kbd \
$(USPACEDIR)/srv/console/console \
$(USPACEDIR)/srv/fs/fat/fat \
$(USPACEDIR)/srv/fs/fat/fat
 
RD_APPS = \
$(USPACEDIR)/app/tetris/tetris \
$(USPACEDIR)/app/tester/tester \
$(USPACEDIR)/app/dltest/dltest \
$(USPACEDIR)/app/trace/trace \
$(USPACEDIR)/app/klog/klog \
$(USPACEDIR)/app/bdsh/bdsh
 
58,7 → 61,7
 
build: $(BASE)/image.iso
 
$(BASE)/image.iso: arch/$(ARCH)/grub/stage2_eltorito arch/$(ARCH)/grub/menu.lst $(KERNELDIR)/kernel.bin $(INIT_TASKS) $(RD_TASKS) $(RD_LIBS)
$(BASE)/image.iso: arch/$(ARCH)/grub/stage2_eltorito arch/$(ARCH)/grub/menu.lst $(KERNELDIR)/kernel.bin $(INIT_TASKS) $(RD_SRVS) $(RD_LIBS) $(RD_APPS)
mkdir -p arch/$(ARCH)/iso/boot/grub
cp arch/$(ARCH)/grub/stage2_eltorito arch/$(ARCH)/iso/boot/grub/
ifneq ($(RDFMT),tmpfs)
71,12 → 74,15
for task in $(INIT_TASKS) ; do \
cp $$task arch/$(ARCH)/iso/boot/ ; \
done
for task in $(RD_TASKS) ; do \
cp $$task $(USPACEDIR)/dist/sbin/ ; \
for file in $(RD_SRVS) ; do \
cp $$file $(USPACEDIR)/dist/srv/ ; \
done
for lib in $(RD_LIBS) ; do \
cp $$lib $(USPACEDIR)/dist/lib/ ; \
done
for file in $(RD_APPS) ; do \
cp $$file $(USPACEDIR)/dist/app/ ; \
done
ifeq ($(RDFMT),tmpfs)
$(BASE)/tools/mktmpfs.py $(USPACEDIR)/dist/ arch/$(ARCH)/iso/boot/initrd.fs
endif
88,11 → 94,14
mkisofs -J -r -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -o $(BASE)/image.iso arch/$(ARCH)/iso/
 
clean:
-for task in $(RD_TASKS) ; do \
rm -f $(USPACEDIR)/dist/sbin/`basename $$task` ; \
-for file in $(RD_SRVS) ; do \
rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \
done
-for lib in $(RD_LIBS) ; do \
rm -f $(USPACEDIR)/dist/lib/`basename $$lib` ; \
done
-for file in $(RD_APPS) ; do \
rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \
done
-rm -fr arch/$(ARCH)/iso
-rm -f $(BASE)/image.iso