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