Subversion Repositories HelenOS

Rev

Rev 2841 | Rev 2848 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2813 svoboda 1
/** @addtogroup generic
2
 * @{
3
 */
4
 
5
/**
6
 * @file
7
 * @brief   Tdebug.
8
 */
9
 
10
#include <console/klog.h>
11
#include <proc/task.h>
12
#include <proc/thread.h>
2815 svoboda 13
#include <arch.h>
2813 svoboda 14
#include <errno.h>
15
#include <ipc/ipc.h>
16
#include <syscall/copy.h>
17
#include <udebug/udebug.h>
18
#include <udebug/udebug_ipc.h>
19
 
2823 svoboda 20
/**
21
 * Get and lock a phone's callee task.
22
 *
23
 * This will return a pointer to the task to which the phone
24
 * is connected. It will lock the task, making sure it exists.
25
 * (TODO: make sure the udebug-cleanup of the task hasn't
26
 * started yet)
27
 */
2813 svoboda 28
static task_t *get_lock_callee_task(phone_t *phone)
29
{
2823 svoboda 30
    answerbox_t *box;
2813 svoboda 31
    task_t *ta;
2823 svoboda 32
    task_id_t taskid;
33
    ipl_t ipl;
2813 svoboda 34
 
2823 svoboda 35
    ipl = interrupts_disable();
36
    spinlock_lock(&phone->lock);
37
    if (phone->state != IPC_PHONE_CONNECTED) {
38
        spinlock_unlock(&phone->lock);
39
        interrupts_restore(ipl);
40
        return NULL;
41
    }
2813 svoboda 42
 
2823 svoboda 43
    box = phone->callee;
44
 
45
    spinlock_lock(&box->lock);
46
    ta = box->task;
47
    taskid = ta->taskid;
48
    spinlock_unlock(&box->lock);
49
    spinlock_unlock(&phone->lock);
2813 svoboda 50
 
2823 svoboda 51
    /* Locking decoupled using taskid */
52
 
53
    spinlock_lock(&tasks_lock);
54
    ta = task_find_by_id(taskid);
55
    if (ta == NULL) {
56
        spinlock_unlock(&tasks_lock);
57
        interrupts_restore(ipl);
58
        return NULL;
59
    }
60
 
2813 svoboda 61
    spinlock_lock(&ta->lock);
2823 svoboda 62
    spinlock_unlock(&tasks_lock);
63
    interrupts_restore(ipl);
2813 svoboda 64
 
65
    return ta;
66
}
67
 
2842 svoboda 68
/**
69
 * Verify that thread t is valid for debugging ops.
70
 *
71
 * Verifies that t belongs to task ta and that debugging operations
72
 * may be used on it.
73
 *
74
 * Thread t's lock must already be held and interrupts must be disabled.
75
 */
76
static int verify_thread(thread_t *t, task_t *ta)
2841 svoboda 77
{
78
    /* Verify that 't' exists and belongs to task 'ta' */
79
    if (!thread_exists(t) || (t->task != ta)) {
80
        return ENOENT;
81
    }
82
 
2842 svoboda 83
    /* Verify that 't' is a userspace thread */
2841 svoboda 84
    if ((t->flags & THREAD_FLAG_USPACE) == 0) {
85
        /* It's not, deny its existence */
86
        return ENOENT;
87
    }
88
 
89
    if ((t->debug_active != true) || (t->debug_stop != true)) {
90
        /* Not in debugging session or already has GO */
91
        return EBUSY;
92
    }
93
 
94
    return EOK;
95
}
96
 
2813 svoboda 97
static int udebug_rp_begin(call_t *call, phone_t *phone)
98
{
99
    task_t *ta;
2823 svoboda 100
    ipl_t ipl;
2827 svoboda 101
    int rc;
2813 svoboda 102
 
2827 svoboda 103
    thread_t *t;
104
    link_t *cur;
105
 
2813 svoboda 106
    klog_printf("debug_begin()");
107
 
2823 svoboda 108
    ipl = interrupts_disable();
2813 svoboda 109
    ta = get_lock_callee_task(phone);
110
    klog_printf("debugging task %llu", ta->taskid);
111
 
2825 svoboda 112
    if (ta->dt_state != UDEBUG_TS_INACTIVE) {
2813 svoboda 113
        spinlock_unlock(&ta->lock);
2823 svoboda 114
        interrupts_restore(ipl);
2813 svoboda 115
        klog_printf("debug_begin(): busy error");
116
        return EBUSY;
117
    }
118
 
2825 svoboda 119
    ta->dt_state = UDEBUG_TS_BEGINNING;
2813 svoboda 120
    ta->debug_begin_call = call;
121
 
122
    if (ta->not_stoppable_count == 0) {
2825 svoboda 123
        ta->dt_state = UDEBUG_TS_ACTIVE;
2813 svoboda 124
        ta->debug_begin_call = NULL;
2827 svoboda 125
        rc = 1; /* actually we need backsend with 0 retval */
126
    } else {
127
        rc = 0; /* no backsend */
2813 svoboda 128
    }
2827 svoboda 129
 
130
    /* Set debug_active on all of the task's userspace threads */
2813 svoboda 131
 
2827 svoboda 132
    for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
133
        t = list_get_instance(cur, thread_t, th_link);
134
 
135
        spinlock_lock(&t->lock);
136
        if ((t->flags & THREAD_FLAG_USPACE) != 0)
137
            t->debug_active = true;
138
        spinlock_unlock(&t->lock);
139
    }
140
 
2813 svoboda 141
    spinlock_unlock(&ta->lock);
2823 svoboda 142
    interrupts_restore(ipl);
2813 svoboda 143
 
2827 svoboda 144
    klog_printf("debug_begin() done (%s)",
145
        rc ? "backsend" : "stoppability wait");
146
 
147
    return rc;
2813 svoboda 148
}
149
 
2834 svoboda 150
static int udebug_rp_end(call_t *call, phone_t *phone)
151
{
152
    task_t *ta;
153
    ipl_t ipl;
154
 
155
    thread_t *t;
156
    link_t *cur;
157
 
158
    klog_printf("udebug_rp_end()");
159
 
160
    ipl = interrupts_disable();
161
    ta = get_lock_callee_task(phone);
162
    klog_printf("task %llu", ta->taskid);
163
 
2835 svoboda 164
    if (ta->dt_state == UDEBUG_TS_BEGINNING &&
165
        ta->dt_state != UDEBUG_TS_ACTIVE) {
2834 svoboda 166
        spinlock_unlock(&ta->lock);
167
        interrupts_restore(ipl);
2835 svoboda 168
        klog_printf("udebug_rp_begin(): task not being debugged");
2834 svoboda 169
        return EINVAL;
170
    }
171
 
2835 svoboda 172
    /* Finish debugging of all userspace threads */
2834 svoboda 173
    for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
174
        t = list_get_instance(cur, thread_t, th_link);
175
 
176
        spinlock_lock(&t->lock);
177
 
2835 svoboda 178
        /* Only process userspace threads */
179
        if ((t->flags & THREAD_FLAG_USPACE) != 0) {
180
            /* Prevent any further debug activity in thread */
181
            t->debug_active = false;
2834 svoboda 182
 
2835 svoboda 183
            /* Still has go? */
184
            if (t->debug_stop == false) {
185
                /*
186
                * Yes, so clear go. As debug_active == false,
187
                 * this doesn't affect anything.
188
                 */
189
                t->debug_stop = true;  
2834 svoboda 190
 
2835 svoboda 191
                /* Answer GO call */
2838 svoboda 192
                klog_printf("answer GO call with EVENT_FINISHED");
193
                IPC_SET_RETVAL(t->debug_go_call->data, 0);
194
                IPC_SET_ARG1(t->debug_go_call->data, UDEBUG_EVENT_FINISHED);
2835 svoboda 195
                ipc_answer(&ta->answerbox, t->debug_go_call);
196
            } else {
197
                /*
198
                 * Debug_stop is already at initial value.
199
                 * Yet this means the thread needs waking up.
200
                 */
201
                waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
202
            }
203
        }
2834 svoboda 204
 
205
        spinlock_unlock(&t->lock);
206
    }
207
 
208
    ta->dt_state = UDEBUG_TS_INACTIVE;
209
 
210
    spinlock_unlock(&ta->lock);
211
    interrupts_restore(ipl);
212
 
2838 svoboda 213
    IPC_SET_RETVAL(call->data, 0);
214
 
2834 svoboda 215
    klog_printf("udebug_rp_end() done\n");
216
 
217
    return 1;
218
}
219
 
220
 
2813 svoboda 221
static int udebug_rp_go(call_t *call, phone_t *phone)
222
{
223
    thread_t *t;
224
    task_t *ta;
2823 svoboda 225
    ipl_t ipl;
2813 svoboda 226
 
227
    klog_printf("debug_go()");
228
    ta = get_lock_callee_task(phone);
2823 svoboda 229
    spinlock_unlock(&ta->lock);
2826 svoboda 230
    // TODO: don't lock ta
2823 svoboda 231
 
2816 svoboda 232
    t = (thread_t *) IPC_GET_ARG2(call->data);
2823 svoboda 233
 
234
    ipl = interrupts_disable();
235
    spinlock_lock(&threads_lock);
2825 svoboda 236
 
2813 svoboda 237
 
2826 svoboda 238
    t->debug_go_call = call;
2825 svoboda 239
    t->debug_stop = false;
2813 svoboda 240
    waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
2825 svoboda 241
 
2823 svoboda 242
    spinlock_unlock(&threads_lock);
243
    interrupts_restore(ipl);
2813 svoboda 244
 
245
    return 0; /* no backsend */
246
}
247
 
248
static int udebug_rp_args_read(call_t *call, phone_t *phone)
249
{
250
    thread_t *t;
251
    task_t *ta;
252
    void *uspace_buffer;
253
    int rc;
2823 svoboda 254
    ipl_t ipl;
2827 svoboda 255
    unative_t buffer[6];
2813 svoboda 256
 
257
    klog_printf("debug_args_read()");
258
 
259
    ta = get_lock_callee_task(phone);
260
    klog_printf("task %llu", ta->taskid);
2823 svoboda 261
    spinlock_unlock(&ta->lock);
262
 
2816 svoboda 263
    t = (thread_t *) IPC_GET_ARG2(call->data);
2823 svoboda 264
 
265
    ipl = interrupts_disable();
266
    spinlock_lock(&threads_lock);
267
 
2841 svoboda 268
    /* Verify that thread t exists and may be operated on */
2842 svoboda 269
    rc = verify_thread(t, ta);
2841 svoboda 270
    if (rc != EOK) {
2823 svoboda 271
        spinlock_unlock(&threads_lock);
272
        interrupts_restore(ipl);
2841 svoboda 273
        return rc;
2813 svoboda 274
    }
275
 
2827 svoboda 276
    //FIXME: additionally we need to verify that we are inside a syscall
277
 
278
    /* Copy to a local buffer before releasing the lock */
279
    memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t));
280
 
2823 svoboda 281
    spinlock_unlock(&threads_lock);
282
    interrupts_restore(ipl);
283
 
2827 svoboda 284
    /* Now copy to userspace */
285
 
2813 svoboda 286
    uspace_buffer = (void *)IPC_GET_ARG3(call->data);
287
 
2833 svoboda 288
    rc = copy_to_uspace(uspace_buffer, buffer, 6 * sizeof(unative_t));
2813 svoboda 289
    if (rc != 0) {
290
        spinlock_unlock(&ta->lock);
291
        klog_printf("debug_args_read() - copy failed");
292
        return rc;
293
    }
294
 
295
    klog_printf("debug_args_read() done");
296
    return 1; /* actually need becksend with retval 0 */
297
}
298
 
2817 svoboda 299
static int udebug_rp_regs_read(call_t *call, phone_t *phone)
300
{
301
    thread_t *t;
302
    task_t *ta;
303
    void *uspace_buffer;
304
    unative_t to_copy;
305
    int rc;
306
    istate_t *state;
2824 svoboda 307
    istate_t state_copy;
308
    ipl_t ipl;
2817 svoboda 309
 
310
    klog_printf("debug_regs_read()");
311
 
2824 svoboda 312
    ta = get_lock_callee_task(phone);
313
    spinlock_unlock(&ta->lock);
2827 svoboda 314
    //FIXME: don't lock ta
2817 svoboda 315
 
2824 svoboda 316
    ipl = interrupts_disable();
317
    spinlock_lock(&threads_lock);
318
 
2817 svoboda 319
    t = (thread_t *) IPC_GET_ARG2(call->data);
2827 svoboda 320
 
2841 svoboda 321
    /* Verify that thread t exists and may be operated on */
2842 svoboda 322
    rc = verify_thread(t, ta);
2841 svoboda 323
    if (rc != EOK) {
2827 svoboda 324
        spinlock_unlock(&threads_lock);
325
        interrupts_restore(ipl);
2841 svoboda 326
        return rc;
2817 svoboda 327
    }
328
 
2824 svoboda 329
    state = t->uspace_state;
330
    if (state == NULL) {
331
        spinlock_unlock(&threads_lock);
332
        interrupts_restore(ipl);
333
        klog_printf("debug_regs_read() - istate not available");
334
        return EBUSY;
335
    }
336
 
337
    /* Copy to a local buffer so that we can release the lock */
338
    memcpy(&state_copy, state, sizeof(state_copy));
339
    spinlock_unlock(&threads_lock);
340
    interrupts_restore(ipl);
341
 
2817 svoboda 342
    uspace_buffer = (void *)IPC_GET_ARG3(call->data);
343
    to_copy = IPC_GET_ARG4(call->data);
344
    if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
345
 
2824 svoboda 346
    rc = copy_to_uspace(uspace_buffer, &state_copy, to_copy);
2817 svoboda 347
    if (rc != 0) {
348
        spinlock_unlock(&ta->lock);
349
        klog_printf("debug_regs_read() - copy failed");
350
        return rc;
351
    }
352
 
353
    IPC_SET_ARG1(call->data, to_copy);
354
    IPC_SET_ARG2(call->data, sizeof(istate_t));
355
 
356
    klog_printf("debug_regs_read() done");
357
    return 1; /* actually need becksend with retval 0 */
358
}
359
 
360
static int udebug_rp_regs_write(call_t *call, phone_t *phone)
361
{
362
    thread_t *t;
363
    task_t *ta;
364
    void *uspace_data;
365
    unative_t to_copy;
366
    int rc;
367
    istate_t *state;
2824 svoboda 368
    istate_t data_copy;
369
    ipl_t ipl;
2817 svoboda 370
 
371
    klog_printf("debug_regs_write()");
372
 
2824 svoboda 373
    /* First copy to a local buffer */
2817 svoboda 374
 
375
    uspace_data = (void *)IPC_GET_ARG3(call->data);
376
    to_copy = IPC_GET_ARG4(call->data);
377
    if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
378
 
2824 svoboda 379
    rc = copy_from_uspace(&data_copy, uspace_data, to_copy);
2817 svoboda 380
    if (rc != 0) {
381
        klog_printf("debug_regs_write() - copy failed");
382
        return rc;
383
    }
384
 
2824 svoboda 385
    ta = get_lock_callee_task(phone);
2817 svoboda 386
    spinlock_unlock(&ta->lock);
2827 svoboda 387
    //FIXME: don't lock ta
2817 svoboda 388
 
2824 svoboda 389
    /* Now try to change the thread's uspace_state */
390
 
391
    ipl = interrupts_disable();
392
    spinlock_lock(&threads_lock);
393
 
394
    t = (thread_t *) IPC_GET_ARG2(call->data);
2827 svoboda 395
 
2841 svoboda 396
    /* Verify that thread t exists and may be operated on */
2842 svoboda 397
    rc = verify_thread(t, ta);
2841 svoboda 398
    if (rc != EOK) {
2824 svoboda 399
        spinlock_unlock(&threads_lock);
400
        interrupts_restore(ipl);
2841 svoboda 401
        return rc;
2824 svoboda 402
    }
403
 
404
    state = t->uspace_state;
405
    if (state == NULL) {
406
        spinlock_unlock(&threads_lock);
407
        interrupts_restore(ipl);
408
        klog_printf("debug_regs_write() - istate not available");
409
        return EBUSY;
410
    }
411
 
412
    memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state));
413
 
414
    spinlock_unlock(&threads_lock);
415
    interrupts_restore(ipl);
416
 
417
    /* Set answer values */
418
 
2817 svoboda 419
    IPC_SET_ARG1(call->data, to_copy);
420
    IPC_SET_ARG2(call->data, sizeof(istate_t));
421
 
422
    klog_printf("debug_regs_write() done");
423
    return 1; /* actually need becksend with retval 0 */
424
}
425
 
2813 svoboda 426
static int udebug_rp_thread_read(call_t *call, phone_t *phone)
427
{
428
    thread_t *t;
429
    link_t *cur;
430
    task_t *ta;
431
    unative_t *uspace_buffer;
432
    unative_t to_copy;
433
    int rc;
2824 svoboda 434
    unsigned total_bytes;
2813 svoboda 435
    unsigned buf_size;
436
    unative_t tid;
2824 svoboda 437
    unsigned num_threads, copied_ids;
438
    ipl_t ipl;
439
    unative_t *buffer;
440
    int flags;
2813 svoboda 441
 
442
    klog_printf("debug_thread_read()");
443
 
2824 svoboda 444
    ipl = interrupts_disable();
2813 svoboda 445
    ta = get_lock_callee_task(phone);
446
 
2827 svoboda 447
    /* Verify task state */
448
    if (ta->dt_state != UDEBUG_TS_ACTIVE) {
449
        spinlock_unlock(&ta->lock);
450
        interrupts_restore(ipl);
451
        return EBUSY;
452
    }
453
 
2824 svoboda 454
    /* Count the threads first */
455
 
456
    num_threads = 0;
2813 svoboda 457
    for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
2824 svoboda 458
        /* Count all threads, to be on the safe side */
459
        ++num_threads;
460
    }
461
 
462
    /* Allocate a buffer and copy down the threads' ids */
463
    buffer = malloc(num_threads * sizeof(unative_t), 0); // ???
464
 
465
    copied_ids = 0;
466
    for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
2813 svoboda 467
        t = list_get_instance(cur, thread_t, th_link);
468
 
2824 svoboda 469
        spinlock_lock(&t->lock);
470
        flags = t->flags;
471
        spinlock_unlock(&t->lock);
472
 
2813 svoboda 473
        /* Not interested in kernel threads */
2824 svoboda 474
        if ((flags & THREAD_FLAG_USPACE) != 0) {
475
            /* Using thread struct pointer for identification */
476
            tid = (unative_t) t;
477
            buffer[copied_ids++] = tid;
478
        }
479
    }
2813 svoboda 480
 
2824 svoboda 481
    spinlock_unlock(&ta->lock);
482
    interrupts_restore(ipl);
2813 svoboda 483
 
2824 svoboda 484
    /* Now copy to userspace */
2813 svoboda 485
 
2824 svoboda 486
    uspace_buffer = (void *)IPC_GET_ARG2(call->data);
487
    buf_size = IPC_GET_ARG3(call->data);
2813 svoboda 488
 
2824 svoboda 489
    total_bytes = copied_ids * sizeof(unative_t);
490
 
491
    if (buf_size > total_bytes)
492
        to_copy = total_bytes;
493
    else
494
        to_copy = buf_size;
495
 
496
    rc = copy_to_uspace(uspace_buffer, buffer, to_copy);
497
    free(buffer);
498
 
499
    if (rc != 0) {
500
        klog_printf("debug_thread_read() - copy failed");
501
        return rc;
2813 svoboda 502
    }
503
 
2824 svoboda 504
    IPC_SET_ARG1(call->data, to_copy);
505
    IPC_SET_ARG2(call->data, total_bytes);
2813 svoboda 506
 
507
    klog_printf("debug_thread_read() done");
508
    return 1; /* actually need becksend with retval 0 */
509
}
510
 
2818 svoboda 511
static int udebug_rp_mem_write(call_t *call, phone_t *phone)
512
{
513
    void *uspace_data;
514
    unative_t to_copy;
515
    int rc;
516
    void *buffer;
517
 
518
    klog_printf("udebug_rp_mem_write()");
519
 
520
    uspace_data = (void *)IPC_GET_ARG2(call->data);
521
    to_copy = IPC_GET_ARG4(call->data);
522
 
523
    buffer = malloc(to_copy, 0); // ???
524
 
525
    rc = copy_from_uspace(buffer, uspace_data, to_copy);
526
    if (rc != 0) {
527
        klog_printf(" - copy failed");
528
        return rc;
529
    }
530
 
531
    call->buffer = buffer;
532
 
533
    klog_printf(" - done");
534
    return 1; /* actually need becksend with retval 0 */
535
}
536
 
537
 
2813 svoboda 538
int udebug_request_preprocess(call_t *call, phone_t *phone)
539
{
540
    int rc;
541
 
542
    switch (IPC_GET_ARG1(call->data)) {
543
    case UDEBUG_M_BEGIN:
544
        rc = udebug_rp_begin(call, phone);
545
        return rc;
2834 svoboda 546
    case UDEBUG_M_END:
547
        rc = udebug_rp_end(call, phone);
548
        return rc;
2813 svoboda 549
    case UDEBUG_M_GO:
550
        rc = udebug_rp_go(call, phone);
551
        return rc;
552
    case UDEBUG_M_ARGS_READ:
553
        rc = udebug_rp_args_read(call, phone);
554
        return rc;
2817 svoboda 555
    case UDEBUG_M_REGS_READ:
556
        rc = udebug_rp_regs_read(call, phone);
557
        return rc;
558
    case UDEBUG_M_REGS_WRITE:
559
        rc = udebug_rp_regs_write(call, phone);
560
        return rc;
2813 svoboda 561
    case UDEBUG_M_THREAD_READ:
562
        rc = udebug_rp_thread_read(call, phone);
2819 svoboda 563
        return rc;
2818 svoboda 564
    case UDEBUG_M_MEM_WRITE:
565
        rc = udebug_rp_mem_write(call, phone);
2813 svoboda 566
        return rc;
567
    default:
568
        break;
569
    }
570
 
571
    return 0;
572
}
573
 
2815 svoboda 574
static void udebug_receive_mem_read(call_t *call)
575
{
576
    unative_t uspace_dst;
577
    void *uspace_ptr;
578
    unsigned size;
579
    void *buffer;
580
    int rc;
2813 svoboda 581
 
2815 svoboda 582
    klog_printf("debug_mem_read()");
583
    uspace_dst = IPC_GET_ARG2(call->data);
584
    uspace_ptr = (void *)IPC_GET_ARG3(call->data);
585
    size = IPC_GET_ARG4(call->data);
586
 
587
    buffer = malloc(size, 0); // ???
588
    klog_printf("debug_mem_read: src=%u, size=%u", uspace_ptr, size);
589
 
590
    /* NOTE: this is not strictly from a syscall... but that shouldn't
591
     * be a problem */
592
    rc = copy_from_uspace(buffer, uspace_ptr, size);
593
    if (rc) {
594
        IPC_SET_RETVAL(call->data, rc);
595
        return;
596
    }
597
 
598
    klog_printf("first word: %u", *((unative_t *)buffer));
599
 
600
    IPC_SET_RETVAL(call->data, 0);
601
    /* Hack: ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
602
       same code in process_answer() can be used
603
       (no way to distinguish method in answer) */
604
    IPC_SET_ARG1(call->data, uspace_dst);
605
    IPC_SET_ARG2(call->data, size);
606
    call->buffer = buffer;
607
 
608
    ipc_answer(&TASK->kernel_box, call);
609
}
610
 
2818 svoboda 611
static void udebug_receive_mem_write(call_t *call)
612
{
613
    void *uspace_dst;
614
    unsigned size;
615
    void *buffer;
616
    int rc;
2827 svoboda 617
    udebug_task_state_t dts;
2818 svoboda 618
 
619
    klog_printf("udebug_receive_mem_write()");
2827 svoboda 620
 
621
    /* Verify task state */
622
    spinlock_lock(&TASK->lock);
623
    dts = TASK->dt_state;
624
    spinlock_unlock(&TASK->lock);
625
 
626
    if (dts != UDEBUG_TS_ACTIVE) {
627
        IPC_SET_RETVAL(call->data, EBUSY);
628
        ipc_answer(&TASK->kernel_box, call);
629
        return;
630
    }
631
 
2818 svoboda 632
    uspace_dst = (void *)IPC_GET_ARG3(call->data);
633
    size = IPC_GET_ARG4(call->data);
634
 
635
    buffer = call->buffer;
636
    klog_printf("dst=%u, size=%u", uspace_dst, size);
637
 
638
    /* NOTE: this is not strictly from a syscall... but that shouldn't
639
     * be a problem */
640
    rc = copy_to_uspace(uspace_dst, buffer, size);
641
    if (rc) {
642
        IPC_SET_RETVAL(call->data, rc);
2827 svoboda 643
        ipc_answer(&TASK->kernel_box, call);
2818 svoboda 644
        return;
645
    }
646
 
647
    IPC_SET_RETVAL(call->data, 0);
648
 
649
    free(call->buffer);
650
    call->buffer = NULL;
651
 
652
    ipc_answer(&TASK->kernel_box, call);
653
}
654
 
655
 
2815 svoboda 656
/**
657
 * Handle a debug call received on the kernel answerbox.
658
 *
659
 * This is called by the kbox servicing thread.
660
 */
661
void udebug_call_receive(call_t *call)
662
{
663
    int debug_method;
664
 
665
    debug_method = IPC_GET_ARG1(call->data);
666
 
667
    switch (debug_method) {
668
    case UDEBUG_M_MEM_READ:
669
        udebug_receive_mem_read(call);
670
        break;
2818 svoboda 671
    case UDEBUG_M_MEM_WRITE:
672
        udebug_receive_mem_write(call);
673
        break;
2815 svoboda 674
    }
675
}
676
 
2813 svoboda 677
/** @}
678
 */