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 63 qemu_chr_fe_accept_input(&dev->chardev); 64 65 return n; 66 } 67 68 void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) 69 { 70 VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev); 71 72 /* XXX this blocks entire thread. Rewrite to use 73 * qemu_chr_fe_write and background I/O callbacks */ 74 qemu_chr_fe_write_all(&dev->chardev, buf, len); 75 } 76 77 static void spapr_vty_realize(VIOsPAPRDevice *sdev, Error **errp) 78 { 79 VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev); 80 81 if (!qemu_chr_fe_backend_connected(&dev->chardev)) { 82 error_setg(errp, "chardev property not set"); 83 return; 84 } 85 86 qemu_chr_fe_set_handlers(&dev->chardev, vty_can_receive, 87 vty_receive, NULL, NULL, dev, NULL, true); 88 } 89 90 /* Forward declaration */ 91 static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr, 92 target_ulong opcode, target_ulong *args) 93 { 94 target_ulong reg = args[0]; 95 target_ulong len = args[1]; 96 target_ulong char0_7 = args[2]; 97 target_ulong char8_15 = args[3]; 98 VIOsPAPRDevice *sdev; 99 uint8_t buf[16]; 100 101 sdev = vty_lookup(spapr, reg); 102 if (!sdev) { 103 return H_PARAMETER; 104 } 105 106 if (len > 16) { 107 return H_PARAMETER; 108 } 109 110 *((uint64_t *)buf) = cpu_to_be64(char0_7); 111 *((uint64_t *)buf + 1) = cpu_to_be64(char8_15); 112 113 vty_putchars(sdev, buf, len); 114 115 return H_SUCCESS; 116 } 117 118 static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPRMachineState *spapr, 119 target_ulong opcode, target_ulong *args) 120 { 121 target_ulong reg = args[0]; 122 target_ulong *len = args + 0; 123 target_ulong *char0_7 = args + 1; 124 target_ulong *char8_15 = args + 2; 125 VIOsPAPRDevice *sdev; 126 uint8_t buf[16]; 127 128 sdev = vty_lookup(spapr, reg); 129 if (!sdev) { 130 return H_PARAMETER; 131 } 132 133 *len = vty_getchars(sdev, buf, sizeof(buf)); 134 if (*len < 16) { 135 memset(buf + *len, 0, 16 - *len); 136 } 137 138 *char0_7 = be64_to_cpu(*((uint64_t *)buf)); 139 *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1)); 140 141 return H_SUCCESS; 142 } 143 144 void spapr_vty_create(VIOsPAPRBus *bus, Chardev *chardev) 145 { 146 DeviceState *dev; 147 148 dev = qdev_create(&bus->bus, "spapr-vty"); 149 qdev_prop_set_chr(dev, "chardev", chardev); 150 qdev_init_nofail(dev); 151 } 152 153 static Property spapr_vty_properties[] = { 154 DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev), 155 DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev), 156 DEFINE_PROP_END_OF_LIST(), 157 }; 158 159 static const VMStateDescription vmstate_spapr_vty = { 160 .name = "spapr_vty", 161 .version_id = 1, 162 .minimum_version_id = 1, 163 .fields = (VMStateField[]) { 164 VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVTYDevice), 165 166 VMSTATE_UINT32(in, VIOsPAPRVTYDevice), 167 VMSTATE_UINT32(out, VIOsPAPRVTYDevice), 168 VMSTATE_BUFFER(buf, VIOsPAPRVTYDevice), 169 VMSTATE_END_OF_LIST() 170 }, 171 }; 172 173 static void spapr_vty_class_init(ObjectClass *klass, void *data) 174 { 175 DeviceClass *dc = DEVICE_CLASS(klass); 176 VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); 177 178 k->realize = spapr_vty_realize; 179 k->dt_name = "vty"; 180 k->dt_type = "serial"; 181 k->dt_compatible = "hvterm1"; 182 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 183 dc->props = spapr_vty_properties; 184 dc->vmsd = &vmstate_spapr_vty; 185 } 186 187 static const TypeInfo spapr_vty_info = { 188 .name = TYPE_VIO_SPAPR_VTY_DEVICE, 189 .parent = TYPE_VIO_SPAPR_DEVICE, 190 .instance_size = sizeof(VIOsPAPRVTYDevice), 191 .class_init = spapr_vty_class_init, 192 }; 193 194 VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) 195 { 196 VIOsPAPRDevice *sdev, *selected; 197 BusChild *kid; 198 199 /* 200 * To avoid the console bouncing around we want one VTY to be 201 * the "default". We haven't really got anything to go on, so 202 * arbitrarily choose the one with the lowest reg value. 203 */ 204 205 selected = NULL; 206 QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 207 DeviceState *iter = kid->child; 208 209 /* Only look at VTY devices */ 210 if (!object_dynamic_cast(OBJECT(iter), TYPE_VIO_SPAPR_VTY_DEVICE)) { 211 continue; 212 } 213 214 sdev = VIO_SPAPR_DEVICE(iter); 215 216 /* First VTY we've found, so it is selected for now */ 217 if (!selected) { 218 selected = sdev; 219 continue; 220 } 221 222 /* Choose VTY with lowest reg value */ 223 if (sdev->reg < selected->reg) { 224 selected = sdev; 225 } 226 } 227 228 return selected; 229 } 230 231 VIOsPAPRDevice *vty_lookup(sPAPRMachineState *spapr, target_ulong reg) 232 { 233 VIOsPAPRDevice *sdev; 234 235 sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 236 if (!sdev && reg == 0) { 237 /* Hack for kernel early debug, which always specifies reg==0. 238 * We search all VIO devices, and grab the vty with the lowest 239 * reg. This attempts to mimic existing PowerVM behaviour 240 * (early debug does work there, despite having no vty with 241 * reg==0. */ 242 return spapr_vty_get_default(spapr->vio_bus); 243 } 244 245 if (!object_dynamic_cast(OBJECT(sdev), TYPE_VIO_SPAPR_VTY_DEVICE)) { 246 return NULL; 247 } 248 249 return sdev; 250 } 251 252 static void spapr_vty_register_types(void) 253 { 254 spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); 255 spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char); 256 type_register_static(&spapr_vty_info); 257 } 258 259 type_init(spapr_vty_register_types) 260