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