Subversion Repositories HelenOS

Rev

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