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