spapr_vty.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #include "qdev.h"
  2. #include "char/char.h"
  3. #include "hw/spapr.h"
  4. #include "hw/spapr_vio.h"
  5. #define VTERM_BUFSIZE 16
  6. typedef struct VIOsPAPRVTYDevice {
  7. VIOsPAPRDevice sdev;
  8. CharDriverState *chardev;
  9. uint32_t in, out;
  10. uint8_t buf[VTERM_BUFSIZE];
  11. } VIOsPAPRVTYDevice;
  12. static int vty_can_receive(void *opaque)
  13. {
  14. VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
  15. return (dev->in - dev->out) < VTERM_BUFSIZE;
  16. }
  17. static void vty_receive(void *opaque, const uint8_t *buf, int size)
  18. {
  19. VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
  20. int i;
  21. if ((dev->in == dev->out) && size) {
  22. /* toggle line to simulate edge interrupt */
  23. qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
  24. }
  25. for (i = 0; i < size; i++) {
  26. assert((dev->in - dev->out) < VTERM_BUFSIZE);
  27. dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
  28. }
  29. }
  30. static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
  31. {
  32. VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
  33. int n = 0;
  34. while ((n < max) && (dev->out != dev->in)) {
  35. buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
  36. }
  37. return n;
  38. }
  39. void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
  40. {
  41. VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
  42. /* FIXME: should check the qemu_chr_fe_write() return value */
  43. qemu_chr_fe_write(dev->chardev, buf, len);
  44. }
  45. static int spapr_vty_init(VIOsPAPRDevice *sdev)
  46. {
  47. VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
  48. if (!dev->chardev) {
  49. fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n");
  50. exit(1);
  51. }
  52. qemu_chr_add_handlers(dev->chardev, vty_can_receive,
  53. vty_receive, NULL, dev);
  54. return 0;
  55. }
  56. /* Forward declaration */
  57. static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
  58. target_ulong opcode, target_ulong *args)
  59. {
  60. target_ulong reg = args[0];
  61. target_ulong len = args[1];
  62. target_ulong char0_7 = args[2];
  63. target_ulong char8_15 = args[3];
  64. VIOsPAPRDevice *sdev;
  65. uint8_t buf[16];
  66. sdev = vty_lookup(spapr, reg);
  67. if (!sdev) {
  68. return H_PARAMETER;
  69. }
  70. if (len > 16) {
  71. return H_PARAMETER;
  72. }
  73. *((uint64_t *)buf) = cpu_to_be64(char0_7);
  74. *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
  75. vty_putchars(sdev, buf, len);
  76. return H_SUCCESS;
  77. }
  78. static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
  79. target_ulong opcode, target_ulong *args)
  80. {
  81. target_ulong reg = args[0];
  82. target_ulong *len = args + 0;
  83. target_ulong *char0_7 = args + 1;
  84. target_ulong *char8_15 = args + 2;
  85. VIOsPAPRDevice *sdev;
  86. uint8_t buf[16];
  87. sdev = vty_lookup(spapr, reg);
  88. if (!sdev) {
  89. return H_PARAMETER;
  90. }
  91. *len = vty_getchars(sdev, buf, sizeof(buf));
  92. if (*len < 16) {
  93. memset(buf + *len, 0, 16 - *len);
  94. }
  95. *char0_7 = be64_to_cpu(*((uint64_t *)buf));
  96. *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
  97. return H_SUCCESS;
  98. }
  99. void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev)
  100. {
  101. DeviceState *dev;
  102. dev = qdev_create(&bus->bus, "spapr-vty");
  103. qdev_prop_set_chr(dev, "chardev", chardev);
  104. qdev_init_nofail(dev);
  105. }
  106. static Property spapr_vty_properties[] = {
  107. DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev),
  108. DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
  109. DEFINE_PROP_END_OF_LIST(),
  110. };
  111. static void spapr_vty_class_init(ObjectClass *klass, void *data)
  112. {
  113. DeviceClass *dc = DEVICE_CLASS(klass);
  114. VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
  115. k->init = spapr_vty_init;
  116. k->dt_name = "vty";
  117. k->dt_type = "serial";
  118. k->dt_compatible = "hvterm1";
  119. dc->props = spapr_vty_properties;
  120. }
  121. static const TypeInfo spapr_vty_info = {
  122. .name = "spapr-vty",
  123. .parent = TYPE_VIO_SPAPR_DEVICE,
  124. .instance_size = sizeof(VIOsPAPRVTYDevice),
  125. .class_init = spapr_vty_class_init,
  126. };
  127. VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
  128. {
  129. VIOsPAPRDevice *sdev, *selected;
  130. BusChild *kid;
  131. /*
  132. * To avoid the console bouncing around we want one VTY to be
  133. * the "default". We haven't really got anything to go on, so
  134. * arbitrarily choose the one with the lowest reg value.
  135. */
  136. selected = NULL;
  137. QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
  138. DeviceState *iter = kid->child;
  139. /* Only look at VTY devices */
  140. if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) {
  141. continue;
  142. }
  143. sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter);
  144. /* First VTY we've found, so it is selected for now */
  145. if (!selected) {
  146. selected = sdev;
  147. continue;
  148. }
  149. /* Choose VTY with lowest reg value */
  150. if (sdev->reg < selected->reg) {
  151. selected = sdev;
  152. }
  153. }
  154. return selected;
  155. }
  156. VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
  157. {
  158. VIOsPAPRDevice *sdev;
  159. sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
  160. if (!sdev && reg == 0) {
  161. /* Hack for kernel early debug, which always specifies reg==0.
  162. * We search all VIO devices, and grab the vty with the lowest
  163. * reg. This attempts to mimic existing PowerVM behaviour
  164. * (early debug does work there, despite having no vty with
  165. * reg==0. */
  166. return spapr_vty_get_default(spapr->vio_bus);
  167. }
  168. return sdev;
  169. }
  170. static void spapr_vty_register_types(void)
  171. {
  172. spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
  173. spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
  174. type_register_static(&spapr_vty_info);
  175. }
  176. type_init(spapr_vty_register_types)