Subversion Repositories HelenOS

Rev

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

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