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