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