1 /*
2 * Copyright (c) 2023, Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * A sample application using sip_svc subsystem to get query values from secure device.
7 * The access to the secure device is defined via EL3 exception level and uses
8 * the ARM Trusted Firmware to provide access.The application runs on Intel Agilex FPGA SoC,
9 * where the app queries voltage sampled from the SDM(Secure Device Manager).
10 */
11
12 #include <zephyr/sip_svc/sip_svc.h>
13 #include <zephyr/drivers/sip_svc/sip_svc_agilex_mailbox.h>
14 #include <zephyr/drivers/sip_svc/sip_svc_agilex_smc.h>
15 #include <zephyr/sys/__assert.h>
16
17 #define SVC_METHOD "smc"
18 #define GET_VOLTAGE_CMD (0x18U)
19 #define SET_VOLTAGE_CHANNEL(x) ((1 << (x)) & 0xffff)
20 #define TIME_DELAY (K_MSEC(1000U))
21
22 struct private_data {
23 struct k_sem semaphore;
24 uint32_t voltage_channel0;
25 };
26
get_voltage_callback(uint32_t c_token,struct sip_svc_response * response)27 void get_voltage_callback(uint32_t c_token, struct sip_svc_response *response)
28 {
29 if (response == NULL) {
30 return;
31 }
32
33 struct private_data *priv = (struct private_data *)response->priv_data;
34
35 uint32_t *resp_data = (uint32_t *)response->resp_data_addr;
36 uint32_t resp_len = response->resp_data_size / 4;
37
38 if (resp_data && resp_len) {
39 priv->voltage_channel0 = resp_data[1];
40 }
41
42 k_sem_give(&(priv->semaphore));
43 }
44
main(void)45 int main(void)
46 {
47 void *mb_smc_ctrl = NULL;
48 uint32_t mb_c_token = SIP_SVC_ID_INVALID;
49 struct sip_svc_request request = {0};
50 uint32_t *cmd_addr = NULL, *resp_addr = NULL;
51 uint32_t cmd_size = (2 * sizeof(uint32_t));
52 uint32_t resp_size = (2 * sizeof(uint32_t));
53 struct private_data priv;
54
55 float voltage;
56 int err, trans_id;
57
58 resp_addr = (uint32_t *)k_malloc(resp_size);
59 __ASSERT(resp_addr != NULL, "Failed to get memory");
60
61 mb_smc_ctrl = sip_svc_get_controller(SVC_METHOD);
62 __ASSERT(mb_smc_ctrl != NULL, "Failed to get the controller from sip_svc");
63
64 mb_c_token = sip_svc_register(mb_smc_ctrl, NULL);
65 __ASSERT(mb_c_token != SIP_SVC_ID_INVALID, "Failed to register with sip_svc");
66
67 k_sem_init(&(priv.semaphore), 0, 1);
68
69 request.header = SIP_SVC_PROTO_HEADER(SIP_SVC_PROTO_CMD_ASYNC, 0);
70 request.a0 = SMC_FUNC_ID_MAILBOX_SEND_COMMAND;
71 request.resp_data_addr = (uint64_t)resp_addr;
72 request.resp_data_size = (uint64_t)resp_size;
73 request.priv_data = (void *)&priv;
74
75 while (1) {
76 err = sip_svc_open(mb_smc_ctrl, mb_c_token, K_FOREVER);
77 __ASSERT(err != SIP_SVC_ID_INVALID, "Failed to open with sip_svc");
78
79 cmd_addr = (uint32_t *)k_malloc(cmd_size);
80 __ASSERT(cmd_addr != NULL, "Failed to get memory");
81
82 /**
83 * Populate the SDM mailbox command ,where first word will be the header,
84 * header will contain the mailbox command and the size of command data to be sent
85 * to SDM. The transaction id and client id will be filled by sip_svc subsystem.
86 */
87 cmd_addr[0] = ((cmd_size / 4 - 1) << 12) | GET_VOLTAGE_CMD;
88 cmd_addr[1] = SET_VOLTAGE_CHANNEL(2);
89
90 /**
91 * Set the pointer to mailbox command buffer to a2 parameter and
92 * mailbox command buffer size to a3 parameter ,which EL3 software will
93 * expect for a ASYNC transaction.
94 */
95 request.a2 = (uint64_t)cmd_addr;
96 request.a3 = (uint64_t)cmd_size;
97
98 trans_id = sip_svc_send(mb_smc_ctrl, mb_c_token, &request, get_voltage_callback);
99 __ASSERT(trans_id < 0, "Error in sending a request to SDM mailbox");
100
101 err = k_sem_take(&(priv.semaphore), K_FOREVER);
102 __ASSERT(err != 0, "Error in taking semaphore");
103
104 /* Voltage is retrieved as a fixed point number with 16 bits below binary point */
105 voltage = ((float)priv.voltage_channel0 / 65536);
106
107 printk("Got response of transaction id 0x%02x and voltage is %fv\n", trans_id,
108 voltage);
109
110 err = sip_svc_close(mb_smc_ctrl, mb_c_token, NULL);
111 __ASSERT(err != SIP_SVC_ID_INVALID, "Failed to close with sip_svc");
112
113 k_sleep(TIME_DELAY);
114 }
115 }
116