|
|
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
68: vm_object_real_name(object)
69: vm_object_t object;
70: {
71: ipc_port_t port = IP_NULL;
72:
73: if (object != VM_OBJECT_NULL) {
74: vm_object_lock(object);
75: if (object->pager_name != IP_NULL)
76: port = ipc_port_make_send(object->pager_name);
77: vm_object_unlock(object);
78: }
79:
80: return port;
81: }
82:
83: /*
84: * Routine: mach_vm_region_info [kernel call]
85: * Purpose:
86: * Retrieve information about a VM region,
87: * including info about the object chain.
88: * Conditions:
89: * Nothing locked.
90: * Returns:
91: * KERN_SUCCESS Retrieve region/object info.
92: * KERN_INVALID_TASK The map is null.
93: * KERN_NO_SPACE There is no entry at/after the address.
94: */
95:
96: kern_return_t
97: mach_vm_region_info(map, address, regionp, portp)
98: vm_map_t map;
99: vm_offset_t address;
100: vm_region_info_t *regionp;
101: ipc_port_t *portp;
102: {
103: vm_map_t cmap; /* current map in traversal */
104: vm_map_t nmap; /* next map to look at */
105: vm_map_entry_t entry; /* entry in current map */
106: vm_object_t object;
107:
108: if (map == VM_MAP_NULL)
109: return KERN_INVALID_TASK;
110:
111: /* find the entry containing (or following) the address */
112:
113: vm_map_lock_read(map);
114: for (cmap = map;;) {
115: /* cmap is read-locked */
116:
117: if (!vm_map_lookup_entry(cmap, address, &entry)) {
118: entry = entry->vme_next;
119: if (entry == vm_map_to_entry(cmap)) {
120: if (map == cmap) {
121: vm_map_unlock_read(cmap);
122: return KERN_NO_SPACE;
123: }
124:
125: /* back out to top-level & skip this submap */
126:
127: address = vm_map_max(cmap);
128: vm_map_unlock_read(cmap);
129: vm_map_lock_read(map);
130: cmap = map;
131: continue;
132: }
133: }
134:
135: if (entry->is_sub_map) {
136: /* move down to the sub map */
137:
138: nmap = entry->object.sub_map;
139: vm_map_lock_read(nmap);
140: vm_map_unlock_read(cmap);
141: cmap = nmap;
142: continue;
143: } else {
144: break;
145: }
146: /*NOTREACHED*/
147: }
148:
149:
150: assert(entry->vme_start < entry->vme_end);
151:
152: regionp->vri_start = entry->vme_start;
153: regionp->vri_end = entry->vme_end;
154:
155: /* attributes from the real entry */
156:
157: regionp->vri_protection = entry->protection;
158: regionp->vri_max_protection = entry->max_protection;
159: regionp->vri_inheritance = entry->inheritance;
160: regionp->vri_wired_count = entry->wired_count;
161: regionp->vri_user_wired_count = entry->user_wired_count;
162:
163: object = entry->object.vm_object;
164: *portp = vm_object_real_name(object);
165: regionp->vri_object = (vm_offset_t) object;
166: regionp->vri_offset = entry->offset;
167: regionp->vri_needs_copy = entry->needs_copy;
168:
169: regionp->vri_sharing = entry->is_shared;
170:
171: vm_map_unlock_read(cmap);
172: return KERN_SUCCESS;
173: }
174:
175: /*
176: * Routine: mach_vm_object_info [kernel call]
177: * Purpose:
178: * Retrieve information about a VM object.
179: * Conditions:
180: * Nothing locked.
181: * Returns:
182: * KERN_SUCCESS Retrieved object info.
183: * KERN_INVALID_ARGUMENT The object is null.
184: */
185:
186: kern_return_t
187: mach_vm_object_info(object, infop, shadowp, copyp)
188: vm_object_t object;
189: vm_object_info_t *infop;
190: ipc_port_t *shadowp;
191: ipc_port_t *copyp;
192: {
193: vm_object_info_t info;
194: vm_object_info_state_t state;
195: ipc_port_t shadow, copy;
196:
197: if (object == VM_OBJECT_NULL)
198: return KERN_INVALID_ARGUMENT;
199:
200: /*
201: * Because of lock-ordering/deadlock considerations,
202: * we can't use vm_object_real_name for the copy object.
203: */
204:
205: retry:
206: vm_object_lock(object);
207: copy = IP_NULL;
208: if (object->copy != VM_OBJECT_NULL) {
209: if (!vm_object_lock_try(object->copy)) {
210: vm_object_unlock(object);
211: simple_lock_pause(); /* wait a bit */
212: goto retry;
213: }
214:
215: if (object->copy->pager_name != IP_NULL)
216: copy = ipc_port_make_send(object->copy->pager_name);
217: vm_object_unlock(object->copy);
218: }
219: shadow = vm_object_real_name(object->shadow);
220:
221: info.voi_object = (vm_offset_t) object;
222: info.voi_pagesize = PAGE_SIZE;
223: info.voi_size = object->size;
224: info.voi_ref_count = object->ref_count;
225: info.voi_resident_page_count = object->resident_page_count;
226: info.voi_absent_count = object->absent_count;
227: info.voi_copy = (vm_offset_t) object->copy;
228: info.voi_shadow = (vm_offset_t) object->shadow;
229: info.voi_shadow_offset = object->shadow_offset;
230: info.voi_paging_offset = object->paging_offset;
231: info.voi_copy_strategy = object->copy_strategy;
232: info.voi_last_alloc = object->last_alloc;
233: info.voi_paging_in_progress = object->paging_in_progress;
234:
235: state = 0;
236: if (object->pager_created)
237: state |= VOI_STATE_PAGER_CREATED;
238: if (object->pager_initialized)
239: state |= VOI_STATE_PAGER_INITIALIZED;
240: if (object->pager_ready)
241: state |= VOI_STATE_PAGER_READY;
242: if (object->can_persist)
243: state |= VOI_STATE_CAN_PERSIST;
244: if (object->internal)
245: state |= VOI_STATE_INTERNAL;
246: if (object->temporary)
247: state |= VOI_STATE_TEMPORARY;
248: if (object->alive)
249: state |= VOI_STATE_ALIVE;
250: if (object->lock_in_progress)
251: state |= VOI_STATE_LOCK_IN_PROGRESS;
252: if (object->lock_restart)
253: state |= VOI_STATE_LOCK_RESTART;
254: if (object->use_old_pageout)
255: state |= VOI_STATE_USE_OLD_PAGEOUT;
256: info.voi_state = state;
257: vm_object_unlock(object);
258:
259: *infop = info;
260: *shadowp = shadow;
261: *copyp = copy;
262: return KERN_SUCCESS;
263: }
264:
265: #define VPI_STATE_NODATA (VPI_STATE_BUSY|VPI_STATE_FICTITIOUS| \
266: VPI_STATE_PRIVATE|VPI_STATE_ABSENT)
267:
268: /*
269: * Routine: mach_vm_object_pages [kernel call]
270: * Purpose:
271: * Retrieve information about the pages in a VM object.
272: * Conditions:
273: * Nothing locked. Obeys CountInOut protocol.
274: * Returns:
275: * KERN_SUCCESS Retrieved object info.
276: * KERN_INVALID_ARGUMENT The object is null.
277: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
278: */
279:
280: kern_return_t
281: mach_vm_object_pages(object, pagesp, countp)
282: vm_object_t object;
283: vm_page_info_array_t *pagesp;
284: natural_t *countp;
285: {
286: vm_size_t size;
287: vm_offset_t addr;
288: vm_page_info_t *pages;
289: unsigned int potential, actual, count;
290: vm_page_t p;
291: kern_return_t kr;
292:
293: if (object == VM_OBJECT_NULL)
294: return KERN_INVALID_ARGUMENT;
295:
296: /* start with in-line memory */
297:
298: pages = *pagesp;
299: potential = *countp;
300:
301: for (size = 0;;) {
302: vm_object_lock(object);
303: actual = object->resident_page_count;
304: if (actual <= potential)
305: break;
306: vm_object_unlock(object);
307:
308: if (pages != *pagesp)
309: kmem_free(ipc_kernel_map, addr, size);
310:
311: size = round_page(actual * sizeof *pages);
312: kr = kmem_alloc(ipc_kernel_map, &addr, size);
313: if (kr != KERN_SUCCESS)
314: return kr;
315:
316: pages = (vm_page_info_t *) addr;
317: potential = size/sizeof *pages;
318: }
319: /* object is locked, we have enough wired memory */
320:
321: count = 0;
322: queue_iterate(&object->memq, p, vm_page_t, listq) {
323: vm_page_info_t *info = &pages[count++];
324: vm_page_info_state_t state = 0;
325:
326: info->vpi_offset = p->offset;
327: info->vpi_phys_addr = p->phys_addr;
328: info->vpi_wire_count = p->wire_count;
329: info->vpi_page_lock = p->page_lock;
330: info->vpi_unlock_request = p->unlock_request;
331:
332: if (p->busy)
333: state |= VPI_STATE_BUSY;
334: if (p->wanted)
335: state |= VPI_STATE_WANTED;
336: if (p->tabled)
337: state |= VPI_STATE_TABLED;
338: if (p->fictitious)
339: state |= VPI_STATE_FICTITIOUS;
340: if (p->private)
341: state |= VPI_STATE_PRIVATE;
342: if (p->absent)
343: state |= VPI_STATE_ABSENT;
344: if (p->error)
345: state |= VPI_STATE_ERROR;
346: if (p->dirty)
347: state |= VPI_STATE_DIRTY;
348: if (p->precious)
349: state |= VPI_STATE_PRECIOUS;
350: if (p->overwriting)
351: state |= VPI_STATE_OVERWRITING;
352:
353: if (((state & (VPI_STATE_NODATA|VPI_STATE_DIRTY)) == 0) &&
354: pmap_is_modified(p->phys_addr)) {
355: state |= VPI_STATE_DIRTY;
356: p->dirty = TRUE;
357: }
358:
359: vm_page_lock_queues();
360: if (p->inactive)
361: state |= VPI_STATE_INACTIVE;
362: if (p->active)
363: state |= VPI_STATE_ACTIVE;
364: if (p->laundry)
365: state |= VPI_STATE_LAUNDRY;
366: if (p->free)
367: state |= VPI_STATE_FREE;
368: if (p->reference)
369: state |= VPI_STATE_REFERENCE;
370:
371: if (((state & (VPI_STATE_NODATA|VPI_STATE_REFERENCE)) == 0) &&
372: pmap_is_referenced(p->phys_addr)) {
373: state |= VPI_STATE_REFERENCE;
374: p->reference = TRUE;
375: }
376: vm_page_unlock_queues();
377:
378: info->vpi_state = state;
379: }
380:
381: if (object->resident_page_count != count)
382: panic("mach_vm_object_pages");
383: vm_object_unlock(object);
384:
385: if (pages == *pagesp) {
386: /* data fit in-line; nothing to deallocate */
387:
388: *countp = actual;
389: } else if (actual == 0) {
390: kmem_free(ipc_kernel_map, addr, size);
391:
392: *countp = 0;
393: } else {
394: vm_size_t size_used, rsize_used;
395: vm_map_copy_t copy;
396:
397: /* kmem_alloc doesn't zero memory */
398:
399: size_used = actual * sizeof *pages;
400: rsize_used = round_page(size_used);
401:
402: if (rsize_used != size)
403: kmem_free(ipc_kernel_map,
404: addr + rsize_used, size - rsize_used);
405:
406: if (size_used != rsize_used)
1.1.1.3 ! root 407: memset((char *) (addr + size_used), 0,
! 408: rsize_used - size_used);
1.1 root 409:
410: kr = vm_map_copyin(ipc_kernel_map, addr, rsize_used,
411: TRUE, ©);
412: assert(kr == KERN_SUCCESS);
413:
414: *pagesp = (vm_page_info_t *) copy;
415: *countp = actual;
416: }
417:
418: return KERN_SUCCESS;
419: }
420:
1.1.1.2 root 421: #endif /* MACH_VM_DEBUG */
1.1 root 422:
423: /*
424: * Routine: host_virtual_physical_table_info
425: * Purpose:
426: * Return information about the VP table.
427: * Conditions:
428: * Nothing locked. Obeys CountInOut protocol.
429: * Returns:
430: * KERN_SUCCESS Returned information.
431: * KERN_INVALID_HOST The host is null.
432: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
433: */
434:
435: kern_return_t
436: host_virtual_physical_table_info(host, infop, countp)
437: host_t host;
438: hash_info_bucket_array_t *infop;
439: natural_t *countp;
440: {
441: vm_offset_t addr;
442: vm_size_t size = 0;/* '=0' to quiet gcc warnings */
443: hash_info_bucket_t *info;
444: unsigned int potential, actual;
445: kern_return_t kr;
446:
447: if (host == HOST_NULL)
448: return KERN_INVALID_HOST;
449:
450: /* start with in-line data */
451:
452: info = *infop;
453: potential = *countp;
454:
455: for (;;) {
456: actual = vm_page_info(info, potential);
457: if (actual <= potential)
458: break;
459:
460: /* allocate more memory */
461:
462: if (info != *infop)
463: kmem_free(ipc_kernel_map, addr, size);
464:
465: size = round_page(actual * sizeof *info);
466: kr = kmem_alloc_pageable(ipc_kernel_map, &addr, size);
467: if (kr != KERN_SUCCESS)
468: return KERN_RESOURCE_SHORTAGE;
469:
470: info = (hash_info_bucket_t *) addr;
471: potential = size/sizeof *info;
472: }
473:
474: if (info == *infop) {
475: /* data fit in-line; nothing to deallocate */
476:
477: *countp = actual;
478: } else if (actual == 0) {
479: kmem_free(ipc_kernel_map, addr, size);
480:
481: *countp = 0;
482: } else {
483: vm_map_copy_t copy;
484: vm_size_t used;
485:
486: used = round_page(actual * sizeof *info);
487:
488: if (used != size)
489: kmem_free(ipc_kernel_map, addr + used, size - used);
490:
491: kr = vm_map_copyin(ipc_kernel_map, addr, used,
492: TRUE, ©);
493: assert(kr == KERN_SUCCESS);
494:
495: *infop = (hash_info_bucket_t *) copy;
496: *countp = actual;
497: }
498:
499: return KERN_SUCCESS;
500: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.