1*043036a2SApple OSS Distributions /*
2*043036a2SApple OSS Distributions * Copyright (c) 2024 Apple Inc. All rights reserved.
3*043036a2SApple OSS Distributions *
4*043036a2SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*043036a2SApple OSS Distributions *
6*043036a2SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*043036a2SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*043036a2SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*043036a2SApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*043036a2SApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*043036a2SApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*043036a2SApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*043036a2SApple OSS Distributions * terms of an Apple operating system software license agreement.
14*043036a2SApple OSS Distributions *
15*043036a2SApple OSS Distributions * Please obtain a copy of the License at
16*043036a2SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*043036a2SApple OSS Distributions *
18*043036a2SApple OSS Distributions * The Original Code and all software distributed under the License are
19*043036a2SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*043036a2SApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*043036a2SApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*043036a2SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*043036a2SApple OSS Distributions * Please see the License for the specific language governing rights and
24*043036a2SApple OSS Distributions * limitations under the License.
25*043036a2SApple OSS Distributions *
26*043036a2SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*043036a2SApple OSS Distributions *
28*043036a2SApple OSS Distributions */
29*043036a2SApple OSS Distributions
30*043036a2SApple OSS Distributions #include <sys/proc.h>
31*043036a2SApple OSS Distributions #include <sys/sysctl.h>
32*043036a2SApple OSS Distributions #include <sys/kern_memorystatus.h>
33*043036a2SApple OSS Distributions #include <mach-o/dyld.h>
34*043036a2SApple OSS Distributions #include <mach/mach_vm.h>
35*043036a2SApple OSS Distributions #include <mach/vm_page_size.h>
36*043036a2SApple OSS Distributions #include <mach/shared_region.h>
37*043036a2SApple OSS Distributions #include <mach/mach.h>
38*043036a2SApple OSS Distributions #include <os/reason_private.h>
39*043036a2SApple OSS Distributions #include <TargetConditionals.h>
40*043036a2SApple OSS Distributions #include <darwintest.h>
41*043036a2SApple OSS Distributions #include <darwintest_utils.h>
42*043036a2SApple OSS Distributions
43*043036a2SApple OSS Distributions T_GLOBAL_META(
44*043036a2SApple OSS Distributions T_META_NAMESPACE("xnu.memorystatus"),
45*043036a2SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
46*043036a2SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("VM"),
47*043036a2SApple OSS Distributions T_META_ASROOT(true),
48*043036a2SApple OSS Distributions T_META_TAG_VM_PREFERRED
49*043036a2SApple OSS Distributions );
50*043036a2SApple OSS Distributions
51*043036a2SApple OSS Distributions #define SIZE_ESTIMATE_EXTRA_ENTRIES 5
52*043036a2SApple OSS Distributions #define MAX_TRIES 3
53*043036a2SApple OSS Distributions
54*043036a2SApple OSS Distributions #define _STR(x) #x
55*043036a2SApple OSS Distributions #define STR(x) _STR(x)
56*043036a2SApple OSS Distributions
57*043036a2SApple OSS Distributions memorystatus_priority_entry_v2_t*
get_priority_list(pid_t pid,int call,size_t entry_size,ssize_t * len)58*043036a2SApple OSS Distributions get_priority_list(pid_t pid, int call, size_t entry_size, ssize_t* len)
59*043036a2SApple OSS Distributions {
60*043036a2SApple OSS Distributions int i;
61*043036a2SApple OSS Distributions ssize_t size;
62*043036a2SApple OSS Distributions memorystatus_priority_entry_v2_t *list = NULL;
63*043036a2SApple OSS Distributions
64*043036a2SApple OSS Distributions for (i = 0; i < MAX_TRIES; i++) {
65*043036a2SApple OSS Distributions T_LOG("Attempt %d", i + 1);
66*043036a2SApple OSS Distributions
67*043036a2SApple OSS Distributions size = memorystatus_control(call, pid, 0, NULL, 0);
68*043036a2SApple OSS Distributions
69*043036a2SApple OSS Distributions T_ASSERT_GT(size, 0l, "Priority list query size > 0");
70*043036a2SApple OSS Distributions T_ASSERT_EQ(size % entry_size, 0ul, "Priority list size is multiple of struct size");
71*043036a2SApple OSS Distributions
72*043036a2SApple OSS Distributions if (size <= 0) {
73*043036a2SApple OSS Distributions return NULL;
74*043036a2SApple OSS Distributions }
75*043036a2SApple OSS Distributions
76*043036a2SApple OSS Distributions /* pad out the size just in case the list gets bigger */
77*043036a2SApple OSS Distributions if (pid == 0) {
78*043036a2SApple OSS Distributions size += SIZE_ESTIMATE_EXTRA_ENTRIES * entry_size;
79*043036a2SApple OSS Distributions }
80*043036a2SApple OSS Distributions
81*043036a2SApple OSS Distributions list = malloc(size);
82*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(list, "malloc");
83*043036a2SApple OSS Distributions
84*043036a2SApple OSS Distributions *len = memorystatus_control(call, pid, 0, list, size);
85*043036a2SApple OSS Distributions
86*043036a2SApple OSS Distributions if (*len <= 0) {
87*043036a2SApple OSS Distributions T_LOG("Failed, maybe the list grew? Trying again...");
88*043036a2SApple OSS Distributions free(list);
89*043036a2SApple OSS Distributions continue;
90*043036a2SApple OSS Distributions }
91*043036a2SApple OSS Distributions
92*043036a2SApple OSS Distributions T_ASSERT_GE(size, *len, "List fits in buffer");
93*043036a2SApple OSS Distributions T_ASSERT_GT(size, 0l, "List size nonzero");
94*043036a2SApple OSS Distributions return list;
95*043036a2SApple OSS Distributions }
96*043036a2SApple OSS Distributions
97*043036a2SApple OSS Distributions T_FAIL("Tried more than MAX_TRIES=" STR(MAX_TRIES) " times");
98*043036a2SApple OSS Distributions return NULL;
99*043036a2SApple OSS Distributions }
100*043036a2SApple OSS Distributions
101*043036a2SApple OSS Distributions void
validate_entry(memorystatus_priority_entry_v2_t * entry,size_t entry_size,pid_t expect_pid)102*043036a2SApple OSS Distributions validate_entry(memorystatus_priority_entry_v2_t *entry, size_t entry_size, pid_t expect_pid)
103*043036a2SApple OSS Distributions {
104*043036a2SApple OSS Distributions int i;
105*043036a2SApple OSS Distributions if (expect_pid == -1) {
106*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_GE(entry->pid, 0, "PID valid");
107*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_NE(entry->pid, 0, "kernel_task not in list");
108*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_NE(entry->pid, 1, "launchd not in list");
109*043036a2SApple OSS Distributions } else {
110*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(entry->pid, expect_pid, "PID correct");
111*043036a2SApple OSS Distributions }
112*043036a2SApple OSS Distributions
113*043036a2SApple OSS Distributions if (entry->pid > 1) {
114*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_GE(
115*043036a2SApple OSS Distributions entry->priority,
116*043036a2SApple OSS Distributions 0,
117*043036a2SApple OSS Distributions "Entry priority >= 0");
118*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_LE(
119*043036a2SApple OSS Distributions entry->priority,
120*043036a2SApple OSS Distributions JETSAM_PRIORITY_MAX,
121*043036a2SApple OSS Distributions "Entry priority <= JETSAM_PRIORITY_MAX (" STR(JETSAM_PRIORITY_MAX) ")");
122*043036a2SApple OSS Distributions } else {
123*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(
124*043036a2SApple OSS Distributions entry->priority,
125*043036a2SApple OSS Distributions JETSAM_PRIORITY_INTERNAL,
126*043036a2SApple OSS Distributions "Entry priority == JETSAM_PRIORITY_INTERNAL (" STR(JETSAM_PRIORITY_INTERNAL) ")");
127*043036a2SApple OSS Distributions }
128*043036a2SApple OSS Distributions
129*043036a2SApple OSS Distributions if (entry_size == sizeof(memorystatus_priority_entry_v2_t)) {
130*043036a2SApple OSS Distributions boolean_t found_nonzero = false;
131*043036a2SApple OSS Distributions for (i = 0; i < sizeof(entry->_reserved) / sizeof(entry->_reserved[0]); i++) {
132*043036a2SApple OSS Distributions if (entry->_reserved[i]) {
133*043036a2SApple OSS Distributions found_nonzero = true;
134*043036a2SApple OSS Distributions break;
135*043036a2SApple OSS Distributions }
136*043036a2SApple OSS Distributions }
137*043036a2SApple OSS Distributions T_QUIET; T_ASSERT_FALSE(found_nonzero, "Entry reserved is empty");
138*043036a2SApple OSS Distributions }
139*043036a2SApple OSS Distributions }
140*043036a2SApple OSS Distributions
141*043036a2SApple OSS Distributions T_DECL(jetsam_priority_list_v2_list, "Jetsam priority list v2 - list")
142*043036a2SApple OSS Distributions {
143*043036a2SApple OSS Distributions int i;
144*043036a2SApple OSS Distributions ssize_t len;
145*043036a2SApple OSS Distributions memorystatus_priority_entry_v2_t *list = get_priority_list(
146*043036a2SApple OSS Distributions 0,
147*043036a2SApple OSS Distributions MEMORYSTATUS_CMD_GET_PRIORITY_LIST_V2,
148*043036a2SApple OSS Distributions sizeof(*list),
149*043036a2SApple OSS Distributions &len);
150*043036a2SApple OSS Distributions
151*043036a2SApple OSS Distributions T_ASSERT_NOTNULL(list, "Priority list not null");
152*043036a2SApple OSS Distributions for (i = 0; i < len / sizeof(memorystatus_priority_entry_v2_t); i++) {
153*043036a2SApple OSS Distributions validate_entry(&list[i], sizeof(*list), -1);
154*043036a2SApple OSS Distributions }
155*043036a2SApple OSS Distributions free(list);
156*043036a2SApple OSS Distributions T_PASS("Entries valid");
157*043036a2SApple OSS Distributions }
158*043036a2SApple OSS Distributions
159*043036a2SApple OSS Distributions void
validate_single(pid_t pid)160*043036a2SApple OSS Distributions validate_single(pid_t pid)
161*043036a2SApple OSS Distributions {
162*043036a2SApple OSS Distributions ssize_t len;
163*043036a2SApple OSS Distributions memorystatus_priority_entry_v2_t *list = get_priority_list(
164*043036a2SApple OSS Distributions pid,
165*043036a2SApple OSS Distributions MEMORYSTATUS_CMD_GET_PRIORITY_LIST_V2,
166*043036a2SApple OSS Distributions sizeof(*list),
167*043036a2SApple OSS Distributions &len);
168*043036a2SApple OSS Distributions
169*043036a2SApple OSS Distributions T_ASSERT_NOTNULL(list, "Getting self priority entry");
170*043036a2SApple OSS Distributions T_ASSERT_EQ(len, sizeof(memorystatus_priority_entry_v2_t), "Single entry returned");
171*043036a2SApple OSS Distributions validate_entry(list, sizeof(*list), pid);
172*043036a2SApple OSS Distributions free(list);
173*043036a2SApple OSS Distributions }
174*043036a2SApple OSS Distributions
175*043036a2SApple OSS Distributions T_DECL(jetsam_priority_list_v2_single, "Jetsam priority list v2 - single")
176*043036a2SApple OSS Distributions {
177*043036a2SApple OSS Distributions T_LOG("Getting entry for self...");
178*043036a2SApple OSS Distributions validate_single(getpid());
179*043036a2SApple OSS Distributions
180*043036a2SApple OSS Distributions T_LOG("Getting entry for launchd...");
181*043036a2SApple OSS Distributions validate_single(1);
182*043036a2SApple OSS Distributions
183*043036a2SApple OSS Distributions T_PASS("Entries valid");
184*043036a2SApple OSS Distributions }
185*043036a2SApple OSS Distributions
186*043036a2SApple OSS Distributions T_DECL(jetsam_priority_list_compat, "Jetsam priority list - v1 compat")
187*043036a2SApple OSS Distributions {
188*043036a2SApple OSS Distributions int i;
189*043036a2SApple OSS Distributions ssize_t len;
190*043036a2SApple OSS Distributions
191*043036a2SApple OSS Distributions memorystatus_priority_entry_t *list = (memorystatus_priority_entry_t*) get_priority_list(
192*043036a2SApple OSS Distributions 0,
193*043036a2SApple OSS Distributions MEMORYSTATUS_CMD_GET_PRIORITY_LIST,
194*043036a2SApple OSS Distributions sizeof(*list),
195*043036a2SApple OSS Distributions &len);
196*043036a2SApple OSS Distributions
197*043036a2SApple OSS Distributions T_ASSERT_NOTNULL(list, "Priority list not null");
198*043036a2SApple OSS Distributions
199*043036a2SApple OSS Distributions for (i = 0; i < len / sizeof(memorystatus_priority_entry_v2_t); i++) {
200*043036a2SApple OSS Distributions validate_entry((memorystatus_priority_entry_v2_t*) (&list[i]), sizeof(*list), -1);
201*043036a2SApple OSS Distributions }
202*043036a2SApple OSS Distributions
203*043036a2SApple OSS Distributions free(list);
204*043036a2SApple OSS Distributions T_PASS("Entries valid");
205*043036a2SApple OSS Distributions }
206