From nobody Mon Dec 15 17:00:19 2025 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4dVRBr36bsz6L1gZ for ; Mon, 15 Dec 2025 17:00:20 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4dVRBr05xRz3pl1 for ; Mon, 15 Dec 2025 17:00:20 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1765818020; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Jxnn/g6LYpOou6MY3BG03SuEomEKU03JKGPR2WUh4zQ=; b=Vxdz2Gh7CMtaV28GyL7ukdZxqpqvSAAc/5JRjX6qVD2fjJ8gO0/mrENVfxNAm46ZtmUH6r lcjoijNx5uej5LtofAaK+SzeuW6oeA0dE+Pz27EQmWU6x2HEe1Qrfk4w9gtfaiT1VfgOq0 f3zGGekKejT8Uf0bAB6bj3GOCX22SDZBuNdVOAzuc+qICifXhJxcxr4B+hW/gh0rJUgN9M PETKtKqrk8USvfKES/ShFYLGXOXGqVM+22lSuaMK/1Ig9eUaNBAT2xzog4f3zvMFb7BZQ3 bE0PJJV+QsL/i1jLFFCDtYQH30BmaxvdCy8jz21Fn26tU8JYx6djTJ/l93YUxg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1765818020; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Jxnn/g6LYpOou6MY3BG03SuEomEKU03JKGPR2WUh4zQ=; b=yY+qN3wUnJBnL+B1UcwWgGulgioi964+O5oNFTRNrhO64pekH3L1lPCdHUILeYkg3hQvjL xFhZoB91dYUNMj6Obsr/ZDtsb6HsFdbvBRzcWcgOYMdUd3C4g818wNUgx0htjcOU82QvdX R6+QHeh+syoUmJKRoz2rE9G2N3Vo/UWa2pG/kU+OAzsgzn2cej4xkTsMtGUKvC7rU55fYc cY/EfPXhU0TSkRvg1D2/SAbkOTozocgkwIo3wk17QbWVY8U7bh/Rielh45+PBBpqR/+Dpr aqJVavs+rQqFNTGHgNU2s92lwxohJksxJNQlcXcvhnIfwlmrO3/RezC3ls9Zzg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1765818020; a=rsa-sha256; cv=none; b=sKfR2YpIsypmEVGVLCqvGSunb4iDZuuQovWi2du/rbdKvOZR39/KytChGYi8hnqbPXlEiI bQ5u/9Fusn6bLc5BR23dWuC2uYLWmB90t2Tt9LE84Z8PRK/7ctKSDiOb3s/J82XgBX6dKg PHGWfLb5A+ihElQhOTjHhL2RuLlyvlS9qln9cJGxTnmerVUp0lMJNtZn9Bj1iDQkKEzYDF 2JG6J5sStYGR9QVffEK5yfTUroWnm7F5p6EggFxga/yh5wpIGTng+QSMyzH+FYHh6lFNrK RTHzzY9r1C9xn1LizzjRHbNgm9VDIylawzeZ3MJGtuD5EW3JYM9O7SBmhKm5lg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4dVRBq6m4VzCYd for ; Mon, 15 Dec 2025 17:00:19 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id d36f by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 15 Dec 2025 17:00:19 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Jessica Clarke Subject: git: a5ccd406ddc5 - stable/14 - riscv: Fix and generalise saving TP (PCPU pointer) whilst in userspace List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: jrtc27 X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: a5ccd406ddc5b73060e154495745651646f1dcf5 Auto-Submitted: auto-generated Date: Mon, 15 Dec 2025 17:00:19 +0000 Message-Id: <69403ea3.d36f.1253e05f@gitrepo.freebsd.org> The branch stable/14 has been updated by jrtc27: URL: https://cgit.FreeBSD.org/src/commit/?id=a5ccd406ddc5b73060e154495745651646f1dcf5 commit a5ccd406ddc5b73060e154495745651646f1dcf5 Author: Jessica Clarke AuthorDate: 2025-02-04 17:28:42 +0000 Commit: Jessica Clarke CommitDate: 2025-12-15 16:58:44 +0000 riscv: Fix and generalise saving TP (PCPU pointer) whilst in userspace In cpu_fork, we allocate sizeof(struct pcb) + sizeof(struct trapframe) space on the stack, then round it for stack alignment. This not only fails to include the space needed for TP but also doesn't round up the trapframe allocation to be stack-aligned, yet TF_SIZE does, as is the expectation of fork_trampoline and cpu_exception_handler. Given that sizeof(struct pcb) + sizeof(struct trapframe) is a multiple of 16, this causes the saved TP to be stored in the PCB's pcb_sp (the intended trapframe padding aliasing pcb_ra), which is probably harmless in practice as the PCB isn't expected to be current, but definitely not intended. In cpu_thread_alloc, we do include the 8 bytes for TP and then stack align that. This again fails to include the padding for trapframe as present in TF_SIZE, but sizeof(struct pcb) + sizeof(struct trapframe) happens to be a multiple of 16, as above, so adding 8 then rounding to stack alignment (16) includes an extra 8 bytes of padding, giving the right result for the wrong reason (and could be broken by future struct growth). Extract the calculation into a shared function that rounds correctly regardless of the struct layouts. Also introduce a new struct kernframe to encapsulate and clearly document this shared state rather than using magic constants, and also enable it to be easily extended in future, as we intend to do downstream in CheriBSD. Reviewed by: jhb MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D48799 (cherry picked from commit 21c534b9f5d5de07137f9a42e016876dd6ae66c1) --- sys/riscv/include/frame.h | 14 ++++++++++++++ sys/riscv/riscv/exception.S | 4 ++-- sys/riscv/riscv/genassym.c | 4 +++- sys/riscv/riscv/swtch.S | 2 +- sys/riscv/riscv/vm_machdep.c | 35 ++++++++++++++++++++++++----------- 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/sys/riscv/include/frame.h b/sys/riscv/include/frame.h index f134842d1c45..c70a3a48ee0a 100644 --- a/sys/riscv/include/frame.h +++ b/sys/riscv/include/frame.h @@ -57,6 +57,10 @@ struct trapframe { uint64_t tf_scause; }; +#ifdef _KERNEL +#define TF_SIZE (roundup2(sizeof(struct trapframe), STACKALIGNBYTES + 1)) +#endif + /* * Signal frame. Pushed onto user stack before calling sigcode. */ @@ -65,6 +69,16 @@ struct sigframe { ucontext_t sf_uc; /* actual saved ucontext */ }; +#ifdef _KERNEL +/* + * Kernel frame. Reserved near the top of kernel stacks for saving kernel + * state while in userspace. + */ +struct kernframe { + register_t kf_tp; +}; +#endif + #endif /* !LOCORE */ /* Definitions for syscalls */ diff --git a/sys/riscv/riscv/exception.S b/sys/riscv/riscv/exception.S index 8acb5cd691d4..eb8d92b55d05 100644 --- a/sys/riscv/riscv/exception.S +++ b/sys/riscv/riscv/exception.S @@ -53,7 +53,7 @@ .option pop /* Load our pcpu */ - ld tp, (TF_SIZE)(sp) + ld tp, (TF_SIZE + KF_TP)(sp) .endif sd t0, (TF_T + 0 * 8)(sp) @@ -139,7 +139,7 @@ csrw sscratch, t0 /* Store our pcpu */ - sd tp, (TF_SIZE)(sp) + sd tp, (TF_SIZE + KF_TP)(sp) ld tp, (TF_TP)(sp) /* And restore the user's global pointer */ diff --git a/sys/riscv/riscv/genassym.c b/sys/riscv/riscv/genassym.c index 67714346cc75..2b2c558fa181 100644 --- a/sys/riscv/riscv/genassym.c +++ b/sys/riscv/riscv/genassym.c @@ -85,7 +85,7 @@ ASSYM(TD_FRAME, offsetof(struct thread, td_frame)); ASSYM(TD_MD, offsetof(struct thread, td_md)); ASSYM(TD_LOCK, offsetof(struct thread, td_lock)); -ASSYM(TF_SIZE, roundup2(sizeof(struct trapframe), STACKALIGNBYTES + 1)); +ASSYM(TF_SIZE, TF_SIZE); ASSYM(TF_RA, offsetof(struct trapframe, tf_ra)); ASSYM(TF_SP, offsetof(struct trapframe, tf_sp)); ASSYM(TF_GP, offsetof(struct trapframe, tf_gp)); @@ -98,6 +98,8 @@ ASSYM(TF_STVAL, offsetof(struct trapframe, tf_stval)); ASSYM(TF_SCAUSE, offsetof(struct trapframe, tf_scause)); ASSYM(TF_SSTATUS, offsetof(struct trapframe, tf_sstatus)); +ASSYM(KF_TP, offsetof(struct kernframe, kf_tp)); + ASSYM(RISCV_BOOTPARAMS_SIZE, sizeof(struct riscv_bootparams)); ASSYM(RISCV_BOOTPARAMS_KERN_L1PT, offsetof(struct riscv_bootparams, kern_l1pt)); ASSYM(RISCV_BOOTPARAMS_KERN_PHYS, offsetof(struct riscv_bootparams, kern_phys)); diff --git a/sys/riscv/riscv/swtch.S b/sys/riscv/riscv/swtch.S index 8312a6b5f347..cfd19a2d76d6 100644 --- a/sys/riscv/riscv/swtch.S +++ b/sys/riscv/riscv/swtch.S @@ -419,7 +419,7 @@ ENTRY(fork_trampoline) * Store our pcpup on stack, we will load it back * on kernel mode trap. */ - sd tp, (TF_SIZE)(sp) + sd tp, (TF_SIZE + KF_TP)(sp) ld tp, (TF_TP)(sp) /* Save kernel stack so we can use it doing a user trap */ diff --git a/sys/riscv/riscv/vm_machdep.c b/sys/riscv/riscv/vm_machdep.c index 26b8c0dffcde..0e9a52ba89b0 100644 --- a/sys/riscv/riscv/vm_machdep.c +++ b/sys/riscv/riscv/vm_machdep.c @@ -58,6 +58,26 @@ #define TP_OFFSET 16 /* sizeof(struct tcb) */ #endif +static void +cpu_set_pcb_frame(struct thread *td) +{ + td->td_pcb = (struct pcb *)((char *)td->td_kstack + + td->td_kstack_pages * PAGE_SIZE) - 1; + + /* + * td->td_frame + TF_SIZE will be the saved kernel stack pointer whilst + * in userspace, so keep it aligned so it's also aligned when we + * subtract TF_SIZE in the trap handler (and here for the initial stack + * pointer). This also keeps the struct kernframe just afterwards + * aligned no matter what's in it or struct pcb. + * + * NB: TF_SIZE not sizeof(struct trapframe) as we need the rounded + * value to match the trap handler. + */ + td->td_frame = (struct trapframe *)(STACKALIGN( + (char *)td->td_pcb - sizeof(struct kernframe)) - TF_SIZE); +} + /* * Finish a fork operation, with process p2 nearly set up. * Copy and update the pcb, set up the stack so that the child @@ -74,13 +94,12 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) /* RISCVTODO: save the FPU state here */ - pcb2 = (struct pcb *)(td2->td_kstack + - td2->td_kstack_pages * PAGE_SIZE) - 1; + cpu_set_pcb_frame(td2); - td2->td_pcb = pcb2; + pcb2 = td2->td_pcb; bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); - tf = (struct trapframe *)STACKALIGN((struct trapframe *)pcb2 - 1); + tf = td2->td_frame; bcopy(td1->td_frame, tf, sizeof(*tf)); /* Clear syscall error flag */ @@ -92,8 +111,6 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) tf->tf_sstatus |= (SSTATUS_SPIE); /* Enable interrupts. */ tf->tf_sstatus &= ~(SSTATUS_SPP); /* User mode. */ - td2->td_frame = tf; - /* Set the return value registers for fork() */ td2->td_pcb->pcb_s[0] = (uintptr_t)fork_return; td2->td_pcb->pcb_s[1] = (uintptr_t)td2; @@ -217,11 +234,7 @@ cpu_thread_exit(struct thread *td) void cpu_thread_alloc(struct thread *td) { - - td->td_pcb = (struct pcb *)(td->td_kstack + - td->td_kstack_pages * PAGE_SIZE) - 1; - td->td_frame = (struct trapframe *)STACKALIGN( - (caddr_t)td->td_pcb - 8 - sizeof(struct trapframe)); + cpu_set_pcb_frame(td); } void