Export CONFIG_ options via #version/kconfig
[akaros.git] / kern / drivers / dev / version.c
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
17 enum {
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
29 struct dev verdevtab;
30 static 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
40 extern char __note_build_id_start[];
41 extern char __note_build_id_end[];
42
43 extern const char *__kconfig_str;
44
45 static char *get_build_id_start(void)
46 {
47         return __note_build_id_start + BUILD_ID_OFFSET;
48 }
49
50 static size_t build_id_sz(void)
51 {
52         return __note_build_id_end - get_build_id_start();
53 }
54
55 static 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
68 static size_t ver_get_file_size(const char *src)
69 {
70         if (!src)
71                 return 0;
72         return strlen(src) + 1;
73 }
74
75 static struct chan *ver_attach(char *spec)
76 {
77         return devattach(verdevtab.name, spec);
78 }
79
80 static 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 = ver_get_file_size(build_info_version_name);
88         vertab[Kverkconfig].length = strlen(__kconfig_str) + 1;
89 }
90
91 static void ver_shutdown(void)
92 {
93
94 }
95
96 static struct walkqid *ver_walk(struct chan *c, struct chan *nc, char **name,
97                                                                  int nname)
98 {
99         return devwalk(c, nc, name, nname, vertab, ARRAY_SIZE(vertab), devgen);
100 }
101
102 static int ver_stat(struct chan *c, uint8_t *db, int n)
103 {
104         return devstat(c, db, n, vertab, ARRAY_SIZE(vertab), devgen);
105 }
106
107 static struct chan *ver_open(struct chan *c, int omode)
108 {
109         if (c->qid.type & QTDIR) {
110                 if (openmode(omode) != O_READ)
111                         error(EPERM, ERROR_FIXME);
112         }
113         c->mode = openmode(omode);
114         c->flag |= COPEN;
115         c->offset = 0;
116         return c;
117 }
118
119 static void ver_close(struct chan *c)
120 {
121 }
122
123 /* Returns a char representing the lowest 4 bits of x */
124 static char num_to_nibble(unsigned int x)
125 {
126         return "0123456789abcdef"[x & 0xf];
127 }
128
129 static ssize_t read_buildid(void *va, long n, off64_t off)
130 {
131         /* Each build_id byte needs 2 chars, and 1 for the \0 */
132         char build_id[BUILD_ID_SZ * 2 + 1] = {0};
133         uint8_t hi, lo;
134         uint8_t *b = (uint8_t*)get_build_id_start();
135
136         for (int i = 0; i < BUILD_ID_SZ; i++) {
137                 hi = *b >> 4;
138                 lo = *b & 0xf;
139                 build_id[i * 2 + 0] = num_to_nibble(hi);
140                 build_id[i * 2 + 1] = num_to_nibble(lo);
141                 b++;
142         }
143         return readmem(off, va, n, build_id, sizeof(build_id));
144 }
145
146 static long ver_read(struct chan *c, void *va, long n, int64_t off)
147 {
148         switch ((int) c->qid.path) {
149         case Kverdirqid:
150                 return devdirread(c, va, n, vertab, ARRAY_SIZE(vertab), devgen);
151         case Kverbuildid:
152                 return read_buildid(va, n, off);
153         case Kverdate:
154                 if (build_info_date)
155                         return ver_emit_nlstr(va, build_info_date, n, (long) off);
156                 break;
157         case Kvercommitid:
158                 if (build_info_commitid)
159                         return ver_emit_nlstr(va, build_info_commitid, n, (long) off);
160                 break;
161         case Kverversion:
162                 if (build_info_version)
163                         return ver_emit_nlstr(va, build_info_version, n, (long) off);
164                 break;
165         case Kverversionname:
166                 if (build_info_version_name)
167                         return ver_emit_nlstr(va, build_info_version_name, n, (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
178 static long ver_write(struct chan *c, void *a, long n, int64_t unused)
179 {
180         error(ENOTSUP, ERROR_FIXME);
181         return -1;
182 }
183
184 struct dev verdevtab __devtab = {
185         .name = "version",
186
187         .reset = devreset,
188         .init = ver_init,
189         .shutdown = ver_shutdown,
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 };