debuggers.hg

view tools/ioemu/hw/xen_console.c @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children 5c0bf00e371d
line source
1 /*
2 * Copyright (C) International Business Machines Corp., 2005
3 * Author(s): Anthony Liguori <aliguori@us.ibm.com>
4 *
5 * Copyright (C) Red Hat 2007
6 *
7 * Xen Console
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; under version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
23 #include <malloc.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <sys/select.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <termios.h>
31 #include <stdarg.h>
32 #include <sys/mman.h>
33 #include <xs.h>
34 #include <xen/io/console.h>
35 #include <xenctrl.h>
37 #include "vl.h"
39 #include "xen_console.h"
41 #define dolog(val, fmt, ...) fprintf(stderr, fmt "\n", ## __VA_ARGS__)
43 struct buffer
44 {
45 uint8_t *data;
46 size_t consumed;
47 size_t size;
48 size_t capacity;
49 size_t max_capacity;
50 };
52 struct domain
53 {
54 int domid;
55 struct buffer buffer;
57 char *conspath;
58 char *serialpath;
59 int use_consolepath;
60 int ring_ref;
61 evtchn_port_t local_port;
62 evtchn_port_t remote_port;
63 int xce_handle;
64 struct xs_handle *xsh;
65 struct xencons_interface *interface;
66 CharDriverState *chr;
67 };
70 static void buffer_append(struct domain *dom)
71 {
72 struct buffer *buffer = &dom->buffer;
73 XENCONS_RING_IDX cons, prod, size;
74 struct xencons_interface *intf = dom->interface;
76 cons = intf->out_cons;
77 prod = intf->out_prod;
78 xen_mb();
80 size = prod - cons;
81 if ((size == 0) || (size > sizeof(intf->out)))
82 return;
84 if ((buffer->capacity - buffer->size) < size) {
85 buffer->capacity += (size + 1024);
86 buffer->data = realloc(buffer->data, buffer->capacity);
87 if (buffer->data == NULL) {
88 dolog(LOG_ERR, "Memory allocation failed");
89 exit(ENOMEM);
90 }
91 }
93 while (cons != prod)
94 buffer->data[buffer->size++] = intf->out[
95 MASK_XENCONS_IDX(cons++, intf->out)];
97 xen_mb();
98 intf->out_cons = cons;
99 xc_evtchn_notify(dom->xce_handle, dom->local_port);
101 if (buffer->max_capacity &&
102 buffer->size > buffer->max_capacity) {
103 /* Discard the middle of the data. */
105 size_t over = buffer->size - buffer->max_capacity;
106 uint8_t *maxpos = buffer->data + buffer->max_capacity;
108 memmove(maxpos - over, maxpos, over);
109 buffer->data = realloc(buffer->data, buffer->max_capacity);
110 buffer->size = buffer->capacity = buffer->max_capacity;
112 if (buffer->consumed > buffer->max_capacity - over)
113 buffer->consumed = buffer->max_capacity - over;
114 }
115 }
117 static void buffer_advance(struct buffer *buffer, size_t len)
118 {
119 buffer->consumed += len;
120 if (buffer->consumed == buffer->size) {
121 buffer->consumed = 0;
122 buffer->size = 0;
123 }
124 }
126 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
127 int xs_gather(struct xs_handle *xs, const char *dir, ...)
128 {
129 va_list ap;
130 const char *name;
131 char *path;
132 int ret = 0;
134 va_start(ap, dir);
135 while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
136 const char *fmt = va_arg(ap, char *);
137 void *result = va_arg(ap, void *);
138 char *p;
140 if (asprintf(&path, "%s/%s", dir, name) == -1) {
141 ret = ENOMEM;
142 break;
143 }
144 p = xs_read(xs, XBT_NULL, path, NULL);
145 free(path);
146 if (p == NULL) {
147 ret = ENOENT;
148 break;
149 }
150 if (fmt) {
151 if (sscanf(p, fmt, result) == 0)
152 ret = EINVAL;
153 free(p);
154 } else
155 *(char **)result = p;
156 }
157 va_end(ap);
158 return ret;
159 }
161 static int domain_create_ring(struct domain *dom)
162 {
163 int err, remote_port, ring_ref, rc;
165 err = xs_gather(dom->xsh, dom->serialpath,
166 "ring-ref", "%u", &ring_ref,
167 "port", "%i", &remote_port,
168 NULL);
169 if (err) {
170 err = xs_gather(dom->xsh, dom->conspath,
171 "ring-ref", "%u", &ring_ref,
172 "port", "%i", &remote_port,
173 NULL);
174 if (err) {
175 fprintf(stderr, "Console: failed to find ring-ref/port yet\n");
176 goto out;
177 }
178 dom->use_consolepath = 1;
179 } else
180 dom->use_consolepath = 0;
181 fprintf(stderr, "Console: got ring-ref %d port %d\n", ring_ref, remote_port);
183 if ((ring_ref == dom->ring_ref) && (remote_port == dom->remote_port))
184 goto out;
186 if (ring_ref != dom->ring_ref) {
187 if (dom->interface != NULL)
188 munmap(dom->interface, getpagesize());
189 dom->interface = xc_map_foreign_range(
190 xc_handle, dom->domid, getpagesize(),
191 PROT_READ|PROT_WRITE,
192 (unsigned long)ring_ref);
193 if (dom->interface == NULL) {
194 err = errno;
195 goto out;
196 }
197 dom->ring_ref = ring_ref;
198 }
200 dom->local_port = -1;
201 dom->remote_port = -1;
203 dom->xce_handle = xc_evtchn_open();
204 if (dom->xce_handle == -1) {
205 err = errno;
206 goto out;
207 }
209 rc = xc_evtchn_bind_interdomain(dom->xce_handle,
210 dom->domid, remote_port);
212 if (rc == -1) {
213 err = errno;
214 xc_evtchn_close(dom->xce_handle);
215 dom->xce_handle = -1;
216 goto out;
217 }
218 dom->local_port = rc;
219 dom->remote_port = remote_port;
221 out:
222 return err;
223 }
226 static struct domain *create_domain(int domid, CharDriverState *chr)
227 {
228 struct domain *dom;
229 char *s;
231 dom = (struct domain *)malloc(sizeof(struct domain));
232 if (dom == NULL) {
233 dolog(LOG_ERR, "Out of memory %s:%s():L%d",
234 __FILE__, __FUNCTION__, __LINE__);
235 exit(ENOMEM);
236 }
238 dom->domid = domid;
239 dom->chr = chr;
241 dom->xsh = xs_daemon_open();
242 if (dom->xsh == NULL) {
243 fprintf(logfile, "Could not contact xenstore for console watch\n");
244 goto out;
245 }
247 dom->serialpath = xs_get_domain_path(dom->xsh, dom->domid);
248 s = realloc(dom->serialpath, strlen(dom->serialpath) +
249 strlen("/serial/0") + 1);
250 if (s == NULL)
251 goto out;
252 dom->serialpath = s;
253 strcat(dom->serialpath, "/serial/0");
255 dom->conspath = xs_get_domain_path(dom->xsh, dom->domid);
256 s = realloc(dom->conspath, strlen(dom->conspath) +
257 strlen("/console") + 1);
258 if (s == NULL)
259 goto out;
260 dom->conspath = s;
261 strcat(dom->conspath, "/console");
263 dom->buffer.data = 0;
264 dom->buffer.consumed = 0;
265 dom->buffer.size = 0;
266 dom->buffer.capacity = 0;
267 dom->buffer.max_capacity = 0;
269 dom->ring_ref = -1;
270 dom->local_port = -1;
271 dom->remote_port = -1;
272 dom->interface = NULL;
273 dom->xce_handle = -1;
276 return dom;
277 out:
278 free(dom->serialpath);
279 free(dom->conspath);
280 free(dom);
281 return NULL;
282 }
285 static int ring_free_bytes(struct domain *dom)
286 {
287 struct xencons_interface *intf = dom->interface;
288 XENCONS_RING_IDX cons, prod, space;
290 cons = intf->in_cons;
291 prod = intf->in_prod;
292 xen_mb();
294 space = prod - cons;
295 if (space > sizeof(intf->in))
296 return 0; /* ring is screwed: ignore it */
298 return (sizeof(intf->in) - space);
299 }
301 static int xencons_can_receive(void *opaque)
302 {
303 struct domain *dom = (struct domain *)opaque;
305 return ring_free_bytes(dom);
306 }
308 static void xencons_receive(void *opaque, const uint8_t *buf, int len)
309 {
310 struct domain *dom = (struct domain *)opaque;
311 int i, max;
312 struct xencons_interface *intf = dom->interface;
313 XENCONS_RING_IDX prod;
315 max = ring_free_bytes(dom);
316 /* The can_receive() func limits this, but check again anyway */
317 if (max < len)
318 len = max;
320 prod = intf->in_prod;
321 for (i = 0; i < len; i++) {
322 intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
323 buf[i];
324 }
325 xen_wmb();
326 intf->in_prod = prod;
327 xc_evtchn_notify(dom->xce_handle, dom->local_port);
328 }
330 static void xencons_send(struct domain *dom)
331 {
332 ssize_t len;
333 len = qemu_chr_write(dom->chr, dom->buffer.data + dom->buffer.consumed,
334 dom->buffer.size - dom->buffer.consumed);
335 if (len < 1) {
336 /*
337 * Disable log because if we're redirecting to /dev/pts/N we
338 * don't want to flood logs when no client has the PTY open
339 */
340 /*
341 dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n",
342 dom->domid, len, errno);
343 */
344 } else {
345 buffer_advance(&dom->buffer, len);
346 }
347 }
349 static void xencons_ring_read(void *opaque)
350 {
351 evtchn_port_t port;
352 struct domain *dom = (struct domain *)opaque;
354 if ((port = xc_evtchn_pending(dom->xce_handle)) == -1)
355 return;
357 buffer_append(dom);
359 (void)xc_evtchn_unmask(dom->xce_handle, port);
361 if (dom->buffer.size - dom->buffer.consumed)
362 xencons_send(dom);
363 }
365 static void xencons_startup(void *opaque)
366 {
367 struct domain *dom = (struct domain *)opaque;
368 unsigned dummy;
369 char **vec;
370 int err;
371 vec = xs_read_watch(dom->xsh, &dummy);
372 if (vec)
373 free(vec);
374 fprintf(stderr, "Console: got watch\n");
375 err = domain_create_ring(dom);
376 if (err)
377 return;
379 xs_unwatch(dom->xsh, dom->conspath, "");
380 xs_unwatch(dom->xsh, dom->serialpath, "");
381 qemu_set_fd_handler2(xs_fileno(dom->xsh), NULL, NULL, NULL, NULL);
383 fprintf(stderr, "Console: connected to guest frontend\n");
384 if (qemu_set_fd_handler2(xc_evtchn_fd(dom->xce_handle), NULL, xencons_ring_read, NULL, dom) < 0)
385 return;
387 qemu_chr_add_handlers(dom->chr, xencons_can_receive, xencons_receive,
388 NULL, dom);
389 }
392 int xencons_init(int domid, CharDriverState *chr)
393 {
394 struct domain *dom = create_domain(domid, chr);
396 if (!dom)
397 return -1;
399 /* Setup watches so we asynchronously connect to serial console */
400 if (!(xs_watch(dom->xsh, dom->conspath, ""))) {
401 fprintf(stderr, "Unable to watch console %s\n", dom->conspath);
402 goto fail;
403 }
404 if (!(xs_watch(dom->xsh, dom->serialpath, ""))) {
405 fprintf(stderr, "Unable to watch console %s\n", dom->conspath);
406 xs_unwatch(dom->xsh, dom->conspath, "");
407 goto fail;
408 }
409 qemu_set_fd_handler2(xs_fileno(dom->xsh), NULL, xencons_startup, NULL, dom);
410 fprintf(stderr, "Console: prepared domain, waiting for ringref at %s or %s\n",
411 dom->conspath, dom->serialpath);
413 return 0;
415 fail:
416 xs_daemon_close(dom->xsh);
417 free(dom->serialpath);
418 free(dom->conspath);
419 free(dom);
420 return -1;
421 }
424 /*
425 * Local variables:
426 * c-file-style: "linux"
427 * indent-tabs-mode: t
428 * c-indent-level: 8
429 * c-basic-offset: 8
430 * tab-width: 8
431 * End:
432 */