For rumpdisk to efficiently determine the physical address, both for checking whether it is below 4GiB, and for giving it to the disk driver, we need a gnumach primitive (and that is not conditioned by MACH_VM_DEBUG like mach_vm_region_info and mach_vm_object_pages_phys are).
--- Please notably review the RPC part, I really don't know that much about mig. diff --git a/i386/include/mach/i386/machine_types.defs b/i386/include/mach/i386/machine_types.defs index 3d540be9..76c7dcf9 100755 --- a/i386/include/mach/i386/machine_types.defs +++ b/i386/include/mach/i386/machine_types.defs @@ -102,5 +102,6 @@ type long_integer_t = rpc_long_integer_t * Physical address size */ type rpc_phys_addr_t = uint64_t; +type rpc_phys_addr_array_t = array[] of rpc_phys_addr_t; #endif /* _MACHINE_MACHINE_TYPES_DEFS_ */ diff --git a/i386/include/mach/i386/vm_types.h b/i386/include/mach/i386/vm_types.h index bd07ef26..8f528ae1 100644 --- a/i386/include/mach/i386/vm_types.h +++ b/i386/include/mach/i386/vm_types.h @@ -94,6 +94,7 @@ typedef unsigned long phys_addr_t; typedef unsigned long long phys_addr_t; #endif typedef unsigned long long rpc_phys_addr_t; +typedef rpc_phys_addr_t *rpc_phys_addr_array_t; /* * A vm_size_t is the proper type for e.g. diff --git a/include/mach/gnumach.defs b/include/mach/gnumach.defs index 05101a48..6252de96 100644 --- a/include/mach/gnumach.defs +++ b/include/mach/gnumach.defs @@ -197,3 +197,13 @@ routine vm_allocate_contiguous( simpleroutine task_set_essential( task : task_t; essential : boolean_t); + +/* + * Returns physical addresses of a region of memory + */ +routine vm_pages_phys( + host_priv : host_priv_t; + target_task : vm_task_t; + vaddr : vm_address_t; + size : vm_size_t; + out pages : rpc_phys_addr_array_t); diff --git a/vm/vm_user.c b/vm/vm_user.c index 08cc17a4..6c16c397 100644 --- a/vm/vm_user.c +++ b/vm/vm_user.c @@ -700,3 +700,90 @@ kern_return_t vm_allocate_contiguous( return KERN_SUCCESS; } + +/* + * vm_pages_phys returns information about a region of memory + */ +kern_return_t vm_pages_phys( + host_t host, + vm_map_t map, + vm_address_t address, + vm_size_t size, + rpc_phys_addr_array_t *pagespp, + mach_msg_type_number_t *countp) +{ + if (host == HOST_NULL) + return KERN_INVALID_HOST; + if (map == VM_MAP_NULL) + return KERN_INVALID_TASK; + + if (!page_aligned(address)) + return KERN_INVALID_ARGUMENT; + if (!page_aligned(size)) + return KERN_INVALID_ARGUMENT; + + mach_msg_type_number_t count = atop(size), cur; + + if (*countp < count) + return KERN_INVALID_ARGUMENT; + + rpc_phys_addr_array_t pagesp = *pagespp; + + for (cur = 0; cur < count; cur++) + { + vm_map_t cmap; /* current map in traversal */ + rpc_phys_addr_t paddr; + vm_map_entry_t entry; /* entry in current map */ + + /* 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 = VM_MAP_ENTRY_NULL; + break; + } + + if (entry->is_sub_map) { + /* move down to the sub map */ + + vm_map_t nmap = entry->object.sub_map; + vm_map_lock_read(nmap); + vm_map_unlock_read(cmap); + cmap = nmap; + continue; + } else { + /* Found it */ + break; + } + /*NOTREACHED*/ + } + + paddr = 0; + if (entry) + { + vm_offset_t offset = address - entry->vme_start + entry->offset; + vm_object_t object = entry->object.vm_object; + + if (object) { + vm_object_lock(object); + vm_page_t page = vm_page_lookup(object, offset); + if (page) { + if (page->phys_addr != (typeof(pagesp[cur])) page->phys_addr) + printf("warning: physical address overflow in vm_pages_phys!!\n"); + else + paddr = page->phys_addr; + } + vm_object_unlock(object); + } + } + vm_map_unlock_read(cmap); + pagesp[cur] = paddr; + + address += PAGE_SIZE; + } + *countp = count; + + return KERN_SUCCESS; +}