From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail.mainlining.org (mail.mainlining.org [5.75.144.95]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B3EA43D75C4 for ; Tue, 25 Aug 2026 20:58:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=5.75.144.95 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787691538; cv=none; b=tVM6L8a9KVuugrTSUlqe1G9zb6igFLb1yNbyvJHVQQyvAPs8q5W0rqaRC2T2k4NjMRlvOomM0KRZfvzIr+/HwOqhJjvSiTmbw8MHuEcBWOUISgmJb0KvJQd/wXCMKQ5ba14V13DIi8fWcBrcDq5HDsHifHg7TEj+2bIgy3ILG7g= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787691538; c=relaxed/simple; bh=wrZPU/vB6yrO2p31oARv3vfmvNsJyjuT2pkHRG4kssA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JOOLgNNbr3e3PjnRFZRh5GmazM4WI03egG8t33uuIa13ZahBT/g3UxJg4aOhttBJ88t1FcXoVW8y/zQR/+9/4HGV553Urv/o5OQqI8rWVICEPPtLqcFD+3qvIM9hrtn5JOYuCHZXL//Cv38a5a0Z7dR3QXn80bATnaqjwGOCVEA= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=mainlining.org; spf=pass smtp.mailfrom=mainlining.org; dkim=pass (2048-bit key) header.d=mainlining.org header.i=@mainlining.org header.b=AMjKzy0J; dkim=permerror (0-bit key) header.d=mainlining.org header.i=@mainlining.org header.b=UxxEbtkt; arc=none smtp.client-ip=5.75.144.95 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=mainlining.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=mainlining.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=mainlining.org header.i=@mainlining.org header.b="AMjKzy0J"; dkim=permerror (0-bit key) header.d=mainlining.org header.i=@mainlining.org header.b="UxxEbtkt" DKIM-Signature: v=1; a=rsa-sha256; s=202507r; d=mainlining.org; c=relaxed/relaxed; h=Message-ID:Date:Subject:To:From; t=1787691522; bh=rEGlkv18mRe1qNNtTlr2JCI qchOSWxy0YcEBCLLf6KE=; b=AMjKzy0Jmvstw3XfAeDtfanNVzCtFyAdF/q2+ErvENgGyIgCcQ UWOvIWeYxGS6f5WiPi5UzLLGqWgN3M8UknaG/ZrXnAzluenI2OHsnV7YxLR+AIEFUHr87W7GlB5 1xNb1mYLHum1JJhwPr/9jLkxdRzrxrhgBUzRe7nCT5SQfKZ7eOnXJDEZIcS4S1TUrPz9QHScKk5 602zFGLprRUu3bGGr3Xh17JjgDqGJ/ymYp5qjY3X9agrlGBQf3pDxuwDf6CRMpn14unr9STWmzj 3j9mLwo9QeApOCy28Fd/vpR7eo+IbTrofkUVUefQAoxdoZlanIBHrOwn9mVD3l4xqRA==; DKIM-Signature: v=1; a=ed25519-sha256; s=202507e; d=mainlining.org; c=relaxed/relaxed; h=Message-ID:Date:Subject:To:From; t=1787691522; bh=rEGlkv18mRe1qNNtTlr2JCI qchOSWxy0YcEBCLLf6KE=; b=UxxEbtktDwBAOHGUQbb+V1PU+FoeCibh+Zhog3Px+tdF30povN 2iinhe50EZPD06cC01718+XDk14huWKkLbCw==; From: Bradley Morgan To: Will Deacon Cc: Catalin Marinas , Mark Rutland , James Morse , Marc Zyngier , Ard Biesheuvel , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, brads@mainlining.org Subject: [PATCH 4/7] arm64: hibernate: fix _cpu_resume() calling convention Date: Tue, 25 Aug 2026 20:58:36 +0000 Message-ID: <20260825205839.14571-5-brads@mainlining.org> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260825205839.14571-1-brads@mainlining.org> References: <20260825205839.14571-1-brads@mainlining.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit The hibernate path borrows bits of the normal idle suspend/resume code and open codes the rest. It skips cpu_resume() and has swsusp_arch_suspend_exit() branch straight into _cpu_resume() at the kernel's native EL with the MMU on. Commit 82e4958800c01daa ("arm64: head: Move all finalise_el2 calls to after __enable_mmu") changed the calling convention for _cpu_resume() to expect EL1 with the boot mode in x19, but we never updated swsusp_arch_suspend_exit() to match. So when swsusp_arch_suspend_exit() calls _cpu_resume(), x19 holds the final struct pbe next pointer, which must be NULL since it marks the end of the list. _cpu_resume() then passes that to finalise_el2() in x0, and finalise_el2() only issues an HVC when the value is BOOT_CPU_MODE_EL2 and we are at EL1, so it happens not to fire. That is the right outcome, but it is pure luck rather than design. Split _cpu_resume() so this is less fragile. __cpu_resume_switched() is the shared part, used by both the idle and hibernate code. It takes no arguments and issues no HVC. The name is meant to match __primary_switched and __secondary_switched. __cpu_resume_switched_finalise_el2() is for the idle path only. It pulls the boot mode from x19 and calls finalise_el2() before __cpu_resume_switched(). It is kept local to sleep.S so the odd calling convention does not leak any further. Fixes: 82e4958800c01daa ("arm64: head: Move all finalise_el2 calls to after __enable_mmu") Signed-off-by: Bradley Morgan Cc: Ard Biesheuvel Cc: Catalin Marinas Cc: James Morse Cc: Marc Zyngier Cc: Will Deacon --- arch/arm64/include/asm/suspend.h | 2 +- arch/arm64/kernel/hibernate.c | 2 +- arch/arm64/kernel/sleep.S | 9 ++++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h index e9ce68d50ba4..1b7570902264 100644 --- a/arch/arm64/include/asm/suspend.h +++ b/arch/arm64/include/asm/suspend.h @@ -41,7 +41,7 @@ extern int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)); extern void cpu_resume(void); int __cpu_suspend_enter(struct sleep_stack_data *state); void __cpu_suspend_exit(void); -void _cpu_resume(void); +void __cpu_resume_switched(void); int swsusp_arch_suspend(void); int swsusp_arch_resume(void); diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index 8ac29058a839..30b02e39a397 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -114,7 +114,7 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size) arch_hdr_invariants(&hdr->invariants); hdr->ttbr1_el1 = __pa_symbol(swapper_pg_dir); - hdr->reenter_kernel = _cpu_resume; + hdr->reenter_kernel = __cpu_resume_switched; /* We can't use __hyp_get_vectors() because kvm may still be loaded */ if (el2_reset_needed()) diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index f093cdf71be1..da45ab63bd9c 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -107,16 +107,19 @@ SYM_CODE_START(cpu_resume) adrp x1, swapper_pg_dir adrp x2, idmap_pg_dir bl __enable_mmu - ldr x8, =_cpu_resume + ldr x8, =__cpu_resume_switched_finalise_el2 br x8 SYM_CODE_END(cpu_resume) .ltorg .popsection -SYM_FUNC_START(_cpu_resume) +SYM_FUNC_START_LOCAL(__cpu_resume_switched_finalise_el2) mov x0, x19 bl finalise_el2 + b __cpu_resume_switched +SYM_FUNC_END(__cpu_resume_switched_finalise_el2) +SYM_FUNC_START(__cpu_resume_switched) mrs x1, mpidr_el1 adr_l x8, mpidr_hash // x8 = struct mpidr_hash virt address @@ -152,4 +155,4 @@ SYM_FUNC_START(_cpu_resume) ldp x29, lr, [x29] mov x0, #0 ret -SYM_FUNC_END(_cpu_resume) +SYM_FUNC_END(__cpu_resume_switched) -- 2.47.3