diff --git a/sdb-lib/Makefile b/sdb-lib/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..469967349ea267e5e8ae9c9a24c87b31cb455d56
--- /dev/null
+++ b/sdb-lib/Makefile
@@ -0,0 +1,43 @@
+
+LINUX ?= /lib/modules/$(shell uname -r)/build
+
+# If we compile for the kernel, we need to include real kernel headers.
+# The thing is enough a mess that I moved it to a different file
+include Makefile.arch
+
+
+AS              = $(CROSS_COMPILE)as
+LD              = $(CROSS_COMPILE)ld
+CC              = $(CROSS_COMPILE)gcc
+CPP             = $(CC) -E
+AR              = $(CROSS_COMPILE)ar
+NM              = $(CROSS_COMPILE)nm
+STRIP           = $(CROSS_COMPILE)strip
+OBJCOPY         = $(CROSS_COMPILE)objcopy
+OBJDUMP         = $(CROSS_COMPILE)objdump
+
+# calculate endianness at compile time
+ENDIAN := $(shell ./check-endian $(CC))
+
+CFLAGS = -Wall -ggdb -O2
+CFLAGS += -I../include/linux -I../include # for <sdb.h>
+CFLAGS += -ffunction-sections -fdata-sections
+CFLAGS += -Wno-pointer-sign
+CFLAGS += $(ENDIAN) $(LINUXINCLUDE)
+
+
+LIB = libsdbfs.a
+OBJS = glue.o access.o
+
+all: $(LIB)
+
+$(OBJS): $(wildcard *.h)
+
+$(LIB): $(OBJS)
+	$(AR) r $@ $(OBJS)
+
+clean:
+	rm -f $(OBJS) $(LIB) *~ core
+
+# add the other unused targets, so the rule in ../Makefile works
+modules install modules_install:
diff --git a/sdb-lib/Makefile.arch b/sdb-lib/Makefile.arch
new file mode 100644
index 0000000000000000000000000000000000000000..12ca01c5d1cda0b2aa2c0c04ac0d68147289fd7d
--- /dev/null
+++ b/sdb-lib/Makefile.arch
@@ -0,0 +1,58 @@
+
+srctree = $(LINUX)
+
+#
+# This set of contortions comes from the kernel Makefile. We need this
+# in order to properly compile libsdbfs for the kernel without being
+# in a kernel build environment (for example, to check for compile errors).
+#
+
+ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+                                  -e s/arm.*/arm/ -e s/sa110/arm/ \
+                                  -e s/s390x/s390/ -e s/parisc64/parisc/ \
+                                  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
+                                  -e s/sh[234].*/sh/ )
+
+SRCARCH         := $(ARCH)
+
+# Additional ARCH settings for x86
+ifeq ($(ARCH),i386)
+        SRCARCH := x86
+endif
+ifeq ($(ARCH),x86_64)
+        SRCARCH := x86
+endif
+
+# Additional ARCH settings for sparc
+ifeq ($(ARCH),sparc32)
+       SRCARCH := sparc
+endif
+ifeq ($(ARCH),sparc64)
+       SRCARCH := sparc
+endif
+
+# Additional ARCH settings for sh
+ifeq ($(ARCH),sh64)
+       SRCARCH := sh
+endif
+
+# Additional ARCH settings for tile
+ifeq ($(ARCH),tilepro)
+       SRCARCH := tile
+endif
+ifeq ($(ARCH),tilegx)
+       SRCARCH := tile
+endif
+
+# Where to locate arch specific headers
+hdr-arch  := $(SRCARCH)
+
+ifeq ($(ARCH),m68knommu)
+       hdr-arch  := m68k
+endif
+
+# Use LINUXINCLUDE when you must reference the include/ directory.
+# Needed to be compatible with the O= option
+LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include \
+                   -Iarch/$(hdr-arch)/include/generated \
+                   -I$(srctree)/include
diff --git a/sdb-lib/access.c b/sdb-lib/access.c
new file mode 100644
index 0000000000000000000000000000000000000000..9b47ecb66a92c6e3e95c5f6be1f2610b03c9970e
--- /dev/null
+++ b/sdb-lib/access.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012,2013 CERN (www.cern.ch)
+ * Author: Alessandro Rubini <rubini@gnudd.com>
+ *
+ * Released according to the GNU GPL, version 2 or any later version.
+ *
+ * This work is part of the White Rabbit project, a research effort led
+ * by CERN, the European Institute for Nuclear Research.
+ */
+
+/* To avoid many #ifdef and associated mess, all headers are included there */
+#include "libsdbfs.h"
+
+int sdbfs_fstat(struct sdbfs *fs, struct sdb_device *record_return)
+{
+	if (!fs->currentp)
+		return -ENOENT;
+	memcpy(record_return, fs->currentp, sizeof(*record_return));
+	return 0;
+}
+
+int sdbfs_fread(struct sdbfs *fs, int offset, void *buf, int count)
+{
+	int ret = count;
+
+	if (!fs->currentp)
+		return -ENOENT;
+	if (offset < 0)
+		offset = fs->read_offset;
+	if (offset + count > fs->f_len)
+		count = fs->f_len - offset;
+	if (fs->data)
+		memcpy(buf, fs->data + fs->f_offset + offset, count);
+	else
+		ret = fs->read(fs, fs->f_offset + offset, buf, count);
+	if (ret > 0)
+		fs->read_offset = offset + ret;
+	return ret;
+}
+
+int sdbfs_fwrite(struct sdbfs *fs, int offset, void *buf, int count)
+{
+	int ret = count;
+
+	if (!fs->currentp)
+		return -ENOENT;
+	if (offset < 0)
+		offset = fs->read_offset;
+	if (offset + count > fs->f_len)
+		count = fs->f_len - offset;
+	if (fs->data)
+		memcpy(buf, fs->data + fs->f_offset + offset, count);
+	else
+		ret = fs->write(fs, fs->f_offset + offset, buf, count);
+	if (ret > 0)
+		fs->read_offset = offset + ret;
+	return ret;
+}
diff --git a/sdb-lib/check-endian b/sdb-lib/check-endian
new file mode 100755
index 0000000000000000000000000000000000000000..0c2acff5342d14a0d15cb82c7377f7d051cadd4e
--- /dev/null
+++ b/sdb-lib/check-endian
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Check endianness at compile time, so we can pass the -D to CFLAGS
+
+CC=$1
+if [ "x$CC" == "x" ]; then
+    echo "$0: pass the compiler path (\$CC) as argument" >& 2
+    exit 1
+fi
+
+# Check endianness, by making an object file
+TMPC=$(mktemp /tmp/endian-c-XXXXXX)
+TMPO=$(mktemp /tmp/endian-o-XXXXXX)
+echo "int i = 0xbbee;" > $TMPC
+
+$CC -x c -c $TMPC -o $TMPO
+OBJCOPY=$(echo $CC | sed 's/gcc$/objcopy/')
+if $OBJCOPY -O binary $TMPO /dev/stdout | od -t x1 -An | \
+    grep -q 'bb ee'; then
+    echo " -DSDBFS_BIG_ENDIAN"
+else
+    echo " -DSDBFS_LITTLE_ENDIAN"
+fi
+rm -f $TMPC $TMPO
diff --git a/sdb-lib/glue.c b/sdb-lib/glue.c
new file mode 100644
index 0000000000000000000000000000000000000000..4a57bfc1c46bc5fa8ee33d64eebc631798206adc
--- /dev/null
+++ b/sdb-lib/glue.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2012 CERN (www.cern.ch)
+ * Author: Alessandro Rubini <rubini@gnudd.com>
+ *
+ * Released according to the GNU GPL, version 2 or any later version.
+ *
+ * This work is part of the White Rabbit project, a research effort led
+ * by CERN, the European Institute for Nuclear Research.
+ */
+
+/* To avoid many #ifdef and associated mess, all headers are included there */
+#include "libsdbfs.h"
+
+static struct sdbfs *sdbfs_list;
+
+/* All fields unused by the caller are expected to be zeroed */
+int sdbfs_dev_create(struct sdbfs *fs, int verbose)
+{
+	unsigned int magic;
+
+	/* First, check we have the magic */
+	if (fs->data)
+		magic = *(unsigned int *)(fs->data + fs->entrypoint);
+	else
+		fs->read(fs, fs->entrypoint, &magic, sizeof(magic));
+	if (htonl(magic) != SDB_MAGIC)
+		return -ENOTDIR;
+
+
+	if (verbose)
+		fs->flags |= SDBFS_F_VERBOSE;
+
+	fs->next = sdbfs_list;
+	sdbfs_list = fs;
+
+	return 0;
+}
+
+int sdbfs_dev_destroy(struct sdbfs *fs)
+{
+	struct sdbfs **p;
+
+	for (p = &sdbfs_list; *p && *p != fs; p = &(*p)->next)
+		;
+	if (!*p)
+		return -ENOENT;
+	*p = fs->next;
+	return 0;
+}
+
+struct sdbfs *sdbfs_dev_find(const char *name)
+{
+	struct sdbfs *l;
+
+	for (l = sdbfs_list; l && strcmp(l->name, name); l = l->next)
+		;
+	if (!l)
+		return NULL;
+	return l;
+}
+
+/*
+ * To open by name or by ID we need to scan the tree. The scan
+ * function is also exported in order for "sdb-ls" to use it
+ */
+
+static struct sdb_device *sdbfs_readentry(struct sdbfs *fs,
+					  unsigned long offset)
+{
+	/*
+	 * This function reads an entry from a known good offset. It
+	 * returns the pointer to the entry, which may be stored in
+	 * the fs structure itself. Only touches fs->current_record
+	 */
+	if (fs->data)
+		return (struct sdb_device *)(fs->data + offset);
+	if (!fs->read)
+		return NULL;
+	fs->read(fs, offset, &fs->current_record, sizeof(fs->current_record));
+	return &fs->current_record;
+}
+
+struct sdb_device *sdbfs_scan(struct sdbfs *fs, int newscan)
+{
+	/*
+	 * This returns a pointer to the next sdb record, or a new one.
+	 * Subdirectories are not supported. Uses all internal fields
+	 */
+	struct sdb_device *ret;
+	struct sdb_interconnect *i;
+
+	if (newscan) {
+		fs->f_offset = fs->entrypoint;
+	} else {
+		fs->f_offset += sizeof(struct sdb_device);
+		if (!fs->nleft)
+			return NULL;
+	}
+	ret = sdbfs_readentry(fs, fs->f_offset);
+	if (newscan) {
+		i = (typeof(i))ret;
+		fs->nleft = ntohs(i->sdb_records) - 1;
+	} else {
+		fs->nleft--;
+	}
+	return ret;
+}
+
+static void __open(struct sdbfs *fs)
+{
+	fs->f_offset = htonll(fs->currentp->sdb_component.addr_first);
+	fs->f_len = htonll(fs->currentp->sdb_component.addr_last)
+		+ 1 - fs->f_offset;
+	fs->read_offset = 0;
+}
+
+int sdbfs_open_name(struct sdbfs *fs, const char *name)
+{
+	struct sdb_device *d;
+	int len = strlen(name);
+
+	if (len > 19)
+		return -ENOENT;
+	sdbfs_scan(fs, 1); /* new scan: get the interconnect and igore it */
+	while ( (d = sdbfs_scan(fs, 0)) != NULL) {
+		if (strncmp(name, d->sdb_component.product.name, len))
+			continue;
+		if (len < 19 && d->sdb_component.product.name[len] != ' ')
+			continue;
+		fs->currentp = d;
+		__open(fs);
+		return 0;
+	}
+	return -ENOENT;
+}
+
+int sdbfs_open_id(struct sdbfs *fs, uint64_t vid, uint32_t did)
+{
+	struct sdb_device *d;
+
+	sdbfs_scan(fs, 1); /* new scan: get the interconnect and igore it */
+	while ( (d = sdbfs_scan(fs, 0)) != NULL) {
+		if (vid != d->sdb_component.product.vendor_id)
+			continue;
+		if (did != d->sdb_component.product.device_id)
+			continue;
+		fs->currentp = d;
+		__open(fs);
+		return 0;
+	}
+	return -ENOENT;
+}
+
+int sdbfs_close(struct sdbfs *fs)
+{
+	fs->currentp = NULL;
+	return 0;
+}
+
diff --git a/sdb-lib/libsdbfs-freestanding.h b/sdb-lib/libsdbfs-freestanding.h
new file mode 100644
index 0000000000000000000000000000000000000000..3f7868df9e1e018a660add51a6a4b5315f5ba9f2
--- /dev/null
+++ b/sdb-lib/libsdbfs-freestanding.h
@@ -0,0 +1,19 @@
+
+/* Though freestanding, some minimal headers are expected to exist */
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#define SDB_KERNEL	0
+#define SDB_USER	0
+#define SDB_FREESTAND	1
+
+#ifdef SDBFS_BIG_ENDIAN
+#  define ntohs(x) (x)
+#  define htons(x) (x)
+#  define ntohl(x) (x)
+#  define htonl(x) (x)
+#else
+#  error "No support, yet, for little-endian freestanding library"
+#endif
diff --git a/sdb-lib/libsdbfs-kernel.h b/sdb-lib/libsdbfs-kernel.h
new file mode 100644
index 0000000000000000000000000000000000000000..16e359e852e14b65076398f9c70f75467b556f38
--- /dev/null
+++ b/sdb-lib/libsdbfs-kernel.h
@@ -0,0 +1,24 @@
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <asm/byteorder.h>
+
+/*
+ * The default installed /usr/include/linux stuff misses the __KERNEL__ parts.
+ * For libsdbfs it means we won't get uint32_t and similar types.
+ *
+ * So, check if we got the information we need before strange errors happen.
+ * The DECLARE_BITMAP macro is in <linux/types.h> since the epoch, but it
+ * is not installed in /usr/include/linux/types.h, so use it to check.
+ */
+#ifndef DECLARE_BITMAP
+#  error "Please point LINUX to a source tree if you define __KERNEL__"
+#endif
+
+#define SDB_KERNEL	1
+#define SDB_USER	0
+#define SDB_FREESTAND	0
+
+
+#define sdb_print(format, ...) printk(format, __VA_ARGS__)
diff --git a/sdb-lib/libsdbfs-user.h b/sdb-lib/libsdbfs-user.h
new file mode 100644
index 0000000000000000000000000000000000000000..d54961c4c2e0633e73ad785788f907c113b63f16
--- /dev/null
+++ b/sdb-lib/libsdbfs-user.h
@@ -0,0 +1,15 @@
+#ifndef __LIBSDBFS_USER_H__
+#define __LIBSDBFS_USER_H__
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <arpa/inet.h> /* htonl */
+
+#define SDB_KERNEL	0
+#define SDB_USER	1
+#define SDB_FREESTAND	0
+
+#define sdb_print(format, ...) fprintf(stderr, format, __VA_ARGS__)
+
+#endif /* __LIBSDBFS_USER_H__ */
diff --git a/sdb-lib/libsdbfs.h b/sdb-lib/libsdbfs.h
new file mode 100644
index 0000000000000000000000000000000000000000..698c7703c343c127cdbe95a36bd35af4694cd3d7
--- /dev/null
+++ b/sdb-lib/libsdbfs.h
@@ -0,0 +1,81 @@
+#ifndef __LIBSDBFS_H__
+#define __LIBSDBFS_H__
+
+/* The library can work in three different environments */
+#ifdef __KERNEL__
+#  include "libsdbfs-kernel.h"
+#elif defined(__unix__)
+#  include "libsdbfs-user.h"
+#else
+#  include "libsdbfs-freestanding.h"
+#endif
+
+#include <sdb.h> /* Please point your "-I" to some sensible place */
+
+/*
+ * Data structures: please not that the library intself doesn't use
+ * malloc, so it's the caller who must deal withallocation/removal.
+ * For this reason we can have no opaque structures, but some fields
+ * are private
+ */
+
+struct sdbfs {
+
+	/* Some fields are informative */
+	char *name;			/* may be null */
+	void *drvdata;			/* driver may need some detail.. */
+	int blocksize;
+	unsigned long entrypoint;
+
+	/* The "driver" must offer some methods */
+	void *data;			/* Use this if directly mapped */
+	unsigned long datalen;		/* Length of the above array */
+	int (*read)(struct sdbfs *fs, int offset, void *buf, int count);
+	int (*write)(struct sdbfs *fs, int offset, void *buf, int count);
+	int (*erase)(struct sdbfs *fs, int offset, int count);
+
+	/* The following fields are library-private */
+	struct sdb_device current_record;
+	struct sdb_device *currentp;
+	int nleft;
+	unsigned long f_offset;
+	unsigned long f_len;
+	unsigned long read_offset;
+	unsigned long flags;
+	struct sdbfs *next;
+};
+
+#define SDBFS_F_VERBOSE		0x0001
+
+
+/* Defined in glue.c */
+int sdbfs_dev_create(struct sdbfs *fs, int verbose);
+int sdbfs_dev_destroy(struct sdbfs *fs);
+struct sdbfs *sdbfs_dev_find(const char *name);
+int sdbfs_open_name(struct sdbfs *fs, const char *name);
+int sdbfs_open_id(struct sdbfs *fs, uint64_t vid, uint32_t did);
+int sdbfs_close(struct sdbfs *fs);
+struct sdb_device *sdbfs_scan(struct sdbfs *fs, int newscan);
+
+/* Defined in access.c */
+int sdbfs_fstat(struct sdbfs *fs, struct sdb_device *record_return);
+int sdbfs_fread(struct sdbfs *fs, int offset, void *buf, int count);
+int sdbfs_fwrite(struct sdbfs *fs, int offset, void *buf, int count);
+
+/* This is needed to convert endianness. Hoping it is not defined elsewhere */
+static inline uint64_t htonll(uint64_t ll)
+{
+        uint64_t res;
+
+        if (htonl(1) == 1)
+                return ll;
+        res = htonl(ll >> 32);
+        res |= (uint64_t)(htonl((uint32_t)ll)) << 32;
+        return res;
+}
+static inline uint64_t ntohll(uint64_t ll)
+{
+	return htonll(ll);
+}
+
+#endif /* __LIBSDBFS_H__ */