drivers/char/hw_random/optee-rng.c

Source file repositories/reference/linux-study-clean/drivers/char/hw_random/optee-rng.c

File Facts

System
Linux kernel
Corpus path
drivers/char/hw_random/optee-rng.c
Extension
.c
Size
7210 bytes
Lines
289
Domain
Driver Families
Bucket
drivers/char
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct optee_rng_private {
	struct device *dev;
	struct tee_context *ctx;
	u32 session_id;
	u32 data_rate;
	struct tee_shm *entropy_shm_pool;
	struct hwrng optee_rng;
};

#define to_optee_rng_private(r) \
		container_of(r, struct optee_rng_private, optee_rng)

static size_t get_optee_rng_data(struct optee_rng_private *pvt_data,
				 void *buf, size_t req_size)
{
	int ret = 0;
	u8 *rng_data = NULL;
	size_t rng_size = 0;
	struct tee_ioctl_invoke_arg inv_arg;
	struct tee_param param[4];

	memset(&inv_arg, 0, sizeof(inv_arg));
	memset(&param, 0, sizeof(param));

	/* Invoke TA_CMD_GET_ENTROPY function of Trusted App */
	inv_arg.func = TA_CMD_GET_ENTROPY;
	inv_arg.session = pvt_data->session_id;
	inv_arg.num_params = 4;

	/* Fill invoke cmd params */
	param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
	param[0].u.memref.shm = pvt_data->entropy_shm_pool;
	param[0].u.memref.size = req_size;
	param[0].u.memref.shm_offs = 0;

	ret = tee_client_invoke_func(pvt_data->ctx, &inv_arg, param);
	if ((ret < 0) || (inv_arg.ret != 0)) {
		dev_err(pvt_data->dev, "TA_CMD_GET_ENTROPY invoke err: %x\n",
			inv_arg.ret);
		return 0;
	}

	rng_data = tee_shm_get_va(pvt_data->entropy_shm_pool, 0);
	if (IS_ERR(rng_data)) {
		dev_err(pvt_data->dev, "tee_shm_get_va failed\n");
		return 0;
	}

	rng_size = param[0].u.memref.size;
	memcpy(buf, rng_data, rng_size);

	return rng_size;
}

static int optee_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
{
	struct optee_rng_private *pvt_data = to_optee_rng_private(rng);
	size_t read = 0, rng_size;
	int timeout = 1;
	u8 *data = buf;

	if (max > MAX_ENTROPY_REQ_SZ)
		max = MAX_ENTROPY_REQ_SZ;

	while (read < max) {
		rng_size = get_optee_rng_data(pvt_data, data, (max - read));

		data += rng_size;
		read += rng_size;

		if (wait && pvt_data->data_rate) {
			if ((timeout-- == 0) || (read == max))
				return read;
			msleep((1000 * (max - read)) / pvt_data->data_rate);
		} else {
			return read;
		}
	}

	return read;
}

static int optee_rng_init(struct hwrng *rng)
{
	struct optee_rng_private *pvt_data = to_optee_rng_private(rng);
	struct tee_shm *entropy_shm_pool = NULL;

	entropy_shm_pool = tee_shm_alloc_kernel_buf(pvt_data->ctx,
						    MAX_ENTROPY_REQ_SZ);
	if (IS_ERR(entropy_shm_pool)) {

Annotation

Implementation Notes