Skip to content

Commit ae6247e

Browse files
author
Hernan Gatta
committed
ocall: add an example to show how to use OCALLs
The example first initializes a TEE context using the new settings API. It then opens a session against the example OCALL TA via the new API to configure sessions. The TA issues an OCALL during session open, which is handled by the host. Thereafter, it performs a function invocation into the OCALL TA to request that the latter call it back. The OCALLs include value and memref parameters that are passed in multiple directions. Via these parameters the TA and CA exchange information the same way they would during a normal CA-to-TA function invocation. Signed-off-by: Hernan Gatta <[email protected]> Acked-by: Jerome Forissier <[email protected]>
1 parent 9a7dc59 commit ae6247e

File tree

11 files changed

+621
-0
lines changed

11 files changed

+621
-0
lines changed

ocall/Android.mk

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
###################### optee-hello-world ######################
2+
LOCAL_PATH := $(call my-dir)
3+
4+
OPTEE_CLIENT_EXPORT = $(LOCAL_PATH)/../../optee_client/out/export
5+
6+
include $(CLEAR_VARS)
7+
LOCAL_CFLAGS += -DANDROID_BUILD
8+
LOCAL_CFLAGS += -Wall
9+
10+
LOCAL_SRC_FILES += host/main.c
11+
12+
LOCAL_C_INCLUDES := $(LOCAL_PATH)/ta/include \
13+
$(OPTEE_CLIENT_EXPORT)/include \
14+
15+
LOCAL_SHARED_LIBRARIES := libteec
16+
LOCAL_MODULE := optee_example_ocall
17+
LOCAL_VENDOR_MODULE := true
18+
LOCAL_MODULE_TAGS := optional
19+
include $(BUILD_EXECUTABLE)
20+
21+
include $(LOCAL_PATH)/ta/Android.mk

ocall/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
project (optee_example_ocall C)
2+
3+
set (SRC host/main.c)
4+
5+
add_executable (${PROJECT_NAME} ${SRC})
6+
7+
target_include_directories(${PROJECT_NAME}
8+
PRIVATE ta/include
9+
PRIVATE include)
10+
11+
target_link_libraries (${PROJECT_NAME} PRIVATE teec)
12+
13+
install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})

ocall/Makefile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export V?=0
2+
3+
# If _HOST or _TA specific compilers are not specified, then use CROSS_COMPILE
4+
HOST_CROSS_COMPILE ?= $(CROSS_COMPILE)
5+
TA_CROSS_COMPILE ?= $(CROSS_COMPILE)
6+
7+
.PHONY: all
8+
all:
9+
$(MAKE) -C host CROSS_COMPILE="$(HOST_CROSS_COMPILE)" --no-builtin-variables
10+
$(MAKE) -C ta CROSS_COMPILE="$(TA_CROSS_COMPILE)" LDFLAGS=""
11+
12+
.PHONY: clean
13+
clean:
14+
$(MAKE) -C host clean
15+
$(MAKE) -C ta clean

ocall/host/Makefile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
CC ?= $(CROSS_COMPILE)gcc
2+
LD ?= $(CROSS_COMPILE)ld
3+
AR ?= $(CROSS_COMPILE)ar
4+
NM ?= $(CROSS_COMPILE)nm
5+
OBJCOPY ?= $(CROSS_COMPILE)objcopy
6+
OBJDUMP ?= $(CROSS_COMPILE)objdump
7+
READELF ?= $(CROSS_COMPILE)readelf
8+
9+
OBJS = main.o
10+
11+
CFLAGS += -Wall -I../ta/include -I$(TEEC_EXPORT)/include -I./include
12+
#Add/link other required libraries here
13+
LDADD += -lteec -L$(TEEC_EXPORT)/lib
14+
15+
BINARY = optee_example_hello_world
16+
17+
.PHONY: all
18+
all: $(BINARY)
19+
20+
$(BINARY): $(OBJS)
21+
$(CC) -o $@ $< $(LDADD)
22+
23+
.PHONY: clean
24+
clean:
25+
rm -f $(OBJS) $(BINARY)
26+
27+
%.o: %.c
28+
$(CC) $(CFLAGS) -c $< -o $@

ocall/host/main.c

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
/*
2+
* Copyright (c) 2020, Microsoft Corporation
3+
* All rights reserved.
4+
*
5+
* SPDX-License-Identifier: BSD-2-Clause
6+
*/
7+
8+
#include <err.h>
9+
#include <stdio.h>
10+
#include <string.h>
11+
12+
#include <tee_client_api.h>
13+
#include <tee_client_api_extensions.h>
14+
15+
#include <ocall_ta.h>
16+
17+
static void print_uuid(TEEC_UUID *uuid)
18+
{
19+
printf("%x-%x-%x-%x%x-%x%x%x%x%x%x",
20+
uuid->timeLow,
21+
uuid->timeMid,
22+
uuid->timeHiAndVersion,
23+
uuid->clockSeqAndNode[0],
24+
uuid->clockSeqAndNode[1],
25+
uuid->clockSeqAndNode[2],
26+
uuid->clockSeqAndNode[3],
27+
uuid->clockSeqAndNode[4],
28+
uuid->clockSeqAndNode[5],
29+
uuid->clockSeqAndNode[6],
30+
uuid->clockSeqAndNode[7]);
31+
}
32+
33+
/*
34+
* This function is called by the TEE Client API whenever an OCALL arrives from
35+
* the TA.
36+
*
37+
* The 'taUUID' parameter carries the UUID of the TA that sent the OCALL. Since
38+
* a TA can open a session to another TA, it is possible to receive OCALLs from
39+
* other TAs that your TA calls into, if any.
40+
*
41+
* The 'commandId' indicates which function the TA wishes the CA to run.
42+
*
43+
* 'ctxData' is the arbitrary pointer that was set via the TEE context OCALL
44+
* setting, if any. Similarly, 'sessionData' is the arbitrary pointer set via
45+
* the session data setting, if it was supplied, or NULL.
46+
*/
47+
TEEC_Result ocall_handler(TEEC_UUID *taUUID, uint32_t commandId,
48+
uint32_t paramTypes,
49+
TEEC_Parameter params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
50+
void *ctxData, void *sessionData)
51+
{
52+
const char *msg = "This string was sent by the CA";
53+
uint32_t expected_pt;
54+
55+
printf("Received an OCALL for Command Id: %u\n", commandId);
56+
printf("The TA that sent it is: ");
57+
print_uuid(taUUID);
58+
printf("\n");
59+
60+
switch (commandId) {
61+
case CA_OCALL_CMD_REPLY_SESSION_OPEN:
62+
expected_pt = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT,
63+
TEEC_NONE,
64+
TEEC_NONE,
65+
TEEC_MEMREF_TEMP_INPUT);
66+
if (paramTypes != expected_pt) {
67+
fprintf(stderr, "Bad parameter types\n");
68+
return TEEC_ERROR_BAD_PARAMETERS;
69+
}
70+
if (!params[3].tmpref.buffer) {
71+
fprintf(stderr, "No buffer\n");
72+
return TEEC_ERROR_BAD_PARAMETERS;
73+
}
74+
75+
/* Print out the OCALL's INPUT/INOUT parameters */
76+
printf("Input values: 0x%x, 0x%x\n", params[0].value.a,
77+
params[0].value.b);
78+
printf("Input string: %s\n", (char *)params[3].tmpref.buffer);
79+
80+
/* Set the OCALL's INOUT parameters */
81+
params[0].value.a = 0xCDDC1001;
82+
params[0].value.b = 0xFFFFCAFE;
83+
break;
84+
case CA_OCALL_CMD_REPLY_TA:
85+
expected_pt = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
86+
TEEC_VALUE_INOUT,
87+
TEEC_MEMREF_TEMP_INPUT,
88+
TEEC_MEMREF_TEMP_INOUT);
89+
if (paramTypes != expected_pt) {
90+
fprintf(stderr, "Bad parameter types\n");
91+
return TEEC_ERROR_BAD_PARAMETERS;
92+
}
93+
if (!params[2].tmpref.buffer || !params[3].tmpref.buffer) {
94+
fprintf(stderr, "No buffer(s)\n");
95+
return TEEC_ERROR_BAD_PARAMETERS;
96+
}
97+
if (params[3].tmpref.size < strlen(msg) + 1) {
98+
fprintf(stderr, "Bad parameters\n");
99+
return TEEC_ERROR_BAD_PARAMETERS;
100+
}
101+
102+
/* Print out the OCALL's INPUT/INOUT parameters */
103+
printf("Input values: %u, %u\n", params[0].value.a,
104+
params[0].value.b);
105+
printf("Inout values: %u, %u\n", params[1].value.a,
106+
params[1].value.b);
107+
108+
printf("Input string: %s\n", (char *)params[2].tmpref.buffer);
109+
printf("Input size: %zu\n", params[2].tmpref.size);
110+
111+
printf("Inout string: %s\n", (char *)params[3].tmpref.buffer);
112+
printf("Inout size: %zu\n", params[3].tmpref.size);
113+
114+
/* Set the OCALL's INOUT parameters */
115+
params[1].value.a = 0x3;
116+
params[1].value.b = 0x4;
117+
118+
params[3].tmpref.size = strlen(msg) + 1;
119+
memcpy(params[3].tmpref.buffer, msg, params[3].tmpref.size);
120+
break;
121+
default:
122+
fprintf(stderr, "Bad function ID\n");
123+
return TEEC_ERROR_BAD_PARAMETERS;
124+
}
125+
126+
printf("OCALL handled\n");
127+
return TEEC_SUCCESS;
128+
}
129+
130+
int main(int argc, char* argv[])
131+
{
132+
TEEC_Context ctx;
133+
TEEC_Session sess;
134+
TEEC_UUID uuid = TA_OCALL_UUID;
135+
TEEC_Operation op;
136+
137+
TEEC_Result res;
138+
uint32_t err_origin;
139+
140+
char buf[128];
141+
char buf2[128];
142+
char *msg1 = "This string was sent by the CA";
143+
const char *msg2 = "The CA thinks this is a fun riddle";
144+
145+
/*
146+
* The TEE context OCALL setting allows specifying the callback handler
147+
* for when an OCALL arrives from the TA. This handler is effectively
148+
* the equivalent of TA_InvokeCommandEntryPoint, but on the CA side.
149+
* Additionally, one may set an arbitrary pointer that will be passed
150+
* to the OCALL handler when invoked.
151+
*
152+
* NOTE: You must pass this setting to the TEE context initialization
153+
* routine to receive OCALLs; otherwise, all OCALLs will return
154+
* a failure code.
155+
*/
156+
TEEC_ContextSettingOCall ocall_setting = {
157+
.handler = ocall_handler,
158+
.data = &ctx,
159+
};
160+
161+
/* Array of TEE context settings */
162+
TEEC_ContextSetting ctx_settings = {
163+
.type = TEEC_CONTEXT_SETTING_OCALL,
164+
.u.ocall = &ocall_setting,
165+
};
166+
167+
/* Initialize a TEE context with settings */
168+
res = TEEC_InitializeContext2(NULL, &ctx, &ctx_settings, 1);
169+
if (res != TEEC_SUCCESS)
170+
errx(1, "TEEC_InitializeContext failed with code 0x%x", res);
171+
172+
/*
173+
* The session data setting allows attaching an arbitrary pointer to the
174+
* session. This pointer will be passed to the OCALL handler when
175+
* invoked.
176+
*
177+
* NOTE: This is optional; you can use TEEC_OpenSession as well even if
178+
* you expect OCALLs.
179+
*/
180+
TEEC_SessionSettingData data_setting = {
181+
.data = &sess
182+
};
183+
184+
/* Array of session settings */
185+
TEEC_SessionSetting session_settings = {
186+
.type = TEEC_SESSION_SETTING_DATA,
187+
.u.data = &data_setting,
188+
};
189+
190+
/* Set up the parameters for the TA's session open handler */
191+
memset(&op, 0, sizeof(op));
192+
op.paramTypes = TEEC_PARAM_TYPES(
193+
TEEC_VALUE_INPUT,
194+
TEEC_MEMREF_TEMP_INPUT,
195+
TEEC_NONE,
196+
TEEC_NONE);
197+
198+
op.params[0].value.a = 0x0000CAFE;
199+
op.params[0].value.b = 0xCAFE0000;
200+
201+
op.params[1].tmpref.buffer = (void *)msg2;
202+
op.params[1].tmpref.size = strlen(msg2) + 1;
203+
204+
/* Open a session with settings; the sample TA will issue an OCALL */
205+
res = TEEC_OpenSession2(&ctx, &sess, &uuid, TEEC_LOGIN_PUBLIC, NULL,
206+
&op, &err_origin, &session_settings, 1);
207+
if (res != TEEC_SUCCESS)
208+
errx(1, "TEEC_OpenSessionEx failed with code 0x%x origin 0x%x",
209+
res, err_origin);
210+
211+
/*
212+
* The code below executes after the OCALL has been handled in the
213+
* callback at the top of this file.
214+
*/
215+
216+
/*
217+
* Set up the parameters for the function invocation. These are just to
218+
* show that the CA can pass parameters to the TA and that during the
219+
* function invocation that carries those parameters to the TA, the TA
220+
* can make an OCALL with parameters of its own choosing. That is, the
221+
* parameters passed from the CA to the TA do not interfere with those
222+
* passed from the TA to the CA, and vice-versa.
223+
*/
224+
memset(&op, 0, sizeof(op));
225+
op.paramTypes = TEEC_PARAM_TYPES(
226+
TEEC_VALUE_INPUT,
227+
TEEC_VALUE_INOUT,
228+
TEEC_MEMREF_TEMP_INPUT,
229+
TEEC_MEMREF_TEMP_INOUT);
230+
231+
op.params[0].value.a = 0x3;
232+
op.params[0].value.b = 0x4;
233+
234+
op.params[1].value.a = 0x5;
235+
op.params[1].value.b = 0x6;
236+
237+
op.params[2].tmpref.buffer = msg1;
238+
op.params[2].tmpref.size = strlen(msg1) + 1;
239+
240+
op.params[3].tmpref.buffer = buf;
241+
op.params[3].tmpref.size = sizeof(buf);
242+
memcpy(buf, msg2, strlen(msg2) + 1);
243+
244+
/* Ask the TA to call us back */
245+
res = TEEC_InvokeCommand(&sess, TA_OCALL_CMD_CALL_CA, &op, &err_origin);
246+
if (res != TEEC_SUCCESS)
247+
errx(1, "TEEC_InvokeCommand failed with code 0x%x origin 0x%x",
248+
res, err_origin);
249+
250+
/*
251+
* The code below once again executes after the OCALL has been handled
252+
* in the callback at the top of this file.
253+
*/
254+
255+
/*
256+
* Print out the values of the INOUT parameters of the original function
257+
* invocation that we got from the TA..
258+
*/
259+
printf("INOUT parameters from the original function invocation:\n");
260+
printf("Inout values: %u, %u\n", op.params[1].value.a,
261+
op.params[1].value.b);
262+
263+
printf("Inout string: %s\n", (char *)op.params[3].tmpref.buffer);
264+
printf("Inout size: %zu\n", op.params[3].tmpref.size);
265+
266+
/* All done */
267+
TEEC_CloseSession(&sess);
268+
269+
TEEC_FinalizeContext(&ctx);
270+
271+
return 0;
272+
}

ocall/ta/Android.mk

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
LOCAL_PATH := $(call my-dir)
2+
3+
local_module := 9b2c0652-3b9b-4d83-971e-e56c40512793.ta
4+
include $(BUILD_OPTEE_MK)

ocall/ta/Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CFG_TEE_TA_LOG_LEVEL ?= 4
2+
CPPFLAGS += -DCFG_TEE_TA_LOG_LEVEL=$(CFG_TEE_TA_LOG_LEVEL)
3+
4+
# The UUID for the Trusted Application
5+
BINARY=9b2c0652-3b9b-4d83-971e-e56c40512793
6+
7+
-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk
8+
9+
ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), )
10+
clean:
11+
@echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA'
12+
@echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)'
13+
endif

ocall/ta/include/ocall_ta.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (c) 2020, Microsoft Corporation
3+
* All rights reserved.
4+
*
5+
* SPDX-License-Identifier: BSD-2-Clause
6+
*/
7+
8+
#ifndef TA_OCALL_H
9+
#define TA_OCALL_H
10+
11+
/* 9b2c0652-3b9b-4d83-971e-e56c40512793 */
12+
#define TA_OCALL_UUID \
13+
{ 0x9b2c0652, 0x3b9b, 0x4d83, \
14+
{ 0x97, 0x1e, 0xe5, 0x6c, 0x40, 0x51, 0x27, 0x93 } }
15+
16+
#define TA_OCALL_CMD_CALL_CA 0
17+
18+
#define CA_OCALL_CMD_REPLY_SESSION_OPEN 99
19+
#define CA_OCALL_CMD_REPLY_TA 100
20+
21+
#endif /*TA_OCALL_H*/

0 commit comments

Comments
 (0)