1*a563ca70SAlex Hornung /*
2*a563ca70SAlex Hornung * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
3*a563ca70SAlex Hornung * All rights reserved.
4*a563ca70SAlex Hornung *
5*a563ca70SAlex Hornung * Redistribution and use in source and binary forms, with or without
6*a563ca70SAlex Hornung * modification, are permitted provided that the following conditions
7*a563ca70SAlex Hornung * are met:
8*a563ca70SAlex Hornung *
9*a563ca70SAlex Hornung * 1. Redistributions of source code must retain the above copyright
10*a563ca70SAlex Hornung * notice, this list of conditions and the following disclaimer.
11*a563ca70SAlex Hornung * 2. Redistributions in binary form must reproduce the above copyright
12*a563ca70SAlex Hornung * notice, this list of conditions and the following disclaimer in
13*a563ca70SAlex Hornung * the documentation and/or other materials provided with the
14*a563ca70SAlex Hornung * distribution.
15*a563ca70SAlex Hornung *
16*a563ca70SAlex Hornung * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17*a563ca70SAlex Hornung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18*a563ca70SAlex Hornung * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19*a563ca70SAlex Hornung * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20*a563ca70SAlex Hornung * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21*a563ca70SAlex Hornung * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22*a563ca70SAlex Hornung * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23*a563ca70SAlex Hornung * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24*a563ca70SAlex Hornung * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25*a563ca70SAlex Hornung * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26*a563ca70SAlex Hornung * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*a563ca70SAlex Hornung * SUCH DAMAGE.
28*a563ca70SAlex Hornung */
29*a563ca70SAlex Hornung
30*a563ca70SAlex Hornung #include <sys/param.h>
31*a563ca70SAlex Hornung #include <sys/systm.h>
32*a563ca70SAlex Hornung #include <sys/kernel.h>
33*a563ca70SAlex Hornung #include <sys/proc.h>
34*a563ca70SAlex Hornung #include <sys/conf.h>
35*a563ca70SAlex Hornung #include <sys/malloc.h>
36*a563ca70SAlex Hornung #include <machine/md_var.h>
37*a563ca70SAlex Hornung #include <sys/ctype.h>
38*a563ca70SAlex Hornung #include <sys/kthread.h>
39*a563ca70SAlex Hornung #include <sys/device.h>
40*a563ca70SAlex Hornung #include <sys/fcntl.h>
41*a563ca70SAlex Hornung #include <sys/module.h>
42*a563ca70SAlex Hornung #include <libprop/proplib.h>
43*a563ca70SAlex Hornung #include <sys/tbridge.h>
44*a563ca70SAlex Hornung
45*a563ca70SAlex Hornung static cdev_t tbridge_dev;
46*a563ca70SAlex Hornung static d_open_t tbridge_dev_open;
47*a563ca70SAlex Hornung static d_close_t tbridge_dev_close;
48*a563ca70SAlex Hornung static d_ioctl_t tbridge_dev_ioctl;
49*a563ca70SAlex Hornung
50*a563ca70SAlex Hornung
51*a563ca70SAlex Hornung static struct dev_ops tbridge_dev_ops = {
52*a563ca70SAlex Hornung { "tbridge", 0, 0 },
53*a563ca70SAlex Hornung .d_open = tbridge_dev_open,
54*a563ca70SAlex Hornung .d_close = tbridge_dev_close,
55*a563ca70SAlex Hornung .d_ioctl = tbridge_dev_ioctl
56*a563ca70SAlex Hornung };
57*a563ca70SAlex Hornung
58*a563ca70SAlex Hornung static struct tbridge_testcase *tbridge_curtest = NULL;
59*a563ca70SAlex Hornung static prop_dictionary_t tbridge_testcase = NULL;
60*a563ca70SAlex Hornung static int tbridge_result_ready = 0;
61*a563ca70SAlex Hornung static char tbridge_msgbuf[131072]; /* 128 kB message buffer */
62*a563ca70SAlex Hornung static char *tbridge_msgbuf_ptr;
63*a563ca70SAlex Hornung size_t tbridge_msgbuf_remsz;
64*a563ca70SAlex Hornung
65*a563ca70SAlex Hornung static prop_dictionary_t
testcase_get_result_dict(prop_dictionary_t testcase)66*a563ca70SAlex Hornung testcase_get_result_dict(prop_dictionary_t testcase)
67*a563ca70SAlex Hornung {
68*a563ca70SAlex Hornung prop_dictionary_t result_dict;
69*a563ca70SAlex Hornung int r;
70*a563ca70SAlex Hornung
71*a563ca70SAlex Hornung result_dict = prop_dictionary_get(testcase, "result");
72*a563ca70SAlex Hornung if (result_dict == NULL) {
73*a563ca70SAlex Hornung result_dict = prop_dictionary_create();
74*a563ca70SAlex Hornung if (result_dict == NULL) {
75*a563ca70SAlex Hornung kprintf("could not allocate new result dict");
76*a563ca70SAlex Hornung return NULL;
77*a563ca70SAlex Hornung }
78*a563ca70SAlex Hornung
79*a563ca70SAlex Hornung r = prop_dictionary_set(testcase, "result", result_dict);
80*a563ca70SAlex Hornung if (r == 0) {
81*a563ca70SAlex Hornung kprintf("prop_dictionary operation failed");
82*a563ca70SAlex Hornung return NULL;
83*a563ca70SAlex Hornung }
84*a563ca70SAlex Hornung }
85*a563ca70SAlex Hornung
86*a563ca70SAlex Hornung return result_dict;
87*a563ca70SAlex Hornung }
88*a563ca70SAlex Hornung
89*a563ca70SAlex Hornung static int
testcase_get_timeout(prop_dictionary_t testcase)90*a563ca70SAlex Hornung testcase_get_timeout(prop_dictionary_t testcase)
91*a563ca70SAlex Hornung {
92*a563ca70SAlex Hornung int32_t val;
93*a563ca70SAlex Hornung int r;
94*a563ca70SAlex Hornung
95*a563ca70SAlex Hornung r = prop_dictionary_get_int32(prop_dictionary_get(testcase, "opts"),
96*a563ca70SAlex Hornung "timeout_in_secs", &val);
97*a563ca70SAlex Hornung if (r == 0)
98*a563ca70SAlex Hornung val = 600/* default timeout = 10min */;
99*a563ca70SAlex Hornung
100*a563ca70SAlex Hornung return val;
101*a563ca70SAlex Hornung }
102*a563ca70SAlex Hornung
103*a563ca70SAlex Hornung static int
testcase_set_stdout_buf(prop_dictionary_t testcase,const char * buf)104*a563ca70SAlex Hornung testcase_set_stdout_buf(prop_dictionary_t testcase, const char *buf)
105*a563ca70SAlex Hornung {
106*a563ca70SAlex Hornung prop_dictionary_t dict = testcase_get_result_dict(testcase);
107*a563ca70SAlex Hornung
108*a563ca70SAlex Hornung return !prop_dictionary_set_cstring(dict, "stdout_buf", buf);
109*a563ca70SAlex Hornung }
110*a563ca70SAlex Hornung
111*a563ca70SAlex Hornung static int
testcase_set_result(prop_dictionary_t testcase,int result)112*a563ca70SAlex Hornung testcase_set_result(prop_dictionary_t testcase, int result)
113*a563ca70SAlex Hornung {
114*a563ca70SAlex Hornung prop_dictionary_t dict = testcase_get_result_dict(testcase);
115*a563ca70SAlex Hornung
116*a563ca70SAlex Hornung return !prop_dictionary_set_int32(dict, "result", result);
117*a563ca70SAlex Hornung }
118*a563ca70SAlex Hornung
119*a563ca70SAlex Hornung static const char *
testcase_get_name(prop_dictionary_t testcase)120*a563ca70SAlex Hornung testcase_get_name(prop_dictionary_t testcase)
121*a563ca70SAlex Hornung {
122*a563ca70SAlex Hornung const char *str;
123*a563ca70SAlex Hornung int r;
124*a563ca70SAlex Hornung
125*a563ca70SAlex Hornung r = prop_dictionary_get_cstring_nocopy(testcase, "name", &str);
126*a563ca70SAlex Hornung if (r == 0)
127*a563ca70SAlex Hornung str = "???";
128*a563ca70SAlex Hornung
129*a563ca70SAlex Hornung return str;
130*a563ca70SAlex Hornung }
131*a563ca70SAlex Hornung
132*a563ca70SAlex Hornung int
tbridge_printf(const char * fmt,...)133*a563ca70SAlex Hornung tbridge_printf(const char *fmt, ...)
134*a563ca70SAlex Hornung {
135*a563ca70SAlex Hornung __va_list args;
136*a563ca70SAlex Hornung int i;
137*a563ca70SAlex Hornung
138*a563ca70SAlex Hornung __va_start(args,fmt);
139*a563ca70SAlex Hornung i = kvsnprintf(tbridge_msgbuf_ptr, tbridge_msgbuf_remsz, fmt, args);
140*a563ca70SAlex Hornung __va_end(args);
141*a563ca70SAlex Hornung
142*a563ca70SAlex Hornung tbridge_msgbuf_ptr += i;
143*a563ca70SAlex Hornung tbridge_msgbuf_remsz -= i;
144*a563ca70SAlex Hornung
145*a563ca70SAlex Hornung return i;
146*a563ca70SAlex Hornung }
147*a563ca70SAlex Hornung
148*a563ca70SAlex Hornung static int
tbridge_register(struct tbridge_testcase * test)149*a563ca70SAlex Hornung tbridge_register(struct tbridge_testcase *test)
150*a563ca70SAlex Hornung {
151*a563ca70SAlex Hornung if (tbridge_curtest != NULL)
152*a563ca70SAlex Hornung return EBUSY;
153*a563ca70SAlex Hornung
154*a563ca70SAlex Hornung tbridge_curtest = test;
155*a563ca70SAlex Hornung
156*a563ca70SAlex Hornung return 0;
157*a563ca70SAlex Hornung }
158*a563ca70SAlex Hornung
159*a563ca70SAlex Hornung static int
tbridge_unregister(void)160*a563ca70SAlex Hornung tbridge_unregister(void)
161*a563ca70SAlex Hornung {
162*a563ca70SAlex Hornung tbridge_curtest = NULL;
163*a563ca70SAlex Hornung
164*a563ca70SAlex Hornung return 0;
165*a563ca70SAlex Hornung }
166*a563ca70SAlex Hornung
167*a563ca70SAlex Hornung int
tbridge_testcase_modhandler(module_t mod,int type,void * arg)168*a563ca70SAlex Hornung tbridge_testcase_modhandler(module_t mod, int type, void *arg)
169*a563ca70SAlex Hornung {
170*a563ca70SAlex Hornung struct tbridge_testcase *tcase = (struct tbridge_testcase *)arg;
171*a563ca70SAlex Hornung int error = 0;
172*a563ca70SAlex Hornung
173*a563ca70SAlex Hornung switch (type) {
174*a563ca70SAlex Hornung case MOD_LOAD:
175*a563ca70SAlex Hornung error = tbridge_register(tcase);
176*a563ca70SAlex Hornung break;
177*a563ca70SAlex Hornung
178*a563ca70SAlex Hornung case MOD_UNLOAD:
179*a563ca70SAlex Hornung if (tcase->tb_abort != NULL)
180*a563ca70SAlex Hornung error = tcase->tb_abort();
181*a563ca70SAlex Hornung
182*a563ca70SAlex Hornung if (!error)
183*a563ca70SAlex Hornung tbridge_unregister();
184*a563ca70SAlex Hornung break;
185*a563ca70SAlex Hornung
186*a563ca70SAlex Hornung default:
187*a563ca70SAlex Hornung break;
188*a563ca70SAlex Hornung }
189*a563ca70SAlex Hornung
190*a563ca70SAlex Hornung return error;
191*a563ca70SAlex Hornung }
192*a563ca70SAlex Hornung
193*a563ca70SAlex Hornung void
tbridge_test_done(int result)194*a563ca70SAlex Hornung tbridge_test_done(int result)
195*a563ca70SAlex Hornung {
196*a563ca70SAlex Hornung KKASSERT(tbridge_testcase != NULL);
197*a563ca70SAlex Hornung
198*a563ca70SAlex Hornung kprintf("testcase '%s' called test_done with result=%d\n",
199*a563ca70SAlex Hornung testcase_get_name(tbridge_testcase), result);
200*a563ca70SAlex Hornung
201*a563ca70SAlex Hornung testcase_set_result(tbridge_testcase, result);
202*a563ca70SAlex Hornung testcase_set_stdout_buf(tbridge_testcase, tbridge_msgbuf);
203*a563ca70SAlex Hornung
204*a563ca70SAlex Hornung tbridge_result_ready = 1;
205*a563ca70SAlex Hornung wakeup(&tbridge_result_ready);
206*a563ca70SAlex Hornung }
207*a563ca70SAlex Hornung
208*a563ca70SAlex Hornung static void
tbridge_reset(void)209*a563ca70SAlex Hornung tbridge_reset(void)
210*a563ca70SAlex Hornung {
211*a563ca70SAlex Hornung tbridge_msgbuf_ptr = tbridge_msgbuf;
212*a563ca70SAlex Hornung tbridge_msgbuf_remsz = sizeof(tbridge_msgbuf);
213*a563ca70SAlex Hornung
214*a563ca70SAlex Hornung if (tbridge_testcase != NULL) {
215*a563ca70SAlex Hornung prop_object_release(tbridge_testcase);
216*a563ca70SAlex Hornung tbridge_testcase = NULL;
217*a563ca70SAlex Hornung }
218*a563ca70SAlex Hornung
219*a563ca70SAlex Hornung safemem_reset_error_count();
220*a563ca70SAlex Hornung tbridge_result_ready = 0;
221*a563ca70SAlex Hornung }
222*a563ca70SAlex Hornung
223*a563ca70SAlex Hornung
224*a563ca70SAlex Hornung /*
225*a563ca70SAlex Hornung * dev stuff
226*a563ca70SAlex Hornung */
227*a563ca70SAlex Hornung static int
tbridge_dev_open(struct dev_open_args * ap)228*a563ca70SAlex Hornung tbridge_dev_open(struct dev_open_args *ap)
229*a563ca70SAlex Hornung {
230*a563ca70SAlex Hornung return 0;
231*a563ca70SAlex Hornung }
232*a563ca70SAlex Hornung
233*a563ca70SAlex Hornung static int
tbridge_dev_close(struct dev_close_args * ap)234*a563ca70SAlex Hornung tbridge_dev_close(struct dev_close_args *ap)
235*a563ca70SAlex Hornung {
236*a563ca70SAlex Hornung return 0;
237*a563ca70SAlex Hornung }
238*a563ca70SAlex Hornung
239*a563ca70SAlex Hornung static int
tbridge_dev_ioctl(struct dev_ioctl_args * ap)240*a563ca70SAlex Hornung tbridge_dev_ioctl(struct dev_ioctl_args *ap)
241*a563ca70SAlex Hornung {
242*a563ca70SAlex Hornung struct plistref *pref;
243*a563ca70SAlex Hornung struct thread *td;
244*a563ca70SAlex Hornung int error, r;
245*a563ca70SAlex Hornung
246*a563ca70SAlex Hornung error = 0;
247*a563ca70SAlex Hornung
248*a563ca70SAlex Hornung /* Use proplib(3) for userspace/kernel communication */
249*a563ca70SAlex Hornung pref = (struct plistref *)ap->a_data;
250*a563ca70SAlex Hornung
251*a563ca70SAlex Hornung switch(ap->a_cmd) {
252*a563ca70SAlex Hornung case TBRIDGE_LOADTEST:
253*a563ca70SAlex Hornung tbridge_reset();
254*a563ca70SAlex Hornung
255*a563ca70SAlex Hornung if (tbridge_curtest == NULL)
256*a563ca70SAlex Hornung return EINVAL;
257*a563ca70SAlex Hornung
258*a563ca70SAlex Hornung error = prop_dictionary_copyin_ioctl(pref, ap->a_cmd,
259*a563ca70SAlex Hornung &tbridge_testcase);
260*a563ca70SAlex Hornung if (error)
261*a563ca70SAlex Hornung return error;
262*a563ca70SAlex Hornung
263*a563ca70SAlex Hornung break;
264*a563ca70SAlex Hornung
265*a563ca70SAlex Hornung case TBRIDGE_GETRESULT:
266*a563ca70SAlex Hornung error = kthread_create(tbridge_curtest->tb_run, NULL, &td,
267*a563ca70SAlex Hornung "testrunner");
268*a563ca70SAlex Hornung if (error)
269*a563ca70SAlex Hornung tbridge_test_done(RESULT_PREFAIL);
270*a563ca70SAlex Hornung
271*a563ca70SAlex Hornung /* The following won't be called if the thread wasn't created */
272*a563ca70SAlex Hornung if (!tbridge_result_ready) {
273*a563ca70SAlex Hornung r = tsleep(&tbridge_result_ready, 0, "tbridgeres",
274*a563ca70SAlex Hornung hz * testcase_get_timeout(tbridge_testcase));
275*a563ca70SAlex Hornung if (r != 0) {
276*a563ca70SAlex Hornung if (tbridge_curtest->tb_abort != NULL)
277*a563ca70SAlex Hornung tbridge_curtest->tb_abort();
278*a563ca70SAlex Hornung
279*a563ca70SAlex Hornung tbridge_test_done(RESULT_TIMEOUT);
280*a563ca70SAlex Hornung }
281*a563ca70SAlex Hornung }
282*a563ca70SAlex Hornung
283*a563ca70SAlex Hornung if (safemem_get_error_count() != 0) {
284*a563ca70SAlex Hornung /*
285*a563ca70SAlex Hornung * If there were any double-frees or buffer over- or
286*a563ca70SAlex Hornung * underflows, we mark the result as 'signalled', i.e.
287*a563ca70SAlex Hornung * the equivalent of a SIGSEGV/SIGBUS in userland.
288*a563ca70SAlex Hornung */
289*a563ca70SAlex Hornung testcase_set_result(tbridge_testcase, RESULT_SIGNALLED);
290*a563ca70SAlex Hornung }
291*a563ca70SAlex Hornung
292*a563ca70SAlex Hornung error = prop_dictionary_copyout_ioctl(pref, ap->a_cmd,
293*a563ca70SAlex Hornung tbridge_testcase);
294*a563ca70SAlex Hornung if (error)
295*a563ca70SAlex Hornung return error;
296*a563ca70SAlex Hornung
297*a563ca70SAlex Hornung break;
298*a563ca70SAlex Hornung default:
299*a563ca70SAlex Hornung error = ENOTTY; /* Inappropriate ioctl for device */
300*a563ca70SAlex Hornung break;
301*a563ca70SAlex Hornung }
302*a563ca70SAlex Hornung
303*a563ca70SAlex Hornung return(error);
304*a563ca70SAlex Hornung }
305*a563ca70SAlex Hornung
306*a563ca70SAlex Hornung
307*a563ca70SAlex Hornung static int
testbridge_modevent(module_t mod,int type,void * unused)308*a563ca70SAlex Hornung testbridge_modevent(module_t mod, int type, void *unused)
309*a563ca70SAlex Hornung {
310*a563ca70SAlex Hornung switch (type) {
311*a563ca70SAlex Hornung case MOD_LOAD:
312*a563ca70SAlex Hornung tbridge_dev = make_dev(&tbridge_dev_ops,
313*a563ca70SAlex Hornung 0,
314*a563ca70SAlex Hornung UID_ROOT,
315*a563ca70SAlex Hornung GID_WHEEL,
316*a563ca70SAlex Hornung 0600,
317*a563ca70SAlex Hornung "tbridge");
318*a563ca70SAlex Hornung
319*a563ca70SAlex Hornung tbridge_testcase = NULL;
320*a563ca70SAlex Hornung tbridge_reset();
321*a563ca70SAlex Hornung
322*a563ca70SAlex Hornung kprintf("dfregress kernel test bridge ready!\n");
323*a563ca70SAlex Hornung return 0;
324*a563ca70SAlex Hornung
325*a563ca70SAlex Hornung case MOD_UNLOAD:
326*a563ca70SAlex Hornung destroy_dev(tbridge_dev);
327*a563ca70SAlex Hornung kprintf("dfregress kernel test bridge unloaded.\n");
328*a563ca70SAlex Hornung return 0;
329*a563ca70SAlex Hornung }
330*a563ca70SAlex Hornung
331*a563ca70SAlex Hornung return EINVAL;
332*a563ca70SAlex Hornung }
333*a563ca70SAlex Hornung
334*a563ca70SAlex Hornung static moduledata_t testbridge_mod = {
335*a563ca70SAlex Hornung "testbridge",
336*a563ca70SAlex Hornung testbridge_modevent,
337*a563ca70SAlex Hornung 0
338*a563ca70SAlex Hornung };
339*a563ca70SAlex Hornung
340*a563ca70SAlex Hornung DECLARE_MODULE(testbridge, testbridge_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
341*a563ca70SAlex Hornung MODULE_VERSION(testbridge, 1);
342