@@ -26,8 +26,180 @@ static void virtio_crypto_process(VirtIOCrypto *vcrypto)
{
}
+static inline int virtio_crypto_vq2q(int queue_index)
+{
+ return queue_index;
+}
+
+static void
+virtio_crypto_cipher_session_helper(VirtIODevice *vdev,
+ CryptoSymSessionInfo *info,
+ struct virtio_crypto_cipher_session_para *cipher_para,
+ struct virtio_crypto_cipher_session_output *cipher_out)
+{
+ hwaddr key_gpa;
+ void *key_hva;
+ hwaddr len;
+
+ info->cipher_alg = virtio_ldl_p(vdev, &cipher_para->algo);
+ info->key_len = virtio_ldl_p(vdev, &cipher_para->keylen);
+ info->direction = virtio_ldl_p(vdev, &cipher_para->op);
+ len = info->key_len;
+ /* get cipher key */
+ if (len > 0) {
+ DPRINTF("keylen=%" PRIu32 "\n", info->key_len);
+ key_gpa = virtio_ldq_p(vdev, &cipher_out->key_addr);
+
+ key_hva = cpu_physical_memory_map(key_gpa, &len, 0);
+
+ info->cipher_key = g_malloc(info->key_len);
+ memcpy(info->cipher_key, key_hva, info->key_len);
+ cpu_physical_memory_unmap(key_hva, len, 0, len);
+ }
+}
+
+static int64_t
+virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
+ struct virtio_crypto_sym_create_session_req *sess_req,
+ uint32_t queue_id,
+ uint64_t *session_id)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+ CryptoSymSessionInfo info;
+ int ret;
+ CryptoClientState *cc;
+ int queue_index;;
+ uint32_t op_type;
+ hwaddr auth_key_gpa;
+ void *auth_key_hva;
+ struct virtio_crypto_session_input *input;
+ hwaddr len;
+
+ op_type = virtio_ldl_p(vdev, &sess_req->op_type);
+ info.op_type = op_type;
+
+ if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) {
+ virtio_crypto_cipher_session_helper(vdev, &info,
+ &sess_req->u.cipher.para,
+ &sess_req->u.cipher.out);
+ input = &sess_req->u.cipher.input;
+ } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
+ /* cipher part */
+ virtio_crypto_cipher_session_helper(vdev, &info,
+ &sess_req->u.chain.para.cipher_param,
+ &sess_req->u.chain.out.cipher);
+ input = &sess_req->u.chain.input;
+ /* hash part */
+ info.alg_chain_order = virtio_ldl_p(vdev,
+ &sess_req->u.chain.para.alg_chain_order);
+ info.add_len = virtio_ldl_p(vdev,
+ &sess_req->u.chain.para.aad_len);
+ info.hash_mode = virtio_ldl_p(vdev, &sess_req->u.chain.para.hash_mode);
+ if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) {
+ info.hash_alg = virtio_ldl_p(vdev,
+ &sess_req->u.chain.para.u.mac_param.algo);
+ len = info.auth_key_len = virtio_ldl_p(vdev,
+ &sess_req->u.chain.para.u.mac_param.auth_key_len);
+ info.hash_result_len = virtio_ldl_p(vdev,
+ &sess_req->u.chain.para.u.mac_param.hash_result_len);
+ /* get auth key */
+ if (len > 0) {
+ DPRINTF("keylen=%" PRIu32 "\n", info.auth_key_len);
+ auth_key_gpa = virtio_ldq_p(vdev,
+ &sess_req->u.chain.out.mac.auth_key_addr);
+ auth_key_hva = cpu_physical_memory_map(auth_key_gpa,
+ &len, false);
+ info.auth_key = g_malloc(len);
+ memcpy(info.auth_key, auth_key_hva, len);
+ cpu_physical_memory_unmap(auth_key_hva, len, false, len);
+ }
+ } else if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) {
+ info.hash_alg = virtio_ldl_p(vdev,
+ &sess_req->u.chain.para.u.hash_param.algo);
+ info.hash_result_len = virtio_ldl_p(vdev,
+ &sess_req->u.chain.para.u.hash_param.hash_result_len);
+ } else {
+ /* VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED */
+ error_report("unsupported hash mode");
+ goto err;
+ }
+ } else {
+ /* VIRTIO_CRYPTO_SYM_OP_NONE */
+ error_report("unsupported cipher type");
+ goto err;
+ }
+
+ queue_index = virtio_crypto_vq2q(queue_id);
+ cc = qemu_get_crypto_subqueue(vcrypto->crypto, queue_index);
+ ret = qemu_crypto_create_session(cc, &info, session_id);
+ if (ret == 0) {
+ DPRINTF("create session_id=%" PRIu64 "\n", *session_id);
+ /* Set the result, notify the frontend driver soon */
+ virtio_stl_p(vdev, &input->status, VIRTIO_CRYPTO_OP_OK);
+ virtio_stq_p(vdev, &input->session_id, *session_id);
+ return 0;
+ }
+
+err:
+ virtio_stl_p(vdev, &input->status, VIRTIO_CRYPTO_OP_ERR);
+ return -1;
+}
+
static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
{
+ VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
+ struct virtio_crypto_op_ctrl_req ctrl;
+ VirtQueueElement *elem;
+ size_t s;
+ struct iovec *iov;
+ unsigned int iov_cnt;
+ uint32_t queue_id;
+ uint32_t opcode;
+ uint64_t session_id = 0;
+
+ for (;;) {
+ elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!elem) {
+ break;
+ }
+ if (elem->in_num < 1 ||
+ iov_size(elem->in_sg, elem->in_num) < sizeof(ctrl)) {
+ error_report("virtio-crypto ctrl missing headers");
+ exit(1);
+ }
+
+ iov_cnt = elem->in_num;
+ iov = elem->in_sg;
+ s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl));
+ assert(s == sizeof(ctrl));
+ opcode = virtio_ldl_p(vdev, &ctrl.header.opcode);
+ queue_id = virtio_ldl_p(vdev, &ctrl.header.queue_id);
+
+ switch (opcode) {
+ case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
+ virtio_crypto_create_sym_session(vcrypto,
+ &ctrl.u.sym_create_session,
+ queue_id,
+ &session_id);
+
+ break;
+ case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION:
+ case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
+ case VIRTIO_CRYPTO_HASH_DESTROY_SESSION:
+ case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
+ case VIRTIO_CRYPTO_MAC_DESTROY_SESSION:
+ case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
+ case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION:
+ default:
+ error_report("virtio-crypto unsupported ctrl opcode: %u",
+ opcode);
+ exit(1);
+ }
+
+ virtqueue_push(vq, elem, sizeof(ctrl));
+ virtio_notify(vdev, vq);
+ g_free(elem);
+ }
}
static void virtio_crypto_handle_dataq_bh(VirtIODevice *vdev, VirtQueue *vq)
Realize the Symmetric algos session creation handler, including plain cipher and chainning algorithms. Signed-off-by: Gonglei <arei.gonglei@huawei.com> --- hw/virtio/virtio-crypto.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+)