2 * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <machine/md_var.h>
37 #include <sys/ctype.h>
38 #include <sys/kthread.h>
39 #include <sys/device.h>
40 #include <sys/fcntl.h>
41 #include <sys/ioccom.h>
42 #include <machine/varargs.h>
43 #include <sys/module.h>
44 #include <libprop/proplib.h>
45 #include "../framework/dfregress.h"
46 #include "../framework/tbridge.h"
48 static cdev_t tbridge_dev;
49 static d_open_t tbridge_dev_open;
50 static d_close_t tbridge_dev_close;
51 static d_ioctl_t tbridge_dev_ioctl;
54 static struct dev_ops tbridge_dev_ops = {
56 .d_open = tbridge_dev_open,
57 .d_close = tbridge_dev_close,
58 .d_ioctl = tbridge_dev_ioctl
61 static struct tbridge_testcase *tbridge_curtest = NULL;
62 static prop_dictionary_t tbridge_testcase = NULL;
63 static int tbridge_result_ready = 0;
64 static char tbridge_msgbuf[131072]; /* 128 kB message buffer */
65 static char *tbridge_msgbuf_ptr;
66 size_t tbridge_msgbuf_remsz;
68 static prop_dictionary_t
69 testcase_get_result_dict(prop_dictionary_t testcase)
71 prop_dictionary_t result_dict;
74 result_dict = prop_dictionary_get(testcase, "result");
75 if (result_dict == NULL) {
76 result_dict = prop_dictionary_create();
77 if (result_dict == NULL) {
78 kprintf("could not allocate new result dict");
82 r = prop_dictionary_set(testcase, "result", result_dict);
84 kprintf("prop_dictionary operation failed");
93 testcase_get_timeout(prop_dictionary_t testcase)
98 r = prop_dictionary_get_int32(prop_dictionary_get(testcase, "opts"),
99 "timeout_in_secs", &val);
101 val = 600/* default timeout = 10min */;
107 testcase_set_stdout_buf(prop_dictionary_t testcase, const char *buf)
109 prop_dictionary_t dict = testcase_get_result_dict(testcase);
111 return !prop_dictionary_set_cstring(dict, "stdout_buf", buf);
115 testcase_set_result(prop_dictionary_t testcase, int result)
117 prop_dictionary_t dict = testcase_get_result_dict(testcase);
119 return !prop_dictionary_set_int32(dict, "result", result);
123 testcase_get_name(prop_dictionary_t testcase)
128 r = prop_dictionary_get_cstring_nocopy(testcase, "name", &str);
136 tbridge_printf(const char *fmt, ...)
141 __va_start(args,fmt);
142 i = kvsnprintf(tbridge_msgbuf_ptr, tbridge_msgbuf_remsz, fmt, args);
145 tbridge_msgbuf_ptr += i;
146 tbridge_msgbuf_remsz -= i;
152 tbridge_register(struct tbridge_testcase *test)
154 if (tbridge_curtest != NULL)
157 tbridge_curtest = test;
163 tbridge_unregister(void)
165 tbridge_curtest = NULL;
171 tbridge_testcase_modhandler(module_t mod, int type, void *arg)
173 struct tbridge_testcase *tcase = (struct tbridge_testcase *)arg;
178 error = tbridge_register(tcase);
182 if (tcase->tb_abort != NULL)
183 error = tcase->tb_abort();
186 tbridge_unregister();
197 tbridge_test_done(int result)
199 KKASSERT(tbridge_testcase != NULL);
201 kprintf("testcase '%s' called test_done with result=%d\n",
202 testcase_get_name(tbridge_testcase), result);
204 testcase_set_result(tbridge_testcase, result);
205 testcase_set_stdout_buf(tbridge_testcase, tbridge_msgbuf);
207 tbridge_result_ready = 1;
208 wakeup(&tbridge_result_ready);
214 tbridge_msgbuf_ptr = tbridge_msgbuf;
215 tbridge_msgbuf_remsz = sizeof(tbridge_msgbuf);
217 if (tbridge_testcase != NULL) {
218 prop_object_release(tbridge_testcase);
219 tbridge_testcase = NULL;
222 safemem_reset_error_count();
223 tbridge_result_ready = 0;
231 tbridge_dev_open(struct dev_open_args *ap)
237 tbridge_dev_close(struct dev_close_args *ap)
243 tbridge_dev_ioctl(struct dev_ioctl_args *ap)
245 struct plistref *pref;
251 /* Use proplib(3) for userspace/kernel communication */
252 pref = (struct plistref *)ap->a_data;
255 case TBRIDGE_LOADTEST:
258 if (tbridge_curtest == NULL)
261 error = prop_dictionary_copyin_ioctl(pref, ap->a_cmd,
268 case TBRIDGE_GETRESULT:
269 error = kthread_create(tbridge_curtest->tb_run, NULL, &td,
272 tbridge_test_done(RESULT_PREFAIL);
274 /* The following won't be called if the thread wasn't created */
275 if (!tbridge_result_ready) {
276 r = tsleep(&tbridge_result_ready, 0, "tbridgeres",
277 hz * testcase_get_timeout(tbridge_testcase));
279 if (tbridge_curtest->tb_abort != NULL)
280 tbridge_curtest->tb_abort();
282 tbridge_test_done(RESULT_TIMEOUT);
286 if (safemem_get_error_count() != 0) {
288 * If there were any double-frees or buffer over- or
289 * underflows, we mark the result as 'signalled', i.e.
290 * the equivalent of a SIGSEGV/SIGBUS in userland.
292 testcase_set_result(tbridge_testcase, RESULT_SIGNALLED);
295 error = prop_dictionary_copyout_ioctl(pref, ap->a_cmd,
302 error = ENOTTY; /* Inappropriate ioctl for device */
311 testbridge_modevent(module_t mod, int type, void *unused)
315 tbridge_dev = make_dev(&tbridge_dev_ops,
322 tbridge_testcase = NULL;
325 kprintf("dfregress kernel test bridge ready!\n");
329 destroy_dev(tbridge_dev);
330 kprintf("dfregress kernel test bridge unloaded.\n");
337 static moduledata_t testbridge_mod = {
343 DECLARE_MODULE(testbridge, testbridge_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
344 MODULE_VERSION(testbridge, 1);