Subversion Repositories HelenOS

Rev

Rev 2898 | Rev 2900 | 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);
63
    if (!buffer) return ENOMEM;
2886 svoboda 64
 
65
    rc = copy_from_uspace(buffer, uspace_data, to_copy);
2817 svoboda 66
    if (rc != 0) {
67
        klog_printf("debug_regs_write() - copy failed");
68
        return rc;
69
    }
70
 
2886 svoboda 71
    call->buffer = buffer;
2824 svoboda 72
 
2886 svoboda 73
    klog_printf(" - done");
2892 svoboda 74
    return 0;
2817 svoboda 75
}
76
 
2885 svoboda 77
static int udebug_rp_mem_write(call_t *call, phone_t *phone)
2813 svoboda 78
{
2885 svoboda 79
    void *uspace_data;
80
    unative_t to_copy;
81
    int rc;
82
    void *buffer;
83
 
84
    klog_printf("udebug_rp_mem_write()");
85
 
86
    uspace_data = (void *)IPC_GET_ARG2(call->data);
87
    to_copy = IPC_GET_ARG4(call->data);
88
 
2896 svoboda 89
    buffer = malloc(to_copy, 0);
90
    if (!buffer) return ENOMEM;
2885 svoboda 91
 
92
    rc = copy_from_uspace(buffer, uspace_data, to_copy);
93
    if (rc != 0) {
94
        klog_printf(" - copy failed");
95
        return rc;
96
    }
97
 
98
    call->buffer = buffer;
99
 
100
    klog_printf(" - done");
2892 svoboda 101
    return 0;
2885 svoboda 102
}
103
 
104
 
105
int udebug_request_preprocess(call_t *call, phone_t *phone)
106
{
107
    int rc;
108
 
109
    switch (IPC_GET_ARG1(call->data)) {
110
    case UDEBUG_M_REGS_WRITE:
111
        rc = udebug_rp_regs_write(call, phone);
112
        return rc;
113
    case UDEBUG_M_MEM_WRITE:
114
        rc = udebug_rp_mem_write(call, phone);
115
        return rc;
116
    default:
117
        break;
118
    }
119
 
120
    return 0;
121
}
122
 
123
static void udebug_receive_begin(call_t *call)
124
{
2887 svoboda 125
    int rc;
2885 svoboda 126
 
2887 svoboda 127
    rc = udebug_begin(call);
128
    if (rc < 0) {
129
        IPC_SET_RETVAL(call->data, rc);
2885 svoboda 130
        ipc_answer(&TASK->kernel_box, call);
2887 svoboda 131
        return;
2885 svoboda 132
    }
133
 
2887 svoboda 134
    if (rc != 0) {
135
        IPC_SET_RETVAL(call->data, 0);
136
        ipc_answer(&TASK->kernel_box, call);
2885 svoboda 137
    }
138
}
139
 
140
static void udebug_receive_end(call_t *call)
141
{
142
    int rc;
143
 
2887 svoboda 144
    rc = udebug_end();
2885 svoboda 145
 
2887 svoboda 146
    IPC_SET_RETVAL(call->data, rc);
2885 svoboda 147
    ipc_answer(&TASK->kernel_box, call);
148
}
149
 
2899 svoboda 150
static void udebug_receive_set_evmask(call_t *call)
151
{
152
    int rc;
153
    udebug_evmask_t mask;
154
 
155
    mask = IPC_GET_ARG2(call->data);
156
    rc = udebug_set_evmask(mask);
157
 
158
    IPC_SET_RETVAL(call->data, rc);
159
    ipc_answer(&TASK->kernel_box, call);
160
}
161
 
162
 
2886 svoboda 163
static void udebug_receive_go(call_t *call)
164
{
165
    thread_t *t;
166
    int rc;
167
 
168
    klog_printf("debug_go()");
169
 
170
    t = (thread_t *)IPC_GET_ARG2(call->data);
171
 
2887 svoboda 172
    rc = udebug_go(t, call);
173
    if (rc < 0) {
2886 svoboda 174
        IPC_SET_RETVAL(call->data, rc);
175
        ipc_answer(&TASK->kernel_box, call);
176
        return;
177
    }
178
}
179
 
2898 svoboda 180
static void udebug_receive_stop(call_t *call)
181
{
182
    thread_t *t;
183
    int rc;
2886 svoboda 184
 
2898 svoboda 185
    klog_printf("debug_stop()");
186
 
187
    t = (thread_t *)IPC_GET_ARG2(call->data);
188
 
189
    rc = udebug_stop(t, call);
190
    IPC_SET_RETVAL(call->data, rc);
191
    ipc_answer(&TASK->kernel_box, call);
192
}
193
 
2885 svoboda 194
static void udebug_receive_thread_read(call_t *call)
195
{
196
    unative_t uspace_addr;
2813 svoboda 197
    unative_t to_copy;
2824 svoboda 198
    unsigned total_bytes;
2813 svoboda 199
    unsigned buf_size;
2887 svoboda 200
    void *buffer;
201
    size_t n;
202
    int rc;
2813 svoboda 203
 
2897 svoboda 204
    uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
205
    buf_size = IPC_GET_ARG3(call->data);    /* Dest. buffer size */
206
 
207
    /*
208
     * Read thread list. Variable n will be filled with actual number
209
     * of threads times thread-id size.
210
     */
211
    rc = udebug_thread_read(&buffer, buf_size, &n);
2887 svoboda 212
    if (rc < 0) {
213
        IPC_SET_RETVAL(call->data, rc);
2885 svoboda 214
        ipc_answer(&TASK->kernel_box, call);
215
        return;
2827 svoboda 216
    }
217
 
2897 svoboda 218
    total_bytes = n;
2813 svoboda 219
 
2897 svoboda 220
    /* Copy MAX(buf_size, total_bytes) bytes */
2813 svoboda 221
 
2824 svoboda 222
    if (buf_size > total_bytes)
223
        to_copy = total_bytes;
224
    else
225
        to_copy = buf_size;
226
 
2897 svoboda 227
    /*
228
     * Make use of call->buffer to transfer data to caller's userspace
229
     */
230
 
2885 svoboda 231
    IPC_SET_RETVAL(call->data, 0);
232
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
233
       same code in process_answer() can be used
234
       (no way to distinguish method in answer) */
235
    IPC_SET_ARG1(call->data, uspace_addr);
236
    IPC_SET_ARG2(call->data, to_copy);
2824 svoboda 237
 
2885 svoboda 238
    IPC_SET_ARG3(call->data, total_bytes);
2887 svoboda 239
    call->buffer = buffer;
2813 svoboda 240
 
2885 svoboda 241
    ipc_answer(&TASK->kernel_box, call);
2813 svoboda 242
}
243
 
2886 svoboda 244
static void udebug_receive_args_read(call_t *call)
245
{
246
    thread_t *t;
247
    unative_t uspace_addr;
248
    int rc;
2887 svoboda 249
    void *buffer;
2818 svoboda 250
 
2886 svoboda 251
    t = (thread_t *)IPC_GET_ARG2(call->data);
252
 
2887 svoboda 253
    rc = udebug_args_read(t, &buffer);
2886 svoboda 254
    if (rc != EOK) {
255
        IPC_SET_RETVAL(call->data, rc);
256
        ipc_answer(&TASK->kernel_box, call);
257
        return;
258
    }
259
 
260
    /*
261
     * Make use of call->buffer to transfer data to caller's userspace
262
     */
263
 
264
    uspace_addr = IPC_GET_ARG3(call->data);
265
 
266
    IPC_SET_RETVAL(call->data, 0);
267
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
268
       same code in process_answer() can be used
269
       (no way to distinguish method in answer) */
270
    IPC_SET_ARG1(call->data, uspace_addr);
271
    IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
2887 svoboda 272
    call->buffer = buffer;
2886 svoboda 273
 
274
    ipc_answer(&TASK->kernel_box, call);
275
}
276
 
277
static void udebug_receive_regs_read(call_t *call)
278
{
279
    thread_t *t;
280
    unative_t uspace_addr;
281
    unative_t to_copy;
282
    unative_t buf_size;
283
    unative_t total_bytes;
284
    void *buffer;
285
    int rc;
2887 svoboda 286
    size_t n;
2886 svoboda 287
 
288
    klog_printf("debug_regs_read()");
289
 
290
    t = (thread_t *) IPC_GET_ARG2(call->data);
291
 
2887 svoboda 292
    rc = udebug_regs_read(t, &buffer, &n);
293
    if (rc < 0) {
2886 svoboda 294
        IPC_SET_RETVAL(call->data, rc);
295
        ipc_answer(&TASK->kernel_box, call);
296
        return;
297
    }
298
 
299
    /*
300
     * Make use of call->buffer to transfer data to caller's userspace
301
     */
302
 
303
    uspace_addr = IPC_GET_ARG3(call->data);
304
    buf_size = IPC_GET_ARG4(call->data);
305
 
2887 svoboda 306
    total_bytes = n;
2886 svoboda 307
 
308
    if (buf_size > total_bytes)
309
        to_copy = total_bytes;
310
    else
311
        to_copy = buf_size;
312
 
313
    IPC_SET_RETVAL(call->data, 0);
314
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
315
       same code in process_answer() can be used
316
       (no way to distinguish method in answer) */
317
    IPC_SET_ARG1(call->data, uspace_addr);
318
    IPC_SET_ARG2(call->data, to_copy);
319
 
320
    IPC_SET_ARG3(call->data, total_bytes);
2887 svoboda 321
    call->buffer = buffer;
2886 svoboda 322
 
323
    ipc_answer(&TASK->kernel_box, call);
324
}
325
 
326
static void udebug_receive_regs_write(call_t *call)
327
{
328
    thread_t *t;
329
    void *uspace_data;
330
    unative_t to_copy;
331
    int rc;
332
 
333
    uspace_data = (void *)IPC_GET_ARG3(call->data);
334
    to_copy = IPC_GET_ARG4(call->data);
335
 
336
    t = (thread_t *) IPC_GET_ARG2(call->data);
337
 
2887 svoboda 338
    rc = udebug_regs_write(t, call->buffer);
339
    if (rc < 0) {
2886 svoboda 340
        IPC_SET_RETVAL(call->data, rc);
341
        ipc_answer(&TASK->kernel_box, call);
342
        return;
343
    }
344
 
345
    /* Set answer values */
346
 
347
    IPC_SET_ARG1(call->data, to_copy);
348
    IPC_SET_ARG2(call->data, sizeof(istate_t));
349
 
350
    IPC_SET_RETVAL(call->data, 0);
2887 svoboda 351
    free(call->buffer);
352
    call->buffer = NULL;
353
 
2886 svoboda 354
    ipc_answer(&TASK->kernel_box, call);
355
}
356
 
357
 
2815 svoboda 358
static void udebug_receive_mem_read(call_t *call)
359
{
360
    unative_t uspace_dst;
2887 svoboda 361
    unative_t uspace_src;
2815 svoboda 362
    unsigned size;
363
    void *buffer;
364
    int rc;
2813 svoboda 365
 
2815 svoboda 366
    uspace_dst = IPC_GET_ARG2(call->data);
2887 svoboda 367
    uspace_src = IPC_GET_ARG3(call->data);
2815 svoboda 368
    size = IPC_GET_ARG4(call->data);
369
 
2887 svoboda 370
    rc = udebug_mem_read(uspace_src, size, &buffer);
371
    if (rc < 0) {
2815 svoboda 372
        IPC_SET_RETVAL(call->data, rc);
2886 svoboda 373
        ipc_answer(&TASK->kernel_box, call);
2815 svoboda 374
        return;
375
    }
376
 
377
    IPC_SET_RETVAL(call->data, 0);
2887 svoboda 378
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
2815 svoboda 379
       same code in process_answer() can be used
380
       (no way to distinguish method in answer) */
381
    IPC_SET_ARG1(call->data, uspace_dst);
382
    IPC_SET_ARG2(call->data, size);
383
    call->buffer = buffer;
384
 
385
    ipc_answer(&TASK->kernel_box, call);
386
}
387
 
2818 svoboda 388
static void udebug_receive_mem_write(call_t *call)
389
{
2887 svoboda 390
    unative_t uspace_dst;
2818 svoboda 391
    unsigned size;
392
    int rc;
393
 
394
    klog_printf("udebug_receive_mem_write()");
2827 svoboda 395
 
2887 svoboda 396
    uspace_dst = IPC_GET_ARG3(call->data);
2818 svoboda 397
    size = IPC_GET_ARG4(call->data);
398
 
2887 svoboda 399
    rc = udebug_mem_write(uspace_dst, call->buffer, size);
400
    if (rc < 0) {
2818 svoboda 401
        IPC_SET_RETVAL(call->data, rc);
2827 svoboda 402
        ipc_answer(&TASK->kernel_box, call);
2818 svoboda 403
        return;
404
    }
405
 
406
    IPC_SET_RETVAL(call->data, 0);
407
    free(call->buffer);
408
    call->buffer = NULL;
409
 
410
    ipc_answer(&TASK->kernel_box, call);
411
}
412
 
413
 
2815 svoboda 414
/**
415
 * Handle a debug call received on the kernel answerbox.
416
 *
417
 * This is called by the kbox servicing thread.
418
 */
419
void udebug_call_receive(call_t *call)
420
{
421
    int debug_method;
422
 
423
    debug_method = IPC_GET_ARG1(call->data);
424
 
2888 svoboda 425
    if (debug_method != UDEBUG_M_BEGIN) {
426
        /*
427
         * Verify that the sender is this task's debugger.
428
         * Note that this is the only thread that could change
429
         * TASK->debugger. Therefore no locking is necessary
430
         * and the sender can be safely considered valid until
431
         * control exits this function.
432
         */
433
        if (TASK->debugger != call->sender) {
434
            IPC_SET_RETVAL(call->data, EINVAL);
435
            ipc_answer(&TASK->kernel_box, call);
436
            return;
437
        }
438
    }
439
 
2815 svoboda 440
    switch (debug_method) {
2885 svoboda 441
    case UDEBUG_M_BEGIN:
442
        udebug_receive_begin(call);
443
        break;
444
    case UDEBUG_M_END:
445
        udebug_receive_end(call);
446
        break;
2899 svoboda 447
    case UDEBUG_M_SET_EVMASK:
448
        udebug_receive_set_evmask(call);
449
        break;
2886 svoboda 450
    case UDEBUG_M_GO:
451
        udebug_receive_go(call);
452
        break;
2898 svoboda 453
    case UDEBUG_M_STOP:
454
        udebug_receive_stop(call);
455
        break;
2885 svoboda 456
    case UDEBUG_M_THREAD_READ:
457
        udebug_receive_thread_read(call);
458
        break;
2886 svoboda 459
    case UDEBUG_M_ARGS_READ:
460
        udebug_receive_args_read(call);
461
        break;
462
    case UDEBUG_M_REGS_READ:
463
        udebug_receive_regs_read(call);
464
        break;
465
    case UDEBUG_M_REGS_WRITE:
466
        udebug_receive_regs_write(call);
467
        break;
2815 svoboda 468
    case UDEBUG_M_MEM_READ:
469
        udebug_receive_mem_read(call);
470
        break;
2818 svoboda 471
    case UDEBUG_M_MEM_WRITE:
472
        udebug_receive_mem_write(call);
473
        break;
2815 svoboda 474
    }
475
}
476
 
2813 svoboda 477
/** @}
478
 */