diff mbox series

[4/4] um: allow PM with suspend-to-idle

Message ID 20201120222625.7a475c89cdd4.Id4fe7fb6f0405eb24f3db3ae7a6276293f0ce6f7@changeid
State Changes Requested
Headers show
Series um: suspend/resume | expand

Commit Message

Johannes Berg Nov. 20, 2020, 9:29 p.m. UTC
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(-)

Comments

Johannes Berg Nov. 20, 2020, 9:33 p.m. UTC | #1
On Fri, 2020-11-20 at 22:29 +0100, 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.

So what I said about rtcwake ... maybe that's an argument for removing
the USR1 handling? I wasn't really too sure about it.

But on the other hand, typically real systems will have at least *some*
kind of wakeup source that you can manually use and that's always
enabled, perhaps the power button for example; the SIGUSR1 handling was
meant to simulate such a thing.

(Today, if you send SIGUSR1 to the main 'linux' process, it just dies,
but I hope nobody relies on that ...?)

johannes
Anton Ivanov Nov. 21, 2020, 9:34 a.m. UTC | #2
On 20/11/2020 21:33, Johannes Berg wrote:
> On Fri, 2020-11-20 at 22:29 +0100, 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.
> 
> So what I said about rtcwake ... maybe that's an argument for removing
> the USR1 handling? I wasn't really too sure about it.
> 
> But on the other hand, typically real systems will have at least *some*
> kind of wakeup source that you can manually use and that's always
> enabled, perhaps the power button for example; the SIGUSR1 handling was
> meant to simulate such a thing.

This usually translates to the IRQ controller being powered on even if 
the rest of the machine is off and some lines being able to function 
even in power down state.

Not that difficult actually. Going to sleep should just turn off all 
relevant IRQs including de-registering fds. If you are not 
de-registering the fds, the fact that it is turned off in the controller 
will be of no use - it will be re-triggered.

Waking up should restore the state.

Once that is in place, you can emulate the full PM sleep/wake up cycle.

Emulating suspend to disk is more interesting. I actually looked at it 
many years ago and that looked nearly impossible to implement.

> 
> (Today, if you send SIGUSR1 to the main 'linux' process, it just dies,
> but I hope nobody relies on that ...?)
> 
> johannes
> 
> 
> _______________________________________________
> linux-um mailing list
> linux-um@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-um
>
Johannes Berg Nov. 21, 2020, 9:42 a.m. UTC | #3
On Sat, 2020-11-21 at 09:34 +0000, Anton Ivanov wrote:
> On 20/11/2020 21:33, Johannes Berg wrote:
> > On Fri, 2020-11-20 at 22:29 +0100, 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.
> > 
> > So what I said about rtcwake ... maybe that's an argument for removing
> > the USR1 handling? I wasn't really too sure about it.
> > 
> > But on the other hand, typically real systems will have at least *some*
> > kind of wakeup source that you can manually use and that's always
> > enabled, perhaps the power button for example; the SIGUSR1 handling was
> > meant to simulate such a thing.
> 
> This usually translates to the IRQ controller being powered on even if 
> the rest of the machine is off and some lines being able to function 
> even in power down state.
> 
> Not that difficult actually. Going to sleep should just turn off all 
> relevant IRQs including de-registering fds. If you are not 
> de-registering the fds, the fact that it is turned off in the controller 
> will be of no use - it will be re-triggered.

Right. Now I have only s2idle where of course all this machinery is
still enabled, even if you had a real (say x86) system s2idle would
obviously not turn off any hardware.

> Waking up should restore the state.
> 
> Once that is in place, you can emulate the full PM sleep/wake up cycle.

Indeed. I'll continue work later. This was a one-day hack so far :-)

> Emulating suspend to disk is more interesting. I actually looked at it 
> many years ago and that looked nearly impossible to implement.

Hmmmm... That's going to be very tricky, if not impossible, due to you
being a new process when restoring, and then memory layout may differ, I
think?

Not a use case I care about for UML, TBH, though I did implement suspend
to disk for powerpc many years ago :-)

johannes
diff mbox series

Patch

diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index eb51fec75948..daee3bf35942 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -207,3 +207,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 c89ce642b0d3..5992157ab63f 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 00141e70de56..15b6792134b6 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)