From patchwork Thu Aug 28 10:16:31 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Taras Kondratiuk X-Patchwork-Id: 36175 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-vc0-f199.google.com (mail-vc0-f199.google.com [209.85.220.199]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 7F4CB202DD for ; Thu, 28 Aug 2014 10:17:01 +0000 (UTC) Received: by mail-vc0-f199.google.com with SMTP id id10sf2563246vcb.6 for ; Thu, 28 Aug 2014 03:17:01 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:in-reply-to :references:cc:subject:precedence:list-id:list-unsubscribe :list-archive:list-post:list-help:list-subscribe:mime-version :errors-to:sender:x-original-sender :x-original-authentication-results:mailing-list:content-type :content-transfer-encoding; bh=MlUL6tSpAU/fWTKrIYjN4AuvhZq6qyXeD3RSLMFBoUQ=; b=e63+wg6syRwqb/UaUIM5bM2M2vWzHV24lolNt/rO2oxPYMA14Ndey2CfQYcI6Bce7v ZLBzRtZD09YWgdH/BEJXFZn6kD2ItSVES+nubjNlZvj/0dps0TUmiABxGEwOchOzM/ju eBuikds8bGYlm5hDul6jVC1KBdcl22egW4O1x5GdbDeNXh98eMkKOSa3Ix7bt41mr2Jm VfrGVJzFLxWkmA2+SxaYy4ISznTJUtoT+3VgTrDBGq1QQ5IFkJeCwcem15mMfp3wHZVC BaQ6cxSX/fImMPSRMdmBT4PZSYL3TbRJFspwYs7RNVNZDgZmUAgQfB0eBGJMR7o9veK2 XG0g== X-Gm-Message-State: ALoCoQmG7csnAwl+bOw3rdeJlgzrt1mC/V5OGdTGpx/cZdDl9XrBfQH5tA3K7QPx60GTMFaxvJZN X-Received: by 10.236.100.134 with SMTP id z6mr1657464yhf.8.1409221021282; Thu, 28 Aug 2014 03:17:01 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.49.235 with SMTP id q98ls483502qga.91.gmail; Thu, 28 Aug 2014 03:17:01 -0700 (PDT) X-Received: by 10.220.81.132 with SMTP id x4mr2396566vck.0.1409221021166; Thu, 28 Aug 2014 03:17:01 -0700 (PDT) Received: from mail-vc0-f176.google.com (mail-vc0-f176.google.com [209.85.220.176]) by mx.google.com with ESMTPS id ct1si2997932vdc.80.2014.08.28.03.17.01 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 28 Aug 2014 03:17:01 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.176 as permitted sender) client-ip=209.85.220.176; Received: by mail-vc0-f176.google.com with SMTP id ik5so538892vcb.35 for ; Thu, 28 Aug 2014 03:17:01 -0700 (PDT) X-Received: by 10.52.138.210 with SMTP id qs18mr1977972vdb.18.1409221021043; Thu, 28 Aug 2014 03:17:01 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.221.45.67 with SMTP id uj3csp211818vcb; Thu, 28 Aug 2014 03:17:00 -0700 (PDT) X-Received: by 10.224.88.137 with SMTP id a9mr4901871qam.88.1409221020227; Thu, 28 Aug 2014 03:17:00 -0700 (PDT) Received: from ip-10-141-164-156.ec2.internal (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTPS id j52si4968324qga.27.2014.08.28.03.16.59 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Thu, 28 Aug 2014 03:17:00 -0700 (PDT) Received-SPF: none (google.com: lng-odp-bounces@lists.linaro.org does not designate permitted sender hosts) client-ip=54.225.227.206; Received: from localhost ([127.0.0.1] helo=ip-10-141-164-156.ec2.internal) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1XMwlG-0004N2-Gc; Thu, 28 Aug 2014 10:16:58 +0000 Received: from mail-la0-f51.google.com ([209.85.215.51]) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1XMwl4-0004MV-U2 for lng-odp@lists.linaro.org; Thu, 28 Aug 2014 10:16:47 +0000 Received: by mail-la0-f51.google.com with SMTP id gl10so647220lab.10 for ; Thu, 28 Aug 2014 03:16:41 -0700 (PDT) X-Received: by 10.112.42.167 with SMTP id p7mr2961697lbl.83.1409221000978; Thu, 28 Aug 2014 03:16:40 -0700 (PDT) Received: from uglx0153363.synapse.com ([195.238.92.128]) by mx.google.com with ESMTPSA id j3sm2080216lah.0.2014.08.28.03.16.40 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 28 Aug 2014 03:16:40 -0700 (PDT) From: Taras Kondratiuk To: lng-odp@lists.linaro.org Date: Thu, 28 Aug 2014 13:16:31 +0300 Message-Id: <1409220991-12011-4-git-send-email-taras.kondratiuk@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1409220991-12011-1-git-send-email-taras.kondratiuk@linaro.org> References: <1409220991-12011-1-git-send-email-taras.kondratiuk@linaro.org> X-Topics: crypto patch Cc: Taras Kondratiuk Subject: [lng-odp] [PATCHv2 3/3] linux-keystone2: Add intial crypto implementation X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Errors-To: lng-odp-bounces@lists.linaro.org Sender: lng-odp-bounces@lists.linaro.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: taras.kondratiuk@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.176 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 The patch implements asynchronous out-of-place ODP crypto operations: results are stored in a new buffer. Implementation based on NWAL library. Signed-off-by: Taras Kondratiuk Signed-off-by: Taras Kondratiuk --- platform/linux-keystone2/Makefile.am | 2 + platform/linux-keystone2/README | 2 +- platform/linux-keystone2/include/api/odp_crypto.h | 375 +++++++++++++++ .../linux-keystone2/include/odp_crypto_internal.h | 84 ++++ platform/linux-keystone2/include/odp_internal.h | 2 + platform/linux-keystone2/odp_crypto.c | 490 ++++++++++++++++++++ platform/linux-keystone2/odp_init.c | 5 + 7 files changed, 959 insertions(+), 1 deletion(-) create mode 100644 platform/linux-keystone2/include/api/odp_crypto.h create mode 100644 platform/linux-keystone2/include/odp_crypto_internal.h create mode 100644 platform/linux-keystone2/odp_crypto.c diff --git a/platform/linux-keystone2/Makefile.am b/platform/linux-keystone2/Makefile.am index c94edf2..61b58b7 100644 --- a/platform/linux-keystone2/Makefile.am +++ b/platform/linux-keystone2/Makefile.am @@ -19,6 +19,7 @@ LIBS += $(KS2_LIBS) include_HEADERS = \ $(srcdir)/include/api/odp_buffer.h \ $(srcdir)/include/api/odp_buffer_pool.h \ + $(srcdir)/include/api/odp_crypto.h \ $(srcdir)/include/api/odp_packet.h \ $(srcdir)/include/api/odp_packet_io.h \ $(srcdir)/include/api/odp_debug.h \ @@ -63,6 +64,7 @@ subdirheaders_HEADERS = \ __LIB__libodp_la_SOURCES = \ odp_buffer.c \ odp_buffer_pool.c \ + odp_crypto.c \ odp_init.c \ odp_packet.c \ odp_packet_io.c \ diff --git a/platform/linux-keystone2/README b/platform/linux-keystone2/README index 207acf2..9a7e807 100644 --- a/platform/linux-keystone2/README +++ b/platform/linux-keystone2/README @@ -7,7 +7,7 @@ SPDX-License-Identifier: BSD-3-Clause 1. Intro OpenDataPlane implementation for TI Keystone2 SoC's. Current version supports -HW buffer, queues and Packet IO management. This drop does not target high +HW buffer, queues, Packet IO and Crypto APIs. This drop does not target high performance. It is rather proof of ODP API functionality. It still uses linux-generic's SW scheduler. diff --git a/platform/linux-keystone2/include/api/odp_crypto.h b/platform/linux-keystone2/include/api/odp_crypto.h new file mode 100644 index 0000000..9082f9b --- /dev/null +++ b/platform/linux-keystone2/include/api/odp_crypto.h @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2014, Linaro Limited + * Copyright (c) 2014, Texas Instruments Incorporated + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * ODP crypto + */ + +#ifndef ODP_CRYPTO_H_ +#define ODP_CRYPTO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include + +/** Invalid session handle */ +#define ODP_CRYPTO_SESSION_INVALID NULL + +/** + * Crypto API opaque session handle + */ +typedef struct odp_crypto_session_s *odp_crypto_session_t; + +/** + * Crypto API operation mode + */ +enum odp_crypto_op_mode { + ODP_CRYPTO_SYNC, /**< Synchronous, return results immediately */ + ODP_CRYPTO_ASYNC, /**< Aynchronous, return results via posted event */ +}; + +/** + * Crypto API operation type + */ +enum odp_crypto_op { + ODP_CRYPTO_OP_ENCODE, /**< Encrypt and/or compute authentication ICV */ + ODP_CRYPTO_OP_DECODE /**< Decrypt and/or verify authentication ICV */ +}; + +/** + * Crypto API cipher algorithm + */ +enum odp_cipher_alg { + ODP_CIPHER_ALG_NULL = NWAL_SA_EALG_NULL, /**< No cipher algorithm specified */ + ODP_CIPHER_ALG_DES = NWAL_SA_EALG_DES_CBC, /**< DES */ + ODP_CIPHER_ALG_3DES_CBC = NWAL_SA_EALG_3DES_CBC, /**< Triple DES with cipher block chaining */ + ODP_CIPHER_ALG_AES_CBC = NWAL_SA_EALG_AES_CBC, + ODP_CIPHER_ALG_AES_CTR = NWAL_SA_EALG_AES_CTR, + ODP_CIPHER_ALG_AES_GCM = NWAL_SA_EALG_AES_GCM, + ODP_CIPHER_ALG_AES_CCM = NWAL_SA_EALG_AES_CCM, +}; + +/** + * Crypto API authentication algorithm + */ +enum odp_auth_alg { + ODP_AUTH_ALG_NULL = NWAL_SA_AALG_NULL, /**< No authentication algorithm specified */ + ODP_AUTH_ALG_MD5_96 = NWAL_SA_AALG_HMAC_MD5, /**< HMAC-MD5 with 96 bit key */ + ODP_AUTH_ALG_HMAC_SHA1 = NWAL_SA_AALG_HMAC_SHA1, +}; + +/** + * Crypto API key structure + */ +typedef struct odp_crypto_key { + uint8_t *data; /**< Key data */ + uint32_t length; /**< Key length in bytes */ +} odp_crypto_key_t; + +/** + * Crypto API IV structure + */ +typedef struct odp_crypto_iv { + uint8_t *data; /**< IV data */ + uint32_t length; /**< IV length in bytes */ +} odp_crypto_iv_t; + +/** + * Crypto API data range specifier + */ +typedef struct odp_crypto_data_range { + uint32_t offset; /**< Offset from beginning of buffer (chain) */ + uint32_t length; /**< Length of data to operate on */ +} odp_crypto_data_range_t; + +/** + * Crypto API session creation paramters + * + * @todo Add "odp_session_proc_info_t" + */ +typedef struct odp_crypto_session_params { + enum odp_crypto_op op; /**< Encode versus decode */ + bool auth_cipher_text; /**< Authenticate/cipher ordering */ + enum odp_crypto_op_mode pref_mode; /**< Preferred sync vs async */ + enum odp_cipher_alg cipher_alg; /**< Cipher algorithm */ + odp_crypto_key_t cipher_key; /**< Cipher key */ + odp_crypto_iv_t iv; /**< Cipher Initialization Vector (IV) */ + enum odp_auth_alg auth_alg; /**< Authentication algorithm */ + odp_crypto_key_t auth_key; /**< Authentication key */ + odp_queue_t compl_queue; /**< Async mode completion event queue */ + odp_buffer_pool_t output_pool; /**< Output buffer pool */ +} odp_crypto_session_params_t; + +/** + * @var odp_crypto_session_params_t::auth_cipher_text + * + * Controls ordering of authentication and cipher operations, + * and is relative to the operation (encode vs decode). + * When encoding, @c TRUE indicates the authentication operation + * should be peformed @b after the cipher operation else before. + * When decoding, @c TRUE indicates the reverse order of operation. + * + * @var odp_crypto_session_params_t::compl_queue + * + * When the API operates asynchronously, the completion queue is + * used to return the completion status of the operation to the + * application. + * + * @var odp_crypto_session_params_t::output_pool + * + * When the output packet is not specified during the call to + * odp_crypto_operation, the output packet buffer will be allocated + * from this pool. + */ + +/** + * Crypto API per packet operation parameters + * + * @todo Clarify who zero's ICV and how this relates to "hash_result_offset" + */ +typedef struct odp_crypto_op_params { + odp_crypto_session_t session; /**< Session handle from creation */ + odp_packet_t pkt; /**< Input packet buffer */ + odp_packet_t out_pkt; /**< Output packet buffer */ + uint8_t *override_iv_ptr; /**< Override session IV pointer */ + uint32_t hash_result_offset; /**< Offset from start of packet buffer for hash result */ + odp_crypto_data_range_t cipher_range; /**< Data range to apply cipher */ + odp_crypto_data_range_t auth_range; /**< Data range to authenticate */ +} odp_crypto_op_params_t; + +/** + * @var odp_crypto_op_params_t::pkt + * Specifies the input packet buffer for the crypto operation. When the + * @c out_pkt variable is set to @c ODP_PACKET_INVALID (indicating a new + * buffer should be allocated for the resulting packet), the #define TBD + * indicates whether the implementation will free the input packet buffer + * or if it becomes the responsibility of the caller. + * + * @var odp_crypto_op_params_t::out_pkt + * + * The API supports both "in place" (the original packet "pkt" is + * modified) and "copy" (the packet is replicated to a new buffer + * which contains the modified data). + * + * The "in place" mode of operation is indicated by setting @c out_pkt + * equal to @c pkt. For the copy mode of operation, setting @c out_pkt + * to a valid packet buffer value indicates the caller wishes to specify + * the destination buffer. Setting @c out_pkt to @c ODP_PACKET_INVALID + * indicates the caller wishes the destination packet buffer be allocated + * from the output pool specified during session creation. + * + * @sa odp_crypto_session_params_t::output_pool. + */ + +/** + * Crypto API session creation return code + */ +enum odp_crypto_ses_create_err { + ODP_CRYPTO_SES_CREATE_ERR_NONE, /**< Session created */ + ODP_CRYPTO_SES_CREATE_ERR_ENOMEM, /**< Creation failed, no resources */ + ODP_CRYPTO_SES_CREATE_ERR_INV_CIPHER, /**< Creation failed, bad cipher params */ + ODP_CRYPTO_SES_CREATE_ERR_INV_AUTH, /**< Creation failed, bad auth params */ +}; + +/** + * Crypto API algorithm return code + */ +enum crypto_alg_err { + ODP_CRYPTO_ALG_ERR_NONE, /**< Algorithm successful */ + ODP_CRYPTO_ALG_ERR_DATA_SIZE, /**< Invalid data block size */ + ODP_CRYPTO_ALG_ERR_KEY_SIZE, /**< Key size invalid for algorithm */ + ODP_CRYPTO_ALG_ERR_ICV_CHECK, /**< Computed ICV value mismatch */ +}; + +/** + * Crypto API hardware centric return code + */ +enum crypto_hw_err { + ODP_CRYPTO_HW_ERR_NONE, /**< Operation completed successfully */ + ODP_CRYPTO_HW_ERR_DMA, /**< Error detected during DMA of data */ + ODP_CRYPTO_HW_ERR_BP_DEPLETED, /**< Operation failed due to buffer pool depletion */ +}; + +/** + * Cryto API per packet operation completion status + */ +typedef struct odp_crypto_compl_status { + enum crypto_alg_err alg_err; /**< Algorithm specific return code */ + enum crypto_hw_err hw_err; /**< Hardware specific return code */ +} odp_crypto_compl_status_t; + + +/** + * Crypto session creation (synchronouse) + * + * @param params Session parameters + * @param session Created session else ODP_CRYPTO_SESSION_INVALID + * @param status Failure code if unsuccessful + * + * @return 0 if successful else -1 + */ +int +odp_crypto_session_create(odp_crypto_session_params_t *params, + odp_crypto_session_t *session, + enum odp_crypto_ses_create_err *status); + +int odp_crypto_session_destroy(odp_crypto_session_t ses); + +/** + * Crypto session creation (asynchronous) + * + * Initiate crypto session creation. Results are delivered using + * the completion event via the completion queue. + * + * @param params Session parameters + * @param completion_event Event by which the session creation results are + * delivered. + * @param completion_queue Queue by which the completion event will be + * delivered. + * + * @return 0 if successful else -1 + * + */ +int +odp_crypto_session_create_async(odp_crypto_session_params_t *params, + odp_buffer_t completion_event, + odp_queue_t completion_queue); + + +/** + * Crypto session creation completion status + * + * Accessor function for obtaining creation status from the completion event. + * + * @param completion_event Event containing operation results + * @param status Pointer to store creation return code + */ +void +odp_crypto_get_ses_create_compl_status(odp_buffer_t completion_event, + enum odp_crypto_ses_create_err *status); + +/** + * Crypto session creation completion return value + * + * Accessor function for obtaining handle for newly created session. + * + * @param completion_event Event containing operation results + * @param session Pointer to store session handle + */ +void +odp_crypto_get_ses_create_compl_session(odp_buffer_t completion_event, + odp_crypto_session_t *session); + +/** + * Crypto per packet operation + * + * Performs the cryptographic operations specified during session creation + * on the packet. If the operation is performed synchronously, "posted" + * will return FALSE and the result of the operation is immediately available + * in the completion event. If "posted" returns TRUE the result will be + * delivered via the completion queue specified when the session was created. + * + * @todo Resolve if completion_event is necessary, can/should the output + * packet buffer always be used instead. + * + * @param params Operation parameters + * @param posted Pointer to return posted, TRUE for async operation + * @param completion_event Event by which the operation results are delivered. + * + * @return 0 if successful else -1 + */ +int +odp_crypto_operation(odp_crypto_op_params_t *params, + bool *posted, + odp_buffer_t completion_event); + +/** + * Crypto per packet operation set user context in completion event + * + * @param completion_event Event containing operation results + * @param ctx User data + */ +void +odp_crypto_set_operation_compl_ctx(odp_buffer_t completion_event, + void *ctx); + +/** + * Crypto per packet operation completion status + * + * Accessor function for obtaining operation status from the completion event. + * + * @param completion_event Event containing operation results + * @param auth Pointer to store authentication results + * @param cipher Pointer to store cipher results + */ +void +odp_crypto_get_operation_compl_status(odp_buffer_t completion_event, + odp_crypto_compl_status_t *auth, + odp_crypto_compl_status_t *cipher); + +/** + * Crypto per packet operation query completed operation packet + * + * Accessor function for obtaining current packet buffer, can be + * different from input packet buffer on some systems + * + * @param completion_event Event containing operation results + * + * @return Packet structure where data now resides + */ +odp_packet_t +odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event); + +/** + * Crypto per packet operation query user context in completion event + * + * @param completion_event Event containing operation results + * + * @return User data + */ +void * +odp_crypto_get_operation_compl_ctx(odp_buffer_t completion_event); + +/** + * Generate random byte string + * + * @param buf Pointer to store result + * @param len Pointer to input length value as well as return value + * @param use_entropy Use entropy + * + * @todo Define the implication of the use_entropy parameter + * + * @return 0 if succesful + */ +int +odp_hw_random_get(uint8_t *buf, size_t *len, bool use_entropy); + +/** + * Initialize the crypto subsystem, called once from main thread + * + * @param max_sessions Maximum number of sessions to support + * + * @return 0 if succesful + */ +int +odp_crypto_init(uint32_t max_sessions); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/platform/linux-keystone2/include/odp_crypto_internal.h b/platform/linux-keystone2/include/odp_crypto_internal.h new file mode 100644 index 0000000..17756fd --- /dev/null +++ b/platform/linux-keystone2/include/odp_crypto_internal.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2014, Linaro Limited + * Copyright (c) 2014, Texas Instruments Incorporated + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ODP_CRYPTO_INTERNAL_H_ +#define ODP_CRYPTO_INTERNAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define OP_RESULT_MAGIC 0x91919191 + +/** Forward declaration of session structure */ +struct odp_crypto_session_s; + +/** + * Algorithm handler function prototype + */ +typedef +enum crypto_alg_err (*crypto_func_t)(struct odp_crypto_op_params *params, + struct odp_crypto_session_s *session); + +#define ODP_CRYPTO_MAX_IV_LENGTH 32 + +struct iv_full { + uint8_t data[ODP_CRYPTO_MAX_IV_LENGTH]; + size_t length; +}; + + +/** + * Per crypto session data structure + */ +struct odp_crypto_session_s { + nwal_Handle dm_handle; + nwalTxDmPSCmdInfo_t dm_ps_cmdinfo; + odp_buffer_pool_t out_pool; + uint32_t out_flow_id; + odp_queue_t compl_queue; + struct { + enum odp_cipher_alg alg; + struct iv_full iv; + } cipher; + + struct { + enum odp_auth_alg alg; + struct iv_full iv; + uint32_t tag_len; + } auth; + + uint32_t index; + enum odp_crypto_op op; +}; + +/** + * Per packet operation result + */ +struct odp_operation_result_s { + uint32_t magic; + struct odp_crypto_compl_status cipher; + struct odp_crypto_compl_status auth; +}; + +/** + * Per session creation operation result + */ +struct odp_session_result_s { + enum odp_crypto_ses_create_err rc; + odp_crypto_session_t session; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/platform/linux-keystone2/include/odp_internal.h b/platform/linux-keystone2/include/odp_internal.h index d043770..bccd14a 100644 --- a/platform/linux-keystone2/include/odp_internal.h +++ b/platform/linux-keystone2/include/odp_internal.h @@ -34,6 +34,8 @@ int odp_pktio_init_global(void); int odp_queue_init_global(void); +int odp_crypto_init_global(void); + int odp_schedule_init_global(void); int odp_schedule_init_local(void); diff --git a/platform/linux-keystone2/odp_crypto.c b/platform/linux-keystone2/odp_crypto.c new file mode 100644 index 0000000..33a2813 --- /dev/null +++ b/platform/linux-keystone2/odp_crypto.c @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2014, Linaro Limited + * Copyright (c) 2014, Texas Instruments Incorporated + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_SESSIONS 32 + +typedef struct { + odp_atomic_u32_t next; + uint32_t max; + struct odp_crypto_session_s sessions[0]; +} odp_crypto_global_t; + +static odp_crypto_global_t *global; + +static struct odp_crypto_session_s *alloc_session(void) +{ + uint32_t idx; + struct odp_crypto_session_s *session = NULL; + + idx = odp_atomic_fetch_inc_u32(&global->next); + if (idx < global->max) { + session = &global->sessions[idx]; + session->index = idx; + } + return session; +} + +static void _print_nwalCreateDmSAParams(nwalCreateDmSAParams_t *dmSaParam) +{ + odp_pr_dbg("dmSaParam.dmChnType = %u\n", + dmSaParam->dmSaParam.dmChnType); + odp_pr_dbg("dmSaParam.authMode = %u\n", dmSaParam->dmSaParam.authMode); + odp_pr_dbg("dmSaParam.cipherMode = %u\n", + dmSaParam->dmSaParam.cipherMode); + odp_pr_dbg("dmSaParam.enc1st = %u\n", dmSaParam->dmSaParam.enc1st); + odp_pr_dbg("dmSaParam.macSize = %u\n", dmSaParam->dmSaParam.macSize); + odp_pr_dbg("dmSaParam.aadSize = %u\n", dmSaParam->dmSaParam.aadSize); + odp_pr_dbg("dmSaParam.replayWindow = %u\n", + dmSaParam->dmSaParam.replayWindow); + + if (dmSaParam->dmSaParam.cipherMode != NWAL_SA_EALG_NULL) + odp_pr_dbg_mem(dmSaParam->keyParam.pEncKey, + dmSaParam->keyParam.encKeySize, + "keyParam.pEncKey"); + if (dmSaParam->dmSaParam.authMode != NWAL_SA_AALG_NULL) + odp_pr_dbg_mem(dmSaParam->keyParam.pAuthKey, + dmSaParam->keyParam.macKeySize, + "keyParam.pAuthKey"); +} + +int odp_crypto_session_create(odp_crypto_session_params_t *params, + odp_crypto_session_t *session_out, + enum odp_crypto_ses_create_err *status) +{ + nwal_RetValue nwal_ret; + nwalCreateDmSAParams_t sa_params; + nwalMbufPool_t rx_pool; + Cppi_FlowHnd out_flow; + struct odp_crypto_session_s *session; + + ODP_ASSERT((params->cipher_alg != ODP_CIPHER_ALG_NULL || + params->auth_alg != ODP_AUTH_ALG_NULL), + "Both algorithms are NULL"); + + if (params->cipher_alg == ODP_CIPHER_ALG_NULL) { + params->cipher_key.data = NULL; + params->cipher_key.length = 0; + } + + if (params->auth_alg == ODP_AUTH_ALG_NULL && + params->cipher_alg != ODP_CIPHER_ALG_AES_GCM && + params->cipher_alg != ODP_CIPHER_ALG_AES_CCM) { + params->auth_key.data = NULL; + params->auth_key.length = 0; + } + + /* Default to failure result */ + *status = ODP_CRYPTO_SES_CREATE_ERR_NONE; + *session_out = ODP_CRYPTO_SESSION_INVALID; + + + /* Allocate memory for this session */ + session = alloc_session(); + if (!session) { + *status = ODP_CRYPTO_SES_CREATE_ERR_ENOMEM; + return -1; + } + + /* Copy stuff over */ + session->op = params->op; + session->cipher.alg = params->cipher_alg; + session->auth.alg = params->auth_alg; + if (sizeof(session->cipher.iv.data) < params->iv.length) { + *status = ODP_CRYPTO_SES_CREATE_ERR_INV_CIPHER; + return -1; + } + memcpy(session->cipher.iv.data, params->iv.data, params->iv.length); + /** @todo: need separate IV for Auth */ + memcpy(session->auth.iv.data, params->iv.data, params->iv.length); + + session->compl_queue = params->compl_queue; + session->out_pool = params->output_pool; + + rx_pool.numBufPools = 1; + rx_pool.bufPool[0].heapHandle = session->out_pool; + rx_pool.bufPool[0].bufSize = + Pktlib_getMaxBufferSize(session->out_pool); + rx_pool.bufPool[0].descSize = TUNE_NETAPI_DESC_SIZE; + + nwal_ret = nwal_SetupFlow(odp_global->nwal.handle, + &rx_pool, + 0, /* buffer header travels via SA, so no offset */ + odp_local.nwal.cfg.rxPktTailRoomSz, + &out_flow, + nwal_FALSE); + + if (nwal_ret != nwal_OK) { + *status = ODP_CRYPTO_SES_CREATE_ERR_ENOMEM; + return -1; + } + + session->out_flow_id = Cppi_getFlowId(out_flow); + + memset(&sa_params, 0, sizeof(nwalCreateDmSAParams_t)); + sa_params.dmSaParam.dmChnType = + (params->op == ODP_CRYPTO_OP_DECODE) ? + NWAL_DM_CHAN_DECRYPT : + NWAL_DM_CHAN_ENCRYPT; + sa_params.dmSaParam.replayWindow = 64; /** @todo: always 64? */ + sa_params.dmSaParam.authMode = params->auth_alg; + sa_params.dmSaParam.cipherMode = params->cipher_alg; + + sa_params.dmSaParam.enc1st = (params->op == ODP_CRYPTO_OP_ENCODE) ? + params->auth_cipher_text : !params->auth_cipher_text; + + if ((sa_params.dmSaParam.cipherMode == NWAL_SA_EALG_AES_GCM) || + (sa_params.dmSaParam.cipherMode == NWAL_SA_EALG_AES_CCM) || + (sa_params.dmSaParam.authMode == NWAL_SA_AALG_GMAC)) { + sa_params.dmSaParam.macSize = 16; + sa_params.dmSaParam.aadSize = 8; + /* Enc1st needs to always be true for combined algorithms */ + sa_params.dmSaParam.enc1st = nwal_TRUE; + } else if (sa_params.dmSaParam.authMode != NWAL_SA_AALG_NULL) { + sa_params.dmSaParam.macSize = 12; + sa_params.dmSaParam.aadSize = 0; + } else { + sa_params.dmSaParam.enc1st = nwal_TRUE; + sa_params.dmSaParam.macSize = 0; + } + + sa_params.keyParam.pEncKey = params->cipher_key.data; + sa_params.keyParam.encKeySize = params->cipher_key.length; + sa_params.keyParam.pAuthKey = params->auth_key.data; + sa_params.keyParam.macKeySize = params->auth_key.length; + + session->auth.tag_len = sa_params.dmSaParam.macSize; + + ODP_ASSERT(session->auth.tag_len <= + ODP_FIELD_SIZEOF(struct odp_pkthdr, crypto.dec.hash_tag), + "Auth tag length is bigger than hash_tag array"); + + _print_nwalCreateDmSAParams(&sa_params); + odp_pr_dbg("Session addr: %p\n", session); + nwal_ret = nwal_setDMSecAssoc(odp_global->nwal.handle, + (nwal_AppId) session, + &sa_params, + &session->dm_handle); + if (nwal_ret != nwal_OK) { + odp_pr_err("nwal_setDMSecAssoc() returned Error Code %d\n", + nwal_ret); + *status = ODP_CRYPTO_SES_CREATE_ERR_ENOMEM; + return -1; + } + + nwal_ret = nwal_initDMPSCmdInfo(odp_global->nwal.handle, + session->dm_handle, + &session->dm_ps_cmdinfo); + + *status = ODP_CRYPTO_SES_CREATE_ERR_NONE; + *session_out = session; + + return 0; +} + +int odp_crypto_session_destroy(odp_crypto_session_t ses) +{ + struct odp_crypto_session_s *session = ses; + nwal_RetValue nwal_ret; + nwal_ret = nwal_delDMSecAssoc(odp_global->nwal.handle, + session->dm_handle); + return (nwal_ret == nwal_OK) ? 0 : 1; +} + +#define ODP_CRYPTO_BUFFER_PROCESSED_OFFSET (-1) + +static inline void hash_copy_be32(uint8_t *dest, const uint32be_t *sa, size_t n) +{ + union hash_u { + uint32_t hash32; + uint8_t hash[4]; + } hash; + + n /= 4; + while (n--) { + unsigned int i; + hash.hash32 = odp_be_to_cpu_32(*sa++); + for (i = 0; i < sizeof(hash.hash); i++) + *dest++ = hash.hash[i]; + }; +} + +static inline int hash_compare_be32(const uint32_t *orig, const uint32be_t *sa, + size_t n) +{ + n /= 4; + while (n--) { + if (*orig++ != odp_be_to_cpu_32(*sa++)) + return 1; + }; + return 0; +} + +/** + * Set bufPtr to origBuffPtr to pass buffer header via SA + * + * @return offset value + */ +static inline int16_t odp_crypto_buffer_preprocess(odp_buffer_t buf) +{ + struct odp_pkthdr *hdr; + int16_t offset; + Cppi_HostDesc *desc; + uint32_t packet_length; + + desc = _odp_buf_to_cppi_desc(buf); + hdr = odp_packet_hdr(odp_packet_from_buffer(buf)); + offset = desc->buffPtr - desc->origBuffPtr; + hdr->crypto.saved_buf_offset = offset; + odp_pr_dbg("buffPtr: 0x%08x, buffLen: 0x%x, offset: %x\n", + desc->buffPtr, desc->buffLen, offset); + desc->buffPtr -= offset; + desc->buffLen += offset; + packet_length = odp_packet_get_len(odp_packet_from_buffer(buf)); + odp_packet_set_len(odp_packet_from_buffer(buf), + packet_length + offset); + odp_pr_vdbg_packet(odp_packet_from_buffer(buf)); + return offset; +} + +/** + * Restore bufPtr after SA operation + * + * @return offset value + */ +static inline void odp_crypto_buffer_postprocess(odp_buffer_t buf, + enum crypto_alg_err *alg_err) +{ + Cppi_HostDesc *desc; + int16_t offset; + uint8_t *auth_tag = NULL; + uint32_t auth_tag_len = 0; + struct odp_pkthdr *hdr; + struct odp_crypto_session_s *session; + Ti_Pkt *pkt; + uint32_t packet_length; + nwal_Bool_t result; + enum crypto_alg_err auth_err = ODP_CRYPTO_ALG_ERR_NONE; + + odp_pr_vdbg_packet(odp_packet_from_buffer(buf)); + hdr = odp_packet_hdr(odp_packet_from_buffer(buf)); + offset = hdr->crypto.saved_buf_offset; + if (offset == ODP_CRYPTO_BUFFER_PROCESSED_OFFSET) { + /* Buffer already post-processed */ + return; + } + ODP_ASSERT(offset >= 0, "Wrong saved buffer offset\n"); + + hdr->crypto.saved_buf_offset = ODP_CRYPTO_BUFFER_PROCESSED_OFFSET; + pkt = _odp_buf_to_ti_pkt(buf); + desc = _odp_buf_to_cppi_desc(buf); + + odp_pr_dbg("buffPtr: 0x%08x, buffLen: 0x%x, offset: %x\n", + desc->buffPtr, desc->buffLen, offset); + desc->buffPtr += offset; + desc->buffLen -= offset; + packet_length = odp_packet_get_len(odp_packet_from_buffer(buf)); + odp_packet_set_len(odp_packet_from_buffer(buf), + packet_length - offset); + + result = nwal_mGetAppidFmPkt(pkt, (nwal_AppId *)&session); + ODP_ASSERT(result == nwal_TRUE, "Can't get crypto session context\n"); + odp_pr_dbg("Session addr: %p\n", session); + + nwal_mmGetDmAuthTag(pkt, &auth_tag, &auth_tag_len); + + ODP_ASSERT(session->auth.tag_len <= auth_tag_len, + "Auth tag length from SA is bigger than ICV length"); + ODP_ASSERT(!((uintptr_t)auth_tag & 0x3), + "Auth tag is not 4 bytes aligned"); + + if (session->op == ODP_CRYPTO_OP_ENCODE) { + /* Copy hash to packet */ + uint8_t *data = odp_buffer_addr(buf); + data += hdr->crypto.hash_offset; + hash_copy_be32(data, (uint32be_t *)(void *)auth_tag, + session->auth.tag_len); + } else if (hash_compare_be32(hdr->crypto.dec.hash_tag, + (uint32be_t *)(void *)auth_tag, + session->auth.tag_len)) { + odp_pr_dbg("ICV is wrong\n"); + odp_pr_dbg_mem(hdr->crypto.dec.hash_tag, session->auth.tag_len, + "Saved auth tag"); + odp_pr_dbg_mem(auth_tag, session->auth.tag_len, + "Decoded auth tag"); + auth_err = ODP_CRYPTO_ALG_ERR_ICV_CHECK; + } + + if (alg_err) + *alg_err = auth_err; + return; +} + +int odp_crypto_operation(odp_crypto_op_params_t *params, + bool *posted, + odp_buffer_t completion_event ODP_UNUSED) +{ + nwalTxDmPSCmdInfo_t *dm_cmd_info; + Cppi_HostDesc *desc; + struct odp_crypto_session_s *session; + odp_buffer_t buf = odp_buffer_from_packet(params->pkt); + struct odp_pkthdr *hdr = odp_packet_hdr(params->pkt); + uint32_t offset; + uint8_t *data; + + session = (struct odp_crypto_session_s *)(intptr_t)params->session; + + /* Out packet is allocated from out poll and can't be specified */ + if (params->out_pkt != ODP_PACKET_INVALID) + return -1; + + dm_cmd_info = &session->dm_ps_cmdinfo; + dm_cmd_info->rxSbSaQ = _odp_queue_to_qmss_queue(session->compl_queue); + dm_cmd_info->rxPktFlowId = session->out_flow_id; + + /* Save hash tag for decode operation and fill hash result with 0's*/ + data = odp_packet_buf_addr(params->pkt); + data += params->hash_result_offset; + hdr->crypto.hash_offset = params->hash_result_offset; + if (session->op == ODP_CRYPTO_OP_DECODE) + memcpy(hdr->crypto.dec.hash_tag, data, session->auth.tag_len); + memset(data, 0, session->auth.tag_len); + + offset = odp_crypto_buffer_preprocess(buf); + + nwal_mCmdDMUpdate(_odp_buf_to_ti_pkt(buf), + dm_cmd_info, + nwal_HANDLE_INVALID, + params->cipher_range.offset + offset, + params->cipher_range.length, + (params->override_iv_ptr) ? + params->override_iv_ptr : + session->cipher.iv.data, + params->auth_range.offset + offset, + params->auth_range.length, + NULL, + 0, /** @todo: Should be aadSize from session? */ + NULL); + + desc = _odp_buf_to_cppi_desc(buf); + desc = Osal_qmssConvertDescVirtToPhy(0, desc); + + Qmss_queuePushDescSizeRaw(dm_cmd_info->txQueue, + desc, + NWAL_DESC_SIZE); + + *posted = 1; + return 0; +} + + +int odp_crypto_init_global(void) +{ + size_t mem_size; + + /* Calculate the memory size we need */ + mem_size = sizeof(*global); + mem_size += (MAX_SESSIONS * sizeof(struct odp_crypto_session_s)); + + /* Allocate our globally shared memory */ + global = odp_shm_reserve("crypto_pool", mem_size, ODP_CACHE_LINE_SIZE); + + /* Clear it out */ + memset(global, 0, mem_size); + + /* Initialize it */ + global->max = MAX_SESSIONS; + + return 0; +} + +int odp_hw_random_get(uint8_t *buf, uint32_t *len, bool use_entropy ODP_UNUSED) +{ + Sa_RngData_t random; + uint8_t *random_buf; + uint32_t length = *len; + uint32_t i; + nwal_RetValue ret; + + ret = nwal_getSARandomNum(odp_global->nwal.handle, &random); + if (ret != nwal_OK) { + *len = 0; + return -1; + } + random_buf = (uint8_t *)&random; + if (length > sizeof(Sa_RngData_t)) + length = sizeof(Sa_RngData_t); + + for (i = 0; i < length; i++) + *buf++ = *random_buf++; + *len = length; + + return 0; +} +void +odp_crypto_get_operation_compl_status(odp_buffer_t completion_event, + struct odp_crypto_compl_status *auth, + struct odp_crypto_compl_status *cipher) +{ + auth->hw_err = ODP_CRYPTO_HW_ERR_NONE; + auth->alg_err = ODP_CRYPTO_ALG_ERR_NONE; + cipher->hw_err = ODP_CRYPTO_HW_ERR_NONE; + cipher->alg_err = ODP_CRYPTO_ALG_ERR_NONE; + + odp_crypto_buffer_postprocess(completion_event, &auth->alg_err); + + return; +} + +odp_packet_t +odp_crypto_get_operation_compl_packet(odp_buffer_t completion_event) +{ + odp_crypto_buffer_postprocess(completion_event, NULL); + return odp_packet_from_buffer(completion_event); +} + + +void *odp_crypto_get_operation_compl_ctx(odp_buffer_t completion ODP_UNUSED) +{ + /* Not supported */ + return NULL; +} + +void odp_crypto_get_ses_create_compl_status(odp_buffer_t completion_event, + enum odp_crypto_ses_create_err *status) +{ + struct odp_session_result_s *result; + + result = odp_buffer_addr(completion_event); + *status = result->rc; +} + +void odp_crypto_get_ses_create_compl_session(odp_buffer_t completion_event, + odp_crypto_session_t *session) +{ + struct odp_session_result_s *result; + + result = odp_buffer_addr(completion_event); + *session = result->session; +} diff --git a/platform/linux-keystone2/odp_init.c b/platform/linux-keystone2/odp_init.c index 3161f75..12c9ff2 100644 --- a/platform/linux-keystone2/odp_init.c +++ b/platform/linux-keystone2/odp_init.c @@ -66,6 +66,11 @@ int odp_init_global(void) return -1; } + if (odp_crypto_init_global()) { + odp_pr_err("ODP crypto init failed.\n"); + return -1; + } + if (odp_timer_init_global()) { odp_pr_err("ODP timer init failed.\n"); return -1;