1.. zephyr:code-sample:: ivshmem-doorbell
2   :name: IVSHMEM doorbell
3   :relevant-api: ivshmem
4
5   Use Inter-VM Shared Memory to exchange messages between two processes running on different
6   operating systems.
7
8Overview
9********
10
11This sample shows how two processes on different operating systems can
12communicate using ivshmem. This is a subset of the functionality provided by
13OpenAMP.
14
15Prerequisites
16*************
17
18QEMU needs to available.
19
20ivshmem-server needs to be available and running. The server is available in
21Zephyr SDK or pre-built in some distributions. Otherwise, it is available in
22QEMU source tree.
23
24ivshmem-client needs to be available as it is employed in this sample as an
25external application. The same conditions of ivshmem-server applies to the
26ivshmem-server, as it is also available via QEMU.
27
28Building and Running
29********************
30
31Building ivshmem-doorbell is as follows:
32
33qemu_cortex_a53
34===============
35
36.. zephyr-app-commands::
37   :zephyr-app: samples/drivers/virtualization/ivshmem/doorbell
38   :host-os: unix
39   :board: qemu_cortex_a53
40   :goals: run
41   :compact:
42
43qemu_kvm_arm64
44==============
45
46.. zephyr-app-commands::
47   :zephyr-app: samples/drivers/virtualization/ivshmem/doorbell
48   :host-os: unix
49   :board: qemu_kvm_arm64
50   :goals: run
51   :compact:
52
53qemu_x86_64
54===========
55
56.. zephyr-app-commands::
57   :zephyr-app: samples/drivers/virtualization/ivshmem/doorbell
58   :host-os: unix
59   :board: qemu_x86_64
60   :goals: run
61   :compact:
62
63How to
64******
65
66.. note::
67
68   The ivshmem shared memory can be manipulated to crash QEMU and bring down
69   Zephyr. Check :ref:`ivshmem_doorbell_sample_security` section for more details.
70
71.. note::
72
73   Due to limited RAM memory available in qemu_x86_64 dts, it is not possible
74   to use the default shared memory size of ivshmem (4MB) for this platform.
75
76Steps to reproduce this sample:
77
78#. Run ivshmem-server. For the ivshmem-server, both number of vectors and
79   shared memory size are decided at run-time (when the server is executed).
80   For Zephyr, the number of vectors and shared memory size of ivshmem are
81   decided at compile-time and run-time, respectively.
82
83   - (Arm64) Use vectors == 2 for the project configuration in this sample.
84     Here is an example:
85
86     .. code-block:: console
87
88        # n = number of vectors
89        $ sudo ivshmem-server -n 2
90        $ *** Example code, do not use in production ***
91
92   - (x86_64) The default shared memory size is bigger than the memory
93     available for x86_64. For the provided sample configuration:
94
95     .. code-block:: console
96
97        # n = number of vectors, l = shared memory size
98        $ sudo ivshmem-server -n 2 -l 4096
99        $ *** Example code, do not use in production ***
100
101   - (Optional) If vectors != 2, you need to change ivshmem driver
102     :kconfig:option:`CONFIG_IVSHMEM_MSI_X_VECTORS`.
103
104#. Appropriately set ownership of :file:`/dev/shm/ivshmem` and
105   ``/tmp/ivshmem_socket`` for your deployment scenario. For instance:
106
107   .. code-block:: console
108
109      # assumption: "ivshmem" group should be the only allowed to access ivshmem
110      $ sudo chgrp ivshmem /dev/shm/ivshmem
111      $ sudo chmod 060 /dev/shm/ivshmem
112      $ sudo chgrp ivshmem /tmp/ivshmem_socket
113      $ sudo chmod 060 /tmp/ivshmem_socket
114      $
115
116#. Run Zephyr.
117
118   .. code-block:: console
119
120      $ west build -t run
121      -- west build: running target run
122      [0/1] To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: cortex-a53
123      *** Booting Zephyr OS build zephyr-v3.3.0-1649-g612f49da5dee ***
124      Use write_shared_memory.sh and ivshmem-client to send a message
125
126#. Write a message in the shared memory. The shared memory size *must* be kept
127   the same as specified for ivshmem-server. This is the purpose of the
128   ``write_shared_memory`` script; failing to respect the shared memory size
129   may lead to a QEMU crash. For instance:
130
131   - (Arm64) a simple "hello world" message (the script assumes the default
132     size of ivshmem-server):
133
134     .. code-block:: console
135
136        # ./write_shared_memory.sh -m "your message"
137        $ ./write_shared_memory.sh -m "hello world"
138        $
139
140   - (x86_64) a simple "hello world" message:
141
142     .. code-block:: console
143
144        # ./write_shared_memory.sh -m "your message" -s <size of shared memory>
145        # assumption: the user created ivshmem-server with size 4096
146        $ ./write_shared_memory.sh -m "hello world" -s 4096
147        $
148
1495. Send an interrupt to the guest. Using ivshmem-client, for instance:
150
151   .. code-block:: console
152
153      # find out client id. In this execution, it is 0 (peer_id)
154      $ ivshmem-client
155      dump: dump peers (including us)
156      int <peer> <vector>: notify one vector on a peer
157      int <peer> all: notify all vectors of a peer
158      int all: notify all vectors of all peers (excepting us)
159      listen on server socket 3
160      cmd> dump
161      our_id = 1
162      vector 0 is enabled (fd=7)
163      vector 1 is enabled (fd=8)
164      peer_id = 0
165      vector 0 is enabled (fd=5)
166      vector 1 is enabled (fd=6)
167      cmd> int 0 0
168
169#. The sample will print the text in the shared memory whenever an interrupt is
170   received (in any of the ivshmem-vectors). Example of output for arm64:
171
172   .. code-block:: console
173
174      $ west build -t run
175      -- west build: running target run
176      [0/1] To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: cortex-a53
177      *** Booting Zephyr OS build zephyr-v3.3.0-1649-g612f49da5dee ***
178      Use write_shared_memory.sh and ivshmem-client to send a message
179      received IRQ and full message: hello world
180
181Known Issues
182************
183
184The guest application should be started before the host one, even though the
185latter starts the communication. This is because it takes a while for the guest
186to actually register the IRQ (needs to enable PCI, map PCI BARs, enable IRQ,
187map callback). If the host is initialized first, the guest may lose the first
188IRQ and the protocol will not work.
189
190.. _ivshmem_doorbell_sample_security:
191
192Security
193********
194
195This sample assumes that the shared memory region size is constant; therefore,
196once the memory is set during PCI configuration, it should not be tampered
197with. This is straight-forward if you are writing an application and uses
198:c:func:`mmap`; however, using shell tools (like :command:`echo`) will treat
199the shared memory as a file, and overwrite the shared memory size to the input
200length.
201
202One way to ensure proper consistency is: (i) restrict access to the shared
203memory to trusted users; a rogue user with improper access can easily truncate
204the memory size to zero, for example by using :command:`truncate`, and make QEMU
205crash, as the application will attempt to read the initial, bigger, size; and
206(ii) make sure writes always respect the shared memory region size.
207