akaros/kern/drivers/dev/version.c
<<
>>
Prefs
   1/* Copyright (c) 2015 Google Inc
   2 * Davide Libenzi <dlibenzi@google.com>
   3 * See LICENSE for details.
   4 */
   5
   6#include <ros/common.h>
   7#include <ros/errno.h>
   8#include <smp.h>
   9#include <ns.h>
  10#include <kmalloc.h>
  11#include <string.h>
  12#include <stdio.h>
  13#include <assert.h>
  14#include <err.h>
  15#include <build_info.h>
  16
  17enum {
  18        Kverdirqid = 0,
  19        Kverbuildid,
  20        Kverdate,
  21        Kvercommitid,
  22        Kverversion,
  23        Kverversionname,
  24        Kverkconfig,
  25        BUILD_ID_SZ = 20,
  26        BUILD_ID_OFFSET = 16,
  27};
  28
  29struct dev verdevtab;
  30static struct dirtab vertab[] = {
  31        {".",           {Kverdirqid, 0, QTDIR}, 0,      DMDIR|0550},
  32        {"build_id",    {Kverbuildid},          0,      0444},
  33        {"date",        {Kverdate},             0,      0444},
  34        {"commitid",    {Kvercommitid},         0,      0444},
  35        {"version",     {Kverversion},          0,      0444},
  36        {"version_name",{Kverversionname},      0,      0444},
  37        {"kconfig",     {Kverkconfig},          0,      0444},
  38};
  39
  40extern char __note_build_id_start[];
  41extern char __note_build_id_end[];
  42
  43extern const char *__kconfig_str;
  44
  45static char *get_build_id_start(void)
  46{
  47        return __note_build_id_start + BUILD_ID_OFFSET;
  48}
  49
  50static size_t build_id_sz(void)
  51{
  52        return __note_build_id_end - get_build_id_start();
  53}
  54
  55static long ver_emit_nlstr(char *dest, const char *src, long size,
  56                                                   long offset)
  57{
  58        long n, slen = strlen(src);
  59        char *buf = kmalloc(slen + 1, MEM_WAIT);
  60
  61        snprintf(buf, slen + 1, "%s", src);
  62        n = readmem(offset, dest, size, buf, slen + 1);
  63        kfree(buf);
  64
  65        return n;
  66}
  67
  68static size_t ver_get_file_size(const char *src)
  69{
  70        if (!src)
  71                return 0;
  72        return strlen(src) + 1;
  73}
  74
  75static struct chan *ver_attach(char *spec)
  76{
  77        return devattach(verdevtab.name, spec);
  78}
  79
  80static void ver_init(void)
  81{
  82        /* Our devtab's length params are wrong - need to stitch them up. */
  83        vertab[Kverbuildid].length = build_id_sz();
  84        vertab[Kverdate].length = ver_get_file_size(build_info_date);
  85        vertab[Kvercommitid].length = ver_get_file_size(build_info_commitid);
  86        vertab[Kverversion].length = ver_get_file_size(build_info_version);
  87        vertab[Kverversionname].length =
  88                ver_get_file_size(build_info_version_name);
  89        vertab[Kverkconfig].length = strlen(__kconfig_str) + 1;
  90}
  91
  92static struct walkqid *ver_walk(struct chan *c, struct chan *nc, char **name,
  93                                unsigned int nname)
  94{
  95        return devwalk(c, nc, name, nname, vertab, ARRAY_SIZE(vertab), devgen);
  96}
  97
  98static size_t ver_stat(struct chan *c, uint8_t *db, size_t n)
  99{
 100        return devstat(c, db, n, vertab, ARRAY_SIZE(vertab), devgen);
 101}
 102
 103static struct chan *ver_open(struct chan *c, int omode)
 104{
 105        if (c->qid.type & QTDIR) {
 106                if (openmode(omode) != O_READ)
 107                        error(EPERM, ERROR_FIXME);
 108        }
 109        c->mode = openmode(omode);
 110        c->flag |= COPEN;
 111        c->offset = 0;
 112        return c;
 113}
 114
 115static void ver_close(struct chan *c)
 116{
 117}
 118
 119/* Returns a char representing the lowest 4 bits of x */
 120static char num_to_nibble(unsigned int x)
 121{
 122        return "0123456789abcdef"[x & 0xf];
 123}
 124
 125static ssize_t read_buildid(void *va, long n, off64_t off)
 126{
 127        /* Each build_id byte needs 2 chars, and 1 for the \0 */
 128        char build_id[BUILD_ID_SZ * 2 + 1] = {0};
 129        uint8_t hi, lo;
 130        uint8_t *b = (uint8_t*)get_build_id_start();
 131
 132        for (int i = 0; i < BUILD_ID_SZ; i++) {
 133                hi = *b >> 4;
 134                lo = *b & 0xf;
 135                build_id[i * 2 + 0] = num_to_nibble(hi);
 136                build_id[i * 2 + 1] = num_to_nibble(lo);
 137                b++;
 138        }
 139        return readmem(off, va, n, build_id, sizeof(build_id));
 140}
 141
 142static size_t ver_read(struct chan *c, void *va, size_t n, off64_t off)
 143{
 144        switch ((int) c->qid.path) {
 145        case Kverdirqid:
 146                return devdirread(c, va, n, vertab, ARRAY_SIZE(vertab), devgen);
 147        case Kverbuildid:
 148                return read_buildid(va, n, off);
 149        case Kverdate:
 150                if (build_info_date)
 151                        return ver_emit_nlstr(va, build_info_date, n,
 152                                              (long) off);
 153                break;
 154        case Kvercommitid:
 155                if (build_info_commitid)
 156                        return ver_emit_nlstr(va, build_info_commitid, n,
 157                                              (long) off);
 158                break;
 159        case Kverversion:
 160                if (build_info_version)
 161                        return ver_emit_nlstr(va, build_info_version, n,
 162                                              (long) off);
 163                break;
 164        case Kverversionname:
 165                if (build_info_version_name)
 166                        return ver_emit_nlstr(va, build_info_version_name, n,
 167                                              (long) off);
 168                break;
 169        case Kverkconfig:
 170                return readstr(off, va, n, __kconfig_str);
 171        default:
 172                error(EINVAL, ERROR_FIXME);
 173        }
 174
 175        return 0;
 176}
 177
 178static size_t ver_write(struct chan *c, void *a, size_t n, off64_t unused)
 179{
 180        error(ENOTSUP, ERROR_FIXME);
 181        return -1;
 182}
 183
 184struct dev verdevtab __devtab = {
 185        .name = "version",
 186
 187        .reset = devreset,
 188        .init = ver_init,
 189        .shutdown = devshutdown,
 190        .attach = ver_attach,
 191        .walk = ver_walk,
 192        .stat = ver_stat,
 193        .open = ver_open,
 194        .create = devcreate,
 195        .close = ver_close,
 196        .read = ver_read,
 197        .bread = devbread,
 198        .write = ver_write,
 199        .bwrite = devbwrite,
 200        .remove = devremove,
 201        .wstat = devwstat,
 202};
 203