|
|
1.1.1.2 root 1: /*
1.1 root 2: * Mach Operating System
3: * Copyright (c) 1991,1990 Carnegie Mellon University
4: * All Rights Reserved.
1.1.1.2 root 5: *
1.1 root 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.
1.1.1.2 root 11: *
1.1 root 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.
1.1.1.2 root 15: *
1.1 root 16: * Carnegie Mellon requests users of this software to return to
1.1.1.2 root 17: *
1.1 root 18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
1.1.1.2 root 22: *
1.1 root 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:
1.1.1.3 root 34: #include <string.h>
1.1 root 35:
1.1.1.3 root 36: #include <kern/debug.h>
1.1 root 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:
1.1.1.3 root 54: #if MACH_VM_DEBUG
1.1 root 55:
56: /*
57: * Routine: vm_object_real_name
58: * Purpose:
59: * Convert a VM object to a name port.
60: * Conditions:
61: * Takes object and port locks.
62: * Returns:
63: * A naked send right for the object's name port,
64: * or IP_NULL if the object or its name port is null.
65: */
66:
67: ipc_port_t
1.1.1.4 root 68: vm_object_real_name(vm_object_t object)
1.1 root 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
1.1.1.4 root 96: mach_vm_region_info(
97: vm_map_t map,
98: vm_offset_t address,
99: vm_region_info_t *regionp,
100: ipc_port_t *portp)
1.1 root 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
1.1.1.4 root 186: mach_vm_object_info(
187: vm_object_t object,
188: vm_object_info_t *infop,
189: ipc_port_t *shadowp,
190: ipc_port_t *copyp)
1.1 root 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: info.voi_state = state;
254: vm_object_unlock(object);
255:
256: *infop = info;
257: *shadowp = shadow;
258: *copyp = copy;
259: return KERN_SUCCESS;
260: }
261:
262: #define VPI_STATE_NODATA (VPI_STATE_BUSY|VPI_STATE_FICTITIOUS| \
263: VPI_STATE_PRIVATE|VPI_STATE_ABSENT)
264:
265: /*
266: * Routine: mach_vm_object_pages [kernel call]
267: * Purpose:
268: * Retrieve information about the pages in a VM object.
269: * Conditions:
270: * Nothing locked. Obeys CountInOut protocol.
271: * Returns:
272: * KERN_SUCCESS Retrieved object info.
273: * KERN_INVALID_ARGUMENT The object is null.
274: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
275: */
276:
277: kern_return_t
1.1.1.4 root 278: mach_vm_object_pages(
279: vm_object_t object,
280: vm_page_info_array_t *pagesp,
281: natural_t *countp)
1.1 root 282: {
283: vm_size_t size;
284: vm_offset_t addr;
285: vm_page_info_t *pages;
286: unsigned int potential, actual, count;
287: vm_page_t p;
288: kern_return_t kr;
289:
290: if (object == VM_OBJECT_NULL)
291: return KERN_INVALID_ARGUMENT;
292:
293: /* start with in-line memory */
294:
295: pages = *pagesp;
296: potential = *countp;
297:
298: for (size = 0;;) {
299: vm_object_lock(object);
300: actual = object->resident_page_count;
301: if (actual <= potential)
302: break;
303: vm_object_unlock(object);
304:
305: if (pages != *pagesp)
306: kmem_free(ipc_kernel_map, addr, size);
307:
308: size = round_page(actual * sizeof *pages);
309: kr = kmem_alloc(ipc_kernel_map, &addr, size);
310: if (kr != KERN_SUCCESS)
311: return kr;
312:
313: pages = (vm_page_info_t *) addr;
314: potential = size/sizeof *pages;
315: }
316: /* object is locked, we have enough wired memory */
317:
318: count = 0;
319: queue_iterate(&object->memq, p, vm_page_t, listq) {
320: vm_page_info_t *info = &pages[count++];
321: vm_page_info_state_t state = 0;
322:
323: info->vpi_offset = p->offset;
324: info->vpi_phys_addr = p->phys_addr;
325: info->vpi_wire_count = p->wire_count;
326: info->vpi_page_lock = p->page_lock;
327: info->vpi_unlock_request = p->unlock_request;
328:
329: if (p->busy)
330: state |= VPI_STATE_BUSY;
331: if (p->wanted)
332: state |= VPI_STATE_WANTED;
333: if (p->tabled)
334: state |= VPI_STATE_TABLED;
335: if (p->fictitious)
336: state |= VPI_STATE_FICTITIOUS;
337: if (p->private)
338: state |= VPI_STATE_PRIVATE;
339: if (p->absent)
340: state |= VPI_STATE_ABSENT;
341: if (p->error)
342: state |= VPI_STATE_ERROR;
343: if (p->dirty)
344: state |= VPI_STATE_DIRTY;
345: if (p->precious)
346: state |= VPI_STATE_PRECIOUS;
347: if (p->overwriting)
348: state |= VPI_STATE_OVERWRITING;
349:
350: if (((state & (VPI_STATE_NODATA|VPI_STATE_DIRTY)) == 0) &&
351: pmap_is_modified(p->phys_addr)) {
352: state |= VPI_STATE_DIRTY;
353: p->dirty = TRUE;
354: }
355:
356: vm_page_lock_queues();
357: if (p->inactive)
358: state |= VPI_STATE_INACTIVE;
359: if (p->active)
360: state |= VPI_STATE_ACTIVE;
361: if (p->laundry)
362: state |= VPI_STATE_LAUNDRY;
363: if (p->free)
364: state |= VPI_STATE_FREE;
365: if (p->reference)
366: state |= VPI_STATE_REFERENCE;
367:
368: if (((state & (VPI_STATE_NODATA|VPI_STATE_REFERENCE)) == 0) &&
369: pmap_is_referenced(p->phys_addr)) {
370: state |= VPI_STATE_REFERENCE;
371: p->reference = TRUE;
372: }
373: vm_page_unlock_queues();
374:
375: info->vpi_state = state;
376: }
377:
378: if (object->resident_page_count != count)
379: panic("mach_vm_object_pages");
380: vm_object_unlock(object);
381:
382: if (pages == *pagesp) {
383: /* data fit in-line; nothing to deallocate */
384:
385: *countp = actual;
386: } else if (actual == 0) {
387: kmem_free(ipc_kernel_map, addr, size);
388:
389: *countp = 0;
390: } else {
391: vm_size_t size_used, rsize_used;
392: vm_map_copy_t copy;
393:
394: /* kmem_alloc doesn't zero memory */
395:
396: size_used = actual * sizeof *pages;
397: rsize_used = round_page(size_used);
398:
399: if (rsize_used != size)
400: kmem_free(ipc_kernel_map,
401: addr + rsize_used, size - rsize_used);
402:
403: if (size_used != rsize_used)
1.1.1.4 root 404: memset((void *) (addr + size_used), 0,
1.1.1.3 root 405: rsize_used - size_used);
1.1 root 406:
407: kr = vm_map_copyin(ipc_kernel_map, addr, rsize_used,
408: TRUE, ©);
409: assert(kr == KERN_SUCCESS);
410:
411: *pagesp = (vm_page_info_t *) copy;
412: *countp = actual;
413: }
414:
415: return KERN_SUCCESS;
416: }
417:
1.1.1.2 root 418: #endif /* MACH_VM_DEBUG */
1.1 root 419:
420: /*
421: * Routine: host_virtual_physical_table_info
422: * Purpose:
423: * Return information about the VP table.
424: * Conditions:
425: * Nothing locked. Obeys CountInOut protocol.
426: * Returns:
427: * KERN_SUCCESS Returned information.
428: * KERN_INVALID_HOST The host is null.
429: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
430: */
431:
432: kern_return_t
433: host_virtual_physical_table_info(host, infop, countp)
1.1.1.4 root 434: const host_t host;
1.1 root 435: hash_info_bucket_array_t *infop;
436: natural_t *countp;
437: {
438: vm_offset_t addr;
439: vm_size_t size = 0;/* '=0' to quiet gcc warnings */
440: hash_info_bucket_t *info;
441: unsigned int potential, actual;
442: kern_return_t kr;
443:
444: if (host == HOST_NULL)
445: return KERN_INVALID_HOST;
446:
447: /* start with in-line data */
448:
449: info = *infop;
450: potential = *countp;
451:
452: for (;;) {
453: actual = vm_page_info(info, potential);
454: if (actual <= potential)
455: break;
456:
457: /* allocate more memory */
458:
459: if (info != *infop)
460: kmem_free(ipc_kernel_map, addr, size);
461:
462: size = round_page(actual * sizeof *info);
463: kr = kmem_alloc_pageable(ipc_kernel_map, &addr, size);
464: if (kr != KERN_SUCCESS)
465: return KERN_RESOURCE_SHORTAGE;
466:
467: info = (hash_info_bucket_t *) addr;
468: potential = size/sizeof *info;
469: }
470:
471: if (info == *infop) {
472: /* data fit in-line; nothing to deallocate */
473:
474: *countp = actual;
475: } else if (actual == 0) {
476: kmem_free(ipc_kernel_map, addr, size);
477:
478: *countp = 0;
479: } else {
480: vm_map_copy_t copy;
481: vm_size_t used;
482:
483: used = round_page(actual * sizeof *info);
484:
485: if (used != size)
486: kmem_free(ipc_kernel_map, addr + used, size - used);
487:
488: kr = vm_map_copyin(ipc_kernel_map, addr, used,
489: TRUE, ©);
490: assert(kr == KERN_SUCCESS);
491:
492: *infop = (hash_info_bucket_t *) copy;
493: *countp = actual;
494: }
495:
496: return KERN_SUCCESS;
497: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.