diff --git a/hdata/spira.h b/hdata/spira.h
index 88fd2bf..328fb8d 100644
--- a/hdata/spira.h
+++ b/hdata/spira.h
@@ -528,6 +528,8 @@ struct msvpd_trace {
 /* Idata index 5: Hostboot reserved memory address range */
 #define MSVPD_IDATA_HB_RESERVED_MEM	5
 struct msvpd_hb_reserved_mem {
+#define MSVPD_HBRMEM_RANGE_TYPE	PPC_BITMASK32(0,7)
+#define HBRMEM_CONTAINER_VERIFICATION_CODE 	0x3
 	__be32		type_instance;
 	__be64		start_addr;
 	__be64		end_addr;
@@ -1258,6 +1260,16 @@ struct secureboot_tpm_info {
 	__be32 drtm_log_size;
 } __packed;
 
+/* Idata index 2: Hash and Verification Function Offsets Array */
+#define TPMREL_IDATA_HASH_VERIF_OFFSETS 	2
+
+struct hash_and_verification {
+	__be32 type;
+	__be32 version;
+	__be32 dbob_id;
+	__be32 offset;
+} __packed;
+
 static inline const char *cpu_state(u32 flags)
 {
 	switch ((flags & CPU_ID_VERIFY_MASK) >> CPU_ID_VERIFY_SHIFT) {
diff --git a/hdata/test/stubs.c b/hdata/test/stubs.c
index abeb832..ce1384d 100644
--- a/hdata/test/stubs.c
+++ b/hdata/test/stubs.c
@@ -117,4 +117,6 @@ NOOP_STUB(mem_reserve_hwbuf);
 NOOP_STUB(add_chip_dev_associativity);
 NOOP_STUB(enable_mambo_console);
 NOOP_STUB(backtrace);
+NOOP_STUB(cvc_register);
+NOOP_STUB(cvc_service_register);
 
diff --git a/hdata/tpmrel.c b/hdata/tpmrel.c
index 0aaa70b..11ed3ce 100644
--- a/hdata/tpmrel.c
+++ b/hdata/tpmrel.c
@@ -20,6 +20,8 @@
 
 #include <skiboot.h>
 #include <device.h>
+#include <inttypes.h>
+#include <libstb/cvc.h>
 
 #include "spira.h"
 #include "hdata.h"
@@ -72,6 +74,93 @@ static void tpmrel_add_firmware_event_log(const struct HDIF_common_hdr *hdif_hdr
 	}
 }
 
+static const struct msvpd_hb_reserved_mem *get_cvc_reserved_memory(void)
+{
+
+	const struct msvpd_hb_reserved_mem *hb_resv_mem;
+	const struct HDIF_common_hdr *ms_vpd;
+	uint32_t type;
+	int count, i;
+
+	ms_vpd = get_hdif(&spira.ntuples.ms_vpd, MSVPD_HDIF_SIG);
+
+	if (!ms_vpd) {
+		prlog(PR_ERR, "MS VPD invalid\n");
+		return NULL;
+	}
+
+	count = HDIF_get_iarray_size(ms_vpd, MSVPD_IDATA_HB_RESERVED_MEM);
+	if (count <= 0) {
+		prlog(PR_ERR, "no hostboot reserved memory found\n");
+		return NULL;
+	}
+
+	for (i = 0; i < count; i++) {
+		hb_resv_mem = HDIF_get_iarray_item(ms_vpd,
+						   MSVPD_IDATA_HB_RESERVED_MEM,
+						   i, NULL);
+		if (!CHECK_SPPTR(hb_resv_mem))
+			continue;
+
+		type = be32_to_cpu(hb_resv_mem->type_instance);
+		type = GETFIELD(MSVPD_HBRMEM_RANGE_TYPE, type);
+
+		/* Reserved memory for the Container Verification Code? */
+		if (type == HBRMEM_CONTAINER_VERIFICATION_CODE)
+			return hb_resv_mem;
+	}
+
+	return NULL;
+}
+
+#define HRMOR_BIT (1ul << 63)
+
+static void tpmrel_cvc_init(struct HDIF_common_hdr *hdif_hdr)
+{
+	const struct hash_and_verification *hv;
+	const struct msvpd_hb_reserved_mem *cvc_resv_mem;
+	uint32_t type, version, offset;
+	uint64_t start_addr, end_addr;
+	int count, i;
+
+	cvc_resv_mem = get_cvc_reserved_memory();
+
+	if (!cvc_resv_mem) {
+		prlog(PR_ERR, "CVC reserved memory not found\n");
+		return;
+	}
+
+	start_addr = be64_to_cpu(cvc_resv_mem->start_addr);
+	start_addr &= ~HRMOR_BIT;
+	end_addr = be64_to_cpu(cvc_resv_mem->end_addr);
+	end_addr &= ~HRMOR_BIT;
+	prlog(PR_DEBUG, "Found CVC at 0x%"PRIx64"...0x%"PRIx64"\n",
+	      start_addr, end_addr);
+	cvc_register(start_addr, end_addr);
+	/*
+	 * Initialize each service provided by the container verification code
+	 */
+	count = HDIF_get_iarray_size(hdif_hdr, TPMREL_IDATA_HASH_VERIF_OFFSETS);
+	if (count <= 0 ) {
+		prlog(PR_ERR, "no CVC service found\n");
+		return;
+	}
+
+	for (i = 0; i < count; i++) {
+
+		hv = HDIF_get_iarray_item(hdif_hdr,
+					  TPMREL_IDATA_HASH_VERIF_OFFSETS,
+					  i, NULL);
+		type = be32_to_cpu(hv->type);
+		version = be32_to_cpu(hv->version);
+		offset = be32_to_cpu(hv->offset);
+
+		prlog(PR_DEBUG, "Found CVC service. type=0x%x version=%d "
+		      "offset=0x%x\n", type, version, offset);
+		cvc_service_register(type, version, offset);
+	}
+}
+
 void node_stb_parse(void)
 {
 	struct HDIF_common_hdr *hdif_hdr;
@@ -87,4 +176,5 @@ void node_stb_parse(void)
 	}
 
 	tpmrel_add_firmware_event_log(hdif_hdr);
+	tpmrel_cvc_init(hdif_hdr);
 }
diff --git a/libstb/Makefile.inc b/libstb/Makefile.inc
index 64be4d6..010e4b1 100644
--- a/libstb/Makefile.inc
+++ b/libstb/Makefile.inc
@@ -4,7 +4,7 @@ LIBSTB_DIR = libstb
 
 SUBDIRS += $(LIBSTB_DIR)
 
-LIBSTB_SRCS = container.c rom.c tpm_chip.c stb.c
+LIBSTB_SRCS = container.c rom.c tpm_chip.c stb.c cvc.c
 LIBSTB_OBJS = $(LIBSTB_SRCS:%.c=%.o)
 LIBSTB = $(LIBSTB_DIR)/built-in.o
 
diff --git a/libstb/cvc.c b/libstb/cvc.c
new file mode 100644
index 0000000..ebf0ecf
--- /dev/null
+++ b/libstb/cvc.c
@@ -0,0 +1,114 @@
+/* Copyright 2013-2017 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) "STB: " fmt
+#endif
+
+#include <skiboot.h>
+#include "cvc.h"
+
+struct cvc_service {
+	int id;
+	uint64_t addr;    /* base_addr + offset */
+	uint32_t version;
+	struct list_node link;
+};
+
+struct container_verification_code {
+	uint64_t start_addr;
+	uint64_t end_addr;
+	struct list_head service_list;
+};
+
+static struct {
+	enum cvc_service_id id;
+	const char *name;
+} cvc_sevice_map[] = {
+	{ CVC_SHA512_SERVICE, "sha512" },
+	{ CVC_VERIFY_SERVICE, "verify" },
+};
+
+static struct container_verification_code *cvc = NULL;
+
+static struct cvc_service *cvc_find_service(enum cvc_service_id id)
+{
+	struct cvc_service *service;
+	if (!cvc)
+		return NULL;
+
+	list_for_each(&cvc->service_list, service, link) {
+		if (service->id == id)
+			return service;
+	}
+	return NULL;
+}
+
+static const char *cvc_get_service_name(enum cvc_service_id id)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(cvc_sevice_map); i++) {
+		if (cvc_sevice_map[i].id == id)
+			return cvc_sevice_map[i].name;
+	}
+	return NULL;
+}
+
+void cvc_register(uint64_t start_addr, uint64_t end_addr)
+{
+	if (cvc)
+		return;
+
+	cvc = malloc(sizeof(struct container_verification_code));
+	assert(cvc);
+	cvc->start_addr = start_addr;
+	cvc->end_addr = end_addr;
+	list_head_init(&cvc->service_list);
+}
+
+void cvc_service_register(uint32_t id, uint32_t version, uint32_t offset)
+{
+	struct cvc_service *service;
+	const char *name;
+
+	if (!cvc)
+		return;
+
+	/* Service already registered? */
+	if (cvc_find_service(id))
+		return;
+
+	if (cvc->start_addr + offset > cvc->end_addr) {
+		prlog(PR_WARNING, "CVC offset %x out of range, "
+		      "id=0x%x\n", offset, id);
+		return;
+	}
+
+	name = cvc_get_service_name(id);
+	if (!name) {
+		prlog(PR_ERR, "CVC service 0x%x not supported\n", id);
+		return;
+	}
+
+	service = malloc(sizeof(struct cvc_service));
+	assert(service);
+	service->id = id;
+	service->version = version;
+	service->addr = cvc->start_addr + offset;
+	list_add_tail(&cvc->service_list, &service->link);
+	prlog(PR_INFO, "CVC-%s service found @0x%llx\n", name, service->addr);
+}
diff --git a/libstb/cvc.h b/libstb/cvc.h
new file mode 100644
index 0000000..8b5700c
--- /dev/null
+++ b/libstb/cvc.h
@@ -0,0 +1,29 @@
+/* Copyright 2013-2017 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CVC_H
+#define __CVC_H
+
+/* As defined in the HDAT spec version 10.5e */
+enum cvc_service_id {
+	CVC_SHA512_SERVICE = 0x00,
+	CVC_VERIFY_SERVICE = 0x01,
+};
+
+void cvc_register(uint64_t start_addr, uint64_t end_addr);
+void cvc_service_register(uint32_t type, uint32_t version, uint32_t offset);
+
+#endif /* __CVC_H */
