Add a build-id to the kernel
[akaros.git] / kern / drivers / dev / version.c
index a8ed8db..129ad0b 100644 (file)
 
 enum {
        Kverdirqid = 0,
+       Kverbuildid,
        Kverdate,
        Kvercommitid,
        Kverversion,
        Kverversionname,
+       BUILD_ID_SZ = 20,
+       BUILD_ID_OFFSET = 16,
 };
 
 struct dev verdevtab;
 static struct dirtab vertab[] = {
        {".",                           {Kverdirqid,            0, QTDIR}, 0,   DMDIR|0550},
+       {"build_id",            {Kverbuildid},          0,      0444},
        {"date",                        {Kverdate},                     0,      0444},
        {"commitid",            {Kvercommitid},         0,      0444},
        {"version",                     {Kverversion},          0,      0444},
        {"version_name",        {Kverversionname},      0,      0444},
 };
 
+extern char __note_build_id_start[];
+extern char __note_build_id_end[];
+
+static char *get_build_id_start(void)
+{
+       return __note_build_id_start + BUILD_ID_OFFSET;
+}
+
+static size_t build_id_sz(void)
+{
+       return __note_build_id_end - get_build_id_start();
+}
+
 static long ver_emit_nlstr(char *dest, const char *src, long size,
                                                   long offset)
 {
@@ -59,6 +76,7 @@ static struct chan *ver_attach(char *spec)
 static void ver_init(void)
 {
        /* Our devtab's length params are wrong - need to stitch them up. */
+       vertab[Kverbuildid].length = build_id_sz();
        vertab[Kverdate].length = ver_get_file_size(build_info_date);
        vertab[Kvercommitid].length = ver_get_file_size(build_info_commitid);
        vertab[Kverversion].length = ver_get_file_size(build_info_version);
@@ -98,11 +116,36 @@ static void ver_close(struct chan *c)
 
 }
 
+/* Returns a char representing the lowest 4 bits of x */
+static char num_to_nibble(int x)
+{
+       return "0123456789abcdef"[x % 16];
+}
+
+static ssize_t read_buildid(void *va, long n, off64_t off)
+{
+       /* Each build_id byte needs 2 chars, and 1 for the \0 */
+       char build_id[BUILD_ID_SZ * 2 + 1] = {0};
+       uint8_t hi, lo;
+       uint8_t *b = (uint8_t*)get_build_id_start();
+
+       for (int i = 0; i < BUILD_ID_SZ; i++) {
+               hi = *b >> 4;
+               lo = *b & 0xf;
+               build_id[i * 2 + 0] = num_to_nibble(hi);
+               build_id[i * 2 + 1] = num_to_nibble(lo);
+               b++;
+       }
+       return readmem(off, va, n, build_id, sizeof(build_id));
+}
+
 static long ver_read(struct chan *c, void *va, long n, int64_t off)
 {
        switch ((int) c->qid.path) {
        case Kverdirqid:
                return devdirread(c, va, n, vertab, ARRAY_SIZE(vertab), devgen);
+       case Kverbuildid:
+               return read_buildid(va, n, off);
        case Kverdate:
                if (build_info_date)
                        return ver_emit_nlstr(va, build_info_date, n, (long) off);