xref: /openbmc/linux/arch/um/kernel/time.c (revision eec94b8acb03aaaa6fb050883624381f5c07a3f0)
1 /*
2  * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
3  * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
4  * Copyright (C) 2012-2014 Cisco Systems
5  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
6  * Licensed under the GPL
7  */
8 
9 #include <linux/clockchips.h>
10 #include <linux/init.h>
11 #include <linux/interrupt.h>
12 #include <linux/jiffies.h>
13 #include <linux/mm.h>
14 #include <linux/sched.h>
15 #include <linux/spinlock.h>
16 #include <linux/threads.h>
17 #include <asm/irq.h>
18 #include <asm/param.h>
19 #include <kern_util.h>
20 #include <os.h>
21 #include <timer-internal.h>
22 #include <shared/init.h>
23 
24 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
25 enum time_travel_mode time_travel_mode;
26 unsigned long long time_travel_time;
27 enum time_travel_timer_mode time_travel_timer_mode;
28 unsigned long long time_travel_timer_expiry;
29 unsigned long long time_travel_timer_interval;
30 
31 static bool time_travel_start_set;
32 static unsigned long long time_travel_start;
33 #else
34 #define time_travel_start_set 0
35 #define time_travel_start 0
36 #endif
37 
38 void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
39 {
40 	unsigned long flags;
41 
42 	if (time_travel_mode != TT_MODE_OFF)
43 		time_travel_set_time(time_travel_timer_expiry);
44 
45 	local_irq_save(flags);
46 	do_IRQ(TIMER_IRQ, regs);
47 	local_irq_restore(flags);
48 }
49 
50 static int itimer_shutdown(struct clock_event_device *evt)
51 {
52 	if (time_travel_mode != TT_MODE_OFF)
53 		time_travel_set_timer_mode(TT_TMR_DISABLED);
54 
55 	if (time_travel_mode != TT_MODE_INFCPU)
56 		os_timer_disable();
57 
58 	return 0;
59 }
60 
61 static int itimer_set_periodic(struct clock_event_device *evt)
62 {
63 	unsigned long long interval = NSEC_PER_SEC / HZ;
64 
65 	if (time_travel_mode != TT_MODE_OFF) {
66 		time_travel_set_timer_mode(TT_TMR_PERIODIC);
67 		time_travel_set_timer_expiry(time_travel_time + interval);
68 		time_travel_set_timer_interval(interval);
69 	}
70 
71 	if (time_travel_mode != TT_MODE_INFCPU)
72 		os_timer_set_interval(interval);
73 
74 	return 0;
75 }
76 
77 static int itimer_next_event(unsigned long delta,
78 			     struct clock_event_device *evt)
79 {
80 	delta += 1;
81 
82 	if (time_travel_mode != TT_MODE_OFF) {
83 		time_travel_set_timer_mode(TT_TMR_ONESHOT);
84 		time_travel_set_timer_expiry(time_travel_time + delta);
85 	}
86 
87 	if (time_travel_mode != TT_MODE_INFCPU)
88 		return os_timer_one_shot(delta);
89 
90 	return 0;
91 }
92 
93 static int itimer_one_shot(struct clock_event_device *evt)
94 {
95 	return itimer_next_event(0, evt);
96 }
97 
98 static struct clock_event_device timer_clockevent = {
99 	.name			= "posix-timer",
100 	.rating			= 250,
101 	.cpumask		= cpu_possible_mask,
102 	.features		= CLOCK_EVT_FEAT_PERIODIC |
103 				  CLOCK_EVT_FEAT_ONESHOT,
104 	.set_state_shutdown	= itimer_shutdown,
105 	.set_state_periodic	= itimer_set_periodic,
106 	.set_state_oneshot	= itimer_one_shot,
107 	.set_next_event		= itimer_next_event,
108 	.shift			= 0,
109 	.max_delta_ns		= 0xffffffff,
110 	.max_delta_ticks	= 0xffffffff,
111 	.min_delta_ns		= TIMER_MIN_DELTA,
112 	.min_delta_ticks	= TIMER_MIN_DELTA, // microsecond resolution should be enough for anyone, same as 640K RAM
113 	.irq			= 0,
114 	.mult			= 1,
115 };
116 
117 static irqreturn_t um_timer(int irq, void *dev)
118 {
119 	if (get_current()->mm != NULL)
120 	{
121         /* userspace - relay signal, results in correct userspace timers */
122 		os_alarm_process(get_current()->mm->context.id.u.pid);
123 	}
124 
125 	(*timer_clockevent.event_handler)(&timer_clockevent);
126 
127 	return IRQ_HANDLED;
128 }
129 
130 static u64 timer_read(struct clocksource *cs)
131 {
132 	if (time_travel_mode != TT_MODE_OFF) {
133 		/*
134 		 * We make reading the timer cost a bit so that we don't get
135 		 * stuck in loops that expect time to move more than the
136 		 * exact requested sleep amount, e.g. python's socket server,
137 		 * see https://bugs.python.org/issue37026.
138 		 */
139 		time_travel_set_time(time_travel_time + TIMER_MULTIPLIER);
140 		return time_travel_time / TIMER_MULTIPLIER;
141 	}
142 
143 	return os_nsecs() / TIMER_MULTIPLIER;
144 }
145 
146 static struct clocksource timer_clocksource = {
147 	.name		= "timer",
148 	.rating		= 300,
149 	.read		= timer_read,
150 	.mask		= CLOCKSOURCE_MASK(64),
151 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
152 };
153 
154 static void __init um_timer_setup(void)
155 {
156 	int err;
157 
158 	err = request_irq(TIMER_IRQ, um_timer, IRQF_TIMER, "hr timer", NULL);
159 	if (err != 0)
160 		printk(KERN_ERR "register_timer : request_irq failed - "
161 		       "errno = %d\n", -err);
162 
163 	err = os_timer_create();
164 	if (err != 0) {
165 		printk(KERN_ERR "creation of timer failed - errno = %d\n", -err);
166 		return;
167 	}
168 
169 	err = clocksource_register_hz(&timer_clocksource, NSEC_PER_SEC/TIMER_MULTIPLIER);
170 	if (err) {
171 		printk(KERN_ERR "clocksource_register_hz returned %d\n", err);
172 		return;
173 	}
174 	clockevents_register_device(&timer_clockevent);
175 }
176 
177 void read_persistent_clock64(struct timespec64 *ts)
178 {
179 	long long nsecs;
180 
181 	if (time_travel_start_set)
182 		nsecs = time_travel_start + time_travel_time;
183 	else
184 		nsecs = os_persistent_clock_emulation();
185 
186 	set_normalized_timespec64(ts, nsecs / NSEC_PER_SEC,
187 				  nsecs % NSEC_PER_SEC);
188 }
189 
190 void __init time_init(void)
191 {
192 	timer_set_signal_handler();
193 	late_time_init = um_timer_setup;
194 }
195 
196 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
197 unsigned long calibrate_delay_is_known(void)
198 {
199 	if (time_travel_mode == TT_MODE_INFCPU)
200 		return 1;
201 	return 0;
202 }
203 
204 int setup_time_travel(char *str)
205 {
206 	if (strcmp(str, "=inf-cpu") == 0) {
207 		time_travel_mode = TT_MODE_INFCPU;
208 		timer_clockevent.name = "time-travel-timer-infcpu";
209 		timer_clocksource.name = "time-travel-clock";
210 		return 1;
211 	}
212 
213 	if (!*str) {
214 		time_travel_mode = TT_MODE_BASIC;
215 		timer_clockevent.name = "time-travel-timer";
216 		timer_clocksource.name = "time-travel-clock";
217 		return 1;
218 	}
219 
220 	return -EINVAL;
221 }
222 
223 __setup("time-travel", setup_time_travel);
224 __uml_help(setup_time_travel,
225 "time-travel\n"
226 "This option just enables basic time travel mode, in which the clock/timers\n"
227 "inside the UML instance skip forward when there's nothing to do, rather than\n"
228 "waiting for real time to elapse. However, instance CPU speed is limited by\n"
229 "the real CPU speed, so e.g. a 10ms timer will always fire after ~10ms wall\n"
230 "clock (but quicker when there's nothing to do).\n"
231 "\n"
232 "time-travel=inf-cpu\n"
233 "This enables time travel mode with infinite processing power, in which there\n"
234 "are no wall clock timers, and any CPU processing happens - as seen from the\n"
235 "guest - instantly. This can be useful for accurate simulation regardless of\n"
236 "debug overhead, physical CPU speed, etc. but is somewhat dangerous as it can\n"
237 "easily lead to getting stuck (e.g. if anything in the system busy loops).\n");
238 
239 int setup_time_travel_start(char *str)
240 {
241 	int err;
242 
243 	err = kstrtoull(str, 0, &time_travel_start);
244 	if (err)
245 		return err;
246 
247 	time_travel_start_set = 1;
248 	return 1;
249 }
250 
251 __setup("time-travel-start", setup_time_travel_start);
252 __uml_help(setup_time_travel_start,
253 "time-travel-start=<seconds>\n"
254 "Configure the UML instance's wall clock to start at this value rather than\n"
255 "the host's wall clock at the time of UML boot.\n");
256 #endif
257