Skip to content

Commit c2e448b

Browse files
committed
drivers: xen: add basic XenStore access features
Add functions for accessing XenStore. Currently not support write feature. Signed-off-by: TOKITA Hiroshi <[email protected]>
1 parent 546de70 commit c2e448b

File tree

3 files changed

+390
-0
lines changed

3 files changed

+390
-0
lines changed

drivers/xen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ zephyr_sources_ifdef(CONFIG_XEN_GRANT_TABLE gnttab.c)
77
zephyr_sources(memory.c)
88
zephyr_sources(sched.c)
99
zephyr_sources(dmop.c)
10+
zephyr_sources(xenstore.c)
1011

1112
add_subdirectory_ifdef(CONFIG_XEN_DOM0 dom0)

drivers/xen/xenstore.c

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
/*
2+
* Copyright (c) 2023 EPAM Systems
3+
* Copyright (c) 2025 TOKITA Hiroshi
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#include <stdint.h>
9+
10+
#include <xen/public/io/xs_wire.h>
11+
12+
#include <zephyr/xen/generic.h>
13+
#include <zephyr/xen/hvm.h>
14+
#include <zephyr/xen/sched.h>
15+
#include <zephyr/xen/events.h>
16+
#include <zephyr/xen/xenstore.h>
17+
#include <zephyr/sys/device_mmio.h>
18+
#include <sys/types.h>
19+
20+
#include <zephyr/logging/log.h>
21+
22+
/*
23+
* Importing and modifying code from the following source.
24+
* https://github.com/xen-troops/zephyr-xenlib/blob/v3.1.0/xenstore-srv/src/xenstore_srv.c
25+
*
26+
* The queues used are swapped because the read and write directions for xenstore are different.
27+
*/
28+
29+
static bool check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
30+
{
31+
return ((prod - cons) > XENSTORE_RING_SIZE);
32+
}
33+
34+
static size_t get_input_offset(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, size_t *len)
35+
{
36+
size_t delta = prod - cons;
37+
*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
38+
39+
if (delta < *len) {
40+
*len = delta;
41+
}
42+
43+
return MASK_XENSTORE_IDX(cons);
44+
}
45+
46+
static size_t get_output_offset(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, size_t *len)
47+
{
48+
size_t free_space = XENSTORE_RING_SIZE - (prod - cons);
49+
50+
*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
51+
if (free_space < *len) {
52+
*len = free_space;
53+
}
54+
55+
return MASK_XENSTORE_IDX(prod);
56+
}
57+
58+
static int ring_write(struct xenstore *xenstore, const void *data, size_t len)
59+
{
60+
size_t avail;
61+
void *dest;
62+
struct xenstore_domain_interface *intf = xenstore->domint;
63+
XENSTORE_RING_IDX cons, prod;
64+
65+
cons = intf->req_cons;
66+
prod = intf->req_prod;
67+
z_barrier_dmem_fence_full();
68+
69+
if (check_indexes(cons, prod)) {
70+
return -EINVAL;
71+
}
72+
73+
dest = intf->req + get_output_offset(cons, prod, &avail);
74+
if (avail < len) {
75+
len = avail;
76+
}
77+
78+
memcpy(dest, data, len);
79+
z_barrier_dmem_fence_full();
80+
intf->req_prod += len;
81+
82+
notify_evtchn(xenstore->local_evtchn);
83+
84+
return len;
85+
}
86+
87+
static int ring_read(struct xenstore *xenstore, void *data, size_t len)
88+
{
89+
size_t avail;
90+
const void *src;
91+
struct xenstore_domain_interface *intf = xenstore->domint;
92+
XENSTORE_RING_IDX cons, prod;
93+
94+
cons = intf->rsp_cons;
95+
prod = intf->rsp_prod;
96+
z_barrier_dmem_fence_full();
97+
98+
if (check_indexes(cons, prod)) {
99+
return -EIO;
100+
}
101+
102+
src = intf->rsp + get_input_offset(cons, prod, &avail);
103+
if (avail < len) {
104+
len = avail;
105+
}
106+
107+
if (data) {
108+
memcpy(data, src, len);
109+
}
110+
111+
z_barrier_dmem_fence_full();
112+
intf->rsp_cons += len;
113+
114+
notify_evtchn(xenstore->local_evtchn);
115+
116+
return len;
117+
}
118+
119+
/*
120+
* End importing.
121+
*/
122+
123+
LOG_MODULE_REGISTER(xen_xenstore);
124+
125+
static atomic_t next_req_id;
126+
static struct k_sem xs_lock;
127+
128+
static uint8_t read_buf[XENSTORE_RING_SIZE * 2];
129+
static size_t read_pos;
130+
static int expected_req_id;
131+
132+
static xs_notify_cb notify_cb;
133+
static void *notify_param;
134+
135+
static inline size_t ring_avail_for_read(struct xenstore *xenstore)
136+
{
137+
struct xenstore_domain_interface *intf = xenstore->domint;
138+
XENSTORE_RING_IDX cons, prod;
139+
140+
cons = intf->rsp_cons;
141+
prod = intf->rsp_prod;
142+
143+
return prod - cons;
144+
}
145+
146+
static void store_cb(void *ptr)
147+
{
148+
while (ring_avail_for_read(ptr)) {
149+
int ret = ring_read(ptr, read_buf + read_pos, ring_avail_for_read(ptr));
150+
if (ret < 0) {
151+
break;
152+
}
153+
read_pos += ret;
154+
}
155+
156+
if (read_pos >= sizeof(struct xsd_sockmsg)) {
157+
struct xsd_sockmsg *hdr = (void *)read_buf;
158+
159+
while (read_pos >= (hdr->len + sizeof(struct xsd_sockmsg))) {
160+
if (hdr->req_id == expected_req_id) {
161+
k_sem_give(&xs_lock);
162+
} else {
163+
if (notify_cb) {
164+
notify_cb(read_buf, read_pos, notify_param);
165+
}
166+
}
167+
read_pos -= (hdr->len + sizeof(struct xsd_sockmsg));
168+
}
169+
}
170+
}
171+
172+
static int xs_rw_common(struct xenstore *xenstore, int type, const char **params, size_t param_num,
173+
char *buf, size_t len, uint32_t *preq_id)
174+
{
175+
size_t plen = 0;
176+
int err;
177+
178+
for (int i = 0; i < param_num; i++) {
179+
plen += strlen(params[i]) + 1;
180+
}
181+
182+
if (plen > XENSTORE_PAYLOAD_MAX) {
183+
LOG_ERR("strlen(path) + 1: %ld > XENSTORE_PAYLOAD_MAX", plen);
184+
return -ENAMETOOLONG;
185+
}
186+
187+
*preq_id = atomic_inc(&next_req_id);
188+
if (*preq_id == 0) {
189+
*preq_id = atomic_inc(&next_req_id);
190+
}
191+
192+
struct xsd_sockmsg hdr = {
193+
.type = type,
194+
.req_id = *preq_id,
195+
.tx_id = 0,
196+
.len = plen,
197+
};
198+
199+
err = ring_write(xenstore, &hdr, sizeof(struct xsd_sockmsg));
200+
if (err < 0) {
201+
LOG_ERR("ring_write(hdr) failed: %d", err);
202+
return -EAGAIN;
203+
}
204+
205+
for (int i = 0; i < param_num; i++) {
206+
err = ring_write(xenstore, params[i], strlen(params[i]) + 1);
207+
if (err < 0) {
208+
LOG_ERR("ring_write(path) failed: %d", err);
209+
return -EAGAIN;
210+
}
211+
}
212+
213+
return 0;
214+
}
215+
216+
static ssize_t xs_r(struct xenstore *xenstore, int type, const char **params, size_t params_num,
217+
char *buf, size_t len, k_timeout_t timeout)
218+
{
219+
ssize_t copy_len = 0;
220+
int err;
221+
struct xsd_sockmsg *hdr;
222+
223+
err = xs_rw_common(xenstore, type, params, params_num, buf, len, &expected_req_id);
224+
if (err < 0) {
225+
LOG_ERR("xs_rw_common error: %d", err);
226+
return -EIO;
227+
}
228+
229+
k_sem_take(&xs_lock, timeout);
230+
231+
hdr = (void *)read_buf;
232+
233+
if (hdr->len > len) {
234+
LOG_ERR("no buffer hdr.len=%d > len=%ld)", hdr->len, len);
235+
err = -ENOBUFS;
236+
goto end;
237+
}
238+
239+
copy_len = (len - 1 < hdr->len) ? len - 1 : hdr->len;
240+
memcpy(buf, read_buf + sizeof(struct xsd_sockmsg), copy_len);
241+
read_pos = 0;
242+
243+
buf[copy_len] = '\0';
244+
245+
end:
246+
if (err) {
247+
return err;
248+
}
249+
250+
return copy_len;
251+
}
252+
253+
int xs_init_xenstore(struct xenstore *xenstore)
254+
{
255+
uint64_t paddr = 0;
256+
uint64_t value = 0;
257+
mm_reg_t vaddr = 0;
258+
int err;
259+
260+
k_sem_init(&xs_lock, 0, 1);
261+
262+
err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, DOMID_SELF, &value);
263+
if (err) {
264+
LOG_ERR("hvm_get_parameter(STORE_EVTCHN) failed: %d", err);
265+
return -ENODEV;
266+
}
267+
xenstore->local_evtchn = value;
268+
269+
err = hvm_get_parameter(HVM_PARAM_STORE_PFN, DOMID_SELF, &paddr);
270+
if (err) {
271+
LOG_ERR("hvm_get_param(STORE_PFN) failed: err=%d", err);
272+
return -EIO;
273+
}
274+
device_map(&vaddr, XEN_PFN_PHYS(paddr), XEN_PAGE_SIZE, K_MEM_CACHE_WB | K_MEM_PERM_RW);
275+
276+
xenstore->domint = (struct xenstore_domain_interface *)vaddr;
277+
278+
ring_read(xenstore, NULL, -1);
279+
280+
bind_event_channel(xenstore->local_evtchn, store_cb, xenstore);
281+
unmask_event_channel(xenstore->local_evtchn);
282+
283+
return 0;
284+
}
285+
286+
void xs_set_notify_callback(xs_notify_cb cb, void *param)
287+
{
288+
notify_cb = cb;
289+
notify_param = param;
290+
}
291+
292+
ssize_t xs_read(struct xenstore *xenstore, const char *path, char *buf, size_t len)
293+
{
294+
const char *params[] = {path};
295+
296+
return xs_r(xenstore, XS_READ, params, 1, buf, len, K_FOREVER);
297+
}
298+
299+
ssize_t xs_directory(struct xenstore *xenstore, const char *path, char *buf, size_t len)
300+
{
301+
const char *params[] = {path};
302+
303+
return xs_r(xenstore, XS_DIRECTORY, params, 1, buf, len, K_FOREVER);
304+
}
305+
306+
ssize_t xs_watch(struct xenstore *xenstore, const char *path, const char *token, char *buf,
307+
size_t len)
308+
{
309+
const char *params[] = {path, token};
310+
311+
return xs_r(xenstore, XS_WATCH, params, 2, buf, len, K_FOREVER);
312+
}

include/zephyr/xen/xenstore.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2025 TOKITA Hiroshi
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_XEN_XENSTORE_H_
8+
#define ZEPHYR_XEN_XENSTORE_H_
9+
10+
#include <sys/types.h>
11+
12+
struct buffered_data {
13+
/* Used to link buffers into singly-linked list */
14+
sys_snode_t node;
15+
/* The number of bytes that was processed for read/write */
16+
size_t used;
17+
/* The total size of message header and payload */
18+
size_t total_size;
19+
/* Buffer with header and payload */
20+
uint8_t *buffer;
21+
};
22+
23+
struct xenstore {
24+
sys_slist_t out_list;
25+
struct buffered_data *in;
26+
/* Count the number of used out buffers to prevent Denial of Service attacks */
27+
int used_out_bufs;
28+
struct xenstore_domain_interface *domint;
29+
struct xen_domain *domain;
30+
struct k_sem xb_sem;
31+
struct k_thread thrd;
32+
atomic_t thrd_stop;
33+
evtchn_port_t remote_evtchn;
34+
evtchn_port_t local_evtchn;
35+
size_t xs_stack_slot;
36+
int transaction;
37+
int running_transaction;
38+
int stop_transaction_id;
39+
bool pending_stop_transaction;
40+
};
41+
42+
typedef void (*xs_notify_cb)(char *buf, size_t len, void *param);
43+
44+
/**
45+
* @brief Read the value of a Xenstore path entry.
46+
*
47+
* Sends a read request to the Xenstore service and retrieves the
48+
* value at the specified path.
49+
*
50+
* @param path Null-terminated Xenstore path string.
51+
* @param buf Buffer to receive the returned value.
52+
* @param len Maximum buffer length.
53+
* @return Number of bytes read (excluding terminating null), or negative errno on error.
54+
*/
55+
ssize_t xs_read(struct xenstore *xs, const char *path, char *buf, size_t len);
56+
57+
/**
58+
* @brief List the entries in a Xenstore directory.
59+
*
60+
* Sends a directory request to the Xenstore service and populates
61+
* the buffer with a whitespace-separated list of entries.
62+
*
63+
* @param path Null-terminated Xenstore directory path string.
64+
* @param buf Buffer to receive the directory listing.
65+
* @param len Maximum buffer length.
66+
* @return Number of bytes written (excluding terminating null), or negative errno on
67+
* error.
68+
*/
69+
ssize_t xs_directory(struct xenstore *xs, const char *path, char *buf, size_t len);
70+
71+
ssize_t xs_watch(struct xenstore *xs, const char *path, const char *token, char *buf, size_t len);
72+
73+
void xs_set_notify_callback(xs_notify_cb cb, void *param);
74+
75+
int xs_init_xenstore(struct xenstore *xs);
76+
77+
#endif /* ZEPHYR_XEN_XENSTORE_H_ */

0 commit comments

Comments
 (0)