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>
2077d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong#include <dlfcn.h>
2124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
2224943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerMachVMMemory::MachVMMemory() :
2324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    m_page_size    (kInvalidPageSize),
2424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    m_err        (0)
2524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
2624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
2724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
2824943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerMachVMMemory::~MachVMMemory()
2924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
3024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
3124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
3224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnernub_size_t
33fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason MolendaMachVMMemory::PageSize(task_t task)
3424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
3524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (m_page_size == kInvalidPageSize)
3624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
37fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22
38fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda        if (task != TASK_NULL)
39fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda        {
40fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda            kern_return_t kr;
41fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda            mach_msg_type_number_t info_count = TASK_VM_INFO_COUNT;
42fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda            task_vm_info_data_t vm_info;
43fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda            kr = task_info (task, TASK_VM_INFO, (task_info_t) &vm_info, &info_count);
44fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda            if (kr == KERN_SUCCESS)
45fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda            {
46dfb7c7f12cbefccf5f097ec90f6d157e2a32f35dJason Molenda                DNBLogThreadedIf(LOG_TASK, "MachVMMemory::PageSize task_info returned page size of 0x%x", (int) vm_info.page_size);
47e255a7d13780e35b97e0f2954cba47cc9eaae7e0Jason Molenda                m_page_size = vm_info.page_size;
48e255a7d13780e35b97e0f2954cba47cc9eaae7e0Jason Molenda                return m_page_size;
49fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda            }
5092748483a4c36e9bf2535abb863dbca1271053a1Jason Molenda            else
5192748483a4c36e9bf2535abb863dbca1271053a1Jason Molenda            {
5292748483a4c36e9bf2535abb863dbca1271053a1Jason Molenda                DNBLogThreadedIf(LOG_TASK, "MachVMMemory::PageSize task_info call failed to get page size, TASK_VM_INFO %d, TASK_VM_INFO_COUNT %d, kern return %d", TASK_VM_INFO, TASK_VM_INFO_COUNT, kr);
5392748483a4c36e9bf2535abb863dbca1271053a1Jason Molenda            }
54fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda        }
55fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda#endif
5624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        m_err = ::host_page_size( ::mach_host_self(), &m_page_size);
5724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (m_err.Fail())
5824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            m_page_size = 0;
5924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
6024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return m_page_size;
6124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
6224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
6324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnernub_size_t
64fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason MolendaMachVMMemory::MaxBytesLeftInPage(task_t task, nub_addr_t addr, nub_size_t count)
6524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
66fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda    const nub_size_t page_size = PageSize(task);
6724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (page_size > 0)
6824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
6924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        nub_size_t page_offset = (addr % page_size);
7024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        nub_size_t bytes_left_in_page = page_size - page_offset;
7124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (count > bytes_left_in_page)
7224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            count = bytes_left_in_page;
7324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
7424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return count;
7524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
7624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
771308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Claytonnub_bool_t
78a9385537809ef342c843c5ab972e513742652047Greg ClaytonMachVMMemory::GetMemoryRegionInfo(task_t task, nub_addr_t address, DNBRegionInfo *region_info)
79dc8ff30b6dbe28c851e99712e20c1358eca4709dJason Molenda{
80dc8ff30b6dbe28c851e99712e20c1358eca4709dJason Molenda    MachVMRegion vmRegion(task);
81dc8ff30b6dbe28c851e99712e20c1358eca4709dJason Molenda
82a9385537809ef342c843c5ab972e513742652047Greg Clayton    if (vmRegion.GetRegionForAddress(address))
83a9385537809ef342c843c5ab972e513742652047Greg Clayton    {
84a9385537809ef342c843c5ab972e513742652047Greg Clayton        region_info->addr = vmRegion.StartAddress();
85a9385537809ef342c843c5ab972e513742652047Greg Clayton        region_info->size = vmRegion.GetByteSize();
86a9385537809ef342c843c5ab972e513742652047Greg Clayton        region_info->permissions = vmRegion.GetDNBPermissions();
87a9385537809ef342c843c5ab972e513742652047Greg Clayton    }
881308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton    else
891308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton    {
901308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        region_info->addr = address;
911308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        region_info->size = 0;
921308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        if (vmRegion.GetError().Success())
931308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        {
941308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            // vmRegion.GetRegionForAddress() return false, indicating that "address"
951308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            // wasn't in a valid region, but the "vmRegion" info was successfully
961308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            // read from the task which means the info describes the next valid
971308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            // region from which we can infer the size of this invalid region
981308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            mach_vm_address_t start_addr = vmRegion.StartAddress();
991308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            if (address < start_addr)
1001308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton                region_info->size = start_addr - address;
1011308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        }
1021308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        // If we can't get any infor about the size from the next region, just fill
1031308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        // 1 in as the byte size
1041308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        if (region_info->size == 0)
1051308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton            region_info->size = 1;
1061308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton
1071308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        // Not readable, writeable or executable
1081308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton        region_info->permissions = 0;
1091308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton    }
1101308a9555ad586ff03c8f97bcfe7f3212d06bc86Greg Clayton    return true;
111dc8ff30b6dbe28c851e99712e20c1358eca4709dJason Molenda}
112fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
113e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong// For integrated graphics chip, this makes the accounting info for 'wired' memory more like top.
114fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molendauint64_t
115fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason MolendaMachVMMemory::GetStolenPages(task_t task)
116e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong{
117e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    static uint64_t stolenPages = 0;
118e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    static bool calculated = false;
119e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    if (calculated) return stolenPages;
120e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
121e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	static int mib_reserved[CTL_MAXNAME];
122e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	static int mib_unusable[CTL_MAXNAME];
123e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	static int mib_other[CTL_MAXNAME];
124e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	static size_t mib_reserved_len = 0;
125e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	static size_t mib_unusable_len = 0;
126e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	static size_t mib_other_len = 0;
127e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	int r;
128e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
129e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	/* This can be used for testing: */
130e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	//tsamp->pages_stolen = (256 * 1024 * 1024ULL) / tsamp->pagesize;
131e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
132e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	if(0 == mib_reserved_len)
133e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    {
134e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		mib_reserved_len = CTL_MAXNAME;
135e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
136e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		r = sysctlnametomib("machdep.memmap.Reserved", mib_reserved,
137e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                            &mib_reserved_len);
138e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
139e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(-1 == r)
140e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
141e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			mib_reserved_len = 0;
142e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			return 0;
143e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
144e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
145e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		mib_unusable_len = CTL_MAXNAME;
146e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
147e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		r = sysctlnametomib("machdep.memmap.Unusable", mib_unusable,
148e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                            &mib_unusable_len);
149e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
150e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(-1 == r)
151e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
152e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			mib_reserved_len = 0;
153e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			return 0;
154e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
155e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
156e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
157e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		mib_other_len = CTL_MAXNAME;
158e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
159e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		r = sysctlnametomib("machdep.memmap.Other", mib_other,
160e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                            &mib_other_len);
161e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
162e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(-1 == r)
163e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
164e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			mib_reserved_len = 0;
165e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			return 0;
166e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
167e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	}
168e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
169e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	if(mib_reserved_len > 0 && mib_unusable_len > 0 && mib_other_len > 0)
170e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    {
171e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		uint64_t reserved = 0, unusable = 0, other = 0;
172e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		size_t reserved_len;
173e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		size_t unusable_len;
174e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		size_t other_len;
175e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
176e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		reserved_len = sizeof(reserved);
177e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		unusable_len = sizeof(unusable);
178e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		other_len = sizeof(other);
179e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
180e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		/* These are all declared as QUAD/uint64_t sysctls in the kernel. */
181e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
182e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(-1 == sysctl(mib_reserved, mib_reserved_len, &reserved,
183e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                        &reserved_len, NULL, 0))
184e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
185e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			return 0;
186e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
187e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
188e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(-1 == sysctl(mib_unusable, mib_unusable_len, &unusable,
189e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                        &unusable_len, NULL, 0))
190e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
191e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			return 0;
192e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
193e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
194e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(-1 == sysctl(mib_other, mib_other_len, &other,
195e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                        &other_len, NULL, 0))
196e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
197e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			return 0;
198e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
199e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
200e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		if(reserved_len == sizeof(reserved)
201e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		   && unusable_len == sizeof(unusable)
202e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		   && other_len == sizeof(other))
203e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong        {
204e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			uint64_t stolen = reserved + unusable + other;
205e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			uint64_t mb128 = 128 * 1024 * 1024ULL;
206e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
207e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			if(stolen >= mb128)
208e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong            {
209e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong                stolen = (stolen & ~((128 * 1024 * 1024ULL) - 1)); // rounding down
21008f60c88b61c42c35abf3233f0cbe19d29fbe814Jason Molenda                stolenPages = stolen / PageSize (task);
211e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong			}
212e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong		}
213e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong	}
214e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
215e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    calculated = true;
216e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    return stolenPages;
217e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong}
218e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
219e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ongstatic uint64_t GetPhysicalMemory()
220e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong{
221e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    // This doesn't change often at all. No need to poll each time.
222e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    static uint64_t physical_memory = 0;
223e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    static bool calculated = false;
224e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    if (calculated) return physical_memory;
225e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
226e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    int mib[2];
227e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    mib[0] = CTL_HW;
228e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    mib[1] = HW_MEMSIZE;
229e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    size_t len = sizeof(physical_memory);
230e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    sysctl(mib, 2, &physical_memory, &len, NULL, 0);
231e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong    return physical_memory;
232e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong}
233e45c499d61f372cc93abdacf3dbfa9466c412066Han Ming Ong
234fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han 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.
235fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molendavoid
236fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason MolendaMachVMMemory::GetRegionSizes(task_t task, mach_vm_size_t &rsize, mach_vm_size_t &dirty_size)
237fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong{
238fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22
239fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong
240fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong    task_vm_info_data_t vm_info;
241fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong    mach_msg_type_number_t info_count;
242fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong    kern_return_t kr;
243fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong
244fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong    info_count = TASK_VM_INFO_COUNT;
245fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong#ifdef TASK_VM_INFO_PURGEABLE
246fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong    kr = task_info(task, TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &info_count);
247fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong#else
248fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong    kr = task_info(task, TASK_VM_INFO, (task_info_t)&vm_info, &info_count);
249fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong#endif
250fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong    if (kr == KERN_SUCCESS)
251fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong        dirty_size = vm_info.internal;
252fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong
253fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong#else
254fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    mach_vm_address_t address = 0;
255fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    mach_vm_size_t size;
256fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    kern_return_t err = 0;
257fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    unsigned nestingDepth = 0;
258fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    mach_vm_size_t pages_resident = 0;
259fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    mach_vm_size_t pages_dirtied = 0;
260fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
261fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    while (1)
262fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    {
2632a647e4b0eb044cffab5c8c29b6af9ed52129544Han Ming Ong        mach_msg_type_number_t count;
264fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        struct vm_region_submap_info_64 info;
265fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
266fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        count = VM_REGION_SUBMAP_INFO_COUNT_64;
267fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        err = mach_vm_region_recurse(task, &address, &size, &nestingDepth, (vm_region_info_t)&info, &count);
268fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        if (err == KERN_INVALID_ADDRESS)
269fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
270fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            // It seems like this is a good break too.
271fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            break;
272fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        }
273fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        else if (err)
274fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
275fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            mach_error("vm_region",err);
276fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            break; // reached last region
277fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        }
278fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
279fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        bool should_count = true;
280fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        if (info.is_submap)
281fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        { // is it a submap?
282fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            nestingDepth++;
283fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            should_count = false;
284fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        }
285fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        else
286fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
287fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            // Don't count malloc stack logging data in the TOTAL VM usage lines.
288fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            if (info.user_tag == VM_MEMORY_ANALYSIS_TOOL)
289fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                should_count = false;
290190276872994426fb0398e1cf521748249b75875Han Ming Ong
291fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            address = address+size;
292fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        }
293fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
294fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        if (should_count)
295fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
296fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            pages_resident += info.pages_resident;
297fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            pages_dirtied += info.pages_dirtied;
298fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        }
299fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    }
300fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
30177d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    vm_size_t pagesize = PageSize (task);
3022a647e4b0eb044cffab5c8c29b6af9ed52129544Han Ming Ong    rsize = pages_resident * pagesize;
3032a647e4b0eb044cffab5c8c29b6af9ed52129544Han Ming Ong    dirty_size = pages_dirtied * pagesize;
304fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong
305fa72100a0ac0267163cacde1af4ef43822dc390aHan Ming Ong#endif
306fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong}
307fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
308fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong// Test whether the virtual address is within the architecture's shared region.
309fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ongstatic bool InSharedRegion(mach_vm_address_t addr, cpu_type_t type)
310fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong{
311559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    mach_vm_address_t base = 0, size = 0;
312fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
313559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    switch(type) {
314559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        case CPU_TYPE_ARM:
315559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            base = SHARED_REGION_BASE_ARM;
316559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            size = SHARED_REGION_SIZE_ARM;
317fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            break;
318fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
319559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        case CPU_TYPE_X86_64:
320559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            base = SHARED_REGION_BASE_X86_64;
321559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            size = SHARED_REGION_SIZE_X86_64;
322fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            break;
323fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
324559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        case CPU_TYPE_I386:
325559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            base = SHARED_REGION_BASE_I386;
326559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            size = SHARED_REGION_SIZE_I386;
327fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            break;
328fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
329559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        default: {
330fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            // Log error abut unknown CPU type
331fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            break;
332559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        }
333559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    }
334fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
335fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
336559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    return(addr >= base && addr < (base + size));
337fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong}
338fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
339fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molendavoid
340fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason MolendaMachVMMemory::GetMemorySizes(task_t task, cpu_type_t cputype, nub_process_t pid, mach_vm_size_t &rprvt, mach_vm_size_t &vprvt)
341fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong{
342fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    // Collecting some other info cheaply but not reporting for now.
343fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    mach_vm_size_t empty = 0;
344559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    mach_vm_size_t fw_private = 0;
345fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
346559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    mach_vm_size_t aliased = 0;
347fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    bool global_shared_text_data_mapped = false;
34877d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    vm_size_t pagesize = PageSize (task);
3492a647e4b0eb044cffab5c8c29b6af9ed52129544Han Ming Ong
350559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    for (mach_vm_address_t addr=0, size=0; ; addr += size)
351fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    {
352559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        vm_region_top_info_data_t info;
353559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        mach_msg_type_number_t count = VM_REGION_TOP_INFO_COUNT;
354559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        mach_port_t object_name;
355fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
356559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        kern_return_t kr = mach_vm_region(task, &addr, &size, VM_REGION_TOP_INFO, (vm_region_info_t)&info, &count, &object_name);
357559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        if (kr != KERN_SUCCESS) break;
358559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda
359559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        if (InSharedRegion(addr, cputype))
360fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
361559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            // Private Shared
362559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            fw_private += info.private_pages_resident * pagesize;
363fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
364559cf6e8b52b940f5f4362b32d628838d6301e2eJason 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.
365559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            if (global_shared_text_data_mapped == FALSE && info.share_mode == SM_EMPTY) {
3662a647e4b0eb044cffab5c8c29b6af9ed52129544Han Ming Ong                vm_region_basic_info_data_64_t b_info;
367559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                mach_vm_address_t b_addr = addr;
368559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                mach_vm_size_t b_size = size;
369559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                count = VM_REGION_BASIC_INFO_COUNT_64;
370559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda
371559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                kr = mach_vm_region(task, &b_addr, &b_size, VM_REGION_BASIC_INFO, (vm_region_info_t)&b_info, &count, &object_name);
372559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                if (kr != KERN_SUCCESS) break;
373fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
374559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                if (b_info.reserved) {
375559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    global_shared_text_data_mapped = TRUE;
376559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                }
377559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            }
378559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda
379559cf6e8b52b940f5f4362b32d628838d6301e2eJason 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.
380559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            if (info.share_mode != SM_PRIVATE)
381fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            {
382559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                continue;
383559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            }
384559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        }
385559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda
386559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        // Update counters according to the region type.
387559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        if (info.share_mode == SM_COW && info.ref_count == 1)
388fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
389559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            // Treat single reference SM_COW as SM_PRIVATE
390559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            info.share_mode = SM_PRIVATE;
391559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        }
392fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
393559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        switch (info.share_mode)
394fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong        {
395559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            case SM_LARGE_PAGE:
396559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                // Treat SM_LARGE_PAGE the same as SM_PRIVATE
397559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                // since they are not shareable and are wired.
398559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            case SM_PRIVATE:
399559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                rprvt += info.private_pages_resident * pagesize;
400559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                rprvt += info.shared_pages_resident * pagesize;
401559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                vprvt += size;
402559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                break;
403559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda
404559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            case SM_EMPTY:
405fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                empty += size;
406559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                break;
407559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda
408559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            case SM_COW:
409559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            case SM_SHARED:
410fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            {
411559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                if (pid == 0)
412fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                {
413559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    // Treat kernel_task specially
414559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    if (info.share_mode == SM_COW)
415fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                    {
416559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                        rprvt += info.private_pages_resident * pagesize;
417559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                        vprvt += size;
418559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    }
419559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    break;
420559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                }
421fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
422559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                if (info.share_mode == SM_COW)
423fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                {
424559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    rprvt += info.private_pages_resident * pagesize;
425559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                    vprvt += info.private_pages_resident * pagesize;
426559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                }
427559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                break;
428fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong            }
429559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda            default:
430fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong                // log that something is really bad.
431559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda                break;
432559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda        }
433559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    }
434fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
435559cf6e8b52b940f5f4362b32d628838d6301e2eJason Molenda    rprvt += aliased;
436fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong}
437fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
43877d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22
439813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong#ifndef TASK_VM_INFO_PURGEABLE
44077d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong// cribbed from sysmond
44177d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ongstatic uint64_t
44277d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming OngSumVMPurgeableInfo(const vm_purgeable_info_t info)
44377d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong{
44477d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    uint64_t sum = 0;
44577d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    int i;
44677d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong
44777d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    for (i = 0; i < 8; i++)
44877d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    {
44977d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        sum += info->fifo_data[i].size;
45077d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    }
45177d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    sum += info->obsolete_data.size;
45277d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    for (i = 0; i < 8; i++)
45377d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    {
45477d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        sum += info->lifo_data[i].size;
45577d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    }
45677d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong
45777d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    return sum;
45877d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong}
459813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong#endif /* !TASK_VM_INFO_PURGEABLE */
46077d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong#endif
46177d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong
46277d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ongstatic void
46377d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming OngGetPurgeableAndAnonymous(task_t task, uint64_t &purgeable, uint64_t &anonymous)
46477d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong{
46577d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22
46677d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong
46777d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    kern_return_t kr;
468813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong#ifndef TASK_VM_INFO_PURGEABLE
46977d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    task_purgable_info_t purgeable_info;
47077d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    uint64_t purgeable_sum = 0;
471813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong#endif /* !TASK_VM_INFO_PURGEABLE */
47277d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    mach_msg_type_number_t info_count;
47377d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    task_vm_info_data_t vm_info;
47477d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong
475813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong#ifndef TASK_VM_INFO_PURGEABLE
4763a54da4467c036cf6b8ed4afe5cdd9dd7409c2d5Han Ming Ong    typedef kern_return_t (*task_purgable_info_type) (task_t, task_purgable_info_t *);
4773a54da4467c036cf6b8ed4afe5cdd9dd7409c2d5Han Ming Ong    task_purgable_info_type task_purgable_info_ptr = NULL;
4783a54da4467c036cf6b8ed4afe5cdd9dd7409c2d5Han Ming Ong    task_purgable_info_ptr = (task_purgable_info_type)dlsym(RTLD_NEXT, "task_purgable_info");
4793a54da4467c036cf6b8ed4afe5cdd9dd7409c2d5Han Ming Ong    if (task_purgable_info_ptr != NULL)
48077d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    {
4813a54da4467c036cf6b8ed4afe5cdd9dd7409c2d5Han Ming Ong        kr = (*task_purgable_info_ptr)(task, &purgeable_info);
48277d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        if (kr == KERN_SUCCESS) {
48377d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong            purgeable_sum = SumVMPurgeableInfo(&purgeable_info);
48477d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong            purgeable = purgeable_sum;
48577d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        }
48677d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    }
487813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong#endif /* !TASK_VM_INFO_PURGEABLE */
48877d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong
48977d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    info_count = TASK_VM_INFO_COUNT;
490813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong#ifdef TASK_VM_INFO_PURGEABLE
491813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong    kr = task_info(task, TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &info_count);
492813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong#else
49377d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    kr = task_info(task, TASK_VM_INFO, (task_info_t)&vm_info, &info_count);
494813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong#endif
49577d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    if (kr == KERN_SUCCESS)
49677d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    {
497813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong#ifdef TASK_VM_INFO_PURGEABLE
498813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong        purgeable = vm_info.purgeable_volatile_resident;
499813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong        anonymous = vm_info.internal - vm_info.purgeable_volatile_pmap;
500813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong#else
50177d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        if (purgeable_sum < vm_info.internal)
50277d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        {
50377d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong            anonymous = vm_info.internal - purgeable_sum;
50477d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        }
50577d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        else
50677d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        {
50777d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong            anonymous = 0;
50877d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        }
509813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong#endif
51077d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong    }
511813bec3072bc145dc9d80c5ef04daf8406b91ac0Han Ming Ong
51277d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong#endif
51377d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong}
51477d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong
515fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ongnub_bool_t
51677d340f114b99ec8e2f7a48cbb674c93e237022bHan 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, mach_vm_size_t &purgeable, mach_vm_size_t &anonymous)
517fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong{
518cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong    if (scanType & eProfileHostMemory)
519cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        physical_memory = GetPhysicalMemory();
520cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong
521cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong    if (scanType & eProfileMemory)
522cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong    {
523cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        static mach_port_t localHost = mach_host_self();
524cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
525cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        host_statistics(localHost, HOST_VM_INFO, (host_info_t)&vm_stats, &count);
526fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda        vm_stats.wire_count += GetStolenPages(task);
527fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
528cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        GetMemorySizes(task, cputype, pid, rprvt, vprvt);
529fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
530cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        rsize = ti.resident_size;
531cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong        vsize = ti.virtual_size;
532a53a76965eb603afe5705c694ee8e3344f91cc61Han Ming Ong
533a53a76965eb603afe5705c694ee8e3344f91cc61Han Ming Ong        if (scanType & eProfileMemoryDirtyPage)
534a53a76965eb603afe5705c694ee8e3344f91cc61Han Ming Ong        {
535a53a76965eb603afe5705c694ee8e3344f91cc61Han 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.
536a53a76965eb603afe5705c694ee8e3344f91cc61Han Ming Ong            GetRegionSizes(task, rsize, dirty_size);
537a53a76965eb603afe5705c694ee8e3344f91cc61Han Ming Ong        }
53877d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong
53977d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        if (scanType & eProfileMemoryAnonymous)
54077d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        {
54177d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong            GetPurgeableAndAnonymous(task, purgeable, anonymous);
54277d340f114b99ec8e2f7a48cbb674c93e237022bHan Ming Ong        }
543cec43ab7f30085ac7f65a26a58b956a69e363a3bHan Ming Ong    }
544fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong
545fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong    return true;
546fb9cee64303d36d6fe5d87e63dd8701d1ddb70a9Han Ming Ong}
547dc8ff30b6dbe28c851e99712e20c1358eca4709dJason Molenda
54824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnernub_size_t
54924943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerMachVMMemory::Read(task_t task, nub_addr_t address, void *data, nub_size_t data_count)
55024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
55124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (data == NULL || data_count == 0)
55224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return 0;
55324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
55424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    nub_size_t total_bytes_read = 0;
55524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    nub_addr_t curr_addr = address;
55624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    uint8_t *curr_data = (uint8_t*)data;
55724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    while (total_bytes_read < data_count)
55824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
559fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda        mach_vm_size_t curr_size = MaxBytesLeftInPage(task, curr_addr, data_count - total_bytes_read);
56024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        mach_msg_type_number_t curr_bytes_read = 0;
56124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        vm_offset_t vm_memory = NULL;
56224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        m_err = ::mach_vm_read (task, curr_addr, curr_size, &vm_memory, &curr_bytes_read);
563d906b1b24a6c838d78039b399ee43dc57598ab52Jim Ingham
56455f768792c75eb5f9474edb09ca416c8737eeac0Jim Ingham        if (DNBLogCheckLogBit(LOG_MEMORY))
56524943d2ee8bfaa7cf5893e4709143924157a5c1eChris 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);
56624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
56724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (m_err.Success())
56824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
56924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            if (curr_bytes_read != curr_size)
57024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            {
57124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                if (DNBLogCheckLogBit(LOG_MEMORY))
57224943d2ee8bfaa7cf5893e4709143924157a5c1eChris 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);
57324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            }
57424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            ::memcpy (curr_data, (void *)vm_memory, curr_bytes_read);
57524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            ::vm_deallocate (mach_task_self (), vm_memory, curr_bytes_read);
57624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            total_bytes_read += curr_bytes_read;
57724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            curr_addr += curr_bytes_read;
57824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            curr_data += curr_bytes_read;
57924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
58024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        else
58124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
58224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            break;
58324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
58424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
58524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return total_bytes_read;
58624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
58724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
58824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
58924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnernub_size_t
59024943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerMachVMMemory::Write(task_t task, nub_addr_t address, const void *data, nub_size_t data_count)
59124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
59224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    MachVMRegion vmRegion(task);
59324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
59424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    nub_size_t total_bytes_written = 0;
59524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    nub_addr_t curr_addr = address;
59624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    const uint8_t *curr_data = (const uint8_t*)data;
59724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
59824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
59924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    while (total_bytes_written < data_count)
60024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
60124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (vmRegion.GetRegionForAddress(curr_addr))
60224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
60324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            mach_vm_size_t curr_data_count = data_count - total_bytes_written;
60424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            mach_vm_size_t region_bytes_left = vmRegion.BytesRemaining(curr_addr);
60524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            if (region_bytes_left == 0)
60624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            {
60724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                break;
60824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            }
60924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            if (curr_data_count > region_bytes_left)
61024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                curr_data_count = region_bytes_left;
61124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
61224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            if (vmRegion.SetProtections(curr_addr, curr_data_count, VM_PROT_READ | VM_PROT_WRITE))
61324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            {
61424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                nub_size_t bytes_written = WriteRegion(task, curr_addr, curr_data, curr_data_count);
61524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                if (bytes_written <= 0)
61624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                {
61724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                    // Error should have already be posted by WriteRegion...
61824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                    break;
61924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                }
62024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                else
62124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                {
62224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                    total_bytes_written += bytes_written;
62324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                    curr_addr += bytes_written;
62424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                    curr_data += bytes_written;
62524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                }
62624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            }
62724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            else
62824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            {
62924943d2ee8bfaa7cf5893e4709143924157a5c1eChris 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));
63024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                break;
63124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            }
63224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
63324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        else
63424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
63524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS, "Failed to get region for address: 0x%8.8llx", (uint64_t)address);
63624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            break;
63724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
63824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
63924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
64024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return total_bytes_written;
64124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
64224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
64324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
64424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnernub_size_t
64524943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerMachVMMemory::WriteRegion(task_t task, const nub_addr_t address, const void *data, const nub_size_t data_count)
64624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
64724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (data == NULL || data_count == 0)
64824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        return 0;
64924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
65024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    nub_size_t total_bytes_written = 0;
65124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    nub_addr_t curr_addr = address;
65224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    const uint8_t *curr_data = (const uint8_t*)data;
65324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    while (total_bytes_written < data_count)
65424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    {
655fb190f3e1ddbaf9fb72e15a96e103de2b9c0dc44Jason Molenda        mach_msg_type_number_t curr_data_count = MaxBytesLeftInPage(task, curr_addr, data_count - total_bytes_written);
65624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        m_err = ::mach_vm_write (task, curr_addr, (pointer_t) curr_data, curr_data_count);
65724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail())
65824943d2ee8bfaa7cf5893e4709143924157a5c1eChris 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);
65924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
66024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#if !defined (__i386__) && !defined (__x86_64__)
66124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        vm_machine_attribute_val_t mattr_value = MATTR_VAL_CACHE_FLUSH;
66224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
66324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        m_err = ::vm_machine_attribute (task, curr_addr, curr_data_count, MATTR_CACHE, &mattr_value);
66424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail())
66524943d2ee8bfaa7cf5893e4709143924157a5c1eChris 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);
66624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#endif
66724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
66824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        if (m_err.Success())
66924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
67024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            total_bytes_written += curr_data_count;
67124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            curr_addr += curr_data_count;
67224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            curr_data += curr_data_count;
67324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
67424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        else
67524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        {
67624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            break;
67724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        }
67824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
67924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return total_bytes_written;
68024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
681