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