Rev 2827 | Rev 2834 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2827 | Rev 2833 | ||
---|---|---|---|
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_go(call_t *call, phone_t *phone) |
121 | static int udebug_rp_go(call_t *call, phone_t *phone) |
122 | { |
122 | { |
123 | thread_t *t; |
123 | thread_t *t; |
124 | task_t *ta; |
124 | task_t *ta; |
125 | ipl_t ipl; |
125 | ipl_t ipl; |
126 | 126 | ||
127 | klog_printf("debug_go()"); |
127 | klog_printf("debug_go()"); |
128 | ta = get_lock_callee_task(phone); |
128 | ta = get_lock_callee_task(phone); |
129 | spinlock_unlock(&ta->lock); |
129 | spinlock_unlock(&ta->lock); |
130 | // TODO: don't lock ta |
130 | // TODO: don't lock ta |
131 | 131 | ||
132 | t = (thread_t *) IPC_GET_ARG2(call->data); |
132 | t = (thread_t *) IPC_GET_ARG2(call->data); |
133 | 133 | ||
134 | ipl = interrupts_disable(); |
134 | ipl = interrupts_disable(); |
135 | spinlock_lock(&threads_lock); |
135 | spinlock_lock(&threads_lock); |
136 | 136 | ||
137 | /* Verify that 't' exists and belongs to task 'ta' */ |
137 | /* Verify that 't' exists and belongs to task 'ta' */ |
138 | if (!thread_exists(t) || (t->task != ta)) { |
138 | if (!thread_exists(t) || (t->task != ta)) { |
139 | spinlock_unlock(&threads_lock); |
139 | spinlock_unlock(&threads_lock); |
140 | interrupts_restore(ipl); |
140 | interrupts_restore(ipl); |
141 | return ENOENT; |
141 | return ENOENT; |
142 | } |
142 | } |
143 | 143 | ||
144 | if ((t->debug_active != true) || (t->debug_stop != true)) { |
144 | if ((t->debug_active != true) || (t->debug_stop != true)) { |
145 | /* Not in debugging session or already has GO */ |
145 | /* Not in debugging session or already has GO */ |
146 | spinlock_unlock(&threads_lock); |
146 | spinlock_unlock(&threads_lock); |
147 | interrupts_restore(ipl); |
147 | interrupts_restore(ipl); |
148 | return EBUSY; |
148 | return EBUSY; |
149 | } |
149 | } |
150 | 150 | ||
151 | t->debug_go_call = call; |
151 | t->debug_go_call = call; |
152 | t->debug_stop = false; |
152 | t->debug_stop = false; |
153 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
153 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
154 | 154 | ||
155 | spinlock_unlock(&threads_lock); |
155 | spinlock_unlock(&threads_lock); |
156 | interrupts_restore(ipl); |
156 | interrupts_restore(ipl); |
157 | 157 | ||
158 | return 0; /* no backsend */ |
158 | return 0; /* no backsend */ |
159 | } |
159 | } |
160 | 160 | ||
161 | static int udebug_rp_args_read(call_t *call, phone_t *phone) |
161 | static int udebug_rp_args_read(call_t *call, phone_t *phone) |
162 | { |
162 | { |
163 | thread_t *t; |
163 | thread_t *t; |
164 | task_t *ta; |
164 | task_t *ta; |
165 | void *uspace_buffer; |
165 | void *uspace_buffer; |
166 | unative_t to_copy; |
- | |
167 | int rc; |
166 | int rc; |
168 | ipl_t ipl; |
167 | ipl_t ipl; |
169 | unative_t buffer[6]; |
168 | unative_t buffer[6]; |
170 | 169 | ||
171 | klog_printf("debug_args_read()"); |
170 | klog_printf("debug_args_read()"); |
172 | 171 | ||
173 | ta = get_lock_callee_task(phone); |
172 | ta = get_lock_callee_task(phone); |
174 | klog_printf("task %llu", ta->taskid); |
173 | klog_printf("task %llu", ta->taskid); |
175 | spinlock_unlock(&ta->lock); |
174 | spinlock_unlock(&ta->lock); |
176 | 175 | ||
177 | t = (thread_t *) IPC_GET_ARG2(call->data); |
176 | t = (thread_t *) IPC_GET_ARG2(call->data); |
178 | 177 | ||
179 | ipl = interrupts_disable(); |
178 | ipl = interrupts_disable(); |
180 | spinlock_lock(&threads_lock); |
179 | spinlock_lock(&threads_lock); |
181 | 180 | ||
182 | /* Verify that 't' exists and belongs to task 'ta' */ |
181 | /* Verify that 't' exists and belongs to task 'ta' */ |
183 | if (!thread_exists(t) || (t->task != ta)) { |
182 | if (!thread_exists(t) || (t->task != ta)) { |
184 | spinlock_unlock(&threads_lock); |
183 | spinlock_unlock(&threads_lock); |
185 | interrupts_restore(ipl); |
184 | interrupts_restore(ipl); |
186 | return ENOENT; |
185 | return ENOENT; |
187 | } |
186 | } |
188 | 187 | ||
189 | //FIXME: additionally we need to verify that we are inside a syscall |
188 | //FIXME: additionally we need to verify that we are inside a syscall |
190 | if ((t->debug_active != true) || (t->debug_stop != true)) { |
189 | if ((t->debug_active != true) || (t->debug_stop != true)) { |
191 | /* Not in debugging session or has GO */ |
190 | /* Not in debugging session or has GO */ |
192 | spinlock_unlock(&threads_lock); |
191 | spinlock_unlock(&threads_lock); |
193 | interrupts_restore(ipl); |
192 | interrupts_restore(ipl); |
194 | return EBUSY; |
193 | return EBUSY; |
195 | } |
194 | } |
196 | 195 | ||
197 | /* Copy to a local buffer before releasing the lock */ |
196 | /* Copy to a local buffer before releasing the lock */ |
198 | memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t)); |
197 | memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t)); |
199 | 198 | ||
200 | spinlock_unlock(&threads_lock); |
199 | spinlock_unlock(&threads_lock); |
201 | interrupts_restore(ipl); |
200 | interrupts_restore(ipl); |
202 | 201 | ||
203 | /* Now copy to userspace */ |
202 | /* Now copy to userspace */ |
204 | 203 | ||
205 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
204 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
206 | to_copy = IPC_GET_ARG4(call->data); |
- | |
207 | if (to_copy > 6 * sizeof(unative_t)) to_copy = 6 * sizeof(unative_t); |
- | |
208 | 205 | ||
209 | rc = copy_to_uspace(uspace_buffer, buffer, to_copy); |
206 | rc = copy_to_uspace(uspace_buffer, buffer, 6 * sizeof(unative_t)); |
210 | if (rc != 0) { |
207 | if (rc != 0) { |
211 | spinlock_unlock(&ta->lock); |
208 | spinlock_unlock(&ta->lock); |
212 | klog_printf("debug_args_read() - copy failed"); |
209 | klog_printf("debug_args_read() - copy failed"); |
213 | return rc; |
210 | return rc; |
214 | } |
211 | } |
215 | 212 | ||
216 | IPC_SET_ARG1(call->data, to_copy); |
- | |
217 | - | ||
218 | klog_printf("debug_args_read() done"); |
213 | klog_printf("debug_args_read() done"); |
219 | return 1; /* actually need becksend with retval 0 */ |
214 | return 1; /* actually need becksend with retval 0 */ |
220 | } |
215 | } |
221 | 216 | ||
222 | static int udebug_rp_regs_read(call_t *call, phone_t *phone) |
217 | static int udebug_rp_regs_read(call_t *call, phone_t *phone) |
223 | { |
218 | { |
224 | thread_t *t; |
219 | thread_t *t; |
225 | task_t *ta; |
220 | task_t *ta; |
226 | void *uspace_buffer; |
221 | void *uspace_buffer; |
227 | unative_t to_copy; |
222 | unative_t to_copy; |
228 | int rc; |
223 | int rc; |
229 | istate_t *state; |
224 | istate_t *state; |
230 | istate_t state_copy; |
225 | istate_t state_copy; |
231 | ipl_t ipl; |
226 | ipl_t ipl; |
232 | 227 | ||
233 | klog_printf("debug_regs_read()"); |
228 | klog_printf("debug_regs_read()"); |
234 | 229 | ||
235 | ta = get_lock_callee_task(phone); |
230 | ta = get_lock_callee_task(phone); |
236 | spinlock_unlock(&ta->lock); |
231 | spinlock_unlock(&ta->lock); |
237 | //FIXME: don't lock ta |
232 | //FIXME: don't lock ta |
238 | 233 | ||
239 | ipl = interrupts_disable(); |
234 | ipl = interrupts_disable(); |
240 | spinlock_lock(&threads_lock); |
235 | spinlock_lock(&threads_lock); |
241 | 236 | ||
242 | t = (thread_t *) IPC_GET_ARG2(call->data); |
237 | t = (thread_t *) IPC_GET_ARG2(call->data); |
243 | 238 | ||
244 | /* Verify that 't' exists and belongs to task 'ta' */ |
239 | /* Verify that 't' exists and belongs to task 'ta' */ |
245 | if (!thread_exists(t) || (t->task != ta)) { |
240 | if (!thread_exists(t) || (t->task != ta)) { |
246 | spinlock_unlock(&threads_lock); |
241 | spinlock_unlock(&threads_lock); |
247 | interrupts_restore(ipl); |
242 | interrupts_restore(ipl); |
248 | return ENOENT; |
243 | return ENOENT; |
249 | } |
244 | } |
250 | 245 | ||
251 | if ((t->debug_active != true) || (t->debug_stop != true)) { |
246 | if ((t->debug_active != true) || (t->debug_stop != true)) { |
252 | /* Not in debugging session or has GO */ |
247 | /* Not in debugging session or has GO */ |
253 | spinlock_unlock(&threads_lock); |
248 | spinlock_unlock(&threads_lock); |
254 | interrupts_restore(ipl); |
249 | interrupts_restore(ipl); |
255 | return EBUSY; |
250 | return EBUSY; |
256 | } |
251 | } |
257 | 252 | ||
258 | state = t->uspace_state; |
253 | state = t->uspace_state; |
259 | if (state == NULL) { |
254 | if (state == NULL) { |
260 | spinlock_unlock(&threads_lock); |
255 | spinlock_unlock(&threads_lock); |
261 | interrupts_restore(ipl); |
256 | interrupts_restore(ipl); |
262 | klog_printf("debug_regs_read() - istate not available"); |
257 | klog_printf("debug_regs_read() - istate not available"); |
263 | return EBUSY; |
258 | return EBUSY; |
264 | } |
259 | } |
265 | 260 | ||
266 | /* Copy to a local buffer so that we can release the lock */ |
261 | /* Copy to a local buffer so that we can release the lock */ |
267 | memcpy(&state_copy, state, sizeof(state_copy)); |
262 | memcpy(&state_copy, state, sizeof(state_copy)); |
268 | spinlock_unlock(&threads_lock); |
263 | spinlock_unlock(&threads_lock); |
269 | interrupts_restore(ipl); |
264 | interrupts_restore(ipl); |
270 | 265 | ||
271 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
266 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
272 | to_copy = IPC_GET_ARG4(call->data); |
267 | to_copy = IPC_GET_ARG4(call->data); |
273 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
268 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
274 | 269 | ||
275 | rc = copy_to_uspace(uspace_buffer, &state_copy, to_copy); |
270 | rc = copy_to_uspace(uspace_buffer, &state_copy, to_copy); |
276 | if (rc != 0) { |
271 | if (rc != 0) { |
277 | spinlock_unlock(&ta->lock); |
272 | spinlock_unlock(&ta->lock); |
278 | klog_printf("debug_regs_read() - copy failed"); |
273 | klog_printf("debug_regs_read() - copy failed"); |
279 | return rc; |
274 | return rc; |
280 | } |
275 | } |
281 | 276 | ||
282 | IPC_SET_ARG1(call->data, to_copy); |
277 | IPC_SET_ARG1(call->data, to_copy); |
283 | IPC_SET_ARG2(call->data, sizeof(istate_t)); |
278 | IPC_SET_ARG2(call->data, sizeof(istate_t)); |
284 | 279 | ||
285 | klog_printf("debug_regs_read() done"); |
280 | klog_printf("debug_regs_read() done"); |
286 | return 1; /* actually need becksend with retval 0 */ |
281 | return 1; /* actually need becksend with retval 0 */ |
287 | } |
282 | } |
288 | 283 | ||
289 | static int udebug_rp_regs_write(call_t *call, phone_t *phone) |
284 | static int udebug_rp_regs_write(call_t *call, phone_t *phone) |
290 | { |
285 | { |
291 | thread_t *t; |
286 | thread_t *t; |
292 | task_t *ta; |
287 | task_t *ta; |
293 | void *uspace_data; |
288 | void *uspace_data; |
294 | unative_t to_copy; |
289 | unative_t to_copy; |
295 | int rc; |
290 | int rc; |
296 | istate_t *state; |
291 | istate_t *state; |
297 | istate_t data_copy; |
292 | istate_t data_copy; |
298 | ipl_t ipl; |
293 | ipl_t ipl; |
299 | 294 | ||
300 | klog_printf("debug_regs_write()"); |
295 | klog_printf("debug_regs_write()"); |
301 | 296 | ||
302 | /* First copy to a local buffer */ |
297 | /* First copy to a local buffer */ |
303 | 298 | ||
304 | uspace_data = (void *)IPC_GET_ARG3(call->data); |
299 | uspace_data = (void *)IPC_GET_ARG3(call->data); |
305 | to_copy = IPC_GET_ARG4(call->data); |
300 | to_copy = IPC_GET_ARG4(call->data); |
306 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
301 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
307 | 302 | ||
308 | rc = copy_from_uspace(&data_copy, uspace_data, to_copy); |
303 | rc = copy_from_uspace(&data_copy, uspace_data, to_copy); |
309 | if (rc != 0) { |
304 | if (rc != 0) { |
310 | klog_printf("debug_regs_write() - copy failed"); |
305 | klog_printf("debug_regs_write() - copy failed"); |
311 | return rc; |
306 | return rc; |
312 | } |
307 | } |
313 | 308 | ||
314 | ta = get_lock_callee_task(phone); |
309 | ta = get_lock_callee_task(phone); |
315 | spinlock_unlock(&ta->lock); |
310 | spinlock_unlock(&ta->lock); |
316 | //FIXME: don't lock ta |
311 | //FIXME: don't lock ta |
317 | 312 | ||
318 | /* Now try to change the thread's uspace_state */ |
313 | /* Now try to change the thread's uspace_state */ |
319 | 314 | ||
320 | ipl = interrupts_disable(); |
315 | ipl = interrupts_disable(); |
321 | spinlock_lock(&threads_lock); |
316 | spinlock_lock(&threads_lock); |
322 | 317 | ||
323 | t = (thread_t *) IPC_GET_ARG2(call->data); |
318 | t = (thread_t *) IPC_GET_ARG2(call->data); |
324 | 319 | ||
325 | /* Verify that 't' exists and belongs to task 'ta' */ |
320 | /* Verify that 't' exists and belongs to task 'ta' */ |
326 | if (!thread_exists(t) || (t->task != ta)) { |
321 | if (!thread_exists(t) || (t->task != ta)) { |
327 | spinlock_unlock(&threads_lock); |
322 | spinlock_unlock(&threads_lock); |
328 | interrupts_restore(ipl); |
323 | interrupts_restore(ipl); |
329 | return ENOENT; |
324 | return ENOENT; |
330 | } |
325 | } |
331 | 326 | ||
332 | if ((t->debug_active != true) || (t->debug_stop != true)) { |
327 | if ((t->debug_active != true) || (t->debug_stop != true)) { |
333 | /* Not in debugging session or has GO */ |
328 | /* Not in debugging session or has GO */ |
334 | spinlock_unlock(&threads_lock); |
329 | spinlock_unlock(&threads_lock); |
335 | interrupts_restore(ipl); |
330 | interrupts_restore(ipl); |
336 | return EBUSY; |
331 | return EBUSY; |
337 | } |
332 | } |
338 | 333 | ||
339 | state = t->uspace_state; |
334 | state = t->uspace_state; |
340 | if (state == NULL) { |
335 | if (state == NULL) { |
341 | spinlock_unlock(&threads_lock); |
336 | spinlock_unlock(&threads_lock); |
342 | interrupts_restore(ipl); |
337 | interrupts_restore(ipl); |
343 | klog_printf("debug_regs_write() - istate not available"); |
338 | klog_printf("debug_regs_write() - istate not available"); |
344 | return EBUSY; |
339 | return EBUSY; |
345 | } |
340 | } |
346 | 341 | ||
347 | memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state)); |
342 | memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state)); |
348 | 343 | ||
349 | spinlock_unlock(&threads_lock); |
344 | spinlock_unlock(&threads_lock); |
350 | interrupts_restore(ipl); |
345 | interrupts_restore(ipl); |
351 | 346 | ||
352 | /* Set answer values */ |
347 | /* Set answer values */ |
353 | 348 | ||
354 | IPC_SET_ARG1(call->data, to_copy); |
349 | IPC_SET_ARG1(call->data, to_copy); |
355 | IPC_SET_ARG2(call->data, sizeof(istate_t)); |
350 | IPC_SET_ARG2(call->data, sizeof(istate_t)); |
356 | 351 | ||
357 | klog_printf("debug_regs_write() done"); |
352 | klog_printf("debug_regs_write() done"); |
358 | return 1; /* actually need becksend with retval 0 */ |
353 | return 1; /* actually need becksend with retval 0 */ |
359 | } |
354 | } |
360 | 355 | ||
361 | static int udebug_rp_thread_read(call_t *call, phone_t *phone) |
356 | static int udebug_rp_thread_read(call_t *call, phone_t *phone) |
362 | { |
357 | { |
363 | thread_t *t; |
358 | thread_t *t; |
364 | link_t *cur; |
359 | link_t *cur; |
365 | task_t *ta; |
360 | task_t *ta; |
366 | unative_t *uspace_buffer; |
361 | unative_t *uspace_buffer; |
367 | unative_t to_copy; |
362 | unative_t to_copy; |
368 | int rc; |
363 | int rc; |
369 | unsigned total_bytes; |
364 | unsigned total_bytes; |
370 | unsigned buf_size; |
365 | unsigned buf_size; |
371 | unative_t tid; |
366 | unative_t tid; |
372 | unsigned num_threads, copied_ids; |
367 | unsigned num_threads, copied_ids; |
373 | ipl_t ipl; |
368 | ipl_t ipl; |
374 | unative_t *buffer; |
369 | unative_t *buffer; |
375 | int flags; |
370 | int flags; |
376 | 371 | ||
377 | klog_printf("debug_thread_read()"); |
372 | klog_printf("debug_thread_read()"); |
378 | 373 | ||
379 | ipl = interrupts_disable(); |
374 | ipl = interrupts_disable(); |
380 | ta = get_lock_callee_task(phone); |
375 | ta = get_lock_callee_task(phone); |
381 | 376 | ||
382 | /* Verify task state */ |
377 | /* Verify task state */ |
383 | if (ta->dt_state != UDEBUG_TS_ACTIVE) { |
378 | if (ta->dt_state != UDEBUG_TS_ACTIVE) { |
384 | spinlock_unlock(&ta->lock); |
379 | spinlock_unlock(&ta->lock); |
385 | interrupts_restore(ipl); |
380 | interrupts_restore(ipl); |
386 | return EBUSY; |
381 | return EBUSY; |
387 | } |
382 | } |
388 | 383 | ||
389 | /* Count the threads first */ |
384 | /* Count the threads first */ |
390 | 385 | ||
391 | num_threads = 0; |
386 | num_threads = 0; |
392 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
387 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
393 | /* Count all threads, to be on the safe side */ |
388 | /* Count all threads, to be on the safe side */ |
394 | ++num_threads; |
389 | ++num_threads; |
395 | } |
390 | } |
396 | 391 | ||
397 | /* Allocate a buffer and copy down the threads' ids */ |
392 | /* Allocate a buffer and copy down the threads' ids */ |
398 | buffer = malloc(num_threads * sizeof(unative_t), 0); // ??? |
393 | buffer = malloc(num_threads * sizeof(unative_t), 0); // ??? |
399 | 394 | ||
400 | copied_ids = 0; |
395 | copied_ids = 0; |
401 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
396 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
402 | t = list_get_instance(cur, thread_t, th_link); |
397 | t = list_get_instance(cur, thread_t, th_link); |
403 | 398 | ||
404 | spinlock_lock(&t->lock); |
399 | spinlock_lock(&t->lock); |
405 | flags = t->flags; |
400 | flags = t->flags; |
406 | spinlock_unlock(&t->lock); |
401 | spinlock_unlock(&t->lock); |
407 | 402 | ||
408 | /* Not interested in kernel threads */ |
403 | /* Not interested in kernel threads */ |
409 | if ((flags & THREAD_FLAG_USPACE) != 0) { |
404 | if ((flags & THREAD_FLAG_USPACE) != 0) { |
410 | /* Using thread struct pointer for identification */ |
405 | /* Using thread struct pointer for identification */ |
411 | tid = (unative_t) t; |
406 | tid = (unative_t) t; |
412 | buffer[copied_ids++] = tid; |
407 | buffer[copied_ids++] = tid; |
413 | } |
408 | } |
414 | } |
409 | } |
415 | 410 | ||
416 | spinlock_unlock(&ta->lock); |
411 | spinlock_unlock(&ta->lock); |
417 | interrupts_restore(ipl); |
412 | interrupts_restore(ipl); |
418 | 413 | ||
419 | /* Now copy to userspace */ |
414 | /* Now copy to userspace */ |
420 | 415 | ||
421 | uspace_buffer = (void *)IPC_GET_ARG2(call->data); |
416 | uspace_buffer = (void *)IPC_GET_ARG2(call->data); |
422 | buf_size = IPC_GET_ARG3(call->data); |
417 | buf_size = IPC_GET_ARG3(call->data); |
423 | 418 | ||
424 | total_bytes = copied_ids * sizeof(unative_t); |
419 | total_bytes = copied_ids * sizeof(unative_t); |
425 | 420 | ||
426 | if (buf_size > total_bytes) |
421 | if (buf_size > total_bytes) |
427 | to_copy = total_bytes; |
422 | to_copy = total_bytes; |
428 | else |
423 | else |
429 | to_copy = buf_size; |
424 | to_copy = buf_size; |
430 | 425 | ||
431 | rc = copy_to_uspace(uspace_buffer, buffer, to_copy); |
426 | rc = copy_to_uspace(uspace_buffer, buffer, to_copy); |
432 | free(buffer); |
427 | free(buffer); |
433 | 428 | ||
434 | if (rc != 0) { |
429 | if (rc != 0) { |
435 | klog_printf("debug_thread_read() - copy failed"); |
430 | klog_printf("debug_thread_read() - copy failed"); |
436 | return rc; |
431 | return rc; |
437 | } |
432 | } |
438 | 433 | ||
439 | IPC_SET_ARG1(call->data, to_copy); |
434 | IPC_SET_ARG1(call->data, to_copy); |
440 | IPC_SET_ARG2(call->data, total_bytes); |
435 | IPC_SET_ARG2(call->data, total_bytes); |
441 | 436 | ||
442 | klog_printf("debug_thread_read() done"); |
437 | klog_printf("debug_thread_read() done"); |
443 | return 1; /* actually need becksend with retval 0 */ |
438 | return 1; /* actually need becksend with retval 0 */ |
444 | } |
439 | } |
445 | 440 | ||
446 | static int udebug_rp_mem_write(call_t *call, phone_t *phone) |
441 | static int udebug_rp_mem_write(call_t *call, phone_t *phone) |
447 | { |
442 | { |
448 | void *uspace_data; |
443 | void *uspace_data; |
449 | unative_t to_copy; |
444 | unative_t to_copy; |
450 | int rc; |
445 | int rc; |
451 | void *buffer; |
446 | void *buffer; |
452 | 447 | ||
453 | klog_printf("udebug_rp_mem_write()"); |
448 | klog_printf("udebug_rp_mem_write()"); |
454 | 449 | ||
455 | uspace_data = (void *)IPC_GET_ARG2(call->data); |
450 | uspace_data = (void *)IPC_GET_ARG2(call->data); |
456 | to_copy = IPC_GET_ARG4(call->data); |
451 | to_copy = IPC_GET_ARG4(call->data); |
457 | 452 | ||
458 | buffer = malloc(to_copy, 0); // ??? |
453 | buffer = malloc(to_copy, 0); // ??? |
459 | 454 | ||
460 | rc = copy_from_uspace(buffer, uspace_data, to_copy); |
455 | rc = copy_from_uspace(buffer, uspace_data, to_copy); |
461 | if (rc != 0) { |
456 | if (rc != 0) { |
462 | klog_printf(" - copy failed"); |
457 | klog_printf(" - copy failed"); |
463 | return rc; |
458 | return rc; |
464 | } |
459 | } |
465 | 460 | ||
466 | call->buffer = buffer; |
461 | call->buffer = buffer; |
467 | 462 | ||
468 | klog_printf(" - done"); |
463 | klog_printf(" - done"); |
469 | return 1; /* actually need becksend with retval 0 */ |
464 | return 1; /* actually need becksend with retval 0 */ |
470 | } |
465 | } |
471 | 466 | ||
472 | 467 | ||
473 | int udebug_request_preprocess(call_t *call, phone_t *phone) |
468 | int udebug_request_preprocess(call_t *call, phone_t *phone) |
474 | { |
469 | { |
475 | int rc; |
470 | int rc; |
476 | 471 | ||
477 | switch (IPC_GET_ARG1(call->data)) { |
472 | switch (IPC_GET_ARG1(call->data)) { |
478 | case UDEBUG_M_BEGIN: |
473 | case UDEBUG_M_BEGIN: |
479 | rc = udebug_rp_begin(call, phone); |
474 | rc = udebug_rp_begin(call, phone); |
480 | return rc; |
475 | return rc; |
481 | case UDEBUG_M_GO: |
476 | case UDEBUG_M_GO: |
482 | rc = udebug_rp_go(call, phone); |
477 | rc = udebug_rp_go(call, phone); |
483 | return rc; |
478 | return rc; |
484 | case UDEBUG_M_ARGS_READ: |
479 | case UDEBUG_M_ARGS_READ: |
485 | rc = udebug_rp_args_read(call, phone); |
480 | rc = udebug_rp_args_read(call, phone); |
486 | return rc; |
481 | return rc; |
487 | case UDEBUG_M_REGS_READ: |
482 | case UDEBUG_M_REGS_READ: |
488 | rc = udebug_rp_regs_read(call, phone); |
483 | rc = udebug_rp_regs_read(call, phone); |
489 | return rc; |
484 | return rc; |
490 | case UDEBUG_M_REGS_WRITE: |
485 | case UDEBUG_M_REGS_WRITE: |
491 | rc = udebug_rp_regs_write(call, phone); |
486 | rc = udebug_rp_regs_write(call, phone); |
492 | return rc; |
487 | return rc; |
493 | case UDEBUG_M_THREAD_READ: |
488 | case UDEBUG_M_THREAD_READ: |
494 | rc = udebug_rp_thread_read(call, phone); |
489 | rc = udebug_rp_thread_read(call, phone); |
495 | return rc; |
490 | return rc; |
496 | case UDEBUG_M_MEM_WRITE: |
491 | case UDEBUG_M_MEM_WRITE: |
497 | rc = udebug_rp_mem_write(call, phone); |
492 | rc = udebug_rp_mem_write(call, phone); |
498 | return rc; |
493 | return rc; |
499 | default: |
494 | default: |
500 | break; |
495 | break; |
501 | } |
496 | } |
502 | 497 | ||
503 | return 0; |
498 | return 0; |
504 | } |
499 | } |
505 | 500 | ||
506 | static void udebug_receive_mem_read(call_t *call) |
501 | static void udebug_receive_mem_read(call_t *call) |
507 | { |
502 | { |
508 | unative_t uspace_dst; |
503 | unative_t uspace_dst; |
509 | void *uspace_ptr; |
504 | void *uspace_ptr; |
510 | unsigned size; |
505 | unsigned size; |
511 | void *buffer; |
506 | void *buffer; |
512 | int rc; |
507 | int rc; |
513 | 508 | ||
514 | klog_printf("debug_mem_read()"); |
509 | klog_printf("debug_mem_read()"); |
515 | uspace_dst = IPC_GET_ARG2(call->data); |
510 | uspace_dst = IPC_GET_ARG2(call->data); |
516 | uspace_ptr = (void *)IPC_GET_ARG3(call->data); |
511 | uspace_ptr = (void *)IPC_GET_ARG3(call->data); |
517 | size = IPC_GET_ARG4(call->data); |
512 | size = IPC_GET_ARG4(call->data); |
518 | 513 | ||
519 | buffer = malloc(size, 0); // ??? |
514 | buffer = malloc(size, 0); // ??? |
520 | klog_printf("debug_mem_read: src=%u, size=%u", uspace_ptr, size); |
515 | klog_printf("debug_mem_read: src=%u, size=%u", uspace_ptr, size); |
521 | 516 | ||
522 | /* NOTE: this is not strictly from a syscall... but that shouldn't |
517 | /* NOTE: this is not strictly from a syscall... but that shouldn't |
523 | * be a problem */ |
518 | * be a problem */ |
524 | rc = copy_from_uspace(buffer, uspace_ptr, size); |
519 | rc = copy_from_uspace(buffer, uspace_ptr, size); |
525 | if (rc) { |
520 | if (rc) { |
526 | IPC_SET_RETVAL(call->data, rc); |
521 | IPC_SET_RETVAL(call->data, rc); |
527 | return; |
522 | return; |
528 | } |
523 | } |
529 | 524 | ||
530 | klog_printf("first word: %u", *((unative_t *)buffer)); |
525 | klog_printf("first word: %u", *((unative_t *)buffer)); |
531 | 526 | ||
532 | IPC_SET_RETVAL(call->data, 0); |
527 | IPC_SET_RETVAL(call->data, 0); |
533 | /* Hack: ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that |
528 | /* Hack: ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that |
534 | same code in process_answer() can be used |
529 | same code in process_answer() can be used |
535 | (no way to distinguish method in answer) */ |
530 | (no way to distinguish method in answer) */ |
536 | IPC_SET_ARG1(call->data, uspace_dst); |
531 | IPC_SET_ARG1(call->data, uspace_dst); |
537 | IPC_SET_ARG2(call->data, size); |
532 | IPC_SET_ARG2(call->data, size); |
538 | call->buffer = buffer; |
533 | call->buffer = buffer; |
539 | 534 | ||
540 | ipc_answer(&TASK->kernel_box, call); |
535 | ipc_answer(&TASK->kernel_box, call); |
541 | } |
536 | } |
542 | 537 | ||
543 | static void udebug_receive_mem_write(call_t *call) |
538 | static void udebug_receive_mem_write(call_t *call) |
544 | { |
539 | { |
545 | void *uspace_dst; |
540 | void *uspace_dst; |
546 | unsigned size; |
541 | unsigned size; |
547 | void *buffer; |
542 | void *buffer; |
548 | int rc; |
543 | int rc; |
549 | udebug_task_state_t dts; |
544 | udebug_task_state_t dts; |
550 | 545 | ||
551 | klog_printf("udebug_receive_mem_write()"); |
546 | klog_printf("udebug_receive_mem_write()"); |
552 | 547 | ||
553 | /* Verify task state */ |
548 | /* Verify task state */ |
554 | spinlock_lock(&TASK->lock); |
549 | spinlock_lock(&TASK->lock); |
555 | dts = TASK->dt_state; |
550 | dts = TASK->dt_state; |
556 | spinlock_unlock(&TASK->lock); |
551 | spinlock_unlock(&TASK->lock); |
557 | 552 | ||
558 | if (dts != UDEBUG_TS_ACTIVE) { |
553 | if (dts != UDEBUG_TS_ACTIVE) { |
559 | IPC_SET_RETVAL(call->data, EBUSY); |
554 | IPC_SET_RETVAL(call->data, EBUSY); |
560 | ipc_answer(&TASK->kernel_box, call); |
555 | ipc_answer(&TASK->kernel_box, call); |
561 | return; |
556 | return; |
562 | } |
557 | } |
563 | 558 | ||
564 | uspace_dst = (void *)IPC_GET_ARG3(call->data); |
559 | uspace_dst = (void *)IPC_GET_ARG3(call->data); |
565 | size = IPC_GET_ARG4(call->data); |
560 | size = IPC_GET_ARG4(call->data); |
566 | 561 | ||
567 | buffer = call->buffer; |
562 | buffer = call->buffer; |
568 | klog_printf("dst=%u, size=%u", uspace_dst, size); |
563 | klog_printf("dst=%u, size=%u", uspace_dst, size); |
569 | 564 | ||
570 | /* NOTE: this is not strictly from a syscall... but that shouldn't |
565 | /* NOTE: this is not strictly from a syscall... but that shouldn't |
571 | * be a problem */ |
566 | * be a problem */ |
572 | rc = copy_to_uspace(uspace_dst, buffer, size); |
567 | rc = copy_to_uspace(uspace_dst, buffer, size); |
573 | if (rc) { |
568 | if (rc) { |
574 | IPC_SET_RETVAL(call->data, rc); |
569 | IPC_SET_RETVAL(call->data, rc); |
575 | ipc_answer(&TASK->kernel_box, call); |
570 | ipc_answer(&TASK->kernel_box, call); |
576 | return; |
571 | return; |
577 | } |
572 | } |
578 | 573 | ||
579 | IPC_SET_RETVAL(call->data, 0); |
574 | IPC_SET_RETVAL(call->data, 0); |
580 | 575 | ||
581 | free(call->buffer); |
576 | free(call->buffer); |
582 | call->buffer = NULL; |
577 | call->buffer = NULL; |
583 | 578 | ||
584 | ipc_answer(&TASK->kernel_box, call); |
579 | ipc_answer(&TASK->kernel_box, call); |
585 | } |
580 | } |
586 | 581 | ||
587 | 582 | ||
588 | /** |
583 | /** |
589 | * Handle a debug call received on the kernel answerbox. |
584 | * Handle a debug call received on the kernel answerbox. |
590 | * |
585 | * |
591 | * This is called by the kbox servicing thread. |
586 | * This is called by the kbox servicing thread. |
592 | */ |
587 | */ |
593 | void udebug_call_receive(call_t *call) |
588 | void udebug_call_receive(call_t *call) |
594 | { |
589 | { |
595 | int debug_method; |
590 | int debug_method; |
596 | 591 | ||
597 | debug_method = IPC_GET_ARG1(call->data); |
592 | debug_method = IPC_GET_ARG1(call->data); |
598 | 593 | ||
599 | switch (debug_method) { |
594 | switch (debug_method) { |
600 | case UDEBUG_M_MEM_READ: |
595 | case UDEBUG_M_MEM_READ: |
601 | udebug_receive_mem_read(call); |
596 | udebug_receive_mem_read(call); |
602 | break; |
597 | break; |
603 | case UDEBUG_M_MEM_WRITE: |
598 | case UDEBUG_M_MEM_WRITE: |
604 | udebug_receive_mem_write(call); |
599 | udebug_receive_mem_write(call); |
605 | break; |
600 | break; |
606 | } |
601 | } |
607 | } |
602 | } |
608 | 603 | ||
609 | /** @} |
604 | /** @} |
610 | */ |
605 | */ |
611 | 606 |