1f0021dbaSEmil Condrea /*
2f0021dbaSEmil Condrea * Xen para-virtualization device
3f0021dbaSEmil Condrea *
4f0021dbaSEmil Condrea * (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
5f0021dbaSEmil Condrea *
6f0021dbaSEmil Condrea * This library is free software; you can redistribute it and/or
7f0021dbaSEmil Condrea * modify it under the terms of the GNU Lesser General Public
8f0021dbaSEmil Condrea * License as published by the Free Software Foundation; either
961f3c91aSChetan Pant * version 2.1 of the License, or (at your option) any later version.
10f0021dbaSEmil Condrea *
11f0021dbaSEmil Condrea * This library is distributed in the hope that it will be useful,
12f0021dbaSEmil Condrea * but WITHOUT ANY WARRANTY; without even the implied warranty of
13f0021dbaSEmil Condrea * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14f0021dbaSEmil Condrea * Lesser General Public License for more details.
15f0021dbaSEmil Condrea *
16f0021dbaSEmil Condrea * You should have received a copy of the GNU Lesser General Public
17f0021dbaSEmil Condrea * License along with this library; if not, see <http://www.gnu.org/licenses/>
18f0021dbaSEmil Condrea */
19f0021dbaSEmil Condrea
20f0021dbaSEmil Condrea #include "qemu/osdep.h"
21b5863634SThomas Huth #include "qemu/log.h"
22db725815SMarkus Armbruster #include "qemu/main-loop.h"
233a6c9172SJuergen Gross #include "hw/qdev-core.h"
242d0ed5e6SPaul Durrant #include "hw/xen/xen-legacy-backend.h"
25f0021dbaSEmil Condrea #include "hw/xen/xen_pvdev.h"
26f0021dbaSEmil Condrea
27148512e0SEmil Condrea /* private */
28f0021dbaSEmil Condrea static int debug;
29ecf79818SEmil Condrea
30ecf79818SEmil Condrea struct xs_dirs {
31ecf79818SEmil Condrea char *xs_dir;
32ecf79818SEmil Condrea QTAILQ_ENTRY(xs_dirs) list;
33ecf79818SEmil Condrea };
34ecf79818SEmil Condrea
35b58deb34SPaolo Bonzini static QTAILQ_HEAD(, xs_dirs) xs_cleanup =
36ecf79818SEmil Condrea QTAILQ_HEAD_INITIALIZER(xs_cleanup);
37ecf79818SEmil Condrea
382d0ed5e6SPaul Durrant static QTAILQ_HEAD(, XenLegacyDevice) xendevs =
39148512e0SEmil Condrea QTAILQ_HEAD_INITIALIZER(xendevs);
40148512e0SEmil Condrea
41f0021dbaSEmil Condrea /* ------------------------------------------------------------- */
42f0021dbaSEmil Condrea
xenstore_cleanup_dir(char * dir)43ecf79818SEmil Condrea static void xenstore_cleanup_dir(char *dir)
44ecf79818SEmil Condrea {
45ecf79818SEmil Condrea struct xs_dirs *d;
46ecf79818SEmil Condrea
47ecf79818SEmil Condrea d = g_malloc(sizeof(*d));
48ecf79818SEmil Condrea d->xs_dir = dir;
49ecf79818SEmil Condrea QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
50ecf79818SEmil Condrea }
51ecf79818SEmil Condrea
xen_config_cleanup(void)52ecf79818SEmil Condrea void xen_config_cleanup(void)
53ecf79818SEmil Condrea {
54ecf79818SEmil Condrea struct xs_dirs *d;
55ecf79818SEmil Condrea
56ecf79818SEmil Condrea QTAILQ_FOREACH(d, &xs_cleanup, list) {
57ba2a92dbSPaul Durrant qemu_xen_xs_destroy(xenstore, 0, d->xs_dir);
58ecf79818SEmil Condrea }
59ecf79818SEmil Condrea }
60ecf79818SEmil Condrea
xenstore_mkdir(char * path,int p)61ecf79818SEmil Condrea int xenstore_mkdir(char *path, int p)
62ecf79818SEmil Condrea {
63ba2a92dbSPaul Durrant if (!qemu_xen_xs_create(xenstore, 0, 0, xen_domid, p, path)) {
6496c77dbaSEmil Condrea xen_pv_printf(NULL, 0, "xs_mkdir %s: failed\n", path);
65ecf79818SEmil Condrea return -1;
66ecf79818SEmil Condrea }
67ecf79818SEmil Condrea xenstore_cleanup_dir(g_strdup(path));
68ecf79818SEmil Condrea return 0;
69ecf79818SEmil Condrea }
70ecf79818SEmil Condrea
xenstore_write_str(const char * base,const char * node,const char * val)71f0021dbaSEmil Condrea int xenstore_write_str(const char *base, const char *node, const char *val)
72f0021dbaSEmil Condrea {
73f0021dbaSEmil Condrea char abspath[XEN_BUFSIZE];
74f0021dbaSEmil Condrea
75f0021dbaSEmil Condrea snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
76ba2a92dbSPaul Durrant if (!qemu_xen_xs_write(xenstore, 0, abspath, val, strlen(val))) {
77f0021dbaSEmil Condrea return -1;
78f0021dbaSEmil Condrea }
79f0021dbaSEmil Condrea return 0;
80f0021dbaSEmil Condrea }
81f0021dbaSEmil Condrea
xenstore_read_str(const char * base,const char * node)82f0021dbaSEmil Condrea char *xenstore_read_str(const char *base, const char *node)
83f0021dbaSEmil Condrea {
84f0021dbaSEmil Condrea char abspath[XEN_BUFSIZE];
85f0021dbaSEmil Condrea unsigned int len;
86f0021dbaSEmil Condrea char *str, *ret = NULL;
87f0021dbaSEmil Condrea
88f0021dbaSEmil Condrea snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
89ba2a92dbSPaul Durrant str = qemu_xen_xs_read(xenstore, 0, abspath, &len);
90f0021dbaSEmil Condrea if (str != NULL) {
91f0021dbaSEmil Condrea /* move to qemu-allocated memory to make sure
92*54abe918SMichael Tokarev * callers can safely g_free() stuff. */
93f0021dbaSEmil Condrea ret = g_strdup(str);
94f0021dbaSEmil Condrea free(str);
95f0021dbaSEmil Condrea }
96f0021dbaSEmil Condrea return ret;
97f0021dbaSEmil Condrea }
98f0021dbaSEmil Condrea
xenstore_write_int(const char * base,const char * node,int ival)99f0021dbaSEmil Condrea int xenstore_write_int(const char *base, const char *node, int ival)
100f0021dbaSEmil Condrea {
101f0021dbaSEmil Condrea char val[12];
102f0021dbaSEmil Condrea
103f0021dbaSEmil Condrea snprintf(val, sizeof(val), "%d", ival);
104f0021dbaSEmil Condrea return xenstore_write_str(base, node, val);
105f0021dbaSEmil Condrea }
106f0021dbaSEmil Condrea
xenstore_write_int64(const char * base,const char * node,int64_t ival)107f0021dbaSEmil Condrea int xenstore_write_int64(const char *base, const char *node, int64_t ival)
108f0021dbaSEmil Condrea {
109f0021dbaSEmil Condrea char val[21];
110f0021dbaSEmil Condrea
111f0021dbaSEmil Condrea snprintf(val, sizeof(val), "%"PRId64, ival);
112f0021dbaSEmil Condrea return xenstore_write_str(base, node, val);
113f0021dbaSEmil Condrea }
114f0021dbaSEmil Condrea
xenstore_read_int(const char * base,const char * node,int * ival)115f0021dbaSEmil Condrea int xenstore_read_int(const char *base, const char *node, int *ival)
116f0021dbaSEmil Condrea {
117f0021dbaSEmil Condrea char *val;
118f0021dbaSEmil Condrea int rc = -1;
119f0021dbaSEmil Condrea
120f0021dbaSEmil Condrea val = xenstore_read_str(base, node);
121f0021dbaSEmil Condrea if (val && 1 == sscanf(val, "%d", ival)) {
122f0021dbaSEmil Condrea rc = 0;
123f0021dbaSEmil Condrea }
124f0021dbaSEmil Condrea g_free(val);
125f0021dbaSEmil Condrea return rc;
126f0021dbaSEmil Condrea }
127f0021dbaSEmil Condrea
xenstore_read_uint64(const char * base,const char * node,uint64_t * uval)128f0021dbaSEmil Condrea int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
129f0021dbaSEmil Condrea {
130f0021dbaSEmil Condrea char *val;
131f0021dbaSEmil Condrea int rc = -1;
132f0021dbaSEmil Condrea
133f0021dbaSEmil Condrea val = xenstore_read_str(base, node);
134f0021dbaSEmil Condrea if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
135f0021dbaSEmil Condrea rc = 0;
136f0021dbaSEmil Condrea }
137f0021dbaSEmil Condrea g_free(val);
138f0021dbaSEmil Condrea return rc;
139f0021dbaSEmil Condrea }
140f0021dbaSEmil Condrea
xenbus_strstate(enum xenbus_state state)141f0021dbaSEmil Condrea const char *xenbus_strstate(enum xenbus_state state)
142f0021dbaSEmil Condrea {
143f0021dbaSEmil Condrea static const char *const name[] = {
144f0021dbaSEmil Condrea [XenbusStateUnknown] = "Unknown",
145f0021dbaSEmil Condrea [XenbusStateInitialising] = "Initialising",
146f0021dbaSEmil Condrea [XenbusStateInitWait] = "InitWait",
147f0021dbaSEmil Condrea [XenbusStateInitialised] = "Initialised",
148f0021dbaSEmil Condrea [XenbusStateConnected] = "Connected",
149f0021dbaSEmil Condrea [XenbusStateClosing] = "Closing",
150f0021dbaSEmil Condrea [XenbusStateClosed] = "Closed",
151f0021dbaSEmil Condrea };
152f0021dbaSEmil Condrea return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
153f0021dbaSEmil Condrea }
154f0021dbaSEmil Condrea
155f0021dbaSEmil Condrea /*
156f0021dbaSEmil Condrea * msg_level:
157f0021dbaSEmil Condrea * 0 == errors (stderr + logfile).
158f0021dbaSEmil Condrea * 1 == informative debug messages (logfile only).
159f0021dbaSEmil Condrea * 2 == noisy debug messages (logfile only).
160f0021dbaSEmil Condrea * 3 == will flood your log (logfile only).
161f0021dbaSEmil Condrea */
162d62449daSDaniel P. Berrangé G_GNUC_PRINTF(3, 0)
xen_pv_output_msg(struct XenLegacyDevice * xendev,FILE * f,const char * fmt,va_list args)1636fef2229SRichard Henderson static void xen_pv_output_msg(struct XenLegacyDevice *xendev,
1646fef2229SRichard Henderson FILE *f, const char *fmt, va_list args)
1656fef2229SRichard Henderson {
1666fef2229SRichard Henderson if (xendev) {
1676fef2229SRichard Henderson fprintf(f, "xen be: %s: ", xendev->name);
1686fef2229SRichard Henderson } else {
1696fef2229SRichard Henderson fprintf(f, "xen be core: ");
1706fef2229SRichard Henderson }
1716fef2229SRichard Henderson vfprintf(f, fmt, args);
1726fef2229SRichard Henderson }
1736fef2229SRichard Henderson
xen_pv_printf(struct XenLegacyDevice * xendev,int msg_level,const char * fmt,...)1742d0ed5e6SPaul Durrant void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level,
175f0021dbaSEmil Condrea const char *fmt, ...)
176f0021dbaSEmil Condrea {
1776fef2229SRichard Henderson FILE *logfile;
178f0021dbaSEmil Condrea va_list args;
179f0021dbaSEmil Condrea
1806fef2229SRichard Henderson if (msg_level > (xendev ? xendev->debug : debug)) {
181f0021dbaSEmil Condrea return;
182f0021dbaSEmil Condrea }
1836fef2229SRichard Henderson
1846fef2229SRichard Henderson logfile = qemu_log_trylock();
1856fef2229SRichard Henderson if (logfile) {
186f0021dbaSEmil Condrea va_start(args, fmt);
1876fef2229SRichard Henderson xen_pv_output_msg(xendev, logfile, fmt, args);
188f0021dbaSEmil Condrea va_end(args);
1896fef2229SRichard Henderson qemu_log_unlock(logfile);
1906fef2229SRichard Henderson }
1916fef2229SRichard Henderson
192f0021dbaSEmil Condrea if (msg_level == 0) {
193f0021dbaSEmil Condrea va_start(args, fmt);
1946fef2229SRichard Henderson xen_pv_output_msg(xendev, stderr, fmt, args);
195f0021dbaSEmil Condrea va_end(args);
196f0021dbaSEmil Condrea }
197f0021dbaSEmil Condrea }
19831c17aa5SEmil Condrea
xen_pv_evtchn_event(void * opaque)19949442d96SEmil Condrea void xen_pv_evtchn_event(void *opaque)
20031c17aa5SEmil Condrea {
2012d0ed5e6SPaul Durrant struct XenLegacyDevice *xendev = opaque;
20231c17aa5SEmil Condrea evtchn_port_t port;
20331c17aa5SEmil Condrea
204b6cacfeaSDavid Woodhouse port = qemu_xen_evtchn_pending(xendev->evtchndev);
20531c17aa5SEmil Condrea if (port != xendev->local_port) {
20696c77dbaSEmil Condrea xen_pv_printf(xendev, 0,
20731c17aa5SEmil Condrea "xenevtchn_pending returned %d (expected %d)\n",
20831c17aa5SEmil Condrea port, xendev->local_port);
20931c17aa5SEmil Condrea return;
21031c17aa5SEmil Condrea }
211b6cacfeaSDavid Woodhouse qemu_xen_evtchn_unmask(xendev->evtchndev, port);
21231c17aa5SEmil Condrea
21331c17aa5SEmil Condrea if (xendev->ops->event) {
21431c17aa5SEmil Condrea xendev->ops->event(xendev);
21531c17aa5SEmil Condrea }
21631c17aa5SEmil Condrea }
21731c17aa5SEmil Condrea
xen_pv_unbind_evtchn(struct XenLegacyDevice * xendev)2182d0ed5e6SPaul Durrant void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev)
21931c17aa5SEmil Condrea {
22031c17aa5SEmil Condrea if (xendev->local_port == -1) {
22131c17aa5SEmil Condrea return;
22231c17aa5SEmil Condrea }
223b6cacfeaSDavid Woodhouse qemu_set_fd_handler(qemu_xen_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
224b6cacfeaSDavid Woodhouse qemu_xen_evtchn_unbind(xendev->evtchndev, xendev->local_port);
22596c77dbaSEmil Condrea xen_pv_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
22631c17aa5SEmil Condrea xendev->local_port = -1;
22731c17aa5SEmil Condrea }
22831c17aa5SEmil Condrea
xen_pv_send_notify(struct XenLegacyDevice * xendev)2292d0ed5e6SPaul Durrant int xen_pv_send_notify(struct XenLegacyDevice *xendev)
23031c17aa5SEmil Condrea {
231b6cacfeaSDavid Woodhouse return qemu_xen_evtchn_notify(xendev->evtchndev, xendev->local_port);
23231c17aa5SEmil Condrea }
233148512e0SEmil Condrea
234148512e0SEmil Condrea /* ------------------------------------------------------------- */
235148512e0SEmil Condrea
xen_pv_find_xendev(const char * type,int dom,int dev)2362d0ed5e6SPaul Durrant struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
237148512e0SEmil Condrea {
2382d0ed5e6SPaul Durrant struct XenLegacyDevice *xendev;
239148512e0SEmil Condrea
240148512e0SEmil Condrea QTAILQ_FOREACH(xendev, &xendevs, next) {
241148512e0SEmil Condrea if (xendev->dom != dom) {
242148512e0SEmil Condrea continue;
243148512e0SEmil Condrea }
244148512e0SEmil Condrea if (xendev->dev != dev) {
245148512e0SEmil Condrea continue;
246148512e0SEmil Condrea }
247148512e0SEmil Condrea if (strcmp(xendev->type, type) != 0) {
248148512e0SEmil Condrea continue;
249148512e0SEmil Condrea }
250148512e0SEmil Condrea return xendev;
251148512e0SEmil Condrea }
252148512e0SEmil Condrea return NULL;
253148512e0SEmil Condrea }
254148512e0SEmil Condrea
255148512e0SEmil Condrea /*
256148512e0SEmil Condrea * release xen backend device.
257148512e0SEmil Condrea */
xen_pv_del_xendev(struct XenLegacyDevice * xendev)2582d0ed5e6SPaul Durrant void xen_pv_del_xendev(struct XenLegacyDevice *xendev)
259148512e0SEmil Condrea {
260148512e0SEmil Condrea if (xendev->ops->free) {
261148512e0SEmil Condrea xendev->ops->free(xendev);
262148512e0SEmil Condrea }
263148512e0SEmil Condrea
264148512e0SEmil Condrea if (xendev->fe) {
265ba2a92dbSPaul Durrant qemu_xen_xs_unwatch(xenstore, xendev->watch);
266148512e0SEmil Condrea g_free(xendev->fe);
267148512e0SEmil Condrea }
268148512e0SEmil Condrea
269148512e0SEmil Condrea if (xendev->evtchndev != NULL) {
270b6cacfeaSDavid Woodhouse qemu_xen_evtchn_close(xendev->evtchndev);
271148512e0SEmil Condrea }
272148512e0SEmil Condrea if (xendev->gnttabdev != NULL) {
273c412ba47SDavid Woodhouse qemu_xen_gnttab_close(xendev->gnttabdev);
274148512e0SEmil Condrea }
275148512e0SEmil Condrea
276148512e0SEmil Condrea QTAILQ_REMOVE(&xendevs, xendev, next);
2773a6c9172SJuergen Gross
2783a6c9172SJuergen Gross qdev_unplug(&xendev->qdev, NULL);
279148512e0SEmil Condrea }
280148512e0SEmil Condrea
xen_pv_insert_xendev(struct XenLegacyDevice * xendev)2812d0ed5e6SPaul Durrant void xen_pv_insert_xendev(struct XenLegacyDevice *xendev)
282148512e0SEmil Condrea {
283148512e0SEmil Condrea QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
284148512e0SEmil Condrea }
285