5.4.x内核模块密码算法调用逻辑分析

一、以下是请求过程:

static inline int crypto_wait_req(int err, struct crypto_wait *wait)
{
	switch (err) {
	case -EINPROGRESS:
	case -EBUSY:
		wait_for_completion(&wait->completion);
		reinit_completion(&wait->completion);
		err = wait->err;
		break;
	};

	return err;
}

static inline void crypto_init_wait(struct crypto_wait *wait)
{
	init_completion(&wait->completion);
}

二、 completion 用法

通常wait_for_completion需要completion唤醒配合,如下:

#include <linux/completion.h>

static struct completion my_completion;                                            // 1. 定义完成事件

static int my_thread_function(void *data) {
    pr_info("Thread started...\n");
    msleep(5000); // 模拟一个长时间的操作
    pr_info("Operation completed!\n");

    complete(&my_completion);                                                   // 3. 标记完成事件
    return 0;
}

static int __init my_init(void) {
    struct task_struct *thread;

    pr_info("Module init...\n");

    // 初始化完成事件
    init_completion(&my_completion);

    // 创建一个内核线程
    thread = kthread_run(my_thread_function, NULL, "my_thread");
    if (IS_ERR(thread)) {
        pr_err("Failed to create thread.\n");
        return PTR_ERR(thread);
    }

    // 等待完成事件
    wait_for_completion(&my_completion);                   //2. 阻塞当前线程,直到完成事件被标记为已完成。
    pr_info("Main thread: Operation completed!\n");

    return 0;
}

三、 set_callback

static inline void ahash_request_set_callback(struct ahash_request *req,
					      u32 flags,
					      crypto_completion_t compl,
					      void *data)
{
	req->base.complete = compl;
	req->base.data = data;
	req->base.flags = flags;
}

四、crypto_ahash_update

硬件加速请求。

+static int ccp_do_sm3_update(struct ahash_request *req, unsigned int nbytes,
+			     unsigned int final)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct ccp_ctx *ctx = crypto_ahash_ctx(tfm);
+	struct ccp_sm3_req_ctx *rctx = ahash_request_ctx(req);


+	ret = ccp_crypto_enqueue_request(&req->base, &rctx->cmd);
+
+	return ret;
+
+e_free:
+	sg_free_table(&rctx->data_sg);
+
+	return ret;
+}

int ccp_crypto_enqueue_request(struct crypto_async_request *req,
			       struct ccp_cmd *cmd)
{
	struct ccp_crypto_cmd *crypto_cmd;
	gfp_t gfp;

	gfp = req->flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC;

	crypto_cmd = kzalloc(sizeof(*crypto_cmd), gfp);
	if (!crypto_cmd)
		return -ENOMEM;

	/* The tfm pointer must be saved and not referenced from the
	 * crypto_async_request (req) pointer because it is used after
	 * completion callback for the request and the req pointer
	 * might not be valid anymore.
	 */
	crypto_cmd->cmd = cmd;
	crypto_cmd->req = req;
	crypto_cmd->tfm = req->tfm;

	cmd->callback = ccp_crypto_complete;
	cmd->data = crypto_cmd;

	if (req->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)
		cmd->flags |= CCP_CMD_MAY_BACKLOG;
	else
		cmd->flags &= ~CCP_CMD_MAY_BACKLOG;

	return ccp_crypto_enqueue_cmd(crypto_cmd);
}

ccp_crypto_enqueue_request使用例子

static struct completion my_completion;

// CCP 操作完成的回调函数
static void ccp_crypto_complete(struct crypto_async_request *req, int error) {
    printk(KERN_INFO "CCP operation completed.\n");

    if (error) {
        printk(KERN_ERR "CCP operation failed with error code %d\n", error);
    } else {
        printk(KERN_INFO "CCP operation succeeded.\n");
        // 在这里处理操作的结果
    }

    // 唤醒等待完成的线程
    complete(&my_completion);
}

static int __init my_init(void) {
    struct ccp_cmd cmd;
    struct crypto_async_request *req;
    int ret;

    printk(KERN_INFO "Module init...\n");

    // 初始化完成事件
    init_completion(&my_completion);

    // 分配 CCP 操作结构体
    req = crypto_req_alloc(ccp_queue, GFP_KERNEL);
    if (!req) {
        printk(KERN_ERR "Failed to allocate CCP request structure.\n");
        return -ENOMEM;
    }

    // 初始化 CCP 操作结构体
    memset(&cmd, 0, sizeof(cmd));
    cmd.req = req;
    cmd.req->complete = ccp_crypto_complete; // 操作完成的回调函数

    // 设置其他操作参数
    // ...

    // 提交请求给 CCP 硬件加速器
    ret = ccp_crypto_enqueue_request(cmd.req, &cmd);
    if (ret) {
        printk(KERN_ERR "Failed to enqueue request: %d\n", ret);
        crypto_req_put(req);
        return ret;
    }

    // 等待完成事件
    wait_for_completion(&my_completion);

    // 释放 CCP 操作结构体
    crypto_req_put(req);

    return 0;
}
struct ccp_cmd {
	/* The list_head, work_struct, ccp and ret variables are for use
	 * by the CCP driver only.
	 */
	struct list_head entry;
	struct work_struct work;
	struct ccp_device *ccp;
	int ret;

	u32 flags;

	enum ccp_engine engine;
	u32 engine_error;

	union {
		struct ccp_aes_engine aes;
		struct ccp_xts_aes_engine xts;
		struct ccp_des3_engine des3;
		struct ccp_sha_engine sha;
		struct ccp_rsa_engine rsa;
		struct ccp_passthru_engine passthru;
		struct ccp_passthru_nomap_engine passthru_nomap;
		struct ccp_ecc_engine ecc;
	} u;

	/* Completion callback support */
	void (*callback)(void *data, int err);
	void *data;
};
struct crypto_async_request {
	struct list_head list;
	crypto_completion_t complete;
	void *data;
	struct crypto_tfm *tfm;

	u32 flags;
};

大致的逻辑应该是通过update 把硬件加速命令通过ccp_crypto_enqueue_request传递到硬件加速其中。如果处理完成直接返回正确,处理异常如果是设备忙碌,外部会通过crypto_wait_req等待,直到硬件加速器执行完毕唤醒wait。

crypto引擎的使用流程

	crypto_init_wait(&wait);
	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
				   crypto_req_done, &wait);
	crypto_ahash_clear_flags(ahash_tfm, ~0);

	buf = kzalloc(keylen + QCE_MAX_ALIGN_SIZE, GFP_KERNEL);
	if (!buf) {
		ret = -ENOMEM;
		goto err_free_req;
	}

	memcpy(buf, key, keylen);
	sg_init_one(&sg, buf, keylen);
	ahash_request_set_crypt(req, &sg, ctx->authkey, keylen);

	ret = crypto_wait_req(crypto_ahash_digest(req), &wait);

如上,crypto_init_wait 初始化complete, set_callback设置回调任务。crypto_wait_req(crypto_ahash_digest(req), &wait);等待任务完成,
回调crypto_req_done唤醒任务。

ccp 队列任务处理逻辑

drivers\crypto\ccp\ccp-dev.c

static void ccp_do_cmd_complete(unsigned long data)
{
	struct ccp_tasklet_data *tdata = (struct ccp_tasklet_data *)data;
	struct ccp_cmd *cmd = tdata->cmd;

	cmd->callback(cmd->data, cmd->ret);

	complete(&tdata->completion);
}
/**
 * ccp_cmd_queue_thread - create a kernel thread to manage a CCP queue
 *
 * @data: thread-specific data
 */
int ccp_cmd_queue_thread(void *data)
{
	struct ccp_cmd_queue *cmd_q = (struct ccp_cmd_queue *)data;
	struct ccp_cmd *cmd;
	struct ccp_tasklet_data tdata;
	struct tasklet_struct tasklet;

	tasklet_init(&tasklet, ccp_do_cmd_complete, (unsigned long)&tdata);

	set_current_state(TASK_INTERRUPTIBLE);
	while (!kthread_should_stop()) {
		schedule();

		set_current_state(TASK_INTERRUPTIBLE);

		cmd = ccp_dequeue_cmd(cmd_q);
		if (!cmd)
			continue;

		__set_current_state(TASK_RUNNING);

		/* Execute the command */
		cmd->ret = ccp_run_cmd(cmd_q, cmd);

		/* Schedule the completion callback */
		tdata.cmd = cmd;
		init_completion(&tdata.completion);
		tasklet_schedule(&tasklet);
		wait_for_completion(&tdata.completion);
	}

	__set_current_state(TASK_RUNNING);

	return 0;
}

tasklet_init 是一个 Linux 内核中用于初始化 Tasklet 的函数。Tasklet 是 Linux 内核中一种轻量级的软中断机制,用于在中断上下文之外执行延迟的、短暂的任务。

#include <linux/interrupt.h>

// 定义 Tasklet 执行的函数
void tasklet_function(unsigned long data) {
    printk(KERN_INFO "Tasklet executed with data: %lu\n", data);
}

// 中断处理程序
irqreturn_t my_interrupt_handler(int irq, void *dev_id) {
    // 触发 Tasklet 执行
    tasklet_schedule((struct tasklet_struct *)dev_id);
    return IRQ_HANDLED;
}

int init_module(void) {
    // 分配 Tasklet
    struct tasklet_struct *my_tasklet;
    my_tasklet = kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
    if (!my_tasklet) {
        return -ENOMEM;
    }

    // 初始化 Tasklet
    tasklet_init(my_tasklet, tasklet_function, 42);

    // 注册中断处理程序并将 Tasklet 作为参数传递给它
    // 这只是一个示例,实际中断处理程序的注册方式取决于硬件和具体情况
    request_irq(IRQ_NUMBER, my_interrupt_handler, IRQF_SHARED, "my_interrupt", (void *)my_tasklet);

    return 0;
}

void cleanup_module(void) {
    // 删除中断处理程序
    free_irq(IRQ_NUMBER, (void *)my_tasklet);

    // 删除 Tasklet
    tasklet_kill(my_tasklet);
    kfree(my_tasklet);
}

如上tasklet_init注册的任务会在中断中利用tasklet_shedule触发从而执行任务。
也就是说ccp_cmd_queue_thread类似一个监听服务,在不断地处理任务。

static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
{
	struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
	struct ahash_alg *alg = crypto_ahash_alg(hash);

	hash->setkey = ahash_nosetkey;

	if (tfm->__crt_alg->cra_type != &crypto_ahash_type)
		return crypto_init_shash_ops_async(tfm);

	hash->init = alg->init;
	hash->update = alg->update;
	hash->final = alg->final;
	hash->finup = alg->finup ?: ahash_def_finup;
	hash->digest = alg->digest;
	hash->export = alg->export;
	hash->import = alg->import;

	if (alg->setkey) {
		hash->setkey = alg->setkey;
		ahash_set_needkey(hash);
	}

	return 0;
}

ccp 引擎触发流程:
在这里插入图片描述

算法调用流程:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值