Subversion Repositories HelenOS

Rev

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