LCOV - code coverage report
Current view: top level - drivers/crypto/qat - qat_sym.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 1 159 0.6 %
Date: 2024-01-22 15:55:54 Functions: 1 9 11.1 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 70 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2015-2023 Intel Corporation
       3                 :            :  */
       4                 :            : 
       5                 :            : #ifdef RTE_QAT_OPENSSL
       6                 :            : #include <openssl/evp.h>
       7                 :            : #endif
       8                 :            : 
       9                 :            : #include <rte_mempool.h>
      10                 :            : #include <rte_mbuf.h>
      11                 :            : #include <rte_crypto_sym.h>
      12                 :            : #include <bus_pci_driver.h>
      13                 :            : #include <rte_byteorder.h>
      14                 :            : #include <rte_security_driver.h>
      15                 :            : 
      16                 :            : #include "qat_sym.h"
      17                 :            : #include "qat_crypto.h"
      18                 :            : #include "qat_qp.h"
      19                 :            : 
      20                 :            : uint8_t qat_sym_driver_id;
      21                 :            : int qat_legacy_capa;
      22                 :            : 
      23                 :            : struct qat_crypto_gen_dev_ops qat_sym_gen_dev_ops[QAT_N_GENS];
      24                 :            : 
      25                 :            : /* An rte_driver is needed in the registration of both the device and the driver
      26                 :            :  * with cryptodev.
      27                 :            :  * The actual qat pci's rte_driver can't be used as its name represents
      28                 :            :  * the whole pci device with all services. Think of this as a holder for a name
      29                 :            :  * for the crypto part of the pci device.
      30                 :            :  */
      31                 :            : static const char qat_sym_drv_name[] = RTE_STR(CRYPTODEV_NAME_QAT_SYM_PMD);
      32                 :            : static const struct rte_driver cryptodev_qat_sym_driver = {
      33                 :            :         .name = qat_sym_drv_name,
      34                 :            :         .alias = qat_sym_drv_name
      35                 :            : };
      36                 :            : 
      37                 :            : void
      38                 :          0 : qat_sym_init_op_cookie(void *op_cookie)
      39                 :            : {
      40                 :            :         struct qat_sym_op_cookie *cookie = op_cookie;
      41                 :            : 
      42                 :          0 :         cookie->qat_sgl_src_phys_addr =
      43                 :            :                         rte_mempool_virt2iova(cookie) +
      44                 :            :                         offsetof(struct qat_sym_op_cookie,
      45                 :            :                         qat_sgl_src);
      46                 :            : 
      47                 :          0 :         cookie->qat_sgl_dst_phys_addr =
      48                 :          0 :                         rte_mempool_virt2iova(cookie) +
      49                 :            :                         offsetof(struct qat_sym_op_cookie,
      50                 :            :                         qat_sgl_dst);
      51                 :            : 
      52                 :          0 :         cookie->opt.spc_gmac.cd_phys_addr =
      53                 :          0 :                         rte_mempool_virt2iova(cookie) +
      54                 :            :                         offsetof(struct qat_sym_op_cookie,
      55                 :            :                         opt.spc_gmac.cd_cipher);
      56                 :            : 
      57                 :          0 :         cookie->digest_null_phys_addr =
      58                 :          0 :                         rte_mempool_virt2iova(cookie) +
      59                 :            :                         offsetof(struct qat_sym_op_cookie,
      60                 :            :                         digest_null);
      61                 :          0 : }
      62                 :            : 
      63                 :            : static __rte_always_inline int
      64                 :          0 : qat_sym_build_request(void *in_op, uint8_t *out_msg,
      65                 :            :                 void *op_cookie, uint64_t *opaque, enum qat_device_gen dev_gen)
      66                 :            : {
      67                 :            :         struct rte_crypto_op *op = (struct rte_crypto_op *)in_op;
      68                 :          0 :         uintptr_t sess = (uintptr_t)opaque[0];
      69                 :          0 :         uintptr_t build_request_p = (uintptr_t)opaque[1];
      70                 :          0 :         qat_sym_build_request_t build_request = (void *)build_request_p;
      71                 :            :         struct qat_sym_session *ctx = NULL;
      72                 :          0 :         enum rte_proc_type_t proc_type = rte_eal_process_type();
      73                 :            : 
      74         [ #  # ]:          0 :         if (proc_type == RTE_PROC_AUTO || proc_type == RTE_PROC_INVALID)
      75                 :            :                 return -EINVAL;
      76                 :            : 
      77         [ #  # ]:          0 :         if (likely(op->sess_type == RTE_CRYPTO_OP_WITH_SESSION)) {
      78                 :          0 :                 ctx = (void *)CRYPTODEV_GET_SYM_SESS_PRIV(op->sym->session);
      79         [ #  # ]:          0 :                 if (sess != (uintptr_t)ctx) {
      80                 :            :                         struct rte_cryptodev *cdev;
      81                 :            :                         struct qat_cryptodev_private *internals;
      82                 :            : 
      83                 :          0 :                         cdev = rte_cryptodev_pmd_get_dev(ctx->dev_id);
      84                 :          0 :                         internals = cdev->data->dev_private;
      85                 :            : 
      86         [ #  # ]:          0 :                         if (internals->qat_dev->qat_dev_gen != dev_gen) {
      87                 :          0 :                                 op->status =
      88                 :            :                                         RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
      89                 :          0 :                                 return -EINVAL;
      90                 :            :                         }
      91                 :            : 
      92         [ #  # ]:          0 :                         if (unlikely(ctx->build_request[proc_type] == NULL)) {
      93                 :            :                                 int ret =
      94                 :          0 :                                 qat_sym_gen_dev_ops[dev_gen].set_session(
      95                 :            :                                         (void *)cdev, (void *)ctx);
      96         [ #  # ]:          0 :                                 if (ret < 0) {
      97                 :          0 :                                         op->status =
      98                 :            :                                                 RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
      99                 :          0 :                                         return -EINVAL;
     100                 :            :                                 }
     101                 :            :                         }
     102                 :            : 
     103                 :          0 :                         build_request = ctx->build_request[proc_type];
     104                 :          0 :                         opaque[0] = (uintptr_t)ctx;
     105                 :          0 :                         opaque[1] = (uintptr_t)build_request;
     106                 :            :                 }
     107         [ #  # ]:          0 :         } else if (op->sess_type == RTE_CRYPTO_OP_SECURITY_SESSION) {
     108                 :          0 :                 ctx = SECURITY_GET_SESS_PRIV(op->sym->session);
     109                 :            :                 if (unlikely(!ctx)) {
     110                 :            :                         QAT_DP_LOG(ERR, "No session for this device");
     111                 :            :                         return -EINVAL;
     112                 :            :                 }
     113         [ #  # ]:          0 :                 if (sess != (uintptr_t)ctx) {
     114                 :            :                         struct rte_cryptodev *cdev;
     115                 :            :                         struct qat_cryptodev_private *internals;
     116                 :            : 
     117                 :            : #ifdef RTE_QAT_OPENSSL
     118         [ #  # ]:          0 :                         if (unlikely(ctx->bpi_ctx == NULL)) {
     119                 :            : #else
     120                 :            :                         if (unlikely(ctx->mb_mgr == NULL)) {
     121                 :            : #endif
     122                 :          0 :                                 QAT_DP_LOG(ERR, "QAT PMD only supports security"
     123                 :            :                                                 " operation requests for"
     124                 :            :                                                 " DOCSIS, op (%p) is not for"
     125                 :            :                                                 " DOCSIS.", op);
     126                 :          0 :                                 return -EINVAL;
     127   [ #  #  #  #  :          0 :                         } else if (unlikely(((op->sym->m_dst != NULL) &&
                   #  # ]
     128                 :            :                                         (op->sym->m_dst != op->sym->m_src)) ||
     129                 :            :                                         op->sym->m_src->nb_segs > 1)) {
     130                 :          0 :                                 QAT_DP_LOG(ERR, "OOP and/or multi-segment"
     131                 :            :                                                 " buffers not supported for"
     132                 :            :                                                 " DOCSIS security.");
     133                 :          0 :                                 op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
     134                 :          0 :                                 return -EINVAL;
     135                 :            :                         }
     136                 :          0 :                         cdev = rte_cryptodev_pmd_get_dev(ctx->dev_id);
     137                 :          0 :                         internals = cdev->data->dev_private;
     138                 :            : 
     139         [ #  # ]:          0 :                         if (internals->qat_dev->qat_dev_gen != dev_gen) {
     140                 :          0 :                                 op->status =
     141                 :            :                                         RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
     142                 :          0 :                                 return -EINVAL;
     143                 :            :                         }
     144                 :            : 
     145         [ #  # ]:          0 :                         if (unlikely(ctx->build_request[proc_type] == NULL)) {
     146                 :            :                                 int ret =
     147                 :          0 :                                 qat_sym_gen_dev_ops[dev_gen].set_session(
     148                 :            :                                         (void *)cdev, (void *)sess);
     149         [ #  # ]:          0 :                                 if (ret < 0) {
     150                 :          0 :                                         op->status =
     151                 :            :                                                 RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
     152                 :          0 :                                         return -EINVAL;
     153                 :            :                                 }
     154                 :            :                         }
     155                 :            : 
     156                 :          0 :                         sess = (uintptr_t)op->sym->session;
     157                 :          0 :                         build_request = ctx->build_request[proc_type];
     158                 :          0 :                         opaque[0] = sess;
     159                 :          0 :                         opaque[1] = (uintptr_t)build_request;
     160                 :            :                 }
     161                 :            :         } else { /* RTE_CRYPTO_OP_SESSIONLESS */
     162                 :          0 :                 op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
     163                 :          0 :                 QAT_LOG(DEBUG, "QAT does not support sessionless operation");
     164                 :          0 :                 return -1;
     165                 :            :         }
     166                 :            : 
     167                 :          0 :         return build_request(op, (void *)ctx, out_msg, op_cookie);
     168                 :            : }
     169                 :            : 
     170                 :            : uint16_t
     171                 :          0 : qat_sym_enqueue_burst(void *qp, struct rte_crypto_op **ops,
     172                 :            :                 uint16_t nb_ops)
     173                 :            : {
     174                 :          0 :         return qat_enqueue_op_burst(qp, qat_sym_build_request,
     175                 :            :                         (void **)ops, nb_ops);
     176                 :            : }
     177                 :            : 
     178                 :            : uint16_t
     179                 :          0 : qat_sym_dequeue_burst(void *qp, struct rte_crypto_op **ops,
     180                 :            :                 uint16_t nb_ops)
     181                 :            : {
     182                 :          0 :         return qat_dequeue_op_burst(qp, (void **)ops,
     183                 :            :                                 qat_sym_process_response, nb_ops);
     184                 :            : }
     185                 :            : 
     186                 :            : int
     187                 :          0 : qat_sym_dev_create(struct qat_pci_device *qat_pci_dev,
     188                 :            :                 struct qat_dev_cmd_param *qat_dev_cmd_param)
     189                 :            : {
     190                 :            :         int i = 0, ret = 0;
     191                 :            :         uint16_t slice_map = 0;
     192                 :            :         struct qat_device_info *qat_dev_instance =
     193                 :          0 :                         &qat_pci_devs[qat_pci_dev->qat_dev_id];
     194                 :          0 :         struct rte_cryptodev_pmd_init_params init_params = {
     195                 :            :                 .name = "",
     196                 :          0 :                 .socket_id = qat_dev_instance->pci_dev->device.numa_node,
     197                 :            :                 .private_data_size = sizeof(struct qat_cryptodev_private)
     198                 :            :         };
     199                 :            :         char name[RTE_CRYPTODEV_NAME_MAX_LEN];
     200                 :            :         char capa_memz_name[RTE_CRYPTODEV_NAME_MAX_LEN];
     201                 :            :         struct rte_cryptodev *cryptodev;
     202                 :            :         struct qat_cryptodev_private *internals;
     203                 :            :         const struct qat_crypto_gen_dev_ops *gen_dev_ops =
     204                 :          0 :                 &qat_sym_gen_dev_ops[qat_pci_dev->qat_dev_gen];
     205                 :            : 
     206                 :            :         snprintf(name, RTE_CRYPTODEV_NAME_MAX_LEN, "%s_%s",
     207                 :          0 :                         qat_pci_dev->name, "sym");
     208                 :          0 :         QAT_LOG(DEBUG, "Creating QAT SYM device %s", name);
     209                 :            : 
     210         [ #  # ]:          0 :         if (gen_dev_ops->cryptodev_ops == NULL) {
     211                 :          0 :                 QAT_LOG(ERR, "Device %s does not support symmetric crypto",
     212                 :            :                                 name);
     213                 :          0 :                 return -(EFAULT);
     214                 :            :         }
     215                 :            : 
     216                 :            :         /*
     217                 :            :          * All processes must use same driver id so they can share sessions.
     218                 :            :          * Store driver_id so we can validate that all processes have the same
     219                 :            :          * value, typically they have, but could differ if binaries built
     220                 :            :          * separately.
     221                 :            :          */
     222         [ #  # ]:          0 :         if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
     223                 :          0 :                 qat_pci_dev->qat_sym_driver_id =
     224                 :            :                                 qat_sym_driver_id;
     225         [ #  # ]:          0 :         } else if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
     226         [ #  # ]:          0 :                 if (qat_pci_dev->qat_sym_driver_id !=
     227                 :            :                                 qat_sym_driver_id) {
     228                 :          0 :                         QAT_LOG(ERR,
     229                 :            :                                 "Device %s have different driver id than corresponding device in primary process",
     230                 :            :                                 name);
     231                 :          0 :                         return -(EFAULT);
     232                 :            :                 }
     233                 :            :         }
     234                 :            : 
     235                 :            :         /* Populate subset device to use in cryptodev device creation */
     236                 :          0 :         qat_dev_instance->sym_rte_dev.driver = &cryptodev_qat_sym_driver;
     237                 :          0 :         qat_dev_instance->sym_rte_dev.numa_node =
     238                 :          0 :                         qat_dev_instance->pci_dev->device.numa_node;
     239                 :          0 :         qat_dev_instance->sym_rte_dev.devargs = NULL;
     240                 :            : 
     241                 :          0 :         cryptodev = rte_cryptodev_pmd_create(name,
     242                 :            :                         &(qat_dev_instance->sym_rte_dev), &init_params);
     243                 :            : 
     244         [ #  # ]:          0 :         if (cryptodev == NULL)
     245                 :            :                 return -ENODEV;
     246                 :            : 
     247                 :          0 :         qat_dev_instance->sym_rte_dev.name = cryptodev->data->name;
     248                 :          0 :         cryptodev->driver_id = qat_sym_driver_id;
     249                 :          0 :         cryptodev->dev_ops = gen_dev_ops->cryptodev_ops;
     250                 :            : 
     251                 :          0 :         cryptodev->enqueue_burst = qat_sym_enqueue_burst;
     252                 :          0 :         cryptodev->dequeue_burst = qat_sym_dequeue_burst;
     253                 :            : 
     254                 :          0 :         cryptodev->feature_flags = gen_dev_ops->get_feature_flags(qat_pci_dev);
     255                 :            : 
     256         [ #  # ]:          0 :         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
     257                 :            :                 return 0;
     258                 :            : 
     259         [ #  # ]:          0 :         if (gen_dev_ops->create_security_ctx) {
     260                 :          0 :                 cryptodev->security_ctx =
     261                 :          0 :                         gen_dev_ops->create_security_ctx((void *)cryptodev);
     262         [ #  # ]:          0 :                 if (cryptodev->security_ctx == NULL) {
     263                 :          0 :                         QAT_LOG(ERR, "rte_security_ctx memory alloc failed");
     264                 :            :                         ret = -ENOMEM;
     265                 :          0 :                         goto error;
     266                 :            :                 }
     267                 :            : 
     268                 :          0 :                 cryptodev->feature_flags |= RTE_CRYPTODEV_FF_SECURITY;
     269                 :          0 :                 QAT_LOG(INFO, "Device %s rte_security support ensabled", name);
     270                 :            :         } else {
     271                 :          0 :                 QAT_LOG(INFO, "Device %s rte_security support disabled", name);
     272                 :            :         }
     273                 :            :         snprintf(capa_memz_name, RTE_CRYPTODEV_NAME_MAX_LEN,
     274                 :            :                         "QAT_SYM_CAPA_GEN_%d",
     275                 :          0 :                         qat_pci_dev->qat_dev_gen);
     276                 :            : 
     277                 :          0 :         internals = cryptodev->data->dev_private;
     278                 :          0 :         internals->qat_dev = qat_pci_dev;
     279                 :            : 
     280                 :          0 :         internals->dev_id = cryptodev->data->dev_id;
     281                 :            : 
     282         [ #  # ]:          0 :         while (qat_dev_cmd_param[i].name != NULL) {
     283         [ #  # ]:          0 :                 if (!strcmp(qat_dev_cmd_param[i].name, SYM_ENQ_THRESHOLD_NAME))
     284                 :          0 :                         internals->min_enq_burst_threshold =
     285                 :          0 :                                         qat_dev_cmd_param[i].val;
     286         [ #  # ]:          0 :                 if (!strcmp(qat_dev_cmd_param[i].name,
     287                 :            :                                 SYM_CIPHER_CRC_ENABLE_NAME))
     288                 :          0 :                         internals->cipher_crc_offload_enable =
     289                 :          0 :                                         qat_dev_cmd_param[i].val;
     290         [ #  # ]:          0 :                 if (!strcmp(qat_dev_cmd_param[i].name, QAT_LEGACY_CAPA))
     291                 :          0 :                         qat_legacy_capa = qat_dev_cmd_param[i].val;
     292         [ #  # ]:          0 :                 if (!strcmp(qat_dev_cmd_param[i].name, QAT_CMD_SLICE_MAP))
     293                 :          0 :                         slice_map = qat_dev_cmd_param[i].val;
     294                 :          0 :                 i++;
     295                 :            :         }
     296                 :            : 
     297         [ #  # ]:          0 :         if (gen_dev_ops->get_capabilities(internals,
     298                 :            :                         capa_memz_name, slice_map) < 0) {
     299                 :          0 :                 QAT_LOG(ERR,
     300                 :            :                         "Device cannot obtain capabilities, destroying PMD for %s",
     301                 :            :                         name);
     302                 :            :                 ret = -1;
     303                 :          0 :                 goto error;
     304                 :            :         }
     305                 :          0 :         internals->service_type = QAT_SERVICE_SYMMETRIC;
     306                 :          0 :         qat_pci_dev->sym_dev = internals;
     307                 :          0 :         QAT_LOG(DEBUG, "Created QAT SYM device %s as cryptodev instance %d",
     308                 :            :                         cryptodev->data->name, internals->dev_id);
     309                 :            : 
     310                 :          0 :         return 0;
     311                 :            : 
     312                 :          0 : error:
     313                 :          0 :         rte_free(cryptodev->security_ctx);
     314                 :          0 :         cryptodev->security_ctx = NULL;
     315                 :          0 :         rte_cryptodev_pmd_destroy(cryptodev);
     316                 :            :         memset(&qat_dev_instance->sym_rte_dev, 0,
     317                 :            :                 sizeof(qat_dev_instance->sym_rte_dev));
     318                 :            : 
     319                 :          0 :         return ret;
     320                 :            : }
     321                 :            : 
     322                 :            : int
     323                 :          0 : qat_sym_dev_destroy(struct qat_pci_device *qat_pci_dev)
     324                 :            : {
     325                 :            :         struct rte_cryptodev *cryptodev;
     326                 :            : 
     327         [ #  # ]:          0 :         if (qat_pci_dev == NULL)
     328                 :            :                 return -ENODEV;
     329         [ #  # ]:          0 :         if (qat_pci_dev->sym_dev == NULL)
     330                 :            :                 return 0;
     331         [ #  # ]:          0 :         if (rte_eal_process_type() == RTE_PROC_PRIMARY)
     332                 :          0 :                 rte_memzone_free(qat_pci_dev->sym_dev->capa_mz);
     333                 :            : 
     334                 :            :         /* free crypto device */
     335                 :          0 :         cryptodev = rte_cryptodev_pmd_get_dev(qat_pci_dev->sym_dev->dev_id);
     336                 :          0 :         rte_free(cryptodev->security_ctx);
     337                 :          0 :         cryptodev->security_ctx = NULL;
     338                 :          0 :         rte_cryptodev_pmd_destroy(cryptodev);
     339                 :          0 :         qat_pci_devs[qat_pci_dev->qat_dev_id].sym_rte_dev.name = NULL;
     340                 :          0 :         qat_pci_dev->sym_dev = NULL;
     341                 :            : 
     342                 :          0 :         return 0;
     343                 :            : }
     344                 :            : 
     345                 :            : int
     346                 :          0 : qat_sym_configure_dp_ctx(struct rte_cryptodev *dev, uint16_t qp_id,
     347                 :            :         struct rte_crypto_raw_dp_ctx *raw_dp_ctx,
     348                 :            :         enum rte_crypto_op_sess_type sess_type,
     349                 :            :         union rte_cryptodev_session_ctx session_ctx, uint8_t is_update)
     350                 :            : {
     351                 :          0 :         struct qat_cryptodev_private *internals = dev->data->dev_private;
     352                 :          0 :         enum qat_device_gen qat_dev_gen = internals->qat_dev->qat_dev_gen;
     353                 :            :         struct qat_crypto_gen_dev_ops *gen_dev_ops =
     354                 :            :                         &qat_sym_gen_dev_ops[qat_dev_gen];
     355                 :            :         struct qat_qp *qp;
     356                 :            :         struct qat_sym_session *ctx;
     357                 :            :         struct qat_sym_dp_ctx *dp_ctx;
     358                 :            : 
     359         [ #  # ]:          0 :         if (!gen_dev_ops->set_raw_dp_ctx) {
     360                 :          0 :                 QAT_LOG(ERR, "Device GEN %u does not support raw data path",
     361                 :            :                                 qat_dev_gen);
     362                 :          0 :                 return -ENOTSUP;
     363                 :            :         }
     364                 :            : 
     365                 :          0 :         qp = dev->data->queue_pairs[qp_id];
     366                 :            :         dp_ctx = (struct qat_sym_dp_ctx *)raw_dp_ctx->drv_ctx_data;
     367                 :            : 
     368         [ #  # ]:          0 :         if (!is_update) {
     369                 :            :                 memset(raw_dp_ctx, 0, sizeof(*raw_dp_ctx) +
     370                 :            :                                 sizeof(struct qat_sym_dp_ctx));
     371                 :          0 :                 raw_dp_ctx->qp_data = dev->data->queue_pairs[qp_id];
     372                 :          0 :                 dp_ctx->tail = qp->tx_q.tail;
     373                 :          0 :                 dp_ctx->head = qp->rx_q.head;
     374                 :            :                 dp_ctx->cached_enqueue = dp_ctx->cached_dequeue = 0;
     375                 :            :         }
     376                 :            : 
     377         [ #  # ]:          0 :         if (sess_type != RTE_CRYPTO_OP_WITH_SESSION)
     378                 :            :                 return -EINVAL;
     379                 :            : 
     380                 :          0 :         ctx = CRYPTODEV_GET_SYM_SESS_PRIV(session_ctx.crypto_sess);
     381                 :            : 
     382                 :          0 :         dp_ctx->session = ctx;
     383                 :            : 
     384                 :          0 :         return gen_dev_ops->set_raw_dp_ctx(raw_dp_ctx, ctx);
     385                 :            : }
     386                 :            : 
     387                 :            : int
     388                 :          0 : qat_sym_get_dp_ctx_size(struct rte_cryptodev *dev __rte_unused)
     389                 :            : {
     390                 :          0 :         return sizeof(struct qat_sym_dp_ctx);
     391                 :            : }
     392                 :            : 
     393                 :            : static struct cryptodev_driver qat_crypto_drv;
     394                 :        235 : RTE_PMD_REGISTER_CRYPTO_DRIVER(qat_crypto_drv,
     395                 :            :                 cryptodev_qat_sym_driver,
     396                 :            :                 qat_sym_driver_id);

Generated by: LCOV version 1.14