Message ID | 20201202205659.5557e53e8d0e.Id4fe7fb6f0405eb24f3db3ae7a6276293f0ce6f7@changeid |
---|---|
State | Accepted |
Headers | show |
Series | um: suspend/resume support | expand |
On 02/12/2020 19:58, Johannes Berg wrote: > From: Johannes Berg <johannes.berg@intel.com> > > In order to be able to experiment with suspend in UML, add the > minimal work to be able to suspend (s2idle) an instance of UML, > and be able to wake it back up from that state with the USR1 > signal sent to the main UML process. > > Signed-off-by: Johannes Berg <johannes.berg@intel.com> > --- > arch/um/Kconfig | 5 +++++ > arch/um/include/shared/kern_util.h | 2 ++ > arch/um/include/shared/os.h | 1 + > arch/um/kernel/um_arch.c | 25 +++++++++++++++++++++++++ > arch/um/os-Linux/signal.c | 14 +++++++++++++- > 5 files changed, 46 insertions(+), 1 deletion(-) > > diff --git a/arch/um/Kconfig b/arch/um/Kconfig > index 4b799fad8b48..1c57599b82fa 100644 > --- a/arch/um/Kconfig > +++ b/arch/um/Kconfig > @@ -192,3 +192,8 @@ config UML_TIME_TRAVEL_SUPPORT > endmenu > > source "arch/um/drivers/Kconfig" > + > +config ARCH_SUSPEND_POSSIBLE > + def_bool y > + > +source "kernel/power/Kconfig" > diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h > index ccafb62e8cce..9c08e728a675 100644 > --- a/arch/um/include/shared/kern_util.h > +++ b/arch/um/include/shared/kern_util.h > @@ -39,6 +39,8 @@ extern int is_syscall(unsigned long addr); > > extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); > > +extern void uml_pm_wake(void); > + > extern int start_uml(void); > extern void paging_init(void); > > diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h > index 0f7fb8bad728..78250a05394a 100644 > --- a/arch/um/include/shared/os.h > +++ b/arch/um/include/shared/os.h > @@ -241,6 +241,7 @@ extern int set_signals(int enable); > extern int set_signals_trace(int enable); > extern int os_is_signal_stack(void); > extern void deliver_alarm(void); > +extern void register_pm_wake_signal(void); > > /* util.c */ > extern void stack_protections(unsigned long address); > diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c > index 76b37297b7d4..237a8d73a096 100644 > --- a/arch/um/kernel/um_arch.c > +++ b/arch/um/kernel/um_arch.c > @@ -13,6 +13,7 @@ > #include <linux/sched.h> > #include <linux/sched/task.h> > #include <linux/kmsg_dump.h> > +#include <linux/suspend.h> > > #include <asm/processor.h> > #include <asm/sections.h> > @@ -377,3 +378,27 @@ void *text_poke(void *addr, const void *opcode, size_t len) > void text_poke_sync(void) > { > } > + > +#ifdef CONFIG_PM_SLEEP > +void uml_pm_wake(void) > +{ > + pm_system_wakeup(); > +} > + > +static int init_pm_wake_signal(void) > +{ > + /* > + * In external time-travel mode we can't use signals to wake up > + * since that would mess with the scheduling. We'll have to do > + * some additional work to support wakeup on virtio devices or > + * similar, perhaps implementing a fake RTC controller that can > + * trigger wakeup (and request the appropriate scheduling from > + * the external scheduler when going to suspend.) > + */ > + if (time_travel_mode != TT_MODE_EXTERNAL) > + register_pm_wake_signal(); > + return 0; > +} > + > +late_initcall(init_pm_wake_signal); > +#endif > diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c > index b58bc68cbe64..0a2ea84033b4 100644 > --- a/arch/um/os-Linux/signal.c > +++ b/arch/um/os-Linux/signal.c > @@ -136,6 +136,16 @@ void set_sigstack(void *sig_stack, int size) > panic("enabling signal stack failed, errno = %d\n", errno); > } > > +static void sigusr1_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) > +{ > + uml_pm_wake(); > +} > + > +void register_pm_wake_signal(void) > +{ > + set_handler(SIGUSR1); > +} > + > static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { > [SIGSEGV] = sig_handler, > [SIGBUS] = sig_handler, > @@ -145,7 +155,9 @@ static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { > > [SIGIO] = sig_handler, > [SIGWINCH] = sig_handler, > - [SIGALRM] = timer_alarm_handler > + [SIGALRM] = timer_alarm_handler, > + > + [SIGUSR1] = sigusr1_handler, > }; > > static void hard_handler(int sig, siginfo_t *si, void *p) > Acked-By: Anton Ivanov <anton.ivanov@cambridgegreys.com>
diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 4b799fad8b48..1c57599b82fa 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -192,3 +192,8 @@ config UML_TIME_TRAVEL_SUPPORT endmenu source "arch/um/drivers/Kconfig" + +config ARCH_SUSPEND_POSSIBLE + def_bool y + +source "kernel/power/Kconfig" diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h index ccafb62e8cce..9c08e728a675 100644 --- a/arch/um/include/shared/kern_util.h +++ b/arch/um/include/shared/kern_util.h @@ -39,6 +39,8 @@ extern int is_syscall(unsigned long addr); extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); +extern void uml_pm_wake(void); + extern int start_uml(void); extern void paging_init(void); diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index 0f7fb8bad728..78250a05394a 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -241,6 +241,7 @@ extern int set_signals(int enable); extern int set_signals_trace(int enable); extern int os_is_signal_stack(void); extern void deliver_alarm(void); +extern void register_pm_wake_signal(void); /* util.c */ extern void stack_protections(unsigned long address); diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 76b37297b7d4..237a8d73a096 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -13,6 +13,7 @@ #include <linux/sched.h> #include <linux/sched/task.h> #include <linux/kmsg_dump.h> +#include <linux/suspend.h> #include <asm/processor.h> #include <asm/sections.h> @@ -377,3 +378,27 @@ void *text_poke(void *addr, const void *opcode, size_t len) void text_poke_sync(void) { } + +#ifdef CONFIG_PM_SLEEP +void uml_pm_wake(void) +{ + pm_system_wakeup(); +} + +static int init_pm_wake_signal(void) +{ + /* + * In external time-travel mode we can't use signals to wake up + * since that would mess with the scheduling. We'll have to do + * some additional work to support wakeup on virtio devices or + * similar, perhaps implementing a fake RTC controller that can + * trigger wakeup (and request the appropriate scheduling from + * the external scheduler when going to suspend.) + */ + if (time_travel_mode != TT_MODE_EXTERNAL) + register_pm_wake_signal(); + return 0; +} + +late_initcall(init_pm_wake_signal); +#endif diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index b58bc68cbe64..0a2ea84033b4 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -136,6 +136,16 @@ void set_sigstack(void *sig_stack, int size) panic("enabling signal stack failed, errno = %d\n", errno); } +static void sigusr1_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) +{ + uml_pm_wake(); +} + +void register_pm_wake_signal(void) +{ + set_handler(SIGUSR1); +} + static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { [SIGSEGV] = sig_handler, [SIGBUS] = sig_handler, @@ -145,7 +155,9 @@ static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { [SIGIO] = sig_handler, [SIGWINCH] = sig_handler, - [SIGALRM] = timer_alarm_handler + [SIGALRM] = timer_alarm_handler, + + [SIGUSR1] = sigusr1_handler, }; static void hard_handler(int sig, siginfo_t *si, void *p)