diff --git a/test/common_plat/m4/configure.m4 b/test/common_plat/m4/configure.m4
index 20c3a3b..1fc350d 100644
--- a/test/common_plat/m4/configure.m4
+++ b/test/common_plat/m4/configure.m4
@@ -32,4 +32,5 @@ AC_CONFIG_FILES([test/common_plat/Makefile
 		 test/common_plat/validation/api/timer/Makefile
 		 test/common_plat/validation/api/traffic_mngr/Makefile
 		 test/common_plat/validation/drv/Makefile
-		 test/common_plat/validation/drv/drvatomic/Makefile])
+		 test/common_plat/validation/drv/drvatomic/Makefile
+		 test/common_plat/validation/drv/drvshmem/Makefile])
diff --git a/test/common_plat/validation/drv/Makefile.am b/test/common_plat/validation/drv/Makefile.am
index eedbad5..bcdb92e 100644
--- a/test/common_plat/validation/drv/Makefile.am
+++ b/test/common_plat/validation/drv/Makefile.am
@@ -1,4 +1,5 @@
-ODPDRV_MODULES = drvatomic
+ODPDRV_MODULES = drvatomic \
+		 drvshmem
 
 SUBDIRS = $(ODPDRV_MODULES)
 
diff --git a/test/common_plat/validation/drv/drvshmem/.gitignore b/test/common_plat/validation/drv/drvshmem/.gitignore
new file mode 100644
index 0000000..726dea3
--- /dev/null
+++ b/test/common_plat/validation/drv/drvshmem/.gitignore
@@ -0,0 +1 @@
+drvshmem_main
diff --git a/test/common_plat/validation/drv/drvshmem/Makefile.am b/test/common_plat/validation/drv/drvshmem/Makefile.am
new file mode 100644
index 0000000..816a5e6
--- /dev/null
+++ b/test/common_plat/validation/drv/drvshmem/Makefile.am
@@ -0,0 +1,10 @@
+include ../Makefile.inc
+
+noinst_LTLIBRARIES = libtestdrvshmem.la
+libtestdrvshmem_la_SOURCES = drvshmem.c
+
+test_PROGRAMS = drvshmem_main$(EXEEXT)
+dist_drvshmem_main_SOURCES = drvshmem_main.c
+drvshmem_main_LDADD = libtestdrvshmem.la $(LIBCUNIT_COMMON) $(LIBODP)
+
+EXTRA_DIST = drvshmem.h
diff --git a/test/common_plat/validation/drv/drvshmem/drvshmem.c b/test/common_plat/validation/drv/drvshmem/drvshmem.c
new file mode 100644
index 0000000..42ad844
--- /dev/null
+++ b/test/common_plat/validation/drv/drvshmem/drvshmem.c
@@ -0,0 +1,351 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include <odp_drv.h>
+#include <odp_api.h>
+#include <odp_cunit_common.h>
+#include "drvshmem.h"
+#include <stdlib.h>
+
+#define ALIGN_SIZE  (128)
+#define MEM_NAME "test_shmem"
+#define TEST_SHARE_FOO (0xf0f0f0f0)
+#define TEST_SHARE_BAR (0xf0f0f0f)
+#define SMALL_MEM 10
+#define MEDIUM_MEM 4096
+#define BIG_MEM 16777216
+
+typedef struct {
+	odpdrv_barrier_t test_barrier1;
+	odpdrv_barrier_t test_barrier2;
+	uint32_t foo;
+	uint32_t bar;
+	odpdrv_atomic_u32_t index;
+	odpdrv_shm_t shm[MAX_WORKERS];
+} shared_test_data_t;
+
+/* memory stuff expected to fit in a single page */
+typedef struct {
+	int data[SMALL_MEM];
+} shared_test_data_small_t;
+
+/* memory stuff expected to fit in a huge page */
+typedef struct {
+	int data[MEDIUM_MEM];
+} shared_test_data_medium_t;
+
+/* memory stuff expected to fit in many huge pages */
+typedef struct {
+	int data[BIG_MEM];
+} shared_test_data_big_t;
+
+/*
+ * thread part for the drvshmem_test_basic test
+ */
+static int run_test_basic_thread(void *arg ODP_UNUSED)
+{
+	odpdrv_shm_info_t  info;
+	odpdrv_shm_t shm;
+	shared_test_data_t *shared_test_data;
+	int thr;
+
+	thr = odp_thread_id();
+	printf("Thread %i starts\n", thr);
+
+	shm = odpdrv_shm_lookup_by_name(MEM_NAME);
+	CU_ASSERT(ODPDRV_SHM_INVALID != shm);
+	shared_test_data = odpdrv_shm_addr(shm);
+	CU_ASSERT(NULL != shared_test_data);
+
+	odpdrv_barrier_wait(&shared_test_data->test_barrier1);
+	odpdrv_shm_print_all("(from thread) After lookup for the global shmem");
+	CU_ASSERT(TEST_SHARE_FOO == shared_test_data->foo);
+	CU_ASSERT(TEST_SHARE_BAR == shared_test_data->bar);
+	CU_ASSERT(0 == odpdrv_shm_info(shm, &info));
+	CU_ASSERT(0 == strcmp(MEM_NAME, info.name));
+	CU_ASSERT(0 == info.flags);
+	CU_ASSERT(shared_test_data == info.addr);
+	CU_ASSERT(sizeof(shared_test_data_t) <= info.size);
+#ifdef MAP_HUGETLB
+	CU_ASSERT(odp_sys_huge_page_size() == info.page_size);
+#else
+	CU_ASSERT(odp_sys_page_size() == info.page_size);
+#endif
+	odpdrv_shm_print_all("(from thread) About to end");
+
+	fflush(stdout);
+	return CU_get_number_of_failures();
+}
+
+/*
+ * test basic things: shmem creation, info, share, and free
+ */
+void drvshmem_test_basic(void)
+{
+	int base;	/* memory usage when test starts */
+	pthrd_arg thrdarg;
+	odpdrv_shm_t shm;
+	shared_test_data_t *shared_test_data;
+	odp_cpumask_t unused;
+
+	base = odpdrv_shm_print_all("Before drvshmem_test_basic");
+	shm = odpdrv_shm_reserve(MEM_NAME,
+				 sizeof(shared_test_data_t), ALIGN_SIZE, 0);
+	CU_ASSERT(ODPDRV_SHM_INVALID != shm);
+	CU_ASSERT(odpdrv_shm_to_u64(shm) !=
+					odpdrv_shm_to_u64(ODPDRV_SHM_INVALID));
+
+	CU_ASSERT(0 == odpdrv_shm_free_by_handle(shm));
+	CU_ASSERT(ODPDRV_SHM_INVALID == odpdrv_shm_lookup_by_name(MEM_NAME));
+
+	shm = odpdrv_shm_reserve(MEM_NAME,
+				 sizeof(shared_test_data_t), ALIGN_SIZE, 0);
+	CU_ASSERT(ODPDRV_SHM_INVALID != shm);
+
+	shared_test_data = odpdrv_shm_addr(shm);
+	CU_ASSERT_FATAL(NULL != shared_test_data);
+	shared_test_data->foo = TEST_SHARE_FOO;
+	shared_test_data->bar = TEST_SHARE_BAR;
+
+	CU_ASSERT(odpdrv_shm_free_by_address((char *)shared_test_data - 1) < 0);
+
+	thrdarg.numthrds = odp_cpumask_default_worker(&unused, 0);
+
+	if (thrdarg.numthrds > MAX_WORKERS)
+		thrdarg.numthrds = MAX_WORKERS;
+
+	odpdrv_barrier_init(&shared_test_data->test_barrier1, thrdarg.numthrds);
+	odp_cunit_thread_create(run_test_basic_thread, &thrdarg);
+	CU_ASSERT(odp_cunit_thread_exit(&thrdarg) >= 0);
+
+	CU_ASSERT(0 == odpdrv_shm_free_by_handle(shm));
+	CU_ASSERT(odpdrv_shm_print_all("Test completion") == base);
+}
+
+/*
+ * thread part for the drvshmem_test_reserve_after_fork
+ */
+static int run_test_reserve_after_fork(void *arg ODP_UNUSED)
+{
+	odpdrv_shm_t shm;
+	shared_test_data_t *glob_data;
+	int thr;
+	int thr_index;
+	char *name;
+	int name_len;
+	int size;
+	shared_test_data_small_t  *pattern_small;
+	shared_test_data_medium_t *pattern_medium;
+	shared_test_data_big_t    *pattern_big;
+	int i;
+
+	thr = odp_thread_id();
+	printf("Thread %i starts\n", thr);
+
+	shm = odpdrv_shm_lookup_by_name(MEM_NAME);
+	glob_data = odpdrv_shm_addr(shm);
+
+	/*
+	 * odp_thread_id are not guaranteed to be consecutive, so we create
+	 * a consecutive ID
+	 */
+	thr_index = odpdrv_atomic_fetch_inc_u32(&glob_data->index);
+
+	/* allocate some memory (of different sizes) and fill with pattern */
+	name_len = strlen(MEM_NAME) + 20;
+	name = malloc(name_len);
+	snprintf(name, name_len, "%s-%09d", MEM_NAME, thr_index);
+	switch (thr_index % 3) {
+	case 0:
+		size = sizeof(shared_test_data_small_t);
+		shm = odpdrv_shm_reserve(name, size, 0, 0);
+		CU_ASSERT(ODPDRV_SHM_INVALID != shm);
+		glob_data->shm[thr_index] = shm;
+		pattern_small = odpdrv_shm_addr(shm);
+		CU_ASSERT_PTR_NOT_NULL(pattern_small);
+		for (i = 0; i < SMALL_MEM; i++)
+			pattern_small->data[i] = i;
+		break;
+	case 1:
+		size = sizeof(shared_test_data_medium_t);
+		shm = odpdrv_shm_reserve(name, size, 0, 0);
+		CU_ASSERT(ODPDRV_SHM_INVALID != shm);
+		glob_data->shm[thr_index] = shm;
+		pattern_medium = odpdrv_shm_addr(shm);
+		CU_ASSERT_PTR_NOT_NULL(pattern_medium);
+		for (i = 0; i < MEDIUM_MEM; i++)
+			pattern_medium->data[i] = (i << 2);
+		break;
+	case 2:
+		size = sizeof(shared_test_data_big_t);
+		shm = odpdrv_shm_reserve(name, size, 0, 0);
+		CU_ASSERT(ODPDRV_SHM_INVALID != shm);
+		glob_data->shm[thr_index] = shm;
+		pattern_big = odpdrv_shm_addr(shm);
+		CU_ASSERT_PTR_NOT_NULL(pattern_big);
+		for (i = 0; i < BIG_MEM; i++)
+			pattern_big->data[i] = (i >> 2);
+		break;
+	}
+	free(name);
+
+	/* print block address */
+	printf("In thread: Block index: %d mapped at %lx\n",
+	       thr_index, (long int)odpdrv_shm_addr(shm));
+
+	odpdrv_barrier_wait(&glob_data->test_barrier1);
+	odpdrv_barrier_wait(&glob_data->test_barrier2);
+
+	fflush(stdout);
+	return CU_get_number_of_failures();
+}
+
+/*
+ * test sharing memory reserved after odp_thread creation (e.g. fork()):
+ */
+void drvshmem_test_reserve_after_fork(void)
+{
+	int base;	/* memory usage when test starts */
+	pthrd_arg thrdarg;
+	odpdrv_shm_t shm;
+	odpdrv_shm_t thr_shm;
+	shared_test_data_t *glob_data;
+	odp_cpumask_t unused;
+	char *name;
+	int name_len;
+	int thr_index;
+	int i;
+	void *address;
+	shared_test_data_small_t  *pattern_small;
+	shared_test_data_medium_t *pattern_medium;
+	shared_test_data_big_t    *pattern_big;
+
+	base = odpdrv_shm_print_all("Before drvshmem_test_reserve_after_fork");
+	shm = odpdrv_shm_reserve(MEM_NAME, sizeof(shared_test_data_t), 0, 0);
+	CU_ASSERT(ODPDRV_SHM_INVALID != shm);
+	glob_data = odpdrv_shm_addr(shm);
+	CU_ASSERT_PTR_NOT_NULL(glob_data);
+
+	thrdarg.numthrds = odp_cpumask_default_worker(&unused, 0);
+	if (thrdarg.numthrds > MAX_WORKERS)
+		thrdarg.numthrds = MAX_WORKERS;
+
+	odpdrv_barrier_init(&glob_data->test_barrier1, thrdarg.numthrds + 1);
+	odpdrv_barrier_init(&glob_data->test_barrier2, thrdarg.numthrds + 1);
+	odpdrv_atomic_store_u32(&glob_data->index, 0);
+
+	odp_cunit_thread_create(run_test_reserve_after_fork, &thrdarg);
+
+	/* wait until all threads have made their shm_reserve: */
+	odpdrv_barrier_wait(&glob_data->test_barrier1);
+	CU_ASSERT(odpdrv_shm_print_all("After all thread reserve")
+		  == base + thrdarg.numthrds + 1);
+
+	/* perform a lookup of all memories, by handle or name: */
+	name_len = strlen(MEM_NAME) + 20;
+	name = malloc(name_len);
+	for (thr_index = 0; thr_index < thrdarg.numthrds; thr_index++) {
+		if (thr_index % 2) {
+			snprintf(name, name_len, "%s-%09d",
+				 MEM_NAME, thr_index);
+			thr_shm = odpdrv_shm_lookup_by_name(name);
+			CU_ASSERT(thr_shm == glob_data->shm[thr_index]);
+		} else {
+			odpdrv_shm_lookup_by_handle(glob_data->shm[thr_index]);
+		}
+	}
+
+	/* check that the patterns are correct: */
+	for (thr_index = 0; thr_index < thrdarg.numthrds; thr_index++) {
+		switch (thr_index % 3) {
+		case 0:
+			pattern_small =
+				odpdrv_shm_addr(glob_data->shm[thr_index]);
+			CU_ASSERT_PTR_NOT_NULL(pattern_small);
+			for (i = 0; i < SMALL_MEM; i++)
+				CU_ASSERT(pattern_small->data[i] == i);
+			break;
+		case 1:
+			pattern_medium =
+				odpdrv_shm_addr(glob_data->shm[thr_index]);
+			CU_ASSERT_PTR_NOT_NULL(pattern_medium);
+			for (i = 0; i < MEDIUM_MEM; i++)
+				CU_ASSERT(pattern_medium->data[i] == (i << 2));
+			break;
+		case 2:
+			pattern_big =
+				odpdrv_shm_addr(glob_data->shm[thr_index]);
+			CU_ASSERT_PTR_NOT_NULL(pattern_big);
+			for (i = 0; i < BIG_MEM; i++)
+				CU_ASSERT(pattern_big->data[i] == (i >> 2));
+			break;
+		}
+	}
+
+	/*
+	 * print the mapping address of the blocks
+	 */
+	for (thr_index = 0; thr_index < thrdarg.numthrds; thr_index++) {
+		address = odpdrv_shm_addr(glob_data->shm[thr_index]);
+		printf("In main Block index: %d mapped at %lx\n",
+		       thr_index, (long int)address);
+	}
+
+	CU_ASSERT(odpdrv_shm_print_all("After main lookup of thread shmem")
+		  == base + thrdarg.numthrds + 1);
+
+	/* unblock the threads and let them terminate (no free is done): */
+	odpdrv_barrier_wait(&glob_data->test_barrier2);
+
+	/* at the same time, (race),free of all memories, by handle or name: */
+	for (thr_index = 0; thr_index < thrdarg.numthrds; thr_index++) {
+		if (thr_index % 2) {
+			thr_shm = glob_data->shm[thr_index];
+			CU_ASSERT(odpdrv_shm_free_by_handle(thr_shm) == 0);
+		} else {
+			snprintf(name, name_len, "%s-%09d",
+				 MEM_NAME, thr_index);
+			CU_ASSERT(odpdrv_shm_free_by_name(name) == 0);
+		}
+	}
+	free(name);
+
+	/* wait for all thread endings: */
+	CU_ASSERT(odp_cunit_thread_exit(&thrdarg) >= 0);
+
+	/* just glob_data should remain: */
+	CU_ASSERT(odpdrv_shm_print_all("After all threads end") == base + 1);
+
+	CU_ASSERT(0 == odpdrv_shm_free_by_handle(shm));
+	CU_ASSERT(odpdrv_shm_print_all("Test completion") == base);
+}
+
+odp_testinfo_t drvshmem_suite[] = {
+	ODP_TEST_INFO(drvshmem_test_basic),
+	ODP_TEST_INFO(drvshmem_test_reserve_after_fork),
+	ODP_TEST_INFO_NULL,
+};
+
+odp_suiteinfo_t drvshmem_suites[] = {
+	{"Shared Memory", NULL, NULL, drvshmem_suite},
+	ODP_SUITE_INFO_NULL,
+};
+
+int drvshmem_main(int argc, char *argv[])
+{
+	int ret;
+
+	/* parse common options: */
+	if (odp_cunit_parse_options(argc, argv))
+		return -1;
+
+	ret = odp_cunit_register(drvshmem_suites);
+
+	if (ret == 0)
+		ret = odp_cunit_run();
+
+	return ret;
+}
diff --git a/test/common_plat/validation/drv/drvshmem/drvshmem.h b/test/common_plat/validation/drv/drvshmem/drvshmem.h
new file mode 100644
index 0000000..12d738e
--- /dev/null
+++ b/test/common_plat/validation/drv/drvshmem/drvshmem.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#ifndef _ODP_TEST_DRVSHMEM_H_
+#define _ODP_TEST_DRVSHMEM_H_
+
+#include <odp_cunit_common.h>
+
+/* test functions: */
+void drvshmem_test_basic(void);
+void drvshmem_test_reserve_after_fork(void);
+
+/* test arrays: */
+extern odp_testinfo_t drvshmem_suite[];
+
+/* test registry: */
+extern odp_suiteinfo_t drvshmem_suites[];
+
+/* main test program: */
+int drvshmem_main(int argc, char *argv[]);
+
+#endif
diff --git a/test/common_plat/validation/drv/drvshmem/drvshmem_main.c b/test/common_plat/validation/drv/drvshmem/drvshmem_main.c
new file mode 100644
index 0000000..566ccec
--- /dev/null
+++ b/test/common_plat/validation/drv/drvshmem/drvshmem_main.c
@@ -0,0 +1,12 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include "drvshmem.h"
+
+int main(int argc, char *argv[])
+{
+	return drvshmem_main(argc, argv);
+}
diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.am
index 23b8e03..2b7cbc3 100644
--- a/test/linux-generic/Makefile.am
+++ b/test/linux-generic/Makefile.am
@@ -35,6 +35,7 @@ TESTS = validation/api/pktio/pktio_run.sh \
 	$(ALL_API_VALIDATION_DIR)/shmem/shmem_main$(EXEEXT) \
 	$(ALL_API_VALIDATION_DIR)/system/system_main$(EXEEXT) \
 	$(ALL_DRV_VALIDATION_DIR)/drvatomic/drvatomic_main$(EXEEXT) \
+	$(ALL_DRV_VALIDATION_DIR)/drvshmem/drvshmem_main$(EXEEXT) \
 	ring/ring_main$(EXEEXT)
 
 SUBDIRS += validation/api/pktio\
