1 #include "qemu/osdep.h" 2 #include "qemu/error-report.h" 3 #include "qemu/module.h" 4 #include "qapi/error.h" 5 #include "cpu.h" 6 #include "migration/vmstate.h" 7 #include "chardev/char-fe.h" 8 #include "hw/irq.h" 9 #include "hw/ppc/spapr.h" 10 #include "hw/ppc/spapr_vio.h" 11 #include "hw/qdev-properties.h" 12 13 #define VTERM_BUFSIZE 16 14 15 typedef struct SpaprVioVty { 16 SpaprVioDevice sdev; 17 CharBackend chardev; 18 uint32_t in, out; 19 uint8_t buf[VTERM_BUFSIZE]; 20 } SpaprVioVty; 21 22 #define TYPE_VIO_SPAPR_VTY_DEVICE "spapr-vty" 23 #define VIO_SPAPR_VTY_DEVICE(obj) \ 24 OBJECT_CHECK(SpaprVioVty, (obj), TYPE_VIO_SPAPR_VTY_DEVICE) 25 26 static int vty_can_receive(void *opaque) 27 { 28 SpaprVioVty *dev = VIO_SPAPR_VTY_DEVICE(opaque); 29 30 return VTERM_BUFSIZE - (dev->in - dev->out); 31 } 32 33 static void vty_receive(void *opaque, const uint8_t *buf, int size) 34 { 35 SpaprVioVty *dev = VIO_SPAPR_VTY_DEVICE(opaque); 36 int i; 37 38 if ((dev->in == dev->out) && size) { 39 /* toggle line to simulate edge interrupt */ 40 qemu_irq_pulse(spapr_vio_qirq(&dev->sdev)); 41 } 42 for (i = 0; i < size; i++) { 43 if (dev->in - dev->out >= VTERM_BUFSIZE) { 44 static bool reported; 45 if (!reported) { 46 error_report("VTY input buffer exhausted - characters dropped." 47 " (input size = %i)", size); 48 reported = true; 49 } 50 break; 51 } 52 dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i]; 53 } 54 } 55 56 static int vty_getchars(SpaprVioDevice *sdev, uint8_t *buf, int max) 57 { 58 SpaprVioVty *dev = VIO_SPAPR_VTY_DEVICE(sdev); 59 int n = 0; 60 61 while ((n < max) && (dev->out != dev->in)) { 62 buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE]; 63 64 /* PowerVM's vty implementation has a bug where it inserts a 65 * \0 after every \r going to the guest. Existing guests have 66 * a workaround for this which removes every \0 immediately 67 * following a \r, so here we make ourselves bug-for-bug 68 * compatible, so that the guest won't drop a real \0-after-\r 69 * that happens to occur in a binary stream. */ 70 if (buf[n - 1] == '\r') { 71 if (n < max) { 72 buf[n++] = '\0'; 73 } else { 74 /* No room for the extra \0, roll back and try again 75 * next time */ 76 dev->out--; 77 n--; 78 break; 79 } 80 } 81 } 82 83 qemu_chr_fe_accept_input(&dev->chardev); 84 85 return n; 86 } 87 88 void vty_putchars(SpaprVioDevice *sdev, uint8_t *buf, int len) 89 { 90 SpaprVioVty *dev = VIO_SPAPR_VTY_DEVICE(sdev); 91 92 /* XXX this blocks entire thread. Rewrite to use 93 * qemu_chr_fe_write and background I/O callbacks */ 94 qemu_chr_fe_write_all(&dev->chardev, buf, len); 95 } 96 97 static void spapr_vty_realize(SpaprVioDevice *sdev, Error **errp) 98 { 99 SpaprVioVty *dev = VIO_SPAPR_VTY_DEVICE(sdev); 100 101 if (!qemu_chr_fe_backend_connected(&dev->chardev)) { 102 error_setg(errp, "chardev property not set"); 103 return; 104 } 105 106 qemu_chr_fe_set_handlers(&dev->chardev, vty_can_receive, 107 vty_receive, NULL, NULL, dev, NULL, true); 108 } 109 110 /* Forward declaration */ 111 static target_ulong h_put_term_char(PowerPCCPU *cpu, SpaprMachineState *spapr, 112 target_ulong opcode, target_ulong *args) 113 { 114 target_ulong reg = args[0]; 115 target_ulong len = args[1]; 116 target_ulong char0_7 = args[2]; 117 target_ulong char8_15 = args[3]; 118 SpaprVioDevice *sdev; 119 uint8_t buf[16]; 120 121 sdev = vty_lookup(spapr, reg); 122 if (!sdev) { 123 return H_PARAMETER; 124 } 125 126 if (len > 16) { 127 return H_PARAMETER; 128 } 129 130 *((uint64_t *)buf) = cpu_to_be64(char0_7); 131 *((uint64_t *)buf + 1) = cpu_to_be64(char8_15); 132 133 vty_putchars(sdev, buf, len); 134 135 return H_SUCCESS; 136 } 137 138 static target_ulong h_get_term_char(PowerPCCPU *cpu, SpaprMachineState *spapr, 139 target_ulong opcode, target_ulong *args) 140 { 141 target_ulong reg = args[0]; 142 target_ulong *len = args + 0; 143 target_ulong *char0_7 = args + 1; 144 target_ulong *char8_15 = args + 2; 145 SpaprVioDevice *sdev; 146 uint8_t buf[16]; 147 148 sdev = vty_lookup(spapr, reg); 149 if (!sdev) { 150 return H_PARAMETER; 151 } 152 153 *len = vty_getchars(sdev, buf, sizeof(buf)); 154 if (*len < 16) { 155 memset(buf + *len, 0, 16 - *len); 156 } 157 158 *char0_7 = be64_to_cpu(*((uint64_t *)buf)); 159 *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1)); 160 161 return H_SUCCESS; 162 } 163 164 void spapr_vty_create(SpaprVioBus *bus, Chardev *chardev) 165 { 166 DeviceState *dev; 167 168 dev = qdev_create(&bus->bus, "spapr-vty"); 169 qdev_prop_set_chr(dev, "chardev", chardev); 170 qdev_init_nofail(dev); 171 } 172 173 static Property spapr_vty_properties[] = { 174 DEFINE_SPAPR_PROPERTIES(SpaprVioVty, sdev), 175 DEFINE_PROP_CHR("chardev", SpaprVioVty, chardev), 176 DEFINE_PROP_END_OF_LIST(), 177 }; 178 179 static const VMStateDescription vmstate_spapr_vty = { 180 .name = "spapr_vty", 181 .version_id = 1, 182 .minimum_version_id = 1, 183 .fields = (VMStateField[]) { 184 VMSTATE_SPAPR_VIO(sdev, SpaprVioVty), 185 186 VMSTATE_UINT32(in, SpaprVioVty), 187 VMSTATE_UINT32(out, SpaprVioVty), 188 VMSTATE_BUFFER(buf, SpaprVioVty), 189 VMSTATE_END_OF_LIST() 190 }, 191 }; 192 193 static void spapr_vty_class_init(ObjectClass *klass, void *data) 194 { 195 DeviceClass *dc = DEVICE_CLASS(klass); 196 SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); 197 198 k->realize = spapr_vty_realize; 199 k->dt_name = "vty"; 200 k->dt_type = "serial"; 201 k->dt_compatible = "hvterm1"; 202 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 203 dc->props = spapr_vty_properties; 204 dc->vmsd = &vmstate_spapr_vty; 205 } 206 207 static const TypeInfo spapr_vty_info = { 208 .name = TYPE_VIO_SPAPR_VTY_DEVICE, 209 .parent = TYPE_VIO_SPAPR_DEVICE, 210 .instance_size = sizeof(SpaprVioVty), 211 .class_init = spapr_vty_class_init, 212 }; 213 214 SpaprVioDevice *spapr_vty_get_default(SpaprVioBus *bus) 215 { 216 SpaprVioDevice *sdev, *selected; 217 BusChild *kid; 218 219 /* 220 * To avoid the console bouncing around we want one VTY to be 221 * the "default". We haven't really got anything to go on, so 222 * arbitrarily choose the one with the lowest reg value. 223 */ 224 225 selected = NULL; 226 QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 227 DeviceState *iter = kid->child; 228 229 /* Only look at VTY devices */ 230 if (!object_dynamic_cast(OBJECT(iter), TYPE_VIO_SPAPR_VTY_DEVICE)) { 231 continue; 232 } 233 234 sdev = VIO_SPAPR_DEVICE(iter); 235 236 /* First VTY we've found, so it is selected for now */ 237 if (!selected) { 238 selected = sdev; 239 continue; 240 } 241 242 /* Choose VTY with lowest reg value */ 243 if (sdev->reg < selected->reg) { 244 selected = sdev; 245 } 246 } 247 248 return selected; 249 } 250 251 SpaprVioDevice *vty_lookup(SpaprMachineState *spapr, target_ulong reg) 252 { 253 SpaprVioDevice *sdev; 254 255 sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 256 if (!sdev && reg == 0) { 257 /* Hack for kernel early debug, which always specifies reg==0. 258 * We search all VIO devices, and grab the vty with the lowest 259 * reg. This attempts to mimic existing PowerVM behaviour 260 * (early debug does work there, despite having no vty with 261 * reg==0. */ 262 return spapr_vty_get_default(spapr->vio_bus); 263 } 264 265 if (!object_dynamic_cast(OBJECT(sdev), TYPE_VIO_SPAPR_VTY_DEVICE)) { 266 return NULL; 267 } 268 269 return sdev; 270 } 271 272 static void spapr_vty_register_types(void) 273 { 274 spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); 275 spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char); 276 type_register_static(&spapr_vty_info); 277 } 278 279 type_init(spapr_vty_register_types) 280