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 3e72952..a4079aa 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 */
@@ -549,7 +552,11 @@ void odph_ring_list_dump(void)
 /* search a ring from its name */
 odph_ring_t *odph_ring_lookup(const char *name)
 {
-	odph_ring_t *r = odp_shm_lookup(name);
+	odp_shm_t shm;
+	odph_ring_t *r;
+
+	shm = odp_shm_lookup(name);
+	r   = odp_shm_addr(shm);
 
 	odp_rwlock_read_lock(&qlock);
 	TAILQ_FOREACH(r, &odp_ring_list, next) {
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;
 }
 
 
