#include "kernel/panic.h" #include #include #include #include #include #include #include #include #include #include static volatile bool initial_continue = false; static volatile bool debug_enabled = false; static spin_lock_t debug_io_lock = SPIN_LOCK_INIT; static enum mxdbg_status read_remote( struct mxdbg_host *host, void *buf, size_t count, size_t *nr_read) { debug_read(buf, count, nr_read); return MXDBG_SUCCESS; } static enum mxdbg_status write_remote( struct mxdbg_host *host, const void *buf, size_t count, size_t *nr_written) { spin_lock(&debug_io_lock); debug_write(buf, count, nr_written); spin_unlock(&debug_io_lock); return MXDBG_SUCCESS; } static enum mxdbg_status identify( struct mxdbg_host *host, enum mxdbg_identity_key key, void *out, size_t max) { switch (key) { case MXDBG_IDENTITY_KERNEL_NAME: snprintf(out, max, "%s", KERNEL_NAME); break; case MXDBG_IDENTITY_KERNEL_VERSION: snprintf(out, max, "%s", KERNEL_VERSION); break; case MXDBG_IDENTITY_KERNEL_ARCH: snprintf(out, max, "%s", KERNEL_ARCH); break; default: return MXDBG_ERR_INVALID_ARGUMENT; } return MXDBG_SUCCESS; } static enum mxdbg_status identify_task( struct mxdbg_host *host, tid_t tid, enum mxdbg_identity_key key, void *out, size_t max) { struct task *task = task_from_tid(tid); if (!task) { return MXDBG_ERR_INVALID_ARGUMENT; } switch (key) { case MXDBG_IDENTITY_TASK_NAME: snprintf(out, max, "%s", task->t_name); break; case MXDBG_IDENTITY_TASK_PARENT: *(uint16_t *)out = task->t_parent ? task->t_parent->t_id : -1; break; case MXDBG_IDENTITY_TASK_NR_THREADS: *(uint16_t *)out = queue_length(&task->t_threads); break; default: return MXDBG_ERR_INVALID_ARGUMENT; } return MXDBG_SUCCESS; } static enum mxdbg_status resume(struct mxdbg_host *host) { initial_continue = true; return MXDBG_SUCCESS; } static struct mxdbg_host dbg_host = { .read_remote = read_remote, .write_remote = write_remote, .identify = identify, .identify_task = identify_task, .resume = resume, }; static void debugger(void) { ml_int_enable(); while (1) { mxdbg_host_handle_request(&dbg_host); } } kern_status_t debug_await(void) { debug_enabled = true; printk("debug: waiting for connection..."); while (!initial_continue) { mxdbg_host_handle_request(&dbg_host); } return KERN_OK; } kern_status_t debug_create_task(void) { struct task *kernel_task = get_current_task(); struct thread *debug_thread = task_create_thread(kernel_task); thread_init_kernel(debug_thread, (virt_addr_t)debugger); schedule_thread_on_cpu(debug_thread); put_current_task(kernel_task); return KERN_OK; } kern_status_t debug_event_task_created(tid_t id) { if (!debug_enabled) { return KERN_OK; } struct mxdbg_packet_event ev = {0}; mxdbg_packet_init(&ev.ev_base, sizeof ev, MXDBG_PACKET_EVENT, 0); ev.ev_type = MXDBG_EVENT_TASK_CREATED; ev.ev_task = id; size_t w; write_remote(&dbg_host, &ev, sizeof ev, &w); return KERN_OK; } kern_status_t debug_event_task_started(void) { return KERN_OK; } kern_status_t debug_event_task_stopped(void) { return KERN_OK; } kern_status_t debug_event_task_destroyed(void) { return KERN_OK; }