123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- /*
- * Mach Operating System
- * Copyright (c) 1991,1990 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
- /*
- * File: vm/vm_debug.c.
- * Author: Rich Draves
- * Date: March, 1990
- *
- * Exported kernel calls. See mach_debug/mach_debug.defs.
- */
- #include <string.h>
- #include <kern/debug.h>
- #include <kern/thread.h>
- #include <mach/kern_return.h>
- #include <mach/machine/vm_types.h>
- #include <mach/memory_object.h>
- #include <mach/vm_prot.h>
- #include <mach/vm_inherit.h>
- #include <mach/vm_param.h>
- #include <mach_debug/vm_info.h>
- #include <mach_debug/hash_info.h>
- #include <vm/vm_map.h>
- #include <vm/vm_kern.h>
- #include <vm/vm_object.h>
- #include <kern/task.h>
- #include <kern/host.h>
- #include <ipc/ipc_port.h>
- #if MACH_VM_DEBUG
- /*
- * Routine: vm_object_real_name
- * Purpose:
- * Convert a VM object to a name port.
- * Conditions:
- * Takes object and port locks.
- * Returns:
- * A naked send right for the object's name port,
- * or IP_NULL if the object or its name port is null.
- */
- ipc_port_t
- vm_object_real_name(vm_object_t object)
- {
- ipc_port_t port = IP_NULL;
- if (object != VM_OBJECT_NULL) {
- vm_object_lock(object);
- if (object->pager_name != IP_NULL)
- port = ipc_port_make_send(object->pager_name);
- vm_object_unlock(object);
- }
- return port;
- }
- /*
- * Routine: mach_vm_region_info [kernel call]
- * Purpose:
- * Retrieve information about a VM region,
- * including info about the object chain.
- * Conditions:
- * Nothing locked.
- * Returns:
- * KERN_SUCCESS Retrieve region/object info.
- * KERN_INVALID_TASK The map is null.
- * KERN_NO_SPACE There is no entry at/after the address.
- */
- kern_return_t
- mach_vm_region_info(
- vm_map_t map,
- vm_offset_t address,
- vm_region_info_t *regionp,
- ipc_port_t *portp)
- {
- vm_map_t cmap; /* current map in traversal */
- vm_map_t nmap; /* next map to look at */
- vm_map_entry_t entry; /* entry in current map */
- vm_object_t object;
- if (map == VM_MAP_NULL)
- return KERN_INVALID_TASK;
- /* find the entry containing (or following) the address */
- vm_map_lock_read(map);
- for (cmap = map;;) {
- /* cmap is read-locked */
- if (!vm_map_lookup_entry(cmap, address, &entry)) {
- entry = entry->vme_next;
- if (entry == vm_map_to_entry(cmap)) {
- if (map == cmap) {
- vm_map_unlock_read(cmap);
- return KERN_NO_SPACE;
- }
- /* back out to top-level & skip this submap */
- address = vm_map_max(cmap);
- vm_map_unlock_read(cmap);
- vm_map_lock_read(map);
- cmap = map;
- continue;
- }
- }
- if (entry->is_sub_map) {
- /* move down to the sub map */
- nmap = entry->object.sub_map;
- vm_map_lock_read(nmap);
- vm_map_unlock_read(cmap);
- cmap = nmap;
- continue;
- } else {
- break;
- }
- /*NOTREACHED*/
- }
- assert(entry->vme_start < entry->vme_end);
- regionp->vri_start = entry->vme_start;
- regionp->vri_end = entry->vme_end;
- /* attributes from the real entry */
- regionp->vri_protection = entry->protection;
- regionp->vri_max_protection = entry->max_protection;
- regionp->vri_inheritance = entry->inheritance;
- regionp->vri_wired_count = !!entry->wired_count; /* Doesn't stack */
- regionp->vri_user_wired_count = regionp->vri_wired_count; /* Obsolete */
- object = entry->object.vm_object;
- *portp = vm_object_real_name(object);
- regionp->vri_object = (vm_offset_t) object;
- regionp->vri_offset = entry->offset;
- regionp->vri_needs_copy = entry->needs_copy;
- regionp->vri_sharing = entry->is_shared;
- vm_map_unlock_read(cmap);
- return KERN_SUCCESS;
- }
- /*
- * Routine: mach_vm_object_info [kernel call]
- * Purpose:
- * Retrieve information about a VM object.
- * Conditions:
- * Nothing locked.
- * Returns:
- * KERN_SUCCESS Retrieved object info.
- * KERN_INVALID_ARGUMENT The object is null.
- */
- kern_return_t
- mach_vm_object_info(
- vm_object_t object,
- vm_object_info_t *infop,
- ipc_port_t *shadowp,
- ipc_port_t *copyp)
- {
- vm_object_info_t info;
- vm_object_info_state_t state;
- ipc_port_t shadow, copy;
- if (object == VM_OBJECT_NULL)
- return KERN_INVALID_ARGUMENT;
- /*
- * Because of lock-ordering/deadlock considerations,
- * we can't use vm_object_real_name for the copy object.
- */
- retry:
- vm_object_lock(object);
- copy = IP_NULL;
- if (object->copy != VM_OBJECT_NULL) {
- if (!vm_object_lock_try(object->copy)) {
- vm_object_unlock(object);
- simple_lock_pause(); /* wait a bit */
- goto retry;
- }
- if (object->copy->pager_name != IP_NULL)
- copy = ipc_port_make_send(object->copy->pager_name);
- vm_object_unlock(object->copy);
- }
- shadow = vm_object_real_name(object->shadow);
- info.voi_object = (vm_offset_t) object;
- info.voi_pagesize = PAGE_SIZE;
- info.voi_size = object->size;
- info.voi_ref_count = object->ref_count;
- info.voi_resident_page_count = object->resident_page_count;
- info.voi_absent_count = object->absent_count;
- info.voi_copy = (vm_offset_t) object->copy;
- info.voi_shadow = (vm_offset_t) object->shadow;
- info.voi_shadow_offset = object->shadow_offset;
- info.voi_paging_offset = object->paging_offset;
- info.voi_copy_strategy = object->copy_strategy;
- info.voi_last_alloc = object->last_alloc;
- info.voi_paging_in_progress = object->paging_in_progress;
- state = 0;
- if (object->pager_created)
- state |= VOI_STATE_PAGER_CREATED;
- if (object->pager_initialized)
- state |= VOI_STATE_PAGER_INITIALIZED;
- if (object->pager_ready)
- state |= VOI_STATE_PAGER_READY;
- if (object->can_persist)
- state |= VOI_STATE_CAN_PERSIST;
- if (object->internal)
- state |= VOI_STATE_INTERNAL;
- if (object->temporary)
- state |= VOI_STATE_TEMPORARY;
- if (object->alive)
- state |= VOI_STATE_ALIVE;
- if (object->lock_in_progress)
- state |= VOI_STATE_LOCK_IN_PROGRESS;
- if (object->lock_restart)
- state |= VOI_STATE_LOCK_RESTART;
- info.voi_state = state;
- vm_object_unlock(object);
- *infop = info;
- *shadowp = shadow;
- *copyp = copy;
- return KERN_SUCCESS;
- }
- #define VPI_STATE_NODATA (VPI_STATE_BUSY|VPI_STATE_FICTITIOUS| \
- VPI_STATE_PRIVATE|VPI_STATE_ABSENT)
- /*
- * Routine: mach_vm_object_pages [kernel call]
- * Purpose:
- * Retrieve information about the pages in a VM object.
- * Conditions:
- * Nothing locked. Obeys CountInOut protocol.
- * Returns:
- * KERN_SUCCESS Retrieved object info.
- * KERN_INVALID_ARGUMENT The object is null.
- * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
- */
- kern_return_t
- mach_vm_object_pages(
- vm_object_t object,
- vm_page_info_array_t *pagesp,
- natural_t *countp)
- {
- vm_size_t size;
- vm_offset_t addr;
- vm_page_info_t *pages;
- unsigned int potential, actual, count;
- vm_page_t p;
- kern_return_t kr;
- if (object == VM_OBJECT_NULL)
- return KERN_INVALID_ARGUMENT;
- /* start with in-line memory */
- pages = *pagesp;
- potential = *countp;
- for (size = 0;;) {
- vm_object_lock(object);
- actual = object->resident_page_count;
- if (actual <= potential)
- break;
- vm_object_unlock(object);
- if (pages != *pagesp)
- kmem_free(ipc_kernel_map, addr, size);
- size = round_page(actual * sizeof *pages);
- kr = kmem_alloc(ipc_kernel_map, &addr, size);
- if (kr != KERN_SUCCESS)
- return kr;
- pages = (vm_page_info_t *) addr;
- potential = size/sizeof *pages;
- }
- /* object is locked, we have enough wired memory */
- count = 0;
- queue_iterate(&object->memq, p, vm_page_t, listq) {
- vm_page_info_t *info = &pages[count++];
- vm_page_info_state_t state = 0;
- info->vpi_offset = p->offset;
- info->vpi_phys_addr = p->phys_addr;
- info->vpi_wire_count = p->wire_count;
- info->vpi_page_lock = p->page_lock;
- info->vpi_unlock_request = p->unlock_request;
- if (p->busy)
- state |= VPI_STATE_BUSY;
- if (p->wanted)
- state |= VPI_STATE_WANTED;
- if (p->tabled)
- state |= VPI_STATE_TABLED;
- if (p->fictitious)
- state |= VPI_STATE_FICTITIOUS;
- if (p->private)
- state |= VPI_STATE_PRIVATE;
- if (p->absent)
- state |= VPI_STATE_ABSENT;
- if (p->error)
- state |= VPI_STATE_ERROR;
- if (p->dirty)
- state |= VPI_STATE_DIRTY;
- if (p->precious)
- state |= VPI_STATE_PRECIOUS;
- if (p->overwriting)
- state |= VPI_STATE_OVERWRITING;
- if (((state & (VPI_STATE_NODATA|VPI_STATE_DIRTY)) == 0) &&
- pmap_is_modified(p->phys_addr)) {
- state |= VPI_STATE_DIRTY;
- p->dirty = TRUE;
- }
- vm_page_lock_queues();
- if (p->inactive)
- state |= VPI_STATE_INACTIVE;
- if (p->active)
- state |= VPI_STATE_ACTIVE;
- if (p->laundry)
- state |= VPI_STATE_LAUNDRY;
- if (p->free)
- state |= VPI_STATE_FREE;
- if (p->reference)
- state |= VPI_STATE_REFERENCE;
- if (((state & (VPI_STATE_NODATA|VPI_STATE_REFERENCE)) == 0) &&
- pmap_is_referenced(p->phys_addr)) {
- state |= VPI_STATE_REFERENCE;
- p->reference = TRUE;
- }
- vm_page_unlock_queues();
- info->vpi_state = state;
- }
- if (object->resident_page_count != count)
- panic("mach_vm_object_pages");
- vm_object_unlock(object);
- if (pages == *pagesp) {
- /* data fit in-line; nothing to deallocate */
- *countp = actual;
- } else if (actual == 0) {
- kmem_free(ipc_kernel_map, addr, size);
- *countp = 0;
- } else {
- vm_size_t size_used, rsize_used;
- vm_map_copy_t copy;
- /* kmem_alloc doesn't zero memory */
- size_used = actual * sizeof *pages;
- rsize_used = round_page(size_used);
- if (rsize_used != size)
- kmem_free(ipc_kernel_map,
- addr + rsize_used, size - rsize_used);
- if (size_used != rsize_used)
- memset((void *) (addr + size_used), 0,
- rsize_used - size_used);
- kr = vm_map_copyin(ipc_kernel_map, addr, rsize_used,
- TRUE, ©);
- assert(kr == KERN_SUCCESS);
- *pagesp = (vm_page_info_t *) copy;
- *countp = actual;
- }
- return KERN_SUCCESS;
- }
- #endif /* MACH_VM_DEBUG */
- /*
- * Routine: host_virtual_physical_table_info
- * Purpose:
- * Return information about the VP table.
- * Conditions:
- * Nothing locked. Obeys CountInOut protocol.
- * Returns:
- * KERN_SUCCESS Returned information.
- * KERN_INVALID_HOST The host is null.
- * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
- */
- kern_return_t
- host_virtual_physical_table_info(host, infop, countp)
- const host_t host;
- hash_info_bucket_array_t *infop;
- natural_t *countp;
- {
- vm_offset_t addr;
- vm_size_t size = 0;/* '=0' to quiet gcc warnings */
- hash_info_bucket_t *info;
- unsigned int potential, actual;
- kern_return_t kr;
- if (host == HOST_NULL)
- return KERN_INVALID_HOST;
- /* start with in-line data */
- info = *infop;
- potential = *countp;
- for (;;) {
- actual = vm_page_info(info, potential);
- if (actual <= potential)
- break;
- /* allocate more memory */
- if (info != *infop)
- kmem_free(ipc_kernel_map, addr, size);
- size = round_page(actual * sizeof *info);
- kr = kmem_alloc_pageable(ipc_kernel_map, &addr, size);
- if (kr != KERN_SUCCESS)
- return KERN_RESOURCE_SHORTAGE;
- info = (hash_info_bucket_t *) addr;
- potential = size/sizeof *info;
- }
- if (info == *infop) {
- /* data fit in-line; nothing to deallocate */
- *countp = actual;
- } else if (actual == 0) {
- kmem_free(ipc_kernel_map, addr, size);
- *countp = 0;
- } else {
- vm_map_copy_t copy;
- vm_size_t used;
- used = round_page(actual * sizeof *info);
- if (used != size)
- kmem_free(ipc_kernel_map, addr + used, size - used);
- kr = vm_map_copyin(ipc_kernel_map, addr, used,
- TRUE, ©);
- assert(kr == KERN_SUCCESS);
- *infop = (hash_info_bucket_t *) copy;
- *countp = actual;
- }
- return KERN_SUCCESS;
- }
|