diff --git a/modular-framework/list.h b/modular-framework/list.h
new file mode 100644
index 00000000..366d9f38
--- /dev/null
+++ b/modular-framework/list.h
@@ -0,0 +1,620 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <stddef.h>
+
+#if defined(__STDC__)
+#define typeof __typeof__
+#endif
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+
+#define LIST_POISON1  ((void *) 0x100)
+#define LIST_POISON2  ((void *) 0x200)
+
+/*
+ * Prevent the compiler from merging or refetching reads or writes. The
+ * compiler is also forbidden from reordering successive instances of
+ * READ_ONCE, WRITE_ONCE and ACCESS_ONCE (see below), but only when the
+ * compiler is aware of some particular ordering.  One way to make the
+ * compiler aware of ordering is to put the two invocations of READ_ONCE,
+ * WRITE_ONCE or ACCESS_ONCE() in different C statements.
+ */
+
+#define READ_ONCE(x)			\
+({					\
+	volatile typeof(x) *__p = &(x);	\
+	*__p;				\
+})
+
+#define WRITE_ONCE(x, val)		\
+({					\
+	volatile typeof(x) *__p = &(x);	\
+	*__p = (typeof(x)) (val);	\
+})
+
+#define container_of(ptr, type, member)				\
+({								\
+        typeof( ((type *)0)->member ) *__mptr = (ptr);		\
+        (type *)( (char *)__mptr - offsetof(type, member) );	\
+})
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+        struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+	WRITE_ONCE(list->next, list);
+	list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	WRITE_ONCE(prev->next, new);
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+	next->prev = prev;
+	WRITE_ONCE(prev->next, next);
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void __list_del_entry(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+}
+
+static inline void list_del(struct list_head *entry)
+{
+	__list_del_entry(entry);
+	entry->next = LIST_POISON1;
+	entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+				struct list_head *new)
+{
+	new->next = old->next;
+	new->next->prev = new;
+	new->prev = old->prev;
+	new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+					struct list_head *new)
+{
+	list_replace(old, new);
+	INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+	__list_del_entry(entry);
+	INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+	__list_del_entry(list);
+	list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+				  struct list_head *head)
+{
+	__list_del_entry(list);
+	list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+				const struct list_head *head)
+{
+	return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+	return READ_ONCE(head->next) == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+	struct list_head *next = head->next;
+	return (next == head) && (next == head->prev);
+}
+
+/**
+ * list_rotate_left - rotate the list to the left
+ * @head: the head of the list
+ */
+static inline void list_rotate_left(struct list_head *head)
+{
+	struct list_head *first;
+
+	if (!list_empty(head)) {
+		first = head->next;
+		list_move_tail(first, head);
+	}
+}
+
+/**
+ * list_is_singular - tests whether a list has just one entry.
+ * @head: the list to test.
+ */
+static inline int list_is_singular(const struct list_head *head)
+{
+	return !list_empty(head) && (head->next == head->prev);
+}
+
+static inline void __list_cut_position(struct list_head *list,
+		struct list_head *head, struct list_head *entry)
+{
+	struct list_head *new_first = entry->next;
+	list->next = head->next;
+	list->next->prev = list;
+	list->prev = entry;
+	entry->next = list;
+	head->next = new_first;
+	new_first->prev = head;
+}
+
+/**
+ * list_cut_position - cut a list into two
+ * @list: a new list to add all removed entries
+ * @head: a list with entries
+ * @entry: an entry within head, could be the head itself
+ *	and if so we won't cut the list
+ *
+ * This helper moves the initial part of @head, up to and
+ * including @entry, from @head to @list. You should
+ * pass on @entry an element you know is on @head. @list
+ * should be an empty list or a list you do not care about
+ * losing its data.
+ *
+ */
+static inline void list_cut_position(struct list_head *list,
+		struct list_head *head, struct list_head *entry)
+{
+	if (list_empty(head))
+		return;
+	if (list_is_singular(head) &&
+		(head->next != entry && head != entry))
+		return;
+	if (entry == head)
+		INIT_LIST_HEAD(list);
+	else
+		__list_cut_position(list, head, entry);
+}
+
+static inline void __list_splice(const struct list_head *list,
+				 struct list_head *prev,
+				 struct list_head *next)
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+
+	first->prev = prev;
+	prev->next = first;
+
+	last->next = next;
+	next->prev = last;
+}
+
+/**
+ * list_splice - join two lists, this is designed for stacks
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(const struct list_head *list,
+				struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head, head->next);
+}
+
+/**
+ * list_splice_tail - join two lists, each list being a queue
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice_tail(struct list_head *list,
+				struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head->prev, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head, head->next);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_splice_tail_init - join two lists and reinitialise the emptied list
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * Each of the lists is a queue.
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_tail_init(struct list_head *list,
+					 struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head->prev, head);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_head within the struct.
+ */
+#define list_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr:	the list head to take the element from.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+	list_entry((ptr)->next, type, member)
+
+/**
+ * list_last_entry - get the last element from a list
+ * @ptr:	the list head to take the element from.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_last_entry(ptr, type, member) \
+	list_entry((ptr)->prev, type, member)
+
+/**
+ * list_first_entry_or_null - get the first element from a list
+ * @ptr:	the list head to take the element from.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Note that if the list is empty, it returns NULL.
+ */
+#define list_first_entry_or_null(ptr, type, member) ({ \
+	struct list_head *head__ = (ptr); \
+	struct list_head *pos__ = READ_ONCE(head__->next); \
+	pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
+})
+
+/**
+ * list_next_entry - get the next element in list
+ * @pos:	the type * to cursor
+ * @member:	the name of the list_head within the struct.
+ */
+#define list_next_entry(pos, member) \
+	list_entry((pos)->member.next, typeof(*(pos)), member)
+
+/**
+ * list_prev_entry - get the prev element in list
+ * @pos:	the type * to cursor
+ * @member:	the name of the list_head within the struct.
+ */
+#define list_prev_entry(pos, member) \
+	list_entry((pos)->member.prev, typeof(*(pos)), member)
+
+/**
+ * list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ */
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev	-	iterate over a list backwards
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+	for (pos = (head)->prev, n = pos->prev; \
+	     pos != (head); \
+	     pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_first_entry(head, typeof(*pos), member);	\
+	     &pos->member != (head);					\
+	     pos = list_next_entry(pos, member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)			\
+	for (pos = list_last_entry(head, typeof(*pos), member);		\
+	     &pos->member != (head); 					\
+	     pos = list_prev_entry(pos, member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos:	the type * to use as a start point
+ * @head:	the head of the list
+ * @member:	the name of the list_head within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+	((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) 		\
+	for (pos = list_next_entry(pos, member);			\
+	     &pos->member != (head);					\
+	     pos = list_next_entry(pos, member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member)		\
+	for (pos = list_prev_entry(pos, member);			\
+	     &pos->member != (head);					\
+	     pos = list_prev_entry(pos, member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) 			\
+	for (; &pos->member != (head);					\
+	     pos = list_next_entry(pos, member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_first_entry(head, typeof(*pos), member),	\
+		n = list_next_entry(pos, member);			\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_next_entry(n, member))
+
+/**
+ * list_for_each_entry_safe_continue - continue list iteration safe against removal
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) 		\
+	for (pos = list_next_entry(pos, member), 				\
+		n = list_next_entry(pos, member);				\
+	     &pos->member != (head);						\
+	     pos = n, n = list_next_entry(n, member))
+
+/**
+ * list_for_each_entry_safe_from - iterate over list from current point safe against removal
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) 			\
+	for (n = list_next_entry(pos, member);					\
+	     &pos->member != (head);						\
+	     pos = n, n = list_next_entry(n, member))
+
+/**
+ * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member)		\
+	for (pos = list_last_entry(head, typeof(*pos), member),		\
+		n = list_prev_entry(pos, member);			\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_prev_entry(n, member))
+
+/**
+ * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
+ * @pos:	the loop cursor used in the list_for_each_entry_safe loop
+ * @n:		temporary storage used in list_for_each_entry_safe
+ * @member:	the name of the list_head within the struct.
+ *
+ * list_safe_reset_next is not safe to use in general if the list may be
+ * modified concurrently (eg. the lock is dropped in the loop body). An
+ * exception to this is if the cursor element (pos) is pinned in the list,
+ * and list_safe_reset_next is called after re-taking the lock and before
+ * completing the current iteration of the loop body.
+ */
+#define list_safe_reset_next(pos, n, member)				\
+	n = list_next_entry(pos, member)
+
+#endif
diff --git a/modular-framework/module.c b/modular-framework/module.c
new file mode 100644
index 00000000..6f80d938
--- /dev/null
+++ b/modular-framework/module.c
@@ -0,0 +1,158 @@
+/* Copyright (c) 2017, ARM Limited. All rights reserved.
+ *
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include "module.h"
+
+#define MODULE_FRAMEWORK_VERSION 0x00010000UL
+SUBSYSTEM(module, "module framework", MODULE_FRAMEWORK_VERSION);
+
+/* Keep it simple, allow one registration session at a time. */
+static struct {
+	rwlock_t lock;
+	subsystem_t *subsystem;
+	module_base_t *module;
+} registration = {
+	.lock = RW_LOCK_UNLOCKED(lock),
+	.subsystem = NULL,
+	.module = NULL,
+};
+
+#define REGISTRATION_SANITY_CHECK(subsystem, module)		\
+do {								\
+	if (subsystem == NULL || module == NULL)		\
+		return -ENOENT;					\
+								\
+	if (!list_empty(&module->list)) {			\
+		printf("module %s was already registered.\n",	\
+		        module->name);				\
+		return -EAGAIN;					\
+	}							\
+} while(0)
+
+/* Module is linked statically or dynamically, and are loaded by
+ * program loader (execve) or dynamic linker/loader (ld.so)
+ *
+ * subsystem_register_module() should complete the whole registration
+ * session and link the module into subsystem's module array.
+ */
+static int linker_register_module(
+	subsystem_t *subsystem, module_base_t *module)
+{
+	REGISTRATION_SANITY_CHECK(subsystem, module);
+
+	/* Allow one registration session at a time */
+	rwlock_write_lock(&registration.lock);
+
+	/* Block the subsystem API calls in load new
+	 * implementation modules. */
+	rwlock_write_lock(&subsystem->lock);
+	module->handler = NULL; /* no DSO handler */
+	list_add(&module->list, &subsystem->modules);
+	rwlock_write_unlock(&subsystem->lock);
+
+	rwlock_write_unlock(&registration.lock);
+	return 0;
+}
+
+static int (*do_register_module)(subsystem_t *, module_base_t *)
+		= &linker_register_module;
+
+static int loader_register_module(
+	subsystem_t *subsystem, module_base_t *module)
+{
+	REGISTRATION_SANITY_CHECK(subsystem, module);
+
+	/* Registration session lock must be held by
+	 * module_loader_start(). */
+	if (rwlock_write_trylock(&registration.lock) == 0) {
+		registration.subsystem = subsystem;
+		registration.module = module;
+		return 0;
+	}
+
+	rwlock_write_unlock(&registration.lock);
+	return -EACCES;
+}
+
+void module_loader_start(void)
+{
+	rwlock_write_lock(&registration.lock);
+
+	if (registration.module != NULL ||
+	    registration.subsystem != NULL) {
+		printf("module loader start warn, A previous "
+		       "registration did not complete yet.\n");
+	}
+
+	registration.module = NULL;
+	registration.subsystem = NULL;
+	do_register_module = &loader_register_module;
+}
+
+void module_loader_end(void)
+{
+	if (registration.module != NULL ||
+	    registration.subsystem != NULL) {
+		printf("module loader end warn, A previous "
+		       "registration did not complete yet.\n");
+	}
+
+	registration.module = NULL;
+	registration.subsystem = NULL;
+	do_register_module = &linker_register_module;
+
+	rwlock_write_unlock(&registration.lock);
+}
+
+int module_install_dso(void *dso)
+{
+	/* Bottom halves of the registration, context exclusion
+	 * is guarenteed by module_loader_start()
+	 */
+	if (0 == rwlock_write_trylock(&registration.lock)) {
+		subsystem_t *subsystem = registration.subsystem;
+		module_base_t *module = registration.module;
+
+		if (subsystem != NULL && module != NULL) {
+			rwlock_write_lock(&subsystem->lock);
+			module->handler = dso;
+			list_add(&module->list, &subsystem->modules);
+			rwlock_write_unlock(&subsystem->lock);
+		}
+
+		registration.subsystem = NULL;
+		registration.module = NULL;
+		return 0;
+	}
+
+	rwlock_write_unlock(&registration.lock);
+	return -EACCES;
+}
+
+int module_abandon_dso(void)
+{
+	/* Bottom halves of the registration, context exclusion
+	 * is guarenteed by module_loader_start()
+	 */
+	if (0 == rwlock_write_trylock(&registration.lock)) {
+		registration.subsystem = NULL;
+		registration.module = NULL;
+		return 0;
+	}
+
+	rwlock_write_unlock(&registration.lock);
+	return -EACCES;
+}
+
+int __subsystem_register_module(
+	subsystem_t *subsystem, module_base_t *module)
+{
+	return do_register_module(subsystem, module);
+}
diff --git a/modular-framework/module.h b/modular-framework/module.h
new file mode 100644
index 00000000..e26ca3aa
--- /dev/null
+++ b/modular-framework/module.h
@@ -0,0 +1,205 @@
+/* Copyright (c) 2017, ARM Limited. All rights reserved.
+ *
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * Modular programming framework supports runtime selectable
+ * implementations for variant software subsystems.
+ *
+ * Multiple implementations of the same subsystem can be built
+ * into individual static libraries or loadable DSOs, and use
+ * constructor functions to register themselves.
+ *
+ * A subsystem can choose one active implementation and provide
+ * APIs to switch between implementations.
+ *
+ * Alternatively, subsystem can load multiple implementations
+ * and determine the APIs route in runtime.
+
+ * Also in need to pursue extreme performance the subsystem
+ * can choose one specific implementation module and build it
+ * to override subsystem API symbols directly, thus eliminate
+ * one level indirection of API calls through function pointers.
+ *
+ * This framework tries to minimizes dependencies to the linked
+ * list and rwlock facilities only.
+ */
+
+#ifndef MODULE_H
+#define MODULE_H
+
+#include "list.h"
+#include "rwlock.h"
+
+typedef struct {
+	rwlock_t lock;
+	uint32_t version;
+	const char *name;
+	const char *description;
+	struct list_head modules;
+	struct list_head *active;
+} subsystem_t;
+
+/* Subsystem instance name */
+#define subsystem(name) name ## _subsystem
+
+/* The trick is to use macro SUBSYSTEM() for both subsystem
+ * declaration and definition. ARGC() macro chooses either
+ * SUBSYSTEM_DEFINE() or SUBSYSTEM_DECLARE() depends on argument
+ * number,
+ */
+#define _ARGC(_0, _1, _2, _3, ...) _3
+#define  ARGC(...) _ARGC(__VA_ARGS__, DEFINE, 2, DECLARE, 0)
+
+#define _OVERLOAD(M, S, ...) M ## _ ## S(__VA_ARGS__)
+#define  OVERLOAD(M, S, ...) _OVERLOAD(M, S, __VA_ARGS__)
+
+#define SUBSYSTEM_DEFINE(_name, _description, _version)		\
+	subsystem_t subsystem(_name) = {			\
+		.lock = RW_LOCK_UNLOCKED(lock),			\
+		.name = # _name,				\
+		.version = _version,				\
+		.description = _description,			\
+	}
+
+#define SUBSYSTEM_DECLARE(name) subsystem_t subsystem(name)
+#define SUBSYSTEM(...) OVERLOAD(SUBSYSTEM, ARGC(__VA_ARGS__), __VA_ARGS__)
+
+/* Subsystem API prototype name */
+#define api_proto(subsystem, api) subsystem ##_## api ## _proto_t
+
+/* Subsystem API declaration */
+#define SUBSYSTEM_API(name, _return, api, ...) 			\
+	extern _return name ##_## api(__VA_ARGS__);		\
+	typedef _return (*api_proto(name, api))(__VA_ARGS__)	\
+
+/* Subsystem API stubs are weak */
+#define SUBSYSTEM_API_STUB(name, api) 				\
+	__attribute__((weak)) name ##_## api
+
+/* In case subsystem API implementations are built as static
+ * libraries or preload DSOs, one implementation can use this
+ * macro to override the APIs weak stubs.
+ */
+#define SUBSYSTEM_API_OVERRIDE(name, api, _alias)		\
+	__attribute__((alias(#_alias))) name ##_## api
+
+#define subsystem_constructor(name) 				\
+	do {							\
+		rwlock_init(&subsystem(name).lock);		\
+		INIT_LIST_HEAD(&subsystem(name).modules);	\
+		subsystem(name).active = NULL;			\
+	} while(0)
+
+#define SUBSYSTEM_CONSTRUCTOR(name) 				\
+	static void __attribute__((constructor(101)))		\
+		name ## _subsystem_constructor(void)
+
+#define subsystem_lock(access, name)				\
+	rwlock_ ##access## _lock(&subsystem(name).lock)
+
+#define subsystem_unlock(access, name)				\
+	rwlock_ ##access## _unlock(&subsystem(name).lock)
+
+#define subsystem_foreach_module(name, mod)			\
+	list_for_each_entry(mod, &subsystem(name).modules, list)
+
+#define MODULE_CLASS(subsystem)					\
+	struct subsystem ## _module {				\
+		struct list_head list;				\
+		const char *name;				\
+		void *handler; /* DSO */			\
+		int (*init_local)(void);			\
+		int (*term_local)(void);			\
+		int (*init_global)(void);			\
+		int (*term_global)(void);			\
+
+/* Base class to all inherited subsystem module classes */
+typedef MODULE_CLASS(base) } module_base_t;
+
+/* Module constructors should be late than subsystem constructors,
+ * in statically linked scenarios (both subsystems and modules are
+ * linked statically). thus the priority 102 compared to the above
+ * subsystem constructor priority 101.
+ */
+#define MODULE_CONSTRUCTOR(name) 				\
+	static void __attribute__((constructor(102)))		\
+		name ## _module_constructor(void)
+
+/* All subsystems' initialization and termination routines are
+ * the same, provide template to instantiation.
+ */
+#define SUBSYSTEM_INITERM_TEMPLATE(subs, method, print)		\
+static inline int subs ## _subsystem ##_## method(void)		\
+{								\
+	module_base_t *mod = NULL;				\
+								\
+	subsystem_lock(read, subs);				\
+	subsystem_foreach_module(subs, mod) {			\
+		int result = mod->method ? mod->method() : -1;	\
+		if (result < 0) {				\
+			subsystem_unlock(read, subs);		\
+			print("error %d to %s subsystem %s "	\
+			      "module %s.\n", result, # method, \
+			      subsystem(subs).name, mod->name);	\
+			return result;				\
+		}						\
+	}							\
+	subsystem_unlock(read, subs);				\
+	return 0;						\
+}
+
+/* Subsystem Modules Registration
+ *
+ * subsystem_register_module() are called by all modules in their
+ * constructors, whereas the modules could be:
+ *
+ * 1) Linked statically or dynamically, and are loaded by program
+ *    loader (execve) or dynamic linker/loader (ld.so)
+ *
+ *    subsystem_register_module() should complete the whole
+ *    registration session and link the module into subsystem's
+ *    module array.
+ *
+ * 2) Loaded by a module loader in runtime with libdl APIs
+ *
+ *    The whole registration session needs to be split to aim the
+ *    module loader to properly handle dlopen() returns, and save
+ *    the DSO handler into module's data structure.
+ *
+ *    The module loader should program in this way:
+ *	module_loader_start();
+ *	......
+ * 	for each module
+ *		handler = dlopen(module)
+ *		-- the module constructor calls register_module()
+ *		if (handler is valid)
+ *			install_dso(handler);
+ *		else
+	 		abandon_dso();
+ *      ......
+ *	module_loader_end();
+ */
+
+extern void module_loader_start(void);
+extern void module_loader_end(void);
+
+extern int module_install_dso(void *);
+extern int module_abandon_dso(void);
+
+extern int __subsystem_register_module(subsystem_t *, module_base_t *);
+
+/* Macro to allow polymorphism on module classes */
+#define subsystem_register_module(name, module)			\
+({								\
+	module_base_t *base = (module_base_t *)module;		\
+	__subsystem_register_module(&subsystem(name), base);	\
+})
+
+#endif
diff --git a/modular-framework/rwlock.h b/modular-framework/rwlock.h
new file mode 100644
index 00000000..108a35b2
--- /dev/null
+++ b/modular-framework/rwlock.h
@@ -0,0 +1,88 @@
+/* Copyright (c) 2017, ARM Limited. All rights reserved.
+ *
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RWLOCK_H
+#define RWLOCK_H
+
+/* Get ride on ODP rwlock implementation and in meanwhile
+ * keep the modular framework as generic as possible, and
+ * can be re-used in other projects.
+ *
+ * Assume that ODP rwlock facility will be available at the
+ * beginning of the world without any initialization.
+ */
+#include <odp/api/rwlock.h>
+
+typedef odp_rwlock_t rwlock_t;
+#define RW_LOCK_UNLOCKED(lock) ODP_RW_LOCK_UNLOCK(lock)
+
+#if defined(BUILD_ODP_RWLOCK)
+	/* only defined in odp rwlock source to link the implementation */
+	#define _ALIAS(impl, api) __attribute__((weak, alias(#impl))) api
+	#define ODP_ALIAS(api) _ALIAS(odp_ ## api, api)
+#else
+	/* other objects only see declarations */
+	#define ODP_ALIAS(api) api
+#endif
+
+/**
+ * Initialize a reader/writer lock.
+ *
+ * @param rwlock Pointer to a reader/writer lock
+ */
+void ODP_ALIAS(rwlock_init)(rwlock_t *rwlock);
+
+/**
+ * Acquire read permission on a reader/writer lock.
+ *
+ * @param rwlock Pointer to a reader/writer lock
+ */
+void ODP_ALIAS(rwlock_read_lock)(rwlock_t *rwlock);
+
+/**
+ * Try to acquire read permission to a reader/writer lock.
+ *
+ * @param rwlock Pointer to a reader/writer lock
+ *
+ * @retval  0 Lock was not available for read access
+ * @retval !0 Read access to lock acquired
+ */
+int ODP_ALIAS(rwlock_read_trylock)(rwlock_t *rwlock);
+
+/**
+ * Release read permission on a reader/writer lock.
+ *
+ * @param rwlock Pointer to a reader/writer lock
+ */
+void ODP_ALIAS(rwlock_read_unlock)(rwlock_t *rwlock);
+
+/**
+ * Acquire write permission on a reader/writer lock.
+ *
+ * @param rwlock Pointer to a reader/writer lock
+ */
+void ODP_ALIAS(rwlock_write_lock)(rwlock_t *rwlock);
+
+/**
+ * Try to acquire write permission to a reader/writer lock.
+ *
+ * @param rwlock Pointer to a reader/writer lock
+ *
+ * @retval  0 Lock was not available for write access
+ * @retval !0 Write access to lock acquired
+ */
+int ODP_ALIAS(rwlock_write_trylock)(rwlock_t *rwlock);
+
+/**
+ * Release write permission on a reader/writer lock.
+ *
+ * @param rwlock Pointer to a reader/writer lock
+ */
+void ODP_ALIAS(rwlock_write_unlock)(rwlock_t *rwlock);
+
+#endif /* RWLOCK_H */
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am
index ba4a31ea..3fc032da 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -6,6 +6,7 @@ include $(top_srcdir)/platform/@with_platform@/Makefile.inc
 
 AM_CFLAGS +=  -I$(srcdir)/include
 AM_CFLAGS +=  -I$(top_srcdir)/include
+AM_CFLAGS +=  -I$(top_srcdir)/modular-framework
 AM_CFLAGS +=  -I$(top_srcdir)/include/odp/arch/@ARCH_ABI@
 AM_CFLAGS +=  -I$(top_builddir)/include
 AM_CFLAGS +=  -Iinclude
@@ -292,6 +293,16 @@ if HAVE_PCAP
 __LIB__libodp_linux_la_SOURCES += pktio/pcap.c
 endif
 
+modularframeworkdir = $(top_srcdir)/modular-framework
+noinst_HEADERS += $(modularframeworkdir)/list.h \
+		  $(modularframeworkdir)/rwlock.h \
+		  $(modularframeworkdir)/module.h
+
+__LIB__libodp_linux_la_SOURCES += ../../modular-framework/module.c
+
+odp_rwlock.o odp_rwlock.lo : \
+	CFLAGS += -DBUILD_ODP_RWLOCK -include $(modularframeworkdir)/rwlock.h
+
 __LIB__libodp_linux_la_LIBADD = $(ATOMIC_LIBS)
 
 # Create symlink for ABI header files. Application does not need to use the arch
diff --git a/platform/linux-generic/include/odp/api/plat/atomic_types.h b/platform/linux-generic/include/odp/api/plat/atomic_types.h
index a674ac99..86c9e5b0 100644
--- a/platform/linux-generic/include/odp/api/plat/atomic_types.h
+++ b/platform/linux-generic/include/odp/api/plat/atomic_types.h
@@ -81,6 +81,8 @@ typedef struct odp_atomic_u64_s odp_atomic_u64_t;
 
 typedef struct odp_atomic_u32_s odp_atomic_u32_t;
 
+#define ODP_ATOMIC_INIT(a) { .v = a }
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/platform/linux-generic/include/odp/api/plat/rwlock_types.h b/platform/linux-generic/include/odp/api/plat/rwlock_types.h
index f7dc0449..a69a5f00 100644
--- a/platform/linux-generic/include/odp/api/plat/rwlock_types.h
+++ b/platform/linux-generic/include/odp/api/plat/rwlock_types.h
@@ -30,6 +30,8 @@ struct odp_rwlock_s {
 
 typedef struct odp_rwlock_s odp_rwlock_t;
 
+#define ODP_RW_LOCK_UNLOCK(lock) { .cnt = ODP_ATOMIC_INIT(0) }
+
 #ifdef __cplusplus
 }
 #endif
