| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  Copyright (C) International Business Machines  Corp., 2005 | 
					
						
							|  |  |  |  *  Author(s): Anthony Liguori <aliguori@us.ibm.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Copyright (C) Red Hat 2007 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Xen Console | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  *  it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  *  the Free Software Foundation; under version 2 of the License. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  *  GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  You should have received a copy of the GNU General Public License along | 
					
						
							| 
									
										
										
										
											2009-07-16 20:47:01 +00:00
										 |  |  |  *  with this program; if not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:17:06 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | #include <sys/select.h>
 | 
					
						
							|  |  |  | #include <termios.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-22 12:52:55 +03:00
										 |  |  | #include "qapi/error.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:57 +02:00
										 |  |  | #include "sysemu/sysemu.h"
 | 
					
						
							| 
									
										
										
										
											2017-01-26 18:26:44 +04:00
										 |  |  | #include "chardev/char-fe.h"
 | 
					
						
							| 
									
										
										
										
											2019-01-08 14:48:46 +00:00
										 |  |  | #include "hw/xen/xen-legacy-backend.h"
 | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 11:54:41 +01:00
										 |  |  | #include "hw/xen/interface/io/console.h"
 | 
					
						
							| 
									
										
										
										
											2012-06-21 11:43:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | struct buffer { | 
					
						
							|  |  |  |     uint8_t *data; | 
					
						
							|  |  |  |     size_t consumed; | 
					
						
							|  |  |  |     size_t size; | 
					
						
							|  |  |  |     size_t capacity; | 
					
						
							|  |  |  |     size_t max_capacity; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct XenConsole { | 
					
						
							| 
									
										
										
										
											2019-01-08 14:48:46 +00:00
										 |  |  |     struct XenLegacyDevice  xendev;  /* must be first */ | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     struct buffer     buffer; | 
					
						
							|  |  |  |     char              console[XEN_BUFSIZE]; | 
					
						
							|  |  |  |     int               ring_ref; | 
					
						
							|  |  |  |     void              *sring; | 
					
						
							| 
									
										
										
										
											2016-10-22 12:52:52 +03:00
										 |  |  |     CharBackend       chr; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     int               backlog; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void buffer_append(struct XenConsole *con) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct buffer *buffer = &con->buffer; | 
					
						
							|  |  |  |     XENCONS_RING_IDX cons, prod, size; | 
					
						
							|  |  |  |     struct xencons_interface *intf = con->sring; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cons = intf->out_cons; | 
					
						
							|  |  |  |     prod = intf->out_prod; | 
					
						
							|  |  |  |     xen_mb(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     size = prod - cons; | 
					
						
							|  |  |  |     if ((size == 0) || (size > sizeof(intf->out))) | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if ((buffer->capacity - buffer->size) < size) { | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         buffer->capacity += (size + 1024); | 
					
						
							|  |  |  |         buffer->data = g_realloc(buffer->data, buffer->capacity); | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (cons != prod) | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         buffer->data[buffer->size++] = intf->out[ | 
					
						
							|  |  |  |             MASK_XENCONS_IDX(cons++, intf->out)]; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     xen_mb(); | 
					
						
							|  |  |  |     intf->out_cons = cons; | 
					
						
							| 
									
										
										
										
											2016-10-25 08:50:16 +03:00
										 |  |  |     xen_pv_send_notify(&con->xendev); | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (buffer->max_capacity && | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         buffer->size > buffer->max_capacity) { | 
					
						
							|  |  |  |         /* Discard the middle of the data. */ | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         size_t over = buffer->size - buffer->max_capacity; | 
					
						
							|  |  |  |         uint8_t *maxpos = buffer->data + buffer->max_capacity; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         memmove(maxpos - over, maxpos, over); | 
					
						
							|  |  |  |         buffer->data = g_realloc(buffer->data, buffer->max_capacity); | 
					
						
							|  |  |  |         buffer->size = buffer->capacity = buffer->max_capacity; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         if (buffer->consumed > buffer->max_capacity - over) | 
					
						
							|  |  |  |             buffer->consumed = buffer->max_capacity - over; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void buffer_advance(struct buffer *buffer, size_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     buffer->consumed += len; | 
					
						
							|  |  |  |     if (buffer->consumed == buffer->size) { | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         buffer->consumed = 0; | 
					
						
							|  |  |  |         buffer->size = 0; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ring_free_bytes(struct XenConsole *con) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct xencons_interface *intf = con->sring; | 
					
						
							|  |  |  |     XENCONS_RING_IDX cons, prod, space; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cons = intf->in_cons; | 
					
						
							|  |  |  |     prod = intf->in_prod; | 
					
						
							|  |  |  |     xen_mb(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     space = prod - cons; | 
					
						
							|  |  |  |     if (space > sizeof(intf->in)) | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         return 0; /* ring is screwed: ignore it */ | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return (sizeof(intf->in) - space); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int xencons_can_receive(void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct XenConsole *con = opaque; | 
					
						
							|  |  |  |     return ring_free_bytes(con); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void xencons_receive(void *opaque, const uint8_t *buf, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct XenConsole *con = opaque; | 
					
						
							|  |  |  |     struct xencons_interface *intf = con->sring; | 
					
						
							|  |  |  |     XENCONS_RING_IDX prod; | 
					
						
							|  |  |  |     int i, max; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     max = ring_free_bytes(con); | 
					
						
							|  |  |  |     /* The can_receive() func limits this, but check again anyway */ | 
					
						
							|  |  |  |     if (max < len) | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         len = max; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     prod = intf->in_prod; | 
					
						
							|  |  |  |     for (i = 0; i < len; i++) { | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         intf->in[MASK_XENCONS_IDX(prod++, intf->in)] = | 
					
						
							|  |  |  |             buf[i]; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     xen_wmb(); | 
					
						
							|  |  |  |     intf->in_prod = prod; | 
					
						
							| 
									
										
										
										
											2016-10-25 08:50:16 +03:00
										 |  |  |     xen_pv_send_notify(&con->xendev); | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void xencons_send(struct XenConsole *con) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ssize_t len, size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     size = con->buffer.size - con->buffer.consumed; | 
					
						
							| 
									
										
										
										
											2017-07-06 15:08:52 +03:00
										 |  |  |     if (qemu_chr_fe_backend_connected(&con->chr)) { | 
					
						
							| 
									
										
										
										
											2016-10-22 12:52:55 +03:00
										 |  |  |         len = qemu_chr_fe_write(&con->chr, | 
					
						
							| 
									
										
										
										
											2016-10-22 12:52:52 +03:00
										 |  |  |                                 con->buffer.data + con->buffer.consumed, | 
					
						
							|  |  |  |                                 size); | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |         len = size; | 
					
						
							| 
									
										
										
										
											2016-10-22 12:52:52 +03:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     if (len < 1) { | 
					
						
							| 
									
										
										
										
											2016-10-25 08:50:07 +03:00
										 |  |  |         if (!con->backlog) { | 
					
						
							|  |  |  |             con->backlog = 1; | 
					
						
							| 
									
										
										
										
											2016-10-25 08:50:14 +03:00
										 |  |  |             xen_pv_printf(&con->xendev, 1, | 
					
						
							| 
									
										
										
										
											2016-10-25 08:50:07 +03:00
										 |  |  |                           "backlog piling up, nobody listening?\n"); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2016-10-25 08:50:07 +03:00
										 |  |  |         buffer_advance(&con->buffer, len); | 
					
						
							|  |  |  |         if (con->backlog && len == size) { | 
					
						
							|  |  |  |             con->backlog = 0; | 
					
						
							| 
									
										
										
										
											2016-10-25 08:50:14 +03:00
										 |  |  |             xen_pv_printf(&con->xendev, 1, "backlog is gone\n"); | 
					
						
							| 
									
										
										
										
											2016-10-25 08:50:07 +03:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-07 16:17:51 +00:00
										 |  |  | static int store_con_info(struct XenConsole *con) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Chardev *cs = qemu_chr_fe_get_driver(&con->chr); | 
					
						
							|  |  |  |     char *pts = NULL; | 
					
						
							|  |  |  |     char *dom_path; | 
					
						
							| 
									
										
										
										
											2023-04-12 19:51:01 +01:00
										 |  |  |     g_autoptr(GString) path = NULL; | 
					
						
							| 
									
										
										
										
											2023-01-07 16:17:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Only continue if we're talking to a pty. */ | 
					
						
							|  |  |  |     if (!CHARDEV_IS_PTY(cs)) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     pts = cs->filename + 4; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dom_path = qemu_xen_xs_get_domain_path(xenstore, xen_domid); | 
					
						
							|  |  |  |     if (!dom_path) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     path = g_string_new(dom_path); | 
					
						
							|  |  |  |     free(dom_path); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (con->xendev.dev) { | 
					
						
							|  |  |  |         g_string_append_printf(path, "/device/console/%d", con->xendev.dev); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         g_string_append(path, "/console"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     g_string_append(path, "/tty"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (xenstore_write_str(con->console, path->str, pts)) { | 
					
						
							|  |  |  |         fprintf(stderr, "xenstore_write_str for '%s' fail", path->str); | 
					
						
							| 
									
										
										
										
											2023-04-12 19:51:01 +01:00
										 |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2023-01-07 16:17:51 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-12 19:51:01 +01:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2023-01-07 16:17:51 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-08 14:48:46 +00:00
										 |  |  | static int con_init(struct XenLegacyDevice *xendev) | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); | 
					
						
							| 
									
										
										
										
											2011-06-30 18:26:29 +01:00
										 |  |  |     char *type, *dom, label[32]; | 
					
						
							| 
									
										
										
										
											2011-06-24 16:59:46 +01:00
										 |  |  |     int ret = 0; | 
					
						
							| 
									
										
										
										
											2011-06-30 18:26:29 +01:00
										 |  |  |     const char *output; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* setup */ | 
					
						
							| 
									
										
										
										
											2023-01-02 11:05:16 +00:00
										 |  |  |     dom = qemu_xen_xs_get_domain_path(xenstore, con->xendev.dom); | 
					
						
							| 
									
										
										
										
											2012-12-17 11:36:09 +00:00
										 |  |  |     if (!xendev->dev) { | 
					
						
							|  |  |  |         snprintf(con->console, sizeof(con->console), "%s/console", dom); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         snprintf(con->console, sizeof(con->console), "%s/device/console/%d", dom, xendev->dev); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     free(dom); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     type = xenstore_read_str(con->console, "type"); | 
					
						
							| 
									
										
										
										
											2009-04-23 18:42:30 +00:00
										 |  |  |     if (!type || strcmp(type, "ioemu") != 0) { | 
					
						
							| 
									
										
										
										
											2016-10-25 08:50:14 +03:00
										 |  |  |         xen_pv_printf(xendev, 1, "not for me (type=%s)\n", type); | 
					
						
							| 
									
										
										
										
											2011-06-24 16:59:46 +01:00
										 |  |  |         ret = -1; | 
					
						
							|  |  |  |         goto out; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 18:26:29 +01:00
										 |  |  |     output = xenstore_read_str(con->console, "output"); | 
					
						
							| 
									
										
										
										
											2011-07-03 09:44:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* no Xen override, use qemu output device */ | 
					
						
							| 
									
										
										
										
											2011-06-30 18:26:29 +01:00
										 |  |  |     if (output == NULL) { | 
					
						
							| 
									
										
										
										
											2016-10-22 12:52:52 +03:00
										 |  |  |         if (con->xendev.dev) { | 
					
						
							| 
									
										
										
										
											2018-04-20 15:52:43 +01:00
										 |  |  |             qemu_chr_fe_init(&con->chr, serial_hd(con->xendev.dev), | 
					
						
							| 
									
										
										
										
											2016-10-22 12:52:52 +03:00
										 |  |  |                              &error_abort); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-07-03 09:44:48 +02:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         snprintf(label, sizeof(label), "xencons%d", con->xendev.dev); | 
					
						
							| 
									
										
										
										
											2016-10-22 12:52:52 +03:00
										 |  |  |         qemu_chr_fe_init(&con->chr, | 
					
						
							| 
									
										
											  
											
												chardev: mark the calls that allow an implicit mux monitor
This is mostly for readability of the code. Let's make it clear which
callers can create an implicit monitor when the chardev is muxed.
This will also enforce a safer behaviour, as we don't really support
creating monitor anywhere/anytime at the moment. Add an assert() to
make sure the programmer explicitely wanted that behaviour.
There are documented cases, such as: -serial/-parallel/-virtioconsole
and to less extent -debugcon.
Less obvious and questionable ones are -gdb, SLIRP -guestfwd and Xen
console. Add a FIXME note for those, but keep the support for now.
Other qemu_chr_new() callers either have a fixed parameter/filename
string or do not need it, such as -qtest:
* qtest.c: qtest_init()
  Afaik, only used by tests/libqtest.c, without mux. I don't think we
  support it outside of qemu testing: drop support for implicit mux
  monitor (qemu_chr_new() call: no implicit mux now).
* hw/
  All with literal @filename argument that doesn't enable mux monitor.
* tests/
  All with @filename argument that doesn't enable mux monitor.
On a related note, the list of monitor creation places:
- the chardev creators listed above: all from command line (except
  perhaps Xen console?)
- -gdb & hmp gdbserver will create a "GDB monitor command" chardev
  that is wired to an HMP monitor.
- -mon command line option
From this short study, I would like to think that a monitor may only
be created in the main thread today, though I remain skeptical :)
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
											
										 
											2018-08-22 19:19:42 +02:00
										 |  |  |                          /*
 | 
					
						
							|  |  |  |                           * FIXME: sure we want to support implicit | 
					
						
							|  |  |  |                           * muxed monitors here? | 
					
						
							|  |  |  |                           */ | 
					
						
							| 
									
										
										
										
											2019-02-13 14:18:13 +01:00
										 |  |  |                          qemu_chr_new_mux_mon(label, output, NULL), | 
					
						
							|  |  |  |                          &error_abort); | 
					
						
							| 
									
										
										
										
											2011-06-30 18:26:29 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-07-03 09:44:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-07 16:17:51 +00:00
										 |  |  |     store_con_info(con); | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-24 16:59:46 +01:00
										 |  |  | out: | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     g_free(type); | 
					
						
							| 
									
										
										
										
											2011-06-24 16:59:46 +01:00
										 |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-08 14:48:46 +00:00
										 |  |  | static int con_initialise(struct XenLegacyDevice *xendev) | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); | 
					
						
							|  |  |  |     int limit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1) | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1) | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     if (xenstore_read_int(con->console, "limit", &limit) == 0) | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         con->buffer.max_capacity = limit; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-17 11:36:09 +00:00
										 |  |  |     if (!xendev->dev) { | 
					
						
							| 
									
										
										
										
											2016-01-15 13:23:40 +00:00
										 |  |  |         xen_pfn_t mfn = con->ring_ref; | 
					
						
							| 
									
										
										
										
											2023-01-02 01:13:46 +00:00
										 |  |  |         con->sring = qemu_xen_foreignmem_map(con->xendev.dom, NULL, | 
					
						
							|  |  |  |                                              PROT_READ | PROT_WRITE, | 
					
						
							|  |  |  |                                              1, &mfn, NULL); | 
					
						
							| 
									
										
										
										
											2012-12-17 11:36:09 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2018-05-17 16:35:53 +01:00
										 |  |  |         con->sring = xen_be_map_grant_ref(xendev, con->ring_ref, | 
					
						
							|  |  |  |                                           PROT_READ | PROT_WRITE); | 
					
						
							| 
									
										
										
										
											2012-12-17 11:36:09 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     if (!con->sring) | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     xen_be_bind_evtchn(&con->xendev); | 
					
						
							| 
									
										
										
										
											2016-10-22 12:52:59 +03:00
										 |  |  |     qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive, | 
					
						
							| 
									
										
										
										
											2017-07-06 15:08:49 +03:00
										 |  |  |                              xencons_receive, NULL, NULL, con, NULL, true); | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-25 08:50:14 +03:00
										 |  |  |     xen_pv_printf(xendev, 1, | 
					
						
							| 
									
										
										
										
											2016-10-25 08:50:08 +03:00
										 |  |  |                   "ring mfn %d, remote port %d, local port %d, limit %zd\n", | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |                   con->ring_ref, | 
					
						
							|  |  |  |                   con->xendev.remote_port, | 
					
						
							|  |  |  |                   con->xendev.local_port, | 
					
						
							|  |  |  |                   con->buffer.max_capacity); | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-08 14:48:46 +00:00
										 |  |  | static void con_disconnect(struct XenLegacyDevice *xendev) | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 00:49:13 +04:00
										 |  |  |     qemu_chr_fe_deinit(&con->chr, false); | 
					
						
							| 
									
										
										
										
											2016-10-25 08:50:15 +03:00
										 |  |  |     xen_pv_unbind_evtchn(&con->xendev); | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (con->sring) { | 
					
						
							| 
									
										
										
										
											2016-01-15 13:23:37 +00:00
										 |  |  |         if (!xendev->dev) { | 
					
						
							| 
									
										
										
										
											2023-01-02 01:13:46 +00:00
										 |  |  |             qemu_xen_foreignmem_unmap(con->sring, 1); | 
					
						
							| 
									
										
										
										
											2012-12-17 11:36:09 +00:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2023-01-10 00:03:49 +00:00
										 |  |  |             xen_be_unmap_grant_ref(xendev, con->sring, con->ring_ref); | 
					
						
							| 
									
										
										
										
											2012-12-17 11:36:09 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-01-15 13:23:37 +00:00
										 |  |  |         con->sring = NULL; | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-08 14:48:46 +00:00
										 |  |  | static void con_event(struct XenLegacyDevice *xendev) | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     buffer_append(con); | 
					
						
							|  |  |  |     if (con->buffer.size - con->buffer.consumed) | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |         xencons_send(con); | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct XenDevOps xen_console_ops = { | 
					
						
							|  |  |  |     .size       = sizeof(struct XenConsole), | 
					
						
							| 
									
										
										
										
											2012-12-17 11:36:09 +00:00
										 |  |  |     .flags      = DEVOPS_FLAG_IGNORE_STATE|DEVOPS_FLAG_NEED_GNTDEV, | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     .init       = con_init, | 
					
						
							| 
									
										
										
										
											2011-06-17 12:15:35 +00:00
										 |  |  |     .initialise = con_initialise, | 
					
						
							| 
									
										
										
										
											2009-04-22 15:19:19 +00:00
										 |  |  |     .event      = con_event, | 
					
						
							|  |  |  |     .disconnect = con_disconnect, | 
					
						
							|  |  |  | }; |