diff --git a/example/generator/odp_generator.c b/example/generator/odp_generator.c
index 10c7b31..27fc868 100644
--- a/example/generator/odp_generator.c
+++ b/example/generator/odp_generator.c
@@ -523,6 +523,7 @@ int main(int argc, char *argv[])
 	int i;
 	int first_core;
 	int core_count;
+	odp_shm_t shm;
 
 	/* Init ODP before calling anything else */
 	if (odp_init_global()) {
@@ -537,8 +538,10 @@ int main(int argc, char *argv[])
 	odp_atomic_init_u64(&counters.icmp);
 
 	/* Reserve memory for args from shared mem */
-	args = odp_shm_reserve("shm_args", sizeof(args_t),
-			       ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve("shm_args", sizeof(args_t),
+			      ODP_CACHE_LINE_SIZE, 0);
+	args = odp_shm_addr(shm);
+
 	if (args == NULL) {
 		ODP_ERR("Error: shared mem alloc failed.\n");
 		exit(EXIT_FAILURE);
@@ -582,8 +585,10 @@ int main(int argc, char *argv[])
 	odp_init_local(thr_id);
 
 	/* Create packet pool */
-	pool_base = odp_shm_reserve("shm_packet_pool",
-				    SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve("shm_packet_pool",
+			      SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+	pool_base = odp_shm_addr(shm);
+
 	if (pool_base == NULL) {
 		ODP_ERR("Error: packet pool mem alloc failed.\n");
 		exit(EXIT_FAILURE);
diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c
index 5b7abf6..a9bba24 100644
--- a/example/ipsec/odp_ipsec.c
+++ b/example/ipsec/odp_ipsec.c
@@ -368,6 +368,7 @@ void ipsec_init_pre(void)
 {
 	odp_queue_param_t qparam;
 	void *pool_base;
+	odp_shm_t shm;
 
 	/*
 	 * Create queues
@@ -400,9 +401,10 @@ void ipsec_init_pre(void)
 	}
 
 	/* Create output buffer pool */
-	pool_base = odp_shm_reserve("shm_out_pool",
-				    SHM_OUT_POOL_SIZE, ODP_CACHE_LINE_SIZE,
-				    0);
+	shm = odp_shm_reserve("shm_out_pool",
+			      SHM_OUT_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+
+	pool_base = odp_shm_addr(shm);
 
 	out_pool = odp_buffer_pool_create("out_pool", pool_base,
 					  SHM_OUT_POOL_SIZE,
@@ -1179,6 +1181,7 @@ main(int argc, char *argv[])
 	int first_core;
 	int core_count;
 	int stream_count;
+	odp_shm_t shm;
 
 	/* Init ODP before calling anything else */
 	if (odp_init_global()) {
@@ -1191,8 +1194,11 @@ main(int argc, char *argv[])
 	odp_init_local(thr_id);
 
 	/* Reserve memory for args from shared mem */
-	args = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE,
-			       0);
+	shm = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE,
+			      0);
+
+	args = odp_shm_addr(shm);
+
 	if (NULL == args) {
 		ODP_ERR("Error: shared mem alloc failed.\n");
 		exit(EXIT_FAILURE);
@@ -1233,9 +1239,11 @@ main(int argc, char *argv[])
 	printf("First core:         %i\n\n", first_core);
 
 	/* Create packet buffer pool */
-	pool_base = odp_shm_reserve("shm_packet_pool",
-				    SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE,
-				    0);
+	shm = odp_shm_reserve("shm_packet_pool",
+			      SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+
+	pool_base = odp_shm_addr(shm);
+
 	if (NULL == pool_base) {
 		ODP_ERR("Error: packet pool mem alloc failed.\n");
 		exit(EXIT_FAILURE);
@@ -1252,9 +1260,11 @@ main(int argc, char *argv[])
 	}
 
 	/* Create context buffer pool */
-	pool_base = odp_shm_reserve("shm_ctx_pool",
-				    SHM_CTX_POOL_SIZE, ODP_CACHE_LINE_SIZE,
-				    0);
+	shm = odp_shm_reserve("shm_ctx_pool",
+			      SHM_CTX_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+
+	pool_base = odp_shm_addr(shm);
+
 	if (NULL == pool_base) {
 		ODP_ERR("Error: context pool mem alloc failed.\n");
 		exit(EXIT_FAILURE);
diff --git a/example/ipsec/odp_ipsec_cache.c b/example/ipsec/odp_ipsec_cache.c
index 1b99218..01650d0 100644
--- a/example/ipsec/odp_ipsec_cache.c
+++ b/example/ipsec/odp_ipsec_cache.c
@@ -19,10 +19,15 @@ ipsec_cache_t *ipsec_cache;
 
 void init_ipsec_cache(void)
 {
-	ipsec_cache = odp_shm_reserve("shm_ipsec_cache",
-				      sizeof(ipsec_cache_t),
-				      ODP_CACHE_LINE_SIZE,
-				      0);
+	odp_shm_t shm;
+
+	shm = odp_shm_reserve("shm_ipsec_cache",
+			      sizeof(ipsec_cache_t),
+			      ODP_CACHE_LINE_SIZE,
+			      0);
+
+	ipsec_cache = odp_shm_addr(shm);
+
 	if (ipsec_cache == NULL) {
 		ODP_ERR("Error: shared mem alloc failed.\n");
 		exit(EXIT_FAILURE);
diff --git a/example/ipsec/odp_ipsec_fwd_db.c b/example/ipsec/odp_ipsec_fwd_db.c
index de2e43e..9ed5d00 100644
--- a/example/ipsec/odp_ipsec_fwd_db.c
+++ b/example/ipsec/odp_ipsec_fwd_db.c
@@ -18,10 +18,15 @@ fwd_db_t *fwd_db;
 
 void init_fwd_db(void)
 {
-	fwd_db = odp_shm_reserve("shm_fwd_db",
-				 sizeof(fwd_db_t),
-				 ODP_CACHE_LINE_SIZE,
-				 0);
+	odp_shm_t shm;
+
+	shm = odp_shm_reserve("shm_fwd_db",
+			      sizeof(fwd_db_t),
+			      ODP_CACHE_LINE_SIZE,
+			      0);
+
+	fwd_db = odp_shm_addr(shm);
+
 	if (fwd_db == NULL) {
 		ODP_ERR("Error: shared mem alloc failed.\n");
 		exit(EXIT_FAILURE);
diff --git a/example/ipsec/odp_ipsec_loop_db.c b/example/ipsec/odp_ipsec_loop_db.c
index 222ccb9..f773352 100644
--- a/example/ipsec/odp_ipsec_loop_db.c
+++ b/example/ipsec/odp_ipsec_loop_db.c
@@ -18,11 +18,15 @@ loopback_db_t *loopback_db;
 void init_loopback_db(void)
 {
 	int idx;
+	odp_shm_t shm;
+
+	shm = odp_shm_reserve("loopback_db",
+			      sizeof(loopback_db_t),
+			      ODP_CACHE_LINE_SIZE,
+			      0);
+
+	loopback_db = odp_shm_addr(shm);
 
-	loopback_db = odp_shm_reserve("loopback_db",
-				      sizeof(loopback_db_t),
-				      ODP_CACHE_LINE_SIZE,
-				      0);
 	if (loopback_db == NULL) {
 		ODP_ERR("Error: shared mem alloc failed.\n");
 		exit(EXIT_FAILURE);
diff --git a/example/ipsec/odp_ipsec_sa_db.c b/example/ipsec/odp_ipsec_sa_db.c
index 612da86..f6da623 100644
--- a/example/ipsec/odp_ipsec_sa_db.c
+++ b/example/ipsec/odp_ipsec_sa_db.c
@@ -18,10 +18,15 @@ static sa_db_t *sa_db;
 
 void init_sa_db(void)
 {
-	sa_db = odp_shm_reserve("shm_sa_db",
-				sizeof(sa_db_t),
-				ODP_CACHE_LINE_SIZE,
-				0);
+	odp_shm_t shm;
+
+	shm = odp_shm_reserve("shm_sa_db",
+			      sizeof(sa_db_t),
+			      ODP_CACHE_LINE_SIZE,
+			      0);
+
+	sa_db = odp_shm_addr(shm);
+
 	if (sa_db == NULL) {
 		ODP_ERR("Error: shared mem alloc failed.\n");
 		exit(EXIT_FAILURE);
diff --git a/example/ipsec/odp_ipsec_sp_db.c b/example/ipsec/odp_ipsec_sp_db.c
index 7d9bba1..f288dfe 100644
--- a/example/ipsec/odp_ipsec_sp_db.c
+++ b/example/ipsec/odp_ipsec_sp_db.c
@@ -18,10 +18,15 @@ sp_db_t *sp_db;
 
 void init_sp_db(void)
 {
-	sp_db = odp_shm_reserve("shm_sp_db",
-				sizeof(sp_db_t),
-				ODP_CACHE_LINE_SIZE,
-				0);
+	odp_shm_t shm;
+
+	shm = odp_shm_reserve("shm_sp_db",
+			      sizeof(sp_db_t),
+			      ODP_CACHE_LINE_SIZE,
+			      0);
+
+	sp_db = odp_shm_addr(shm);
+
 	if (sp_db == NULL) {
 		ODP_ERR("Error: shared mem alloc failed.\n");
 		exit(EXIT_FAILURE);
diff --git a/example/ipsec/odp_ipsec_stream.c b/example/ipsec/odp_ipsec_stream.c
index ced055a..de8305a 100644
--- a/example/ipsec/odp_ipsec_stream.c
+++ b/example/ipsec/odp_ipsec_stream.c
@@ -48,10 +48,15 @@ stream_db_t *stream_db;
 
 void init_stream_db(void)
 {
-	stream_db = odp_shm_reserve("stream_db",
-				    sizeof(stream_db_t),
-				    ODP_CACHE_LINE_SIZE,
-				    0);
+	odp_shm_t shm;
+
+	shm = odp_shm_reserve("stream_db",
+			      sizeof(stream_db_t),
+			      ODP_CACHE_LINE_SIZE,
+			      0);
+
+	stream_db = odp_shm_addr(shm);
+
 	if (stream_db == NULL) {
 		ODP_ERR("Error: shared mem alloc failed.\n");
 		exit(EXIT_FAILURE);
diff --git a/example/l2fwd/odp_l2fwd.c b/example/l2fwd/odp_l2fwd.c
index e19aa94..6c1d64a 100644
--- a/example/l2fwd/odp_l2fwd.c
+++ b/example/l2fwd/odp_l2fwd.c
@@ -321,6 +321,7 @@ int main(int argc, char *argv[])
 	int first_core;
 	int core_count;
 	odp_pktio_t pktio;
+	odp_shm_t shm;
 
 	/* Init ODP before calling anything else */
 	if (odp_init_global()) {
@@ -329,8 +330,10 @@ int main(int argc, char *argv[])
 	}
 
 	/* Reserve memory for args from shared mem */
-	gbl_args = odp_shm_reserve("shm_args", sizeof(args_t),
-				   ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve("shm_args", sizeof(args_t),
+			      ODP_CACHE_LINE_SIZE, 0);
+	gbl_args = odp_shm_addr(shm);
+
 	if (gbl_args == NULL) {
 		ODP_ERR("Error: shared mem alloc failed.\n");
 		exit(EXIT_FAILURE);
@@ -380,8 +383,10 @@ int main(int argc, char *argv[])
 	odp_init_local(thr_id);
 
 	/* Create packet pool */
-	pool_base = odp_shm_reserve("shm_packet_pool",
-				    SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve("shm_packet_pool",
+			      SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+	pool_base = odp_shm_addr(shm);
+
 	if (pool_base == NULL) {
 		ODP_ERR("Error: packet pool mem alloc failed.\n");
 		exit(EXIT_FAILURE);
diff --git a/example/odp_example/odp_example.c b/example/odp_example/odp_example.c
index e99df85..c80dbbc 100644
--- a/example/odp_example/odp_example.c
+++ b/example/odp_example/odp_example.c
@@ -943,6 +943,7 @@ int main(int argc, char *argv[])
 	int i, j;
 	int prios;
 	int first_core;
+	odp_shm_t shm;
 
 	printf("\nODP example starts\n");
 
@@ -1003,8 +1004,15 @@ int main(int argc, char *argv[])
 	/*
 	 * Create message pool
 	 */
-	pool_base = odp_shm_reserve("msg_pool",
-				    MSG_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve("msg_pool",
+			      MSG_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+
+	pool_base = odp_shm_addr(shm);
+
+	if (pool_base == NULL) {
+		ODP_ERR("Shared memory reserve failed.\n");
+		return -1;
+	}
 
 	pool = odp_buffer_pool_create("msg_pool", pool_base, MSG_POOL_SIZE,
 				      sizeof(test_message_t),
diff --git a/example/packet/odp_pktio.c b/example/packet/odp_pktio.c
index 7f2d43f..41315f7 100644
--- a/example/packet/odp_pktio.c
+++ b/example/packet/odp_pktio.c
@@ -309,6 +309,7 @@ int main(int argc, char *argv[])
 	int i;
 	int first_core;
 	int core_count;
+	odp_shm_t shm;
 
 	/* Init ODP before calling anything else */
 	if (odp_init_global()) {
@@ -317,8 +318,10 @@ int main(int argc, char *argv[])
 	}
 
 	/* Reserve memory for args from shared mem */
-	args = odp_shm_reserve("shm_args", sizeof(args_t),
-			       ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve("shm_args", sizeof(args_t),
+			      ODP_CACHE_LINE_SIZE, 0);
+	args = odp_shm_addr(shm);
+
 	if (args == NULL) {
 		ODP_ERR("Error: shared mem alloc failed.\n");
 		exit(EXIT_FAILURE);
@@ -358,8 +361,10 @@ int main(int argc, char *argv[])
 	odp_init_local(thr_id);
 
 	/* Create packet pool */
-	pool_base = odp_shm_reserve("shm_packet_pool",
-				    SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve("shm_packet_pool",
+			      SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+	pool_base = odp_shm_addr(shm);
+
 	if (pool_base == NULL) {
 		ODP_ERR("Error: packet pool mem alloc failed.\n");
 		exit(EXIT_FAILURE);
diff --git a/example/timer/odp_timer_test.c b/example/timer/odp_timer_test.c
index fd46f16..6e1715d 100644
--- a/example/timer/odp_timer_test.c
+++ b/example/timer/odp_timer_test.c
@@ -248,6 +248,7 @@ int main(int argc, char *argv[])
 	int first_core;
 	uint64_t cycles, ns;
 	odp_queue_param_t param;
+	odp_shm_t shm;
 
 	printf("\nODP timer example starts\n");
 
@@ -310,8 +311,9 @@ int main(int argc, char *argv[])
 	/*
 	 * Create message pool
 	 */
-	pool_base = odp_shm_reserve("msg_pool",
-				    MSG_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve("msg_pool",
+			      MSG_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+	pool_base = odp_shm_addr(shm);
 
 	pool = odp_buffer_pool_create("msg_pool", pool_base, MSG_POOL_SIZE,
 				      0,
diff --git a/platform/linux-generic/include/api/odp_shared_memory.h b/platform/linux-generic/include/api/odp_shared_memory.h
index 7d9fedd..7ad29c3 100644
--- a/platform/linux-generic/include/api/odp_shared_memory.h
+++ b/platform/linux-generic/include/api/odp_shared_memory.h
@@ -32,10 +32,29 @@ extern "C" {
 #define ODP_SHM_SW_ONLY 0x1 /**< Application SW only, no HW access */
 #define ODP_SHM_PROC    0x2 /**< Share with external processes */
 
+/**
+ * ODP shared memory block
+ */
+typedef uint32_t odp_shm_t;
+
+/** Invalid shared memory block */
+#define ODP_SHM_INVALID 0
+
+
+/**
+ * Shared memory block info
+ */
+typedef struct odp_shm_info_t {
+	const char *name;      /**< Block name */
+	void       *addr;      /**< Block address */
+	uint64_t    size;      /**< Block size in bytes */
+	uint64_t    page_size; /**< Memory page size */
+	uint32_t    flags;     /**< ODP_SHM_* flags */
+} odp_shm_info_t;
 
 
 /**
- * Reserve a block of shared memory
+ * Reserve a contiguous block of shared memory
  *
  * @param name   Name of the block (maximum ODP_SHM_NAME_LEN - 1 chars)
  * @param size   Block size in bytes
@@ -44,8 +63,8 @@ extern "C" {
  *
  * @return Pointer to the reserved block, or NULL
  */
-void *odp_shm_reserve(const char *name, uint64_t size, uint64_t align,
-		      uint32_t flags);
+odp_shm_t odp_shm_reserve(const char *name, uint64_t size, uint64_t align,
+			  uint32_t flags);
 
 /**
  * Lookup for a block of shared memory
@@ -54,7 +73,28 @@ void *odp_shm_reserve(const char *name, uint64_t size, uint64_t align,
  *
  * @return Pointer to the block, or NULL
  */
-void *odp_shm_lookup(const char *name);
+odp_shm_t odp_shm_lookup(const char *name);
+
+
+/**
+ * Shared memory block address
+ *
+ * @param shm   Block handle
+ *
+ * @return Memory block address, or NULL on error
+ */
+void *odp_shm_addr(odp_shm_t shm);
+
+
+/**
+ * Shared memory block info
+ *
+ * @param shm   Block handle
+ * @param info  Block info pointer for output
+ *
+ * @return 0 on success, otherwise non-zero
+ */
+int odp_shm_info(odp_shm_t shm, odp_shm_info_t *info);
 
 
 /**
diff --git a/platform/linux-generic/odp_buffer_pool.c b/platform/linux-generic/odp_buffer_pool.c
index f54a0c4..4d9ff45 100644
--- a/platform/linux-generic/odp_buffer_pool.c
+++ b/platform/linux-generic/odp_buffer_pool.c
@@ -114,10 +114,13 @@ static inline void set_handle(odp_buffer_hdr_t *hdr,
 int odp_buffer_pool_init_global(void)
 {
 	uint32_t i;
+	odp_shm_t shm;
 
-	pool_tbl = odp_shm_reserve("odp_buffer_pools",
-				   sizeof(pool_table_t),
-				   sizeof(pool_entry_t), 0);
+	shm = odp_shm_reserve("odp_buffer_pools",
+			      sizeof(pool_table_t),
+			      sizeof(pool_entry_t), 0);
+
+	pool_tbl = odp_shm_addr(shm);
 
 	if (pool_tbl == NULL)
 		return -1;
diff --git a/platform/linux-generic/odp_crypto.c b/platform/linux-generic/odp_crypto.c
index 2942a84..12d0272 100644
--- a/platform/linux-generic/odp_crypto.c
+++ b/platform/linux-generic/odp_crypto.c
@@ -403,14 +403,17 @@ int
 odp_crypto_init_global(void)
 {
 	size_t mem_size;
+	odp_shm_t shm;
 
 	/* Calculate the memory size we need */
 	mem_size  = sizeof(*global);
 	mem_size += (MAX_SESSIONS * sizeof(odp_crypto_generic_session_t));
 
 	/* Allocate our globally shared memory */
-	global = odp_shm_reserve("crypto_pool", mem_size,
-				 ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve("crypto_pool", mem_size,
+			      ODP_CACHE_LINE_SIZE, 0);
+
+	global = odp_shm_addr(shm);
 
 	/* Clear it out */
 	memset(global, 0, mem_size);
diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c
index 944c1d4..06d8935 100644
--- a/platform/linux-generic/odp_packet_io.c
+++ b/platform/linux-generic/odp_packet_io.c
@@ -52,10 +52,13 @@ int odp_pktio_init_global(void)
 	queue_entry_t *queue_entry;
 	odp_queue_t qid;
 	int id;
+	odp_shm_t shm;
+
+	shm = odp_shm_reserve("odp_pktio_entries",
+			      sizeof(pktio_table_t),
+			      sizeof(pktio_entry_t), 0);
+	pktio_tbl = odp_shm_addr(shm);
 
-	pktio_tbl = odp_shm_reserve("odp_pktio_entries",
-				    sizeof(pktio_table_t),
-				    sizeof(pktio_entry_t), 0);
 	if (pktio_tbl == NULL)
 		return -1;
 
diff --git a/platform/linux-generic/odp_queue.c b/platform/linux-generic/odp_queue.c
index 9852598..1318bcd 100644
--- a/platform/linux-generic/odp_queue.c
+++ b/platform/linux-generic/odp_queue.c
@@ -94,12 +94,15 @@ static void queue_init(queue_entry_t *queue, const char *name,
 int odp_queue_init_global(void)
 {
 	uint32_t i;
+	odp_shm_t shm;
 
 	ODP_DBG("Queue init ... ");
 
-	queue_tbl = odp_shm_reserve("odp_queues",
-				    sizeof(queue_table_t),
-				    sizeof(queue_entry_t), 0);
+	shm = odp_shm_reserve("odp_queues",
+			      sizeof(queue_table_t),
+			      sizeof(queue_entry_t), 0);
+
+	queue_tbl = odp_shm_addr(shm);
 
 	if (queue_tbl == NULL)
 		return -1;
diff --git a/platform/linux-generic/odp_ring.c b/platform/linux-generic/odp_ring.c
index c415d7f..632aa66 100644
--- a/platform/linux-generic/odp_ring.c
+++ b/platform/linux-generic/odp_ring.c
@@ -158,6 +158,7 @@ odph_ring_create(const char *name, unsigned count, unsigned flags)
 	char ring_name[ODPH_RING_NAMESIZE];
 	odph_ring_t *r;
 	size_t ring_size;
+	odp_shm_t shm;
 
 	/* count must be a power of 2 */
 	if (!ODP_VAL_IS_POWER_2(count) || (count > ODPH_RING_SZ_MASK)) {
@@ -171,7 +172,9 @@ odph_ring_create(const char *name, unsigned count, unsigned flags)
 
 	odp_rwlock_write_lock(&qlock);
 	/* reserve a memory zone for this ring.*/
-	r = odp_shm_reserve(ring_name, ring_size, ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve(ring_name, ring_size, ODP_CACHE_LINE_SIZE, 0);
+
+	r = odp_shm_addr(shm);
 
 	if (r != NULL) {
 		/* init the ring structure */
diff --git a/platform/linux-generic/odp_schedule.c b/platform/linux-generic/odp_schedule.c
index 16ae4af..1bf819b 100644
--- a/platform/linux-generic/odp_schedule.c
+++ b/platform/linux-generic/odp_schedule.c
@@ -81,23 +81,28 @@ static inline odp_queue_t select_pri_queue(odp_queue_t queue, int prio)
 
 int odp_schedule_init_global(void)
 {
+	odp_shm_t shm;
 	odp_buffer_pool_t pool;
 	void *pool_base;
 	int i, j;
 
 	ODP_DBG("Schedule init ... ");
 
-	sched = odp_shm_reserve("odp_scheduler",
-				sizeof(sched_t),
-				ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve("odp_scheduler",
+			      sizeof(sched_t),
+			      ODP_CACHE_LINE_SIZE, 0);
+
+	sched = odp_shm_addr(shm);
 
 	if (sched == NULL) {
 		ODP_ERR("Schedule init: Shm reserve failed.\n");
 		return -1;
 	}
 
-	pool_base = odp_shm_reserve("odp_sched_pool",
-				    SCHED_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve("odp_sched_pool",
+			      SCHED_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+
+	pool_base = odp_shm_addr(shm);
 
 	if (pool_base == NULL) {
 		ODP_ERR("Schedule init: Shm reserve failed.\n");
diff --git a/platform/linux-generic/odp_shared_memory.c b/platform/linux-generic/odp_shared_memory.c
index 3d1e12a..1898a34 100644
--- a/platform/linux-generic/odp_shared_memory.c
+++ b/platform/linux-generic/odp_shared_memory.c
@@ -24,12 +24,16 @@
 
 
 typedef struct {
-	char name[ODP_SHM_NAME_LEN];
-	uint64_t size;
-	uint64_t align;
-	void *addr_orig;
-	void *addr;
-	int huge;
+	char      name[ODP_SHM_NAME_LEN];
+	uint64_t  size;
+	uint64_t  align;
+	void      *addr_orig;
+	void      *addr;
+	int       huge;
+	odp_shm_t hdl;
+	uint32_t  flags;
+	uint64_t  page_sz;
+	int       fd;
 
 } odp_shm_block_t;
 
@@ -50,6 +54,18 @@ typedef struct {
 static odp_shm_table_t *odp_shm_tbl;
 
 
+static inline uint32_t from_handle(odp_shm_t shm)
+{
+	return shm - 1;
+}
+
+
+static inline odp_shm_t to_handle(uint32_t index)
+{
+	return index + 1;
+}
+
+
 int odp_shm_init_global(void)
 {
 	void *addr;
@@ -79,25 +95,28 @@ int odp_shm_init_local(void)
 }
 
 
-static int find_block(const char *name)
+static int find_block(const char *name, uint32_t *index)
 {
-	int i;
+	uint32_t i;
 
 	for (i = 0; i < ODP_SHM_NUM_BLOCKS; i++) {
 		if (strcmp(name, odp_shm_tbl->block[i].name) == 0) {
 			/* found it */
-			return i;
+			if (index != NULL)
+				*index = i;
+
+			return 1;
 		}
 	}
 
-	return -1;
+	return 0;
 }
 
 
-void *odp_shm_reserve(const char *name, uint64_t size, uint64_t align,
-		      uint32_t flags)
+odp_shm_t odp_shm_reserve(const char *name, uint64_t size, uint64_t align,
+			  uint32_t flags)
 {
-	int i;
+	uint32_t i;
 	odp_shm_block_t *block;
 	void *addr;
 	int fd = -1;
@@ -105,12 +124,10 @@ void *odp_shm_reserve(const char *name, uint64_t size, uint64_t align,
 	/* If already exists: O_EXCL: error, O_TRUNC: truncate to zero */
 	int oflag = O_RDWR | O_CREAT | O_TRUNC;
 	uint64_t alloc_size = size + align;
-#ifdef MAP_HUGETLB
-	uint64_t huge_sz, page_sz;
+	uint64_t page_sz, huge_sz;
 
 	huge_sz = odp_sys_huge_page_size();
 	page_sz = odp_sys_page_size();
-#endif
 
 	if (flags & ODP_SHM_PROC) {
 		/* Creates a file to /dev/shm */
@@ -119,12 +136,12 @@ void *odp_shm_reserve(const char *name, uint64_t size, uint64_t align,
 
 		if (fd == -1) {
 			ODP_DBG("odp_shm_reserve: shm_open failed\n");
-			return NULL;
+			return ODP_SHM_INVALID;
 		}
 
 		if (ftruncate(fd, alloc_size) == -1) {
 			ODP_DBG("odp_shm_reserve: ftruncate failed\n");
-			return NULL;
+			return ODP_SHM_INVALID;
 		}
 
 	} else {
@@ -133,11 +150,11 @@ void *odp_shm_reserve(const char *name, uint64_t size, uint64_t align,
 
 	odp_spinlock_lock(&odp_shm_tbl->lock);
 
-	if (find_block(name) >= 0) {
+	if (find_block(name, NULL)) {
 		/* Found a block with the same name */
 		odp_spinlock_unlock(&odp_shm_tbl->lock);
 		ODP_DBG("odp_shm_reserve: name already used\n");
-		return NULL;
+		return ODP_SHM_INVALID;
 	}
 
 	for (i = 0; i < ODP_SHM_NUM_BLOCKS; i++) {
@@ -151,13 +168,14 @@ void *odp_shm_reserve(const char *name, uint64_t size, uint64_t align,
 		/* Table full */
 		odp_spinlock_unlock(&odp_shm_tbl->lock);
 		ODP_DBG("odp_shm_reserve: no more blocks\n");
-		return NULL;
+		return ODP_SHM_INVALID;
 	}
 
 	block = &odp_shm_tbl->block[i];
 
-	addr        = MAP_FAILED;
+	block->hdl  = to_handle(i);
 	block->huge = 0;
+	addr        = MAP_FAILED;
 
 #ifdef MAP_HUGETLB
 	/* Try first huge pages */
@@ -171,16 +189,17 @@ void *odp_shm_reserve(const char *name, uint64_t size, uint64_t align,
 	if (addr == MAP_FAILED) {
 		addr = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE,
 			    map_flag, fd, 0);
-
+		block->page_sz = page_sz;
 	} else {
-		block->huge = 1;
+		block->huge    = 1;
+		block->page_sz = huge_sz;
 	}
 
 	if (addr == MAP_FAILED) {
 		/* Alloc failed */
 		odp_spinlock_unlock(&odp_shm_tbl->lock);
 		ODP_DBG("odp_shm_reserve: mmap failed\n");
-		return NULL;
+		return ODP_SHM_INVALID;
 	}
 
 	block->addr_orig = addr;
@@ -192,31 +211,66 @@ void *odp_shm_reserve(const char *name, uint64_t size, uint64_t align,
 	block->name[ODP_SHM_NAME_LEN - 1] = 0;
 	block->size   = size;
 	block->align  = align;
+	block->flags  = flags;
+	block->fd     = fd;
 	block->addr   = addr;
 
 	odp_spinlock_unlock(&odp_shm_tbl->lock);
-	return addr;
+	return block->hdl;
 }
 
 
-void *odp_shm_lookup(const char *name)
+odp_shm_t odp_shm_lookup(const char *name)
 {
-	int i;
-	void *addr;
+	uint32_t i;
+	odp_shm_t hdl;
 
 	odp_spinlock_lock(&odp_shm_tbl->lock);
 
-	i = find_block(name);
-
-	if (i < 0) {
+	if (find_block(name, &i) == 0) {
 		odp_spinlock_unlock(&odp_shm_tbl->lock);
-		return NULL;
+		return ODP_SHM_INVALID;
 	}
 
-	addr = odp_shm_tbl->block[i].addr;
+	hdl = odp_shm_tbl->block[i].hdl;
 	odp_spinlock_unlock(&odp_shm_tbl->lock);
 
-	return addr;
+	return hdl;
+}
+
+
+void *odp_shm_addr(odp_shm_t shm)
+{
+	uint32_t i;
+
+	i = from_handle(shm);
+
+	if (i > (ODP_SHM_NUM_BLOCKS - 1))
+		return NULL;
+
+	return odp_shm_tbl->block[i].addr;
+}
+
+
+int odp_shm_info(odp_shm_t shm, odp_shm_info_t *info)
+{
+	odp_shm_block_t *block;
+	uint32_t i;
+
+	i = from_handle(shm);
+
+	if (i > (ODP_SHM_NUM_BLOCKS - 1))
+		return -1;
+
+	block = &odp_shm_tbl->block[i];
+
+	info->name      = block->name;
+	info->addr      = block->addr;
+	info->size      = block->size;
+	info->page_size = block->page_sz;
+	info->flags     = block->flags;
+
+	return 0;
 }
 
 
diff --git a/test/api_test/odp_shm_test.c b/test/api_test/odp_shm_test.c
index 376b06f..6208e78 100644
--- a/test/api_test/odp_shm_test.c
+++ b/test/api_test/odp_shm_test.c
@@ -19,6 +19,7 @@ static void *run_thread(void *arg)
 {
 	pthrd_arg *parg = (pthrd_arg *)arg;
 	int thr;
+	odp_shm_t shm;
 
 	thr = odp_thread_id();
 
@@ -26,7 +27,8 @@ static void *run_thread(void *arg)
 
 	switch (parg->testcase) {
 	case ODP_SHM_TEST:
-		test_shared_data = odp_shm_lookup("test_shared_data");
+		shm = odp_shm_lookup("test_shared_data");
+		test_shared_data = odp_shm_addr(shm);
 		printf("  [%i] shared data at %p\n", thr, test_shared_data);
 		break;
 	default:
@@ -40,14 +42,16 @@ static void *run_thread(void *arg)
 int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED)
 {
 	pthrd_arg thrdarg;
+	odp_shm_t shm;
 
 	if (odp_test_global_init() != 0)
 		return -1;
 
 	odp_print_system_info();
 
-	test_shared_data = odp_shm_reserve("test_shared_data",
-					   sizeof(test_shared_data_t), 128, 0);
+	shm = odp_shm_reserve("test_shared_data",
+			      sizeof(test_shared_data_t), 128, 0);
+	test_shared_data = odp_shm_addr(shm);
 	memset(test_shared_data, 0, sizeof(test_shared_data_t));
 	printf("test shared data at %p\n\n", test_shared_data);
 
diff --git a/test/api_test/odp_timer_ping.c b/test/api_test/odp_timer_ping.c
index a31567a..5ae379f 100644
--- a/test/api_test/odp_timer_ping.c
+++ b/test/api_test/odp_timer_ping.c
@@ -315,6 +315,7 @@ int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED)
 	odp_buffer_pool_t pool;
 	void *pool_base;
 	int i;
+	odp_shm_t shm;
 
 	if (odp_test_global_init() != 0)
 		return -1;
@@ -327,8 +328,9 @@ int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED)
 	/*
 	 * Create message pool
 	 */
-	pool_base = odp_shm_reserve("msg_pool",
-				    MSG_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+	shm = odp_shm_reserve("msg_pool",
+			      MSG_POOL_SIZE, ODP_CACHE_LINE_SIZE, 0);
+	pool_base = odp_shm_addr(shm);
 
 	pool = odp_buffer_pool_create("msg_pool", pool_base, MSG_POOL_SIZE,
 				      BUF_SIZE,
