Linux kernel -stable discussions
 help / color / mirror / Atom feed
* [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel
       [not found] <20260709121333.23507-1-vladimir.murzin@arm.com>
@ 2026-07-09 12:13 ` Vladimir Murzin
  2026-07-09 13:19   ` Jinjie Ruan
                     ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Vladimir Murzin @ 2026-07-09 12:13 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, maz, will, catalin.marinas, ruanjinjie,
	Ada Couprie Diaz, stable

From: Ada Couprie Diaz <ada.coupriediaz@arm.com>

The arm64 hibernate code manages the exception masking in an unsound
way, leading to potential crashes and/or warnings during resume.

When a hibernation image is saved in `swsusp_arch_suspend()`, all DAIF
exceptions are masked (by virtue of `local_daif_save()`), and the
suspended image is saved assuming that all DAIF exceptions will remain
masked when the image is restored.

When a hibernation image is resumed by `swsusp_arch_resume()`, only
interrupts are masked (by virtue of `local_irq_save()` in
`resume_target_kernel()`). When pseudo-NMI is enabled the DAIF.IF bits
will be clear, and regardless of pseudo-NMI the DAIF.DA bits will be
clear.

This means that there are two problems:

(1) It is possible to take Debug, SError, or pseudo-NMI exceptions
    during the resume process. This is unsafe, as during the resume
    process both the old ane new kernels will tranisently be in an
    inconsistent state, and swsusp_arch_suspend_exit() won't retain
    an executable mapping of any exception vectors.

    Any exception taken here will be fatal and silent.

(2) When re-entering the resumed kernel, some DAIF bits will be clear
    unexpectedly. This permits Debug, SError, or pseudo-NMI exceptions
    to be taken for a short period while the resumed kernel is not yet
    in a consistent state.

    This is detected by CONFIG_ARM64_DEBUG_PRIORITY_MASKING.

Avoid these issues by masking all DAIF exceptions during resume.

Cc: stable@vger.kernel.org
Signed-off-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
---
 arch/arm64/kernel/hibernate.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
index 9717568518ba..d0d9bd91e639 100644
--- a/arch/arm64/kernel/hibernate.c
+++ b/arch/arm64/kernel/hibernate.c
@@ -405,6 +405,7 @@ int swsusp_arch_suspend(void)
 int __nocfi swsusp_arch_resume(void)
 {
 	int rc;
+	unsigned long flags;
 	void *zero_page;
 	size_t exit_size;
 	pgd_t *tmp_pg_dir;
@@ -465,9 +466,21 @@ int __nocfi swsusp_arch_resume(void)
 	if (el2_reset_needed())
 		__hyp_set_vectors(el2_vectors);
 
+	/*
+	 * It is necessary to mask all DAIF exceptions here as:
+	 *
+	 * - The copy of swsusp_arch_suspend_exit() in the hibernation
+	 *   text cannot handle taking any exceptions.
+	 *
+	 * - The suspended kernel masked all DAIF exceptions in
+	 *   swsusp_arch_resume(), and expects to be re-entered in the
+	 *   same state : with all DAIF exceptions masked.
+	 */
+	flags = local_daif_save();
 	hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
 		       resume_hdr.reenter_kernel, restore_pblist,
 		       resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));
+	local_daif_restore(flags);
 
 	return 0;
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel
  2026-07-09 12:13 ` [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel Vladimir Murzin
@ 2026-07-09 13:19   ` Jinjie Ruan
  2026-07-14  9:09     ` Vladimir Murzin
  2026-07-10  3:00   ` Jinjie Ruan
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Jinjie Ruan @ 2026-07-09 13:19 UTC (permalink / raw)
  To: Vladimir Murzin, linux-arm-kernel
  Cc: mark.rutland, maz, will, catalin.marinas, Ada Couprie Diaz,
	stable



On 7/9/2026 8:13 PM, Vladimir Murzin wrote:
> From: Ada Couprie Diaz <ada.coupriediaz@arm.com>
> 
> The arm64 hibernate code manages the exception masking in an unsound
> way, leading to potential crashes and/or warnings during resume.
> 
> When a hibernation image is saved in `swsusp_arch_suspend()`, all DAIF
> exceptions are masked (by virtue of `local_daif_save()`), and the
> suspended image is saved assuming that all DAIF exceptions will remain
> masked when the image is restored.
> 
> When a hibernation image is resumed by `swsusp_arch_resume()`, only
> interrupts are masked (by virtue of `local_irq_save()` in

local_irq_disable()?

> `resume_target_kernel()`). When pseudo-NMI is enabled the DAIF.IF bits
> will be clear, and regardless of pseudo-NMI the DAIF.DA bits will be
> clear.
> 
> This means that there are two problems:
> 
> (1) It is possible to take Debug, SError, or pseudo-NMI exceptions
>     during the resume process. This is unsafe, as during the resume
>     process both the old ane new kernels will tranisently be in an
>     inconsistent state, and swsusp_arch_suspend_exit() won't retain
>     an executable mapping of any exception vectors.
> 
>     Any exception taken here will be fatal and silent.
> 
> (2) When re-entering the resumed kernel, some DAIF bits will be clear
>     unexpectedly. This permits Debug, SError, or pseudo-NMI exceptions
>     to be taken for a short period while the resumed kernel is not yet
>     in a consistent state.
> 
>     This is detected by CONFIG_ARM64_DEBUG_PRIORITY_MASKING.
> 
> Avoid these issues by masking all DAIF exceptions during resume.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
> ---
>  arch/arm64/kernel/hibernate.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
> 
> diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
> index 9717568518ba..d0d9bd91e639 100644
> --- a/arch/arm64/kernel/hibernate.c
> +++ b/arch/arm64/kernel/hibernate.c
> @@ -405,6 +405,7 @@ int swsusp_arch_suspend(void)
>  int __nocfi swsusp_arch_resume(void)
>  {
>  	int rc;
> +	unsigned long flags;
>  	void *zero_page;
>  	size_t exit_size;
>  	pgd_t *tmp_pg_dir;
> @@ -465,9 +466,21 @@ int __nocfi swsusp_arch_resume(void)
>  	if (el2_reset_needed())
>  		__hyp_set_vectors(el2_vectors);
>  
> +	/*
> +	 * It is necessary to mask all DAIF exceptions here as:
> +	 *
> +	 * - The copy of swsusp_arch_suspend_exit() in the hibernation
> +	 *   text cannot handle taking any exceptions.
> +	 *
> +	 * - The suspended kernel masked all DAIF exceptions in
> +	 *   swsusp_arch_resume(), and expects to be re-entered in the
> +	 *   same state : with all DAIF exceptions masked.
> +	 */
> +	flags = local_daif_save();
>  	hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
>  		       resume_hdr.reenter_kernel, restore_pblist,
>  		       resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));
> +	local_daif_restore(flags);
>  
>  	return 0;
>  }


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel
  2026-07-09 12:13 ` [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel Vladimir Murzin
  2026-07-09 13:19   ` Jinjie Ruan
@ 2026-07-10  3:00   ` Jinjie Ruan
  2026-07-14  9:35     ` Vladimir Murzin
  2026-07-10  3:28   ` Jinjie Ruan
  2026-07-10  3:40   ` Liao, Chang
  3 siblings, 1 reply; 10+ messages in thread
From: Jinjie Ruan @ 2026-07-10  3:00 UTC (permalink / raw)
  To: Vladimir Murzin, linux-arm-kernel
  Cc: mark.rutland, maz, will, catalin.marinas, Ada Couprie Diaz,
	stable



On 7/9/2026 8:13 PM, Vladimir Murzin wrote:
> From: Ada Couprie Diaz <ada.coupriediaz@arm.com>
> 
> The arm64 hibernate code manages the exception masking in an unsound
> way, leading to potential crashes and/or warnings during resume.
> 
> When a hibernation image is saved in `swsusp_arch_suspend()`, all DAIF
> exceptions are masked (by virtue of `local_daif_save()`), and the
> suspended image is saved assuming that all DAIF exceptions will remain
> masked when the image is restored.
> 
> When a hibernation image is resumed by `swsusp_arch_resume()`, only
> interrupts are masked (by virtue of `local_irq_save()` in
> `resume_target_kernel()`). When pseudo-NMI is enabled the DAIF.IF bits
> will be clear, and regardless of pseudo-NMI the DAIF.DA bits will be
> clear.
> 
> This means that there are two problems:
> 
> (1) It is possible to take Debug, SError, or pseudo-NMI exceptions
>     during the resume process. This is unsafe, as during the resume
>     process both the old ane new kernels will tranisently be in an
>     inconsistent state, and swsusp_arch_suspend_exit() won't retain
>     an executable mapping of any exception vectors.
> 
>     Any exception taken here will be fatal and silent.
> 
> (2) When re-entering the resumed kernel, some DAIF bits will be clear
>     unexpectedly. This permits Debug, SError, or pseudo-NMI exceptions
>     to be taken for a short period while the resumed kernel is not yet
>     in a consistent state.
> 
>     This is detected by CONFIG_ARM64_DEBUG_PRIORITY_MASKING.
> 
> Avoid these issues by masking all DAIF exceptions during resume.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
> ---
>  arch/arm64/kernel/hibernate.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
> 
> diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
> index 9717568518ba..d0d9bd91e639 100644
> --- a/arch/arm64/kernel/hibernate.c
> +++ b/arch/arm64/kernel/hibernate.c
> @@ -405,6 +405,7 @@ int swsusp_arch_suspend(void)
>  int __nocfi swsusp_arch_resume(void)
>  {
>  	int rc;
> +	unsigned long flags;
>  	void *zero_page;
>  	size_t exit_size;
>  	pgd_t *tmp_pg_dir;
> @@ -465,9 +466,21 @@ int __nocfi swsusp_arch_resume(void)
>  	if (el2_reset_needed())
>  		__hyp_set_vectors(el2_vectors);
>  
> +	/*
> +	 * It is necessary to mask all DAIF exceptions here as:
> +	 *
> +	 * - The copy of swsusp_arch_suspend_exit() in the hibernation
> +	 *   text cannot handle taking any exceptions.
> +	 *
> +	 * - The suspended kernel masked all DAIF exceptions in
> +	 *   swsusp_arch_resume(), and expects to be re-entered in the
> +	 *   same state : with all DAIF exceptions masked.
> +	 */
> +	flags = local_daif_save();
>  	hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
>  		       resume_hdr.reenter_kernel, restore_pblist,
>  		       resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));

hibernate_exit() is a noreturn function, the following
local_daif_restore() will not be called.

> +	local_daif_restore(flags);
>  
>  	return 0;
>  }


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel
  2026-07-09 12:13 ` [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel Vladimir Murzin
  2026-07-09 13:19   ` Jinjie Ruan
  2026-07-10  3:00   ` Jinjie Ruan
@ 2026-07-10  3:28   ` Jinjie Ruan
  2026-07-14  9:37     ` Vladimir Murzin
  2026-07-10  3:40   ` Liao, Chang
  3 siblings, 1 reply; 10+ messages in thread
From: Jinjie Ruan @ 2026-07-10  3:28 UTC (permalink / raw)
  To: Vladimir Murzin, linux-arm-kernel
  Cc: mark.rutland, maz, will, catalin.marinas, Ada Couprie Diaz,
	stable



On 7/9/2026 8:13 PM, Vladimir Murzin wrote:
> From: Ada Couprie Diaz <ada.coupriediaz@arm.com>
> 
> The arm64 hibernate code manages the exception masking in an unsound
> way, leading to potential crashes and/or warnings during resume.
> 
> When a hibernation image is saved in `swsusp_arch_suspend()`, all DAIF
> exceptions are masked (by virtue of `local_daif_save()`), and the
> suspended image is saved assuming that all DAIF exceptions will remain
> masked when the image is restored.
> 
> When a hibernation image is resumed by `swsusp_arch_resume()`, only
> interrupts are masked (by virtue of `local_irq_save()` in
> `resume_target_kernel()`). When pseudo-NMI is enabled the DAIF.IF bits
> will be clear, and regardless of pseudo-NMI the DAIF.DA bits will be
> clear.
> 
> This means that there are two problems:
> 
> (1) It is possible to take Debug, SError, or pseudo-NMI exceptions
>     during the resume process. This is unsafe, as during the resume
>     process both the old ane new kernels will tranisently be in an
>     inconsistent state, and swsusp_arch_suspend_exit() won't retain
>     an executable mapping of any exception vectors.
> 
>     Any exception taken here will be fatal and silent.
> 
> (2) When re-entering the resumed kernel, some DAIF bits will be clear
>     unexpectedly. This permits Debug, SError, or pseudo-NMI exceptions
>     to be taken for a short period while the resumed kernel is not yet
>     in a consistent state.
> 
>     This is detected by CONFIG_ARM64_DEBUG_PRIORITY_MASKING.
> 
> Avoid these issues by masking all DAIF exceptions during resume.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
> ---
>  arch/arm64/kernel/hibernate.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
> 
> diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
> index 9717568518ba..d0d9bd91e639 100644
> --- a/arch/arm64/kernel/hibernate.c
> +++ b/arch/arm64/kernel/hibernate.c
> @@ -405,6 +405,7 @@ int swsusp_arch_suspend(void)
>  int __nocfi swsusp_arch_resume(void)
>  {
>  	int rc;
> +	unsigned long flags;
>  	void *zero_page;
>  	size_t exit_size;
>  	pgd_t *tmp_pg_dir;
> @@ -465,9 +466,21 @@ int __nocfi swsusp_arch_resume(void)
>  	if (el2_reset_needed())
>  		__hyp_set_vectors(el2_vectors);
>  
> +	/*
> +	 * It is necessary to mask all DAIF exceptions here as:
> +	 *
> +	 * - The copy of swsusp_arch_suspend_exit() in the hibernation
> +	 *   text cannot handle taking any exceptions.
> +	 *
> +	 * - The suspended kernel masked all DAIF exceptions in
> +	 *   swsusp_arch_resume(), and expects to be re-entered in the
> +	 *   same state : with all DAIF exceptions masked.
> +	 */
> +	flags = local_daif_save();
>  	hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
>  		       resume_hdr.reenter_kernel, restore_pblist,
>  		       resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));
> +	local_daif_restore(flags);

I believe that the local_daif_save() here is also unnecessary because
hibernate_exit() returns from the "return 0 branch" of
__cpu_suspend_enter() in swsusp_arch_suspend(), and before that,
local_daif_save() has already been called to mask all exceptions.

swsusp_arch_suspend(void)
    -> flags = local_daif_save();
    -> if (__cpu_suspend_enter(&state)) {
           ...
        } else {                // _cpu_resume <- hibernate_exit()

           ...
           in_suspend = 0;
           ...
        }
     -> local_daif_restore(flags);

>  
>  	return 0;
>  }


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel
  2026-07-09 12:13 ` [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel Vladimir Murzin
                     ` (2 preceding siblings ...)
  2026-07-10  3:28   ` Jinjie Ruan
@ 2026-07-10  3:40   ` Liao, Chang
  2026-07-14  9:42     ` Vladimir Murzin
  3 siblings, 1 reply; 10+ messages in thread
From: Liao, Chang @ 2026-07-10  3:40 UTC (permalink / raw)
  To: Vladimir Murzin, linux-arm-kernel
  Cc: mark.rutland, maz, ruanjinjie, stable, catalin.marinas, will

在 2026/7/9 20:13, Vladimir Murzin 写道:
> From: Ada Couprie Diaz <ada.coupriediaz@arm.com>
> 
> The arm64 hibernate code manages the exception masking in an unsound
> way, leading to potential crashes and/or warnings during resume.
> 
> When a hibernation image is saved in `swsusp_arch_suspend()`, all DAIF
> exceptions are masked (by virtue of `local_daif_save()`), and the
> suspended image is saved assuming that all DAIF exceptions will remain
> masked when the image is restored.
> 
> When a hibernation image is resumed by `swsusp_arch_resume()`, only
> interrupts are masked (by virtue of `local_irq_save()` in
> `resume_target_kernel()`). When pseudo-NMI is enabled the DAIF.IF bits
> will be clear, and regardless of pseudo-NMI the DAIF.DA bits will be
> clear.
> 
> This means that there are two problems:
> 
> (1) It is possible to take Debug, SError, or pseudo-NMI exceptions
>     during the resume process. This is unsafe, as during the resume
>     process both the old ane new kernels will tranisently be in an
>     inconsistent state, and swsusp_arch_suspend_exit() won't retain
>     an executable mapping of any exception vectors.
> 
>     Any exception taken here will be fatal and silent.
> 
> (2) When re-entering the resumed kernel, some DAIF bits will be clear
>     unexpectedly. This permits Debug, SError, or pseudo-NMI exceptions
>     to be taken for a short period while the resumed kernel is not yet
>     in a consistent state.
> 
>     This is detected by CONFIG_ARM64_DEBUG_PRIORITY_MASKING.
> 
> Avoid these issues by masking all DAIF exceptions during resume.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Ada Couprie Diaz <ada.coupriediaz@arm.com>
> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
> ---
>  arch/arm64/kernel/hibernate.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
> 
> diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
> index 9717568518ba..d0d9bd91e639 100644
> --- a/arch/arm64/kernel/hibernate.c
> +++ b/arch/arm64/kernel/hibernate.c
> @@ -405,6 +405,7 @@ int swsusp_arch_suspend(void)
>  int __nocfi swsusp_arch_resume(void)
>  {
>  	int rc;
> +	unsigned long flags;
>  	void *zero_page;
>  	size_t exit_size;
>  	pgd_t *tmp_pg_dir;
> @@ -465,9 +466,21 @@ int __nocfi swsusp_arch_resume(void)
>  	if (el2_reset_needed())
>  		__hyp_set_vectors(el2_vectors);
>  
> +	/*
> +	 * It is necessary to mask all DAIF exceptions here as:
> +	 *
> +	 * - The copy of swsusp_arch_suspend_exit() in the hibernation
> +	 *   text cannot handle taking any exceptions.
> +	 *
> +	 * - The suspended kernel masked all DAIF exceptions in
> +	 *   swsusp_arch_resume(), and expects to be re-entered in the
> +	 *   same state : with all DAIF exceptions masked.
> +	 */
> +	flags = local_daif_save();
>  	hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
>  		       resume_hdr.reenter_kernel, restore_pblist,
>  		       resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));
> +	local_daif_restore(flags);

As Jinjie said, the resumed kernel never return from hibernate_exit(). If that's
the case, it seems better to place unreachable() rather than local_daif_restore(),
would you agree?

>  
>  	return 0;
>  }


-- 
BR
Liao, Chang

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel
  2026-07-09 13:19   ` Jinjie Ruan
@ 2026-07-14  9:09     ` Vladimir Murzin
  0 siblings, 0 replies; 10+ messages in thread
From: Vladimir Murzin @ 2026-07-14  9:09 UTC (permalink / raw)
  To: Jinjie Ruan, linux-arm-kernel
  Cc: mark.rutland, maz, will, catalin.marinas, Ada Couprie Diaz,
	stable

On 7/9/26 14:19, Jinjie Ruan wrote:
> 
> On 7/9/2026 8:13 PM, Vladimir Murzin wrote:
>> From: Ada Couprie Diaz <ada.coupriediaz@arm.com>
>>
>> The arm64 hibernate code manages the exception masking in an unsound
>> way, leading to potential crashes and/or warnings during resume.
>>
>> When a hibernation image is saved in `swsusp_arch_suspend()`, all DAIF
>> exceptions are masked (by virtue of `local_daif_save()`), and the
>> suspended image is saved assuming that all DAIF exceptions will remain
>> masked when the image is restored.
>>
>> When a hibernation image is resumed by `swsusp_arch_resume()`, only
>> interrupts are masked (by virtue of `local_irq_save()` in
> local_irq_disable()?

Sorry, yes it should be local_irq_disable(). I'll fix that in next iteration.

Cheers
Vladimir

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel
  2026-07-10  3:00   ` Jinjie Ruan
@ 2026-07-14  9:35     ` Vladimir Murzin
  0 siblings, 0 replies; 10+ messages in thread
From: Vladimir Murzin @ 2026-07-14  9:35 UTC (permalink / raw)
  To: Jinjie Ruan, linux-arm-kernel
  Cc: mark.rutland, maz, will, catalin.marinas, Ada Couprie Diaz,
	stable

On 7/10/26 04:00, Jinjie Ruan wrote:
>> @ -465,9 +466,21 @@ int __nocfi swsusp_arch_resume(void)
>>  	if (el2_reset_needed())
>>  		__hyp_set_vectors(el2_vectors);
>>  
>> +	/*
>> +	 * It is necessary to mask all DAIF exceptions here as:
>> +	 *
>> +	 * - The copy of swsusp_arch_suspend_exit() in the hibernation
>> +	 *   text cannot handle taking any exceptions.
>> +	 *
>> +	 * - The suspended kernel masked all DAIF exceptions in
>> +	 *   swsusp_arch_resume(), and expects to be re-entered in the
>> +	 *   same state : with all DAIF exceptions masked.
>> +	 */
>> +	flags = local_daif_save();
>>  	hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
>>  		       resume_hdr.reenter_kernel, restore_pblist,
>>  		       resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));
> hibernate_exit() is a noreturn function, the following
> local_daif_restore() will not be called.

Agree. I'll fix that in the next iteration.

Cheers
Vladimir


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel
  2026-07-10  3:28   ` Jinjie Ruan
@ 2026-07-14  9:37     ` Vladimir Murzin
  2026-07-14 12:35       ` Jinjie Ruan
  0 siblings, 1 reply; 10+ messages in thread
From: Vladimir Murzin @ 2026-07-14  9:37 UTC (permalink / raw)
  To: Jinjie Ruan, linux-arm-kernel
  Cc: mark.rutland, maz, will, catalin.marinas, Ada Couprie Diaz,
	stable

On 7/10/26 04:28, Jinjie Ruan wrote:
>> @@ -465,9 +466,21 @@ int __nocfi swsusp_arch_resume(void)
>>  	if (el2_reset_needed())
>>  		__hyp_set_vectors(el2_vectors);
>>  
>> +	/*
>> +	 * It is necessary to mask all DAIF exceptions here as:
>> +	 *
>> +	 * - The copy of swsusp_arch_suspend_exit() in the hibernation
>> +	 *   text cannot handle taking any exceptions.
>> +	 *
>> +	 * - The suspended kernel masked all DAIF exceptions in
>> +	 *   swsusp_arch_resume(), and expects to be re-entered in the
>> +	 *   same state : with all DAIF exceptions masked.
>> +	 */
>> +	flags = local_daif_save();
>>  	hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
>>  		       resume_hdr.reenter_kernel, restore_pblist,
>>  		       resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));
>> +	local_daif_restore(flags);
> I believe that the local_daif_save() here is also unnecessary because
> hibernate_exit() returns from the "return 0 branch" of
> __cpu_suspend_enter() in swsusp_arch_suspend(), and before that,
> local_daif_save() has already been called to mask all exceptions.
> 
> swsusp_arch_suspend(void)
>     -> flags = local_daif_save();
>     -> if (__cpu_suspend_enter(&state)) {
>            ...
>         } else {                // _cpu_resume <- hibernate_exit()
> 
>            ...
>            in_suspend = 0;
>            ...
>         }
>      -> local_daif_restore(flags);

I'm not sure I follow, we are protecting path

...
load_image_and_restore()
  -> hibernation_restore()
     -> resume_target_kernel()
        -> local_irq_disable()
        -> swsusp_arch_resume()
	  -> swsusp_arch_suspend_exit (aka hibernate_exit())
	     -> ...


issue can be easily observed with debug diff bellow applied on top of the
series

diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
index 4dd40593f736..709f5f4c420a 100644
--- a/arch/arm64/kernel/hibernate.c
+++ b/arch/arm64/kernel/hibernate.c
@@ -476,6 +476,7 @@ int __nocfi swsusp_arch_resume(void)
         *   swsusp_arch_resume(), and expects to be re-entered in the
         *   same state : with all DAIF exceptions masked.
         */
+       arm64_debug_exc_context(CRITICAL_CONTEXT);
        flags = local_all_irqs_save_mask(CRITICAL_CONTEXT);
        hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
                       resume_hdr.reenter_kernel, restore_pblist,

That would generate warning when run on qemu

 ------------[ cut here ]------------
 Unexpected DAIF+ALLINT: 0xc0 + 0x0 (expected 0x3c0 + 0x2000)
 WARNING: ./arch/arm64/include/asm/interrupts/common_flags.h:175 at swsusp_arch_resume+0x2d0/0x32c, CPU#0: sh/100
 Modules linked in:
 CPU: 0 UID: 0 PID: 100 Comm: sh Not tainted 7.2.0-rc2-00041-gc07d2a0843b2-dirty #288 PREEMPTLAZY 
 Hardware name: linux,dummy-virt (DT)
 pstate: 614000c5 (nZCv daIF -ALLINT +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
 pc : swsusp_arch_resume+0x2d0/0x32c
 lr : swsusp_arch_resume+0x2d0/0x32c
 sp : ffff800081adba80
 x29: ffff800081adbad0 x28: fff00000024ff000 x27: 0000000000000000
 x26: 0000000000000000 x25: 0000000000000000 x24: ffff8000815cd000
 x23: ffff8000815b4000 x22: ffff8000815c28d8 x21: ffff8000815c2000
 x20: fff000000a839000 x19: 0000000000000000 x18: 0000000000000006
 x17: 0000000000000000 x16: 0000000000000000 x15: ffff800081adb64f
 x14: ffff800081adb470 x13: ffff800101adb647 x12: 000000648200003c
 x11: ffff8000815cd8e8 x10: 0000000000000161 x9 : ffff8000815cd8e8
 x8 : 0000000000000162 x7 : ffff8000816258e8 x6 : ffff8000816258e8
 x5 : 3fffffffffffefff x4 : bffffffffffff000 x3 : 0000000000000000
 x2 : 0000000000000000 x1 : 0000000000000000 x0 : fff00000024ff000
 Call trace:
  swsusp_arch_resume+0x2d0/0x32c (P)
  hibernation_restore+0xe0/0x1a4
  load_image_and_restore+0x60/0xb0
  hibernate+0x228/0x374
  state_store+0xe8/0xf4
  kobj_attr_store+0x18/0x34
  sysfs_kf_write+0x5c/0x78
  kernfs_fop_write_iter+0x130/0x200
  vfs_write+0x20c/0x380
  ksys_write+0x70/0x110
  __arm64_sys_write+0x1c/0x28
  invoke_syscall.constprop.0+0x58/0x100
  do_el0_svc+0x40/0xc0
  el0_svc+0x200/0xa0c
  el0t_64_sync_handler+0x110/0x20c
  el0t_64_sync+0x1ac/0x1b0
 ---[ end trace 0000000000000000 ]---

Cheers
Vladimir

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel
  2026-07-10  3:40   ` Liao, Chang
@ 2026-07-14  9:42     ` Vladimir Murzin
  0 siblings, 0 replies; 10+ messages in thread
From: Vladimir Murzin @ 2026-07-14  9:42 UTC (permalink / raw)
  To: Liao, Chang, linux-arm-kernel
  Cc: mark.rutland, maz, ruanjinjie, stable, catalin.marinas, will

On 7/10/26 04:40, Liao, Chang wrote:
>> @@ -465,9 +466,21 @@ int __nocfi swsusp_arch_resume(void)
>>  	if (el2_reset_needed())
>>  		__hyp_set_vectors(el2_vectors);
>>  
>> +	/*
>> +	 * It is necessary to mask all DAIF exceptions here as:
>> +	 *
>> +	 * - The copy of swsusp_arch_suspend_exit() in the hibernation
>> +	 *   text cannot handle taking any exceptions.
>> +	 *
>> +	 * - The suspended kernel masked all DAIF exceptions in
>> +	 *   swsusp_arch_resume(), and expects to be re-entered in the
>> +	 *   same state : with all DAIF exceptions masked.
>> +	 */
>> +	flags = local_daif_save();
>>  	hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
>>  		       resume_hdr.reenter_kernel, restore_pblist,
>>  		       resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));
>> +	local_daif_restore(flags);
> As Jinjie said, the resumed kernel never return from hibernate_exit(). If that's
> the case, it seems better to place unreachable() rather than local_daif_restore(),
> would you agree?

Cannot disagree :) I'll fix that in the next iteration.

Cheers
Vladimir

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel
  2026-07-14  9:37     ` Vladimir Murzin
@ 2026-07-14 12:35       ` Jinjie Ruan
  0 siblings, 0 replies; 10+ messages in thread
From: Jinjie Ruan @ 2026-07-14 12:35 UTC (permalink / raw)
  To: Vladimir Murzin, linux-arm-kernel
  Cc: mark.rutland, maz, will, catalin.marinas, Ada Couprie Diaz,
	stable



On 7/14/2026 5:37 PM, Vladimir Murzin wrote:
> On 7/10/26 04:28, Jinjie Ruan wrote:
>>> @@ -465,9 +466,21 @@ int __nocfi swsusp_arch_resume(void)
>>>  	if (el2_reset_needed())
>>>  		__hyp_set_vectors(el2_vectors);
>>>  
>>> +	/*
>>> +	 * It is necessary to mask all DAIF exceptions here as:
>>> +	 *
>>> +	 * - The copy of swsusp_arch_suspend_exit() in the hibernation
>>> +	 *   text cannot handle taking any exceptions.
>>> +	 *
>>> +	 * - The suspended kernel masked all DAIF exceptions in
>>> +	 *   swsusp_arch_resume(), and expects to be re-entered in the
>>> +	 *   same state : with all DAIF exceptions masked.
>>> +	 */
>>> +	flags = local_daif_save();
>>>  	hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
>>>  		       resume_hdr.reenter_kernel, restore_pblist,
>>>  		       resume_hdr.__hyp_stub_vectors, virt_to_phys(zero_page));
>>> +	local_daif_restore(flags);
>> I believe that the local_daif_save() here is also unnecessary because
>> hibernate_exit() returns from the "return 0 branch" of
>> __cpu_suspend_enter() in swsusp_arch_suspend(), and before that,
>> local_daif_save() has already been called to mask all exceptions.
>>
>> swsusp_arch_suspend(void)
>>     -> flags = local_daif_save();
>>     -> if (__cpu_suspend_enter(&state)) {
>>            ...
>>         } else {                // _cpu_resume <- hibernate_exit()
>>
>>            ...
>>            in_suspend = 0;
>>            ...
>>         }
>>      -> local_daif_restore(flags);

I mean that the return point of hibernate_exit() has already restored
the interrupt mask with local_daif_restore().

> 
> I'm not sure I follow, we are protecting path
> 
> ...
> load_image_and_restore()
>   -> hibernation_restore()
>      -> resume_target_kernel()
>         -> local_irq_disable()
>         -> swsusp_arch_resume()
> 	  -> swsusp_arch_suspend_exit (aka hibernate_exit())
> 	     -> ...
> 
> 
> issue can be easily observed with debug diff bellow applied on top of the
> series
> 
> diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
> index 4dd40593f736..709f5f4c420a 100644
> --- a/arch/arm64/kernel/hibernate.c
> +++ b/arch/arm64/kernel/hibernate.c
> @@ -476,6 +476,7 @@ int __nocfi swsusp_arch_resume(void)
>          *   swsusp_arch_resume(), and expects to be re-entered in the
>          *   same state : with all DAIF exceptions masked.
>          */
> +       arm64_debug_exc_context(CRITICAL_CONTEXT);
>         flags = local_all_irqs_save_mask(CRITICAL_CONTEXT);
>         hibernate_exit(virt_to_phys(tmp_pg_dir), resume_hdr.ttbr1_el1,
>                        resume_hdr.reenter_kernel, restore_pblist,
> 
> That would generate warning when run on qemu
> 
>  ------------[ cut here ]------------
>  Unexpected DAIF+ALLINT: 0xc0 + 0x0 (expected 0x3c0 + 0x2000)
>  WARNING: ./arch/arm64/include/asm/interrupts/common_flags.h:175 at swsusp_arch_resume+0x2d0/0x32c, CPU#0: sh/100
>  Modules linked in:
>  CPU: 0 UID: 0 PID: 100 Comm: sh Not tainted 7.2.0-rc2-00041-gc07d2a0843b2-dirty #288 PREEMPTLAZY 
>  Hardware name: linux,dummy-virt (DT)
>  pstate: 614000c5 (nZCv daIF -ALLINT +PAN -UAO -TCO +DIT -SSBS BTYPE=--)

I encountered some problems when trying to enter the
swsusp_arch_resume() process on QEMU.

Considering that this is the key code, it is necessary to mask the debug
and serror exception , and also to mask ALLINT.

Therefore, LGTM except for the noreturn issue.

Reviewed-by: Jinjie Ruan <ruanjinjie@huawei.com>

>  pc : swsusp_arch_resume+0x2d0/0x32c
>  lr : swsusp_arch_resume+0x2d0/0x32c
>  sp : ffff800081adba80
>  x29: ffff800081adbad0 x28: fff00000024ff000 x27: 0000000000000000
>  x26: 0000000000000000 x25: 0000000000000000 x24: ffff8000815cd000
>  x23: ffff8000815b4000 x22: ffff8000815c28d8 x21: ffff8000815c2000
>  x20: fff000000a839000 x19: 0000000000000000 x18: 0000000000000006
>  x17: 0000000000000000 x16: 0000000000000000 x15: ffff800081adb64f
>  x14: ffff800081adb470 x13: ffff800101adb647 x12: 000000648200003c
>  x11: ffff8000815cd8e8 x10: 0000000000000161 x9 : ffff8000815cd8e8
>  x8 : 0000000000000162 x7 : ffff8000816258e8 x6 : ffff8000816258e8
>  x5 : 3fffffffffffefff x4 : bffffffffffff000 x3 : 0000000000000000
>  x2 : 0000000000000000 x1 : 0000000000000000 x0 : fff00000024ff000
>  Call trace:
>   swsusp_arch_resume+0x2d0/0x32c (P)
>   hibernation_restore+0xe0/0x1a4
>   load_image_and_restore+0x60/0xb0
>   hibernate+0x228/0x374
>   state_store+0xe8/0xf4
>   kobj_attr_store+0x18/0x34
>   sysfs_kf_write+0x5c/0x78
>   kernfs_fop_write_iter+0x130/0x200
>   vfs_write+0x20c/0x380
>   ksys_write+0x70/0x110
>   __arm64_sys_write+0x1c/0x28
>   invoke_syscall.constprop.0+0x58/0x100
>   do_el0_svc+0x40/0xc0
>   el0_svc+0x200/0xa0c
>   el0t_64_sync_handler+0x110/0x20c
>   el0t_64_sync+0x1ac/0x1b0
>  ---[ end trace 0000000000000000 ]---
> 
> Cheers
> Vladimir
> 


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-07-14 12:35 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20260709121333.23507-1-vladimir.murzin@arm.com>
2026-07-09 12:13 ` [RFC PATCH 03/36] arm64: hibernate: mask DAIF before restoring hibernated kernel Vladimir Murzin
2026-07-09 13:19   ` Jinjie Ruan
2026-07-14  9:09     ` Vladimir Murzin
2026-07-10  3:00   ` Jinjie Ruan
2026-07-14  9:35     ` Vladimir Murzin
2026-07-10  3:28   ` Jinjie Ruan
2026-07-14  9:37     ` Vladimir Murzin
2026-07-14 12:35       ` Jinjie Ruan
2026-07-10  3:40   ` Liao, Chang
2026-07-14  9:42     ` Vladimir Murzin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox