[PATCH v7 3/5] um: allow PM with suspend-to-idle
Anton Ivanov
anton.ivanov at kot-begemot.co.uk
Thu Dec 3 06:34:08 EST 2020
On 02/12/2020 19:58, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg at 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 at 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 at cambridgegreys.com>
--
Anton R. Ivanov
https://www.kot-begemot.co.uk/
More information about the linux-um
mailing list