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 along 19 * with this program; if not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 #include "qemu/osdep.h" 23 #include <sys/select.h> 24 #include <termios.h> 25 26 #include "qapi/error.h" 27 #include "hw/hw.h" 28 #include "sysemu/char.h" 29 #include "hw/xen/xen_backend.h" 30 #include "qapi/error.h" 31 32 #include <xen/io/console.h> 33 34 struct buffer { 35 uint8_t *data; 36 size_t consumed; 37 size_t size; 38 size_t capacity; 39 size_t max_capacity; 40 }; 41 42 struct XenConsole { 43 struct XenDevice xendev; /* must be first */ 44 struct buffer buffer; 45 char console[XEN_BUFSIZE]; 46 int ring_ref; 47 void *sring; 48 CharBackend chr; 49 int backlog; 50 }; 51 52 static void buffer_append(struct XenConsole *con) 53 { 54 struct buffer *buffer = &con->buffer; 55 XENCONS_RING_IDX cons, prod, size; 56 struct xencons_interface *intf = con->sring; 57 58 cons = intf->out_cons; 59 prod = intf->out_prod; 60 xen_mb(); 61 62 size = prod - cons; 63 if ((size == 0) || (size > sizeof(intf->out))) 64 return; 65 66 if ((buffer->capacity - buffer->size) < size) { 67 buffer->capacity += (size + 1024); 68 buffer->data = g_realloc(buffer->data, buffer->capacity); 69 } 70 71 while (cons != prod) 72 buffer->data[buffer->size++] = intf->out[ 73 MASK_XENCONS_IDX(cons++, intf->out)]; 74 75 xen_mb(); 76 intf->out_cons = cons; 77 xen_pv_send_notify(&con->xendev); 78 79 if (buffer->max_capacity && 80 buffer->size > buffer->max_capacity) { 81 /* Discard the middle of the data. */ 82 83 size_t over = buffer->size - buffer->max_capacity; 84 uint8_t *maxpos = buffer->data + buffer->max_capacity; 85 86 memmove(maxpos - over, maxpos, over); 87 buffer->data = g_realloc(buffer->data, buffer->max_capacity); 88 buffer->size = buffer->capacity = buffer->max_capacity; 89 90 if (buffer->consumed > buffer->max_capacity - over) 91 buffer->consumed = buffer->max_capacity - over; 92 } 93 } 94 95 static void buffer_advance(struct buffer *buffer, size_t len) 96 { 97 buffer->consumed += len; 98 if (buffer->consumed == buffer->size) { 99 buffer->consumed = 0; 100 buffer->size = 0; 101 } 102 } 103 104 static int ring_free_bytes(struct XenConsole *con) 105 { 106 struct xencons_interface *intf = con->sring; 107 XENCONS_RING_IDX cons, prod, space; 108 109 cons = intf->in_cons; 110 prod = intf->in_prod; 111 xen_mb(); 112 113 space = prod - cons; 114 if (space > sizeof(intf->in)) 115 return 0; /* ring is screwed: ignore it */ 116 117 return (sizeof(intf->in) - space); 118 } 119 120 static int xencons_can_receive(void *opaque) 121 { 122 struct XenConsole *con = opaque; 123 return ring_free_bytes(con); 124 } 125 126 static void xencons_receive(void *opaque, const uint8_t *buf, int len) 127 { 128 struct XenConsole *con = opaque; 129 struct xencons_interface *intf = con->sring; 130 XENCONS_RING_IDX prod; 131 int i, max; 132 133 max = ring_free_bytes(con); 134 /* The can_receive() func limits this, but check again anyway */ 135 if (max < len) 136 len = max; 137 138 prod = intf->in_prod; 139 for (i = 0; i < len; i++) { 140 intf->in[MASK_XENCONS_IDX(prod++, intf->in)] = 141 buf[i]; 142 } 143 xen_wmb(); 144 intf->in_prod = prod; 145 xen_pv_send_notify(&con->xendev); 146 } 147 148 static void xencons_send(struct XenConsole *con) 149 { 150 ssize_t len, size; 151 152 size = con->buffer.size - con->buffer.consumed; 153 if (qemu_chr_fe_get_driver(&con->chr)) { 154 len = qemu_chr_fe_write(&con->chr, 155 con->buffer.data + con->buffer.consumed, 156 size); 157 } else { 158 len = size; 159 } 160 if (len < 1) { 161 if (!con->backlog) { 162 con->backlog = 1; 163 xen_pv_printf(&con->xendev, 1, 164 "backlog piling up, nobody listening?\n"); 165 } 166 } else { 167 buffer_advance(&con->buffer, len); 168 if (con->backlog && len == size) { 169 con->backlog = 0; 170 xen_pv_printf(&con->xendev, 1, "backlog is gone\n"); 171 } 172 } 173 } 174 175 /* -------------------------------------------------------------------- */ 176 177 static int con_init(struct XenDevice *xendev) 178 { 179 struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); 180 char *type, *dom, label[32]; 181 int ret = 0; 182 const char *output; 183 184 /* setup */ 185 dom = xs_get_domain_path(xenstore, con->xendev.dom); 186 if (!xendev->dev) { 187 snprintf(con->console, sizeof(con->console), "%s/console", dom); 188 } else { 189 snprintf(con->console, sizeof(con->console), "%s/device/console/%d", dom, xendev->dev); 190 } 191 free(dom); 192 193 type = xenstore_read_str(con->console, "type"); 194 if (!type || strcmp(type, "ioemu") != 0) { 195 xen_pv_printf(xendev, 1, "not for me (type=%s)\n", type); 196 ret = -1; 197 goto out; 198 } 199 200 output = xenstore_read_str(con->console, "output"); 201 202 /* no Xen override, use qemu output device */ 203 if (output == NULL) { 204 if (con->xendev.dev) { 205 qemu_chr_fe_init(&con->chr, serial_hds[con->xendev.dev], 206 &error_abort); 207 } 208 } else { 209 snprintf(label, sizeof(label), "xencons%d", con->xendev.dev); 210 qemu_chr_fe_init(&con->chr, 211 qemu_chr_new(label, output), &error_abort); 212 } 213 214 xenstore_store_pv_console_info(con->xendev.dev, 215 qemu_chr_fe_get_driver(&con->chr)); 216 217 out: 218 g_free(type); 219 return ret; 220 } 221 222 static int con_initialise(struct XenDevice *xendev) 223 { 224 struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); 225 int limit; 226 227 if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1) 228 return -1; 229 if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1) 230 return -1; 231 if (xenstore_read_int(con->console, "limit", &limit) == 0) 232 con->buffer.max_capacity = limit; 233 234 if (!xendev->dev) { 235 xen_pfn_t mfn = con->ring_ref; 236 con->sring = xenforeignmemory_map(xen_fmem, con->xendev.dom, 237 PROT_READ|PROT_WRITE, 238 1, &mfn, NULL); 239 } else { 240 con->sring = xengnttab_map_grant_ref(xendev->gnttabdev, con->xendev.dom, 241 con->ring_ref, 242 PROT_READ|PROT_WRITE); 243 } 244 if (!con->sring) 245 return -1; 246 247 xen_be_bind_evtchn(&con->xendev); 248 qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive, 249 xencons_receive, NULL, con, NULL, true); 250 251 xen_pv_printf(xendev, 1, 252 "ring mfn %d, remote port %d, local port %d, limit %zd\n", 253 con->ring_ref, 254 con->xendev.remote_port, 255 con->xendev.local_port, 256 con->buffer.max_capacity); 257 return 0; 258 } 259 260 static void con_disconnect(struct XenDevice *xendev) 261 { 262 struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); 263 264 qemu_chr_fe_deinit(&con->chr); 265 xen_pv_unbind_evtchn(&con->xendev); 266 267 if (con->sring) { 268 if (!xendev->dev) { 269 xenforeignmemory_unmap(xen_fmem, con->sring, 1); 270 } else { 271 xengnttab_unmap(xendev->gnttabdev, con->sring, 1); 272 } 273 con->sring = NULL; 274 } 275 } 276 277 static void con_event(struct XenDevice *xendev) 278 { 279 struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); 280 281 buffer_append(con); 282 if (con->buffer.size - con->buffer.consumed) 283 xencons_send(con); 284 } 285 286 /* -------------------------------------------------------------------- */ 287 288 struct XenDevOps xen_console_ops = { 289 .size = sizeof(struct XenConsole), 290 .flags = DEVOPS_FLAG_IGNORE_STATE|DEVOPS_FLAG_NEED_GNTDEV, 291 .init = con_init, 292 .initialise = con_initialise, 293 .event = con_event, 294 .disconnect = con_disconnect, 295 }; 296