Subversion Repositories HelenOS

Rev

Rev 3441 | Rev 3468 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3441 Rev 3457
1
/*
1
/*
2
 * Copyright (c) 2008 Jiri Svoboda
2
 * Copyright (c) 2008 Jiri Svoboda
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
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
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.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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
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.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup generic
29
/** @addtogroup generic
30
 * @{
30
 * @{
31
 */
31
 */
32
 
32
 
33
/**
33
/**
34
 * @file
34
 * @file
35
 * @brief   Udebug IPC message handling.
35
 * @brief   Udebug IPC message handling.
-
 
36
 *
-
 
37
 * This module handles udebug IPC messages and calls the appropriate
-
 
38
 * functions from the udebug_ops module which implement them.
36
 */
39
 */
37
 
40
 
38
#include <proc/task.h>
41
#include <proc/task.h>
39
#include <proc/thread.h>
42
#include <proc/thread.h>
40
#include <arch.h>
43
#include <arch.h>
41
#include <errno.h>
44
#include <errno.h>
42
#include <ipc/ipc.h>
45
#include <ipc/ipc.h>
43
#include <syscall/copy.h>
46
#include <syscall/copy.h>
44
#include <udebug/udebug.h>
47
#include <udebug/udebug.h>
45
#include <udebug/udebug_ops.h>
48
#include <udebug/udebug_ops.h>
46
#include <udebug/udebug_ipc.h>
49
#include <udebug/udebug_ipc.h>
47
 
50
 
48
int udebug_request_preprocess(call_t *call, phone_t *phone)
51
int udebug_request_preprocess(call_t *call, phone_t *phone)
49
{
52
{
50
    switch (IPC_GET_ARG1(call->data)) {
53
    switch (IPC_GET_ARG1(call->data)) {
51
    /* future UDEBUG_M_REGS_WRITE, UDEBUG_M_MEM_WRITE: */
54
    /* future UDEBUG_M_REGS_WRITE, UDEBUG_M_MEM_WRITE: */
52
    default:
55
    default:
53
        break;
56
        break;
54
    }
57
    }
55
 
58
 
56
    return 0;
59
    return 0;
57
}
60
}
58
 
61
 
59
static void udebug_receive_begin(call_t *call)
62
static void udebug_receive_begin(call_t *call)
60
{
63
{
61
    int rc;
64
    int rc;
62
 
65
 
63
    rc = udebug_begin(call);
66
    rc = udebug_begin(call);
64
    if (rc < 0) {
67
    if (rc < 0) {
65
        IPC_SET_RETVAL(call->data, rc);
68
        IPC_SET_RETVAL(call->data, rc);
66
        ipc_answer(&TASK->kernel_box, call);
69
        ipc_answer(&TASK->kernel_box, call);
67
        return;
70
        return;
68
    }
71
    }
69
 
72
 
70
    if (rc != 0) {
73
    if (rc != 0) {
71
        IPC_SET_RETVAL(call->data, 0);
74
        IPC_SET_RETVAL(call->data, 0);
72
        ipc_answer(&TASK->kernel_box, call);
75
        ipc_answer(&TASK->kernel_box, call);
73
    }
76
    }
74
}
77
}
75
 
78
 
76
static void udebug_receive_end(call_t *call)
79
static void udebug_receive_end(call_t *call)
77
{
80
{
78
    int rc;
81
    int rc;
79
 
82
 
80
    rc = udebug_end();
83
    rc = udebug_end();
81
 
84
 
82
    IPC_SET_RETVAL(call->data, rc);
85
    IPC_SET_RETVAL(call->data, rc);
83
    ipc_answer(&TASK->kernel_box, call);
86
    ipc_answer(&TASK->kernel_box, call);
84
}
87
}
85
 
88
 
86
static void udebug_receive_set_evmask(call_t *call)
89
static void udebug_receive_set_evmask(call_t *call)
87
{
90
{
88
    int rc;
91
    int rc;
89
    udebug_evmask_t mask;
92
    udebug_evmask_t mask;
90
 
93
 
91
    mask = IPC_GET_ARG2(call->data);
94
    mask = IPC_GET_ARG2(call->data);
92
    rc = udebug_set_evmask(mask);
95
    rc = udebug_set_evmask(mask);
93
 
96
 
94
    IPC_SET_RETVAL(call->data, rc);
97
    IPC_SET_RETVAL(call->data, rc);
95
    ipc_answer(&TASK->kernel_box, call);
98
    ipc_answer(&TASK->kernel_box, call);
96
}
99
}
97
 
100
 
98
 
101
 
99
static void udebug_receive_go(call_t *call)
102
static void udebug_receive_go(call_t *call)
100
{
103
{
101
    thread_t *t;
104
    thread_t *t;
102
    int rc;
105
    int rc;
103
 
106
 
104
    t = (thread_t *)IPC_GET_ARG2(call->data);
107
    t = (thread_t *)IPC_GET_ARG2(call->data);
105
 
108
 
106
    rc = udebug_go(t, call);
109
    rc = udebug_go(t, call);
107
    if (rc < 0) {
110
    if (rc < 0) {
108
        IPC_SET_RETVAL(call->data, rc);
111
        IPC_SET_RETVAL(call->data, rc);
109
        ipc_answer(&TASK->kernel_box, call);
112
        ipc_answer(&TASK->kernel_box, call);
110
        return;
113
        return;
111
    }
114
    }
112
}
115
}
113
 
116
 
114
static void udebug_receive_stop(call_t *call)
117
static void udebug_receive_stop(call_t *call)
115
{
118
{
116
    thread_t *t;
119
    thread_t *t;
117
    int rc;
120
    int rc;
118
 
121
 
119
    t = (thread_t *)IPC_GET_ARG2(call->data);
122
    t = (thread_t *)IPC_GET_ARG2(call->data);
120
 
123
 
121
    rc = udebug_stop(t, call);
124
    rc = udebug_stop(t, call);
122
    IPC_SET_RETVAL(call->data, rc);
125
    IPC_SET_RETVAL(call->data, rc);
123
    ipc_answer(&TASK->kernel_box, call);
126
    ipc_answer(&TASK->kernel_box, call);
124
}
127
}
125
 
128
 
126
static void udebug_receive_thread_read(call_t *call)
129
static void udebug_receive_thread_read(call_t *call)
127
{
130
{
128
    unative_t uspace_addr;
131
    unative_t uspace_addr;
129
    unative_t to_copy;
132
    unative_t to_copy;
130
    unsigned total_bytes;
133
    unsigned total_bytes;
131
    unsigned buf_size;
134
    unsigned buf_size;
132
    void *buffer;
135
    void *buffer;
133
    size_t n;
136
    size_t n;
134
    int rc;
137
    int rc;
135
 
138
 
136
    uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
139
    uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
137
    buf_size = IPC_GET_ARG3(call->data);    /* Dest. buffer size */
140
    buf_size = IPC_GET_ARG3(call->data);    /* Dest. buffer size */
138
 
141
 
139
    /*
142
    /*
140
     * Read thread list. Variable n will be filled with actual number
143
     * Read thread list. Variable n will be filled with actual number
141
     * of threads times thread-id size.
144
     * of threads times thread-id size.
142
     */
145
     */
143
    rc = udebug_thread_read(&buffer, buf_size, &n);
146
    rc = udebug_thread_read(&buffer, buf_size, &n);
144
    if (rc < 0) {
147
    if (rc < 0) {
145
        IPC_SET_RETVAL(call->data, rc);
148
        IPC_SET_RETVAL(call->data, rc);
146
        ipc_answer(&TASK->kernel_box, call);
149
        ipc_answer(&TASK->kernel_box, call);
147
        return;
150
        return;
148
    }
151
    }
149
 
152
 
150
    total_bytes = n;
153
    total_bytes = n;
151
 
154
 
152
    /* Copy MAX(buf_size, total_bytes) bytes */
155
    /* Copy MAX(buf_size, total_bytes) bytes */
153
 
156
 
154
    if (buf_size > total_bytes)
157
    if (buf_size > total_bytes)
155
        to_copy = total_bytes;
158
        to_copy = total_bytes;
156
    else
159
    else
157
        to_copy = buf_size;
160
        to_copy = buf_size;
158
 
161
 
159
    /*
162
    /*
160
     * Make use of call->buffer to transfer data to caller's userspace
163
     * Make use of call->buffer to transfer data to caller's userspace
161
     */
164
     */
162
 
165
 
163
    IPC_SET_RETVAL(call->data, 0);
166
    IPC_SET_RETVAL(call->data, 0);
164
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
167
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
165
       same code in process_answer() can be used
168
       same code in process_answer() can be used
166
       (no way to distinguish method in answer) */
169
       (no way to distinguish method in answer) */
167
    IPC_SET_ARG1(call->data, uspace_addr);
170
    IPC_SET_ARG1(call->data, uspace_addr);
168
    IPC_SET_ARG2(call->data, to_copy);
171
    IPC_SET_ARG2(call->data, to_copy);
169
 
172
 
170
    IPC_SET_ARG3(call->data, total_bytes);
173
    IPC_SET_ARG3(call->data, total_bytes);
171
    call->buffer = buffer;
174
    call->buffer = buffer;
172
 
175
 
173
    ipc_answer(&TASK->kernel_box, call);
176
    ipc_answer(&TASK->kernel_box, call);
174
}
177
}
175
 
178
 
176
static void udebug_receive_args_read(call_t *call)
179
static void udebug_receive_args_read(call_t *call)
177
{
180
{
178
    thread_t *t;
181
    thread_t *t;
179
    unative_t uspace_addr;
182
    unative_t uspace_addr;
180
    int rc;
183
    int rc;
181
    void *buffer;
184
    void *buffer;
182
 
185
 
183
    t = (thread_t *)IPC_GET_ARG2(call->data);
186
    t = (thread_t *)IPC_GET_ARG2(call->data);
184
 
187
 
185
    rc = udebug_args_read(t, &buffer);
188
    rc = udebug_args_read(t, &buffer);
186
    if (rc != EOK) {
189
    if (rc != EOK) {
187
        IPC_SET_RETVAL(call->data, rc);
190
        IPC_SET_RETVAL(call->data, rc);
188
        ipc_answer(&TASK->kernel_box, call);
191
        ipc_answer(&TASK->kernel_box, call);
189
        return;
192
        return;
190
    }
193
    }
191
 
194
 
192
    /*
195
    /*
193
     * Make use of call->buffer to transfer data to caller's userspace
196
     * Make use of call->buffer to transfer data to caller's userspace
194
     */
197
     */
195
 
198
 
196
    uspace_addr = IPC_GET_ARG3(call->data);
199
    uspace_addr = IPC_GET_ARG3(call->data);
197
 
200
 
198
    IPC_SET_RETVAL(call->data, 0);
201
    IPC_SET_RETVAL(call->data, 0);
199
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
202
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
200
       same code in process_answer() can be used
203
       same code in process_answer() can be used
201
       (no way to distinguish method in answer) */
204
       (no way to distinguish method in answer) */
202
    IPC_SET_ARG1(call->data, uspace_addr);
205
    IPC_SET_ARG1(call->data, uspace_addr);
203
    IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
206
    IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
204
    call->buffer = buffer;
207
    call->buffer = buffer;
205
 
208
 
206
    ipc_answer(&TASK->kernel_box, call);
209
    ipc_answer(&TASK->kernel_box, call);
207
}
210
}
208
 
211
 
209
static void udebug_receive_mem_read(call_t *call)
212
static void udebug_receive_mem_read(call_t *call)
210
{
213
{
211
    unative_t uspace_dst;
214
    unative_t uspace_dst;
212
    unative_t uspace_src;
215
    unative_t uspace_src;
213
    unsigned size;
216
    unsigned size;
214
    void *buffer;
217
    void *buffer;
215
    int rc;
218
    int rc;
216
 
219
 
217
    uspace_dst = IPC_GET_ARG2(call->data);
220
    uspace_dst = IPC_GET_ARG2(call->data);
218
    uspace_src = IPC_GET_ARG3(call->data);
221
    uspace_src = IPC_GET_ARG3(call->data);
219
    size = IPC_GET_ARG4(call->data);
222
    size = IPC_GET_ARG4(call->data);
220
 
223
 
221
    rc = udebug_mem_read(uspace_src, size, &buffer);
224
    rc = udebug_mem_read(uspace_src, size, &buffer);
222
    if (rc < 0) {
225
    if (rc < 0) {
223
        IPC_SET_RETVAL(call->data, rc);
226
        IPC_SET_RETVAL(call->data, rc);
224
        ipc_answer(&TASK->kernel_box, call);
227
        ipc_answer(&TASK->kernel_box, call);
225
        return;
228
        return;
226
    }
229
    }
227
 
230
 
228
    IPC_SET_RETVAL(call->data, 0);
231
    IPC_SET_RETVAL(call->data, 0);
229
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
232
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
230
       same code in process_answer() can be used
233
       same code in process_answer() can be used
231
       (no way to distinguish method in answer) */
234
       (no way to distinguish method in answer) */
232
    IPC_SET_ARG1(call->data, uspace_dst);
235
    IPC_SET_ARG1(call->data, uspace_dst);
233
    IPC_SET_ARG2(call->data, size);
236
    IPC_SET_ARG2(call->data, size);
234
    call->buffer = buffer;
237
    call->buffer = buffer;
235
 
238
 
236
    ipc_answer(&TASK->kernel_box, call);
239
    ipc_answer(&TASK->kernel_box, call);
237
}
240
}
238
 
241
 
239
/**
242
/**
240
 * Handle a debug call received on the kernel answerbox.
243
 * Handle a debug call received on the kernel answerbox.
241
 *
244
 *
242
 * This is called by the kbox servicing thread.
245
 * This is called by the kbox servicing thread.
243
 */
246
 */
244
void udebug_call_receive(call_t *call)
247
void udebug_call_receive(call_t *call)
245
{
248
{
246
    int debug_method;
249
    int debug_method;
247
 
250
 
248
    debug_method = IPC_GET_ARG1(call->data);
251
    debug_method = IPC_GET_ARG1(call->data);
249
 
252
 
250
    if (debug_method != UDEBUG_M_BEGIN) {
253
    if (debug_method != UDEBUG_M_BEGIN) {
251
        /*
254
        /*
252
         * Verify that the sender is this task's debugger.
255
         * Verify that the sender is this task's debugger.
253
         * Note that this is the only thread that could change
256
         * Note that this is the only thread that could change
254
         * TASK->debugger. Therefore no locking is necessary
257
         * TASK->debugger. Therefore no locking is necessary
255
         * and the sender can be safely considered valid until
258
         * and the sender can be safely considered valid until
256
         * control exits this function.
259
         * control exits this function.
257
         */
260
         */
258
        if (TASK->udebug.debugger != call->sender) {
261
        if (TASK->udebug.debugger != call->sender) {
259
            IPC_SET_RETVAL(call->data, EINVAL);
262
            IPC_SET_RETVAL(call->data, EINVAL);
260
            ipc_answer(&TASK->kernel_box, call);
263
            ipc_answer(&TASK->kernel_box, call);
261
            return;
264
            return;
262
        }
265
        }
263
    }
266
    }
264
 
267
 
265
    switch (debug_method) {
268
    switch (debug_method) {
266
    case UDEBUG_M_BEGIN:
269
    case UDEBUG_M_BEGIN:
267
        udebug_receive_begin(call);
270
        udebug_receive_begin(call);
268
        break;
271
        break;
269
    case UDEBUG_M_END:
272
    case UDEBUG_M_END:
270
        udebug_receive_end(call);
273
        udebug_receive_end(call);
271
        break;
274
        break;
272
    case UDEBUG_M_SET_EVMASK:
275
    case UDEBUG_M_SET_EVMASK:
273
        udebug_receive_set_evmask(call);
276
        udebug_receive_set_evmask(call);
274
        break;
277
        break;
275
    case UDEBUG_M_GO:
278
    case UDEBUG_M_GO:
276
        udebug_receive_go(call);
279
        udebug_receive_go(call);
277
        break;
280
        break;
278
    case UDEBUG_M_STOP:
281
    case UDEBUG_M_STOP:
279
        udebug_receive_stop(call);
282
        udebug_receive_stop(call);
280
        break;
283
        break;
281
    case UDEBUG_M_THREAD_READ:
284
    case UDEBUG_M_THREAD_READ:
282
        udebug_receive_thread_read(call);
285
        udebug_receive_thread_read(call);
283
        break;
286
        break;
284
    case UDEBUG_M_ARGS_READ:
287
    case UDEBUG_M_ARGS_READ:
285
        udebug_receive_args_read(call);
288
        udebug_receive_args_read(call);
286
        break;
289
        break;
287
    case UDEBUG_M_MEM_READ:
290
    case UDEBUG_M_MEM_READ:
288
        udebug_receive_mem_read(call);
291
        udebug_receive_mem_read(call);
289
        break;
292
        break;
290
    }
293
    }
291
}
294
}
292
 
295
 
293
/** @}
296
/** @}
294
 */
297
 */
295
 
298