[Linux] RPMsg Porting Guide
Introduction
RPMsg (Remote Processor Messaging) is a standard protocol used to implement lightweight and efficient Inter-Processor Communication (IPC) in multi-core environments. It is widely utilized in systems with a Linux + MCU (or RTOS) architecture, making message exchange between heterogeneous processors simple and reliable.
RPMsg Basic Structure
RPMsg operates on top of the OpenAMP framework. Its core components include:
Virtio
An interface that abstracts virtual devices.
Vring
A ring-buffered queue structure for actual data buffers. It manages incoming and outgoing messages based on these queues.
Remoteproc
A framework to load, boot, and manage remote processors. It primarily provides three functions: start, stop, and kick. While start/stop control the lifecycle of the remote device, kick acts as a doorbell (notification) for communication. Implementing a platform driver for specific vendor scenarios is crucial on the Master side.
RPMsg Endpoint
The actual channel through which messages are sent and received. Endpoints with the same name on both Linux and RTOS are connected to each other.
Why Use RPMsg?
- Provides standard APIs, eliminating the need to implement custom IPC from scratch.
- Enables fast transmission based on shared memory structures.
- Supports major operating systems, including Linux and Zephyr RTOS.
Porting Note
This porting scenario involves communication between two clusters using RPMsg. In this setup, the Master device typically runs Linux, and the Remote device runs an RTOS like Zephyr.
Environment
- Chip: TCC807x
- Master (Linux): Kernel 5.10 (Sub-Core)
- Remote (Zephyr): RTOS 3.7 (Main Core)
The initial phase focuses on a self-boot scenario where the Remote device is already running before Linux boots. We implement only the kick function for doorbell interrupts and provide static carveouts (reserved memory regions). Since we use shared memory based on Virtio, dcache coherency (cache invalidate/flush) must be strictly guaranteed.
Since the resource_table is determined by the final image of the Remote device, we start the work from the Remote side.
Remote Side: Zephyr Configuration
Zephyr provides built-in OpenAMP library support and samples. The openamp_rsc_table sample is an excellent starting point for Linux communication.
Cache Coherency
Ensure the following configurations are enabled in Zephyr to handle cache operations correctly:
CONFIG_CACHE_MANAGEMENT=y
CONFIG_OPENAMP_WITH_DCACHE=y
Verify these settings in build/zephyr/.config after running west build.
Self-boot Scenario Adjustments
Most drivers are designed for auto-boot. For a self-boot scenario, the resource_table.h in the OpenAMP library needs modification to use static addresses for Vrings:
/* Before: Allocated by Master */
#define VRING_RX_ADDRESS -1
#define VRING_TX_ADDRESS -1
#define VRING_BUFF_ADDRESS -1
/* After: Static addresses for Self-boot */
#define VRING_RX_ADDRESS 0x200c9000UL
#define VRING_TX_ADDRESS 0x200c8000UL
#define VRING_BUFF_ADDRESS 0x200ca000UL
Master Side: Linux Driver
Linux provides the RPMsg and Remoteproc frameworks out of the box in drivers/rpmsg and drivers/remoteproc. However, since our TCC807x scenario uses a self-booting remote processor, we develop a custom Remoteproc platform driver.
Execution Flow
- Probe: The driver matches the
compatiblestring in the Device Tree. - rproc_alloc: Creates a handle for the remote processor. Maps the
resource_tablefrom the reserved memory region. - rproc_add_carveout: Informs the framework about pre-allocated shared memory regions.
- rproc_boot: In self-boot mode, it skips firmware loading and transitions the state to
RPROC_DETACHED. - Handle VDEV: Processes
RSC_VDEVentries in the resource table to define Virtio devices. - Virtio Bus Registration: Matches the
VIRTIO_ID_RPMSGand triggersrpmsg_probe. - Virtqueue Initialization: Sets up RX/TX virtqueues based on the mapped Vring memory.
- Buffer Allocation: Allocates actual message payloads and registers them to the receive virtqueue.
Shared Memory Configuration (Device Tree)
The shared memory regions should be defined carefully in the Device Tree to match the Remote device’s resource table layout.
&reserved_memory {
rsc_table0: rsc-table@200c6000 {
no-map;
reg = <0x0 0x200c6000 0x0 0x2000>;
tcc,rsc-offset = <0x3b8>;
tcc,rsc-size = <0x1000>;
};
/* ... define Vrings and Buffers ... */
};
Conclusion
After porting, the rpmsg-client-sample from the Linux kernel successfully communicated with the Zephyr remote. Although it took about three weeks to study Virtio/RPMsg and complete the porting, the result provides a robust foundation for multi-core communication.

Leave a comment