Skip to content

Commit 38dab74

Browse files
Merge patch series "RISC-V Hibernation Support"
Sia Jee Heng <jeeheng.sia@starfivetech.com> says: This series adds RISC-V Hibernation/suspend to disk support. Low level Arch functions were created to support hibernation. swsusp_arch_suspend() relies code from __cpu_suspend_enter() to write cpu state onto the stack, then calling swsusp_save() to save the memory image. Arch specific hibernation header is implemented and is utilized by the arch_hibernation_header_restore() and arch_hibernation_header_save() functions. The arch specific hibernation header consists of satp, hartid, and the cpu_resume address. The kernel built version is also need to be saved into the hibernation image header to making sure only the same kernel is restore when resume. swsusp_arch_resume() creates a temporary page table that covering only the linear map. It copies the restore code to a 'safe' page, then start to restore the memory image. Once completed, it restores the original kernel's page table. It then calls into __hibernate_cpu_resume() to restore the CPU context. Finally, it follows the normal hibernation path back to the hibernation core. To enable hibernation/suspend to disk into RISCV, the below config need to be enabled: - CONFIG_HIBERNATION - CONFIG_ARCH_HIBERNATION_HEADER - CONFIG_ARCH_HIBERNATION_POSSIBLE At high-level, this series includes the following changes: 1) Change suspend_save_csrs() and suspend_restore_csrs() to public function as these functions are common to suspend/hibernation. (patch 1) 2) Refactor the common code in the __cpu_resume_enter() function and __hibernate_cpu_resume() function. The common code are used by hibernation and suspend. (patch 2) 3) Enhance kernel_page_present() function to support huge page. (patch 3) 4) Add arch/riscv low level functions to support hibernation/suspend to disk. (patch 4) * b4-shazam-merge: RISC-V: Add arch functions to support hibernation/suspend-to-disk RISC-V: mm: Enable huge page support to kernel_page_present() function RISC-V: Factor out common code of __cpu_resume_enter() RISC-V: Change suspend_save_csrs and suspend_restore_csrs to public function Link: https://lore.kernel.org/r/20230330064321.1008373-1-jeeheng.sia@starfivetech.com Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
2 parents b3d6bdf + c031721 commit 38dab74

10 files changed

Lines changed: 634 additions & 34 deletions

File tree

arch/riscv/Kconfig

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ config RISCV
5555
select CLINT_TIMER if !MMU
5656
select CLONE_BACKWARDS
5757
select COMMON_CLK
58-
select CPU_PM if CPU_IDLE
58+
select CPU_PM if CPU_IDLE || HIBERNATION
5959
select EDAC_SUPPORT
6060
select GENERIC_ARCH_TOPOLOGY
6161
select GENERIC_ATOMIC64 if !64BIT
@@ -799,6 +799,12 @@ menu "Power management options"
799799

800800
source "kernel/power/Kconfig"
801801

802+
config ARCH_HIBERNATION_POSSIBLE
803+
def_bool y
804+
805+
config ARCH_HIBERNATION_HEADER
806+
def_bool HIBERNATION
807+
802808
endmenu # "Power management options"
803809

804810
menu "CPU Power Management"

arch/riscv/include/asm/assembler.h

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (C) 2023 StarFive Technology Co., Ltd.
4+
*
5+
* Author: Jee Heng Sia <jeeheng.sia@starfivetech.com>
6+
*/
7+
8+
#ifndef __ASSEMBLY__
9+
#error "Only include this from assembly code"
10+
#endif
11+
12+
#ifndef __ASM_ASSEMBLER_H
13+
#define __ASM_ASSEMBLER_H
14+
15+
#include <asm/asm.h>
16+
#include <asm/asm-offsets.h>
17+
#include <asm/csr.h>
18+
19+
/*
20+
* suspend_restore_csrs - restore CSRs
21+
*/
22+
.macro suspend_restore_csrs
23+
REG_L t0, (SUSPEND_CONTEXT_REGS + PT_EPC)(a0)
24+
csrw CSR_EPC, t0
25+
REG_L t0, (SUSPEND_CONTEXT_REGS + PT_STATUS)(a0)
26+
csrw CSR_STATUS, t0
27+
REG_L t0, (SUSPEND_CONTEXT_REGS + PT_BADADDR)(a0)
28+
csrw CSR_TVAL, t0
29+
REG_L t0, (SUSPEND_CONTEXT_REGS + PT_CAUSE)(a0)
30+
csrw CSR_CAUSE, t0
31+
.endm
32+
33+
/*
34+
* suspend_restore_regs - Restore registers (except A0 and T0-T6)
35+
*/
36+
.macro suspend_restore_regs
37+
REG_L ra, (SUSPEND_CONTEXT_REGS + PT_RA)(a0)
38+
REG_L sp, (SUSPEND_CONTEXT_REGS + PT_SP)(a0)
39+
REG_L gp, (SUSPEND_CONTEXT_REGS + PT_GP)(a0)
40+
REG_L tp, (SUSPEND_CONTEXT_REGS + PT_TP)(a0)
41+
REG_L s0, (SUSPEND_CONTEXT_REGS + PT_S0)(a0)
42+
REG_L s1, (SUSPEND_CONTEXT_REGS + PT_S1)(a0)
43+
REG_L a1, (SUSPEND_CONTEXT_REGS + PT_A1)(a0)
44+
REG_L a2, (SUSPEND_CONTEXT_REGS + PT_A2)(a0)
45+
REG_L a3, (SUSPEND_CONTEXT_REGS + PT_A3)(a0)
46+
REG_L a4, (SUSPEND_CONTEXT_REGS + PT_A4)(a0)
47+
REG_L a5, (SUSPEND_CONTEXT_REGS + PT_A5)(a0)
48+
REG_L a6, (SUSPEND_CONTEXT_REGS + PT_A6)(a0)
49+
REG_L a7, (SUSPEND_CONTEXT_REGS + PT_A7)(a0)
50+
REG_L s2, (SUSPEND_CONTEXT_REGS + PT_S2)(a0)
51+
REG_L s3, (SUSPEND_CONTEXT_REGS + PT_S3)(a0)
52+
REG_L s4, (SUSPEND_CONTEXT_REGS + PT_S4)(a0)
53+
REG_L s5, (SUSPEND_CONTEXT_REGS + PT_S5)(a0)
54+
REG_L s6, (SUSPEND_CONTEXT_REGS + PT_S6)(a0)
55+
REG_L s7, (SUSPEND_CONTEXT_REGS + PT_S7)(a0)
56+
REG_L s8, (SUSPEND_CONTEXT_REGS + PT_S8)(a0)
57+
REG_L s9, (SUSPEND_CONTEXT_REGS + PT_S9)(a0)
58+
REG_L s10, (SUSPEND_CONTEXT_REGS + PT_S10)(a0)
59+
REG_L s11, (SUSPEND_CONTEXT_REGS + PT_S11)(a0)
60+
.endm
61+
62+
/*
63+
* copy_page - copy 1 page (4KB) of data from source to destination
64+
* @a0 - destination
65+
* @a1 - source
66+
*/
67+
.macro copy_page a0, a1
68+
lui a2, 0x1
69+
add a2, a2, a0
70+
1 :
71+
REG_L t0, 0(a1)
72+
REG_L t1, SZREG(a1)
73+
74+
REG_S t0, 0(a0)
75+
REG_S t1, SZREG(a0)
76+
77+
addi a0, a0, 2 * SZREG
78+
addi a1, a1, 2 * SZREG
79+
bne a2, a0, 1b
80+
.endm
81+
82+
#endif /* __ASM_ASSEMBLER_H */

arch/riscv/include/asm/suspend.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ struct suspend_context {
2121
#endif
2222
};
2323

24+
/*
25+
* Used by hibernation core and cleared during resume sequence
26+
*/
27+
extern int in_suspend;
28+
2429
/* Low-level CPU suspend entry function */
2530
int __cpu_suspend_enter(struct suspend_context *context);
2631

@@ -33,4 +38,21 @@ int cpu_suspend(unsigned long arg,
3338
/* Low-level CPU resume entry function */
3439
int __cpu_resume_enter(unsigned long hartid, unsigned long context);
3540

41+
/* Used to save and restore the CSRs */
42+
void suspend_save_csrs(struct suspend_context *context);
43+
void suspend_restore_csrs(struct suspend_context *context);
44+
45+
/* Low-level API to support hibernation */
46+
int swsusp_arch_suspend(void);
47+
int swsusp_arch_resume(void);
48+
int arch_hibernation_header_save(void *addr, unsigned int max_size);
49+
int arch_hibernation_header_restore(void *addr);
50+
int __hibernate_cpu_resume(void);
51+
52+
/* Used to resume on the CPU we hibernated on */
53+
int hibernate_resume_nonboot_cpu_disable(void);
54+
55+
asmlinkage void hibernate_restore_image(unsigned long resume_satp, unsigned long satp_temp,
56+
unsigned long cpu_resume);
57+
asmlinkage int hibernate_core_restore_code(void);
3658
#endif

arch/riscv/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ obj-$(CONFIG_MODULES) += module.o
6464
obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o
6565

6666
obj-$(CONFIG_CPU_PM) += suspend_entry.o suspend.o
67+
obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o
6768

6869
obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o
6970
obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o

arch/riscv/kernel/asm-offsets.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/kbuild.h>
1010
#include <linux/mm.h>
1111
#include <linux/sched.h>
12+
#include <linux/suspend.h>
1213
#include <asm/kvm_host.h>
1314
#include <asm/thread_info.h>
1415
#include <asm/ptrace.h>
@@ -116,6 +117,10 @@ void asm_offsets(void)
116117

117118
OFFSET(SUSPEND_CONTEXT_REGS, suspend_context, regs);
118119

120+
OFFSET(HIBERN_PBE_ADDR, pbe, address);
121+
OFFSET(HIBERN_PBE_ORIG, pbe, orig_address);
122+
OFFSET(HIBERN_PBE_NEXT, pbe, next);
123+
119124
OFFSET(KVM_ARCH_GUEST_ZERO, kvm_vcpu_arch, guest_context.zero);
120125
OFFSET(KVM_ARCH_GUEST_RA, kvm_vcpu_arch, guest_context.ra);
121126
OFFSET(KVM_ARCH_GUEST_SP, kvm_vcpu_arch, guest_context.sp);

arch/riscv/kernel/hibernate-asm.S

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Hibernation low level support for RISCV.
4+
*
5+
* Copyright (C) 2023 StarFive Technology Co., Ltd.
6+
*
7+
* Author: Jee Heng Sia <jeeheng.sia@starfivetech.com>
8+
*/
9+
10+
#include <asm/asm.h>
11+
#include <asm/asm-offsets.h>
12+
#include <asm/assembler.h>
13+
#include <asm/csr.h>
14+
15+
#include <linux/linkage.h>
16+
17+
/*
18+
* int __hibernate_cpu_resume(void)
19+
* Switch back to the hibernated image's page table prior to restoring the CPU
20+
* context.
21+
*
22+
* Always returns 0
23+
*/
24+
ENTRY(__hibernate_cpu_resume)
25+
/* switch to hibernated image's page table. */
26+
csrw CSR_SATP, s0
27+
sfence.vma
28+
29+
REG_L a0, hibernate_cpu_context
30+
31+
suspend_restore_csrs
32+
suspend_restore_regs
33+
34+
/* Return zero value. */
35+
mv a0, zero
36+
37+
ret
38+
END(__hibernate_cpu_resume)
39+
40+
/*
41+
* Prepare to restore the image.
42+
* a0: satp of saved page tables.
43+
* a1: satp of temporary page tables.
44+
* a2: cpu_resume.
45+
*/
46+
ENTRY(hibernate_restore_image)
47+
mv s0, a0
48+
mv s1, a1
49+
mv s2, a2
50+
REG_L s4, restore_pblist
51+
REG_L a1, relocated_restore_code
52+
53+
jalr a1
54+
END(hibernate_restore_image)
55+
56+
/*
57+
* The below code will be executed from a 'safe' page.
58+
* It first switches to the temporary page table, then starts to copy the pages
59+
* back to the original memory location. Finally, it jumps to __hibernate_cpu_resume()
60+
* to restore the CPU context.
61+
*/
62+
ENTRY(hibernate_core_restore_code)
63+
/* switch to temp page table. */
64+
csrw satp, s1
65+
sfence.vma
66+
.Lcopy:
67+
/* The below code will restore the hibernated image. */
68+
REG_L a1, HIBERN_PBE_ADDR(s4)
69+
REG_L a0, HIBERN_PBE_ORIG(s4)
70+
71+
copy_page a0, a1
72+
73+
REG_L s4, HIBERN_PBE_NEXT(s4)
74+
bnez s4, .Lcopy
75+
76+
jalr s2
77+
END(hibernate_core_restore_code)

0 commit comments

Comments
 (0)