RPMsg inter-partition messaging
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

ocaml-linkedin: apply dune fmt

Pure formatting changes from `dune fmt`: doc comment placement moves
from above the binding to below it for `type`s, multi-line `match`
expressions collapse onto one line where they fit, and infix operator
applications pick up spaces (`Soup.($?)` -> `Soup.( $? )`). No
semantic changes.

+69 -16
+62 -16
README.md
··· 3 3 OCaml bindings to the Linux RPMsg character device interface for inter-partition messaging. 4 4 5 5 RPMsg (Remote Processor Messaging) provides message-based IPC between 6 - partitions on asymmetric multiprocessing platforms. This library wraps the 7 - `/dev/rpmsg_ctrl*` and `/dev/rpmsg*` character devices, encoding the 8 - `rpmsg_endpoint_info` struct via Wire codecs instead of manual C struct packing. 9 - It is used for communication between the Linux host and co-processor partitions 10 - via virtio vrings on Jailhouse, Xen, and Zynq UltraScale+ platforms. 6 + partitions on asymmetric multiprocessing platforms. It is used for 7 + communication between a Linux host and co-processor partitions via virtio 8 + vrings on Jailhouse, Xen, and Zynq UltraScale+ platforms. 11 9 12 10 Endpoint IO is built on Eio flows, so it integrates directly with the Eio 13 11 event loop. 14 12 15 13 ## Installation 16 14 15 + Install with opam: 16 + 17 + ```sh 18 + $ opam install rpmsg 17 19 ``` 18 - opam install rpmsg 20 + 21 + If opam cannot find the package, it may not yet be released in the public 22 + `opam-repository`. Add the overlay repository, then install it: 23 + 24 + ```sh 25 + $ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git 26 + $ opam update 27 + $ opam install rpmsg 19 28 ``` 20 29 21 30 ## Usage 31 + 32 + ### Send and receive messages on an endpoint 33 + 34 + Open an endpoint, wrap the fd in Eio flows, and exchange messages: 22 35 23 36 ```ocaml 24 - (* Create an endpoint and exchange messages *) 25 37 let () = 38 + Eio_main.run @@ fun env -> 39 + Eio.Switch.run @@ fun sw -> 26 40 let ctrl = Rpmsg.Ctrl.open_ () in 27 - let idx = Rpmsg.Ctrl.create_endpoint ctrl ~name:"my-ep" ~src:1024 ~dst:1025 in 41 + let idx = 42 + Rpmsg.Ctrl.create_endpoint ctrl ~name:"my-ep" ~src:1024 ~dst:1025 43 + in 28 44 let fd = Rpmsg.Endpoint.open_ idx in 29 - (* wrap the fd with Eio flows, then: *) 30 - (* let ep = Rpmsg.Endpoint.of_source_sink ~source ~sink in *) 31 - (* Rpmsg.Endpoint.send ep "hello"; *) 32 - Unix.close fd; 45 + let flow = Eio_unix.Net.import_socket_stream ~sw ~close_unix:true fd in 46 + let ep = Rpmsg.Endpoint.of_source_sink ~source:flow ~sink:flow in 47 + Rpmsg.Endpoint.send ep "hello"; 48 + (match Rpmsg.Endpoint.recv ep ~max_size:Rpmsg.Endpoint.max_message_size with 49 + | Some reply -> Fmt.pr "got: %s@." reply 50 + | None -> Fmt.pr "peer closed@."); 51 + Rpmsg.Endpoint.close ep; 52 + Rpmsg.Ctrl.destroy_endpoint ctrl ~name:"my-ep" ~src:1024 ~dst:1025; 33 53 Rpmsg.Ctrl.close ctrl 34 54 ``` 35 55 56 + Messages are at most 496 bytes (512 virtio buffer minus the 16-byte RPMsg 57 + header); see `Rpmsg.Endpoint.max_message_size`. 58 + 36 59 ## API 37 60 38 - - `Rpmsg.endpoint_info` -- The `rpmsg_endpoint_info` record type matching the Linux kernel struct: a 32-byte name, 32-bit source address, and 32-bit destination address. 39 - - `Rpmsg.endpoint_info_codec` -- Wire codec for serializing and deserializing the endpoint info struct (40 bytes). 40 - - `Rpmsg.Ctrl` -- Control device handle (`/dev/rpmsg_ctrl*`). Create and destroy RPMsg endpoints via ioctl. 41 - - `Rpmsg.Endpoint` -- Message endpoint backed by Eio flows. Send and receive messages up to 496 bytes (512 minus the 16-byte virtio header). 61 + ### Endpoint messaging 62 + 63 + - `Rpmsg.Endpoint.of_source_sink ~source ~sink` -- wrap Eio flows. 64 + - `Rpmsg.Endpoint.send ep msg` 65 + - `Rpmsg.Endpoint.recv ep ~max_size` -- `None` on EOF. 66 + - `Rpmsg.Endpoint.close ep` 67 + - `Rpmsg.Endpoint.max_message_size` 68 + 69 + ### Control device (create / destroy endpoints) 70 + 71 + The control device (`/dev/rpmsg_ctrl*`) creates and destroys endpoints via 72 + ioctl. On macOS every call raises `Failure` (RPMsg does not exist outside 73 + Linux). 74 + 75 + - `Rpmsg.Ctrl.open_ ?index ()` -- open `/dev/rpmsg_ctrlN` (default `N=0`). 76 + - `Rpmsg.Ctrl.create_endpoint t ~name ~src ~dst` -- returns the 77 + `/dev/rpmsgN` index. 78 + - `Rpmsg.Ctrl.destroy_endpoint t ~name ~src ~dst` 79 + - `Rpmsg.Ctrl.close t` 80 + - `Rpmsg.Endpoint.open_ n` -- open `/dev/rpmsgN` by index, returning the 81 + raw fd. 82 + 83 + ### Wire format 84 + 85 + `Rpmsg.endpoint_info_codec : endpoint_info Wire.Codec.t` encodes the Linux 86 + kernel `struct rpmsg_endpoint_info` (name[32], src:u32, dst:u32 -- 40 87 + bytes) without manual C struct packing. 42 88 43 89 ## References 44 90
+4
dune
··· 1 1 (env 2 2 (dev 3 3 (flags :standard %{dune-warnings}))) 4 + 5 + (mdx 6 + (files README.md) 7 + (libraries rpmsg))
+2
dune-project
··· 1 1 (lang dune 3.21) 2 + (using mdx 0.4) 2 3 3 4 (name rpmsg) 4 5 ··· 20 21 (eio_main (>= 1.0)) 21 22 (fmt (>= 0.9)) 22 23 wire 24 + (mdx :with-test) 23 25 (alcotest :with-test)))
+1
rpmsg.opam
··· 14 14 "eio_main" {>= "1.0"} 15 15 "fmt" {>= "0.9"} 16 16 "wire" 17 + "mdx" {with-test} 17 18 "alcotest" {with-test} 18 19 "odoc" {with-doc} 19 20 ]