|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: vm/vm_debug.c. ! 28: * Author: Rich Draves ! 29: * Date: March, 1990 ! 30: * ! 31: * Exported kernel calls. See mach_debug/mach_debug.defs. ! 32: */ ! 33: ! 34: #include <mach_vm_debug.h> ! 35: #if MACH_VM_DEBUG ! 36: ! 37: #include <kern/thread.h> ! 38: #include <mach/kern_return.h> ! 39: #include <mach/machine/vm_types.h> ! 40: #include <mach/memory_object.h> ! 41: #include <mach/vm_prot.h> ! 42: #include <mach/vm_inherit.h> ! 43: #include <mach/vm_param.h> ! 44: #include <mach_debug/vm_info.h> ! 45: #include <mach_debug/hash_info.h> ! 46: #include <vm/vm_map.h> ! 47: #include <vm/vm_kern.h> ! 48: #include <vm/vm_object.h> ! 49: #include <kern/task.h> ! 50: #include <kern/host.h> ! 51: #include <ipc/ipc_port.h> ! 52: ! 53: ! 54: ! 55: /* ! 56: * Routine: vm_object_real_name ! 57: * Purpose: ! 58: * Convert a VM object to a name port. ! 59: * Conditions: ! 60: * Takes object and port locks. ! 61: * Returns: ! 62: * A naked send right for the object's name port, ! 63: * or IP_NULL if the object or its name port is null. ! 64: */ ! 65: ! 66: ipc_port_t ! 67: vm_object_real_name(object) ! 68: vm_object_t object; ! 69: { ! 70: ipc_port_t port = IP_NULL; ! 71: ! 72: if (object != VM_OBJECT_NULL) { ! 73: vm_object_lock(object); ! 74: if (object->pager_name != IP_NULL) ! 75: port = ipc_port_make_send(object->pager_name); ! 76: vm_object_unlock(object); ! 77: } ! 78: ! 79: return port; ! 80: } ! 81: ! 82: /* ! 83: * Routine: mach_vm_region_info [kernel call] ! 84: * Purpose: ! 85: * Retrieve information about a VM region, ! 86: * including info about the object chain. ! 87: * Conditions: ! 88: * Nothing locked. ! 89: * Returns: ! 90: * KERN_SUCCESS Retrieve region/object info. ! 91: * KERN_INVALID_TASK The map is null. ! 92: * KERN_NO_SPACE There is no entry at/after the address. ! 93: */ ! 94: ! 95: kern_return_t ! 96: mach_vm_region_info(map, address, regionp, portp) ! 97: vm_map_t map; ! 98: vm_offset_t address; ! 99: vm_region_info_t *regionp; ! 100: ipc_port_t *portp; ! 101: { ! 102: vm_map_t cmap; /* current map in traversal */ ! 103: vm_map_t nmap; /* next map to look at */ ! 104: vm_map_entry_t entry; /* entry in current map */ ! 105: vm_object_t object; ! 106: ! 107: if (map == VM_MAP_NULL) ! 108: return KERN_INVALID_TASK; ! 109: ! 110: /* find the entry containing (or following) the address */ ! 111: ! 112: vm_map_lock_read(map); ! 113: for (cmap = map;;) { ! 114: /* cmap is read-locked */ ! 115: ! 116: if (!vm_map_lookup_entry(cmap, address, &entry)) { ! 117: entry = entry->vme_next; ! 118: if (entry == vm_map_to_entry(cmap)) { ! 119: if (map == cmap) { ! 120: vm_map_unlock_read(cmap); ! 121: return KERN_NO_SPACE; ! 122: } ! 123: ! 124: /* back out to top-level & skip this submap */ ! 125: ! 126: address = vm_map_max(cmap); ! 127: vm_map_unlock_read(cmap); ! 128: vm_map_lock_read(map); ! 129: cmap = map; ! 130: continue; ! 131: } ! 132: } ! 133: ! 134: if (entry->is_sub_map) { ! 135: /* move down to the sub map */ ! 136: ! 137: nmap = entry->object.sub_map; ! 138: vm_map_lock_read(nmap); ! 139: vm_map_unlock_read(cmap); ! 140: cmap = nmap; ! 141: continue; ! 142: } else { ! 143: break; ! 144: } ! 145: /*NOTREACHED*/ ! 146: } ! 147: ! 148: ! 149: assert(entry->vme_start < entry->vme_end); ! 150: ! 151: regionp->vri_start = entry->vme_start; ! 152: regionp->vri_end = entry->vme_end; ! 153: ! 154: /* attributes from the real entry */ ! 155: ! 156: regionp->vri_protection = entry->protection; ! 157: regionp->vri_max_protection = entry->max_protection; ! 158: regionp->vri_inheritance = entry->inheritance; ! 159: regionp->vri_wired_count = entry->wired_count; ! 160: regionp->vri_user_wired_count = entry->user_wired_count; ! 161: ! 162: object = entry->object.vm_object; ! 163: *portp = vm_object_real_name(object); ! 164: regionp->vri_object = (vm_offset_t) object; ! 165: regionp->vri_offset = entry->offset; ! 166: regionp->vri_needs_copy = entry->needs_copy; ! 167: ! 168: regionp->vri_sharing = entry->is_shared; ! 169: ! 170: vm_map_unlock_read(cmap); ! 171: return KERN_SUCCESS; ! 172: } ! 173: ! 174: /* ! 175: * Routine: mach_vm_object_info [kernel call] ! 176: * Purpose: ! 177: * Retrieve information about a VM object. ! 178: * Conditions: ! 179: * Nothing locked. ! 180: * Returns: ! 181: * KERN_SUCCESS Retrieved object info. ! 182: * KERN_INVALID_ARGUMENT The object is null. ! 183: */ ! 184: ! 185: kern_return_t ! 186: mach_vm_object_info(object, infop, shadowp, copyp) ! 187: vm_object_t object; ! 188: vm_object_info_t *infop; ! 189: ipc_port_t *shadowp; ! 190: ipc_port_t *copyp; ! 191: { ! 192: vm_object_info_t info; ! 193: vm_object_info_state_t state; ! 194: ipc_port_t shadow, copy; ! 195: ! 196: if (object == VM_OBJECT_NULL) ! 197: return KERN_INVALID_ARGUMENT; ! 198: ! 199: /* ! 200: * Because of lock-ordering/deadlock considerations, ! 201: * we can't use vm_object_real_name for the copy object. ! 202: */ ! 203: ! 204: retry: ! 205: vm_object_lock(object); ! 206: copy = IP_NULL; ! 207: if (object->copy != VM_OBJECT_NULL) { ! 208: if (!vm_object_lock_try(object->copy)) { ! 209: vm_object_unlock(object); ! 210: simple_lock_pause(); /* wait a bit */ ! 211: goto retry; ! 212: } ! 213: ! 214: if (object->copy->pager_name != IP_NULL) ! 215: copy = ipc_port_make_send(object->copy->pager_name); ! 216: vm_object_unlock(object->copy); ! 217: } ! 218: shadow = vm_object_real_name(object->shadow); ! 219: ! 220: info.voi_object = (vm_offset_t) object; ! 221: info.voi_pagesize = PAGE_SIZE; ! 222: info.voi_size = object->size; ! 223: info.voi_ref_count = object->ref_count; ! 224: info.voi_resident_page_count = object->resident_page_count; ! 225: info.voi_absent_count = object->absent_count; ! 226: info.voi_copy = (vm_offset_t) object->copy; ! 227: info.voi_shadow = (vm_offset_t) object->shadow; ! 228: info.voi_shadow_offset = object->shadow_offset; ! 229: info.voi_paging_offset = object->paging_offset; ! 230: info.voi_copy_strategy = object->copy_strategy; ! 231: info.voi_last_alloc = object->last_alloc; ! 232: info.voi_paging_in_progress = object->paging_in_progress; ! 233: ! 234: state = 0; ! 235: if (object->pager_created) ! 236: state |= VOI_STATE_PAGER_CREATED; ! 237: if (object->pager_initialized) ! 238: state |= VOI_STATE_PAGER_INITIALIZED; ! 239: if (object->pager_ready) ! 240: state |= VOI_STATE_PAGER_READY; ! 241: if (object->can_persist) ! 242: state |= VOI_STATE_CAN_PERSIST; ! 243: if (object->internal) ! 244: state |= VOI_STATE_INTERNAL; ! 245: if (object->temporary) ! 246: state |= VOI_STATE_TEMPORARY; ! 247: if (object->alive) ! 248: state |= VOI_STATE_ALIVE; ! 249: if (object->lock_in_progress) ! 250: state |= VOI_STATE_LOCK_IN_PROGRESS; ! 251: if (object->lock_restart) ! 252: state |= VOI_STATE_LOCK_RESTART; ! 253: if (object->use_old_pageout) ! 254: state |= VOI_STATE_USE_OLD_PAGEOUT; ! 255: info.voi_state = state; ! 256: vm_object_unlock(object); ! 257: ! 258: *infop = info; ! 259: *shadowp = shadow; ! 260: *copyp = copy; ! 261: return KERN_SUCCESS; ! 262: } ! 263: ! 264: #define VPI_STATE_NODATA (VPI_STATE_BUSY|VPI_STATE_FICTITIOUS| \ ! 265: VPI_STATE_PRIVATE|VPI_STATE_ABSENT) ! 266: ! 267: /* ! 268: * Routine: mach_vm_object_pages [kernel call] ! 269: * Purpose: ! 270: * Retrieve information about the pages in a VM object. ! 271: * Conditions: ! 272: * Nothing locked. Obeys CountInOut protocol. ! 273: * Returns: ! 274: * KERN_SUCCESS Retrieved object info. ! 275: * KERN_INVALID_ARGUMENT The object is null. ! 276: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 277: */ ! 278: ! 279: kern_return_t ! 280: mach_vm_object_pages(object, pagesp, countp) ! 281: vm_object_t object; ! 282: vm_page_info_array_t *pagesp; ! 283: natural_t *countp; ! 284: { ! 285: vm_size_t size; ! 286: vm_offset_t addr; ! 287: vm_page_info_t *pages; ! 288: unsigned int potential, actual, count; ! 289: vm_page_t p; ! 290: kern_return_t kr; ! 291: ! 292: if (object == VM_OBJECT_NULL) ! 293: return KERN_INVALID_ARGUMENT; ! 294: ! 295: /* start with in-line memory */ ! 296: ! 297: pages = *pagesp; ! 298: potential = *countp; ! 299: ! 300: for (size = 0;;) { ! 301: vm_object_lock(object); ! 302: actual = object->resident_page_count; ! 303: if (actual <= potential) ! 304: break; ! 305: vm_object_unlock(object); ! 306: ! 307: if (pages != *pagesp) ! 308: kmem_free(ipc_kernel_map, addr, size); ! 309: ! 310: size = round_page(actual * sizeof *pages); ! 311: kr = kmem_alloc(ipc_kernel_map, &addr, size); ! 312: if (kr != KERN_SUCCESS) ! 313: return kr; ! 314: ! 315: pages = (vm_page_info_t *) addr; ! 316: potential = size/sizeof *pages; ! 317: } ! 318: /* object is locked, we have enough wired memory */ ! 319: ! 320: count = 0; ! 321: queue_iterate(&object->memq, p, vm_page_t, listq) { ! 322: vm_page_info_t *info = &pages[count++]; ! 323: vm_page_info_state_t state = 0; ! 324: ! 325: info->vpi_offset = p->offset; ! 326: info->vpi_phys_addr = p->phys_addr; ! 327: info->vpi_wire_count = p->wire_count; ! 328: info->vpi_page_lock = p->page_lock; ! 329: info->vpi_unlock_request = p->unlock_request; ! 330: ! 331: if (p->busy) ! 332: state |= VPI_STATE_BUSY; ! 333: if (p->wanted) ! 334: state |= VPI_STATE_WANTED; ! 335: if (p->tabled) ! 336: state |= VPI_STATE_TABLED; ! 337: if (p->fictitious) ! 338: state |= VPI_STATE_FICTITIOUS; ! 339: if (p->private) ! 340: state |= VPI_STATE_PRIVATE; ! 341: if (p->absent) ! 342: state |= VPI_STATE_ABSENT; ! 343: if (p->error) ! 344: state |= VPI_STATE_ERROR; ! 345: if (p->dirty) ! 346: state |= VPI_STATE_DIRTY; ! 347: if (p->precious) ! 348: state |= VPI_STATE_PRECIOUS; ! 349: if (p->overwriting) ! 350: state |= VPI_STATE_OVERWRITING; ! 351: ! 352: if (((state & (VPI_STATE_NODATA|VPI_STATE_DIRTY)) == 0) && ! 353: pmap_is_modified(p->phys_addr)) { ! 354: state |= VPI_STATE_DIRTY; ! 355: p->dirty = TRUE; ! 356: } ! 357: ! 358: vm_page_lock_queues(); ! 359: if (p->inactive) ! 360: state |= VPI_STATE_INACTIVE; ! 361: if (p->active) ! 362: state |= VPI_STATE_ACTIVE; ! 363: if (p->laundry) ! 364: state |= VPI_STATE_LAUNDRY; ! 365: if (p->free) ! 366: state |= VPI_STATE_FREE; ! 367: if (p->reference) ! 368: state |= VPI_STATE_REFERENCE; ! 369: ! 370: if (((state & (VPI_STATE_NODATA|VPI_STATE_REFERENCE)) == 0) && ! 371: pmap_is_referenced(p->phys_addr)) { ! 372: state |= VPI_STATE_REFERENCE; ! 373: p->reference = TRUE; ! 374: } ! 375: vm_page_unlock_queues(); ! 376: ! 377: info->vpi_state = state; ! 378: } ! 379: ! 380: if (object->resident_page_count != count) ! 381: panic("mach_vm_object_pages"); ! 382: vm_object_unlock(object); ! 383: ! 384: if (pages == *pagesp) { ! 385: /* data fit in-line; nothing to deallocate */ ! 386: ! 387: *countp = actual; ! 388: } else if (actual == 0) { ! 389: kmem_free(ipc_kernel_map, addr, size); ! 390: ! 391: *countp = 0; ! 392: } else { ! 393: vm_size_t size_used, rsize_used; ! 394: vm_map_copy_t copy; ! 395: ! 396: /* kmem_alloc doesn't zero memory */ ! 397: ! 398: size_used = actual * sizeof *pages; ! 399: rsize_used = round_page(size_used); ! 400: ! 401: if (rsize_used != size) ! 402: kmem_free(ipc_kernel_map, ! 403: addr + rsize_used, size - rsize_used); ! 404: ! 405: if (size_used != rsize_used) ! 406: bzero((char *) (addr + size_used), ! 407: rsize_used - size_used); ! 408: ! 409: kr = vm_map_copyin(ipc_kernel_map, addr, rsize_used, ! 410: TRUE, ©); ! 411: assert(kr == KERN_SUCCESS); ! 412: ! 413: *pagesp = (vm_page_info_t *) copy; ! 414: *countp = actual; ! 415: } ! 416: ! 417: return KERN_SUCCESS; ! 418: } ! 419: ! 420: #endif /* MACH_VM_DEBUG */ ! 421: ! 422: /* ! 423: * Routine: host_virtual_physical_table_info ! 424: * Purpose: ! 425: * Return information about the VP table. ! 426: * Conditions: ! 427: * Nothing locked. Obeys CountInOut protocol. ! 428: * Returns: ! 429: * KERN_SUCCESS Returned information. ! 430: * KERN_INVALID_HOST The host is null. ! 431: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 432: */ ! 433: ! 434: kern_return_t ! 435: host_virtual_physical_table_info(host, infop, countp) ! 436: host_t host; ! 437: hash_info_bucket_array_t *infop; ! 438: natural_t *countp; ! 439: { ! 440: vm_offset_t addr; ! 441: vm_size_t size = 0;/* '=0' to quiet gcc warnings */ ! 442: hash_info_bucket_t *info; ! 443: unsigned int potential, actual; ! 444: kern_return_t kr; ! 445: ! 446: if (host == HOST_NULL) ! 447: return KERN_INVALID_HOST; ! 448: ! 449: /* start with in-line data */ ! 450: ! 451: info = *infop; ! 452: potential = *countp; ! 453: ! 454: for (;;) { ! 455: actual = vm_page_info(info, potential); ! 456: if (actual <= potential) ! 457: break; ! 458: ! 459: /* allocate more memory */ ! 460: ! 461: if (info != *infop) ! 462: kmem_free(ipc_kernel_map, addr, size); ! 463: ! 464: size = round_page(actual * sizeof *info); ! 465: kr = kmem_alloc_pageable(ipc_kernel_map, &addr, size); ! 466: if (kr != KERN_SUCCESS) ! 467: return KERN_RESOURCE_SHORTAGE; ! 468: ! 469: info = (hash_info_bucket_t *) addr; ! 470: potential = size/sizeof *info; ! 471: } ! 472: ! 473: if (info == *infop) { ! 474: /* data fit in-line; nothing to deallocate */ ! 475: ! 476: *countp = actual; ! 477: } else if (actual == 0) { ! 478: kmem_free(ipc_kernel_map, addr, size); ! 479: ! 480: *countp = 0; ! 481: } else { ! 482: vm_map_copy_t copy; ! 483: vm_size_t used; ! 484: ! 485: used = round_page(actual * sizeof *info); ! 486: ! 487: if (used != size) ! 488: kmem_free(ipc_kernel_map, addr + used, size - used); ! 489: ! 490: kr = vm_map_copyin(ipc_kernel_map, addr, used, ! 491: TRUE, ©); ! 492: assert(kr == KERN_SUCCESS); ! 493: ! 494: *infop = (hash_info_bucket_t *) copy; ! 495: *countp = actual; ! 496: } ! 497: ! 498: return KERN_SUCCESS; ! 499: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.