1/* 2 * Copyright (c) 2000-2007 Apple, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28#include <mach/mach_types.h> 29 30#include <kern/kern_types.h> 31#include <kern/processor.h> 32#include <kern/thread.h> 33#include <kern/task.h> 34#include <kern/spl.h> 35#include <kern/lock.h> 36#include <kern/ast.h> 37#include <ipc/ipc_port.h> 38#include <ipc/ipc_object.h> 39#include <vm/vm_map.h> 40#include <vm/vm_kern.h> 41#include <vm/pmap.h> 42#include <vm/vm_protos.h> /* last */ 43 44#undef thread_should_halt 45#undef ipc_port_release 46 47/* BSD KERN COMPONENT INTERFACE */ 48 49task_t bsd_init_task = TASK_NULL; 50char init_task_failure_data[1024]; 51extern unsigned int not_in_kdp; /* Skip acquiring locks if we're in kdp */ 52 53thread_t get_firstthread(task_t); 54int get_task_userstop(task_t); 55int get_thread_userstop(thread_t); 56boolean_t thread_should_abort(thread_t); 57boolean_t current_thread_aborted(void); 58void task_act_iterate_wth_args(task_t, void(*)(thread_t, void *), void *); 59void ipc_port_release(ipc_port_t); 60kern_return_t get_signalact(task_t , thread_t *, int); 61int get_vmsubmap_entries(vm_map_t, vm_object_offset_t, vm_object_offset_t); 62void syscall_exit_funnelcheck(void); 63 64 65/* 66 * 67 */ 68void *get_bsdtask_info(task_t t) 69{ 70 return(t->bsd_info); 71} 72 73/* 74 * 75 */ 76void *get_bsdthreadtask_info(thread_t th) 77{ 78 return(th->task != TASK_NULL ? th->task->bsd_info : NULL); 79} 80 81/* 82 * 83 */ 84void set_bsdtask_info(task_t t,void * v) 85{ 86 t->bsd_info=v; 87} 88 89/* 90 * 91 */ 92void *get_bsdthread_info(thread_t th) 93{ 94 return(th->uthread); 95} 96 97/* 98 * XXX: wait for BSD to fix signal code 99 * Until then, we cannot block here. We know the task 100 * can't go away, so we make sure it is still active after 101 * retrieving the first thread for extra safety. 102 */ 103thread_t get_firstthread(task_t task) 104{ 105 thread_t thread = (thread_t)queue_first(&task->threads); 106 107 if (queue_end(&task->threads, (queue_entry_t)thread)) 108 thread = THREAD_NULL; 109 110 if (!task->active) 111 return (THREAD_NULL); 112 113 return (thread); 114} 115 116kern_return_t 117get_signalact( 118 task_t task, 119 thread_t *result_out, 120 int setast) 121{ 122 kern_return_t result = KERN_SUCCESS; 123 thread_t inc, thread = THREAD_NULL; 124 125 task_lock(task); 126 127 if (!task->active) { 128 task_unlock(task); 129 130 return (KERN_FAILURE); 131 } 132 133 for (inc = (thread_t)queue_first(&task->threads); 134 !queue_end(&task->threads, (queue_entry_t)inc); ) { 135 thread_mtx_lock(inc); 136 if (inc->active && 137 (inc->sched_mode & TH_MODE_ISABORTED) != TH_MODE_ABORT) { 138 thread = inc; 139 break; 140 } 141 thread_mtx_unlock(inc); 142 143 inc = (thread_t)queue_next(&inc->task_threads); 144 } 145 146 if (result_out) 147 *result_out = thread; 148 149 if (thread) { 150 if (setast) 151 act_set_astbsd(thread); 152 153 thread_mtx_unlock(thread); 154 } 155 else 156 result = KERN_FAILURE; 157 158 task_unlock(task); 159 160 return (result); 161} 162 163 164kern_return_t 165check_actforsig( 166 task_t task, 167 thread_t thread, 168 int setast) 169{ 170 kern_return_t result = KERN_FAILURE; 171 thread_t inc; 172 173 task_lock(task); 174 175 if (!task->active) { 176 task_unlock(task); 177 178 return (KERN_FAILURE); 179 } 180 181 for (inc = (thread_t)queue_first(&task->threads); 182 !queue_end(&task->threads, (queue_entry_t)inc); ) { 183 if (inc == thread) { 184 thread_mtx_lock(inc); 185 186 if (inc->active && 187 (inc->sched_mode & TH_MODE_ISABORTED) != TH_MODE_ABORT) { 188 result = KERN_SUCCESS; 189 break; 190 } 191 192 thread_mtx_unlock(inc); 193 break; 194 } 195 196 inc = (thread_t)queue_next(&inc->task_threads); 197 } 198 199 if (result == KERN_SUCCESS) { 200 if (setast) 201 act_set_astbsd(thread); 202 203 thread_mtx_unlock(thread); 204 } 205 206 task_unlock(task); 207 208 return (result); 209} 210 211/* 212 * This is only safe to call from a thread executing in 213 * in the task's context or if the task is locked Otherwise, 214 * the map could be switched for the task (and freed) before 215 * we to return it here. 216 */ 217vm_map_t get_task_map(task_t t) 218{ 219 return(t->map); 220} 221 222vm_map_t get_task_map_reference(task_t t) 223{ 224 vm_map_t m; 225 226 if (t == NULL) 227 return VM_MAP_NULL; 228 229 task_lock(t); 230 if (!t->active) { 231 task_unlock(t); 232 return VM_MAP_NULL; 233 } 234 m = t->map; 235 vm_map_reference_swap(m); 236 task_unlock(t); 237 return m; 238} 239 240/* 241 * 242 */ 243ipc_space_t get_task_ipcspace(task_t t) 244{ 245 return(t->itk_space); 246} 247 248int get_task_numactivethreads(task_t task) 249{ 250 thread_t inc; 251 int num_active_thr=0; 252 task_lock(task); 253 254 for (inc = (thread_t)queue_first(&task->threads); 255 !queue_end(&task->threads, (queue_entry_t)inc); inc = (thread_t)queue_next(&inc->task_threads)) 256 { 257 if(inc->active) 258 num_active_thr++; 259 } 260 task_unlock(task); 261 return num_active_thr; 262} 263 264int get_task_numacts(task_t t) 265{ 266 return(t->thread_count); 267} 268 269/* does this machine need 64bit register set for signal handler */ 270int is_64signalregset(void) 271{ 272 task_t t = current_task(); 273 if(t->taskFeatures[0] & tf64BitData) 274 return(1); 275 else 276 return(0); 277} 278 279/* 280 * The old map reference is returned. 281 */ 282vm_map_t 283swap_task_map(task_t task,vm_map_t map) 284{ 285 thread_t thread = current_thread(); 286 vm_map_t old_map; 287 288 if (task != thread->task) 289 panic("swap_task_map"); 290 291 task_lock(task); 292 old_map = task->map; 293 thread->map = task->map = map; 294 task_unlock(task); 295 296 inval_copy_windows(thread); 297 298 return old_map; 299} 300 301/* 302 * 303 */ 304pmap_t get_task_pmap(task_t t) 305{ 306 return(t->map->pmap); 307} 308 309/* 310 * 311 */ 312pmap_t get_map_pmap(vm_map_t map) 313{ 314 return(map->pmap); 315} 316/* 317 * 318 */ 319task_t get_threadtask(thread_t th) 320{ 321 return(th->task); 322} 323 324/* 325 * 326 */ 327vm_map_offset_t 328get_map_min( 329 vm_map_t map) 330{ 331 return(vm_map_min(map)); 332} 333 334/* 335 * 336 */ 337vm_map_offset_t 338get_map_max( 339 vm_map_t map) 340{ 341 return(vm_map_max(map)); 342} 343vm_map_size_t 344get_vmmap_size( 345 vm_map_t map) 346{ 347 return(map->size); 348} 349 350int 351get_vmsubmap_entries( 352 vm_map_t map, 353 vm_object_offset_t start, 354 vm_object_offset_t end) 355{ 356 int total_entries = 0; 357 vm_map_entry_t entry; 358 359 if (not_in_kdp) 360 vm_map_lock(map); 361 entry = vm_map_first_entry(map); 362 while((entry != vm_map_to_entry(map)) && (entry->vme_start < start)) { 363 entry = entry->vme_next; 364 } 365 366 while((entry != vm_map_to_entry(map)) && (entry->vme_start < end)) { 367 if(entry->is_sub_map) { 368 total_entries += 369 get_vmsubmap_entries(entry->object.sub_map, 370 entry->offset, 371 entry->offset + 372 (entry->vme_end - entry->vme_start)); 373 } else { 374 total_entries += 1; 375 } 376 entry = entry->vme_next; 377 } 378 if (not_in_kdp) 379 vm_map_unlock(map); 380 return(total_entries); 381} 382 383int 384get_vmmap_entries( 385 vm_map_t map) 386{ 387 int total_entries = 0; 388 vm_map_entry_t entry; 389 390 if (not_in_kdp) 391 vm_map_lock(map); 392 entry = vm_map_first_entry(map); 393 394 while(entry != vm_map_to_entry(map)) { 395 if(entry->is_sub_map) { 396 total_entries += 397 get_vmsubmap_entries(entry->object.sub_map, 398 entry->offset, 399 entry->offset + 400 (entry->vme_end - entry->vme_start)); 401 } else { 402 total_entries += 1; 403 } 404 entry = entry->vme_next; 405 } 406 if (not_in_kdp) 407 vm_map_unlock(map); 408 return(total_entries); 409} 410 411/* 412 * 413 */ 414/* 415 * 416 */ 417int 418get_task_userstop( 419 task_t task) 420{ 421 return(task->user_stop_count); 422} 423 424/* 425 * 426 */ 427int 428get_thread_userstop( 429 thread_t th) 430{ 431 return(th->user_stop_count); 432} 433 434/* 435 * 436 */ 437boolean_t 438thread_should_abort( 439 thread_t th) 440{ 441 return ((th->sched_mode & TH_MODE_ISABORTED) == TH_MODE_ABORT); 442} 443 444/* 445 * This routine is like thread_should_abort() above. It checks to 446 * see if the current thread is aborted. But unlike above, it also 447 * checks to see if thread is safely aborted. If so, it returns 448 * that fact, and clears the condition (safe aborts only should 449 * have a single effect, and a poll of the abort status 450 * qualifies. 451 */ 452boolean_t 453current_thread_aborted ( 454 void) 455{ 456 thread_t th = current_thread(); 457 spl_t s; 458 459 if ((th->sched_mode & TH_MODE_ISABORTED) == TH_MODE_ABORT && 460 (th->options & TH_OPT_INTMASK) != THREAD_UNINT) 461 return (TRUE); 462 if (th->sched_mode & TH_MODE_ABORTSAFELY) { 463 s = splsched(); 464 thread_lock(th); 465 if (th->sched_mode & TH_MODE_ABORTSAFELY) 466 th->sched_mode &= ~TH_MODE_ISABORTED; 467 thread_unlock(th); 468 splx(s); 469 } 470 return FALSE; 471} 472 473/* 474 * 475 */ 476void 477task_act_iterate_wth_args( 478 task_t task, 479 void (*func_callback)(thread_t, void *), 480 void *func_arg) 481{ 482 thread_t inc; 483 484 task_lock(task); 485 486 for (inc = (thread_t)queue_first(&task->threads); 487 !queue_end(&task->threads, (queue_entry_t)inc); ) { 488 (void) (*func_callback)(inc, func_arg); 489 inc = (thread_t)queue_next(&inc->task_threads); 490 } 491 492 task_unlock(task); 493} 494 495void 496ipc_port_release( 497 ipc_port_t port) 498{ 499 ipc_object_release(&(port)->ip_object); 500} 501 502void 503astbsd_on(void) 504{ 505 boolean_t reenable; 506 507 reenable = ml_set_interrupts_enabled(FALSE); 508 ast_on_fast(AST_BSD); 509 (void)ml_set_interrupts_enabled(reenable); 510} 511 512 513#include <sys/bsdtask_info.h> 514 515void 516fill_taskprocinfo(task_t task, struct proc_taskinfo_internal * ptinfo) 517{ 518 vm_map_t map; 519 task_absolutetime_info_data_t tinfo; 520 thread_t thread; 521 int cswitch = 0, numrunning = 0; 522 523 map = (task == kernel_task)? kernel_map: task->map; 524 525 ptinfo->pti_virtual_size = map->size; 526 ptinfo->pti_resident_size = 527 (mach_vm_size_t)(pmap_resident_count(map->pmap)) 528 * PAGE_SIZE_64; 529 530 task_lock(task); 531 532 ptinfo->pti_policy = ((task != kernel_task)? 533 POLICY_TIMESHARE: POLICY_RR); 534 535 tinfo.threads_user = tinfo.threads_system = 0; 536 tinfo.total_user = task->total_user_time; 537 tinfo.total_system = task->total_system_time; 538 539 queue_iterate(&task->threads, thread, thread_t, task_threads) { 540 uint64_t tval; 541 542 if ((thread->state & TH_RUN) == TH_RUN) 543 numrunning++; 544 cswitch += thread->c_switch; 545 tval = timer_grab(&thread->user_timer); 546 tinfo.threads_user += tval; 547 tinfo.total_user += tval; 548 549 tval = timer_grab(&thread->system_timer); 550 tinfo.threads_system += tval; 551 tinfo.total_system += tval; 552 } 553 554 ptinfo->pti_total_system = tinfo.total_system; 555 ptinfo->pti_total_user = tinfo.total_user; 556 ptinfo->pti_threads_system = tinfo.threads_system; 557 ptinfo->pti_threads_user = tinfo.threads_user; 558 559 ptinfo->pti_faults = task->faults; 560 ptinfo->pti_pageins = task->pageins; 561 ptinfo->pti_cow_faults = task->cow_faults; 562 ptinfo->pti_messages_sent = task->messages_sent; 563 ptinfo->pti_messages_received = task->messages_received; 564 ptinfo->pti_syscalls_mach = task->syscalls_mach; 565 ptinfo->pti_syscalls_unix = task->syscalls_unix; 566 ptinfo->pti_csw = task->c_switch + cswitch; 567 ptinfo->pti_threadnum = task->thread_count; 568 ptinfo->pti_numrunning = numrunning; 569 ptinfo->pti_priority = task->priority; 570 571 task_unlock(task); 572} 573 574int 575fill_taskthreadinfo(task_t task, uint64_t thaddr, struct proc_threadinfo_internal * ptinfo, void * vpp, int *vidp) 576{ 577 thread_t thact; 578 int err=0; 579 mach_msg_type_number_t count; 580 thread_basic_info_data_t basic_info; 581 kern_return_t kret; 582 583 task_lock(task); 584 585 for (thact = (thread_t)queue_first(&task->threads); 586 !queue_end(&task->threads, (queue_entry_t)thact); ) { 587#if defined(__ppc__) || defined(__arm__) 588 if (thact->machine.cthread_self == thaddr) 589#elif defined (__i386__) 590 if (thact->machine.pcb->cthread_self == thaddr) 591#else 592#error architecture not supported 593#endif 594 { 595 596 count = THREAD_BASIC_INFO_COUNT; 597 if ((kret = thread_info_internal(thact, THREAD_BASIC_INFO, (thread_info_t)&basic_info, &count)) != KERN_SUCCESS) { 598 err = 1; 599 goto out; 600 } 601#if 0 602 ptinfo->pth_user_time = timer_grab(&basic_info.user_time); 603 ptinfo->pth_system_time = timer_grab(&basic_info.system_time); 604#else 605 ptinfo->pth_user_time = ((basic_info.user_time.seconds * NSEC_PER_SEC) + (basic_info.user_time.microseconds * NSEC_PER_USEC)); 606 ptinfo->pth_system_time = ((basic_info.system_time.seconds * NSEC_PER_SEC) + (basic_info.system_time.microseconds * NSEC_PER_USEC)); 607 608#endif 609 ptinfo->pth_cpu_usage = basic_info.cpu_usage; 610 ptinfo->pth_policy = basic_info.policy; 611 ptinfo->pth_run_state = basic_info.run_state; 612 ptinfo->pth_flags = basic_info.flags; 613 ptinfo->pth_sleep_time = basic_info.sleep_time; 614 ptinfo->pth_curpri = thact->sched_pri; 615 ptinfo->pth_priority = thact->priority; 616 ptinfo->pth_maxpriority = thact->max_priority; 617 618 if ((vpp != NULL) && (thact->uthread != NULL)) 619 bsd_threadcdir(thact->uthread, vpp, vidp); 620 err = 0; 621 goto out; 622 } 623 thact = (thread_t)queue_next(&thact->task_threads); 624 } 625 err = 1; 626 627out: 628 task_unlock(task); 629 return(err); 630} 631 632int 633fill_taskthreadlist(task_t task, void * buffer, int thcount) 634{ 635 int numthr=0; 636 thread_t thact; 637 uint64_t * uptr; 638 uint64_t thaddr; 639 640 uptr = (uint64_t *)buffer; 641 642 task_lock(task); 643 644 for (thact = (thread_t)queue_first(&task->threads); 645 !queue_end(&task->threads, (queue_entry_t)thact); ) { 646#if defined(__ppc__) || defined(__arm__) 647 thaddr = thact->machine.cthread_self; 648#elif defined (__i386__) 649 thaddr = thact->machine.pcb->cthread_self; 650#else 651#error architecture not supported 652#endif 653 *uptr++ = thaddr; 654 numthr++; 655 if (numthr >= thcount) 656 goto out; 657 thact = (thread_t)queue_next(&thact->task_threads); 658 } 659 660out: 661 task_unlock(task); 662 return(numthr * sizeof(uint64_t)); 663 664} 665 666int 667get_numthreads(task_t task) 668{ 669 return(task->thread_count); 670} 671 672void 673syscall_exit_funnelcheck(void) 674{ 675 thread_t thread; 676 677 thread = current_thread(); 678 679 if (thread->funnel_lock) 680 panic("syscall exit with funnel held\n"); 681} 682