With #vars, you can specify certain global variables, such as num_cores, to
be exposed to userspace.  If you want, you can:

$ bind -a \#vars /dev
$ cat /dev/num_cores

For debugging, you can add entries to vars_dir[] to temporarily track
certain variables.  In the future, we could try adding support for
dynamically adding entries.

Signed-off-by: Barret Rhoden <[email protected]>
---
 kern/drivers/dev/Kbuild  |   1 +
 kern/drivers/dev/Kconfig |   7 ++
 kern/drivers/dev/vars.c  | 183 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 191 insertions(+)
 create mode 100644 kern/drivers/dev/vars.c

diff --git a/kern/drivers/dev/Kbuild b/kern/drivers/dev/Kbuild
index 57fd9368fb60..ee5e7a74fe21 100644
--- a/kern/drivers/dev/Kbuild
+++ b/kern/drivers/dev/Kbuild
@@ -12,5 +12,6 @@ obj-y                                         += proc.o
 obj-$(CONFIG_REGRESS)                          += regress.o
 obj-y                                          += root.o
 obj-y                                          += srv.o
+obj-$(CONFIG_VARS)                     += vars.o
 
 obj-$(CONFIG_NIX)                              += nix.o
diff --git a/kern/drivers/dev/Kconfig b/kern/drivers/dev/Kconfig
index eb737b8b11cb..85aac58f1a3f 100644
--- a/kern/drivers/dev/Kconfig
+++ b/kern/drivers/dev/Kconfig
@@ -4,3 +4,10 @@ config REGRESS
         help
                 The regression test device allows you to push commands to 
monitor()
                for testing. Defaults to 'y' for now.
+
+config VARS
+       bool "#vars kernel variable exporter"
+       default y
+       help
+               The #vars device exports read access to select kernel 
variables.  The
+               list of variables is statically declared in vars.c
diff --git a/kern/drivers/dev/vars.c b/kern/drivers/dev/vars.c
new file mode 100644
index 000000000000..573e3ac1c1d9
--- /dev/null
+++ b/kern/drivers/dev/vars.c
@@ -0,0 +1,183 @@
+/* Copyright (c) 2015 Google Inc
+ * Barret Rhoden <[email protected]>
+ * See LICENSE for details.
+ *
+ * #vars device, exports read access to select kernel global variables.  These
+ * variables are statically determined (i.e. set in the code below).
+ *
+ * To add a variable, add a VARS_ENTRY to vars_dir.  If the variable is a 
number
+ * and you want it in hex, "or" VARS_HEX into the type.  e.g:
+ *
+ *     VARS_ENTRY(foobar, type_int | VARS_HEX),
+ *
+ * If we add write support to vars, those will also be flags for 'type.'
+ *
+ * Another thing we can consider doing is implementing create() to add 
variables
+ * on the fly.  We can easily get the address (symbol table), but not the type,
+ * unless we get debugging info.  We could consider a CTL command to allow the
+ * user to change the type, though that might overload write() if we also allow
+ * setting variables. */
+
+#include <ns.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <atomic.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <sys/queue.h>
+#include <fdtap.h>
+#include <syscall.h>
+
+struct dev vars_devtab;
+
+static char *devname(void)
+{
+       return vars_devtab.name;
+}
+
+enum {
+       type_s8 = 1,
+       type_s16,
+       type_s32,
+       type_s64,
+       type_u8,
+       type_u16,
+       type_u32,
+       type_u64,
+
+       type_bool,
+       type_char,
+       type_short,
+       type_int,
+       type_long,
+       type_ushort,
+       type_uint,
+       type_ulong,
+       type_ntstr,             /* null-terminated string */
+
+       VARS_HEX = (1 << 31),
+};
+
+/* The qid.path is the addr of the variable.  The qid.vers is the type.  Or-in
+ * any VARS_* flags you want to the type.  "." has no type or addr. */
+#define VARS_ENTRY(name, type) {#name,                                         
\
+                                {(uint64_t)&(name), (type), QTFILE},           
\
+                                sizeof((name)),                                
\
+                                0444}
+
+static struct dirtab vars_dir[] = {
+       {".", {0, 0, QTDIR}, 0, DMDIR | 0555},
+       VARS_ENTRY(num_cores, type_int),
+};
+
+static struct chan *vars_attach(char *spec)
+{
+       struct chan *c;
+
+       c = devattach(devname(), spec);
+       mkqid(&c->qid, 0, 0, QTDIR);
+       return c;
+}
+
+static struct walkqid *vars_walk(struct chan *c, struct chan *nc, char **name,
+                                                                int nname)
+{
+       return devwalk(c, nc, name, nname, vars_dir, ARRAY_SIZE(vars_dir), 
devgen);
+}
+
+static int vars_stat(struct chan *c, uint8_t *db, int n)
+{
+       return devstat(c, db, n, vars_dir, ARRAY_SIZE(vars_dir), devgen);
+}
+
+static struct chan *vars_open(struct chan *c, int omode)
+{
+       return devopen(c, omode, vars_dir, ARRAY_SIZE(vars_dir), devgen);
+}
+
+static void vars_close(struct chan *c)
+{
+}
+
+static long vars_read(struct chan *c, void *ubuf, long n, int64_t offset)
+{
+       char tmp[128];  /* big enough for any number and most strings */
+       size_t size = sizeof(tmp);
+       char *fmt_str_s32 = c->qid.vers & VARS_HEX ? "0x%x" : "%d";
+       char *fmt_str_s64 = c->qid.vers & VARS_HEX ? "0x%lx" : "%ld";
+       char *fmt_str_u32 = c->qid.vers & VARS_HEX ? "0x%x" : "%u";
+       char *fmt_str_u64 = c->qid.vers & VARS_HEX ? "0x%lx" : "%lu";
+       int type = c->qid.vers & ~VARS_HEX;
+
+       switch (type) {
+       case 0:
+               return devdirread(c, ubuf, n, vars_dir, ARRAY_SIZE(vars_dir), 
devgen);
+       case type_bool:
+       case type_u8:
+               size = snprintf(tmp, size, fmt_str_u32, *(uint8_t*)c->qid.path);
+               break;
+       case type_u16:
+               size = snprintf(tmp, size, fmt_str_u32, 
*(uint16_t*)c->qid.path);
+               break;
+       case type_uint:
+       case type_u32:
+               size = snprintf(tmp, size, fmt_str_u32, 
*(uint32_t*)c->qid.path);
+               break;
+       case type_ulong:
+       case type_u64:
+               size = snprintf(tmp, size, fmt_str_u64, 
*(uint64_t*)c->qid.path);
+               break;
+       case type_s8:
+               size = snprintf(tmp, size, fmt_str_s32, *(int8_t*)c->qid.path);
+               break;
+       case type_s16:
+               size = snprintf(tmp, size, fmt_str_s32, *(int16_t*)c->qid.path);
+               break;
+       case type_int:
+       case type_s32:
+               size = snprintf(tmp, size, fmt_str_s32, *(int32_t*)c->qid.path);
+               break;
+       case type_long:
+       case type_s64:
+               size = snprintf(tmp, size, fmt_str_s64, *(int64_t*)c->qid.path);
+               break;
+       case type_char:
+               size = snprintf(tmp, size, "%c", *(char*)c->qid.path);
+               break;
+       case type_ntstr:
+               size = snprintf(tmp, size, "%s", *(char**)c->qid.path);
+               break;
+       default:
+               panic("Unknown #%s type %d", devname(), type);
+       }
+       return readmem(offset, ubuf, n, tmp, size + 1);
+}
+
+static long vars_write(struct chan *c, void *ubuf, long n, int64_t offset)
+{
+       error(EFAIL, "Can't write to a #%s file", devname());
+}
+
+struct dev vars_devtab __devtab = {
+       .name = "vars",
+       .reset = devreset,
+       .init = devinit,
+       .shutdown = devshutdown,
+       .attach = vars_attach,
+       .walk = vars_walk,
+       .stat = vars_stat,
+       .open = vars_open,
+       .create = devcreate,
+       .close = vars_close,
+       .read = vars_read,
+       .bread = devbread,
+       .write = vars_write,
+       .bwrite = devbwrite,
+       .remove = devremove,
+       .wstat = devwstat,
+       .power = devpower,
+       .chaninfo = devchaninfo,
+       .tapfd = 0,
+};
-- 
2.6.0.rc2.230.g3dd15c0

-- 
You received this message because you are subscribed to the Google Groups 
"Akaros" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to