xref: /freebsd/sys/compat/linux/linux_timer.c (revision c989957f28ef5b03f594265612e3437c1e826ed4)
1  /*-
2   * Copyright (c) 2014 Bjoern A. Zeeb
3   * All rights reserved.
4   *
5   * This software was developed by SRI International and the University of
6   * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249
7   * ("MRC2"), as part of the DARPA MRC research programme.
8   *
9   * Redistribution and use in source and binary forms, with or without
10   * modification, are permitted provided that the following conditions
11   * are met:
12   * 1. Redistributions of source code must retain the above copyright
13   *    notice, this list of conditions and the following disclaimer.
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in the
16   *    documentation and/or other materials provided with the distribution.
17   *
18   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28   * SUCH DAMAGE.
29   */
30  
31  #include <sys/param.h>
32  #include <sys/proc.h>
33  #include <sys/signal.h>
34  #include <sys/syscallsubr.h>
35  #include <sys/time.h>
36  
37  #ifdef COMPAT_LINUX32
38  #include <machine/../linux32/linux.h>
39  #include <machine/../linux32/linux32_proto.h>
40  #else
41  #include <machine/../linux/linux.h>
42  #include <machine/../linux/linux_proto.h>
43  #endif
44  #include <compat/linux/linux_time.h>
45  
46  static int
47  linux_convert_l_sigevent(struct l_sigevent *l_sig, struct sigevent *sig)
48  {
49  
50  	CP(*l_sig, *sig, sigev_notify);
51  	switch (l_sig->sigev_notify) {
52  	case L_SIGEV_SIGNAL:
53  		if (!LINUX_SIG_VALID(l_sig->sigev_signo))
54  			return (EINVAL);
55  		sig->sigev_notify = SIGEV_SIGNAL;
56  		sig->sigev_signo = linux_to_bsd_signal(l_sig->sigev_signo);
57  		PTRIN_CP(*l_sig, *sig, sigev_value.sival_ptr);
58  		break;
59  	case L_SIGEV_NONE:
60  		sig->sigev_notify = SIGEV_NONE;
61  		break;
62  	case L_SIGEV_THREAD:
63  #if 0
64  		/* Seems to not be used anywhere (anymore)? */
65  		sig->sigev_notify = SIGEV_THREAD;
66  		return (ENOSYS);
67  #else
68  		return (EINVAL);
69  #endif
70  	case L_SIGEV_THREAD_ID:
71  		if (!LINUX_SIG_VALID(l_sig->sigev_signo))
72  			return (EINVAL);
73  		sig->sigev_notify = SIGEV_THREAD_ID;
74  		CP2(*l_sig, *sig, _l_sigev_un._tid, sigev_notify_thread_id);
75  		sig->sigev_signo = linux_to_bsd_signal(l_sig->sigev_signo);
76  		PTRIN_CP(*l_sig, *sig, sigev_value.sival_ptr);
77  		break;
78  	default:
79  		return (EINVAL);
80  	}
81  	return (0);
82  }
83  
84  int
85  linux_timer_create(struct thread *td, struct linux_timer_create_args *uap)
86  {
87  	struct l_sigevent l_ev;
88  	struct sigevent ev, *evp;
89  	clockid_t nwhich;
90  	int error, id;
91  
92  	if (uap->evp == NULL) {
93  		evp = NULL;
94  	} else {
95  		error = copyin(uap->evp, &l_ev, sizeof(l_ev));
96  		if (error != 0)
97  			return (error);
98  		error = linux_convert_l_sigevent(&l_ev, &ev);
99  		if (error != 0)
100  			return (error);
101  		evp = &ev;
102  	}
103  	error = linux_to_native_clockid(&nwhich, uap->clock_id);
104  	if (error != 0)
105  		return (error);
106  	error = kern_ktimer_create(td, nwhich, evp, &id, -1);
107  	if (error == 0) {
108  		error = copyout(&id, uap->timerid, sizeof(int));
109  		if (error != 0)
110  			kern_ktimer_delete(td, id);
111  	}
112  	return (error);
113  }
114  
115  int
116  linux_timer_settime(struct thread *td, struct linux_timer_settime_args *uap)
117  {
118  	struct l_itimerspec l_val, l_oval;
119  	struct itimerspec val, oval, *ovalp;
120  	int flags, error;
121  
122  	error = copyin(uap->new, &l_val, sizeof(l_val));
123  	if (error != 0)
124  		return (error);
125  	error = linux_to_native_itimerspec(&val, &l_val);
126  	if (error != 0)
127  		return (error);
128  	ovalp = uap->old != NULL ? &oval : NULL;
129  	error = linux_to_native_timerflags(&flags, uap->flags);
130  	if (error != 0)
131  		return (error);
132  	error = kern_ktimer_settime(td, uap->timerid, flags, &val, ovalp);
133  	if (error == 0 && uap->old != NULL) {
134  		error = native_to_linux_itimerspec(&l_val, &val);
135  		if (error == 0)
136  			error = copyout(&l_oval, uap->old, sizeof(l_oval));
137  	}
138  	return (error);
139  }
140  
141  #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
142  int
143  linux_timer_settime64(struct thread *td, struct linux_timer_settime64_args *uap)
144  {
145  	struct l_itimerspec64 l_val, l_oval;
146  	struct itimerspec val, oval, *ovalp;
147  	int flags, error;
148  
149  	error = copyin(uap->new, &l_val, sizeof(l_val));
150  	if (error != 0)
151  		return (error);
152  	error = linux_to_native_itimerspec64(&val, &l_val);
153  	if (error != 0)
154  		return (error);
155  	ovalp = uap->old != NULL ? &oval : NULL;
156  	error = linux_to_native_timerflags(&flags, uap->flags);
157  	if (error != 0)
158  		return (error);
159  	error = kern_ktimer_settime(td, uap->timerid, flags, &val, ovalp);
160  	if (error == 0 && uap->old != NULL) {
161  		error = native_to_linux_itimerspec64(&l_val, &val);
162  		if (error == 0)
163  			error = copyout(&l_oval, uap->old, sizeof(l_oval));
164  	}
165  	return (error);
166  }
167  #endif
168  
169  int
170  linux_timer_gettime(struct thread *td, struct linux_timer_gettime_args *uap)
171  {
172  	struct l_itimerspec l_val;
173  	struct itimerspec val;
174  	int error;
175  
176  	error = kern_ktimer_gettime(td, uap->timerid, &val);
177  	if (error == 0)
178  		error = native_to_linux_itimerspec(&l_val, &val);
179  	if (error == 0)
180  		error = copyout(&l_val, uap->setting, sizeof(l_val));
181  	return (error);
182  }
183  
184  #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
185  int
186  linux_timer_gettime64(struct thread *td, struct linux_timer_gettime64_args *uap)
187  {
188  	struct l_itimerspec64 l_val;
189  	struct itimerspec val;
190  	int error;
191  
192  	error = kern_ktimer_gettime(td, uap->timerid, &val);
193  	if (error == 0)
194  		error = native_to_linux_itimerspec64(&l_val, &val);
195  	if (error == 0)
196  		error = copyout(&l_val, uap->setting, sizeof(l_val));
197  	return (error);
198  }
199  #endif
200  
201  int
202  linux_timer_getoverrun(struct thread *td, struct linux_timer_getoverrun_args *uap)
203  {
204  
205  	return (kern_ktimer_getoverrun(td, uap->timerid));
206  }
207  
208  int
209  linux_timer_delete(struct thread *td, struct linux_timer_delete_args *uap)
210  {
211  
212  	return (kern_ktimer_delete(td, uap->timerid));
213  }
214