blob: 0f3f2c64d2fed25d7d5701056ed7099da2872f23 [file] [log] [blame]
Brad Bishopbec4ebc2022-08-03 09:55:16 -04001From a6721cc391397f5f999db84e4ebec4c20985996a Mon Sep 17 00:00:00 2001
2From: Vishnu Banavath <vishnu.banavath@arm.com>
3Date: Fri, 3 Dec 2021 19:00:54 +0000
4Subject: [PATCH] Add openamp rpc caller
5
6Signed-off-by: Rui Miguel Silva <rui.silva@arm.com>
7Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
8
9Upstream-Status: Pending [Not submitted to upstream yet]
10Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
11
12
13---
14 components/rpc/common/caller/rpc_caller.c | 10 +
15 components/rpc/common/interface/rpc_caller.h | 8 +
16 .../rpc/openamp/caller/sp/component.cmake | 15 +
17 .../rpc/openamp/caller/sp/openamp_caller.c | 203 +++++++
18 .../rpc/openamp/caller/sp/openamp_caller.h | 43 ++
19 .../rpc/openamp/caller/sp/openamp_mhu.c | 191 ++++++
20 .../rpc/openamp/caller/sp/openamp_mhu.h | 19 +
21 .../rpc/openamp/caller/sp/openamp_virtio.c | 554 ++++++++++++++++++
22 .../rpc/openamp/caller/sp/openamp_virtio.h | 24 +
23 deployments/se-proxy/opteesp/CMakeLists.txt | 1 +
24 .../se-proxy/opteesp/default_se-proxy.dts.in | 6 +
25 11 files changed, 1074 insertions(+)
26 create mode 100644 components/rpc/openamp/caller/sp/component.cmake
27 create mode 100644 components/rpc/openamp/caller/sp/openamp_caller.c
28 create mode 100644 components/rpc/openamp/caller/sp/openamp_caller.h
29 create mode 100644 components/rpc/openamp/caller/sp/openamp_mhu.c
30 create mode 100644 components/rpc/openamp/caller/sp/openamp_mhu.h
31 create mode 100644 components/rpc/openamp/caller/sp/openamp_virtio.c
32 create mode 100644 components/rpc/openamp/caller/sp/openamp_virtio.h
33
34diff --git a/components/rpc/common/caller/rpc_caller.c b/components/rpc/common/caller/rpc_caller.c
35index 2dceabeb..20d889c1 100644
36--- a/components/rpc/common/caller/rpc_caller.c
37+++ b/components/rpc/common/caller/rpc_caller.c
38@@ -37,3 +37,13 @@ void rpc_caller_end(struct rpc_caller *s, rpc_call_handle handle)
39 {
40 s->call_end(s->context, handle);
41 }
42+
43+void *rpc_caller_virt_to_phys(struct rpc_caller *s, void *va)
44+{
45+ return s->virt_to_phys(s->context, va);
46+}
47+
48+void *rpc_caller_phys_to_virt(struct rpc_caller *s, void *pa)
49+{
50+ return s->phys_to_virt(s->context, pa);
51+}
52diff --git a/components/rpc/common/interface/rpc_caller.h b/components/rpc/common/interface/rpc_caller.h
53index 387489cd..ef9bb649 100644
54--- a/components/rpc/common/interface/rpc_caller.h
55+++ b/components/rpc/common/interface/rpc_caller.h
56@@ -45,6 +45,10 @@ struct rpc_caller
57 rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len);
58
59 void (*call_end)(void *context, rpc_call_handle handle);
60+
61+ void *(*virt_to_phys)(void *context, void *va);
62+
63+ void *(*phys_to_virt)(void *context, void *pa);
64 };
65
66 /*
67@@ -87,6 +91,10 @@ RPC_CALLER_EXPORTED rpc_status_t rpc_caller_invoke(struct rpc_caller *s, rpc_cal
68 */
69 RPC_CALLER_EXPORTED void rpc_caller_end(struct rpc_caller *s, rpc_call_handle handle);
70
71+RPC_CALLER_EXPORTED void *rpc_caller_virt_to_phys(struct rpc_caller *s, void *va);
72+
73+RPC_CALLER_EXPORTED void *rpc_caller_phys_to_virt(struct rpc_caller *s, void *pa);
74+
75 #ifdef __cplusplus
76 }
77 #endif
78diff --git a/components/rpc/openamp/caller/sp/component.cmake b/components/rpc/openamp/caller/sp/component.cmake
79new file mode 100644
80index 00000000..fc919529
81--- /dev/null
82+++ b/components/rpc/openamp/caller/sp/component.cmake
83@@ -0,0 +1,15 @@
84+#-------------------------------------------------------------------------------
85+# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
86+#
87+# SPDX-License-Identifier: BSD-3-Clause
88+#
89+#-------------------------------------------------------------------------------
90+if (NOT DEFINED TGT)
91+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
92+endif()
93+
94+target_sources(${TGT} PRIVATE
95+ "${CMAKE_CURRENT_LIST_DIR}/openamp_caller.c"
96+ "${CMAKE_CURRENT_LIST_DIR}/openamp_virtio.c"
97+ "${CMAKE_CURRENT_LIST_DIR}/openamp_mhu.c"
98+ )
99diff --git a/components/rpc/openamp/caller/sp/openamp_caller.c b/components/rpc/openamp/caller/sp/openamp_caller.c
100new file mode 100644
101index 00000000..6cdfb756
102--- /dev/null
103+++ b/components/rpc/openamp/caller/sp/openamp_caller.c
104@@ -0,0 +1,203 @@
105+/*
106+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
107+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
108+ *
109+ * SPDX-License-Identifier: BSD-3-Clause
110+ */
111+
112+#include <stddef.h>
113+#include <trace.h>
114+#include "openamp_caller.h"
115+#include "openamp_mhu.h"
116+#include "openamp_virtio.h"
117+#include <protocols/rpc/common/packed-c/status.h>
118+
119+#define OPENAMP_TRANSACTION_IDLE 0x0
120+#define OPENAMP_TRANSACTION_INPROGRESS 0x1
121+#define OPENAMP_TRANSACTION_INVOKED 0x2
122+
123+static rpc_call_handle openamp_call_begin(void *context, uint8_t **req_buf,
124+ size_t req_len)
125+{
126+ struct openamp_caller *openamp = context;
127+ const struct openamp_platform_ops *ops = openamp->platform_ops;
128+ rpc_call_handle handle;
129+ int ret;
130+
131+ if (!req_buf) {
132+ EMSG("openamp: call_begin: not req_buf");
133+ return NULL;
134+ }
135+
136+ if (req_len > UINT32_MAX || req_len == 0) {
137+ EMSG("openamp: call_begin: resp_len invalid: %lu", req_len);
138+ return NULL;
139+ }
140+
141+ if (openamp->status != OPENAMP_TRANSACTION_IDLE) {
142+ EMSG("openamp: call_begin: transaction not idle");
143+ return NULL;
144+ }
145+
146+ ret = ops->platform_call_begin(openamp, req_buf, req_len);
147+ if (ret < 0) {
148+ EMSG("openamp: call_begin: platform begin failed: %d", ret);
149+ return NULL;
150+ }
151+
152+ openamp->status = OPENAMP_TRANSACTION_INPROGRESS;
153+ handle = openamp;
154+
155+ return handle;
156+}
157+
158+static rpc_status_t openamp_call_invoke(void *context, rpc_call_handle handle,
159+ uint32_t opcode, int *opstatus,
160+ uint8_t **resp_buf, size_t *resp_len)
161+{
162+ struct openamp_caller *openamp = context;
163+ const struct openamp_platform_ops *ops = openamp->platform_ops;
164+ rpc_status_t status;
165+ int ret;
166+
167+ (void)opcode;
168+
169+ if ((handle != openamp) || !opstatus || !resp_buf || !resp_len) {
170+ EMSG("openamp: call_invoke: invalid arguments");
171+ return TS_RPC_ERROR_INVALID_PARAMETER;
172+ }
173+
174+ if (openamp->status != OPENAMP_TRANSACTION_INPROGRESS) {
175+ EMSG("openamp: call_invoke: transaction needed to be started");
176+ return TS_RPC_ERROR_NOT_READY;
177+ }
178+
179+ ret = ops->platform_call_invoke(openamp, opstatus, resp_buf, resp_len);
180+ if (ret < 0)
181+ return TS_RPC_ERROR_INTERNAL;
182+
183+ openamp->status = OPENAMP_TRANSACTION_INVOKED;
184+ *opstatus = 0;
185+
186+ return TS_RPC_CALL_ACCEPTED;
187+}
188+
189+static void openamp_call_end(void *context, rpc_call_handle handle)
190+{
191+ struct openamp_caller *openamp = context;
192+ const struct openamp_platform_ops *ops = openamp->platform_ops;
193+
194+ if (handle != openamp) {
195+ EMSG("openamp: call_end: invalid arguments");
196+ return;
197+ }
198+
199+ if (openamp->status == OPENAMP_TRANSACTION_IDLE) {
200+ EMSG("openamp: call_end: transaction idle");
201+ return;
202+ }
203+
204+ ops->platform_call_end(openamp);
205+
206+ openamp->status = OPENAMP_TRANSACTION_IDLE;
207+}
208+
209+static void *openamp_virt_to_phys(void *context, void *va)
210+{
211+ struct openamp_caller *openamp = context;
212+ const struct openamp_platform_ops *ops = openamp->platform_ops;
213+
214+ return ops->platform_virt_to_phys(openamp, va);
215+}
216+
217+static void *openamp_phys_to_virt(void *context, void *pa)
218+{
219+ struct openamp_caller *openamp = context;
220+ const struct openamp_platform_ops *ops = openamp->platform_ops;
221+
222+ return ops->platform_phys_to_virt(openamp, pa);
223+}
224+
225+static int openamp_init(struct openamp_caller *openamp)
226+{
227+ const struct openamp_platform_ops *ops = openamp->platform_ops;
228+ int ret;
229+
230+ ret = ops->transport_init(openamp);
231+ if (ret < 0)
232+ return ret;
233+
234+ ret = ops->platform_init(openamp);
235+ if (ret < 0)
236+ goto denit_transport;
237+
238+ return 0;
239+
240+denit_transport:
241+ ops->transport_deinit(openamp);
242+
243+ return ret;
244+}
245+
246+static const struct openamp_platform_ops openamp_virtio_ops = {
247+ .transport_init = openamp_mhu_init,
248+ .transport_deinit = openamp_mhu_deinit,
249+ .transport_notify = openamp_mhu_notify_peer,
250+ .transport_receive = openamp_mhu_receive,
251+ .platform_init = openamp_virtio_init,
252+ .platform_call_begin = openamp_virtio_call_begin,
253+ .platform_call_invoke = openamp_virtio_call_invoke,
254+ .platform_call_end = openamp_virtio_call_end,
255+ .platform_virt_to_phys = openamp_virtio_virt_to_phys,
256+ .platform_phys_to_virt = openamp_virtio_phys_to_virt,
257+};
258+
259+struct rpc_caller *openamp_caller_init(struct openamp_caller *openamp)
260+{
261+ struct rpc_caller *rpc = &openamp->rpc_caller;
262+ int ret;
263+
264+ if (openamp->ref_count)
265+ return rpc;
266+
267+ rpc_caller_init(rpc, openamp);
268+
269+ rpc->call_begin = openamp_call_begin;
270+ rpc->call_invoke = openamp_call_invoke;
271+ rpc->call_end = openamp_call_end;
272+ rpc->virt_to_phys = openamp_virt_to_phys;
273+ rpc->phys_to_virt = openamp_phys_to_virt;
274+ openamp->platform_ops = &openamp_virtio_ops;
275+
276+ ret = openamp_init(openamp);
277+ if (ret < 0) {
278+ EMSG("openamp_init: failed to start: %d", ret);
279+ return rpc;
280+ }
281+ openamp->ref_count++;
282+
283+ return rpc;
284+}
285+
286+void openamp_caller_deinit(struct openamp_caller *openamp)
287+{
288+ struct rpc_caller *rpc = &openamp->rpc_caller;
289+
290+ if (--openamp->ref_count)
291+ return;
292+
293+ rpc->context = NULL;
294+ rpc->call_begin = NULL;
295+ rpc->call_invoke = NULL;
296+ rpc->call_end = NULL;
297+}
298+
299+int openamp_caller_discover(struct openamp_caller *openamp)
300+{
301+ return openamp_init(openamp);
302+}
303+
304+int openamp_caller_open(struct openamp_caller *openamp)
305+{
306+
307+}
308diff --git a/components/rpc/openamp/caller/sp/openamp_caller.h b/components/rpc/openamp/caller/sp/openamp_caller.h
309new file mode 100644
310index 00000000..3fb67c56
311--- /dev/null
312+++ b/components/rpc/openamp/caller/sp/openamp_caller.h
313@@ -0,0 +1,43 @@
314+/*
315+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
316+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
317+ *
318+ * SPDX-License-Identifier: BSD-3-Clause
319+ */
320+#ifndef OPENAMP_CALLER_H
321+#define OPENAMP_CALLER_H
322+
323+#include <stddef.h>
324+#include <rpc_caller.h>
325+
326+struct openamp_caller {
327+ struct rpc_caller rpc_caller;
328+ const struct openamp_platform_ops *platform_ops;
329+ uint32_t ref_count;
330+ uint8_t status;
331+
332+ void *transport;
333+ void *platform;
334+};
335+
336+struct openamp_platform_ops {
337+ int (*transport_init)(struct openamp_caller *openamp);
338+ int (*transport_deinit)(struct openamp_caller *openamp);
339+ int (*transport_notify)(struct openamp_caller *openamp);
340+ int (*transport_receive)(struct openamp_caller *openamp);
341+ int (*platform_init)(struct openamp_caller *openamp);
342+ int (*platform_deinit)(struct openamp_caller *openamp);
343+ int (*platform_call_begin)(struct openamp_caller *openamp,
344+ uint8_t **req_buf, size_t req_len);
345+ int (*platform_call_invoke)(struct openamp_caller *openamp,
346+ int *opstatus, uint8_t **resp_buf,
347+ size_t *resp_len);
348+ int (*platform_call_end)(struct openamp_caller *openamp);
349+ void *(*platform_virt_to_phys)(struct openamp_caller *openamp, void *va);
350+ void *(*platform_phys_to_virt)(struct openamp_caller *openamp, void *pa);
351+};
352+
353+struct rpc_caller *openamp_caller_init(struct openamp_caller *openamp);
354+void openamp_caller_deinit(struct openamp_caller *openamp);
355+
356+#endif
357diff --git a/components/rpc/openamp/caller/sp/openamp_mhu.c b/components/rpc/openamp/caller/sp/openamp_mhu.c
358new file mode 100644
359index 00000000..ffdadaf8
360--- /dev/null
361+++ b/components/rpc/openamp/caller/sp/openamp_mhu.c
362@@ -0,0 +1,191 @@
363+/*
364+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
365+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
366+ *
367+ * SPDX-License-Identifier: BSD-3-Clause
368+ */
369+
370+#include <config/interface/config_store.h>
371+#include <config/interface/config_blob.h>
372+#include <platform/interface/device_region.h>
373+#include <platform/drivers/arm/mhu_driver/mhu_v2.h>
374+#include <trace.h>
375+#include <errno.h>
376+#include <stdlib.h>
377+#include <stdint.h>
378+#include <stddef.h>
379+#include <limits.h>
380+
381+#include "openamp_caller.h"
382+
383+#define MHU_V_2_NOTIFY_CHANNEL 0
384+#define MHU_V_2_NOTIFY_VALUE 0xff
385+
386+struct openamp_mhu {
387+ struct device_region rx_region;
388+ struct device_region tx_region;
389+ struct mhu_v2_x_dev_t rx_dev;
390+ struct mhu_v2_x_dev_t tx_dev;
391+};
392+
393+static int openamp_mhu_device_get(const char *dev,
394+ struct device_region *dev_region)
395+{
396+ bool found;
397+
398+ found = config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, dev, 0,
399+ dev_region, sizeof(*dev_region));
400+ if (!found)
401+ return -EINVAL;
402+
403+ if (!dev_region->base_addr)
404+ return -EINVAL;
405+
406+ IMSG("mhu: device region found: %s addr: 0x%x size: %d", dev,
407+ dev_region->base_addr, dev_region->io_region_size);
408+
409+ return 0;
410+}
411+
412+int openamp_mhu_receive(struct openamp_caller *openamp)
413+{
414+ struct mhu_v2_x_dev_t *rx_dev;
415+ enum mhu_v2_x_error_t ret;
416+ struct openamp_mhu *mhu;
417+ uint32_t channel = 0;
418+ uint32_t irq_status;
419+
420+ if (!openamp->transport) {
421+ EMSG("openamp: mhu: receive transport not initialized");
422+ return -EINVAL;
423+ }
424+
425+ mhu = openamp->transport;
426+ rx_dev = &mhu->rx_dev;
427+
428+ irq_status = 0;
429+
430+ do {
431+ irq_status = mhu_v2_x_get_interrupt_status(rx_dev);
432+ } while(!irq_status);
433+
434+ ret = mhu_v2_1_get_ch_interrupt_num(rx_dev, &channel);
435+
436+ ret = mhu_v2_x_channel_clear(rx_dev, channel);
437+ if (ret != MHU_V_2_X_ERR_NONE) {
438+ EMSG("openamp: mhu: failed to clear channel: %d", channel);
439+ return -EPROTO;
440+ }
441+
442+ return 0;
443+}
444+
445+int openamp_mhu_notify_peer(struct openamp_caller *openamp)
446+{
447+ struct mhu_v2_x_dev_t *tx_dev;
448+ enum mhu_v2_x_error_t ret;
449+ struct openamp_mhu *mhu;
450+ uint32_t access_ready;
451+
452+ if (!openamp->transport) {
453+ EMSG("openamp: mhu: notify transport not initialized");
454+ return -EINVAL;
455+ }
456+
457+ mhu = openamp->transport;
458+ tx_dev = &mhu->tx_dev;
459+
460+ ret = mhu_v2_x_set_access_request(tx_dev);
461+ if (ret != MHU_V_2_X_ERR_NONE) {
462+ EMSG("openamp: mhu: set access request failed");
463+ return -EPROTO;
464+ }
465+
466+ do {
467+ ret = mhu_v2_x_get_access_ready(tx_dev, &access_ready);
468+ if (ret != MHU_V_2_X_ERR_NONE) {
469+ EMSG("openamp: mhu: failed to get access_ready");
470+ return -EPROTO;
471+ }
472+ } while (!access_ready);
473+
474+ ret = mhu_v2_x_channel_send(tx_dev, MHU_V_2_NOTIFY_CHANNEL,
475+ MHU_V_2_NOTIFY_VALUE);
476+ if (ret != MHU_V_2_X_ERR_NONE) {
477+ EMSG("openamp: mhu: failed send over channel");
478+ return -EPROTO;
479+ }
480+
481+ ret = mhu_v2_x_reset_access_request(tx_dev);
482+ if (ret != MHU_V_2_X_ERR_NONE) {
483+ EMSG("openamp: mhu: failed reset access request");
484+ return -EPROTO;
485+ }
486+
487+ return 0;
488+}
489+
490+int openamp_mhu_init(struct openamp_caller *openamp)
491+{
492+ struct mhu_v2_x_dev_t *rx_dev;
493+ struct mhu_v2_x_dev_t *tx_dev;
494+ struct openamp_mhu *mhu;
495+ int ret;
496+
497+ /* if we already have initialized skip this */
498+ if (openamp->transport)
499+ return 0;
500+
501+ mhu = malloc(sizeof(*mhu));
502+ if (!mhu)
503+ return -1;
504+
505+ ret = openamp_mhu_device_get("mhu-sender", &mhu->tx_region);
506+ if (ret < 0)
507+ goto free_mhu;
508+
509+ ret = openamp_mhu_device_get("mhu-receiver", &mhu->rx_region);
510+ if (ret < 0)
511+ goto free_mhu;
512+
513+ rx_dev = &mhu->rx_dev;
514+ tx_dev = &mhu->tx_dev;
515+
516+ rx_dev->base = (unsigned int)mhu->rx_region.base_addr;
517+ rx_dev->frame = MHU_V2_X_RECEIVER_FRAME;
518+
519+ tx_dev->base = (unsigned int)mhu->tx_region.base_addr;
520+ tx_dev->frame = MHU_V2_X_SENDER_FRAME;
521+
522+ ret = mhu_v2_x_driver_init(rx_dev, MHU_REV_READ_FROM_HW);
523+ if (ret < 0)
524+ goto free_mhu;
525+
526+ ret = mhu_v2_x_driver_init(tx_dev, MHU_REV_READ_FROM_HW);
527+ if (ret < 0)
528+ goto free_mhu;
529+
530+ openamp->transport = (void *)mhu;
531+
532+ return 0;
533+
534+free_mhu:
535+ free(mhu);
536+
537+ return ret;
538+}
539+
540+int openamp_mhu_deinit(struct openamp_caller *openamp)
541+{
542+ struct openamp_mhu *mhu;
543+
544+ if (!openamp->transport)
545+ return 0;
546+
547+ mhu = openamp->transport;
548+ free(mhu);
549+
550+ openamp->transport = NULL;
551+
552+ return 0;
553+}
554diff --git a/components/rpc/openamp/caller/sp/openamp_mhu.h b/components/rpc/openamp/caller/sp/openamp_mhu.h
555new file mode 100644
556index 00000000..2ae5cb8e
557--- /dev/null
558+++ b/components/rpc/openamp/caller/sp/openamp_mhu.h
559@@ -0,0 +1,19 @@
560+/*
561+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
562+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
563+ *
564+ * SPDX-License-Identifier: BSD-3-Clause
565+ */
566+#ifndef OPENAMP_MHU_H
567+#define OPENAMP_MHU_H
568+
569+#include <stddef.h>
570+#include "openamp_caller.h"
571+
572+int openamp_mhu_init(struct openamp_caller *openamp);
573+int openamp_mhu_deinit(struct openamp_caller *openamp);
574+
575+int openamp_mhu_notify_peer(struct openamp_caller *openamp);
576+int openamp_mhu_receive(struct openamp_caller *openamp);
577+
578+#endif
579diff --git a/components/rpc/openamp/caller/sp/openamp_virtio.c b/components/rpc/openamp/caller/sp/openamp_virtio.c
580new file mode 100644
581index 00000000..06e0735b
582--- /dev/null
583+++ b/components/rpc/openamp/caller/sp/openamp_virtio.c
584@@ -0,0 +1,554 @@
585+/*
586+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
587+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
588+ *
589+ * SPDX-License-Identifier: BSD-3-Clause
590+ */
591+
592+#include <metal/device.h>
593+#include <metal/spinlock.h>
594+#include <openamp/open_amp.h>
595+#include <platform/interface/device_region.h>
596+#include <config/interface/config_store.h>
597+
598+#include <stddef.h>
599+#include "openamp_caller.h"
600+
601+#define OPENAMP_SHEM_DEVICE_NAME "openamp-virtio"
602+#define OPENAMP_RPMSG_ENDPOINT_NAME OPENAMP_SHEM_DEVICE_NAME
603+#define OPENAMP_RPMSG_ENDPOINT_ADDR 1024
604+
605+#define OPENAMP_SHEM_PHYS 0x88000000
606+#define OPENAMP_SHEM_PHYS_PAGES 1
607+#define OPENAMP_SHEM_SE_PHYS 0xa8000000
608+
609+#define OPENAMP_SHEM_VDEV_SIZE (4 * 1024)
610+#define OPENAMP_SHEM_VRING_SIZE (4 * 1024)
611+
612+#define OPENAMP_BUFFER_NO_WAIT 0
613+#define OPENAMP_BUFFER_WAIT 1
614+
615+#define VIRTQUEUE_NR 2
616+#define VQ_TX 0
617+#define VQ_RX 1
618+
619+#define VRING_DESCRIPTORS 16
620+#define VRING_ALIGN 4
621+
622+#define container_of(ptr, type, member) \
623+ ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
624+
625+struct openamp_virtio_shm {
626+ uintptr_t base_addr;
627+ size_t size;
628+ uintptr_t vdev_status;
629+ size_t vdev_status_size;
630+ uintptr_t payload_addr;
631+ size_t payload_size;
632+ uintptr_t vring_tx;
633+ size_t vring_tx_size;
634+ uintptr_t vring_rx;
635+ size_t vring_rx_size;
636+
637+ metal_phys_addr_t shm_physmap[OPENAMP_SHEM_PHYS_PAGES];
638+};
639+
640+struct openamp_virtio_metal {
641+ struct metal_spinlock lock;
642+ struct metal_device shm_dev;
643+ struct metal_device *io_dev;
644+
645+ struct metal_io_region *io;
646+ struct openamp_virtio_shm shm;
647+};
648+
649+struct openamp_virtio_device {
650+ struct virtio_device virtio_dev;
651+ struct virtqueue *vq[VIRTQUEUE_NR];
652+ struct virtio_vring_info rvrings[VIRTQUEUE_NR];
653+};
654+
655+struct openamp_virtio_rpmsg {
656+ struct rpmsg_virtio_device rpmsg_vdev;
657+ struct rpmsg_endpoint ep;
658+ uint8_t *req_buf;
659+ uint32_t req_len;
660+ uint8_t *resp_buf;
661+ size_t resp_len;
662+};
663+
664+struct openamp_virtio {
665+ struct openamp_caller *openamp;
666+ struct openamp_virtio_rpmsg rpmsg;
667+ struct openamp_virtio_device vdev;
668+ struct openamp_virtio_metal metal;
669+};
670+
671+static struct openamp_virtio *openamp_virtio_from_dev(struct virtio_device *vdev)
672+{
673+ struct openamp_virtio_device *openamp_vdev;
674+
675+ openamp_vdev = container_of(vdev, struct openamp_virtio_device,
676+ virtio_dev);
677+
678+ return container_of(openamp_vdev, struct openamp_virtio, vdev);
679+}
680+
681+static struct openamp_virtio_rpmsg *openamp_virtio_rpmsg_from_dev(struct rpmsg_device *rdev)
682+{
683+ struct rpmsg_virtio_device *rvdev;
684+
685+ rvdev = container_of(rdev, struct rpmsg_virtio_device, rdev);
686+
687+ return container_of(rvdev, struct openamp_virtio_rpmsg, rpmsg_vdev);
688+
689+}
690+
691+static void openamp_virtio_metal_device_setup(struct metal_device *shm_dev,
692+ struct openamp_virtio_shm *shm)
693+{
694+ struct metal_io_region *shm_region;
695+
696+ shm_region = &shm_dev->regions[0];
697+
698+ shm_dev->name = OPENAMP_SHEM_DEVICE_NAME;
699+ shm_dev->num_regions = 1;
700+
701+ shm_region->virt = (void *)shm->payload_addr;
702+ shm_region->size = shm->payload_size;
703+
704+ shm_region->physmap = &shm->shm_physmap;
705+ shm_region->page_shift = (metal_phys_addr_t)(-1);
706+ shm_region->page_mask = (metal_phys_addr_t)(-1);
707+}
708+
709+static int openamp_virtio_metal_init(struct openamp_virtio_metal *metal)
710+{
711+ struct metal_init_params params = METAL_INIT_DEFAULTS;
712+ struct metal_device *shm_dev = &metal->shm_dev;
713+ int ret;
714+
715+ openamp_virtio_metal_device_setup(shm_dev, &metal->shm);
716+
717+ metal_spinlock_init(&metal->lock);
718+
719+ ret = metal_init(&params);
720+ if (ret < 0)
721+ return ret;
722+
723+ ret = metal_register_generic_device(shm_dev);
724+ if (ret < 0)
725+ goto metal_finish;
726+
727+ ret = metal_device_open("generic", OPENAMP_SHEM_DEVICE_NAME,
728+ &metal->io_dev);
729+ if (ret < 0)
730+ goto metal_finish;
731+
732+ metal->io = metal_device_io_region(metal->io_dev, 0);
733+ if (!metal->io) {
734+ EMSG("openamp: virtio: failed to init metal io");
735+ ret = -EPROTO;
736+ goto metal_finish;
737+ }
738+
739+ return 0;
740+
741+metal_finish:
742+ metal_finish();
743+ return ret;
744+}
745+
746+static unsigned char openamp_virtio_status_get(struct virtio_device *vdev)
747+{
748+ struct openamp_virtio *virtio = openamp_virtio_from_dev(vdev);
749+ struct openamp_virtio_shm *shm = &virtio->metal.shm;
750+
751+ uint32_t status = *(volatile uint32_t *)shm->vdev_status;
752+
753+ return status;
754+}
755+
756+static void openamp_virtio_status_set(struct virtio_device *vdev,
757+ unsigned char status)
758+{
759+ struct openamp_virtio *virtio = openamp_virtio_from_dev(vdev);
760+ struct openamp_virtio_shm *shm = &virtio->metal.shm;
761+
762+ *(volatile uint32_t *)shm->vdev_status = status;
763+}
764+
765+static int count;
766+
767+static uint32_t openamp_virtio_features_get(struct virtio_device *vdev)
768+{
769+ return 1 << VIRTIO_RPMSG_F_NS;
770+}
771+
772+static void openamp_virtio_notify(struct virtqueue *vq)
773+{
774+ struct openamp_virtio_device *openamp_vdev;
775+ struct openamp_caller *openamp;
776+ struct openamp_virtio *virtio;
777+ int ret;
778+
779+ openamp_vdev = container_of(vq->vq_dev, struct openamp_virtio_device, virtio_dev);
780+ virtio = container_of(openamp_vdev, struct openamp_virtio, vdev);
781+ openamp = virtio->openamp;
782+
783+ ret = openamp->platform_ops->transport_notify(openamp);
784+ if (ret < 0)
785+ EMSG("openamp: virtio: erro in transport_notify: %d", ret);
786+}
787+
788+const static struct virtio_dispatch openamp_virtio_dispatch = {
789+ .get_status = openamp_virtio_status_get,
790+ .set_status = openamp_virtio_status_set,
791+ .get_features = openamp_virtio_features_get,
792+ .notify = openamp_virtio_notify,
793+};
794+
795+static int openamp_virtio_device_setup(struct openamp_virtio *virtio)
796+{
797+ struct openamp_virtio_metal *metal = &virtio->metal;
798+ struct openamp_virtio_device *openamp_vdev = &virtio->vdev;
799+ struct virtio_device *vdev = &openamp_vdev->virtio_dev;
800+ struct openamp_virtio_shm *shm = &metal->shm;
801+ struct virtio_vring_info *rvring;
802+
803+ rvring = &openamp_vdev->rvrings[0];
804+
805+ vdev->role = RPMSG_REMOTE;
806+ vdev->vrings_num = VIRTQUEUE_NR;
807+ vdev->func = &openamp_virtio_dispatch;
808+
809+ openamp_vdev->vq[VQ_TX] = virtqueue_allocate(VRING_DESCRIPTORS);
810+ if (!openamp_vdev->vq[VQ_TX]) {
811+ EMSG("openamp: virtio: failed to allocate virtqueue 0");
812+ return -ENOMEM;
813+ }
814+ rvring->io = metal->io;
815+ rvring->info.vaddr = (void *)shm->vring_tx;
816+ rvring->info.num_descs = VRING_DESCRIPTORS;
817+ rvring->info.align = VRING_ALIGN;
818+ rvring->vq = openamp_vdev->vq[VQ_TX];
819+
820+ openamp_vdev->vq[VQ_RX] = virtqueue_allocate(VRING_DESCRIPTORS);
821+ if (!openamp_vdev->vq[VQ_RX]) {
822+ EMSG("openamp: virtio: failed to allocate virtqueue 1");
823+ goto free_vq;
824+ }
825+ rvring = &openamp_vdev->rvrings[VQ_RX];
826+ rvring->io = metal->io;
827+ rvring->info.vaddr = (void *)shm->vring_rx;
828+ rvring->info.num_descs = VRING_DESCRIPTORS;
829+ rvring->info.align = VRING_ALIGN;
830+ rvring->vq = openamp_vdev->vq[VQ_RX];
831+
832+ vdev->vrings_info = &openamp_vdev->rvrings[0];
833+
834+ return 0;
835+
836+free_vq:
837+ virtqueue_free(openamp_vdev->vq[VQ_TX]);
838+ virtqueue_free(openamp_vdev->vq[VQ_RX]);
839+
840+ return -ENOMEM;
841+}
842+
843+static int openamp_virtio_rpmsg_endpoint_callback(struct rpmsg_endpoint *ep,
844+ void *data, size_t len,
845+ uint32_t src, void *priv)
846+{
847+ struct openamp_virtio_rpmsg *vrpmsg;
848+ struct rpmsg_device *rdev;
849+ struct openamp_virtio *virtio;
850+
851+ rdev = ep->rdev;
852+ vrpmsg = openamp_virtio_rpmsg_from_dev(rdev);
853+ virtio = container_of(vrpmsg, struct openamp_virtio, rpmsg);
854+
855+ rpmsg_hold_rx_buffer(ep, data);
856+ vrpmsg->resp_buf = data;
857+ vrpmsg->resp_len = len;
858+
859+ return 0;
860+}
861+
862+static void openamp_virtio_rpmsg_service_unbind(struct rpmsg_endpoint *ep)
863+{
864+ struct openamp_virtio_rpmsg *vrpmsg;
865+ struct rpmsg_device *rdev;
866+
867+ rdev = container_of(ep, struct rpmsg_device, ns_ept);
868+ vrpmsg = openamp_virtio_rpmsg_from_dev(rdev);
869+
870+ rpmsg_destroy_ept(&vrpmsg->ep);
871+}
872+
873+static void openamp_virtio_rpmsg_endpoint_bind(struct rpmsg_device *rdev,
874+ const char *name,
875+ unsigned int dest)
876+{
877+ struct openamp_virtio_rpmsg *vrpmsg;
878+
879+ vrpmsg = openamp_virtio_rpmsg_from_dev(rdev);
880+
881+ rpmsg_create_ept(&vrpmsg->ep, rdev, name, RPMSG_ADDR_ANY, dest,
882+ openamp_virtio_rpmsg_endpoint_callback,
883+ openamp_virtio_rpmsg_service_unbind);
884+}
885+
886+static int openamp_virtio_rpmsg_device_setup(struct openamp_virtio *virtio,
887+ struct device_region *virtio_dev)
888+{
889+ struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
890+ struct rpmsg_virtio_device *rpmsg_vdev = &vrpmsg->rpmsg_vdev;
891+ struct openamp_virtio_device *openamp_vdev = &virtio->vdev;
892+ struct virtio_device *vdev = &openamp_vdev->virtio_dev;
893+ struct openamp_virtio_metal *metal = &virtio->metal;
894+ int ret;
895+
896+ /*
897+ * we assume here that we are the client side and do not need to
898+ * initialize the share memory poll (this is done at server side).
899+ */
900+ ret = rpmsg_init_vdev(rpmsg_vdev, vdev,
901+ openamp_virtio_rpmsg_endpoint_bind, metal->io,
902+ NULL);
903+ if (ret < 0) {
904+ EMSG("openamp: virtio: init vdev failed: %d", ret);
905+ return ret;
906+ }
907+
908+
909+ ret = rpmsg_create_ept(&vrpmsg->ep, &rpmsg_vdev->rdev,
910+ OPENAMP_RPMSG_ENDPOINT_NAME, RPMSG_ADDR_ANY,
911+ RPMSG_ADDR_ANY,
912+ openamp_virtio_rpmsg_endpoint_callback,
913+ openamp_virtio_rpmsg_service_unbind);
914+ if (ret < 0) {
915+ EMSG("openamp: virtio: failed to create endpoint: %d", ret);
916+ return ret;
917+ }
918+
919+ /* set default remote addr */
920+ vrpmsg->ep.dest_addr = OPENAMP_RPMSG_ENDPOINT_ADDR;
921+
922+ return 0;
923+}
924+
925+static void openamp_virtio_shm_set(struct openamp_virtio *virtio,
926+ struct device_region *virtio_region)
927+{
928+ struct openamp_virtio_shm *shm = &virtio->metal.shm;
929+
930+ shm->base_addr = virtio_region->base_addr;
931+ shm->size = virtio_region->io_region_size;
932+
933+ shm->vdev_status = shm->base_addr;
934+ shm->vdev_status_size = OPENAMP_SHEM_VDEV_SIZE;
935+
936+ shm->vring_rx = shm->base_addr + shm->size -
937+ (2 * OPENAMP_SHEM_VRING_SIZE);
938+ shm->vring_rx_size = OPENAMP_SHEM_VRING_SIZE;
939+
940+ shm->vring_tx = shm->vring_rx + shm->vring_rx_size;
941+ shm->vring_tx_size = OPENAMP_SHEM_VRING_SIZE;
942+
943+ shm->payload_addr = shm->vdev_status + shm->vdev_status_size;
944+ shm->payload_size = shm->size - shm->vdev_status_size -
945+ shm->vring_rx_size - shm->vring_tx_size;
946+
947+ shm->shm_physmap[0] = OPENAMP_SHEM_PHYS + shm->vdev_status_size;
948+
949+ IMSG("SHEM: base: 0x%0x size: 0x%0x size: %d",
950+ shm->base_addr, shm->size, shm->size);
951+ IMSG("VDEV: base: 0x%0x size: 0x%0x size: %d",
952+ shm->vdev_status, shm->vdev_status_size, shm->vdev_status_size);
953+ IMSG("PAYLOAD: base: 0x%0x size: 0x%0x size: %d",
954+ shm->payload_addr, shm->payload_size, shm->payload_size);
955+ IMSG("VRING_TX: base: 0x%0x size: 0x%0x size: %d",
956+ shm->vring_tx, shm->vring_tx_size, shm->vring_tx_size);
957+ IMSG("VRING_RX: base: 0x%0x size: 0x%0x size: %d",
958+ shm->vring_rx, shm->vring_rx_size, shm->vring_rx_size);
959+ IMSG("PHYMAP: base: 0x%0x", shm->shm_physmap[0]);
960+}
961+
962+static int openamp_virtio_device_get(const char *dev,
963+ struct device_region *dev_region)
964+{
965+ bool found;
966+
967+ found = config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, dev, 0,
968+ dev_region, sizeof(*dev_region));
969+ if (!found) {
970+ EMSG("openamp: virtio: device region not found: %s", dev);
971+ return -EINVAL;
972+ }
973+
974+ if (dev_region->base_addr == 0 || dev_region->io_region_size == 0) {
975+ EMSG("openamp: virtio: device region not valid");
976+ return -EINVAL;
977+ }
978+
979+ IMSG("openamp: virtio: device region found: %s addr: 0x%x size: %d",
980+ dev, dev_region->base_addr, dev_region->io_region_size);
981+
982+ return 0;
983+}
984+
985+int openamp_virtio_call_begin(struct openamp_caller *openamp, uint8_t **req_buf,
986+ size_t req_len)
987+{
988+ struct openamp_virtio *virtio = openamp->platform;
989+ struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
990+ struct rpmsg_endpoint *ep = &vrpmsg->ep;
991+
992+
993+ *req_buf = rpmsg_get_tx_payload_buffer(ep, &vrpmsg->req_len,
994+ OPENAMP_BUFFER_WAIT);
995+ if (*req_buf == NULL)
996+ return -EINVAL;
997+
998+ if (vrpmsg->req_len < req_len)
999+ return -E2BIG;
1000+
1001+ vrpmsg->req_buf = *req_buf;
1002+
1003+ return 0;
1004+}
1005+
1006+int openamp_virtio_call_invoke(struct openamp_caller *openamp, int *opstatus,
1007+ uint8_t **resp_buf, size_t *resp_len)
1008+{
1009+ const struct openamp_platform_ops *ops = openamp->platform_ops;
1010+ struct openamp_virtio *virtio = openamp->platform;
1011+ struct openamp_virtio_device *openamp_vdev = &virtio->vdev;
1012+ struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
1013+ struct rpmsg_endpoint *ep = &vrpmsg->ep;
1014+ int ret;
1015+
1016+ ret = rpmsg_send_nocopy(ep, vrpmsg->req_buf, vrpmsg->req_len);
1017+ if (ret < 0) {
1018+ EMSG("openamp: virtio: send nocopy failed: %d", ret);
1019+ return -EIO;
1020+ }
1021+
1022+ if (ret != vrpmsg->req_len) {
1023+ EMSG("openamp: virtio: send less bytes %d than requested %d",
1024+ ret, vrpmsg->req_len);
1025+ return -EIO;
1026+ }
1027+
1028+ if (!ops->transport_receive)
1029+ return 0;
1030+
1031+ ret = ops->transport_receive(openamp);
1032+ if (ret < 0) {
1033+ EMSG("openamp: virtio: failed transport_receive");
1034+ return -EIO;
1035+ }
1036+
1037+ virtqueue_notification(openamp_vdev->vq[VQ_RX]);
1038+
1039+ *resp_buf = vrpmsg->resp_buf;
1040+ *resp_len = vrpmsg->resp_len;
1041+
1042+ return 0;
1043+}
1044+
1045+void openamp_virtio_call_end(struct openamp_caller *openamp)
1046+{
1047+ struct openamp_virtio *virtio = openamp->platform;
1048+ struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
1049+
1050+ rpmsg_release_rx_buffer(&vrpmsg->ep, vrpmsg->resp_buf);
1051+
1052+ vrpmsg->req_buf = NULL;
1053+ vrpmsg->req_len = 0;
1054+ vrpmsg->resp_buf = NULL;
1055+ vrpmsg->resp_len = 0;
1056+}
1057+
1058+void *openamp_virtio_virt_to_phys(struct openamp_caller *openamp, void *va)
1059+{
1060+ struct openamp_virtio *virtio = openamp->platform;
1061+ struct openamp_virtio_metal *metal = &virtio->metal;
1062+
1063+ return metal_io_virt_to_phys(metal->io, va);
1064+}
1065+
1066+void *openamp_virtio_phys_to_virt(struct openamp_caller *openamp, void *pa)
1067+{
1068+ struct openamp_virtio *virtio = openamp->platform;
1069+ struct openamp_virtio_metal *metal = &virtio->metal;
1070+
1071+ return metal_io_phys_to_virt(metal->io, pa);
1072+}
1073+
1074+int openamp_virtio_init(struct openamp_caller *openamp)
1075+{
1076+ struct device_region virtio_dev;
1077+ struct openamp_virtio *virtio;
1078+ int ret;
1079+
1080+ if (openamp->platform)
1081+ return 0;
1082+
1083+
1084+ virtio = malloc(sizeof(*virtio));
1085+ if (!virtio)
1086+ return -ENOMEM;
1087+
1088+ virtio->openamp = openamp;
1089+
1090+ ret = openamp_virtio_device_get(OPENAMP_SHEM_DEVICE_NAME, &virtio_dev);
1091+ if (ret < 0)
1092+ goto free_virtio;
1093+
1094+ openamp_virtio_shm_set(virtio, &virtio_dev);
1095+
1096+ ret = openamp_virtio_metal_init(&virtio->metal);
1097+ if (ret < 0)
1098+ goto free_virtio;
1099+
1100+ ret = openamp_virtio_device_setup(virtio);
1101+ if (ret < 0)
1102+ goto finish_metal;
1103+
1104+ ret = openamp_virtio_rpmsg_device_setup(virtio, &virtio_dev);
1105+ if (ret < 0) {
1106+ EMSG("openamp: virtio: rpmsg device setup failed: %d", ret);
1107+ goto finish_metal;
1108+ }
1109+
1110+ openamp->platform = virtio;
1111+
1112+ return 0;
1113+
1114+finish_metal:
1115+ metal_finish();
1116+
1117+free_virtio:
1118+ free(virtio);
1119+
1120+ return ret;
1121+}
1122+
1123+int openamp_virtio_deinit(struct openamp_caller *openamp)
1124+{
1125+ struct openamp_virtio *virtio;
1126+
1127+ if (!openamp->platform)
1128+ return 0;
1129+
1130+ virtio = openamp->platform;
1131+
1132+ metal_finish();
1133+ free(virtio);
1134+
1135+ openamp->platform = NULL;
1136+
1137+ return 0;
1138+}
1139diff --git a/components/rpc/openamp/caller/sp/openamp_virtio.h b/components/rpc/openamp/caller/sp/openamp_virtio.h
1140new file mode 100644
1141index 00000000..915128ff
1142--- /dev/null
1143+++ b/components/rpc/openamp/caller/sp/openamp_virtio.h
1144@@ -0,0 +1,24 @@
1145+/*
1146+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
1147+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
1148+ *
1149+ * SPDX-License-Identifier: BSD-3-Clause
1150+ */
1151+#ifndef OPENAMP_VIRTIO_H
1152+#define OPENAMP_VIRTIO_H
1153+
1154+#include <stddef.h>
1155+#include "openamp_caller.h"
1156+
1157+int openamp_virtio_call_begin(struct openamp_caller *openamp, uint8_t **req_buf,
1158+ size_t req_len);
1159+int openamp_virtio_call_invoke(struct openamp_caller *openamp, int *opstatus,
1160+ uint8_t **resp_buf, size_t *resp_len);
1161+int openamp_virtio_call_end(struct openamp_caller *openamp);
1162+void *openamp_virtio_virt_to_phys(struct openamp_caller *openamp, void *va);
1163+void *openamp_virtio_phys_to_virt(struct openamp_caller *openamp, void *pa);
1164+
1165+int openamp_virtio_init(struct openamp_caller *openamp);
1166+int openamp_virtio_deinit(struct openamp_caller *openamp);
1167+
1168+#endif
1169diff --git a/deployments/se-proxy/opteesp/CMakeLists.txt b/deployments/se-proxy/opteesp/CMakeLists.txt
1170index 248bd7e3..1511bbad 100644
1171--- a/deployments/se-proxy/opteesp/CMakeLists.txt
1172+++ b/deployments/se-proxy/opteesp/CMakeLists.txt
1173@@ -75,6 +75,7 @@ add_components(TARGET "se-proxy"
1174 "components/service/attestation/include"
1175 "components/service/attestation/provider"
1176 "components/service/attestation/provider/serializer/packed-c"
1177+ "components/rpc/openamp/caller/sp"
1178
1179 # Stub service provider backends
1180 "components/rpc/dummy"
1181diff --git a/deployments/se-proxy/opteesp/default_se-proxy.dts.in b/deployments/se-proxy/opteesp/default_se-proxy.dts.in
1182index f351a592..55d49b31 100644
1183--- a/deployments/se-proxy/opteesp/default_se-proxy.dts.in
1184+++ b/deployments/se-proxy/opteesp/default_se-proxy.dts.in
1185@@ -32,6 +32,12 @@
1186 pages-count = <16>;
1187 attributes = <0x3>; /* read-write */
1188 };
1189+ openamp-virtio {
1190+ /* Armv8 A Foundation Platform values */
1191+ base-address = <0x00000000 0x88000000>;
1192+ pages-count = <256>;
1193+ attributes = <0x3>; /* read-write */
1194+ };
1195 };
1196 };
1197 };