spapr_vty.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #include "qdev.h"
  2. #include "qemu-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(dev->sdev.qirq);
  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 VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
  58. static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
  59. target_ulong opcode, target_ulong *args)
  60. {
  61. target_ulong reg = args[0];
  62. target_ulong len = args[1];
  63. target_ulong char0_7 = args[2];
  64. target_ulong char8_15 = args[3];
  65. VIOsPAPRDevice *sdev;
  66. uint8_t buf[16];
  67. sdev = vty_lookup(spapr, reg);
  68. if (!sdev) {
  69. return H_PARAMETER;
  70. }
  71. if (len > 16) {
  72. return H_PARAMETER;
  73. }
  74. *((uint64_t *)buf) = cpu_to_be64(char0_7);
  75. *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
  76. vty_putchars(sdev, buf, len);
  77. return H_SUCCESS;
  78. }
  79. static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr,
  80. target_ulong opcode, target_ulong *args)
  81. {
  82. target_ulong reg = args[0];
  83. target_ulong *len = args + 0;
  84. target_ulong *char0_7 = args + 1;
  85. target_ulong *char8_15 = args + 2;
  86. VIOsPAPRDevice *sdev;
  87. uint8_t buf[16];
  88. sdev = vty_lookup(spapr, reg);
  89. if (!sdev) {
  90. return H_PARAMETER;
  91. }
  92. *len = vty_getchars(sdev, buf, sizeof(buf));
  93. if (*len < 16) {
  94. memset(buf + *len, 0, 16 - *len);
  95. }
  96. *char0_7 = be64_to_cpu(*((uint64_t *)buf));
  97. *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
  98. return H_SUCCESS;
  99. }
  100. void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev)
  101. {
  102. DeviceState *dev;
  103. dev = qdev_create(&bus->bus, "spapr-vty");
  104. qdev_prop_set_uint32(dev, "reg", reg);
  105. qdev_prop_set_chr(dev, "chardev", chardev);
  106. qdev_init_nofail(dev);
  107. }
  108. static void vty_hcalls(VIOsPAPRBus *bus)
  109. {
  110. spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
  111. spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
  112. }
  113. static VIOsPAPRDeviceInfo spapr_vty = {
  114. .init = spapr_vty_init,
  115. .dt_name = "vty",
  116. .dt_type = "serial",
  117. .dt_compatible = "hvterm1",
  118. .hcalls = vty_hcalls,
  119. .qdev.name = "spapr-vty",
  120. .qdev.size = sizeof(VIOsPAPRVTYDevice),
  121. .qdev.props = (Property[]) {
  122. DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0),
  123. DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
  124. DEFINE_PROP_END_OF_LIST(),
  125. },
  126. };
  127. VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
  128. {
  129. VIOsPAPRDevice *sdev, *selected;
  130. DeviceState *iter;
  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(iter, &bus->bus.children, sibling) {
  138. /* Only look at VTY devices */
  139. if (iter->info != &spapr_vty.qdev) {
  140. continue;
  141. }
  142. sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter);
  143. /* First VTY we've found, so it is selected for now */
  144. if (!selected) {
  145. selected = sdev;
  146. continue;
  147. }
  148. /* Choose VTY with lowest reg value */
  149. if (sdev->reg < selected->reg) {
  150. selected = sdev;
  151. }
  152. }
  153. return selected;
  154. }
  155. static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
  156. {
  157. VIOsPAPRDevice *sdev;
  158. sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
  159. if (!sdev && reg == 0) {
  160. /* Hack for kernel early debug, which always specifies reg==0.
  161. * We search all VIO devices, and grab the vty with the lowest
  162. * reg. This attempts to mimic existing PowerVM behaviour
  163. * (early debug does work there, despite having no vty with
  164. * reg==0. */
  165. return spapr_vty_get_default(spapr->vio_bus);
  166. }
  167. return sdev;
  168. }
  169. static void spapr_vty_register(void)
  170. {
  171. spapr_vio_bus_register_withprop(&spapr_vty);
  172. }
  173. device_init(spapr_vty_register);