aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-14 20:17:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-14 20:17:34 -0400
commitf2772a0e4833d1af1901b6f1a38136fb71d1350c (patch)
tree28bf6f0944d745e19947273022224ebc6b2d07c8 /arch/um/kernel
parentfcd98147ac71f35b69e2f50b5fddc5524dd2dfa8 (diff)
parentb482e48d29f1461fd0d059a17f32bcfa274127b3 (diff)
Merge tag 'for-linus-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml
Pull UML updates from Richard Weinberger: - A new timer mode, time travel, for testing with UML - Many bugixes/improvements for the serial line driver - Various bugfixes * tag 'for-linus-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml: um: fix build without CONFIG_UML_TIME_TRAVEL_SUPPORT um: Fix kcov crash during startup um: configs: Remove useless UEVENT_HELPER_PATH um: Support time travel mode um: Pass nsecs to os timer functions um: Remove drivers/ssl.h um: Don't garbage collect in deactivate_all_fds() um: Silence lockdep complaint about mmap_sem um: Remove locking in deactivate_all_fds() um: Timer code cleanup um: fix os_timer_one_shot() um: Fix IRQ controller regression on console read
Diffstat (limited to 'arch/um/kernel')
-rw-r--r--arch/um/kernel/irq.c9
-rw-r--r--arch/um/kernel/process.c42
-rw-r--r--arch/um/kernel/skas/Makefile2
-rw-r--r--arch/um/kernel/skas/syscall.c11
-rw-r--r--arch/um/kernel/time.c131
5 files changed, 183 insertions, 12 deletions
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index 598d7b3d9355..efde1f16c603 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -21,6 +21,8 @@
21#include <irq_user.h> 21#include <irq_user.h>
22 22
23 23
24extern void free_irqs(void);
25
24/* When epoll triggers we do not know why it did so 26/* When epoll triggers we do not know why it did so
25 * we can also have different IRQs for read and write. 27 * we can also have different IRQs for read and write.
26 * This is why we keep a small irq_fd array for each fd - 28 * This is why we keep a small irq_fd array for each fd -
@@ -100,6 +102,8 @@ void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
100 } 102 }
101 } 103 }
102 } 104 }
105
106 free_irqs();
103} 107}
104 108
105static int assign_epoll_events_to_irq(struct irq_entry *irq_entry) 109static int assign_epoll_events_to_irq(struct irq_entry *irq_entry)
@@ -380,10 +384,8 @@ EXPORT_SYMBOL(deactivate_fd);
380 */ 384 */
381int deactivate_all_fds(void) 385int deactivate_all_fds(void)
382{ 386{
383 unsigned long flags;
384 struct irq_entry *to_free; 387 struct irq_entry *to_free;
385 388
386 spin_lock_irqsave(&irq_lock, flags);
387 /* Stop IO. The IRQ loop has no lock so this is our 389 /* Stop IO. The IRQ loop has no lock so this is our
388 * only way of making sure we are safe to dispose 390 * only way of making sure we are safe to dispose
389 * of all IRQ handlers 391 * of all IRQ handlers
@@ -399,8 +401,7 @@ int deactivate_all_fds(void)
399 ); 401 );
400 to_free = to_free->next; 402 to_free = to_free->next;
401 } 403 }
402 garbage_collect_irq_entries(); 404 /* don't garbage collect - we can no longer call kfree() here */
403 spin_unlock_irqrestore(&irq_lock, flags);
404 os_close_epoll_fd(); 405 os_close_epoll_fd();
405 return 0; 406 return 0;
406} 407}
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 691b83b10649..67c0d1a860e9 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -203,10 +203,50 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
203 kmalloc_ok = save_kmalloc_ok; 203 kmalloc_ok = save_kmalloc_ok;
204} 204}
205 205
206static void time_travel_sleep(unsigned long long duration)
207{
208 unsigned long long next = time_travel_time + duration;
209
210 if (time_travel_mode != TT_MODE_INFCPU)
211 os_timer_disable();
212
213 if (time_travel_timer_mode != TT_TMR_DISABLED ||
214 time_travel_timer_expiry < next) {
215 if (time_travel_timer_mode == TT_TMR_ONESHOT)
216 time_travel_set_timer(TT_TMR_DISABLED, 0);
217 /*
218 * time_travel_time will be adjusted in the timer
219 * IRQ handler so it works even when the signal
220 * comes from the OS timer
221 */
222 deliver_alarm();
223 } else {
224 time_travel_set_time(next);
225 }
226
227 if (time_travel_mode != TT_MODE_INFCPU) {
228 if (time_travel_timer_mode == TT_TMR_PERIODIC)
229 os_timer_set_interval(time_travel_timer_interval);
230 else if (time_travel_timer_mode == TT_TMR_ONESHOT)
231 os_timer_one_shot(time_travel_timer_expiry - next);
232 }
233}
234
235static void um_idle_sleep(void)
236{
237 unsigned long long duration = UM_NSEC_PER_SEC;
238
239 if (time_travel_mode != TT_MODE_OFF) {
240 time_travel_sleep(duration);
241 } else {
242 os_idle_sleep(duration);
243 }
244}
245
206void arch_cpu_idle(void) 246void arch_cpu_idle(void)
207{ 247{
208 cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); 248 cpu_tasks[current_thread_info()->cpu].pid = os_getpid();
209 os_idle_sleep(UM_NSEC_PER_SEC); 249 um_idle_sleep();
210 local_irq_enable(); 250 local_irq_enable();
211} 251}
212 252
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index 0b76d8869c94..5bd3edfcfedf 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -12,4 +12,6 @@ obj-y := clone.o mmu.o process.o syscall.o uaccess.o
12CFLAGS_clone.o := $(CFLAGS_NO_HARDENING) 12CFLAGS_clone.o := $(CFLAGS_NO_HARDENING)
13UNPROFILE_OBJS := clone.o 13UNPROFILE_OBJS := clone.o
14 14
15KCOV_INSTRUMENT := n
16
15include arch/um/scripts/Makefile.rules 17include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c
index b783ac87d98a..44bb10785075 100644
--- a/arch/um/kernel/skas/syscall.c
+++ b/arch/um/kernel/skas/syscall.c
@@ -10,12 +10,23 @@
10#include <sysdep/ptrace.h> 10#include <sysdep/ptrace.h>
11#include <sysdep/ptrace_user.h> 11#include <sysdep/ptrace_user.h>
12#include <sysdep/syscalls.h> 12#include <sysdep/syscalls.h>
13#include <shared/timer-internal.h>
13 14
14void handle_syscall(struct uml_pt_regs *r) 15void handle_syscall(struct uml_pt_regs *r)
15{ 16{
16 struct pt_regs *regs = container_of(r, struct pt_regs, regs); 17 struct pt_regs *regs = container_of(r, struct pt_regs, regs);
17 int syscall; 18 int syscall;
18 19
20 /*
21 * If we have infinite CPU resources, then make every syscall also a
22 * preemption point, since we don't have any other preemption in this
23 * case, and kernel threads would basically never run until userspace
24 * went to sleep, even if said userspace interacts with the kernel in
25 * various ways.
26 */
27 if (time_travel_mode == TT_MODE_INFCPU)
28 schedule();
29
19 /* Initialize the syscall number and default return value. */ 30 /* Initialize the syscall number and default return value. */
20 UPT_SYSCALL_NR(r) = PT_SYSCALL_NR(r->gp); 31 UPT_SYSCALL_NR(r) = PT_SYSCALL_NR(r->gp);
21 PT_REGS_SET_SYSCALL_RETURN(regs, -ENOSYS); 32 PT_REGS_SET_SYSCALL_RETURN(regs, -ENOSYS);
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 0c572a48158e..6a051b078359 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -19,11 +19,29 @@
19#include <kern_util.h> 19#include <kern_util.h>
20#include <os.h> 20#include <os.h>
21#include <timer-internal.h> 21#include <timer-internal.h>
22#include <shared/init.h>
23
24#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
25enum time_travel_mode time_travel_mode;
26unsigned long long time_travel_time;
27enum time_travel_timer_mode time_travel_timer_mode;
28unsigned long long time_travel_timer_expiry;
29unsigned long long time_travel_timer_interval;
30
31static bool time_travel_start_set;
32static unsigned long long time_travel_start;
33#else
34#define time_travel_start_set 0
35#define time_travel_start 0
36#endif
22 37
23void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 38void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
24{ 39{
25 unsigned long flags; 40 unsigned long flags;
26 41
42 if (time_travel_mode != TT_MODE_OFF)
43 time_travel_set_time(time_travel_timer_expiry);
44
27 local_irq_save(flags); 45 local_irq_save(flags);
28 do_IRQ(TIMER_IRQ, regs); 46 do_IRQ(TIMER_IRQ, regs);
29 local_irq_restore(flags); 47 local_irq_restore(flags);
@@ -31,26 +49,47 @@ void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
31 49
32static int itimer_shutdown(struct clock_event_device *evt) 50static int itimer_shutdown(struct clock_event_device *evt)
33{ 51{
34 os_timer_disable(); 52 if (time_travel_mode != TT_MODE_OFF)
53 time_travel_set_timer(TT_TMR_DISABLED, 0);
54
55 if (time_travel_mode != TT_MODE_INFCPU)
56 os_timer_disable();
57
35 return 0; 58 return 0;
36} 59}
37 60
38static int itimer_set_periodic(struct clock_event_device *evt) 61static int itimer_set_periodic(struct clock_event_device *evt)
39{ 62{
40 os_timer_set_interval(NULL, NULL); 63 unsigned long long interval = NSEC_PER_SEC / HZ;
64
65 if (time_travel_mode != TT_MODE_OFF)
66 time_travel_set_timer(TT_TMR_PERIODIC,
67 time_travel_time + interval);
68
69 if (time_travel_mode != TT_MODE_INFCPU)
70 os_timer_set_interval(interval);
71
41 return 0; 72 return 0;
42} 73}
43 74
44static int itimer_next_event(unsigned long delta, 75static int itimer_next_event(unsigned long delta,
45 struct clock_event_device *evt) 76 struct clock_event_device *evt)
46{ 77{
47 return os_timer_one_shot(delta); 78 delta += 1;
79
80 if (time_travel_mode != TT_MODE_OFF)
81 time_travel_set_timer(TT_TMR_ONESHOT,
82 time_travel_time + delta);
83
84 if (time_travel_mode != TT_MODE_INFCPU)
85 return os_timer_one_shot(delta);
86
87 return 0;
48} 88}
49 89
50static int itimer_one_shot(struct clock_event_device *evt) 90static int itimer_one_shot(struct clock_event_device *evt)
51{ 91{
52 os_timer_one_shot(1); 92 return itimer_next_event(0, evt);
53 return 0;
54} 93}
55 94
56static struct clock_event_device timer_clockevent = { 95static struct clock_event_device timer_clockevent = {
@@ -87,6 +126,17 @@ static irqreturn_t um_timer(int irq, void *dev)
87 126
88static u64 timer_read(struct clocksource *cs) 127static u64 timer_read(struct clocksource *cs)
89{ 128{
129 if (time_travel_mode != TT_MODE_OFF) {
130 /*
131 * We make reading the timer cost a bit so that we don't get
132 * stuck in loops that expect time to move more than the
133 * exact requested sleep amount, e.g. python's socket server,
134 * see https://bugs.python.org/issue37026.
135 */
136 time_travel_set_time(time_travel_time + TIMER_MULTIPLIER);
137 return time_travel_time / TIMER_MULTIPLIER;
138 }
139
90 return os_nsecs() / TIMER_MULTIPLIER; 140 return os_nsecs() / TIMER_MULTIPLIER;
91} 141}
92 142
@@ -107,7 +157,7 @@ static void __init um_timer_setup(void)
107 printk(KERN_ERR "register_timer : request_irq failed - " 157 printk(KERN_ERR "register_timer : request_irq failed - "
108 "errno = %d\n", -err); 158 "errno = %d\n", -err);
109 159
110 err = os_timer_create(NULL); 160 err = os_timer_create();
111 if (err != 0) { 161 if (err != 0) {
112 printk(KERN_ERR "creation of timer failed - errno = %d\n", -err); 162 printk(KERN_ERR "creation of timer failed - errno = %d\n", -err);
113 return; 163 return;
@@ -123,7 +173,12 @@ static void __init um_timer_setup(void)
123 173
124void read_persistent_clock64(struct timespec64 *ts) 174void read_persistent_clock64(struct timespec64 *ts)
125{ 175{
126 long long nsecs = os_persistent_clock_emulation(); 176 long long nsecs;
177
178 if (time_travel_start_set)
179 nsecs = time_travel_start + time_travel_time;
180 else
181 nsecs = os_persistent_clock_emulation();
127 182
128 set_normalized_timespec64(ts, nsecs / NSEC_PER_SEC, 183 set_normalized_timespec64(ts, nsecs / NSEC_PER_SEC,
129 nsecs % NSEC_PER_SEC); 184 nsecs % NSEC_PER_SEC);
@@ -134,3 +189,65 @@ void __init time_init(void)
134 timer_set_signal_handler(); 189 timer_set_signal_handler();
135 late_time_init = um_timer_setup; 190 late_time_init = um_timer_setup;
136} 191}
192
193#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
194unsigned long calibrate_delay_is_known(void)
195{
196 if (time_travel_mode == TT_MODE_INFCPU)
197 return 1;
198 return 0;
199}
200
201int setup_time_travel(char *str)
202{
203 if (strcmp(str, "=inf-cpu") == 0) {
204 time_travel_mode = TT_MODE_INFCPU;
205 timer_clockevent.name = "time-travel-timer-infcpu";
206 timer_clocksource.name = "time-travel-clock";
207 return 1;
208 }
209
210 if (!*str) {
211 time_travel_mode = TT_MODE_BASIC;
212 timer_clockevent.name = "time-travel-timer";
213 timer_clocksource.name = "time-travel-clock";
214 return 1;
215 }
216
217 return -EINVAL;
218}
219
220__setup("time-travel", setup_time_travel);
221__uml_help(setup_time_travel,
222"time-travel\n"
223"This option just enables basic time travel mode, in which the clock/timers\n"
224"inside the UML instance skip forward when there's nothing to do, rather than\n"
225"waiting for real time to elapse. However, instance CPU speed is limited by\n"
226"the real CPU speed, so e.g. a 10ms timer will always fire after ~10ms wall\n"
227"clock (but quicker when there's nothing to do).\n"
228"\n"
229"time-travel=inf-cpu\n"
230"This enables time travel mode with infinite processing power, in which there\n"
231"are no wall clock timers, and any CPU processing happens - as seen from the\n"
232"guest - instantly. This can be useful for accurate simulation regardless of\n"
233"debug overhead, physical CPU speed, etc. but is somewhat dangerous as it can\n"
234"easily lead to getting stuck (e.g. if anything in the system busy loops).\n");
235
236int setup_time_travel_start(char *str)
237{
238 int err;
239
240 err = kstrtoull(str, 0, &time_travel_start);
241 if (err)
242 return err;
243
244 time_travel_start_set = 1;
245 return 1;
246}
247
248__setup("time-travel-start", setup_time_travel_start);
249__uml_help(setup_time_travel_start,
250"time-travel-start=<seconds>\n"
251"Configure the UML instance's wall clock to start at this value rather than\n"
252"the host's wall clock at the time of UML boot.\n");
253#endif