To write an OpenAMP application, follow these steps:
- A firmware resource table.
The resource table defines the necessary firmware entries for the OpenAMP application. It is a list of system resources required by the remote_proc.
- Create remoteproc struct using resource table.
- Define RPMsg callback functions.
- Create RPMsg virtio device.
- Create an RPMsg endpint and associate the RPMsg device with the callback functions.
- Use
rpmsg_send()to send message across to the remote processor.
After initializing the framework, the flow of an OpenAMP application consists of the
RPMsg channel acting as communication between the master and remote processor via the
RPMsg send() and I/O callback functions. The following is a flow
diagram to show this.
Figure 1. Flow Diagram

Following is a sample OpenAMP set up and flow with a resource table, Remoteproc instance and RPMsg callback functions:
struct resource_table table = {
/* Version number. If the structure changes in the future, this acts as
* reference to what the structure is.
*/
.ver = 1,
/* Number of resources; Matches number of offsets in array */
.num = 2,
/* reserved (must be zero) */
.reserved = 0,
{ /* array of offsets pointing at various resource entries */
/* This RSC_RPROC_MEM entry sets the shared memory address range. It tells the Linux kernel the shared memory range the remote can access. */
{RSC_RPROC_MEM, 0x3ed40000, 0x3ed40000, 0x100000, 0},
/* virtio device header */
{
RSC_VDEV, VIRTIO_ID_RPMSG_, 0, RPMSG_IPU_C0_FEATURES, 0, 0, 0,
NUM_VRINGS, {0, 0},
}
}
};
#include <openamp/remoteproc.h>
#include <openamp/rpmsg.h>
#include <openamp/rpmsg_virtio.h>
/* User defined remoteproc operations for communication */
struct remoteproc rproc_ops = {
.init = local_rproc_init,
.mmap = local_rproc_mmap,
.notify = local_rproc_notify,
.remove = local_rproc_remove,
};
/* Remoteproc instance */
struct remoteproc rproc;
/* RPMsg VirtIO device instance */
struct rpmsg_virtio_device rpmsg_vdev;
/* RPMsg device */
struct rpmsg_device *rpmsg_dev;
/* Resource Table */
void *rsc_table = &resource_table;
/* Size of the resource table */
int rsc_size = sizeof(resource_table);
/* Shared memory metal I/O region */
struct metal_io_region *shm_io;
/* VirtIO device */
struct virtio_device *vdev;
/* RPMsg shared buffers pool */
struct rpmsg_virtio_shm_pool shpool;
/* Shared buffers */
void *shbuf;
/* RPMsg endpoint */
struct rpmsg_endpoint ept;
/* User defined RPMsg name service callback */
void ns_bind_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest);
/* User defined RPMsg endpoint received message callback */
void rpmsg_ept_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv);
/* User defined RPMsg name service unbind request callback */
void ns_unbind_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest);
void main(void)
{
/* Instantiate remoteproc instance */
remoteproc_init(&rproc, &rproc_ops);
/* Mmap shared memories so that they can be used */
remoteproc_mmap(&rproc, &physical_address, NULL, size,
<memory_attributes>, &shm_io);
/* Parse resource table to remoteproc */
remoteproc_set_rsc_table(&rproc, rsc_table, rsc_size);
/* Create VirtIO device from remoteproc */
vdev = remoteproc_create_virtio(&rproc, 0, VIRTIO_DEV_MASTER, NULL);
/* Initialize the shared buffers pool (only if VirtIO master) */
shbuf = metal_io_phys_to_virt(shm_io, SHARED_BUF_PA);
rpmsg_virtio_init_shm_pool(&shpool, shbuf, SHARED_BUFF_SIZE);
/* Initialize RPMsg VirtIO device with the VirtIO device */
rpmsg_init_vdev(&rpmsg_vdev, vdev, ns_bind_cb, io, shm_io, &shpool);
/* Get RPMsg device from RPMsg VirtIO device */
rpmsg_dev = rpmsg_virtio_get_rpmsg_device(&rpmsg_vdev);
/* Create RPMsg endpoint */
rpmsg_create_ept(&ept, rdev, RPMSG_SERVICE_NAME, RPMSG_ADDR_ANY,
rpmsg_ept_cb, ns_unbind_cb);
/* Wait until endpoint is ready */
while (!is_rpmsg_ept_read(&ept)) {
rproc_virtio_notified(vdev, RSC_NOTIFY_ID_ANY);
}
/* Send RPMsg */
rpmsg_send(&ept, data, size);
do {
rproc_virtio_notified(vdev, RSC_NOTIFY_ID_ANY);
} while (!ns_unbind_cb_is_called && !user_decided_to_end_communication);
/* End of communication, destroy the endpoint and clean up */
rpmsg_destroy_ept(&ept);
rpmsg_deinit_vdev(&rpmsg_vdev);
remoteproc_remove_virtio(&rproc, vdev);
remoteproc_remove(&rproc);
}