[04/19] hdata/tpmrel.c: register CVC services during HDAT parsing

Message ID 1510421322-27237-5-git-send-email-cclaudio@linux.vnet.ibm.com
State Superseded
Headers show
Series
  • libstb: add support for secure and trusted boot in P9
Related show

Commit Message

Claudio Carvalho Nov. 11, 2017, 5:28 p.m.
This registers the address range of the Container-Verification-Code
(CVC) and then registers each CVC service provided. The offset of
each service is checked to make sure that it is not out of the CVC
address range.

The hostboot reserved memory that stores the CVC is identified by
parsing the msvpd_hb_reserved_mem HDAT structure. In order to register
its address range, we call the cvc_register() libstb function.

The CVC services provided are identified by parsing the hash_and_verify
HDAT structure. In order to register them, we call the
cvc_service_register() libstb function.

This also updates the hdat_to_dt unit test adding one stub for each
libstb function called.

Since skiboot is the only consumer for the CVC services, this patch
doesn't add them to the device tree.

Signed-off-by: Claudio Carvalho <cclaudio@linux.vnet.ibm.com>
---
 hdata/spira.h       |  12 ++++++
 hdata/test/stubs.c  |   2 +
 hdata/tpmrel.c      |  90 +++++++++++++++++++++++++++++++++++++++++
 libstb/Makefile.inc |   2 +-
 libstb/cvc.c        | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 libstb/cvc.h        |  29 +++++++++++++
 6 files changed, 248 insertions(+), 1 deletion(-)
 create mode 100644 libstb/cvc.c
 create mode 100644 libstb/cvc.h

Comments

Oliver O'Halloran Nov. 21, 2017, 4:59 a.m. | #1
On Sun, Nov 12, 2017 at 4:28 AM, Claudio Carvalho
<cclaudio@linux.vnet.ibm.com> wrote:
> This registers the address range of the Container-Verification-Code
> (CVC) and then registers each CVC service provided. The offset of
> each service is checked to make sure that it is not out of the CVC
> address range.
>
> The hostboot reserved memory that stores the CVC is identified by
> parsing the msvpd_hb_reserved_mem HDAT structure. In order to register
> its address range, we call the cvc_register() libstb function.
>
> The CVC services provided are identified by parsing the hash_and_verify
> HDAT structure. In order to register them, we call the
> cvc_service_register() libstb function.
>
> This also updates the hdat_to_dt unit test adding one stub for each
> libstb function called.
>
> Since skiboot is the only consumer for the CVC services, this patch
> doesn't add them to the device tree.
>
> Signed-off-by: Claudio Carvalho <cclaudio@linux.vnet.ibm.com>
> ---
>  hdata/spira.h       |  12 ++++++
>  hdata/test/stubs.c  |   2 +
>  hdata/tpmrel.c      |  90 +++++++++++++++++++++++++++++++++++++++++
>  libstb/Makefile.inc |   2 +-
>  libstb/cvc.c        | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  libstb/cvc.h        |  29 +++++++++++++
>  6 files changed, 248 insertions(+), 1 deletion(-)
>  create mode 100644 libstb/cvc.c
>  create mode 100644 libstb/cvc.h
>
> 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);

 The parsing here seems to be a duplicate of what's in memory.c. At
this point it should have already been parsed into
/ibm,hostboot/reserved-memory/ in the device-tree, so why not look it
up there?

> +       cvc_register(start_addr, end_addr);

As an aside we try to keep this sort of thing out of the HDAT parser.
In theory we should be able to boot off just a device-tree and have
everything work. The main application of that is allowing cronus
booting. Granted secure cronus booting doesn't make a whole lot of
sense it's not really a problem here, but it's something to keep in
mind.

> +       /*
> +        * 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 */
> --
> 2.7.4
>
Stewart Smith Nov. 22, 2017, 1:06 a.m. | #2
Oliver <oohall@gmail.com> writes:
> On Sun, Nov 12, 2017 at 4:28 AM, Claudio Carvalho
> <cclaudio@linux.vnet.ibm.com> wrote:
>> This registers the address range of the Container-Verification-Code
>> (CVC) and then registers each CVC service provided. The offset of
>> each service is checked to make sure that it is not out of the CVC
>> address range.
>>
>> The hostboot reserved memory that stores the CVC is identified by
>> parsing the msvpd_hb_reserved_mem HDAT structure. In order to register
>> its address range, we call the cvc_register() libstb function.
>>
>> The CVC services provided are identified by parsing the hash_and_verify
>> HDAT structure. In order to register them, we call the
>> cvc_service_register() libstb function.
>>
>> This also updates the hdat_to_dt unit test adding one stub for each
>> libstb function called.
>>
>> Since skiboot is the only consumer for the CVC services, this patch
>> doesn't add them to the device tree.
>>
>> Signed-off-by: Claudio Carvalho <cclaudio@linux.vnet.ibm.com>
>> ---
>>  hdata/spira.h       |  12 ++++++
>>  hdata/test/stubs.c  |   2 +
>>  hdata/tpmrel.c      |  90 +++++++++++++++++++++++++++++++++++++++++
>>  libstb/Makefile.inc |   2 +-
>>  libstb/cvc.c        | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  libstb/cvc.h        |  29 +++++++++++++
>>  6 files changed, 248 insertions(+), 1 deletion(-)
>>  create mode 100644 libstb/cvc.c
>>  create mode 100644 libstb/cvc.h
>>
>> 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);
>
>  The parsing here seems to be a duplicate of what's in memory.c. At
> this point it should have already been parsed into
> /ibm,hostboot/reserved-memory/ in the device-tree, so why not look it
> up there?

I'd prefer that too, If the label isn't there for CVC code, then we
should probably just create one based off the ID.

>> +       cvc_register(start_addr, end_addr);
>
> As an aside we try to keep this sort of thing out of the HDAT parser.
> In theory we should be able to boot off just a device-tree and have
> everything work. The main application of that is allowing cronus
> booting. Granted secure cronus booting doesn't make a whole lot of
> sense it's not really a problem here, but it's something to keep in
> mind.

and we may not always go via HDAT too.
Vasant Hegde Nov. 28, 2017, 6:54 a.m. | #3
On 11/11/2017 10:58 PM, Claudio Carvalho wrote:
> This registers the address range of the Container-Verification-Code
> (CVC) and then registers each CVC service provided. The offset of
> each service is checked to make sure that it is not out of the CVC
> address range.
>
> The hostboot reserved memory that stores the CVC is identified by
> parsing the msvpd_hb_reserved_mem HDAT structure. In order to register
> its address range, we call the cvc_register() libstb function.
>
> The CVC services provided are identified by parsing the hash_and_verify
> HDAT structure. In order to register them, we call the
> cvc_service_register() libstb function.
>
> This also updates the hdat_to_dt unit test adding one stub for each
> libstb function called.
>
> Since skiboot is the only consumer for the CVC services, this patch
> doesn't add them to the device tree.
>
> Signed-off-by: Claudio Carvalho <cclaudio@linux.vnet.ibm.com>
> ---
>  hdata/spira.h       |  12 ++++++
>  hdata/test/stubs.c  |   2 +
>  hdata/tpmrel.c      |  90 +++++++++++++++++++++++++++++++++++++++++
>  libstb/Makefile.inc |   2 +-
>  libstb/cvc.c        | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  libstb/cvc.h        |  29 +++++++++++++
>  6 files changed, 248 insertions(+), 1 deletion(-)
>  create mode 100644 libstb/cvc.c
>  create mode 100644 libstb/cvc.h
>


.../...

>
> 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)
> +{
> +

May be we should add another property inside reserved-memory to identify 
reserved-memory type and use it here. Because today its just secureboot. 
Tomorrow someone else may want to use type field.


> +	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);

Like Oliver mentioned you can add these properties to DT, and then call 
cvc_service_register outside hdata parsing.


-Vasant
Claudio Carvalho Nov. 29, 2017, 1:15 a.m. | #4
On 21/11/2017 23:06, Stewart Smith wrote:
> Oliver <oohall@gmail.com> writes:
>> On Sun, Nov 12, 2017 at 4:28 AM, Claudio Carvalho
>> <cclaudio@linux.vnet.ibm.com> wrote:
>>> This registers the address range of the Container-Verification-Code
>>> (CVC) and then registers each CVC service provided. The offset of
>>> each service is checked to make sure that it is not out of the CVC
>>> address range.
>>>
>>> The hostboot reserved memory that stores the CVC is identified by
>>> parsing the msvpd_hb_reserved_mem HDAT structure. In order to register
>>> its address range, we call the cvc_register() libstb function.
>>>
>>> The CVC services provided are identified by parsing the hash_and_verify
>>> HDAT structure. In order to register them, we call the
>>> cvc_service_register() libstb function.
>>>
>>> This also updates the hdat_to_dt unit test adding one stub for each
>>> libstb function called.
>>>
>>> Since skiboot is the only consumer for the CVC services, this patch
>>> doesn't add them to the device tree.
>>>
>>> Signed-off-by: Claudio Carvalho <cclaudio@linux.vnet.ibm.com>
>>> ---
>>>   hdata/spira.h       |  12 ++++++
>>>   hdata/test/stubs.c  |   2 +
>>>   hdata/tpmrel.c      |  90 +++++++++++++++++++++++++++++++++++++++++
>>>   libstb/Makefile.inc |   2 +-
>>>   libstb/cvc.c        | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>   libstb/cvc.h        |  29 +++++++++++++
>>>   6 files changed, 248 insertions(+), 1 deletion(-)
>>>   create mode 100644 libstb/cvc.c
>>>   create mode 100644 libstb/cvc.h
>>>
>>> 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);
>>   The parsing here seems to be a duplicate of what's in memory.c. At
>> this point it should have already been parsed into
>> /ibm,hostboot/reserved-memory/ in the device-tree, so why not look it
>> up there?
> I'd prefer that too, If the label isn't there for CVC code, then we
> should probably just create one based off the ID.

Correct, the parsing code above is partially duplicated from what exists 
in memory.c. However, I can't look at /ibm,hostboot/reserved-memory 
because the HDAT spec doesn't define the name for reserved memory 
regions, it defines only their types. I could look at 
/ibm,hostboot/reserved-memory if the children have the type, but 
currently they don't have it. It exists only in the HDAT.

>
>>> +       cvc_register(start_addr, end_addr);
>> As an aside we try to keep this sort of thing out of the HDAT parser.
>> In theory we should be able to boot off just a device-tree and have
>> everything work. The main application of that is allowing cronus
>> booting. Granted secure cronus booting doesn't make a whole lot of
>> sense it's not really a problem here, but it's something to keep in
>> mind.
> and we may not always go via HDAT too.
Claudio Carvalho Nov. 29, 2017, 2:37 a.m. | #5
On 28/11/2017 04:54, Vasant Hegde wrote:
> On 11/11/2017 10:58 PM, Claudio Carvalho wrote:
>> This registers the address range of the Container-Verification-Code
>> (CVC) and then registers each CVC service provided. The offset of
>> each service is checked to make sure that it is not out of the CVC
>> address range.
>>
>> The hostboot reserved memory that stores the CVC is identified by
>> parsing the msvpd_hb_reserved_mem HDAT structure. In order to register
>> its address range, we call the cvc_register() libstb function.
>>
>> The CVC services provided are identified by parsing the hash_and_verify
>> HDAT structure. In order to register them, we call the
>> cvc_service_register() libstb function.
>>
>> This also updates the hdat_to_dt unit test adding one stub for each
>> libstb function called.
>>
>> Since skiboot is the only consumer for the CVC services, this patch
>> doesn't add them to the device tree.
>>
>> Signed-off-by: Claudio Carvalho <cclaudio@linux.vnet.ibm.com>
>> ---
>>  hdata/spira.h       |  12 ++++++
>>  hdata/test/stubs.c  |   2 +
>>  hdata/tpmrel.c      |  90 +++++++++++++++++++++++++++++++++++++++++
>>  libstb/Makefile.inc |   2 +-
>>  libstb/cvc.c        | 114 
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  libstb/cvc.h        |  29 +++++++++++++
>>  6 files changed, 248 insertions(+), 1 deletion(-)
>>  create mode 100644 libstb/cvc.c
>>  create mode 100644 libstb/cvc.h
>>
>
>
> .../...
>
>>
>> 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)
>> +{
>> +
>
> May be we should add another property inside reserved-memory to 
> identify reserved-memory type and use it here. Because today its just 
> secureboot. Tomorrow someone else may want to use type field.

hmm ... maybe we don't need to add another property. Double checking the 
HDAT spec, it defines that the label for the CVC reserved memory is 
"ibm,secure-crypt-algo-code" and skiboot uses the label for the 
reserved-memory node name and its "ibm,prd-label", see below. If it is 
OK, I can iterate on the /ibm,hostboot/reserved-memory children looking 
for ibm,prd-label="ibm,secure-crypt-algo-code".

                 ibm,secure-crypt-algo-code@ffd330000 {
                         ibm,prd-label = "ibm,secure-crypt-algo-code";
                         ibm,prd-instance = <0x0>;
                         phandle = <0x545>;
                         reg = <0xf 0xfd330000 0x0 0x10000>;
                 };

If we can't rely on ibm,prd-label, then I think we would need to tweak 
hdata/memory.c to add the memory region type whenever it is 
provided/exists. Roughly speaking, it would be something like this:

@@ -496,9 +501,9 @@ static void get_hb_reserved_mem(struct 
HDIF_common_hdr *ms_vpd)
                 }

                 prlog(PR_DEBUG, "MEM: Reserve '%s' %#" PRIx64 "-%#" 
PRIx64 " (type/inst=0x%08x)\n",
                      label, start_addr, end_addr, 
be32_to_cpu(hb_resv_mem->type_instance));

-               node = add_hb_reserve_node(label, start_addr, end_addr);
+               node = add_hb_reserve_node(label, start_addr, end_addr, 
&type);
                 if (!node) {
                         prerror("unable to add node?\n");
                         continue;
@@ -554,7 +559,7 @@ static void parse_trace_reservations(struct 
HDIF_common_hdr *ms_vpd)
                         "MS VPD: Trace area: 
0x%.16"PRIx64"-0x%.16"PRIx64"\n",
                         start, end);

-               node = add_hb_reserve_node("trace-area", start, end);
+               node = add_hb_reserve_node("trace-area", start, end, NULL);
                 if (!node) {
                         prerror("MEM: Unable to reserve trace area 
%p-%p\n",
                                 (void *) start, (void *) end);

@@ -401,7 +401,8 @@ static void get_msareas(struct dt_node *root,

  static struct dt_node *dt_hb_reserves;

-static struct dt_node *add_hb_reserve_node(const char *name, u64 start, 
u64 end)
+static struct dt_node *add_hb_reserve_node(const char *name, u64 start, 
u64 end,
+                                          u32 *type)
  {
         struct dt_node *node, *hb;

@@ -424,6 +425,8 @@ static struct dt_node *add_hb_reserve_node(const 
char *name, u64 start, u64 end)
         }

         dt_add_property_u64s(node, "reg", start, end - start + 1);
+      if (type)
+               dt_add_property_cells(node, "type", *type);

         return node;
  }

>
>
>> +    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);
>
> Like Oliver mentioned you can add these properties to DT, and then 
> call cvc_service_register outside hdata parsing.
>

Right. I will add the /ibm,secureboot/ibm,cvc node as DT_PRIVATE and 
then call cvc_service_register outside of hdat parsing.

                 ibm,cvc {
                         phandle = <0xd9>;
                         #address-cells = <0x1>;
                         #size-cells = <0x0>;
                         compatible = "ibm,container-verification-code";
                         memory-region = <0x81>;      ;; This points to 
the /ibm,hostboot/reserved-memory/ibm,secure-crypt-algo-code/phandle

                         ibm,cvc-offset@40 {
                                 phandle = <0xda>;
                                 compatible = "ibm,cvc-sha512";
                                 reg = <0x40>;
                                 version = 1;
                         };

                         ibm,cvc-offset@50 {
                                 phandle = <0xdb>;
                                 compatible = "ibm,cvc-verify";
                                 reg = <0x50>;
                                 version = 1;
                         };
                 }


Claudio
Claudio Carvalho Nov. 29, 2017, 11:40 a.m. | #6
>>> 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)
>>> +{
>>> +
>>
>> May be we should add another property inside reserved-memory to 
>> identify reserved-memory type and use it here. Because today its just 
>> secureboot. Tomorrow someone else may want to use type field.
>
> hmm ... maybe we don't need to add another property. Double checking 
> the HDAT spec, it defines that the label for the CVC reserved memory 
> is "ibm,secure-crypt-algo-code" and skiboot uses the label for the 
> reserved-memory node name and its "ibm,prd-label", see below. If it is 
> OK, I can iterate on the /ibm,hostboot/reserved-memory children 
> looking for ibm,prd-label="ibm,secure-crypt-algo-code".
>
>                 ibm,secure-crypt-algo-code@ffd330000 {
>                         ibm,prd-label = "ibm,secure-crypt-algo-code";
>                         ibm,prd-instance = <0x0>;
>                         phandle = <0x545>;
>                         reg = <0xf 0xfd330000 0x0 0x10000>;
>                 };
>

Actually, just realized that ibm,prd-instance is the reserved memory 
type. I can use it to identify the CVC reserved memory. Thank you.

Claudio


>>
>>> +    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);
>>
>> Like Oliver mentioned you can add these properties to DT, and then 
>> call cvc_service_register outside hdata parsing.
>>
>
> Right. I will add the /ibm,secureboot/ibm,cvc node as DT_PRIVATE and 
> then call cvc_service_register outside of hdat parsing.
>
>                 ibm,cvc {
>                         phandle = <0xd9>;
>                         #address-cells = <0x1>;
>                         #size-cells = <0x0>;
>                         compatible = "ibm,container-verification-code";
>                         memory-region = <0x81>;      ;; This points to 
> the /ibm,hostboot/reserved-memory/ibm,secure-crypt-algo-code/phandle
>
>                         ibm,cvc-offset@40 {
>                                 phandle = <0xda>;
>                                 compatible = "ibm,cvc-sha512";
>                                 reg = <0x40>;
>                                 version = 1;
>                         };
>
>                         ibm,cvc-offset@50 {
>                                 phandle = <0xdb>;
>                                 compatible = "ibm,cvc-verify";
>                                 reg = <0x50>;
>                                 version = 1;
>                         };
>                 }
>
>
> Claudio
>
Oliver O'Halloran Nov. 29, 2017, 10:15 p.m. | #7
On Wed, Nov 29, 2017 at 10:40 PM, Claudio Carvalho
<cclaudio@linux.vnet.ibm.com> wrote:
>
>
>>>> 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)
>>>> +{
>>>> +
>>>
>>>
>>> May be we should add another property inside reserved-memory to identify
>>> reserved-memory type and use it here. Because today its just secureboot.
>>> Tomorrow someone else may want to use type field.
>>
>>
>> hmm ... maybe we don't need to add another property. Double checking the
>> HDAT spec, it defines that the label for the CVC reserved memory is
>> "ibm,secure-crypt-algo-code" and skiboot uses the label for the
>> reserved-memory node name and its "ibm,prd-label", see below. If it is OK, I
>> can iterate on the /ibm,hostboot/reserved-memory children looking for
>> ibm,prd-label="ibm,secure-crypt-algo-code".
>>
>>                 ibm,secure-crypt-algo-code@ffd330000 {
>>                         ibm,prd-label = "ibm,secure-crypt-algo-code";
>>                         ibm,prd-instance = <0x0>;
>>                         phandle = <0x545>;
>>                         reg = <0xf 0xfd330000 0x0 0x10000>;
>>                 };
>>
>
> Actually, just realized that ibm,prd-instance is the reserved memory type. I
> can use it to identify the CVC reserved memory. Thank you.
>
> Claudio

Can you check where the prd-label comes from first? IIRC they are
added late in the boot process based on the region names, but if
that's a problem then we can probably just add them in the HDAT parser
rather than as a later step.

>
>
>
>>>
>>>> +    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"more information in the XIVE );
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    for (i = 0; i < count; i++) {more information in the XIVE more information in the XIVE more information in the XIVE
>>>> +more information in the XIVE more information in the XIVE more information in the XIVE
>>>> +        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);
>>>
>>>
>>> Like Oliver mentioned you can add these properties to DT, and then call
>>> cvc_service_register outside hdata parsing.
>>>
>>
>> Right. I will add the /ibm,secureboot/ibm,cvc node as DT_PRIVATE and then
>> call cvc_service_register outside of hdat parsing.
>>
>>                 ibm,cvc {
>>                         phandle = <0xd9>;
>>                         #address-cells = <0x1>;
>>                         #size-cells = <0x0>;
>>                         compatible = "ibm,container-verification-code";
>>                         memory-region = <0x81>;      ;; This points to the
>> /ibm,hostboot/reserved-memory/ibm,secure-crypt-algo-code/phandle
>>
>>                         ibm,cvc-offset@40 {
>>                                 phandle = <0xda>;
>>                                 compatible = "ibm,cvc-sha512";
>>                                 reg = <0x40>;
>>                                 version = 1;
>>                         };
>>
>>                         ibm,cvc-offset@50 {
>>                                 phandle = <0xdb>;
>>                                 compatible = "ibm,cvc-verify";
>>                                 reg = <0x50>;
>>                                 version = 1;
>>                         };
>>                 }
>>
>>
>> Claudio
>>
>
Vasant Hegde Nov. 30, 2017, 12:48 p.m. | #8
On 11/30/2017 03:45 AM, Oliver wrote:
> On Wed, Nov 29, 2017 at 10:40 PM, Claudio Carvalho
> <cclaudio@linux.vnet.ibm.com> wrote:
>>
>>
>>>>> 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)
>>>>> +{
>>>>> +
>>>>
>>>>
>>>> May be we should add another property inside reserved-memory to identify
>>>> reserved-memory type and use it here. Because today its just secureboot.
>>>> Tomorrow someone else may want to use type field.
>>>
>>>
>>> hmm ... maybe we don't need to add another property. Double checking the
>>> HDAT spec, it defines that the label for the CVC reserved memory is
>>> "ibm,secure-crypt-algo-code" and skiboot uses the label for the
>>> reserved-memory node name and its "ibm,prd-label", see below. If it is OK, I
>>> can iterate on the /ibm,hostboot/reserved-memory children looking for
>>> ibm,prd-label="ibm,secure-crypt-algo-code".
>>>
>>>                 ibm,secure-crypt-algo-code@ffd330000 {
>>>                         ibm,prd-label = "ibm,secure-crypt-algo-code";
>>>                         ibm,prd-instance = <0x0>;
>>>                         phandle = <0x545>;
>>>                         reg = <0xf 0xfd330000 0x0 0x10000>;
>>>                 };
>>>
>>
>> Actually, just realized that ibm,prd-instance is the reserved memory type. I
>> can use it to identify the CVC reserved memory. Thank you.
>>
>> Claudio
>
> Can you check where the prd-label comes from first? IIRC they are
> added late in the boot process based on the region names, but if
> that's a problem then we can probably just add them in the HDAT parser
> rather than as a later step.

So in P8, hostboot just passes reserved memory region. Hence we ended up adding 
prd-label just before loading payload. In P9 we are adding prd-label as part of 
device tree creation itself.

So P9 it should be fine to use prd-label from device tree.

-Vasant

Patch

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 */