summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/um/Makefile2
-rw-r--r--arch/um/include/shared/os.h18
-rw-r--r--arch/um/include/shared/skas/stub-data.h7
-rw-r--r--arch/um/include/shared/timer-internal.h13
-rw-r--r--arch/um/kernel/process.c8
-rw-r--r--arch/um/kernel/skas/clone.c6
-rw-r--r--arch/um/kernel/skas/mmu.c3
-rw-r--r--arch/um/kernel/time.c73
-rw-r--r--arch/um/os-Linux/internal.h1
-rw-r--r--arch/um/os-Linux/main.c7
-rw-r--r--arch/um/os-Linux/process.c6
-rw-r--r--arch/um/os-Linux/signal.c41
-rw-r--r--arch/um/os-Linux/skas/process.c45
-rw-r--r--arch/um/os-Linux/time.c249
14 files changed, 255 insertions, 224 deletions
diff --git a/arch/um/Makefile b/arch/um/Makefile
index e3abe6f3156d..25ed4098640e 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -131,7 +131,7 @@ export LDS_ELF_FORMAT := $(ELF_FORMAT)
131# The wrappers will select whether using "malloc" or the kernel allocator. 131# The wrappers will select whether using "malloc" or the kernel allocator.
132LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc 132LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
133 133
134LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) 134LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) -lrt
135 135
136# Used by link-vmlinux.sh which has special support for um link 136# Used by link-vmlinux.sh which has special support for um link
137export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) 137export CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE)
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index f3cbaef20e04..868e6c3f83dd 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -1,4 +1,6 @@
1/* 1/*
2 * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
3 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
2 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL 5 * Licensed under the GPL
4 */ 6 */
@@ -183,6 +185,7 @@ extern int create_mem_file(unsigned long long len);
183/* process.c */ 185/* process.c */
184extern unsigned long os_process_pc(int pid); 186extern unsigned long os_process_pc(int pid);
185extern int os_process_parent(int pid); 187extern int os_process_parent(int pid);
188extern void os_alarm_process(int pid);
186extern void os_stop_process(int pid); 189extern void os_stop_process(int pid);
187extern void os_kill_process(int pid, int reap_child); 190extern void os_kill_process(int pid, int reap_child);
188extern void os_kill_ptraced_process(int pid, int reap_child); 191extern void os_kill_ptraced_process(int pid, int reap_child);
@@ -217,7 +220,7 @@ extern int set_umid(char *name);
217extern char *get_umid(void); 220extern char *get_umid(void);
218 221
219/* signal.c */ 222/* signal.c */
220extern void timer_init(void); 223extern void timer_set_signal_handler(void);
221extern void set_sigstack(void *sig_stack, int size); 224extern void set_sigstack(void *sig_stack, int size);
222extern void remove_sigstack(void); 225extern void remove_sigstack(void);
223extern void set_handler(int sig); 226extern void set_handler(int sig);
@@ -227,6 +230,7 @@ extern void unblock_signals(void);
227extern int get_signals(void); 230extern int get_signals(void);
228extern int set_signals(int enable); 231extern int set_signals(int enable);
229extern int os_is_signal_stack(void); 232extern int os_is_signal_stack(void);
233extern void deliver_alarm(void);
230 234
231/* util.c */ 235/* util.c */
232extern void stack_protections(unsigned long address); 236extern void stack_protections(unsigned long address);
@@ -238,12 +242,16 @@ extern void um_early_printk(const char *s, unsigned int n);
238extern void os_fix_helper_signals(void); 242extern void os_fix_helper_signals(void);
239 243
240/* time.c */ 244/* time.c */
241extern void idle_sleep(unsigned long long nsecs); 245extern void os_idle_sleep(unsigned long long nsecs);
242extern int set_interval(void); 246extern int os_timer_create(void* timer);
243extern int timer_one_shot(int ticks); 247extern int os_timer_set_interval(void* timer, void* its);
244extern long long disable_timer(void); 248extern int os_timer_one_shot(int ticks);
249extern long long os_timer_disable(void);
250extern long os_timer_remain(void* timer);
245extern void uml_idle_timer(void); 251extern void uml_idle_timer(void);
252extern long long os_persistent_clock_emulation(void);
246extern long long os_nsecs(void); 253extern long long os_nsecs(void);
254extern long long os_vnsecs(void);
247 255
248/* skas/mem.c */ 256/* skas/mem.c */
249extern long run_syscall_stub(struct mm_id * mm_idp, 257extern long run_syscall_stub(struct mm_id * mm_idp,
diff --git a/arch/um/include/shared/skas/stub-data.h b/arch/um/include/shared/skas/stub-data.h
index f6ed92c3727d..a9deece956bf 100644
--- a/arch/um/include/shared/skas/stub-data.h
+++ b/arch/um/include/shared/skas/stub-data.h
@@ -1,4 +1,6 @@
1/* 1/*
2
3 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
2 * Copyright (C) 2005 Jeff Dike (jdike@karaya.com) 4 * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL 5 * Licensed under the GPL
4 */ 6 */
@@ -6,12 +8,11 @@
6#ifndef __STUB_DATA_H 8#ifndef __STUB_DATA_H
7#define __STUB_DATA_H 9#define __STUB_DATA_H
8 10
9#include <sys/time.h> 11#include <time.h>
10 12
11struct stub_data { 13struct stub_data {
12 long offset; 14 unsigned long offset;
13 int fd; 15 int fd;
14 struct itimerval timer;
15 long err; 16 long err;
16}; 17};
17 18
diff --git a/arch/um/include/shared/timer-internal.h b/arch/um/include/shared/timer-internal.h
new file mode 100644
index 000000000000..03e6f217f807
--- /dev/null
+++ b/arch/um/include/shared/timer-internal.h
@@ -0,0 +1,13 @@
1/*
2 * Copyright (C) 2012 - 2014 Cisco Systems
3 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4 * Licensed under the GPL
5 */
6
7#ifndef __TIMER_INTERNAL_H__
8#define __TIMER_INTERNAL_H__
9
10#define TIMER_MULTIPLIER 256
11#define TIMER_MIN_DELTA 500
12
13#endif
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index a6d922672b9f..48af59aae129 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -1,4 +1,6 @@
1/* 1/*
2 * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
3 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Copyright 2003 PathScale, Inc. 5 * Copyright 2003 PathScale, Inc.
4 * Licensed under the GPL 6 * Licensed under the GPL
@@ -27,6 +29,7 @@
27#include <kern_util.h> 29#include <kern_util.h>
28#include <os.h> 30#include <os.h>
29#include <skas.h> 31#include <skas.h>
32#include <timer-internal.h>
30 33
31/* 34/*
32 * This is a per-cpu array. A processor only modifies its entry and it only 35 * This is a per-cpu array. A processor only modifies its entry and it only
@@ -203,11 +206,8 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
203 206
204void arch_cpu_idle(void) 207void arch_cpu_idle(void)
205{ 208{
206 unsigned long long nsecs;
207
208 cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); 209 cpu_tasks[current_thread_info()->cpu].pid = os_getpid();
209 nsecs = disable_timer(); 210 os_idle_sleep(UM_NSEC_PER_SEC);
210 idle_sleep(nsecs);
211 local_irq_enable(); 211 local_irq_enable();
212} 212}
213 213
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
index 289771dadf81..0f25d41b1031 100644
--- a/arch/um/kernel/skas/clone.c
+++ b/arch/um/kernel/skas/clone.c
@@ -1,4 +1,5 @@
1/* 1/*
2 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
2 * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL 4 * Licensed under the GPL
4 */ 5 */
@@ -35,11 +36,6 @@ stub_clone_handler(void)
35 if (err) 36 if (err)
36 goto out; 37 goto out;
37 38
38 err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
39 (long) &data->timer, 0);
40 if (err)
41 goto out;
42
43 remap_stack(data->fd, data->offset); 39 remap_stack(data->fd, data->offset);
44 goto done; 40 goto done;
45 41
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index fda1deba1757..9591a66aa5c5 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -1,4 +1,5 @@
1/* 1/*
2 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
2 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL 4 * Licensed under the GPL
4 */ 5 */
@@ -61,10 +62,12 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
61 if (current->mm != NULL && current->mm != &init_mm) 62 if (current->mm != NULL && current->mm != &init_mm)
62 from_mm = &current->mm->context; 63 from_mm = &current->mm->context;
63 64
65 block_signals();
64 if (from_mm) 66 if (from_mm)
65 to_mm->id.u.pid = copy_context_skas0(stack, 67 to_mm->id.u.pid = copy_context_skas0(stack,
66 from_mm->id.u.pid); 68 from_mm->id.u.pid);
67 else to_mm->id.u.pid = start_userspace(stack); 69 else to_mm->id.u.pid = start_userspace(stack);
70 unblock_signals();
68 71
69 if (to_mm->id.u.pid < 0) { 72 if (to_mm->id.u.pid < 0) {
70 ret = to_mm->id.u.pid; 73 ret = to_mm->id.u.pid;
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 5af441efb377..25c23666d592 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -1,4 +1,7 @@
1/* 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
2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 5 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL 6 * Licensed under the GPL
4 */ 7 */
@@ -7,11 +10,15 @@
7#include <linux/init.h> 10#include <linux/init.h>
8#include <linux/interrupt.h> 11#include <linux/interrupt.h>
9#include <linux/jiffies.h> 12#include <linux/jiffies.h>
13#include <linux/mm.h>
14#include <linux/sched.h>
15#include <linux/spinlock.h>
10#include <linux/threads.h> 16#include <linux/threads.h>
11#include <asm/irq.h> 17#include <asm/irq.h>
12#include <asm/param.h> 18#include <asm/param.h>
13#include <kern_util.h> 19#include <kern_util.h>
14#include <os.h> 20#include <os.h>
21#include <timer-internal.h>
15 22
16void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 23void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
17{ 24{
@@ -24,81 +31,97 @@ void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
24 31
25static int itimer_shutdown(struct clock_event_device *evt) 32static int itimer_shutdown(struct clock_event_device *evt)
26{ 33{
27 disable_timer(); 34 os_timer_disable();
28 return 0; 35 return 0;
29} 36}
30 37
31static int itimer_set_periodic(struct clock_event_device *evt) 38static int itimer_set_periodic(struct clock_event_device *evt)
32{ 39{
33 set_interval(); 40 os_timer_set_interval(NULL, NULL);
34 return 0; 41 return 0;
35} 42}
36 43
37static int itimer_next_event(unsigned long delta, 44static int itimer_next_event(unsigned long delta,
38 struct clock_event_device *evt) 45 struct clock_event_device *evt)
39{ 46{
40 return timer_one_shot(delta + 1); 47 return os_timer_one_shot(delta);
41} 48}
42 49
43static struct clock_event_device itimer_clockevent = { 50static int itimer_one_shot(struct clock_event_device *evt)
44 .name = "itimer", 51{
52 os_timer_one_shot(1);
53 return 0;
54}
55
56static struct clock_event_device timer_clockevent = {
57 .name = "posix-timer",
45 .rating = 250, 58 .rating = 250,
46 .cpumask = cpu_all_mask, 59 .cpumask = cpu_all_mask,
47 .features = CLOCK_EVT_FEAT_PERIODIC | 60 .features = CLOCK_EVT_FEAT_PERIODIC |
48 CLOCK_EVT_FEAT_ONESHOT, 61 CLOCK_EVT_FEAT_ONESHOT,
49 .set_state_shutdown = itimer_shutdown, 62 .set_state_shutdown = itimer_shutdown,
50 .set_state_periodic = itimer_set_periodic, 63 .set_state_periodic = itimer_set_periodic,
51 .set_state_oneshot = itimer_shutdown, 64 .set_state_oneshot = itimer_one_shot,
52 .set_next_event = itimer_next_event, 65 .set_next_event = itimer_next_event,
53 .shift = 32, 66 .shift = 0,
67 .max_delta_ns = 0xffffffff,
68 .min_delta_ns = TIMER_MIN_DELTA, //microsecond resolution should be enough for anyone, same as 640K RAM
54 .irq = 0, 69 .irq = 0,
70 .mult = 1,
55}; 71};
56 72
57static irqreturn_t um_timer(int irq, void *dev) 73static irqreturn_t um_timer(int irq, void *dev)
58{ 74{
59 (*itimer_clockevent.event_handler)(&itimer_clockevent); 75 if (get_current()->mm != NULL)
76 {
77 /* userspace - relay signal, results in correct userspace timers */
78 os_alarm_process(get_current()->mm->context.id.u.pid);
79 }
80
81 (*timer_clockevent.event_handler)(&timer_clockevent);
60 82
61 return IRQ_HANDLED; 83 return IRQ_HANDLED;
62} 84}
63 85
64static cycle_t itimer_read(struct clocksource *cs) 86static cycle_t timer_read(struct clocksource *cs)
65{ 87{
66 return os_nsecs() / 1000; 88 return os_nsecs() / TIMER_MULTIPLIER;
67} 89}
68 90
69static struct clocksource itimer_clocksource = { 91static struct clocksource timer_clocksource = {
70 .name = "itimer", 92 .name = "timer",
71 .rating = 300, 93 .rating = 300,
72 .read = itimer_read, 94 .read = timer_read,
73 .mask = CLOCKSOURCE_MASK(64), 95 .mask = CLOCKSOURCE_MASK(64),
74 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 96 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
75}; 97};
76 98
77static void __init setup_itimer(void) 99static void __init timer_setup(void)
78{ 100{
79 int err; 101 int err;
80 102
81 err = request_irq(TIMER_IRQ, um_timer, 0, "timer", NULL); 103 err = request_irq(TIMER_IRQ, um_timer, IRQF_TIMER, "hr timer", NULL);
82 if (err != 0) 104 if (err != 0)
83 printk(KERN_ERR "register_timer : request_irq failed - " 105 printk(KERN_ERR "register_timer : request_irq failed - "
84 "errno = %d\n", -err); 106 "errno = %d\n", -err);
85 107
86 itimer_clockevent.mult = div_sc(HZ, NSEC_PER_SEC, 32); 108 err = os_timer_create(NULL);
87 itimer_clockevent.max_delta_ns = 109 if (err != 0) {
88 clockevent_delta2ns(60 * HZ, &itimer_clockevent); 110 printk(KERN_ERR "creation of timer failed - errno = %d\n", -err);
89 itimer_clockevent.min_delta_ns = 111 return;
90 clockevent_delta2ns(1, &itimer_clockevent); 112 }
91 err = clocksource_register_hz(&itimer_clocksource, USEC_PER_SEC); 113
114 err = clocksource_register_hz(&timer_clocksource, NSEC_PER_SEC/TIMER_MULTIPLIER);
92 if (err) { 115 if (err) {
93 printk(KERN_ERR "clocksource_register_hz returned %d\n", err); 116 printk(KERN_ERR "clocksource_register_hz returned %d\n", err);
94 return; 117 return;
95 } 118 }
96 clockevents_register_device(&itimer_clockevent); 119 clockevents_register_device(&timer_clockevent);
97} 120}
98 121
99void read_persistent_clock(struct timespec *ts) 122void read_persistent_clock(struct timespec *ts)
100{ 123{
101 long long nsecs = os_nsecs(); 124 long long nsecs = os_persistent_clock_emulation();
102 125
103 set_normalized_timespec(ts, nsecs / NSEC_PER_SEC, 126 set_normalized_timespec(ts, nsecs / NSEC_PER_SEC,
104 nsecs % NSEC_PER_SEC); 127 nsecs % NSEC_PER_SEC);
@@ -106,6 +129,6 @@ void read_persistent_clock(struct timespec *ts)
106 129
107void __init time_init(void) 130void __init time_init(void)
108{ 131{
109 timer_init(); 132 timer_set_signal_handler();
110 late_time_init = setup_itimer; 133 late_time_init = timer_setup;
111} 134}
diff --git a/arch/um/os-Linux/internal.h b/arch/um/os-Linux/internal.h
deleted file mode 100644
index 0dc2c9f135f6..000000000000
--- a/arch/um/os-Linux/internal.h
+++ /dev/null
@@ -1 +0,0 @@
1void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc);
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index df9191acd926..9d499de87e63 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -1,4 +1,5 @@
1/* 1/*
2 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL 4 * Licensed under the GPL
4 */ 5 */
@@ -163,13 +164,13 @@ int __init main(int argc, char **argv, char **envp)
163 164
164 /* 165 /*
165 * This signal stuff used to be in the reboot case. However, 166 * This signal stuff used to be in the reboot case. However,
166 * sometimes a SIGVTALRM can come in when we're halting (reproducably 167 * sometimes a timer signal can come in when we're halting (reproducably
167 * when writing out gcov information, presumably because that takes 168 * when writing out gcov information, presumably because that takes
168 * some time) and cause a segfault. 169 * some time) and cause a segfault.
169 */ 170 */
170 171
171 /* stop timers and set SIGVTALRM to be ignored */ 172 /* stop timers and set timer signal to be ignored */
172 disable_timer(); 173 os_timer_disable();
173 174
174 /* disable SIGIO for the fds and set SIGIO to be ignored */ 175 /* disable SIGIO for the fds and set SIGIO to be ignored */
175 err = deactivate_all_fds(); 176 err = deactivate_all_fds();
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index 8408aba915b2..b3e0d40932e1 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -1,4 +1,5 @@
1/* 1/*
2 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
2 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL 4 * Licensed under the GPL
4 */ 5 */
@@ -89,6 +90,11 @@ int os_process_parent(int pid)
89 return parent; 90 return parent;
90} 91}
91 92
93void os_alarm_process(int pid)
94{
95 kill(pid, SIGALRM);
96}
97
92void os_stop_process(int pid) 98void os_stop_process(int pid)
93{ 99{
94 kill(pid, SIGSTOP); 100 kill(pid, SIGSTOP);
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 036d0dbc7b52..c211153ca69a 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -1,4 +1,6 @@
1/* 1/*
2 * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
3 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
2 * Copyright (C) 2004 PathScale, Inc 4 * Copyright (C) 2004 PathScale, Inc
3 * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 5 * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4 * Licensed under the GPL 6 * Licensed under the GPL
@@ -13,7 +15,6 @@
13#include <kern_util.h> 15#include <kern_util.h>
14#include <os.h> 16#include <os.h>
15#include <sysdep/mcontext.h> 17#include <sysdep/mcontext.h>
16#include "internal.h"
17 18
18void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { 19void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
19 [SIGTRAP] = relay_signal, 20 [SIGTRAP] = relay_signal,
@@ -23,7 +24,8 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
23 [SIGBUS] = bus_handler, 24 [SIGBUS] = bus_handler,
24 [SIGSEGV] = segv_handler, 25 [SIGSEGV] = segv_handler,
25 [SIGIO] = sigio_handler, 26 [SIGIO] = sigio_handler,
26 [SIGVTALRM] = timer_handler }; 27 [SIGALRM] = timer_handler
28};
27 29
28static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) 30static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
29{ 31{
@@ -38,7 +40,7 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
38 } 40 }
39 41
40 /* enable signals if sig isn't IRQ signal */ 42 /* enable signals if sig isn't IRQ signal */
41 if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) 43 if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGALRM))
42 unblock_signals(); 44 unblock_signals();
43 45
44 (*sig_info[sig])(sig, si, &r); 46 (*sig_info[sig])(sig, si, &r);
@@ -55,8 +57,8 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
55#define SIGIO_BIT 0 57#define SIGIO_BIT 0
56#define SIGIO_MASK (1 << SIGIO_BIT) 58#define SIGIO_MASK (1 << SIGIO_BIT)
57 59
58#define SIGVTALRM_BIT 1 60#define SIGALRM_BIT 1
59#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT) 61#define SIGALRM_MASK (1 << SIGALRM_BIT)
60 62
61static int signals_enabled; 63static int signals_enabled;
62static unsigned int signals_pending; 64static unsigned int signals_pending;
@@ -78,36 +80,38 @@ void sig_handler(int sig, struct siginfo *si, mcontext_t *mc)
78 set_signals(enabled); 80 set_signals(enabled);
79} 81}
80 82
81static void real_alarm_handler(mcontext_t *mc) 83static void timer_real_alarm_handler(mcontext_t *mc)
82{ 84{
83 struct uml_pt_regs regs; 85 struct uml_pt_regs regs;
84 86
85 if (mc != NULL) 87 if (mc != NULL)
86 get_regs_from_mc(&regs, mc); 88 get_regs_from_mc(&regs, mc);
87 regs.is_user = 0; 89 timer_handler(SIGALRM, NULL, &regs);
88 unblock_signals();
89 timer_handler(SIGVTALRM, NULL, &regs);
90} 90}
91 91
92void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) 92void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
93{ 93{
94 int enabled; 94 int enabled;
95 95
96 enabled = signals_enabled; 96 enabled = signals_enabled;
97 if (!signals_enabled) { 97 if (!signals_enabled) {
98 signals_pending |= SIGVTALRM_MASK; 98 signals_pending |= SIGALRM_MASK;
99 return; 99 return;
100 } 100 }
101 101
102 block_signals(); 102 block_signals();
103 103
104 real_alarm_handler(mc); 104 timer_real_alarm_handler(mc);
105 set_signals(enabled); 105 set_signals(enabled);
106} 106}
107 107
108void timer_init(void) 108void deliver_alarm(void) {
109 timer_alarm_handler(SIGALRM, NULL, NULL);
110}
111
112void timer_set_signal_handler(void)
109{ 113{
110 set_handler(SIGVTALRM); 114 set_handler(SIGALRM);
111} 115}
112 116
113void set_sigstack(void *sig_stack, int size) 117void set_sigstack(void *sig_stack, int size)
@@ -131,10 +135,9 @@ static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = {
131 135
132 [SIGIO] = sig_handler, 136 [SIGIO] = sig_handler,
133 [SIGWINCH] = sig_handler, 137 [SIGWINCH] = sig_handler,
134 [SIGVTALRM] = alarm_handler 138 [SIGALRM] = timer_alarm_handler
135}; 139};
136 140
137
138static void hard_handler(int sig, siginfo_t *si, void *p) 141static void hard_handler(int sig, siginfo_t *si, void *p)
139{ 142{
140 struct ucontext *uc = p; 143 struct ucontext *uc = p;
@@ -188,9 +191,9 @@ void set_handler(int sig)
188 191
189 /* block irq ones */ 192 /* block irq ones */
190 sigemptyset(&action.sa_mask); 193 sigemptyset(&action.sa_mask);
191 sigaddset(&action.sa_mask, SIGVTALRM);
192 sigaddset(&action.sa_mask, SIGIO); 194 sigaddset(&action.sa_mask, SIGIO);
193 sigaddset(&action.sa_mask, SIGWINCH); 195 sigaddset(&action.sa_mask, SIGWINCH);
196 sigaddset(&action.sa_mask, SIGALRM);
194 197
195 if (sig == SIGSEGV) 198 if (sig == SIGSEGV)
196 flags |= SA_NODEFER; 199 flags |= SA_NODEFER;
@@ -283,8 +286,8 @@ void unblock_signals(void)
283 if (save_pending & SIGIO_MASK) 286 if (save_pending & SIGIO_MASK)
284 sig_handler_common(SIGIO, NULL, NULL); 287 sig_handler_common(SIGIO, NULL, NULL);
285 288
286 if (save_pending & SIGVTALRM_MASK) 289 if (save_pending & SIGALRM_MASK)
287 real_alarm_handler(NULL); 290 timer_real_alarm_handler(NULL);
288 } 291 }
289} 292}
290 293
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index d38f4952d748..b856c66ebd3a 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -1,4 +1,5 @@
1/* 1/*
2 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
2 * Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3 * Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3 * Licensed under the GPL 4 * Licensed under the GPL
4 */ 5 */
@@ -45,7 +46,7 @@ static int ptrace_dump_regs(int pid)
45 * Signals that are OK to receive in the stub - we'll just continue it. 46 * Signals that are OK to receive in the stub - we'll just continue it.
46 * SIGWINCH will happen when UML is inside a detached screen. 47 * SIGWINCH will happen when UML is inside a detached screen.
47 */ 48 */
48#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH)) 49#define STUB_SIG_MASK ((1 << SIGALRM) | (1 << SIGWINCH))
49 50
50/* Signals that the stub will finish with - anything else is an error */ 51/* Signals that the stub will finish with - anything else is an error */
51#define STUB_DONE_MASK (1 << SIGTRAP) 52#define STUB_DONE_MASK (1 << SIGTRAP)
@@ -183,19 +184,13 @@ extern char __syscall_stub_start[];
183static int userspace_tramp(void *stack) 184static int userspace_tramp(void *stack)
184{ 185{
185 void *addr; 186 void *addr;
186 int err, fd; 187 int fd;
187 unsigned long long offset; 188 unsigned long long offset;
188 189
189 ptrace(PTRACE_TRACEME, 0, 0, 0); 190 ptrace(PTRACE_TRACEME, 0, 0, 0);
190 191
191 signal(SIGTERM, SIG_DFL); 192 signal(SIGTERM, SIG_DFL);
192 signal(SIGWINCH, SIG_IGN); 193 signal(SIGWINCH, SIG_IGN);
193 err = set_interval();
194 if (err) {
195 printk(UM_KERN_ERR "userspace_tramp - setting timer failed, "
196 "errno = %d\n", err);
197 exit(1);
198 }
199 194
200 /* 195 /*
201 * This has a pte, but it can't be mapped in with the usual 196 * This has a pte, but it can't be mapped in with the usual
@@ -286,7 +281,7 @@ int start_userspace(unsigned long stub_stack)
286 "errno = %d\n", errno); 281 "errno = %d\n", errno);
287 goto out_kill; 282 goto out_kill;
288 } 283 }
289 } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); 284 } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGALRM));
290 285
291 if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) { 286 if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) {
292 err = -EINVAL; 287 err = -EINVAL;
@@ -319,8 +314,6 @@ int start_userspace(unsigned long stub_stack)
319 314
320void userspace(struct uml_pt_regs *regs) 315void userspace(struct uml_pt_regs *regs)
321{ 316{
322 struct itimerval timer;
323 unsigned long long nsecs, now;
324 int err, status, op, pid = userspace_pid[0]; 317 int err, status, op, pid = userspace_pid[0];
325 /* To prevent races if using_sysemu changes under us.*/ 318 /* To prevent races if using_sysemu changes under us.*/
326 int local_using_sysemu; 319 int local_using_sysemu;
@@ -329,13 +322,8 @@ void userspace(struct uml_pt_regs *regs)
329 /* Handle any immediate reschedules or signals */ 322 /* Handle any immediate reschedules or signals */
330 interrupt_end(); 323 interrupt_end();
331 324
332 if (getitimer(ITIMER_VIRTUAL, &timer))
333 printk(UM_KERN_ERR "Failed to get itimer, errno = %d\n", errno);
334 nsecs = timer.it_value.tv_sec * UM_NSEC_PER_SEC +
335 timer.it_value.tv_usec * UM_NSEC_PER_USEC;
336 nsecs += os_nsecs();
337
338 while (1) { 325 while (1) {
326
339 /* 327 /*
340 * This can legitimately fail if the process loads a 328 * This can legitimately fail if the process loads a
341 * bogus value into a segment register. It will 329 * bogus value into a segment register. It will
@@ -405,18 +393,7 @@ void userspace(struct uml_pt_regs *regs)
405 case SIGTRAP: 393 case SIGTRAP:
406 relay_signal(SIGTRAP, (struct siginfo *)&si, regs); 394 relay_signal(SIGTRAP, (struct siginfo *)&si, regs);
407 break; 395 break;
408 case SIGVTALRM: 396 case SIGALRM:
409 now = os_nsecs();
410 if (now < nsecs)
411 break;
412 block_signals();
413 (*sig_info[sig])(sig, (struct siginfo *)&si, regs);
414 unblock_signals();
415 nsecs = timer.it_value.tv_sec *
416 UM_NSEC_PER_SEC +
417 timer.it_value.tv_usec *
418 UM_NSEC_PER_USEC;
419 nsecs += os_nsecs();
420 break; 397 break;
421 case SIGIO: 398 case SIGIO:
422 case SIGILL: 399 case SIGILL:
@@ -464,7 +441,6 @@ __initcall(init_thread_regs);
464 441
465int copy_context_skas0(unsigned long new_stack, int pid) 442int copy_context_skas0(unsigned long new_stack, int pid)
466{ 443{
467 struct timeval tv = { .tv_sec = 0, .tv_usec = UM_USEC_PER_SEC / UM_HZ };
468 int err; 444 int err;
469 unsigned long current_stack = current_stub_stack(); 445 unsigned long current_stack = current_stub_stack();
470 struct stub_data *data = (struct stub_data *) current_stack; 446 struct stub_data *data = (struct stub_data *) current_stack;
@@ -476,11 +452,10 @@ int copy_context_skas0(unsigned long new_stack, int pid)
476 * prepare offset and fd of child's stack as argument for parent's 452 * prepare offset and fd of child's stack as argument for parent's
477 * and child's mmap2 calls 453 * and child's mmap2 calls
478 */ 454 */
479 *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset), 455 *data = ((struct stub_data) {
480 .fd = new_fd, 456 .offset = MMAP_OFFSET(new_offset),
481 .timer = ((struct itimerval) 457 .fd = new_fd
482 { .it_value = tv, 458 });
483 .it_interval = tv }) });
484 459
485 err = ptrace_setregs(pid, thread_regs); 460 err = ptrace_setregs(pid, thread_regs);
486 if (err < 0) { 461 if (err < 0) {
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index e9824d5dd7d5..0e39b9978729 100644
--- a/arch/um/os-Linux/time.c
+++ b/arch/um/os-Linux/time.c
@@ -1,4 +1,7 @@
1/* 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
2 * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com) 5 * Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com)
3 * Licensed under the GPL 6 * Licensed under the GPL
4 */ 7 */
@@ -10,177 +13,177 @@
10#include <sys/time.h> 13#include <sys/time.h>
11#include <kern_util.h> 14#include <kern_util.h>
12#include <os.h> 15#include <os.h>
13#include "internal.h" 16#include <string.h>
17#include <timer-internal.h>
14 18
15int set_interval(void) 19static timer_t event_high_res_timer = 0;
16{
17 int usec = UM_USEC_PER_SEC / UM_HZ;
18 struct itimerval interval = ((struct itimerval) { { 0, usec },
19 { 0, usec } });
20
21 if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
22 return -errno;
23 20
24 return 0; 21static inline long long timeval_to_ns(const struct timeval *tv)
22{
23 return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) +
24 tv->tv_usec * UM_NSEC_PER_USEC;
25} 25}
26 26
27int timer_one_shot(int ticks) 27static inline long long timespec_to_ns(const struct timespec *ts)
28{ 28{
29 unsigned long usec = ticks * UM_USEC_PER_SEC / UM_HZ; 29 return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) +
30 unsigned long sec = usec / UM_USEC_PER_SEC; 30 ts->tv_nsec;
31 struct itimerval interval; 31}
32
33 usec %= UM_USEC_PER_SEC;
34 interval = ((struct itimerval) { { 0, 0 }, { sec, usec } });
35 32
36 if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) 33long long os_persistent_clock_emulation (void) {
37 return -errno; 34 struct timespec realtime_tp;
38 35
39 return 0; 36 clock_gettime(CLOCK_REALTIME, &realtime_tp);
37 return timespec_to_ns(&realtime_tp);
40} 38}
41 39
42/** 40/**
43 * timeval_to_ns - Convert timeval to nanoseconds 41 * os_timer_create() - create an new posix (interval) timer
44 * @ts: pointer to the timeval variable to be converted
45 *
46 * Returns the scalar nanosecond representation of the timeval
47 * parameter.
48 *
49 * Ripped from linux/time.h because it's a kernel header, and thus
50 * unusable from here.
51 */ 42 */
52static inline long long timeval_to_ns(const struct timeval *tv) 43int os_timer_create(void* timer) {
53{ 44
54 return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) + 45 timer_t* t = timer;
55 tv->tv_usec * UM_NSEC_PER_USEC; 46
47 if(t == NULL) {
48 t = &event_high_res_timer;
49 }
50
51 if (timer_create(
52 CLOCK_MONOTONIC,
53 NULL,
54 t) == -1) {
55 return -1;
56 }
57 return 0;
56} 58}
57 59
58long long disable_timer(void) 60int os_timer_set_interval(void* timer, void* i)
59{ 61{
60 struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } }); 62 struct itimerspec its;
61 long long remain, max = UM_NSEC_PER_SEC / UM_HZ; 63 unsigned long long nsec;
64 timer_t* t = timer;
65 struct itimerspec* its_in = i;
62 66
63 if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0) 67 if(t == NULL) {
64 printk(UM_KERN_ERR "disable_timer - setitimer failed, " 68 t = &event_high_res_timer;
65 "errno = %d\n", errno); 69 }
66 70
67 remain = timeval_to_ns(&time.it_value); 71 nsec = UM_NSEC_PER_SEC / UM_HZ;
68 if (remain > max)
69 remain = max;
70 72
71 return remain; 73 if(its_in != NULL) {
72} 74 its.it_value.tv_sec = its_in->it_value.tv_sec;
75 its.it_value.tv_nsec = its_in->it_value.tv_nsec;
76 } else {
77 its.it_value.tv_sec = 0;
78 its.it_value.tv_nsec = nsec;
79 }
73 80
74long long os_nsecs(void) 81 its.it_interval.tv_sec = 0;
75{ 82 its.it_interval.tv_nsec = nsec;
76 struct timeval tv;
77 83
78 gettimeofday(&tv, NULL); 84 if(timer_settime(*t, 0, &its, NULL) == -1) {
79 return timeval_to_ns(&tv); 85 return -errno;
80} 86 }
81 87
82#ifdef UML_CONFIG_NO_HZ_COMMON
83static int after_sleep_interval(struct timespec *ts)
84{
85 return 0; 88 return 0;
86} 89}
87 90
88static void deliver_alarm(void) 91/**
92 * os_timer_remain() - returns the remaining nano seconds of the given interval
93 * timer
94 * Because this is the remaining time of an interval timer, which correspondends
95 * to HZ, this value can never be bigger than one second. Just
96 * the nanosecond part of the timer is returned.
97 * The returned time is relative to the start time of the interval timer.
98 * Return an negative value in an error case.
99 */
100long os_timer_remain(void* timer)
89{ 101{
90 alarm_handler(SIGVTALRM, NULL, NULL); 102 struct itimerspec its;
91} 103 timer_t* t = timer;
92 104
93static unsigned long long sleep_time(unsigned long long nsecs) 105 if(t == NULL) {
94{ 106 t = &event_high_res_timer;
95 return nsecs; 107 }
96}
97 108
98#else 109 if(timer_gettime(t, &its) == -1) {
99unsigned long long last_tick; 110 return -errno;
100unsigned long long skew; 111 }
101 112
102static void deliver_alarm(void) 113 return its.it_value.tv_nsec;
103{ 114}
104 unsigned long long this_tick = os_nsecs();
105 int one_tick = UM_NSEC_PER_SEC / UM_HZ;
106 115
107 /* Protection against the host's time going backwards */ 116int os_timer_one_shot(int ticks)
108 if ((last_tick != 0) && (this_tick < last_tick)) 117{
109 this_tick = last_tick; 118 struct itimerspec its;
119 unsigned long long nsec;
120 unsigned long sec;
110 121
111 if (last_tick == 0) 122 nsec = (ticks + 1);
112 last_tick = this_tick - one_tick; 123 sec = nsec / UM_NSEC_PER_SEC;
124 nsec = nsec % UM_NSEC_PER_SEC;
113 125
114 skew += this_tick - last_tick; 126 its.it_value.tv_sec = nsec / UM_NSEC_PER_SEC;
127 its.it_value.tv_nsec = nsec;
115 128
116 while (skew >= one_tick) { 129 its.it_interval.tv_sec = 0;
117 alarm_handler(SIGVTALRM, NULL, NULL); 130 its.it_interval.tv_nsec = 0; // we cheat here
118 skew -= one_tick;
119 }
120 131
121 last_tick = this_tick; 132 timer_settime(event_high_res_timer, 0, &its, NULL);
133 return 0;
122} 134}
123 135
124static unsigned long long sleep_time(unsigned long long nsecs) 136/**
137 * os_timer_disable() - disable the posix (interval) timer
138 * Returns the remaining interval timer time in nanoseconds
139 */
140long long os_timer_disable(void)
125{ 141{
126 return nsecs > skew ? nsecs - skew : 0; 142 struct itimerspec its;
127}
128 143
129static inline long long timespec_to_us(const struct timespec *ts) 144 memset(&its, 0, sizeof(struct itimerspec));
130{ 145 timer_settime(event_high_res_timer, 0, &its, &its);
131 return ((long long) ts->tv_sec * UM_USEC_PER_SEC) + 146
132 ts->tv_nsec / UM_NSEC_PER_USEC; 147 return its.it_value.tv_sec * UM_NSEC_PER_SEC + its.it_value.tv_nsec;
133} 148}
134 149
135static int after_sleep_interval(struct timespec *ts) 150long long os_vnsecs(void)
136{ 151{
137 int usec = UM_USEC_PER_SEC / UM_HZ; 152 struct timespec ts;
138 long long start_usecs = timespec_to_us(ts);
139 struct timeval tv;
140 struct itimerval interval;
141
142 /*
143 * It seems that rounding can increase the value returned from
144 * setitimer to larger than the one passed in. Over time,
145 * this will cause the remaining time to be greater than the
146 * tick interval. If this happens, then just reduce the first
147 * tick to the interval value.
148 */
149 if (start_usecs > usec)
150 start_usecs = usec;
151
152 start_usecs -= skew / UM_NSEC_PER_USEC;
153 if (start_usecs < 0)
154 start_usecs = 0;
155 153
156 tv = ((struct timeval) { .tv_sec = start_usecs / UM_USEC_PER_SEC, 154 clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ts);
157 .tv_usec = start_usecs % UM_USEC_PER_SEC }); 155 return timespec_to_ns(&ts);
158 interval = ((struct itimerval) { { 0, usec }, tv }); 156}
159 157
160 if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1) 158long long os_nsecs(void)
161 return -errno; 159{
160 struct timespec ts;
162 161
163 return 0; 162 clock_gettime(CLOCK_MONOTONIC,&ts);
163 return timespec_to_ns(&ts);
164} 164}
165#endif
166 165
167void idle_sleep(unsigned long long nsecs) 166/**
167 * os_idle_sleep() - sleep for a given time of nsecs
168 * @nsecs: nanoseconds to sleep
169 */
170void os_idle_sleep(unsigned long long nsecs)
168{ 171{
169 struct timespec ts; 172 struct timespec ts;
170 173
171 /* 174 if (nsecs <= 0) {
172 * nsecs can come in as zero, in which case, this starts a 175 return;
173 * busy loop. To prevent this, reset nsecs to the tick 176 }
174 * interval if it is zero.
175 */
176 if (nsecs == 0)
177 nsecs = UM_NSEC_PER_SEC / UM_HZ;
178 177
179 nsecs = sleep_time(nsecs); 178 ts = ((struct timespec) {
180 ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC, 179 .tv_sec = nsecs / UM_NSEC_PER_SEC,
181 .tv_nsec = nsecs % UM_NSEC_PER_SEC }); 180 .tv_nsec = nsecs % UM_NSEC_PER_SEC
181 });
182 182
183 if (nanosleep(&ts, &ts) == 0) 183 /*
184 * Relay the signal if clock_nanosleep is interrupted.
185 */
186 if (clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL)) {
184 deliver_alarm(); 187 deliver_alarm();
185 after_sleep_interval(&ts); 188 }
186} 189}