Part 1
요약·해설
Vector 수, 4MB/4,096byte 차이, 권한·크기·시작 순서와 crash 위험을 보존합니다.
2
4096 bytes
Trusted access only
Part 2
접을 수 있는 영어 원문 전체
영어 원문 전체 펼치기
F596ACEE057495A4170209927D38FB7282635F9295A30B7BE7AD5E7484985DD1
.. zephyr:code-sample:: ivshmem-doorbell
:name: IVSHMEM doorbell
:relevant-api: ivshmem
Use Inter-VM Shared Memory to exchange messages between two processes running on different
operating systems.
Overview
********
This sample shows how two processes on different operating systems can
communicate using ivshmem. This is a subset of the functionality provided by
OpenAMP.
Prerequisites
*************
QEMU needs to available.
ivshmem-server needs to be available and running. The server is available in
Zephyr SDK or pre-built in some distributions. Otherwise, it is available in
QEMU source tree.
ivshmem-client needs to be available as it is employed in this sample as an
external application. The same conditions of ivshmem-server applies to the
ivshmem-server, as it is also available via QEMU.
Building and Running
********************
Building ivshmem-doorbell is as follows:
qemu_cortex_a53
===============
.. zephyr-app-commands::
:zephyr-app: samples/drivers/virtualization/ivshmem/doorbell
:host-os: unix
:board: qemu_cortex_a53
:goals: run
:compact:
qemu_kvm_arm64
==============
.. zephyr-app-commands::
:zephyr-app: samples/drivers/virtualization/ivshmem/doorbell
:host-os: unix
:board: qemu_kvm_arm64
:goals: run
:compact:
qemu_x86_64
===========
.. zephyr-app-commands::
:zephyr-app: samples/drivers/virtualization/ivshmem/doorbell
:host-os: unix
:board: qemu_x86_64
:goals: run
:compact:
How to
******
.. note::
The ivshmem shared memory can be manipulated to crash QEMU and bring down
Zephyr. Check :ref:`ivshmem_doorbell_sample_security` section for more details.
.. note::
Due to limited RAM memory available in qemu_x86_64 dts, it is not possible
to use the default shared memory size of ivshmem (4MB) for this platform.
Steps to reproduce this sample:
#. Run ivshmem-server. For the ivshmem-server, both number of vectors and
shared memory size are decided at run-time (when the server is executed).
For Zephyr, the number of vectors and shared memory size of ivshmem are
decided at compile-time and run-time, respectively.
- (Arm64) Use vectors == 2 for the project configuration in this sample.
Here is an example:
.. code-block:: console
# n = number of vectors
$ sudo ivshmem-server -n 2
$ *** Example code, do not use in production ***
- (x86_64) The default shared memory size is bigger than the memory
available for x86_64. For the provided sample configuration:
.. code-block:: console
# n = number of vectors, l = shared memory size
$ sudo ivshmem-server -n 2 -l 4096
$ *** Example code, do not use in production ***
- (Optional) If vectors != 2, you need to change ivshmem driver
:kconfig:option:`CONFIG_IVSHMEM_MSI_X_VECTORS`.
#. Appropriately set ownership of :file:`/dev/shm/ivshmem` and
``/tmp/ivshmem_socket`` for your deployment scenario. For instance:
.. code-block:: console
# assumption: "ivshmem" group should be the only allowed to access ivshmem
$ sudo chgrp ivshmem /dev/shm/ivshmem
$ sudo chmod 060 /dev/shm/ivshmem
$ sudo chgrp ivshmem /tmp/ivshmem_socket
$ sudo chmod 060 /tmp/ivshmem_socket
$
#. Run Zephyr.
.. code-block:: console
$ west build -t run
-- west build: running target run
[0/1] To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: cortex-a53
*** Booting Zephyr OS build zephyr-v3.3.0-1649-g612f49da5dee ***
Use write_shared_memory.sh and ivshmem-client to send a message
#. Write a message in the shared memory. The shared memory size *must* be kept
the same as specified for ivshmem-server. This is the purpose of the
``write_shared_memory`` script; failing to respect the shared memory size
may lead to a QEMU crash. For instance:
- (Arm64) a simple "hello world" message (the script assumes the default
size of ivshmem-server):
.. code-block:: console
# ./write_shared_memory.sh -m "your message"
$ ./write_shared_memory.sh -m "hello world"
$
- (x86_64) a simple "hello world" message:
.. code-block:: console
# ./write_shared_memory.sh -m "your message" -s <size of shared memory>
# assumption: the user created ivshmem-server with size 4096
$ ./write_shared_memory.sh -m "hello world" -s 4096
$
5. Send an interrupt to the guest. Using ivshmem-client, for instance:
.. code-block:: console
# find out client id. In this execution, it is 0 (peer_id)
$ ivshmem-client
dump: dump peers (including us)
int <peer> <vector>: notify one vector on a peer
int <peer> all: notify all vectors of a peer
int all: notify all vectors of all peers (excepting us)
listen on server socket 3
cmd> dump
our_id = 1
vector 0 is enabled (fd=7)
vector 1 is enabled (fd=8)
peer_id = 0
vector 0 is enabled (fd=5)
vector 1 is enabled (fd=6)
cmd> int 0 0
#. The sample will print the text in the shared memory whenever an interrupt is
received (in any of the ivshmem-vectors). Example of output for arm64:
.. code-block:: console
$ west build -t run
-- west build: running target run
[0/1] To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: cortex-a53
*** Booting Zephyr OS build zephyr-v3.3.0-1649-g612f49da5dee ***
Use write_shared_memory.sh and ivshmem-client to send a message
received IRQ and full message: hello world
Known Issues
************
The guest application should be started before the host one, even though the
latter starts the communication. This is because it takes a while for the guest
to actually register the IRQ (needs to enable PCI, map PCI BARs, enable IRQ,
map callback). If the host is initialized first, the guest may lose the first
IRQ and the protocol will not work.
.. _ivshmem_doorbell_sample_security:
Security
********
This sample assumes that the shared memory region size is constant; therefore,
once the memory is set during PCI configuration, it should not be tampered
with. This is straight-forward if you are writing an application and uses
:c:func:`mmap`; however, using shell tools (like :command:`echo`) will treat
the shared memory as a file, and overwrite the shared memory size to the input
length.
One way to ensure proper consistency is: (i) restrict access to the shared
memory to trusted users; a rogue user with improper access can easily truncate
the memory size to zero, for example by using :command:`truncate`, and make QEMU
crash, as the application will attempt to read the initial, bigger, size; and
(ii) make sure writes always respect the shared memory region size.
Part 3
한국어 전문 번역
개요
이 sample은 서로 다른 operating system에서 실행되는 process 두 개가 IVSHMEM으로 통신하는 방법을 보여줍니다. OpenAMP가 제공하는 기능의 일부에 해당합니다.
사전 요구 사항
QEMU를 사용할 수 있어야 합니다.
ivshmem-server를 사용할 수 있고 실행 중이어야 합니다. Server는 Zephyr SDK에 포함되거나 일부 distribution에서 prebuilt 형태로 제공되며, 그렇지 않으면 QEMU source tree에서 구할 수 있습니다.
이 sample이 external application으로 사용하는 ivshmem-client도 필요합니다. ivshmem-server와 마찬가지로 QEMU를 통해 구할 수 있습니다.
Build와 실행
IVSHMEM doorbell은 다음 target별로 build합니다.
qemu_cortex_a53
west build -b qemu_cortex_a53 samples/drivers/virtualization/ivshmem/doorbell
west build -t run
qemu_kvm_arm64
west build -b qemu_kvm_arm64 samples/drivers/virtualization/ivshmem/doorbell
west build -t run
qemu_x86_64
west build -b qemu_x86_64 samples/drivers/virtualization/ivshmem/doorbell
west build -t run
실행 절차
주의: IVSHMEM shared memory를 조작하면 QEMU가 crash하고 Zephyr도 중단될 수 있습니다. 아래 보안 절을 반드시 확인하십시오.
qemu_x86_64 참고: DTS에서 사용할 수 있는 RAM이 제한되어 있으므로 이 platform에서는 IVSHMEM 기본 shared-memory 크기 4MB를 사용할 수 없습니다.
ivshmem-server를 실행합니다. Server의 vector 수와 shared-memory 크기는 server 실행 시점에 결정됩니다. Zephyr에서는 vector 수는 compile time에, shared-memory 크기는 runtime에 결정됩니다.Arm64에서는 이 sample project 설정에
vectors == 2를 사용합니다.# n = number of vectors $ sudo ivshmem-server -n 2 $ *** Example code, do not use in production ***x86_64에서는 기본 shared-memory 크기가 사용 가능한 memory보다 큽니다. 제공된 sample 설정은 4,096byte를 사용합니다.
# n = number of vectors, l = shared memory size $ sudo ivshmem-server -n 2 -l 4096 $ *** Example code, do not use in production ***선택 사항으로 vector 수가 2가 아니라면 IVSHMEM driver의
CONFIG_IVSHMEM_MSI_X_VECTORS를 변경해야 합니다.배포 환경에 맞춰
/dev/shm/ivshmem과/tmp/ivshmem_socket의 소유권과 권한을 올바르게 설정합니다. 다음 예제는ivshmemgroup만 접근하도록 허용합니다.# assumption: "ivshmem" group should be the only allowed to access ivshmem $ sudo chgrp ivshmem /dev/shm/ivshmem $ sudo chmod 060 /dev/shm/ivshmem $ sudo chgrp ivshmem /tmp/ivshmem_socket $ sudo chmod 060 /tmp/ivshmem_socket $Zephyr를 실행합니다.
$ west build -t run -- west build: running target run [0/1] To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: cortex-a53 *** Booting Zephyr OS build zephyr-v3.3.0-1649-g612f49da5dee *** Use write_shared_memory.sh and ivshmem-client to send a messageShared memory에 message를 씁니다. Shared-memory 크기는
ivshmem-server에 지정한 값과 반드시 같아야 합니다.write_shared_memoryscript가 이를 처리하며, 크기를 지키지 않으면 QEMU가 crash할 수 있습니다.Arm64에서 기본 ivshmem-server 크기를 사용하는 간단한
hello worldmessage 예제입니다.# ./write_shared_memory.sh -m "your message" $ ./write_shared_memory.sh -m "hello world" $x86_64에서 크기 4,096byte를 명시하는 예제입니다.
# ./write_shared_memory.sh -m "your message" -s <size of shared memory> # assumption: the user created ivshmem-server with size 4096 $ ./write_shared_memory.sh -m "hello world" -s 4096 $예를 들어
ivshmem-client를 사용해 guest에 interrupt를 보냅니다. 먼저 client ID를 확인합니다. 이 실행에서 대상peer_id는 0입니다.# find out client id. In this execution, it is 0 (peer_id) $ ivshmem-client dump: dump peers (including us) int <peer> <vector>: notify one vector on a peer int <peer> all: notify all vectors of a peer int all: notify all vectors of all peers (excepting us) listen on server socket 3 cmd> dump our_id = 1 vector 0 is enabled (fd=7) vector 1 is enabled (fd=8) peer_id = 0 vector 0 is enabled (fd=5) vector 1 is enabled (fd=6) cmd> int 0 0IVSHMEM vector 중 어느 하나에서든 interrupt를 받으면 sample은 shared memory의 text를 출력합니다. 다음은 Arm64 출력 예제입니다.
$ west build -t run -- west build: running target run [0/1] To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: cortex-a53 *** Booting Zephyr OS build zephyr-v3.3.0-1649-g612f49da5dee *** Use write_shared_memory.sh and ivshmem-client to send a message received IRQ and full message: hello world
알려진 문제
통신을 시작하는 쪽은 host지만 guest application을 host보다 먼저 시작해야 합니다. Guest가 IRQ를 실제로 등록하려면 PCI 활성화, PCI BAR mapping, IRQ 활성화와 callback mapping에 시간이 걸립니다. Host를 먼저 초기화하면 guest가 첫 IRQ를 잃어 protocol이 동작하지 않을 수 있습니다.
보안
이 sample은 shared-memory 영역 크기가 일정하다고 가정합니다. 따라서 PCI 설정 중 memory를 구성한 뒤에는 크기를 변조하면 안 됩니다. Application에서 mmap을 사용하면 비교적 명확하지만, echo 같은 shell tool은 shared memory를 file처럼 취급하여 입력 길이로 shared-memory 크기를 덮어씁니다.
일관성을 유지하려면 첫째, shared memory 접근을 신뢰할 수 있는 사용자로 제한해야 합니다. 부적절한 접근 권한을 가진 사용자는 truncate 등으로 크기를 0으로 줄일 수 있고, application이 원래의 더 큰 크기로 읽으려 할 때 QEMU가 crash합니다. 둘째, 모든 write가 shared-memory 영역 크기를 반드시 지키게 해야 합니다.
Source
출처
영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.