Subversion Repositories HelenOS

Rev

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