Subversion Repositories HelenOS

Rev

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

Rev Author Line No. Line
2894 svoboda 1
/*
2
 * Copyright (c) 2008 Jiri Svoboda
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
 
2813 svoboda 29
/** @addtogroup generic
30
 * @{
31
 */
32
 
33
/**
34
 * @file
2894 svoboda 35
 * @brief   Udebug IPC message handling.
2813 svoboda 36
 */
37
 
38
#include <console/klog.h>
39
#include <proc/task.h>
40
#include <proc/thread.h>
2815 svoboda 41
#include <arch.h>
2813 svoboda 42
#include <errno.h>
43
#include <ipc/ipc.h>
44
#include <syscall/copy.h>
45
#include <udebug/udebug.h>
2887 svoboda 46
#include <udebug/udebug_ops.h>
2813 svoboda 47
#include <udebug/udebug_ipc.h>
48
 
2817 svoboda 49
static int udebug_rp_regs_write(call_t *call, phone_t *phone)
50
{
51
    void *uspace_data;
52
    unative_t to_copy;
53
    int rc;
2886 svoboda 54
    void *buffer;
2817 svoboda 55
 
56
    klog_printf("debug_regs_write()");
57
 
58
    uspace_data = (void *)IPC_GET_ARG3(call->data);
59
    to_copy = IPC_GET_ARG4(call->data);
60
    if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
61
 
2896 svoboda 62
    buffer = malloc(to_copy, 0);
2886 svoboda 63
 
64
    rc = copy_from_uspace(buffer, uspace_data, to_copy);
2817 svoboda 65
    if (rc != 0) {
66
        klog_printf("debug_regs_write() - copy failed");
67
        return rc;
68
    }
69
 
2886 svoboda 70
    call->buffer = buffer;
2824 svoboda 71
 
2886 svoboda 72
    klog_printf(" - done");
2892 svoboda 73
    return 0;
2817 svoboda 74
}
75
 
2885 svoboda 76
static int udebug_rp_mem_write(call_t *call, phone_t *phone)
2813 svoboda 77
{
2885 svoboda 78
    void *uspace_data;
79
    unative_t to_copy;
80
    int rc;
81
    void *buffer;
82
 
83
    klog_printf("udebug_rp_mem_write()");
84
 
85
    uspace_data = (void *)IPC_GET_ARG2(call->data);
86
    to_copy = IPC_GET_ARG4(call->data);
87
 
2896 svoboda 88
    buffer = malloc(to_copy, 0);
2885 svoboda 89
 
90
    rc = copy_from_uspace(buffer, uspace_data, to_copy);
91
    if (rc != 0) {
92
        klog_printf(" - copy failed");
93
        return rc;
94
    }
95
 
96
    call->buffer = buffer;
97
 
98
    klog_printf(" - done");
2892 svoboda 99
    return 0;
2885 svoboda 100
}
101
 
102
 
103
int udebug_request_preprocess(call_t *call, phone_t *phone)
104
{
105
    int rc;
106
 
107
    switch (IPC_GET_ARG1(call->data)) {
108
    case UDEBUG_M_REGS_WRITE:
109
        rc = udebug_rp_regs_write(call, phone);
110
        return rc;
111
    case UDEBUG_M_MEM_WRITE:
112
        rc = udebug_rp_mem_write(call, phone);
113
        return rc;
114
    default:
115
        break;
116
    }
117
 
118
    return 0;
119
}
120
 
121
static void udebug_receive_begin(call_t *call)
122
{
2887 svoboda 123
    int rc;
2885 svoboda 124
 
2887 svoboda 125
    rc = udebug_begin(call);
126
    if (rc < 0) {
127
        IPC_SET_RETVAL(call->data, rc);
2885 svoboda 128
        ipc_answer(&TASK->kernel_box, call);
2887 svoboda 129
        return;
2885 svoboda 130
    }
131
 
2887 svoboda 132
    if (rc != 0) {
133
        IPC_SET_RETVAL(call->data, 0);
134
        ipc_answer(&TASK->kernel_box, call);
2885 svoboda 135
    }
136
}
137
 
138
static void udebug_receive_end(call_t *call)
139
{
140
    int rc;
141
 
2887 svoboda 142
    rc = udebug_end();
2885 svoboda 143
 
2887 svoboda 144
    IPC_SET_RETVAL(call->data, rc);
2885 svoboda 145
    ipc_answer(&TASK->kernel_box, call);
146
}
147
 
2899 svoboda 148
static void udebug_receive_set_evmask(call_t *call)
149
{
150
    int rc;
151
    udebug_evmask_t mask;
152
 
153
    mask = IPC_GET_ARG2(call->data);
154
    rc = udebug_set_evmask(mask);
155
 
156
    IPC_SET_RETVAL(call->data, rc);
157
    ipc_answer(&TASK->kernel_box, call);
158
}
159
 
160
 
2886 svoboda 161
static void udebug_receive_go(call_t *call)
162
{
163
    thread_t *t;
164
    int rc;
165
 
166
    klog_printf("debug_go()");
167
 
168
    t = (thread_t *)IPC_GET_ARG2(call->data);
169
 
2887 svoboda 170
    rc = udebug_go(t, call);
171
    if (rc < 0) {
2886 svoboda 172
        IPC_SET_RETVAL(call->data, rc);
173
        ipc_answer(&TASK->kernel_box, call);
174
        return;
175
    }
176
}
177
 
2898 svoboda 178
static void udebug_receive_stop(call_t *call)
179
{
180
    thread_t *t;
181
    int rc;
2886 svoboda 182
 
2898 svoboda 183
    klog_printf("debug_stop()");
184
 
185
    t = (thread_t *)IPC_GET_ARG2(call->data);
186
 
187
    rc = udebug_stop(t, call);
188
    IPC_SET_RETVAL(call->data, rc);
189
    ipc_answer(&TASK->kernel_box, call);
190
}
191
 
2885 svoboda 192
static void udebug_receive_thread_read(call_t *call)
193
{
194
    unative_t uspace_addr;
2813 svoboda 195
    unative_t to_copy;
2824 svoboda 196
    unsigned total_bytes;
2813 svoboda 197
    unsigned buf_size;
2887 svoboda 198
    void *buffer;
199
    size_t n;
200
    int rc;
2813 svoboda 201
 
2897 svoboda 202
    uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
203
    buf_size = IPC_GET_ARG3(call->data);    /* Dest. buffer size */
204
 
205
    /*
206
     * Read thread list. Variable n will be filled with actual number
207
     * of threads times thread-id size.
208
     */
209
    rc = udebug_thread_read(&buffer, buf_size, &n);
2887 svoboda 210
    if (rc < 0) {
211
        IPC_SET_RETVAL(call->data, rc);
2885 svoboda 212
        ipc_answer(&TASK->kernel_box, call);
213
        return;
2827 svoboda 214
    }
215
 
2897 svoboda 216
    total_bytes = n;
2813 svoboda 217
 
2897 svoboda 218
    /* Copy MAX(buf_size, total_bytes) bytes */
2813 svoboda 219
 
2824 svoboda 220
    if (buf_size > total_bytes)
221
        to_copy = total_bytes;
222
    else
223
        to_copy = buf_size;
224
 
2897 svoboda 225
    /*
226
     * Make use of call->buffer to transfer data to caller's userspace
227
     */
228
 
2885 svoboda 229
    IPC_SET_RETVAL(call->data, 0);
230
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
231
       same code in process_answer() can be used
232
       (no way to distinguish method in answer) */
233
    IPC_SET_ARG1(call->data, uspace_addr);
234
    IPC_SET_ARG2(call->data, to_copy);
2824 svoboda 235
 
2885 svoboda 236
    IPC_SET_ARG3(call->data, total_bytes);
2887 svoboda 237
    call->buffer = buffer;
2813 svoboda 238
 
2885 svoboda 239
    ipc_answer(&TASK->kernel_box, call);
2813 svoboda 240
}
241
 
2886 svoboda 242
static void udebug_receive_args_read(call_t *call)
243
{
244
    thread_t *t;
245
    unative_t uspace_addr;
246
    int rc;
2887 svoboda 247
    void *buffer;
2818 svoboda 248
 
2886 svoboda 249
    t = (thread_t *)IPC_GET_ARG2(call->data);
250
 
2887 svoboda 251
    rc = udebug_args_read(t, &buffer);
2886 svoboda 252
    if (rc != EOK) {
253
        IPC_SET_RETVAL(call->data, rc);
254
        ipc_answer(&TASK->kernel_box, call);
255
        return;
256
    }
257
 
258
    /*
259
     * Make use of call->buffer to transfer data to caller's userspace
260
     */
261
 
262
    uspace_addr = IPC_GET_ARG3(call->data);
263
 
264
    IPC_SET_RETVAL(call->data, 0);
265
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
266
       same code in process_answer() can be used
267
       (no way to distinguish method in answer) */
268
    IPC_SET_ARG1(call->data, uspace_addr);
269
    IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
2887 svoboda 270
    call->buffer = buffer;
2886 svoboda 271
 
272
    ipc_answer(&TASK->kernel_box, call);
273
}
274
 
275
static void udebug_receive_regs_read(call_t *call)
276
{
277
    thread_t *t;
278
    unative_t uspace_addr;
279
    unative_t to_copy;
280
    unative_t buf_size;
281
    unative_t total_bytes;
282
    void *buffer;
283
    int rc;
2887 svoboda 284
    size_t n;
2886 svoboda 285
 
286
    klog_printf("debug_regs_read()");
287
 
288
    t = (thread_t *) IPC_GET_ARG2(call->data);
289
 
2887 svoboda 290
    rc = udebug_regs_read(t, &buffer, &n);
291
    if (rc < 0) {
2886 svoboda 292
        IPC_SET_RETVAL(call->data, rc);
293
        ipc_answer(&TASK->kernel_box, call);
294
        return;
295
    }
296
 
297
    /*
298
     * Make use of call->buffer to transfer data to caller's userspace
299
     */
300
 
301
    uspace_addr = IPC_GET_ARG3(call->data);
302
    buf_size = IPC_GET_ARG4(call->data);
303
 
2887 svoboda 304
    total_bytes = n;
2886 svoboda 305
 
306
    if (buf_size > total_bytes)
307
        to_copy = total_bytes;
308
    else
309
        to_copy = buf_size;
310
 
311
    IPC_SET_RETVAL(call->data, 0);
312
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
313
       same code in process_answer() can be used
314
       (no way to distinguish method in answer) */
315
    IPC_SET_ARG1(call->data, uspace_addr);
316
    IPC_SET_ARG2(call->data, to_copy);
317
 
318
    IPC_SET_ARG3(call->data, total_bytes);
2887 svoboda 319
    call->buffer = buffer;
2886 svoboda 320
 
321
    ipc_answer(&TASK->kernel_box, call);
322
}
323
 
324
static void udebug_receive_regs_write(call_t *call)
325
{
326
    thread_t *t;
327
    void *uspace_data;
328
    unative_t to_copy;
329
    int rc;
330
 
331
    uspace_data = (void *)IPC_GET_ARG3(call->data);
332
    to_copy = IPC_GET_ARG4(call->data);
333
 
334
    t = (thread_t *) IPC_GET_ARG2(call->data);
335
 
2887 svoboda 336
    rc = udebug_regs_write(t, call->buffer);
337
    if (rc < 0) {
2886 svoboda 338
        IPC_SET_RETVAL(call->data, rc);
339
        ipc_answer(&TASK->kernel_box, call);
340
        return;
341
    }
342
 
343
    /* Set answer values */
344
 
345
    IPC_SET_ARG1(call->data, to_copy);
346
    IPC_SET_ARG2(call->data, sizeof(istate_t));
347
 
348
    IPC_SET_RETVAL(call->data, 0);
2887 svoboda 349
    free(call->buffer);
350
    call->buffer = NULL;
351
 
2886 svoboda 352
    ipc_answer(&TASK->kernel_box, call);
353
}
354
 
355
 
2815 svoboda 356
static void udebug_receive_mem_read(call_t *call)
357
{
358
    unative_t uspace_dst;
2887 svoboda 359
    unative_t uspace_src;
2815 svoboda 360
    unsigned size;
361
    void *buffer;
362
    int rc;
2813 svoboda 363
 
2815 svoboda 364
    uspace_dst = IPC_GET_ARG2(call->data);
2887 svoboda 365
    uspace_src = IPC_GET_ARG3(call->data);
2815 svoboda 366
    size = IPC_GET_ARG4(call->data);
367
 
2887 svoboda 368
    rc = udebug_mem_read(uspace_src, size, &buffer);
369
    if (rc < 0) {
2815 svoboda 370
        IPC_SET_RETVAL(call->data, rc);
2886 svoboda 371
        ipc_answer(&TASK->kernel_box, call);
2815 svoboda 372
        return;
373
    }
374
 
375
    IPC_SET_RETVAL(call->data, 0);
2887 svoboda 376
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
2815 svoboda 377
       same code in process_answer() can be used
378
       (no way to distinguish method in answer) */
379
    IPC_SET_ARG1(call->data, uspace_dst);
380
    IPC_SET_ARG2(call->data, size);
381
    call->buffer = buffer;
382
 
383
    ipc_answer(&TASK->kernel_box, call);
384
}
385
 
2818 svoboda 386
static void udebug_receive_mem_write(call_t *call)
387
{
2887 svoboda 388
    unative_t uspace_dst;
2818 svoboda 389
    unsigned size;
390
    int rc;
391
 
392
    klog_printf("udebug_receive_mem_write()");
2827 svoboda 393
 
2887 svoboda 394
    uspace_dst = IPC_GET_ARG3(call->data);
2818 svoboda 395
    size = IPC_GET_ARG4(call->data);
396
 
2887 svoboda 397
    rc = udebug_mem_write(uspace_dst, call->buffer, size);
398
    if (rc < 0) {
2818 svoboda 399
        IPC_SET_RETVAL(call->data, rc);
2827 svoboda 400
        ipc_answer(&TASK->kernel_box, call);
2818 svoboda 401
        return;
402
    }
403
 
404
    IPC_SET_RETVAL(call->data, 0);
405
    free(call->buffer);
406
    call->buffer = NULL;
407
 
408
    ipc_answer(&TASK->kernel_box, call);
409
}
410
 
411
 
2815 svoboda 412
/**
413
 * Handle a debug call received on the kernel answerbox.
414
 *
415
 * This is called by the kbox servicing thread.
416
 */
417
void udebug_call_receive(call_t *call)
418
{
419
    int debug_method;
420
 
421
    debug_method = IPC_GET_ARG1(call->data);
422
 
2888 svoboda 423
    if (debug_method != UDEBUG_M_BEGIN) {
424
        /*
425
         * Verify that the sender is this task's debugger.
426
         * Note that this is the only thread that could change
427
         * TASK->debugger. Therefore no locking is necessary
428
         * and the sender can be safely considered valid until
429
         * control exits this function.
430
         */
431
        if (TASK->debugger != call->sender) {
432
            IPC_SET_RETVAL(call->data, EINVAL);
433
            ipc_answer(&TASK->kernel_box, call);
434
            return;
435
        }
436
    }
437
 
2815 svoboda 438
    switch (debug_method) {
2885 svoboda 439
    case UDEBUG_M_BEGIN:
440
        udebug_receive_begin(call);
441
        break;
442
    case UDEBUG_M_END:
443
        udebug_receive_end(call);
444
        break;
2899 svoboda 445
    case UDEBUG_M_SET_EVMASK:
446
        udebug_receive_set_evmask(call);
447
        break;
2886 svoboda 448
    case UDEBUG_M_GO:
449
        udebug_receive_go(call);
450
        break;
2898 svoboda 451
    case UDEBUG_M_STOP:
452
        udebug_receive_stop(call);
453
        break;
2885 svoboda 454
    case UDEBUG_M_THREAD_READ:
455
        udebug_receive_thread_read(call);
456
        break;
2886 svoboda 457
    case UDEBUG_M_ARGS_READ:
458
        udebug_receive_args_read(call);
459
        break;
460
    case UDEBUG_M_REGS_READ:
461
        udebug_receive_regs_read(call);
462
        break;
463
    case UDEBUG_M_REGS_WRITE:
464
        udebug_receive_regs_write(call);
465
        break;
2815 svoboda 466
    case UDEBUG_M_MEM_READ:
467
        udebug_receive_mem_read(call);
468
        break;
2818 svoboda 469
    case UDEBUG_M_MEM_WRITE:
470
        udebug_receive_mem_write(call);
471
        break;
2815 svoboda 472
    }
473
}
474
 
2813 svoboda 475
/** @}
476
 */