sclpconsole.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /*
  2. * SCLP event type
  3. * Ascii Console Data (VT220 Console)
  4. *
  5. * Copyright IBM, Corp. 2012
  6. *
  7. * Authors:
  8. * Heinz Graalfs <graalfs@de.ibm.com>
  9. *
  10. * This work is licensed under the terms of the GNU GPL, version 2 or (at your
  11. * option) any later version. See the COPYING file in the top-level directory.
  12. *
  13. */
  14. #include "qemu/osdep.h"
  15. #include "qemu/thread.h"
  16. #include "qemu/error-report.h"
  17. #include "qemu/module.h"
  18. #include "hw/s390x/sclp.h"
  19. #include "migration/vmstate.h"
  20. #include "hw/qdev-properties.h"
  21. #include "hw/qdev-properties-system.h"
  22. #include "hw/s390x/event-facility.h"
  23. #include "chardev/char-fe.h"
  24. #include "qom/object.h"
  25. typedef struct ASCIIConsoleData {
  26. EventBufferHeader ebh;
  27. char data[];
  28. } QEMU_PACKED ASCIIConsoleData;
  29. /* max size for ASCII data in 4K SCCB page */
  30. #define SIZE_BUFFER_VT220 4080
  31. struct SCLPConsole {
  32. SCLPEvent event;
  33. CharBackend chr;
  34. uint8_t iov[SIZE_BUFFER_VT220];
  35. uint32_t iov_sclp; /* offset in buf for SCLP read operation */
  36. uint32_t iov_bs; /* offset in buf for char layer read operation */
  37. uint32_t iov_data_len; /* length of byte stream in buffer */
  38. uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
  39. bool notify; /* qemu_notify_event() req'd if true */
  40. };
  41. typedef struct SCLPConsole SCLPConsole;
  42. #define TYPE_SCLP_CONSOLE "sclpconsole"
  43. DECLARE_INSTANCE_CHECKER(SCLPConsole, SCLP_CONSOLE,
  44. TYPE_SCLP_CONSOLE)
  45. /* character layer call-back functions */
  46. /* Return number of bytes that fit into iov buffer */
  47. static int chr_can_read(void *opaque)
  48. {
  49. SCLPConsole *scon = opaque;
  50. int avail = SIZE_BUFFER_VT220 - scon->iov_data_len;
  51. if (avail == 0) {
  52. scon->notify = true;
  53. }
  54. return avail;
  55. }
  56. /* Send data from a char device over to the guest */
  57. static void chr_read(void *opaque, const uint8_t *buf, int size)
  58. {
  59. SCLPConsole *scon = opaque;
  60. assert(scon);
  61. /* read data must fit into current buffer */
  62. assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
  63. /* put byte-stream from character layer into buffer */
  64. memcpy(&scon->iov[scon->iov_bs], buf, size);
  65. scon->iov_data_len += size;
  66. scon->iov_sclp_rest += size;
  67. scon->iov_bs += size;
  68. scon->event.event_pending = true;
  69. sclp_service_interrupt(0);
  70. }
  71. /* functions to be called by event facility */
  72. static bool can_handle_event(uint8_t type)
  73. {
  74. return type == SCLP_EVENT_ASCII_CONSOLE_DATA;
  75. }
  76. static sccb_mask_t send_mask(void)
  77. {
  78. return SCLP_EVENT_MASK_MSG_ASCII;
  79. }
  80. static sccb_mask_t receive_mask(void)
  81. {
  82. return SCLP_EVENT_MASK_MSG_ASCII;
  83. }
  84. /* triggered by SCLP's read_event_data -
  85. * copy console data byte-stream into provided (SCLP) buffer
  86. */
  87. static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
  88. int avail)
  89. {
  90. SCLPConsole *cons = SCLP_CONSOLE(event);
  91. /* first byte is hex 0 saying an ascii string follows */
  92. *buf++ = '\0';
  93. avail--;
  94. /* if all data fit into provided SCLP buffer */
  95. if (avail >= cons->iov_sclp_rest) {
  96. /* copy character byte-stream to SCLP buffer */
  97. memcpy(buf, &cons->iov[cons->iov_sclp], cons->iov_sclp_rest);
  98. *size = cons->iov_sclp_rest + 1;
  99. cons->iov_sclp = 0;
  100. cons->iov_bs = 0;
  101. cons->iov_data_len = 0;
  102. cons->iov_sclp_rest = 0;
  103. event->event_pending = false;
  104. /* data provided and no more data pending */
  105. } else {
  106. /* if provided buffer is too small, just copy part */
  107. memcpy(buf, &cons->iov[cons->iov_sclp], avail);
  108. *size = avail + 1;
  109. cons->iov_sclp_rest -= avail;
  110. cons->iov_sclp += avail;
  111. /* more data pending */
  112. }
  113. if (cons->notify) {
  114. cons->notify = false;
  115. qemu_notify_event();
  116. }
  117. }
  118. static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
  119. int *slen)
  120. {
  121. int avail;
  122. size_t src_len;
  123. uint8_t *to;
  124. ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
  125. if (!event->event_pending) {
  126. /* no data pending */
  127. return 0;
  128. }
  129. to = (uint8_t *)&acd->data;
  130. avail = *slen - sizeof(ASCIIConsoleData);
  131. get_console_data(event, to, &src_len, avail);
  132. acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
  133. acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
  134. acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
  135. *slen = avail - src_len;
  136. return 1;
  137. }
  138. /* triggered by SCLP's write_event_data
  139. * - write console data to character layer
  140. * returns < 0 if an error occurred
  141. */
  142. static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
  143. size_t len)
  144. {
  145. SCLPConsole *scon = SCLP_CONSOLE(event);
  146. if (!qemu_chr_fe_backend_connected(&scon->chr)) {
  147. /* If there's no backend, we can just say we consumed all data. */
  148. return len;
  149. }
  150. /* XXX this blocks entire thread. Rewrite to use
  151. * qemu_chr_fe_write and background I/O callbacks */
  152. return qemu_chr_fe_write_all(&scon->chr, buf, len);
  153. }
  154. static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
  155. {
  156. int rc;
  157. int length;
  158. ssize_t written;
  159. ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
  160. length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
  161. written = write_console_data(event, (uint8_t *)acd->data, length);
  162. rc = SCLP_RC_NORMAL_COMPLETION;
  163. /* set event buffer accepted flag */
  164. evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
  165. /* written will be zero if a pty is not connected - don't treat as error */
  166. if (written < 0) {
  167. /* event buffer not accepted due to error in character layer */
  168. evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
  169. rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
  170. }
  171. return rc;
  172. }
  173. static const VMStateDescription vmstate_sclpconsole = {
  174. .name = "sclpconsole",
  175. .version_id = 0,
  176. .minimum_version_id = 0,
  177. .fields = (const VMStateField[]) {
  178. VMSTATE_BOOL(event.event_pending, SCLPConsole),
  179. VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220),
  180. VMSTATE_UINT32(iov_sclp, SCLPConsole),
  181. VMSTATE_UINT32(iov_bs, SCLPConsole),
  182. VMSTATE_UINT32(iov_data_len, SCLPConsole),
  183. VMSTATE_UINT32(iov_sclp_rest, SCLPConsole),
  184. VMSTATE_END_OF_LIST()
  185. }
  186. };
  187. /* qemu object creation and initialization functions */
  188. /* tell character layer our call-back functions */
  189. static int console_init(SCLPEvent *event)
  190. {
  191. static bool console_available;
  192. SCLPConsole *scon = SCLP_CONSOLE(event);
  193. if (console_available) {
  194. error_report("Multiple VT220 operator consoles are not supported");
  195. return -1;
  196. }
  197. console_available = true;
  198. qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
  199. chr_read, NULL, NULL, scon, NULL, true);
  200. return 0;
  201. }
  202. static void console_reset(DeviceState *dev)
  203. {
  204. SCLPEvent *event = SCLP_EVENT(dev);
  205. SCLPConsole *scon = SCLP_CONSOLE(event);
  206. event->event_pending = false;
  207. scon->iov_sclp = 0;
  208. scon->iov_bs = 0;
  209. scon->iov_data_len = 0;
  210. scon->iov_sclp_rest = 0;
  211. scon->notify = false;
  212. }
  213. static Property console_properties[] = {
  214. DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
  215. DEFINE_PROP_END_OF_LIST(),
  216. };
  217. static void console_class_init(ObjectClass *klass, void *data)
  218. {
  219. DeviceClass *dc = DEVICE_CLASS(klass);
  220. SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
  221. device_class_set_props(dc, console_properties);
  222. device_class_set_legacy_reset(dc, console_reset);
  223. dc->vmsd = &vmstate_sclpconsole;
  224. ec->init = console_init;
  225. ec->get_send_mask = send_mask;
  226. ec->get_receive_mask = receive_mask;
  227. ec->can_handle_event = can_handle_event;
  228. ec->read_event_data = read_event_data;
  229. ec->write_event_data = write_event_data;
  230. set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
  231. }
  232. static const TypeInfo sclp_console_info = {
  233. .name = TYPE_SCLP_CONSOLE,
  234. .parent = TYPE_SCLP_EVENT,
  235. .instance_size = sizeof(SCLPConsole),
  236. .class_init = console_class_init,
  237. .class_size = sizeof(SCLPEventClass),
  238. };
  239. static void register_types(void)
  240. {
  241. type_register_static(&sclp_console_info);
  242. }
  243. type_init(register_types)