1*f6217f89SApple OSS Distributions /*
2*f6217f89SApple OSS Distributions * Copyright (c) 2003-2019 Apple Inc. All rights reserved.
3*f6217f89SApple OSS Distributions *
4*f6217f89SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*f6217f89SApple OSS Distributions *
6*f6217f89SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*f6217f89SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*f6217f89SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*f6217f89SApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*f6217f89SApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*f6217f89SApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*f6217f89SApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*f6217f89SApple OSS Distributions * terms of an Apple operating system software license agreement.
14*f6217f89SApple OSS Distributions *
15*f6217f89SApple OSS Distributions * Please obtain a copy of the License at
16*f6217f89SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*f6217f89SApple OSS Distributions *
18*f6217f89SApple OSS Distributions * The Original Code and all software distributed under the License are
19*f6217f89SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*f6217f89SApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*f6217f89SApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*f6217f89SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*f6217f89SApple OSS Distributions * Please see the License for the specific language governing rights and
24*f6217f89SApple OSS Distributions * limitations under the License.
25*f6217f89SApple OSS Distributions *
26*f6217f89SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*f6217f89SApple OSS Distributions */
28*f6217f89SApple OSS Distributions /*
29*f6217f89SApple OSS Distributions * Kernel stack management routines.
30*f6217f89SApple OSS Distributions */
31*f6217f89SApple OSS Distributions
32*f6217f89SApple OSS Distributions #include <mach/mach_host.h>
33*f6217f89SApple OSS Distributions #include <mach/mach_types.h>
34*f6217f89SApple OSS Distributions #include <mach/processor_set.h>
35*f6217f89SApple OSS Distributions
36*f6217f89SApple OSS Distributions #include <kern/kern_types.h>
37*f6217f89SApple OSS Distributions #include <kern/lock_group.h>
38*f6217f89SApple OSS Distributions #include <kern/mach_param.h>
39*f6217f89SApple OSS Distributions #include <kern/misc_protos.h>
40*f6217f89SApple OSS Distributions #include <kern/percpu.h>
41*f6217f89SApple OSS Distributions #include <kern/processor.h>
42*f6217f89SApple OSS Distributions #include <kern/thread.h>
43*f6217f89SApple OSS Distributions #include <kern/zalloc.h>
44*f6217f89SApple OSS Distributions #include <kern/kalloc.h>
45*f6217f89SApple OSS Distributions #include <kern/ledger.h>
46*f6217f89SApple OSS Distributions
47*f6217f89SApple OSS Distributions #include <vm/vm_map_xnu.h>
48*f6217f89SApple OSS Distributions #include <vm/vm_kern_xnu.h>
49*f6217f89SApple OSS Distributions
50*f6217f89SApple OSS Distributions #include <san/kasan.h>
51*f6217f89SApple OSS Distributions
52*f6217f89SApple OSS Distributions /*
53*f6217f89SApple OSS Distributions * We allocate stacks from generic kernel VM.
54*f6217f89SApple OSS Distributions *
55*f6217f89SApple OSS Distributions * The stack_free_list can only be accessed at splsched,
56*f6217f89SApple OSS Distributions * because stack_alloc_try/thread_invoke operate at splsched.
57*f6217f89SApple OSS Distributions */
58*f6217f89SApple OSS Distributions
59*f6217f89SApple OSS Distributions static SIMPLE_LOCK_DECLARE(stack_lock_data, 0);
60*f6217f89SApple OSS Distributions #define stack_lock() simple_lock(&stack_lock_data, LCK_GRP_NULL)
61*f6217f89SApple OSS Distributions #define stack_unlock() simple_unlock(&stack_lock_data)
62*f6217f89SApple OSS Distributions
63*f6217f89SApple OSS Distributions #define STACK_CACHE_SIZE 2
64*f6217f89SApple OSS Distributions
65*f6217f89SApple OSS Distributions static vm_offset_t stack_free_list;
66*f6217f89SApple OSS Distributions
67*f6217f89SApple OSS Distributions static unsigned int stack_free_count, stack_free_hiwat; /* free list count */
68*f6217f89SApple OSS Distributions static unsigned int stack_hiwat;
69*f6217f89SApple OSS Distributions unsigned int stack_total; /* current total count */
70*f6217f89SApple OSS Distributions unsigned long long stack_allocs; /* total count of allocations */
71*f6217f89SApple OSS Distributions
72*f6217f89SApple OSS Distributions static unsigned int stack_free_target;
73*f6217f89SApple OSS Distributions static int stack_free_delta;
74*f6217f89SApple OSS Distributions
75*f6217f89SApple OSS Distributions static unsigned int stack_new_count; /* total new stack allocations */
76*f6217f89SApple OSS Distributions
77*f6217f89SApple OSS Distributions static SECURITY_READ_ONLY_LATE(vm_offset_t) stack_addr_mask;
78*f6217f89SApple OSS Distributions SECURITY_READ_ONLY_LATE(vm_offset_t) kernel_stack_size;
79*f6217f89SApple OSS Distributions SECURITY_READ_ONLY_LATE(vm_offset_t) kernel_stack_mask;
80*f6217f89SApple OSS Distributions vm_offset_t kernel_stack_depth_max;
81*f6217f89SApple OSS Distributions
82*f6217f89SApple OSS Distributions struct stack_cache {
83*f6217f89SApple OSS Distributions vm_offset_t free;
84*f6217f89SApple OSS Distributions unsigned int count;
85*f6217f89SApple OSS Distributions };
86*f6217f89SApple OSS Distributions static struct stack_cache PERCPU_DATA(stack_cache);
87*f6217f89SApple OSS Distributions
88*f6217f89SApple OSS Distributions /*
89*f6217f89SApple OSS Distributions * The next field is at the base of the stack,
90*f6217f89SApple OSS Distributions * so the low end is left unsullied.
91*f6217f89SApple OSS Distributions */
92*f6217f89SApple OSS Distributions #define stack_next(stack) \
93*f6217f89SApple OSS Distributions (*((vm_offset_t *)((stack) + kernel_stack_size) - 1))
94*f6217f89SApple OSS Distributions
95*f6217f89SApple OSS Distributions static inline vm_offset_t
roundup_pow2(vm_offset_t size)96*f6217f89SApple OSS Distributions roundup_pow2(vm_offset_t size)
97*f6217f89SApple OSS Distributions {
98*f6217f89SApple OSS Distributions if ((size & (size - 1)) == 0) {
99*f6217f89SApple OSS Distributions /* if size is a power of 2 we're good */
100*f6217f89SApple OSS Distributions return size;
101*f6217f89SApple OSS Distributions }
102*f6217f89SApple OSS Distributions
103*f6217f89SApple OSS Distributions return 1ul << flsll(size);
104*f6217f89SApple OSS Distributions }
105*f6217f89SApple OSS Distributions
106*f6217f89SApple OSS Distributions static vm_offset_t stack_alloc_internal(void);
107*f6217f89SApple OSS Distributions static void stack_free_stack(vm_offset_t);
108*f6217f89SApple OSS Distributions
109*f6217f89SApple OSS Distributions static void
stack_init(void)110*f6217f89SApple OSS Distributions stack_init(void)
111*f6217f89SApple OSS Distributions {
112*f6217f89SApple OSS Distributions uint32_t kernel_stack_pages = atop(KERNEL_STACK_SIZE);
113*f6217f89SApple OSS Distributions
114*f6217f89SApple OSS Distributions kernel_stack_size = KERNEL_STACK_SIZE;
115*f6217f89SApple OSS Distributions kernel_stack_mask = -KERNEL_STACK_SIZE;
116*f6217f89SApple OSS Distributions
117*f6217f89SApple OSS Distributions if (PE_parse_boot_argn("kernel_stack_pages",
118*f6217f89SApple OSS Distributions &kernel_stack_pages,
119*f6217f89SApple OSS Distributions sizeof(kernel_stack_pages))) {
120*f6217f89SApple OSS Distributions kernel_stack_size = kernel_stack_pages * PAGE_SIZE;
121*f6217f89SApple OSS Distributions }
122*f6217f89SApple OSS Distributions
123*f6217f89SApple OSS Distributions if (kernel_stack_size < round_page(kernel_stack_size)) {
124*f6217f89SApple OSS Distributions panic("stack_init: stack size %p not a multiple of page size %d",
125*f6217f89SApple OSS Distributions (void *) kernel_stack_size, PAGE_SIZE);
126*f6217f89SApple OSS Distributions }
127*f6217f89SApple OSS Distributions
128*f6217f89SApple OSS Distributions stack_addr_mask = roundup_pow2(kernel_stack_size) - 1;
129*f6217f89SApple OSS Distributions kernel_stack_mask = ~stack_addr_mask;
130*f6217f89SApple OSS Distributions }
131*f6217f89SApple OSS Distributions STARTUP(TUNABLES, STARTUP_RANK_MIDDLE, stack_init);
132*f6217f89SApple OSS Distributions
133*f6217f89SApple OSS Distributions /*
134*f6217f89SApple OSS Distributions * stack_alloc:
135*f6217f89SApple OSS Distributions *
136*f6217f89SApple OSS Distributions * Allocate a stack for a thread, may
137*f6217f89SApple OSS Distributions * block.
138*f6217f89SApple OSS Distributions */
139*f6217f89SApple OSS Distributions
140*f6217f89SApple OSS Distributions static vm_offset_t
stack_alloc_internal(void)141*f6217f89SApple OSS Distributions stack_alloc_internal(void)
142*f6217f89SApple OSS Distributions {
143*f6217f89SApple OSS Distributions vm_offset_t stack = 0;
144*f6217f89SApple OSS Distributions spl_t s;
145*f6217f89SApple OSS Distributions kma_flags_t flags = KMA_NOFAIL | KMA_GUARD_FIRST | KMA_GUARD_LAST |
146*f6217f89SApple OSS Distributions KMA_KSTACK | KMA_KOBJECT | KMA_ZERO | KMA_SPRAYQTN;
147*f6217f89SApple OSS Distributions
148*f6217f89SApple OSS Distributions s = splsched();
149*f6217f89SApple OSS Distributions stack_lock();
150*f6217f89SApple OSS Distributions stack_allocs++;
151*f6217f89SApple OSS Distributions stack = stack_free_list;
152*f6217f89SApple OSS Distributions if (stack != 0) {
153*f6217f89SApple OSS Distributions stack_free_list = stack_next(stack);
154*f6217f89SApple OSS Distributions stack_free_count--;
155*f6217f89SApple OSS Distributions } else {
156*f6217f89SApple OSS Distributions if (++stack_total > stack_hiwat) {
157*f6217f89SApple OSS Distributions stack_hiwat = stack_total;
158*f6217f89SApple OSS Distributions }
159*f6217f89SApple OSS Distributions stack_new_count++;
160*f6217f89SApple OSS Distributions }
161*f6217f89SApple OSS Distributions stack_free_delta--;
162*f6217f89SApple OSS Distributions stack_unlock();
163*f6217f89SApple OSS Distributions splx(s);
164*f6217f89SApple OSS Distributions
165*f6217f89SApple OSS Distributions if (stack == 0) {
166*f6217f89SApple OSS Distributions /*
167*f6217f89SApple OSS Distributions * Request guard pages on either side of the stack. Ask
168*f6217f89SApple OSS Distributions * kernel_memory_allocate() for two extra pages to account
169*f6217f89SApple OSS Distributions * for these.
170*f6217f89SApple OSS Distributions */
171*f6217f89SApple OSS Distributions
172*f6217f89SApple OSS Distributions kernel_memory_allocate(kernel_map, &stack,
173*f6217f89SApple OSS Distributions kernel_stack_size + ptoa(2), stack_addr_mask,
174*f6217f89SApple OSS Distributions flags, VM_KERN_MEMORY_STACK);
175*f6217f89SApple OSS Distributions
176*f6217f89SApple OSS Distributions /*
177*f6217f89SApple OSS Distributions * The stack address that comes back is the address of the lower
178*f6217f89SApple OSS Distributions * guard page. Skip past it to get the actual stack base address.
179*f6217f89SApple OSS Distributions */
180*f6217f89SApple OSS Distributions
181*f6217f89SApple OSS Distributions stack += PAGE_SIZE;
182*f6217f89SApple OSS Distributions }
183*f6217f89SApple OSS Distributions return stack;
184*f6217f89SApple OSS Distributions }
185*f6217f89SApple OSS Distributions
186*f6217f89SApple OSS Distributions void
stack_alloc(thread_t thread)187*f6217f89SApple OSS Distributions stack_alloc(
188*f6217f89SApple OSS Distributions thread_t thread)
189*f6217f89SApple OSS Distributions {
190*f6217f89SApple OSS Distributions assert(thread->kernel_stack == 0);
191*f6217f89SApple OSS Distributions machine_stack_attach(thread, stack_alloc_internal());
192*f6217f89SApple OSS Distributions }
193*f6217f89SApple OSS Distributions
194*f6217f89SApple OSS Distributions void
stack_handoff(thread_t from,thread_t to)195*f6217f89SApple OSS Distributions stack_handoff(thread_t from, thread_t to)
196*f6217f89SApple OSS Distributions {
197*f6217f89SApple OSS Distributions assert(from == current_thread());
198*f6217f89SApple OSS Distributions machine_stack_handoff(from, to);
199*f6217f89SApple OSS Distributions }
200*f6217f89SApple OSS Distributions
201*f6217f89SApple OSS Distributions /*
202*f6217f89SApple OSS Distributions * stack_free:
203*f6217f89SApple OSS Distributions *
204*f6217f89SApple OSS Distributions * Detach and free the stack for a thread.
205*f6217f89SApple OSS Distributions */
206*f6217f89SApple OSS Distributions void
stack_free(thread_t thread)207*f6217f89SApple OSS Distributions stack_free(
208*f6217f89SApple OSS Distributions thread_t thread)
209*f6217f89SApple OSS Distributions {
210*f6217f89SApple OSS Distributions vm_offset_t stack = machine_stack_detach(thread);
211*f6217f89SApple OSS Distributions
212*f6217f89SApple OSS Distributions assert(stack);
213*f6217f89SApple OSS Distributions if (stack != thread->reserved_stack) {
214*f6217f89SApple OSS Distributions stack_free_stack(stack);
215*f6217f89SApple OSS Distributions }
216*f6217f89SApple OSS Distributions }
217*f6217f89SApple OSS Distributions
218*f6217f89SApple OSS Distributions void
stack_free_reserved(thread_t thread)219*f6217f89SApple OSS Distributions stack_free_reserved(
220*f6217f89SApple OSS Distributions thread_t thread)
221*f6217f89SApple OSS Distributions {
222*f6217f89SApple OSS Distributions if (thread->reserved_stack != thread->kernel_stack) {
223*f6217f89SApple OSS Distributions stack_free_stack(thread->reserved_stack);
224*f6217f89SApple OSS Distributions }
225*f6217f89SApple OSS Distributions }
226*f6217f89SApple OSS Distributions
227*f6217f89SApple OSS Distributions static void
stack_free_stack(vm_offset_t stack)228*f6217f89SApple OSS Distributions stack_free_stack(
229*f6217f89SApple OSS Distributions vm_offset_t stack)
230*f6217f89SApple OSS Distributions {
231*f6217f89SApple OSS Distributions struct stack_cache *cache;
232*f6217f89SApple OSS Distributions spl_t s;
233*f6217f89SApple OSS Distributions
234*f6217f89SApple OSS Distributions #if KASAN_DEBUG
235*f6217f89SApple OSS Distributions /* Sanity check - stack should be unpoisoned by now */
236*f6217f89SApple OSS Distributions assert(kasan_check_shadow(stack, kernel_stack_size, 0));
237*f6217f89SApple OSS Distributions #endif
238*f6217f89SApple OSS Distributions
239*f6217f89SApple OSS Distributions s = splsched();
240*f6217f89SApple OSS Distributions cache = PERCPU_GET(stack_cache);
241*f6217f89SApple OSS Distributions if (cache->count < STACK_CACHE_SIZE) {
242*f6217f89SApple OSS Distributions stack_next(stack) = cache->free;
243*f6217f89SApple OSS Distributions cache->free = stack;
244*f6217f89SApple OSS Distributions cache->count++;
245*f6217f89SApple OSS Distributions } else {
246*f6217f89SApple OSS Distributions stack_lock();
247*f6217f89SApple OSS Distributions stack_next(stack) = stack_free_list;
248*f6217f89SApple OSS Distributions stack_free_list = stack;
249*f6217f89SApple OSS Distributions if (++stack_free_count > stack_free_hiwat) {
250*f6217f89SApple OSS Distributions stack_free_hiwat = stack_free_count;
251*f6217f89SApple OSS Distributions }
252*f6217f89SApple OSS Distributions stack_free_delta++;
253*f6217f89SApple OSS Distributions stack_unlock();
254*f6217f89SApple OSS Distributions }
255*f6217f89SApple OSS Distributions splx(s);
256*f6217f89SApple OSS Distributions }
257*f6217f89SApple OSS Distributions
258*f6217f89SApple OSS Distributions /*
259*f6217f89SApple OSS Distributions * stack_alloc_try:
260*f6217f89SApple OSS Distributions *
261*f6217f89SApple OSS Distributions * Non-blocking attempt to allocate a
262*f6217f89SApple OSS Distributions * stack for a thread.
263*f6217f89SApple OSS Distributions *
264*f6217f89SApple OSS Distributions * Returns TRUE on success.
265*f6217f89SApple OSS Distributions *
266*f6217f89SApple OSS Distributions * Called at splsched.
267*f6217f89SApple OSS Distributions */
268*f6217f89SApple OSS Distributions boolean_t
stack_alloc_try(thread_t thread)269*f6217f89SApple OSS Distributions stack_alloc_try(
270*f6217f89SApple OSS Distributions thread_t thread)
271*f6217f89SApple OSS Distributions {
272*f6217f89SApple OSS Distributions struct stack_cache *cache;
273*f6217f89SApple OSS Distributions vm_offset_t stack;
274*f6217f89SApple OSS Distributions
275*f6217f89SApple OSS Distributions cache = PERCPU_GET(stack_cache);
276*f6217f89SApple OSS Distributions stack = cache->free;
277*f6217f89SApple OSS Distributions if (stack != 0) {
278*f6217f89SApple OSS Distributions cache->free = stack_next(stack);
279*f6217f89SApple OSS Distributions cache->count--;
280*f6217f89SApple OSS Distributions } else {
281*f6217f89SApple OSS Distributions if (stack_free_list != 0) {
282*f6217f89SApple OSS Distributions stack_lock();
283*f6217f89SApple OSS Distributions stack = stack_free_list;
284*f6217f89SApple OSS Distributions if (stack != 0) {
285*f6217f89SApple OSS Distributions stack_free_list = stack_next(stack);
286*f6217f89SApple OSS Distributions stack_free_count--;
287*f6217f89SApple OSS Distributions stack_free_delta--;
288*f6217f89SApple OSS Distributions }
289*f6217f89SApple OSS Distributions stack_unlock();
290*f6217f89SApple OSS Distributions }
291*f6217f89SApple OSS Distributions }
292*f6217f89SApple OSS Distributions
293*f6217f89SApple OSS Distributions if (stack != 0 || (stack = thread->reserved_stack) != 0) {
294*f6217f89SApple OSS Distributions machine_stack_attach(thread, stack);
295*f6217f89SApple OSS Distributions return TRUE;
296*f6217f89SApple OSS Distributions }
297*f6217f89SApple OSS Distributions
298*f6217f89SApple OSS Distributions return FALSE;
299*f6217f89SApple OSS Distributions }
300*f6217f89SApple OSS Distributions
301*f6217f89SApple OSS Distributions static unsigned int stack_collect_tick, last_stack_tick;
302*f6217f89SApple OSS Distributions
303*f6217f89SApple OSS Distributions /*
304*f6217f89SApple OSS Distributions * stack_collect:
305*f6217f89SApple OSS Distributions *
306*f6217f89SApple OSS Distributions * Free excess kernel stacks, may
307*f6217f89SApple OSS Distributions * block.
308*f6217f89SApple OSS Distributions */
309*f6217f89SApple OSS Distributions void
stack_collect(void)310*f6217f89SApple OSS Distributions stack_collect(void)
311*f6217f89SApple OSS Distributions {
312*f6217f89SApple OSS Distributions if (stack_collect_tick != last_stack_tick) {
313*f6217f89SApple OSS Distributions unsigned int target;
314*f6217f89SApple OSS Distributions vm_offset_t stack;
315*f6217f89SApple OSS Distributions spl_t s;
316*f6217f89SApple OSS Distributions
317*f6217f89SApple OSS Distributions s = splsched();
318*f6217f89SApple OSS Distributions stack_lock();
319*f6217f89SApple OSS Distributions
320*f6217f89SApple OSS Distributions target = stack_free_target + (STACK_CACHE_SIZE * processor_count);
321*f6217f89SApple OSS Distributions target += (stack_free_delta >= 0)? stack_free_delta: -stack_free_delta;
322*f6217f89SApple OSS Distributions
323*f6217f89SApple OSS Distributions while (stack_free_count > target) {
324*f6217f89SApple OSS Distributions stack = stack_free_list;
325*f6217f89SApple OSS Distributions stack_free_list = stack_next(stack);
326*f6217f89SApple OSS Distributions stack_free_count--; stack_total--;
327*f6217f89SApple OSS Distributions stack_unlock();
328*f6217f89SApple OSS Distributions splx(s);
329*f6217f89SApple OSS Distributions
330*f6217f89SApple OSS Distributions /*
331*f6217f89SApple OSS Distributions * Get the stack base address, then decrement by one page
332*f6217f89SApple OSS Distributions * to account for the lower guard page. Add two extra pages
333*f6217f89SApple OSS Distributions * to the size to account for the guard pages on both ends
334*f6217f89SApple OSS Distributions * that were originally requested when the stack was allocated
335*f6217f89SApple OSS Distributions * back in stack_alloc().
336*f6217f89SApple OSS Distributions */
337*f6217f89SApple OSS Distributions
338*f6217f89SApple OSS Distributions stack = (vm_offset_t)vm_map_trunc_page(
339*f6217f89SApple OSS Distributions stack,
340*f6217f89SApple OSS Distributions VM_MAP_PAGE_MASK(kernel_map));
341*f6217f89SApple OSS Distributions stack -= PAGE_SIZE;
342*f6217f89SApple OSS Distributions kmem_free(kernel_map, stack, kernel_stack_size + ptoa(2),
343*f6217f89SApple OSS Distributions KMF_GUARD_FIRST | KMF_GUARD_LAST);
344*f6217f89SApple OSS Distributions stack = 0;
345*f6217f89SApple OSS Distributions
346*f6217f89SApple OSS Distributions s = splsched();
347*f6217f89SApple OSS Distributions stack_lock();
348*f6217f89SApple OSS Distributions
349*f6217f89SApple OSS Distributions target = stack_free_target + (STACK_CACHE_SIZE * processor_count);
350*f6217f89SApple OSS Distributions target += (stack_free_delta >= 0)? stack_free_delta: -stack_free_delta;
351*f6217f89SApple OSS Distributions }
352*f6217f89SApple OSS Distributions
353*f6217f89SApple OSS Distributions last_stack_tick = stack_collect_tick;
354*f6217f89SApple OSS Distributions
355*f6217f89SApple OSS Distributions stack_unlock();
356*f6217f89SApple OSS Distributions splx(s);
357*f6217f89SApple OSS Distributions }
358*f6217f89SApple OSS Distributions }
359*f6217f89SApple OSS Distributions
360*f6217f89SApple OSS Distributions /*
361*f6217f89SApple OSS Distributions * compute_stack_target:
362*f6217f89SApple OSS Distributions *
363*f6217f89SApple OSS Distributions * Computes a new target free list count
364*f6217f89SApple OSS Distributions * based on recent alloc / free activity.
365*f6217f89SApple OSS Distributions *
366*f6217f89SApple OSS Distributions * Limits stack collection to once per
367*f6217f89SApple OSS Distributions * computation period.
368*f6217f89SApple OSS Distributions */
369*f6217f89SApple OSS Distributions void
compute_stack_target(__unused void * arg)370*f6217f89SApple OSS Distributions compute_stack_target(
371*f6217f89SApple OSS Distributions __unused void *arg)
372*f6217f89SApple OSS Distributions {
373*f6217f89SApple OSS Distributions spl_t s;
374*f6217f89SApple OSS Distributions
375*f6217f89SApple OSS Distributions s = splsched();
376*f6217f89SApple OSS Distributions stack_lock();
377*f6217f89SApple OSS Distributions
378*f6217f89SApple OSS Distributions if (stack_free_target > 5) {
379*f6217f89SApple OSS Distributions stack_free_target = (4 * stack_free_target) / 5;
380*f6217f89SApple OSS Distributions } else if (stack_free_target > 0) {
381*f6217f89SApple OSS Distributions stack_free_target--;
382*f6217f89SApple OSS Distributions }
383*f6217f89SApple OSS Distributions
384*f6217f89SApple OSS Distributions stack_free_target += (stack_free_delta >= 0)? stack_free_delta: -stack_free_delta;
385*f6217f89SApple OSS Distributions
386*f6217f89SApple OSS Distributions stack_free_delta = 0;
387*f6217f89SApple OSS Distributions stack_collect_tick++;
388*f6217f89SApple OSS Distributions
389*f6217f89SApple OSS Distributions stack_unlock();
390*f6217f89SApple OSS Distributions splx(s);
391*f6217f89SApple OSS Distributions }
392*f6217f89SApple OSS Distributions
393*f6217f89SApple OSS Distributions /* OBSOLETE */
394*f6217f89SApple OSS Distributions void stack_privilege(
395*f6217f89SApple OSS Distributions thread_t thread);
396*f6217f89SApple OSS Distributions
397*f6217f89SApple OSS Distributions void
stack_privilege(__unused thread_t thread)398*f6217f89SApple OSS Distributions stack_privilege(
399*f6217f89SApple OSS Distributions __unused thread_t thread)
400*f6217f89SApple OSS Distributions {
401*f6217f89SApple OSS Distributions /* OBSOLETE */
402*f6217f89SApple OSS Distributions }
403*f6217f89SApple OSS Distributions
404*f6217f89SApple OSS Distributions /*
405*f6217f89SApple OSS Distributions * Return info on stack usage for threads in a specific processor set
406*f6217f89SApple OSS Distributions */
407*f6217f89SApple OSS Distributions kern_return_t
processor_set_stack_usage(processor_set_t pset,unsigned int * totalp,vm_size_t * spacep,vm_size_t * residentp,vm_size_t * maxusagep,vm_offset_t * maxstackp)408*f6217f89SApple OSS Distributions processor_set_stack_usage(
409*f6217f89SApple OSS Distributions processor_set_t pset,
410*f6217f89SApple OSS Distributions unsigned int *totalp,
411*f6217f89SApple OSS Distributions vm_size_t *spacep,
412*f6217f89SApple OSS Distributions vm_size_t *residentp,
413*f6217f89SApple OSS Distributions vm_size_t *maxusagep,
414*f6217f89SApple OSS Distributions vm_offset_t *maxstackp)
415*f6217f89SApple OSS Distributions {
416*f6217f89SApple OSS Distributions #if DEVELOPMENT || DEBUG
417*f6217f89SApple OSS Distributions unsigned int total = 0;
418*f6217f89SApple OSS Distributions thread_t thread;
419*f6217f89SApple OSS Distributions
420*f6217f89SApple OSS Distributions if (pset == PROCESSOR_SET_NULL || pset != &pset0) {
421*f6217f89SApple OSS Distributions return KERN_INVALID_ARGUMENT;
422*f6217f89SApple OSS Distributions }
423*f6217f89SApple OSS Distributions
424*f6217f89SApple OSS Distributions lck_mtx_lock(&tasks_threads_lock);
425*f6217f89SApple OSS Distributions
426*f6217f89SApple OSS Distributions queue_iterate(&threads, thread, thread_t, threads) {
427*f6217f89SApple OSS Distributions total += (thread->kernel_stack != 0);
428*f6217f89SApple OSS Distributions }
429*f6217f89SApple OSS Distributions
430*f6217f89SApple OSS Distributions lck_mtx_unlock(&tasks_threads_lock);
431*f6217f89SApple OSS Distributions
432*f6217f89SApple OSS Distributions *totalp = total;
433*f6217f89SApple OSS Distributions *residentp = *spacep = total * round_page(kernel_stack_size);
434*f6217f89SApple OSS Distributions *maxusagep = 0;
435*f6217f89SApple OSS Distributions *maxstackp = 0;
436*f6217f89SApple OSS Distributions return KERN_SUCCESS;
437*f6217f89SApple OSS Distributions
438*f6217f89SApple OSS Distributions #else
439*f6217f89SApple OSS Distributions #pragma unused(pset, totalp, spacep, residentp, maxusagep, maxstackp)
440*f6217f89SApple OSS Distributions return KERN_NOT_SUPPORTED;
441*f6217f89SApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
442*f6217f89SApple OSS Distributions }
443*f6217f89SApple OSS Distributions
444*f6217f89SApple OSS Distributions __mockable vm_offset_t
min_valid_stack_address(void)445*f6217f89SApple OSS Distributions min_valid_stack_address(void)
446*f6217f89SApple OSS Distributions {
447*f6217f89SApple OSS Distributions return (vm_offset_t)vm_map_min(kernel_map);
448*f6217f89SApple OSS Distributions }
449*f6217f89SApple OSS Distributions
450*f6217f89SApple OSS Distributions __mockable vm_offset_t
max_valid_stack_address(void)451*f6217f89SApple OSS Distributions max_valid_stack_address(void)
452*f6217f89SApple OSS Distributions {
453*f6217f89SApple OSS Distributions return (vm_offset_t)vm_map_max(kernel_map);
454*f6217f89SApple OSS Distributions }
455