MachVMMemory.cpp revision cec43ab7f30085ac7f65a26a58b956a69e363a3b
124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//===-- MachVMMemory.cpp ----------------------------------------*- C++ -*-===//
224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//
324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//                     The LLVM Compiler Infrastructure
424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//
524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// This file is distributed under the University of Illinois Open Source
624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// License. See LICENSE.TXT for details.
724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//
824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//===----------------------------------------------------------------------===//
924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//
1024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//  Created by Greg Clayton on 6/26/07.
1124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//
1224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner//===----------------------------------------------------------------------===//
1324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
1424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "MachVMMemory.h"
1524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "MachVMRegion.h"
1624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "DNBLog.h"
1724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include <mach/mach_vm.h>
18fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong#include <mach/shared_region.h>
19e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong#include <sys/sysctl.h>
2024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
2124943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerMachVMMemory::MachVMMemory() :
2224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    m_page_size    (kInvalidPageSize),
2324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    m_err        (0)
2424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
2524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
2624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
2724943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerMachVMMemory::~MachVMMemory()
2824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
2924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
3024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
3124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnernub_size_t
3224943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerMachVMMemory::PageSize()
3324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
3424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (m_page_size == kInvalidPageSize)
3524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
3624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        m_err = ::host_page_size( ::mach_host_self(), &m_page_size);
3724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (m_err.Fail())
3824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            m_page_size = 0;
3924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
4024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return m_page_size;
4124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
4224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
4324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnernub_size_t
4424943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerMachVMMemory::MaxBytesLeftInPage(nub_addr_t addr, nub_size_t count)
4524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
4624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    const nub_size_t page_size = PageSize();
4724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (page_size > 0)
4824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
4924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        nub_size_t page_offset = (addr % page_size);
5024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        nub_size_t bytes_left_in_page = page_size - page_offset;
5124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (count > bytes_left_in_page)
5224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            count = bytes_left_in_page;
5324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
5424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return count;
5524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
5624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
571308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Claytonnub_bool_t
58a9385537809ef342c843c5ab972e513742652047Greg ClaytonMachVMMemory::GetMemoryRegionInfo(task_t task, nub_addr_t address, DNBRegionInfo *region_info)
59dc8ff30b6dbe28c851e99712e20c1358eca4709dJason Molenda{
60dc8ff30b6dbe28c851e99712e20c1358eca4709dJason Molenda    MachVMRegion vmRegion(task);
61dc8ff30b6dbe28c851e99712e20c1358eca4709dJason Molenda
62a9385537809ef342c843c5ab972e513742652047Greg Clayton    if (vmRegion.GetRegionForAddress(address))
63a9385537809ef342c843c5ab972e513742652047Greg Clayton    {
64a9385537809ef342c843c5ab972e513742652047Greg Clayton        region_info->addr = vmRegion.StartAddress();
65a9385537809ef342c843c5ab972e513742652047Greg Clayton        region_info->size = vmRegion.GetByteSize();
66a9385537809ef342c843c5ab972e513742652047Greg Clayton        region_info->permissions = vmRegion.GetDNBPermissions();
67a9385537809ef342c843c5ab972e513742652047Greg Clayton    }
681308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton    else
691308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton    {
701308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        region_info->addr = address;
711308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        region_info->size = 0;
721308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        if (vmRegion.GetError().Success())
731308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        {
741308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            // vmRegion.GetRegionForAddress() return false, indicating that "address"
751308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            // wasn't in a valid region, but the "vmRegion" info was successfully
761308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            // read from the task which means the info describes the next valid
771308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            // region from which we can infer the size of this invalid region
781308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            mach_vm_address_t start_addr = vmRegion.StartAddress();
791308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            if (address < start_addr)
801308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton                region_info->size = start_addr - address;
811308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        }
821308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        // If we can't get any infor about the size from the next region, just fill
831308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        // 1 in as the byte size
841308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        if (region_info->size == 0)
851308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            region_info->size = 1;
861308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton
871308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        // Not readable, writeable or executable
881308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        region_info->permissions = 0;
891308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton    }
901308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton    return true;
91dc8ff30b6dbe28c851e99712e20c1358eca4709dJason Molenda}
92fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
93e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong// For integrated graphics chip, this makes the accounting info for 'wired' memory more like top.
94e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ongstatic uint64_t GetStolenPages()
95e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong{
96e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    static uint64_t stolenPages = 0;
97e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    static bool calculated = false;
98e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    if (calculated) return stolenPages;
99e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
100e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	static int mib_reserved[CTL_MAXNAME];
101e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	static int mib_unusable[CTL_MAXNAME];
102e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	static int mib_other[CTL_MAXNAME];
103e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	static size_t mib_reserved_len = 0;
104e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	static size_t mib_unusable_len = 0;
105e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	static size_t mib_other_len = 0;
106e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	int r;
107e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
108e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	/* This can be used for testing: */
109e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	//tsamp->pages_stolen = (256 * 1024 * 1024ULL) / tsamp->pagesize;
110e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
111e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	if(0 == mib_reserved_len)
112e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    {
113e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		mib_reserved_len = CTL_MAXNAME;
114e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
115e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		r = sysctlnametomib("machdep.memmap.Reserved", mib_reserved,
116e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                            &mib_reserved_len);
117e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
118e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(-1 == r)
119e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
120e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			mib_reserved_len = 0;
121e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			return 0;
122e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
123e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
124e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		mib_unusable_len = CTL_MAXNAME;
125e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
126e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		r = sysctlnametomib("machdep.memmap.Unusable", mib_unusable,
127e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                            &mib_unusable_len);
128e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
129e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(-1 == r)
130e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
131e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			mib_reserved_len = 0;
132e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			return 0;
133e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
134e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
135e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
136e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		mib_other_len = CTL_MAXNAME;
137e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
138e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		r = sysctlnametomib("machdep.memmap.Other", mib_other,
139e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                            &mib_other_len);
140e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
141e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(-1 == r)
142e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
143e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			mib_reserved_len = 0;
144e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			return 0;
145e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
146e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	}
147e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
148e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	if(mib_reserved_len > 0 && mib_unusable_len > 0 && mib_other_len > 0)
149e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    {
150e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		uint64_t reserved = 0, unusable = 0, other = 0;
151e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		size_t reserved_len;
152e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		size_t unusable_len;
153e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		size_t other_len;
154e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
155e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		reserved_len = sizeof(reserved);
156e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		unusable_len = sizeof(unusable);
157e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		other_len = sizeof(other);
158e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
159e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		/* These are all declared as QUAD/uint64_t sysctls in the kernel. */
160e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
161e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(-1 == sysctl(mib_reserved, mib_reserved_len, &reserved,
162e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                        &reserved_len, NULL, 0))
163e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
164e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			return 0;
165e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
166e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
167e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(-1 == sysctl(mib_unusable, mib_unusable_len, &unusable,
168e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                        &unusable_len, NULL, 0))
169e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
170e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			return 0;
171e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
172e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
173e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(-1 == sysctl(mib_other, mib_other_len, &other,
174e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                        &other_len, NULL, 0))
175e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
176e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			return 0;
177e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
178e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
179e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(reserved_len == sizeof(reserved)
180e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		   && unusable_len == sizeof(unusable)
181e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		   && other_len == sizeof(other))
182e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
183e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			uint64_t stolen = reserved + unusable + other;
184e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			uint64_t mb128 = 128 * 1024 * 1024ULL;
185e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
186e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			if(stolen >= mb128)
187e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong            {
188e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                stolen = (stolen & ~((128 * 1024 * 1024ULL) - 1)); // rounding down
189e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                stolenPages = stolen/vm_page_size;
190e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			}
191e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
192e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	}
193e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
194e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    calculated = true;
195e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    return stolenPages;
196e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong}
197e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
198e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ongstatic uint64_t GetPhysicalMemory()
199e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong{
200e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    // This doesn't change often at all. No need to poll each time.
201e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    static uint64_t physical_memory = 0;
202e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    static bool calculated = false;
203e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    if (calculated) return physical_memory;
204e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
205e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    int mib[2];
206e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    mib[0] = CTL_HW;
207e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    mib[1] = HW_MEMSIZE;
208e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    size_t len = sizeof(physical_memory);
209e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    sysctl(mib, 2, &physical_memory, &len, NULL, 0);
210e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    return physical_memory;
211e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong}
212e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
213fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong// rsize and dirty_size is not adjusted for dyld shared cache and multiple __LINKEDIT segment, as in vmmap. In practice, dirty_size doesn't differ much but rsize may. There is performance penalty for the adjustment. Right now, only use the dirty_size.
214fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ongstatic void GetRegionSizes(task_t task, mach_vm_size_t &rsize, mach_vm_size_t &dirty_size)
215fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong{
216fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    mach_vm_address_t address = 0;
217fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    mach_vm_size_t size;
218fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    kern_return_t err = 0;
219fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    unsigned nestingDepth = 0;
220fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    mach_vm_size_t pages_resident = 0;
221fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    mach_vm_size_t pages_dirtied = 0;
222fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
223fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    while (1)
224fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    {
225559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        mach_msg_type_number_t  count;
226fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        struct vm_region_submap_info_64 info;
227fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
228fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        count = VM_REGION_SUBMAP_INFO_COUNT_64;
229fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        err = mach_vm_region_recurse(task, &address, &size, &nestingDepth, (vm_region_info_t)&info, &count);
230fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        if (err == KERN_INVALID_ADDRESS)
231fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
232fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            // It seems like this is a good break too.
233fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            break;
234fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        }
235fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        else if (err)
236fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
237fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            mach_error("vm_region",err);
238fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            break; // reached last region
239fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        }
240fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
241fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        bool should_count = true;
242fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        if (info.is_submap)
243fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        { // is it a submap?
244fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            nestingDepth++;
245fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            should_count = false;
246fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        }
247fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        else
248fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
249fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            // Don't count malloc stack logging data in the TOTAL VM usage lines.
250fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            if (info.user_tag == VM_MEMORY_ANALYSIS_TOOL)
251fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                should_count = false;
252fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            // Don't count system shared library region not used by this process.
253fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            if (address >= SHARED_REGION_BASE && address < (SHARED_REGION_BASE + SHARED_REGION_SIZE))
254fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                should_count = false;
255fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
256fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            address = address+size;
257fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        }
258fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
259fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        if (should_count)
260fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
261fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            pages_resident += info.pages_resident;
262fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            pages_dirtied += info.pages_dirtied;
263fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        }
264fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    }
265fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
266fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    rsize = pages_resident * vm_page_size;
267fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    dirty_size = pages_dirtied * vm_page_size;
268fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong}
269fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
270fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong// Test whether the virtual address is within the architecture's shared region.
271fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ongstatic bool InSharedRegion(mach_vm_address_t addr, cpu_type_t type)
272fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong{
273559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    mach_vm_address_t base = 0, size = 0;
274fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
275559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    switch(type) {
276559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        case CPU_TYPE_ARM:
277559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            base = SHARED_REGION_BASE_ARM;
278559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            size = SHARED_REGION_SIZE_ARM;
279fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            break;
280fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
281559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        case CPU_TYPE_X86_64:
282559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            base = SHARED_REGION_BASE_X86_64;
283559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            size = SHARED_REGION_SIZE_X86_64;
284fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            break;
285fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
286559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        case CPU_TYPE_I386:
287559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            base = SHARED_REGION_BASE_I386;
288559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            size = SHARED_REGION_SIZE_I386;
289fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            break;
290fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
291559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        default: {
292fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            // Log error abut unknown CPU type
293fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            break;
294559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        }
295559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    }
296fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
297fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
298559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    return(addr >= base && addr < (base + size));
299fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong}
300fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
301fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ongstatic void GetMemorySizes(task_t task, cpu_type_t cputype, nub_process_t pid, mach_vm_size_t &rprvt, mach_vm_size_t &vprvt)
302fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong{
303fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    // Collecting some other info cheaply but not reporting for now.
304fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    mach_vm_size_t empty = 0;
305559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    mach_vm_size_t fw_private = 0;
306fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
307559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    mach_vm_size_t aliased = 0;
308559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    mach_vm_size_t pagesize = vm_page_size;
309fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    bool global_shared_text_data_mapped = false;
310fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
311559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    for (mach_vm_address_t addr=0, size=0; ; addr += size)
312fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    {
313559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        vm_region_top_info_data_t info;
314559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        mach_msg_type_number_t count = VM_REGION_TOP_INFO_COUNT;
315559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        mach_port_t object_name;
316fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
317559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        kern_return_t kr = mach_vm_region(task, &addr, &size, VM_REGION_TOP_INFO, (vm_region_info_t)&info, &count, &object_name);
318559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        if (kr != KERN_SUCCESS) break;
319559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda
320559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        if (InSharedRegion(addr, cputype))
321fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
322559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            // Private Shared
323559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            fw_private += info.private_pages_resident * pagesize;
324fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
325559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            // Check if this process has the globally shared text and data regions mapped in.  If so, set global_shared_text_data_mapped to TRUE and avoid checking again.
326559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            if (global_shared_text_data_mapped == FALSE && info.share_mode == SM_EMPTY) {
327559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                vm_region_basic_info_data_64_t  b_info;
328559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                mach_vm_address_t b_addr = addr;
329559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                mach_vm_size_t b_size = size;
330559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                count = VM_REGION_BASIC_INFO_COUNT_64;
331559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda
332559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                kr = mach_vm_region(task, &b_addr, &b_size, VM_REGION_BASIC_INFO, (vm_region_info_t)&b_info, &count, &object_name);
333559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                if (kr != KERN_SUCCESS) break;
334fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
335559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                if (b_info.reserved) {
336559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    global_shared_text_data_mapped = TRUE;
337559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                }
338559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            }
339559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda
340559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            // Short circuit the loop if this isn't a shared private region, since that's the only region type we care about within the current address range.
341559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            if (info.share_mode != SM_PRIVATE)
342fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            {
343559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                continue;
344559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            }
345559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        }
346559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda
347559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        // Update counters according to the region type.
348559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        if (info.share_mode == SM_COW && info.ref_count == 1)
349fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
350559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            // Treat single reference SM_COW as SM_PRIVATE
351559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            info.share_mode = SM_PRIVATE;
352559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        }
353fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
354559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        switch (info.share_mode)
355fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
356559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            case SM_LARGE_PAGE:
357559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                // Treat SM_LARGE_PAGE the same as SM_PRIVATE
358559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                // since they are not shareable and are wired.
359559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            case SM_PRIVATE:
360559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                rprvt += info.private_pages_resident * pagesize;
361559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                rprvt += info.shared_pages_resident * pagesize;
362559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                vprvt += size;
363559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                break;
364559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda
365559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            case SM_EMPTY:
366fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                empty += size;
367559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                break;
368559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda
369559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            case SM_COW:
370559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            case SM_SHARED:
371fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            {
372559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                if (pid == 0)
373fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                {
374559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    // Treat kernel_task specially
375559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    if (info.share_mode == SM_COW)
376fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                    {
377559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                        rprvt += info.private_pages_resident * pagesize;
378559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                        vprvt += size;
379559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    }
380559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    break;
381559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                }
382fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
383559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                if (info.share_mode == SM_COW)
384fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                {
385559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    rprvt += info.private_pages_resident * pagesize;
386559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    vprvt += info.private_pages_resident * pagesize;
387559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                }
388559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                break;
389fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            }
390559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            default:
391fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                // log that something is really bad.
392559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                break;
393559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        }
394559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    }
395fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
396559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    rprvt += aliased;
397fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong}
398fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
399fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ongnub_bool_t
400cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming OngMachVMMemory::GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, vm_statistics_data_t &vm_stats, uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size)
401fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong{
402cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong    if (scanType & eProfileHostMemory)
403cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        physical_memory = GetPhysicalMemory();
404cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong
405cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong    if (scanType & eProfileMemory)
406cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong    {
407cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        static mach_port_t localHost = mach_host_self();
408cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
409cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        host_statistics(localHost, HOST_VM_INFO, (host_info_t)&vm_stats, &count);
410cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        vm_stats.wire_count += GetStolenPages();
411fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
412cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        GetMemorySizes(task, cputype, pid, rprvt, vprvt);
413fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
414cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        rsize = ti.resident_size;
415cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        vsize = ti.virtual_size;
416cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong    }
417cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong
418cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong    if (scanType & eProfileMemoryDirtyPage)
419cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong    {
420cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        // This uses vmmap strategy. We don't use the returned rsize for now. We prefer to match top's version since that's what we do for the rest of the metrics.
421cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        GetRegionSizes(task, rsize, dirty_size);
422cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong    }
423fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
424fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    return true;
425fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong}
426dc8ff30b6dbe28c851e99712e20c1358eca4709dJason Molenda
42724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnernub_size_t
42824943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerMachVMMemory::Read(task_t task, nub_addr_t address, void *data, nub_size_t data_count)
42924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
43024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (data == NULL || data_count == 0)
43124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return 0;
43224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
43324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    nub_size_t total_bytes_read = 0;
43424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    nub_addr_t curr_addr = address;
43524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    uint8_t *curr_data = (uint8_t*)data;
43624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    while (total_bytes_read < data_count)
43724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
43824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        mach_vm_size_t curr_size = MaxBytesLeftInPage(curr_addr, data_count - total_bytes_read);
43924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        mach_msg_type_number_t curr_bytes_read = 0;
44024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        vm_offset_t vm_memory = NULL;
44124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        m_err = ::mach_vm_read (task, curr_addr, curr_size, &vm_memory, &curr_bytes_read);
442d906b1b24a6c838d78039b399ee43dc57598ab52Jim Ingham
44355f768792c75eb5f9474edb09ca416c8737eeac0Jim Ingham        if (DNBLogCheckLogBit(LOG_MEMORY))
44424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            m_err.LogThreaded("::mach_vm_read ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt => %i )", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read);
44524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
44624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (m_err.Success())
44724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
44824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            if (curr_bytes_read != curr_size)
44924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            {
45024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                if (DNBLogCheckLogBit(LOG_MEMORY))
45124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                    m_err.LogThreaded("::mach_vm_read ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt=>%i ) only read %u of %llu bytes", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read, curr_bytes_read, (uint64_t)curr_size);
45224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            }
45324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            ::memcpy (curr_data, (void *)vm_memory, curr_bytes_read);
45424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            ::vm_deallocate (mach_task_self (), vm_memory, curr_bytes_read);
45524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            total_bytes_read += curr_bytes_read;
45624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            curr_addr += curr_bytes_read;
45724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            curr_data += curr_bytes_read;
45824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
45924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        else
46024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
46124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            break;
46224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
46324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
46424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return total_bytes_read;
46524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
46624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
46724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
46824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnernub_size_t
46924943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerMachVMMemory::Write(task_t task, nub_addr_t address, const void *data, nub_size_t data_count)
47024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
47124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    MachVMRegion vmRegion(task);
47224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
47324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    nub_size_t total_bytes_written = 0;
47424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    nub_addr_t curr_addr = address;
47524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    const uint8_t *curr_data = (const uint8_t*)data;
47624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
47724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
47824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    while (total_bytes_written < data_count)
47924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
48024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (vmRegion.GetRegionForAddress(curr_addr))
48124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
48224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            mach_vm_size_t curr_data_count = data_count - total_bytes_written;
48324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            mach_vm_size_t region_bytes_left = vmRegion.BytesRemaining(curr_addr);
48424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            if (region_bytes_left == 0)
48524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            {
48624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                break;
48724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            }
48824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            if (curr_data_count > region_bytes_left)
48924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                curr_data_count = region_bytes_left;
49024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
49124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            if (vmRegion.SetProtections(curr_addr, curr_data_count, VM_PROT_READ | VM_PROT_WRITE))
49224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            {
49324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                nub_size_t bytes_written = WriteRegion(task, curr_addr, curr_data, curr_data_count);
49424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                if (bytes_written <= 0)
49524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                {
49624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                    // Error should have already be posted by WriteRegion...
49724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                    break;
49824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                }
49924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                else
50024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                {
50124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                    total_bytes_written += bytes_written;
50224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                    curr_addr += bytes_written;
50324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                    curr_data += bytes_written;
50424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                }
50524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            }
50624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            else
50724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            {
50824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS, "Failed to set read/write protections on region for address: [0x%8.8llx-0x%8.8llx)", (uint64_t)curr_addr, (uint64_t)(curr_addr + curr_data_count));
50924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                break;
51024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            }
51124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
51224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        else
51324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
51424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS, "Failed to get region for address: 0x%8.8llx", (uint64_t)address);
51524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            break;
51624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
51724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
51824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
51924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return total_bytes_written;
52024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
52124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
52224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
52324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnernub_size_t
52424943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerMachVMMemory::WriteRegion(task_t task, const nub_addr_t address, const void *data, const nub_size_t data_count)
52524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
52624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (data == NULL || data_count == 0)
52724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return 0;
52824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
52924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    nub_size_t total_bytes_written = 0;
53024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    nub_addr_t curr_addr = address;
53124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    const uint8_t *curr_data = (const uint8_t*)data;
53224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    while (total_bytes_written < data_count)
53324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
53424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        mach_msg_type_number_t curr_data_count = MaxBytesLeftInPage(curr_addr, data_count - total_bytes_written);
53524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        m_err = ::mach_vm_write (task, curr_addr, (pointer_t) curr_data, curr_data_count);
53624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail())
53724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            m_err.LogThreaded("::mach_vm_write ( task = 0x%4.4x, addr = 0x%8.8llx, data = %8.8p, dataCnt = %u )", task, (uint64_t)curr_addr, curr_data, curr_data_count);
53824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
53924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#if !defined (__i386__) && !defined (__x86_64__)
54024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        vm_machine_attribute_val_t mattr_value = MATTR_VAL_CACHE_FLUSH;
54124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
54224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        m_err = ::vm_machine_attribute (task, curr_addr, curr_data_count, MATTR_CACHE, &mattr_value);
54324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail())
54424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            m_err.LogThreaded("::vm_machine_attribute ( task = 0x%4.4x, addr = 0x%8.8llx, size = %u, attr = MATTR_CACHE, mattr_value => MATTR_VAL_CACHE_FLUSH )", task, (uint64_t)curr_addr, curr_data_count);
54524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#endif
54624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
54724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (m_err.Success())
54824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
54924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            total_bytes_written += curr_data_count;
55024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            curr_addr += curr_data_count;
55124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            curr_data += curr_data_count;
55224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
55324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        else
55424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
55524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            break;
55624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
55724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
55824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return total_bytes_written;
55924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
560