arm64: Move pcb out of kstack into a new UMA zone

This is similar to commit 5e921ff49e
which moved the pcb for amd64, but a bit different.  arm64's pcb is
much larger (over 1KB!) than amd64's since it still embeds FP
registers.  Moving the pcb out of the kstack frees up that much
additional kstack space.  Unlike amd64 however, embedding the pcb in
struct mdthread is not practical as the resulting struct thread would
grow such that UMA would now store 1 thread per 4k page instead of 2
threads per page.  By using a separate UMA zone for pcbs, 2 struct
threads can continue to fit in a single 4k page, and 3 pcbs can fit in
another 4k page.

Reviewed by:	kib, jrtc27, andrew
Sponsored by:	AFRL, DARPA
Pull Request:	https://ron-dev.freebsd.org/FreeBSD/src/pulls/23
This commit is contained in:
John Baldwin
2026-03-25 15:18:05 +00:00
parent dcae0f7d7a
commit d0b10df718
5 changed files with 19 additions and 13 deletions
-2
View File
@@ -53,8 +53,6 @@ ASSYM(PC_CURPCB, offsetof(struct pcpu, pc_curpcb));
ASSYM(PC_CURTHREAD, offsetof(struct pcpu, pc_curthread));
ASSYM(PC_SSBD, offsetof(struct pcpu, pc_ssbd));
/* Size of pcb, rounded to keep stack alignment */
ASSYM(PCB_SIZE, roundup2(sizeof(struct pcb), STACKALIGNBYTES + 1));
ASSYM(PCB_SINGLE_STEP_SHIFT, PCB_SINGLE_STEP_SHIFT);
ASSYM(PCB_REGS, offsetof(struct pcb, pcb_x));
ASSYM(PCB_X19, PCB_X19);
+1 -2
View File
@@ -128,8 +128,7 @@ virtdone:
/* Set up the stack */
adrp x25, initstack_end
add x25, x25, :lo12:initstack_end
sub sp, x25, #PCB_SIZE
add sp, x25, :lo12:initstack_end
/* Zero the BSS */
ldr x15, .Lbss
+2 -1
View File
@@ -131,6 +131,7 @@ uintptr_t boot_canary = 0x49a2d892bc05a0b1ul;
#endif
static struct trapframe proc0_tf;
static struct pcb pcb0;
int early_boot = 1;
int cold = 1;
@@ -443,7 +444,7 @@ init_proc0(void *kstack)
#if defined(PERTHREAD_SSP)
thread0.td_md.md_canary = boot_canary;
#endif
thread0.td_pcb = (struct pcb *)td_kstack_top(&thread0) - 1;
thread0.td_pcb = &pcb0;
thread0.td_pcb->pcb_flags = 0;
thread0.td_pcb->pcb_fpflags = 0;
thread0.td_pcb->pcb_fpusaved = &thread0.td_pcb->pcb_fpustate;
+14 -4
View File
@@ -27,8 +27,8 @@
#include "opt_platform.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/proc.h>
#include <sys/sf_buf.h>
@@ -61,6 +61,8 @@
*/
cpu_reset_hook_t cpu_reset_hook = psci_reset;
static uma_zone_t pcb_zone;
/*
* Finish a fork operation, with process p2 nearly set up.
* Copy and update the pcb, set up the stack so that the child
@@ -260,20 +262,20 @@ cpu_thread_exit(struct thread *td)
void
cpu_thread_alloc(struct thread *td)
{
td->td_pcb = uma_zalloc(pcb_zone, M_WAITOK);
ptrauth_thread_alloc(td);
}
void
cpu_thread_new_kstack(struct thread *td)
{
td->td_pcb = (struct pcb *)td_kstack_top(td) - 1;
td->td_frame = (struct trapframe *)STACKALIGN(
(struct trapframe *)td->td_pcb - 1);
td->td_frame = (struct trapframe *)td_kstack_top(td) - 1;
}
void
cpu_thread_free(struct thread *td)
{
uma_zfree(pcb_zone, td->td_pcb);
}
void
@@ -333,3 +335,11 @@ cpu_sync_core(void)
* return from ELx is a context synchronization event.
*/
}
static void
pcbinit(void *dummy __unused)
{
pcb_zone = uma_zcreate("pcb", sizeof(struct pcb), NULL, NULL, NULL,
NULL, UMA_ALIGNOF(struct pcb), 0);
}
SYSINIT(pcbinit, SI_SUB_INTRINSIC, SI_ORDER_ANY, pcbinit, NULL);
+2 -4
View File
@@ -39,11 +39,9 @@ bool unwind_frame(struct thread *, struct unwind_state *);
#ifdef _SYS_PROC_H_
#include <machine/pcb.h>
#define GET_STACK_USAGE(total, used) do { \
struct thread *td = curthread; \
(total) = ptoa(td->td_kstack_pages) - sizeof(struct pcb); \
(total) = ptoa(td->td_kstack_pages); \
(used) = td->td_kstack + (total) - (char *)&td; \
} while (0)
@@ -51,7 +49,7 @@ static __inline bool
kstack_contains(struct thread *td, vm_offset_t va, size_t len)
{
return (va >= (vm_offset_t)td->td_kstack && va + len >= va &&
va + len <= (vm_offset_t)td_kstack_top(td) - sizeof(struct pcb));
va + len <= (vm_offset_t)td_kstack_top(td));
}
#endif /* _SYS_PROC_H_ */