Skip to content

drivers: vhost: Add Xen-MMIO VIRTIO backend #91605

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
2 changes: 2 additions & 0 deletions drivers/xen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ zephyr_sources(hvm.c)
zephyr_sources(events.c)
zephyr_sources_ifdef(CONFIG_XEN_GRANT_TABLE gnttab.c)
zephyr_sources(memory.c)
zephyr_sources(sched.c)
zephyr_sources(dmop.c)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall comment for commit drivers: xen: add more hypercall wrapper:
I strongly suggest you to split this commit into 3 separate commits and add more description regarding how it will be used in further development. Also, I believe that sched.c and dmop.c should be guarded with separate CONFIG to have a possibility to disable it.


add_subdirectory_ifdef(CONFIG_XEN_DOM0 dom0)
157 changes: 157 additions & 0 deletions drivers/xen/dmop.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* Copyright 2025 TOKITA Hiroshi
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/sys/util.h>
#include <zephyr/xen/dmop.h>
#include <zephyr/arch/arm64/hypercall.h>

int dmop_create_ioreq_server(domid_t domid, uint8_t handle_bufioreq, ioservid_t *id)
{
struct xen_dm_op_buf bufs[1] = {0};
struct xen_dm_op dm_op = {0};
int err;

dm_op.op = XEN_DMOP_create_ioreq_server;
dm_op.u.create_ioreq_server.handle_bufioreq = handle_bufioreq;

set_xen_guest_handle(bufs[0].h, &dm_op);
bufs[0].size = sizeof(struct xen_dm_op);

err = HYPERVISOR_dm_op(domid, ARRAY_SIZE(bufs), bufs);
if (err) {
return err;
}

*id = dm_op.u.create_ioreq_server.id;

return 0;
}

int dmop_destroy_ioreq_server(domid_t domid, ioservid_t id)
{
struct xen_dm_op_buf bufs[1] = {0};
struct xen_dm_op dm_op = {0};
int err;

dm_op.op = XEN_DMOP_destroy_ioreq_server;
dm_op.u.destroy_ioreq_server.id = id;

set_xen_guest_handle(bufs[0].h, &dm_op);
bufs[0].size = sizeof(struct xen_dm_op);

err = HYPERVISOR_dm_op(domid, ARRAY_SIZE(bufs), bufs);
if (err) {
return err;
}

return 0;
}

int dmop_map_io_range_to_ioreq_server(domid_t domid, ioservid_t id, uint32_t type, uint64_t start,
uint64_t end)
{
struct xen_dm_op_buf bufs[1] = {0};
struct xen_dm_op dm_op = {0};
int err;

dm_op.op = XEN_DMOP_map_io_range_to_ioreq_server;
dm_op.u.map_io_range_to_ioreq_server.id = id;
dm_op.u.map_io_range_to_ioreq_server.type = type;
dm_op.u.map_io_range_to_ioreq_server.start = start;
dm_op.u.map_io_range_to_ioreq_server.end = end;

set_xen_guest_handle(bufs[0].h, &dm_op);
bufs[0].size = sizeof(struct xen_dm_op);

err = HYPERVISOR_dm_op(domid, ARRAY_SIZE(bufs), bufs);
if (err < 0) {
return err;
}

return 0;
}

int dmop_unmap_io_range_from_ioreq_server(domid_t domid, ioservid_t id, uint32_t type,
uint64_t start, uint64_t end)
{
struct xen_dm_op_buf bufs[1] = {0};
struct xen_dm_op dm_op = {0};
int err;

dm_op.op = XEN_DMOP_unmap_io_range_from_ioreq_server;
dm_op.u.unmap_io_range_from_ioreq_server.id = id;
dm_op.u.unmap_io_range_from_ioreq_server.type = type;
dm_op.u.unmap_io_range_from_ioreq_server.start = start;
dm_op.u.unmap_io_range_from_ioreq_server.end = end;

set_xen_guest_handle(bufs[0].h, &dm_op);
bufs[0].size = sizeof(struct xen_dm_op);

err = HYPERVISOR_dm_op(domid, ARRAY_SIZE(bufs), bufs);
if (err < 0) {
return err;
}

return 0;
}

int dmop_set_ioreq_server_state(domid_t domid, ioservid_t id, uint8_t enabled)
{
struct xen_dm_op_buf bufs[1] = {0};
struct xen_dm_op dm_op = {0};
int err;

dm_op.op = XEN_DMOP_set_ioreq_server_state;
dm_op.u.set_ioreq_server_state.id = id;
dm_op.u.set_ioreq_server_state.enabled = enabled;

set_xen_guest_handle(bufs[0].h, &dm_op);
bufs[0].size = sizeof(struct xen_dm_op);

err = HYPERVISOR_dm_op(domid, 1, bufs);
if (err) {
return err;
}

return 0;
}

int dmop_nr_vcpus(domid_t domid)
{
struct xen_dm_op_buf bufs[1] = {0};
struct xen_dm_op dm_op = {0};
int err;

dm_op.op = XEN_DMOP_nr_vcpus;

set_xen_guest_handle(bufs[0].h, &dm_op);
bufs[0].size = sizeof(struct xen_dm_op);

err = HYPERVISOR_dm_op(domid, 1, bufs);
if (err < 0) {
return err;
}

return dm_op.u.nr_vcpus.vcpus;
}

int dmop_set_irq_level(domid_t domid, uint32_t irq, uint8_t level)
{
struct xen_dm_op_buf bufs[1] = {0};
struct xen_dm_op dm_op = {0};
int err;

dm_op.op = XEN_DMOP_set_irq_level;
dm_op.u.set_irq_level.irq = irq;
dm_op.u.set_irq_level.level = level;

set_xen_guest_handle(bufs[0].h, &dm_op);
bufs[0].size = sizeof(struct xen_dm_op);

err = HYPERVISOR_dm_op(domid, 1, bufs);

return err;
}
22 changes: 22 additions & 0 deletions drivers/xen/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,25 @@ int xendom_populate_physmap(int domid, unsigned int extent_order,

return HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
}

int xendom_acquire_resource(domid_t domid, uint16_t type, uint32_t id, uint64_t frame,
uint32_t *nr_frames, xen_pfn_t *frame_list)
{
struct xen_mem_acquire_resource acquire_res = {
.domid = domid,
.type = type,
.id = id,
.pad = 0,
.frame = frame,
.nr_frames = *nr_frames,
};
int ret;

set_xen_guest_handle(acquire_res.frame_list, frame_list);

ret = HYPERVISOR_memory_op(XENMEM_acquire_resource, &acquire_res);

*nr_frames = acquire_res.nr_frames;

return ret;
}
19 changes: 19 additions & 0 deletions drivers/xen/sched.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2025 TOKITA Hiroshi
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/arch/arm64/hypercall.h>
#include <zephyr/xen/sched.h>

int sched_poll(evtchn_port_t *ports, unsigned int nr_ports, uint64_t timeout)
{
struct sched_poll poll = {
.ports.p = ports,
.nr_ports = 1,
.timeout = timeout,
};

return HYPERVISOR_sched_op(SCHEDOP_poll, &poll);
}
89 changes: 89 additions & 0 deletions include/zephyr/xen/dmop.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2025 TOKITA Hiroshi
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_XEN_DMOP_H_
#define ZEPHYR_XEN_DMOP_H_

#include <xen/public/hvm/dm_op.h>

/**
* @brief Create an I/O request server in the given Xen domain.
*
* This function issues the XEN_DMOP_create_ioreq_server hypercall to create
* a server that handles I/O requests on behalf of the guest domain.
*
* @param domid Xen domain identifier where the server is created.
* @param handle_bufioreq Flag indicating whether buffered I/O requests should be handled.
* Set to non-zero to enable buffered handling.
* @param id Output pointer to receive the newly created server ID.
*
* @return 0 on success, or a negative errno code on failure.
*/
int dmop_create_ioreq_server(domid_t domid, uint8_t handle_bufioreq, ioservid_t *id);

int dmop_destroy_ioreq_server(domid_t domid, ioservid_t id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for this one(as for dmop_unmap_io_range_from_ioreq_server)


/**
* @brief Map a specified I/O address range to an existing I/O request server.
*
* This function issues the XEN_DMOP_map_io_range_to_ioreq_server hypercall to grant
* access to the given I/O address range for the specified server.
*
* @param domid Xen domain identifier where the mapping is applied.
* @param id I/O request server ID returned by dmop_create_ioreq_server().
* @param type Type identifier for the I/O range (e.g., MMIO, port I/O).
* @param start Start physical address of the I/O range.
* @param end End physical address (inclusive) of the I/O range.
*
* @return 0 on success, or a negative errno code on failure.
*/
int dmop_map_io_range_to_ioreq_server(domid_t domid, ioservid_t id, uint32_t type, uint64_t start,
uint64_t end);

int dmop_unmap_io_range_from_ioreq_server(domid_t domid, ioservid_t id, uint32_t type,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one has missing documentation comment. I understand that this and previous are opposite to each other, but when docs will be generated it will look strange.

uint64_t start, uint64_t end);

/**
* @brief Enable or disable an existing I/O request server.
*
* This function issues the XEN_DMOP_set_ioreq_server_state hypercall to change
* the operational state of the specified I/O request server.
*
* @param domid Xen domain identifier.
* @param id I/O request server ID to modify.
* @param enabled Non-zero to enable the server, zero to disable it.
*
* @return 0 on success, or a negative errno code on failure.
*/
int dmop_set_ioreq_server_state(domid_t domid, ioservid_t id, uint8_t enabled);

/**
* @brief Query the number of virtual CPUs in a Xen domain.
*
* This function issues the XEN_DMOP_nr_vcpus hypercall to retrieve
* the current vCPU count for the specified domain.
*
* @param domid Xen domain identifier to query.
*
* @return The number of vCPUs on success, or a negative errno code on failure.
*/
int dmop_nr_vcpus(domid_t domid);

/**
* @brief Set the interrupt level for a specific IRQ in a Xen domain.
*
* This function issues the XEN_DMOP_set_irq_level hypercall to adjust
* the signal level (assert or deassert) for the given IRQ line.
*
* @param domid Xen domain identifier.
* @param irq IRQ number whose level is to be set.
* @param level Non-zero to assert (raise) the IRQ, zero to deassert (lower) it.
*
* @return 0 on success, or a negative errno code on failure.
*/
int dmop_set_irq_level(domid_t domid, uint32_t irq, uint8_t level);

#endif /* ZEPHYR_XEN_DMOP_H_ */
24 changes: 24 additions & 0 deletions include/zephyr/xen/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
* Copyright (c) 2023 EPAM Systems
*/

#ifndef ZEPHYR_XEN_MEMORY_H_
#define ZEPHYR_XEN_MEMORY_H_

#include <zephyr/kernel.h>
#include <xen/public/memory.h>
#include <xen/public/xen.h>
Expand Down Expand Up @@ -64,3 +67,24 @@ int xendom_remove_from_physmap(int domid, xen_pfn_t gpfn);
int xendom_populate_physmap(int domid, unsigned int extent_order,
unsigned int nr_extents, unsigned int mem_flags,
xen_pfn_t *extent_start);
/**
* @brief Acquire a resource mapping for the Xen domain.
*
* Issues the XENMEM_acquire_resource hypercall to map a resource buffer
* (e.g., I/O request server, grant table, VM trace buffer) into the
* specified domain's physmap, or query its total size.
*
* @param domid Target domain identifier. Use DOMID_SELF for the calling domain.
* @param type Resource type identifier (e.g., XENMEM_resource_ioreq_server).
* @param id Resource-specific identifier (e.g., server ID or table ID).
* @param frame Starting frame number for mapping, or ignored if *nr_frames == 0.
* @param nr_frames [in,out] On input, number of frames to map; on return,
* number of frames actually mapped (or total frames if queried).
* @param frame_list Guest frame list buffer: input GFNs for HVM guests,
* output MFNs for PV guests.
* @return Zero on success, or a negative errno code on failure.
*/
int xendom_acquire_resource(domid_t domid, uint16_t type, uint32_t id, uint64_t frame,
uint32_t *nr_frames, xen_pfn_t *frame_list);

#endif /* ZEPHYR_XEN_MEMORY_H_ */
24 changes: 24 additions & 0 deletions include/zephyr/xen/sched.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2025 TOKITA Hiroshi
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_XEN_SCHED_H_
#define ZEPHYR_XEN_SCHED_H_

#include <xen/public/sched.h>

/**
* @brief Poll one or more Xen event channels for activity.
*
* Issues the SCHEDOP_poll hypercall to wait for events on the specified ports.
*
* @param ports Array of event channel ports to poll.
* @param nr_ports Number of ports in the array.
* @param timeout Timeout in microseconds to wait for an event.
* @return 0 if an event occurred, -EAGAIN on timeout, or negative errno on error.
*/
int sched_poll(evtchn_port_t *ports, unsigned int nr_ports, uint64_t timeout);

#endif /* ZEPHYR_XEN_SCHED_H_ */