summaryrefslogtreecommitdiff
path: root/test/dm/tee.c
blob: 7a11bf89138993172e9293c2c1723bce631b5937 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2018 Linaro Limited
 */

#include <common.h>
#include <dm.h>
#include <log.h>
#include <malloc.h>
#include <dm/test.h>
#include <sandboxtee.h>
#include <tee.h>
#include <test/test.h>
#include <test/ut.h>
#include <tee/optee_ta_avb.h>
#include <tee/optee_ta_rpc_test.h>

static int open_session(struct udevice *dev, u32 *session,
			struct tee_optee_ta_uuid *uuid)
{
	struct tee_open_session_arg arg;
	int rc;

	memset(&arg, 0, sizeof(arg));
	tee_optee_ta_uuid_to_octets(arg.uuid, uuid);
	rc = tee_open_session(dev, &arg, 0, NULL);
	if (rc)
		return rc;
	if (arg.ret)
		return -EIO;
	*session = arg.session;

	return 0;
}

static int invoke_func_avb(struct udevice *dev, u32 session)
{
	struct tee_param param = { .attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT };
	struct tee_invoke_arg arg;

	memset(&arg, 0, sizeof(arg));
	arg.session = session;
	arg.func = TA_AVB_CMD_READ_LOCK_STATE;

	if (tee_invoke_func(dev, &arg, 1, &param) || arg.ret)
		return -1;

	return 0;
}

static int invoke_func_rpc_test(struct udevice *dev, u32 session,
				u64 op, u64 busnum, u64 chip_addr,
				u64 xfer_flags, u8 *buf, size_t buf_size)
{
	struct tee_param param[2];
	struct tee_invoke_arg arg;
	struct tee_shm *shm_buf;
	int rc;

	memset(&arg, 0, sizeof(arg));
	arg.session = session;
	arg.func = op;

	rc = tee_shm_alloc(dev, buf_size,
			   TEE_SHM_ALLOC, &shm_buf);
	if (rc)
		return rc;

	if (op == TA_RPC_TEST_CMD_I2C_WRITE)
		memcpy(shm_buf->addr, buf, buf_size);

	memset(param, 0, sizeof(param));
	param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
	param[0].u.value.a = busnum;
	param[0].u.value.b = chip_addr;
	param[0].u.value.c = xfer_flags;
	param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
	param[1].u.memref.shm = shm_buf;
	param[1].u.memref.size = buf_size;

	if (tee_invoke_func(dev, &arg, 2, param) || arg.ret) {
		rc = -1;
		goto out;
	}

	if (op == TA_RPC_TEST_CMD_I2C_READ)
		memcpy(buf, shm_buf->addr, buf_size);
out:
	tee_shm_free(shm_buf);
	return rc;
}

static int match(struct tee_version_data *vers, const void *data)
{
	return vers->gen_caps & TEE_GEN_CAP_GP;
}

struct test_tee_vars {
	struct tee_shm *reg_shm;
	struct tee_shm *alloc_shm;
};

static int test_tee(struct unit_test_state *uts, struct test_tee_vars *vars)
{
	struct tee_version_data vers;
	struct udevice *dev;
	struct sandbox_tee_state *state;
	struct tee_optee_ta_uuid avb_uuid = TA_AVB_UUID;
	u32 session = 0;
	int rc;
	u8 data[128];

	dev = tee_find_device(NULL, match, NULL, &vers);
	ut_assert(dev);
	state = dev_get_priv(dev);
	ut_assert(!state->session);

	rc = open_session(dev, &session, &avb_uuid);
	ut_assert(!rc);
	ut_assert(session == state->session);

	rc = invoke_func_avb(dev, session);
	ut_assert(!rc);

	rc = tee_close_session(dev, session);
	ut_assert(!rc);
	ut_assert(!state->session);

	ut_assert(!state->num_shms);
	rc = tee_shm_register(dev, data, sizeof(data), 0, &vars->reg_shm);
	ut_assert(!rc);
	ut_assert(state->num_shms == 1);

	rc = tee_shm_alloc(dev, 256, 0, &vars->alloc_shm);
	ut_assert(!rc);
	ut_assert(state->num_shms == 2);

	ut_assert(tee_shm_is_registered(vars->reg_shm, dev));
	ut_assert(tee_shm_is_registered(vars->alloc_shm, dev));

	tee_shm_free(vars->reg_shm);
	vars->reg_shm = NULL;
	tee_shm_free(vars->alloc_shm);
	vars->alloc_shm = NULL;
	ut_assert(!state->num_shms);

	return rc;
}

#define I2C_BUF_SIZE 64

static int test_tee_rpc(struct unit_test_state *uts)
{
	struct tee_version_data vers;
	struct udevice *dev;
	struct sandbox_tee_state *state;
	struct tee_optee_ta_uuid rpc_test_uuid = TA_RPC_TEST_UUID;
	u32 session = 0;
	int rc;

	char *test_str = "Test string";
	u8 data[I2C_BUF_SIZE] = {0};
	u8 data_from_eeprom[I2C_BUF_SIZE] = {0};

	/* Use sandbox I2C EEPROM emulation; bus: 0, chip: 0x2c */
	u64 bus = 0;
	u64 chip = 0x2c;
	u64 xfer_flags = 0;

	dev = tee_find_device(NULL, match, NULL, &vers);
	ut_assert(dev);
	state = dev_get_priv(dev);
	ut_assert(!state->session);

	/* Test RPC call asking for I2C service */
	rc = open_session(dev, &session, &rpc_test_uuid);
	ut_assert(!rc);
	ut_assert(session == state->session);

	/* Write buffer */
	strncpy((char *)data, test_str, strlen(test_str));
	rc = invoke_func_rpc_test(dev, session, TA_RPC_TEST_CMD_I2C_WRITE,
				  bus, chip, xfer_flags, data, sizeof(data));
	ut_assert(!rc);

	/* Read buffer */
	rc = invoke_func_rpc_test(dev, session, TA_RPC_TEST_CMD_I2C_READ,
				  bus, chip, xfer_flags, data_from_eeprom,
				  sizeof(data_from_eeprom));
	ut_assert(!rc);

	/* Compare */
	ut_assert(!memcmp(data, data_from_eeprom, sizeof(data)));

	rc = tee_close_session(dev, session);
	ut_assert(!rc);
	ut_assert(!state->session);

	return rc;
}

static int dm_test_tee(struct unit_test_state *uts)
{
	struct test_tee_vars vars = { NULL, NULL };
	int rc = test_tee(uts, &vars);

	if (rc)
		goto out;

	if (IS_ENABLED(CONFIG_OPTEE_TA_RPC_TEST))
		rc = test_tee_rpc(uts);
out:
	/* In case test_tee() asserts these may still remain allocated */
	tee_shm_free(vars.reg_shm);
	tee_shm_free(vars.alloc_shm);

	return rc;
}

DM_TEST(dm_test_tee, UT_TESTF_SCAN_FDT);