sclpconsole.c 8.0 KB

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