xref: /openbmc/qemu/hw/xen/xen_pvdev.c (revision c5ea91da443b458352c1b629b490ee6631775cb4)
1  /*
2   * Xen para-virtualization device
3   *
4   *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
5   *
6   * This library is free software; you can redistribute it and/or
7   * modify it under the terms of the GNU Lesser General Public
8   * License as published by the Free Software Foundation; either
9   * version 2.1 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public
17   * License along with this library; if not, see <http://www.gnu.org/licenses/>
18   */
19  
20  #include "qemu/osdep.h"
21  #include "qemu/log.h"
22  #include "qemu/main-loop.h"
23  #include "hw/qdev-core.h"
24  #include "hw/xen/xen-legacy-backend.h"
25  #include "hw/xen/xen_pvdev.h"
26  
27  /* private */
28  static int debug;
29  
30  struct xs_dirs {
31      char *xs_dir;
32      QTAILQ_ENTRY(xs_dirs) list;
33  };
34  
35  static QTAILQ_HEAD(, xs_dirs) xs_cleanup =
36      QTAILQ_HEAD_INITIALIZER(xs_cleanup);
37  
38  static QTAILQ_HEAD(, XenLegacyDevice) xendevs =
39      QTAILQ_HEAD_INITIALIZER(xendevs);
40  
41  /* ------------------------------------------------------------- */
42  
xenstore_cleanup_dir(char * dir)43  static void xenstore_cleanup_dir(char *dir)
44  {
45      struct xs_dirs *d;
46  
47      d = g_malloc(sizeof(*d));
48      d->xs_dir = dir;
49      QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
50  }
51  
xen_config_cleanup(void)52  void xen_config_cleanup(void)
53  {
54      struct xs_dirs *d;
55  
56      QTAILQ_FOREACH(d, &xs_cleanup, list) {
57          qemu_xen_xs_destroy(xenstore, 0, d->xs_dir);
58      }
59  }
60  
xenstore_mkdir(char * path,int p)61  int xenstore_mkdir(char *path, int p)
62  {
63      if (!qemu_xen_xs_create(xenstore, 0, 0, xen_domid, p, path)) {
64          xen_pv_printf(NULL, 0, "xs_mkdir %s: failed\n", path);
65          return -1;
66      }
67      xenstore_cleanup_dir(g_strdup(path));
68      return 0;
69  }
70  
xenstore_write_str(const char * base,const char * node,const char * val)71  int xenstore_write_str(const char *base, const char *node, const char *val)
72  {
73      char abspath[XEN_BUFSIZE];
74  
75      snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
76      if (!qemu_xen_xs_write(xenstore, 0, abspath, val, strlen(val))) {
77          return -1;
78      }
79      return 0;
80  }
81  
xenstore_read_str(const char * base,const char * node)82  char *xenstore_read_str(const char *base, const char *node)
83  {
84      char abspath[XEN_BUFSIZE];
85      unsigned int len;
86      char *str, *ret = NULL;
87  
88      snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
89      str = qemu_xen_xs_read(xenstore, 0, abspath, &len);
90      if (str != NULL) {
91          /* move to qemu-allocated memory to make sure
92           * callers can safely g_free() stuff. */
93          ret = g_strdup(str);
94          free(str);
95      }
96      return ret;
97  }
98  
xenstore_write_int(const char * base,const char * node,int ival)99  int xenstore_write_int(const char *base, const char *node, int ival)
100  {
101      char val[12];
102  
103      snprintf(val, sizeof(val), "%d", ival);
104      return xenstore_write_str(base, node, val);
105  }
106  
xenstore_write_int64(const char * base,const char * node,int64_t ival)107  int xenstore_write_int64(const char *base, const char *node, int64_t ival)
108  {
109      char val[21];
110  
111      snprintf(val, sizeof(val), "%"PRId64, ival);
112      return xenstore_write_str(base, node, val);
113  }
114  
xenstore_read_int(const char * base,const char * node,int * ival)115  int xenstore_read_int(const char *base, const char *node, int *ival)
116  {
117      char *val;
118      int rc = -1;
119  
120      val = xenstore_read_str(base, node);
121      if (val && 1 == sscanf(val, "%d", ival)) {
122          rc = 0;
123      }
124      g_free(val);
125      return rc;
126  }
127  
xenstore_read_uint64(const char * base,const char * node,uint64_t * uval)128  int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
129  {
130      char *val;
131      int rc = -1;
132  
133      val = xenstore_read_str(base, node);
134      if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
135          rc = 0;
136      }
137      g_free(val);
138      return rc;
139  }
140  
xenbus_strstate(enum xenbus_state state)141  const char *xenbus_strstate(enum xenbus_state state)
142  {
143      static const char *const name[] = {
144          [XenbusStateUnknown]       = "Unknown",
145          [XenbusStateInitialising]  = "Initialising",
146          [XenbusStateInitWait]      = "InitWait",
147          [XenbusStateInitialised]   = "Initialised",
148          [XenbusStateConnected]     = "Connected",
149          [XenbusStateClosing]       = "Closing",
150          [XenbusStateClosed]        = "Closed",
151      };
152      return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
153  }
154  
155  /*
156   * msg_level:
157   *  0 == errors (stderr + logfile).
158   *  1 == informative debug messages (logfile only).
159   *  2 == noisy debug messages (logfile only).
160   *  3 == will flood your log (logfile only).
161   */
162  G_GNUC_PRINTF(3, 0)
xen_pv_output_msg(struct XenLegacyDevice * xendev,FILE * f,const char * fmt,va_list args)163  static void xen_pv_output_msg(struct XenLegacyDevice *xendev,
164                                FILE *f, const char *fmt, va_list args)
165  {
166      if (xendev) {
167          fprintf(f, "xen be: %s: ", xendev->name);
168      } else {
169          fprintf(f, "xen be core: ");
170      }
171      vfprintf(f, fmt, args);
172  }
173  
xen_pv_printf(struct XenLegacyDevice * xendev,int msg_level,const char * fmt,...)174  void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level,
175                     const char *fmt, ...)
176  {
177      FILE *logfile;
178      va_list args;
179  
180      if (msg_level > (xendev ? xendev->debug : debug)) {
181          return;
182      }
183  
184      logfile = qemu_log_trylock();
185      if (logfile) {
186          va_start(args, fmt);
187          xen_pv_output_msg(xendev, logfile, fmt, args);
188          va_end(args);
189          qemu_log_unlock(logfile);
190      }
191  
192      if (msg_level == 0) {
193          va_start(args, fmt);
194          xen_pv_output_msg(xendev, stderr, fmt, args);
195          va_end(args);
196      }
197  }
198  
xen_pv_evtchn_event(void * opaque)199  void xen_pv_evtchn_event(void *opaque)
200  {
201      struct XenLegacyDevice *xendev = opaque;
202      evtchn_port_t port;
203  
204      port = qemu_xen_evtchn_pending(xendev->evtchndev);
205      if (port != xendev->local_port) {
206          xen_pv_printf(xendev, 0,
207                        "xenevtchn_pending returned %d (expected %d)\n",
208                        port, xendev->local_port);
209          return;
210      }
211      qemu_xen_evtchn_unmask(xendev->evtchndev, port);
212  
213      if (xendev->ops->event) {
214          xendev->ops->event(xendev);
215      }
216  }
217  
xen_pv_unbind_evtchn(struct XenLegacyDevice * xendev)218  void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev)
219  {
220      if (xendev->local_port == -1) {
221          return;
222      }
223      qemu_set_fd_handler(qemu_xen_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
224      qemu_xen_evtchn_unbind(xendev->evtchndev, xendev->local_port);
225      xen_pv_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
226      xendev->local_port = -1;
227  }
228  
xen_pv_send_notify(struct XenLegacyDevice * xendev)229  int xen_pv_send_notify(struct XenLegacyDevice *xendev)
230  {
231      return qemu_xen_evtchn_notify(xendev->evtchndev, xendev->local_port);
232  }
233  
234  /* ------------------------------------------------------------- */
235  
xen_pv_find_xendev(const char * type,int dom,int dev)236  struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
237  {
238      struct XenLegacyDevice *xendev;
239  
240      QTAILQ_FOREACH(xendev, &xendevs, next) {
241          if (xendev->dom != dom) {
242              continue;
243          }
244          if (xendev->dev != dev) {
245              continue;
246          }
247          if (strcmp(xendev->type, type) != 0) {
248              continue;
249          }
250          return xendev;
251      }
252      return NULL;
253  }
254  
255  /*
256   * release xen backend device.
257   */
xen_pv_del_xendev(struct XenLegacyDevice * xendev)258  void xen_pv_del_xendev(struct XenLegacyDevice *xendev)
259  {
260      if (xendev->ops->free) {
261          xendev->ops->free(xendev);
262      }
263  
264      if (xendev->fe) {
265          qemu_xen_xs_unwatch(xenstore, xendev->watch);
266          g_free(xendev->fe);
267      }
268  
269      if (xendev->evtchndev != NULL) {
270          qemu_xen_evtchn_close(xendev->evtchndev);
271      }
272      if (xendev->gnttabdev != NULL) {
273          qemu_xen_gnttab_close(xendev->gnttabdev);
274      }
275  
276      QTAILQ_REMOVE(&xendevs, xendev, next);
277  
278      qdev_unplug(&xendev->qdev, NULL);
279  }
280  
xen_pv_insert_xendev(struct XenLegacyDevice * xendev)281  void xen_pv_insert_xendev(struct XenLegacyDevice *xendev)
282  {
283      QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
284  }
285