Skip to content

Commit d64559b

Browse files
committed
samples: drivers: virtualization: add vhost sample
Add vhost sample Signed-off-by: TOKITA Hiroshi <[email protected]>
1 parent aaa0377 commit d64559b

File tree

7 files changed

+175
-0
lines changed

7 files changed

+175
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
project(vhost)
7+
8+
target_sources(app PRIVATE src/main.c)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
.. zephyr:code-sample:: vhost
2+
:name: Vhost sample application
3+
4+
Overview
5+
********
6+
7+
A simple sample that can be used with any :ref:`supported board <boards>` and
8+
prints "Hello World" to the console.
9+
10+
Building and Running
11+
********************
12+
13+
This application can be built and executed on QEMU as follows:
14+
15+
.. zephyr-app-commands::
16+
:zephyr-app: samples/drivers/virtualization/vhost
17+
:host-os: unix
18+
:board: xenvm
19+
:goals: run
20+
:compact:
21+
22+
To build for another board, change "qemu_x86" above to that board's name.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Copyright (c) 2025 TOKITA Hiroshi
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/ {
8+
vhost: xen-vhost-mmio {
9+
compatible = "xen,vhost-mmio";
10+
device-id = <4>;
11+
vendor-id = <0x7a707972>; /* "zphy" */
12+
num-queues = <2>;
13+
queue-size-max= <16>;
14+
base = <0x2000000>;
15+
};
16+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
* Copyright (c) 2025 TOKITA Hiroshi
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "xenvm.overlay"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CONFIG_VHOST=y
2+
CONFIG_LOG=y
3+
CONFIG_HEAP_MEM_POOL_SIZE=1048576
4+
CONFIG_LOG_MODE_IMMEDIATE=y
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
sample:
2+
description: VHost sample application
3+
name: vhost
4+
common:
5+
integration_platforms:
6+
- xenvm
7+
harness: console
8+
harness_config:
9+
type: one_line
10+
regex:
11+
- "Hello World! (.*)"
12+
tests:
13+
sample.virtualization.vhost:
14+
tags: introduction
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright (c) 2025 TOKITA Hiroshi
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/drivers/vhost.h>
8+
#include <zephyr/drivers/vhost/vringh.h>
9+
#include <zephyr/logging/log.h>
10+
11+
LOG_MODULE_REGISTER(vhost);
12+
13+
struct vhost_iovec riovec[16];
14+
struct vhost_iovec wiovec[16];
15+
16+
struct vringh_iov riov = {
17+
.iov = riovec,
18+
.max_num = 16,
19+
};
20+
21+
struct vringh_iov wiov = {
22+
.iov = wiovec,
23+
.max_num = 16,
24+
};
25+
26+
struct vringh vrh_inst;
27+
28+
void vringh_handler(struct vringh *vrh)
29+
{
30+
LOG_DBG("%s: queue_id=%lu", __func__, vrh->queue_id);
31+
uint16_t head;
32+
33+
while (true) {
34+
int ret = vringh_getdesc(vrh, &riov, &wiov, &head);
35+
36+
if (ret < 0) {
37+
LOG_ERR("vringh_getdesc failed: %d", ret);
38+
return;
39+
}
40+
41+
if (ret == 0) {
42+
return;
43+
}
44+
45+
/* Process writable iovecs */
46+
for (uint32_t s = 0; s < wiov.used; s++) {
47+
uint8_t *dst = wiov.iov[s].iov_base;
48+
uint32_t len = wiov.iov[s].iov_len;
49+
50+
LOG_DBG("%s: addr=%p len=%u", __func__, dst, len);
51+
52+
for (uint32_t i = 0; i < len; i++) {
53+
sys_write8(i, (mem_addr_t)&dst[i]);
54+
}
55+
}
56+
57+
barrier_dmem_fence_full();
58+
59+
uint32_t total_len = 0;
60+
for (uint32_t i = 0; i < wiov.used; i++) {
61+
total_len += wiov.iov[i].iov_len;
62+
}
63+
64+
vringh_complete(vrh, head, total_len);
65+
66+
if (vringh_need_notify(vrh) > 0) {
67+
vringh_notify(vrh);
68+
}
69+
70+
/* Reset iovecs for next iteration */
71+
vringh_iov_reset(&riov);
72+
vringh_iov_reset(&wiov);
73+
}
74+
}
75+
76+
void queue_ready_handler(const struct device *dev, uint16_t qid, void *data)
77+
{
78+
LOG_DBG("%s(dev=%p, qid=%u, data=%p)", __func__, dev, qid, data);
79+
80+
/* Initialize iovecs before descriptor processing */
81+
vringh_iov_init(&riov, riov.iov, riov.max_num);
82+
vringh_iov_init(&wiov, wiov.iov, wiov.max_num);
83+
84+
int err = vringh_init_device(&vrh_inst, dev, qid, vringh_handler);
85+
if (err) {
86+
LOG_ERR("vringh_init_device failed: %d", err);
87+
return;
88+
}
89+
}
90+
91+
int main(void)
92+
{
93+
const struct device *device = DEVICE_DT_GET(DT_NODELABEL(vhost));
94+
95+
if (!device_is_ready(device)) {
96+
LOG_ERR("VHost device not ready");
97+
return -ENODEV;
98+
}
99+
100+
vhost_set_ready_callback(device, queue_ready_handler, (void *)device);
101+
102+
k_sleep(K_FOREVER);
103+
return 0;
104+
}

0 commit comments

Comments
 (0)