rpmsg#
OCaml bindings to the Linux RPMsg character device interface for inter-partition messaging.
RPMsg (Remote Processor Messaging) provides message-based IPC between partitions on asymmetric multiprocessing platforms. It is used for communication between a Linux host and co-processor partitions via virtio vrings on Jailhouse, Xen, and Zynq UltraScale+ platforms.
Endpoint IO is built on Eio flows, so it integrates directly with the Eio event loop.
Installation#
Install with opam:
$ opam install rpmsg
If opam cannot find the package, it may not yet be released in the public
opam-repository. Add the overlay repository, then install it:
$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install rpmsg
Usage#
Send and receive messages on an endpoint#
Open an endpoint, wrap the fd in Eio flows, and exchange messages:
let run () =
Eio_main.run @@ fun env ->
Eio.Switch.run @@ fun sw ->
let ctrl = Rpmsg.Ctrl.open_ () in
let idx =
Rpmsg.Ctrl.create_endpoint ctrl ~name:"my-ep" ~src:1024 ~dst:1025
in
let fd = Rpmsg.Endpoint.open_ idx in
let flow = Eio_unix.Net.import_socket_stream ~sw ~close_unix:true fd in
let ep = Rpmsg.Endpoint.of_source_sink ~source:flow ~sink:flow in
Rpmsg.Endpoint.send ep "hello";
(match Rpmsg.Endpoint.recv ep ~max_size:Rpmsg.Endpoint.max_message_size with
| Some reply -> Fmt.pr "got: %s@." reply
| None -> Fmt.pr "peer closed@.");
Rpmsg.Endpoint.close ep;
Rpmsg.Ctrl.destroy_endpoint ctrl ~name:"my-ep" ~src:1024 ~dst:1025;
Rpmsg.Ctrl.close ctrl
Messages are at most 496 bytes (512 virtio buffer minus the 16-byte RPMsg
header); see Rpmsg.Endpoint.max_message_size.
API#
Endpoint messaging#
Rpmsg.Endpoint.of_source_sink ~source ~sink-- wrap Eio flows.Rpmsg.Endpoint.send ep msgRpmsg.Endpoint.recv ep ~max_size--Noneon EOF.Rpmsg.Endpoint.close epRpmsg.Endpoint.max_message_size
Control device (create / destroy endpoints)#
The control device (/dev/rpmsg_ctrl*) creates and destroys endpoints via
ioctl. On macOS every call raises Failure (RPMsg does not exist outside
Linux).
Rpmsg.Ctrl.open_ ?index ()-- open/dev/rpmsg_ctrlN(defaultN=0).Rpmsg.Ctrl.create_endpoint t ~name ~src ~dst-- returns the/dev/rpmsgNindex.Rpmsg.Ctrl.destroy_endpoint t ~name ~src ~dstRpmsg.Ctrl.close tRpmsg.Endpoint.open_ n-- open/dev/rpmsgNby index, returning the raw fd.
Wire format#
Rpmsg.endpoint_info_codec : endpoint_info Wire.Codec.t encodes the Linux
kernel struct rpmsg_endpoint_info (name[32], src:u32, dst:u32 -- 40
bytes) without manual C struct packing.