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