xref: /openbmc/qemu/hw/xen/xen_pvdev.c (revision c5ea91da443b458352c1b629b490ee6631775cb4)
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