Add a regression device.
authorRonald G. Minnich <rminnich@gmail.com>
Tue, 9 Dec 2014 22:20:12 +0000 (22:20 +0000)
committerRonald G. Minnich <rminnich@gmail.com>
Tue, 9 Dec 2014 22:20:12 +0000 (22:20 +0000)
The regression device is used for regression tests. It is '#Z'
and provides mondata and monctl.

monctl is currently not useful.

mondata on the write side takes monitor commands.

Currently on the read side it returns nothing, but soon
it will return the output of the monitor for that command.

Sample usage:
/ $ echo ps > '#Z/mondata'
     PID Name                 State      Parent
-------------------------------------------------
       1 busybox              WAITING         0
       2 echo                 RUNNING_S       1

Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
kern/drivers/Kconfig
kern/drivers/dev/Kbuild
kern/drivers/dev/Kconfig [new file with mode: 0644]
kern/drivers/dev/regress.c [new file with mode: 0644]
kern/include/console.h
kern/src/monitor.c

index 7c3c79f..fb38aa7 100644 (file)
@@ -1,5 +1,6 @@
 menu "Drivers"
 
 #source "kern/drivers/net/Kconfig"
+source "kern/drivers/dev/Kconfig"
 
 endmenu
index 52bbefe..973fc3d 100644 (file)
@@ -8,6 +8,7 @@ obj-y                                           += mnt.o
 #obj-y                                         += pci.o
 obj-y                                          += pipe.o
 obj-y                                          += proc.o
+obj-$(CONFIG_REGRESS)                          += regress.o
 obj-y                                          += root.o
 obj-y                                          += srv.o
 
diff --git a/kern/drivers/dev/Kconfig b/kern/drivers/dev/Kconfig
new file mode 100644 (file)
index 0000000..eb737b8
--- /dev/null
@@ -0,0 +1,6 @@
+config REGRESS
+        bool "Include the regression test device"
+        default y
+        help
+                The regression test device allows you to push commands to monitor()
+               for testing. Defaults to 'y' for now.
diff --git a/kern/drivers/dev/regress.c b/kern/drivers/dev/regress.c
new file mode 100644 (file)
index 0000000..274af63
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * This file is part of the UCB release of Plan 9. It is subject to the license
+ * terms in the LICENSE file found in the top-level directory of this
+ * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
+ * part of the UCB release of Plan 9, including this file, may be copied,
+ * modified, propagated, or distributed except according to the terms contained
+ * in the LICENSE file.
+ */
+
+// regression device.
+// Currently, has only one file, monitor, which is used to send
+// commands to the monitor.
+// TODO: read them back :-)
+
+#include <vfs.h>
+#include <kfs.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <ip.h>
+#include <console.h>
+
+struct regress
+{
+       spinlock_t lock;
+       struct queue *monitor;
+};
+struct regress regress;
+
+enum{
+       Monitordirqid = 0,
+       Monitordataqid,
+       Monitorctlqid,
+};
+
+struct dirtab regresstab[]={
+       {".",           {Monitordirqid, 0, QTDIR},0,    DMDIR|0550},
+       {"mondata",     {Monitordataqid},               0,      0600},
+       {"monctl",      {Monitorctlqid},                0,      0600},
+};
+
+static size_t mpstatraw_len(void);
+static size_t mpstat_len(void);
+
+static struct chan*
+regressattach(char *spec)
+{
+       uint32_t n;
+
+       regress.monitor = qopen(2 << 20, 0, 0, 0);
+       if (! regress.monitor) {
+               printk("monitor allocate failed. No monitor output\n");
+       }
+       return devattach('Z', spec);
+}
+
+static void
+regressinit(void)
+{
+}
+
+static struct walkqid*
+regresswalk(struct chan *c, struct chan *nc, char **name, int nname)
+{
+       return devwalk(c, nc, name, nname, regresstab, ARRAY_SIZE(regresstab), devgen);
+}
+
+static int
+regressstat(struct chan *c, uint8_t *db, int n)
+{
+       if (regress.monitor)
+               regresstab[Monitordataqid].length = qlen(regress.monitor);
+       else
+               regresstab[Monitordataqid].length = 0;
+
+       return devstat(c, db, n, regresstab, ARRAY_SIZE(regresstab), devgen);
+}
+
+static struct chan*
+regressopen(struct chan *c, int omode)
+{
+       if(c->qid.type & QTDIR){
+               if(openmode(omode) != OREAD)
+                       error(Eperm);
+       }
+       c->mode = openmode(omode);
+       c->flag |= COPEN;
+       c->offset = 0;
+       return c;
+}
+
+static void
+regressclose(struct chan*unused)
+{
+}
+
+static long
+regressread(struct chan *c, void *va, long n, int64_t off)
+{
+       uint64_t w, *bp;
+       char *a, *ea;
+       uintptr_t offset = off;
+       uint64_t pc;
+       int snp_ret, ret = 0;
+
+       switch((int)c->qid.path){
+       case Monitordirqid:
+               return devdirread(c, va, n, regresstab, ARRAY_SIZE(regresstab), devgen);
+
+       case Monitordataqid:
+               if (regress.monitor) {
+                       printd("monitordataqid: regress.monitor %p len %p\n", regress.monitor, qlen(kprof.monitor));
+                       if (qlen(regress.monitor) > 0)
+                               n = qread(regress.monitor, va, n);
+                       else
+                               n = 0;
+               } else
+                       error("no monitor queue");
+               break;
+       default:
+               n = 0;
+               break;
+       }
+       return n;
+}
+
+static long
+regresswrite(struct chan *c, void *a, long n, int64_t unused)
+{
+       ERRSTACK(1);
+       uintptr_t pc;
+       struct cmdbuf *cb;
+       cb = parsecmd(a, n);
+
+       if (waserror()) {
+               kfree(cb);
+               nexterror();
+       }
+
+       switch((int)(c->qid.path)){
+       case Monitorctlqid:
+               error("no ctl commands yet");
+               break;
+
+       case Monitordataqid:
+               if (onecmd(cb->nf, cb->f, NULL) < 0)
+                       n = -1;
+               break;
+       default:
+               error(Ebadusefd);
+       }
+       kfree(cb);
+       poperror();
+       return n;
+}
+
+struct dev regressdevtab __devtab = {
+       'Z',
+       "regress",
+
+       devreset,
+       regressinit,
+       devshutdown,
+       regressattach,
+       regresswalk,
+       regressstat,
+       regressopen,
+       devcreate,
+       regressclose,
+       regressread,
+       devbread,
+       regresswrite,
+       devbwrite,
+       devremove,
+       devwstat,
+};
index fab3dbb..f83d0f5 100644 (file)
@@ -36,4 +36,7 @@ void kb_get_from_buf(struct kb_buffer *kb, char *dst, size_t cnt);
 void __cons_add_char(uint32_t srcid, long a0, long a1, long a2);
 void __run_mon(uint32_t srcid, long a0, long a1, long a2);
 
+/* function to run one command. */
+int onecmd(int argc, char *argv[], struct hw_trapframe *hw_tf);
+
 #endif /* ROS_KERN_CONSOLE_H */
index 3713cac..a7323d8 100644 (file)
@@ -881,6 +881,15 @@ int mon_monitor(int argc, char **argv, struct hw_trapframe *hw_tf)
 #define WHITESPACE "\t\r\n "
 #define MAXARGS 16
 
+
+int onecmd(int argc, char *argv[], struct hw_trapframe *hw_tf) {
+       int i;
+       for (i = 0; i < NCOMMANDS; i++) {
+               if (strcmp(argv[0], commands[i].name) == 0)
+                       return commands[i].func(argc, argv, hw_tf);
+       }
+       return -1;
+}
 static int runcmd(char *NTS real_buf, struct hw_trapframe *hw_tf) {
        char * buf = NTEXPAND(real_buf);
        int argc;