Rev 2842 | Rev 2849 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 2842 | Rev 2848 | ||
|---|---|---|---|
| Line 20... | Line 20... | ||
| 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 | * |
|
| - | 26 | * Interrupts must be already disabled. |
|
| - | 27 | * |
|
| 25 | * (TODO: make sure the udebug-cleanup of the task hasn't |
28 | * (TODO: make sure the udebug-cleanup of the task hasn't |
| 26 | * started yet) |
29 | * started yet) |
| 27 | */ |
30 | */ |
| 28 | static task_t *get_lock_callee_task(phone_t *phone) |
31 | static task_t *get_lock_callee_task(phone_t *phone) |
| 29 | { |
32 | { |
| 30 | answerbox_t *box; |
33 | answerbox_t *box; |
| 31 | task_t *ta; |
34 | task_t *ta; |
| 32 | task_id_t taskid; |
35 | task_id_t taskid; |
| 33 | ipl_t ipl; |
- | |
| 34 | 36 | ||
| 35 | ipl = interrupts_disable(); |
- | |
| 36 | spinlock_lock(&phone->lock); |
37 | spinlock_lock(&phone->lock); |
| 37 | if (phone->state != IPC_PHONE_CONNECTED) { |
38 | if (phone->state != IPC_PHONE_CONNECTED) { |
| 38 | spinlock_unlock(&phone->lock); |
39 | spinlock_unlock(&phone->lock); |
| 39 | interrupts_restore(ipl); |
- | |
| 40 | return NULL; |
40 | return NULL; |
| 41 | } |
41 | } |
| 42 | 42 | ||
| 43 | box = phone->callee; |
43 | box = phone->callee; |
| 44 | 44 | ||
| Line 52... | Line 52... | ||
| 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); |
- | |
| 58 | return NULL; |
57 | return NULL; |
| 59 | } |
58 | } |
| 60 | 59 | ||
| 61 | spinlock_lock(&ta->lock); |
60 | spinlock_lock(&ta->lock); |
| 62 | spinlock_unlock(&tasks_lock); |
61 | spinlock_unlock(&tasks_lock); |
| 63 | interrupts_restore(ipl); |
- | |
| 64 | 62 | ||
| 65 | return ta; |
63 | return ta; |
| 66 | } |
64 | } |
| 67 | 65 | ||
| 68 | /** |
66 | /** |
| Line 130... | Line 128... | ||
| 130 | /* Set debug_active on all of the task's userspace threads */ |
128 | /* Set debug_active on all of the task's userspace threads */ |
| 131 | 129 | ||
| 132 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
130 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
| 133 | t = list_get_instance(cur, thread_t, th_link); |
131 | t = list_get_instance(cur, thread_t, th_link); |
| 134 | 132 | ||
| 135 | spinlock_lock(&t->lock); |
133 | spinlock_lock(&t->debug_lock); |
| 136 | if ((t->flags & THREAD_FLAG_USPACE) != 0) |
134 | if ((t->flags & THREAD_FLAG_USPACE) != 0) |
| 137 | t->debug_active = true; |
135 | t->debug_active = true; |
| 138 | spinlock_unlock(&t->lock); |
136 | spinlock_unlock(&t->debug_lock); |
| 139 | } |
137 | } |
| 140 | 138 | ||
| 141 | spinlock_unlock(&ta->lock); |
139 | spinlock_unlock(&ta->lock); |
| 142 | interrupts_restore(ipl); |
140 | interrupts_restore(ipl); |
| 143 | 141 | ||
| Line 152... | Line 150... | ||
| 152 | task_t *ta; |
150 | task_t *ta; |
| 153 | ipl_t ipl; |
151 | ipl_t ipl; |
| 154 | 152 | ||
| 155 | thread_t *t; |
153 | thread_t *t; |
| 156 | link_t *cur; |
154 | link_t *cur; |
| - | 155 | int flags; |
|
| 157 | 156 | ||
| 158 | klog_printf("udebug_rp_end()"); |
157 | klog_printf("udebug_rp_end()"); |
| 159 | 158 | ||
| 160 | ipl = interrupts_disable(); |
159 | ipl = interrupts_disable(); |
| 161 | ta = get_lock_callee_task(phone); |
160 | ta = get_lock_callee_task(phone); |
| Line 173... | Line 172... | ||
| 173 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
172 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
| 174 | t = list_get_instance(cur, thread_t, th_link); |
173 | t = list_get_instance(cur, thread_t, th_link); |
| 175 | 174 | ||
| 176 | spinlock_lock(&t->lock); |
175 | spinlock_lock(&t->lock); |
| 177 | 176 | ||
| - | 177 | flags = t->flags; |
|
| - | 178 | ||
| - | 179 | spinlock_lock(&t->debug_lock); |
|
| - | 180 | spinlock_unlock(&t->lock); |
|
| - | 181 | ||
| 178 | /* Only process userspace threads */ |
182 | /* Only process userspace threads */ |
| 179 | if ((t->flags & THREAD_FLAG_USPACE) != 0) { |
183 | if ((flags & THREAD_FLAG_USPACE) != 0) { |
| 180 | /* Prevent any further debug activity in thread */ |
184 | /* Prevent any further debug activity in thread */ |
| 181 | t->debug_active = false; |
185 | t->debug_active = false; |
| 182 | 186 | ||
| 183 | /* Still has go? */ |
187 | /* Still has go? */ |
| 184 | if (t->debug_stop == false) { |
188 | if (t->debug_stop == false) { |
| Line 196... | Line 200... | ||
| 196 | } else { |
200 | } else { |
| 197 | /* |
201 | /* |
| 198 | * Debug_stop is already at initial value. |
202 | * Debug_stop is already at initial value. |
| 199 | * Yet this means the thread needs waking up. |
203 | * Yet this means the thread needs waking up. |
| 200 | */ |
204 | */ |
| - | 205 | ||
| - | 206 | /* |
|
| - | 207 | * t's lock must not be held when calling |
|
| - | 208 | * waitq_wakeup. |
|
| - | 209 | */ |
|
| 201 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
210 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
| 202 | } |
211 | } |
| 203 | } |
212 | } |
| 204 | - | ||
| 205 | spinlock_unlock(&t->lock); |
213 | spinlock_unlock(&t->debug_lock); |
| 206 | } |
214 | } |
| 207 | 215 | ||
| 208 | ta->dt_state = UDEBUG_TS_INACTIVE; |
216 | ta->dt_state = UDEBUG_TS_INACTIVE; |
| 209 | 217 | ||
| 210 | spinlock_unlock(&ta->lock); |
218 | spinlock_unlock(&ta->lock); |
| Line 221... | Line 229... | ||
| 221 | static int udebug_rp_go(call_t *call, phone_t *phone) |
229 | static int udebug_rp_go(call_t *call, phone_t *phone) |
| 222 | { |
230 | { |
| 223 | thread_t *t; |
231 | thread_t *t; |
| 224 | task_t *ta; |
232 | task_t *ta; |
| 225 | ipl_t ipl; |
233 | ipl_t ipl; |
| - | 234 | int rc; |
|
| 226 | 235 | ||
| 227 | klog_printf("debug_go()"); |
236 | klog_printf("debug_go()"); |
| - | 237 | ||
| - | 238 | ipl = interrupts_disable(); |
|
| - | 239 | ||
| 228 | ta = get_lock_callee_task(phone); |
240 | ta = get_lock_callee_task(phone); |
| 229 | spinlock_unlock(&ta->lock); |
241 | spinlock_unlock(&ta->lock); |
| 230 | // TODO: don't lock ta |
242 | // TODO: don't lock ta |
| 231 | 243 | ||
| 232 | t = (thread_t *) IPC_GET_ARG2(call->data); |
244 | t = (thread_t *) IPC_GET_ARG2(call->data); |
| 233 | 245 | ||
| 234 | ipl = interrupts_disable(); |
- | |
| 235 | spinlock_lock(&threads_lock); |
246 | spinlock_lock(&threads_lock); |
| - | 247 | if (!thread_exists(t)) { |
|
| - | 248 | spinlock_unlock(&threads_lock); |
|
| - | 249 | interrupts_restore(ipl); |
|
| - | 250 | return ENOENT; |
|
| - | 251 | } |
|
| 236 | 252 | ||
| - | 253 | spinlock_lock(&t->debug_lock); |
|
| - | 254 | ||
| - | 255 | /* Verify that thread t may be operated on */ |
|
| - | 256 | rc = verify_thread(t, ta); |
|
| - | 257 | if (rc != EOK) { |
|
| - | 258 | spinlock_unlock(&t->debug_lock); |
|
| - | 259 | spinlock_unlock(&threads_lock); |
|
| - | 260 | interrupts_restore(ipl); |
|
| - | 261 | return rc; |
|
| - | 262 | } |
|
| - | 263 | ||
| - | 264 | /* |
|
| - | 265 | * Since t->debug_active == true and t->debug_lock is held, |
|
| - | 266 | * we can safely release threads_lock and t will continue |
|
| - | 267 | * to exist (and will stay in debug_active state) |
|
| - | 268 | */ |
|
| - | 269 | spinlock_unlock(&threads_lock); |
|
| 237 | 270 | ||
| 238 | t->debug_go_call = call; |
271 | t->debug_go_call = call; |
| 239 | t->debug_stop = false; |
272 | t->debug_stop = false; |
| - | 273 | ||
| - | 274 | /* |
|
| - | 275 | * Neither t's lock nor threads_lock may be held during wakeup |
|
| - | 276 | */ |
|
| 240 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
277 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
| 241 | 278 | ||
| 242 | spinlock_unlock(&threads_lock); |
279 | spinlock_unlock(&t->debug_lock); |
| 243 | interrupts_restore(ipl); |
280 | interrupts_restore(ipl); |
| 244 | 281 | ||
| 245 | return 0; /* no backsend */ |
282 | return 0; /* no backsend */ |
| 246 | } |
283 | } |
| 247 | 284 | ||
| Line 254... | Line 291... | ||
| 254 | ipl_t ipl; |
291 | ipl_t ipl; |
| 255 | unative_t buffer[6]; |
292 | unative_t buffer[6]; |
| 256 | 293 | ||
| 257 | klog_printf("debug_args_read()"); |
294 | klog_printf("debug_args_read()"); |
| 258 | 295 | ||
| - | 296 | ipl = interrupts_disable(); |
|
| 259 | ta = get_lock_callee_task(phone); |
297 | ta = get_lock_callee_task(phone); |
| 260 | klog_printf("task %llu", ta->taskid); |
298 | klog_printf("task %llu", ta->taskid); |
| 261 | spinlock_unlock(&ta->lock); |
299 | spinlock_unlock(&ta->lock); |
| 262 | 300 | ||
| 263 | t = (thread_t *) IPC_GET_ARG2(call->data); |
301 | t = (thread_t *) IPC_GET_ARG2(call->data); |
| 264 | 302 | ||
| 265 | ipl = interrupts_disable(); |
- | |
| 266 | spinlock_lock(&threads_lock); |
303 | spinlock_lock(&threads_lock); |
| 267 | 304 | ||
| - | 305 | if (!thread_exists(t)) { |
|
| - | 306 | spinlock_unlock(&threads_lock); |
|
| - | 307 | interrupts_restore(ipl); |
|
| - | 308 | return ENOENT; |
|
| - | 309 | } |
|
| - | 310 | ||
| - | 311 | spinlock_lock(&t->debug_lock); |
|
| - | 312 | ||
| 268 | /* Verify that thread t exists and may be operated on */ |
313 | /* Verify that thread t may be operated on */ |
| 269 | rc = verify_thread(t, ta); |
314 | rc = verify_thread(t, ta); |
| 270 | if (rc != EOK) { |
315 | if (rc != EOK) { |
| - | 316 | spinlock_unlock(&t->debug_lock); |
|
| 271 | spinlock_unlock(&threads_lock); |
317 | spinlock_unlock(&threads_lock); |
| 272 | interrupts_restore(ipl); |
318 | interrupts_restore(ipl); |
| 273 | return rc; |
319 | return rc; |
| 274 | } |
320 | } |
| 275 | 321 | ||
| - | 322 | /* |
|
| - | 323 | * We can now safely release threads_lock as debug_active == true |
|
| - | 324 | * and t->debug_lock is held. |
|
| - | 325 | */ |
|
| - | 326 | spinlock_unlock(&threads_lock); |
|
| - | 327 | ||
| 276 | //FIXME: additionally we need to verify that we are inside a syscall |
328 | //FIXME: additionally we need to verify that we are inside a syscall |
| 277 | 329 | ||
| 278 | /* Copy to a local buffer before releasing the lock */ |
330 | /* Copy to a local buffer before releasing the lock */ |
| 279 | memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t)); |
331 | memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t)); |
| 280 | 332 | ||
| 281 | spinlock_unlock(&threads_lock); |
333 | spinlock_unlock(&t->debug_lock); |
| 282 | interrupts_restore(ipl); |
334 | interrupts_restore(ipl); |
| 283 | 335 | ||
| 284 | /* Now copy to userspace */ |
336 | /* Now copy to userspace */ |
| 285 | 337 | ||
| 286 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
338 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
| Line 316... | Line 368... | ||
| 316 | ipl = interrupts_disable(); |
368 | ipl = interrupts_disable(); |
| 317 | spinlock_lock(&threads_lock); |
369 | spinlock_lock(&threads_lock); |
| 318 | 370 | ||
| 319 | t = (thread_t *) IPC_GET_ARG2(call->data); |
371 | t = (thread_t *) IPC_GET_ARG2(call->data); |
| 320 | 372 | ||
| - | 373 | if (!thread_exists(t)) { |
|
| - | 374 | spinlock_unlock(&threads_lock); |
|
| - | 375 | interrupts_restore(ipl); |
|
| - | 376 | return ENOENT; |
|
| - | 377 | } |
|
| - | 378 | ||
| - | 379 | spinlock_lock(&t->debug_lock); |
|
| - | 380 | ||
| 321 | /* Verify that thread t exists and may be operated on */ |
381 | /* Verify that thread t may be operated on */ |
| 322 | rc = verify_thread(t, ta); |
382 | rc = verify_thread(t, ta); |
| 323 | if (rc != EOK) { |
383 | if (rc != EOK) { |
| - | 384 | spinlock_unlock(&t->debug_lock); |
|
| 324 | spinlock_unlock(&threads_lock); |
385 | spinlock_unlock(&threads_lock); |
| 325 | interrupts_restore(ipl); |
386 | interrupts_restore(ipl); |
| 326 | return rc; |
387 | return rc; |
| 327 | } |
388 | } |
| 328 | 389 | ||
| - | 390 | /* |
|
| - | 391 | * We can now safely release threads_lock as debug_active == true |
|
| - | 392 | * and t->debug_lock is held. |
|
| - | 393 | */ |
|
| - | 394 | spinlock_unlock(&threads_lock); |
|
| - | 395 | ||
| 329 | state = t->uspace_state; |
396 | state = t->uspace_state; |
| 330 | if (state == NULL) { |
397 | if (state == NULL) { |
| 331 | spinlock_unlock(&threads_lock); |
398 | spinlock_unlock(&threads_lock); |
| 332 | interrupts_restore(ipl); |
399 | interrupts_restore(ipl); |
| 333 | klog_printf("debug_regs_read() - istate not available"); |
400 | klog_printf("debug_regs_read() - istate not available"); |
| 334 | return EBUSY; |
401 | return EBUSY; |
| 335 | } |
402 | } |
| 336 | 403 | ||
| 337 | /* Copy to a local buffer so that we can release the lock */ |
404 | /* Copy to a local buffer so that we can release the lock */ |
| 338 | memcpy(&state_copy, state, sizeof(state_copy)); |
405 | memcpy(&state_copy, state, sizeof(state_copy)); |
| 339 | spinlock_unlock(&threads_lock); |
406 | spinlock_unlock(&t->debug_lock); |
| 340 | interrupts_restore(ipl); |
407 | interrupts_restore(ipl); |
| 341 | 408 | ||
| 342 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
409 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
| 343 | to_copy = IPC_GET_ARG4(call->data); |
410 | to_copy = IPC_GET_ARG4(call->data); |
| 344 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
411 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
| 345 | 412 | ||
| 346 | rc = copy_to_uspace(uspace_buffer, &state_copy, to_copy); |
413 | rc = copy_to_uspace(uspace_buffer, &state_copy, to_copy); |
| 347 | if (rc != 0) { |
414 | if (rc != 0) { |
| 348 | spinlock_unlock(&ta->lock); |
- | |
| 349 | klog_printf("debug_regs_read() - copy failed"); |
415 | klog_printf("debug_regs_read() - copy failed"); |
| 350 | return rc; |
416 | return rc; |
| 351 | } |
417 | } |
| 352 | 418 | ||
| 353 | IPC_SET_ARG1(call->data, to_copy); |
419 | IPC_SET_ARG1(call->data, to_copy); |
| Line 391... | Line 457... | ||
| 391 | ipl = interrupts_disable(); |
457 | ipl = interrupts_disable(); |
| 392 | spinlock_lock(&threads_lock); |
458 | spinlock_lock(&threads_lock); |
| 393 | 459 | ||
| 394 | t = (thread_t *) IPC_GET_ARG2(call->data); |
460 | t = (thread_t *) IPC_GET_ARG2(call->data); |
| 395 | 461 | ||
| - | 462 | if (!thread_exists(t)) { |
|
| - | 463 | spinlock_unlock(&threads_lock); |
|
| - | 464 | interrupts_restore(ipl); |
|
| - | 465 | return ENOENT; |
|
| - | 466 | } |
|
| - | 467 | ||
| - | 468 | spinlock_lock(&t->debug_lock); |
|
| - | 469 | ||
| 396 | /* Verify that thread t exists and may be operated on */ |
470 | /* Verify that thread t may be operated on */ |
| 397 | rc = verify_thread(t, ta); |
471 | rc = verify_thread(t, ta); |
| 398 | if (rc != EOK) { |
472 | if (rc != EOK) { |
| - | 473 | spinlock_unlock(&t->debug_lock); |
|
| 399 | spinlock_unlock(&threads_lock); |
474 | spinlock_unlock(&threads_lock); |
| 400 | interrupts_restore(ipl); |
475 | interrupts_restore(ipl); |
| 401 | return rc; |
476 | return rc; |
| 402 | } |
477 | } |
| 403 | 478 | ||
| 404 | state = t->uspace_state; |
479 | state = t->uspace_state; |
| 405 | if (state == NULL) { |
480 | if (state == NULL) { |
| 406 | spinlock_unlock(&threads_lock); |
481 | spinlock_unlock(&t->debug_lock); |
| 407 | interrupts_restore(ipl); |
482 | interrupts_restore(ipl); |
| 408 | klog_printf("debug_regs_write() - istate not available"); |
483 | klog_printf("debug_regs_write() - istate not available"); |
| 409 | return EBUSY; |
484 | return EBUSY; |
| 410 | } |
485 | } |
| 411 | 486 | ||
| 412 | memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state)); |
487 | memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state)); |
| 413 | 488 | ||
| 414 | spinlock_unlock(&threads_lock); |
489 | spinlock_unlock(&t->debug_lock); |
| 415 | interrupts_restore(ipl); |
490 | interrupts_restore(ipl); |
| 416 | 491 | ||
| 417 | /* Set answer values */ |
492 | /* Set answer values */ |
| 418 | 493 | ||
| 419 | IPC_SET_ARG1(call->data, to_copy); |
494 | IPC_SET_ARG1(call->data, to_copy); |