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.
