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