char-ringbuf.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * QEMU System Emulator
  3. *
  4. * Copyright (c) 2003-2008 Fabrice Bellard
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "qemu/osdep.h"
  25. #include "chardev/char.h"
  26. #include "qapi/error.h"
  27. #include "qapi/qapi-commands-char.h"
  28. #include "qemu/base64.h"
  29. #include "qemu/module.h"
  30. #include "qemu/option.h"
  31. #include "qom/object.h"
  32. /* Ring buffer chardev */
  33. struct RingBufChardev {
  34. Chardev parent;
  35. size_t size;
  36. size_t prod;
  37. size_t cons;
  38. uint8_t *cbuf;
  39. };
  40. typedef struct RingBufChardev RingBufChardev;
  41. DECLARE_INSTANCE_CHECKER(RingBufChardev, RINGBUF_CHARDEV,
  42. TYPE_CHARDEV_RINGBUF)
  43. static size_t ringbuf_count(const Chardev *chr)
  44. {
  45. const RingBufChardev *d = RINGBUF_CHARDEV(chr);
  46. return d->prod - d->cons;
  47. }
  48. static int ringbuf_chr_write(Chardev *chr, const uint8_t *buf, int len)
  49. {
  50. RingBufChardev *d = RINGBUF_CHARDEV(chr);
  51. int i;
  52. if (!buf || (len < 0)) {
  53. return -1;
  54. }
  55. for (i = 0; i < len; i++) {
  56. d->cbuf[d->prod++ & (d->size - 1)] = buf[i];
  57. if (d->prod - d->cons > d->size) {
  58. d->cons = d->prod - d->size;
  59. }
  60. }
  61. return len;
  62. }
  63. static int ringbuf_chr_read(Chardev *chr, uint8_t *buf, int len)
  64. {
  65. RingBufChardev *d = RINGBUF_CHARDEV(chr);
  66. int i;
  67. qemu_mutex_lock(&chr->chr_write_lock);
  68. for (i = 0; i < len && d->cons != d->prod; i++) {
  69. buf[i] = d->cbuf[d->cons++ & (d->size - 1)];
  70. }
  71. qemu_mutex_unlock(&chr->chr_write_lock);
  72. return i;
  73. }
  74. static void char_ringbuf_finalize(Object *obj)
  75. {
  76. RingBufChardev *d = RINGBUF_CHARDEV(obj);
  77. g_free(d->cbuf);
  78. }
  79. static void qemu_chr_open_ringbuf(Chardev *chr,
  80. ChardevBackend *backend,
  81. bool *be_opened,
  82. Error **errp)
  83. {
  84. ChardevRingbuf *opts = backend->u.ringbuf.data;
  85. RingBufChardev *d = RINGBUF_CHARDEV(chr);
  86. d->size = opts->has_size ? opts->size : 65536;
  87. /* The size must be power of 2 */
  88. if (d->size & (d->size - 1)) {
  89. error_setg(errp, "size of ringbuf chardev must be power of two");
  90. return;
  91. }
  92. d->prod = 0;
  93. d->cons = 0;
  94. d->cbuf = g_malloc0(d->size);
  95. }
  96. void qmp_ringbuf_write(const char *device, const char *data,
  97. bool has_format, enum DataFormat format,
  98. Error **errp)
  99. {
  100. Chardev *chr;
  101. const uint8_t *write_data;
  102. int ret;
  103. gsize write_count;
  104. chr = qemu_chr_find(device);
  105. if (!chr) {
  106. error_setg(errp, "Device '%s' not found", device);
  107. return;
  108. }
  109. if (!CHARDEV_IS_RINGBUF(chr)) {
  110. error_setg(errp, "%s is not a ringbuf device", device);
  111. return;
  112. }
  113. if (has_format && (format == DATA_FORMAT_BASE64)) {
  114. write_data = qbase64_decode(data, -1,
  115. &write_count,
  116. errp);
  117. if (!write_data) {
  118. return;
  119. }
  120. } else {
  121. write_data = (uint8_t *)data;
  122. write_count = strlen(data);
  123. }
  124. ret = ringbuf_chr_write(chr, write_data, write_count);
  125. if (write_data != (uint8_t *)data) {
  126. g_free((void *)write_data);
  127. }
  128. if (ret < 0) {
  129. error_setg(errp, "Failed to write to device %s", device);
  130. return;
  131. }
  132. }
  133. char *qmp_ringbuf_read(const char *device, int64_t size,
  134. bool has_format, enum DataFormat format,
  135. Error **errp)
  136. {
  137. Chardev *chr;
  138. uint8_t *read_data;
  139. size_t count;
  140. char *data;
  141. chr = qemu_chr_find(device);
  142. if (!chr) {
  143. error_setg(errp, "Device '%s' not found", device);
  144. return NULL;
  145. }
  146. if (!CHARDEV_IS_RINGBUF(chr)) {
  147. error_setg(errp, "%s is not a ringbuf device", device);
  148. return NULL;
  149. }
  150. if (size <= 0) {
  151. error_setg(errp, "size must be greater than zero");
  152. return NULL;
  153. }
  154. count = ringbuf_count(chr);
  155. size = size > count ? count : size;
  156. read_data = g_malloc(size + 1);
  157. ringbuf_chr_read(chr, read_data, size);
  158. if (has_format && (format == DATA_FORMAT_BASE64)) {
  159. data = g_base64_encode(read_data, size);
  160. g_free(read_data);
  161. } else {
  162. /*
  163. * FIXME should read only complete, valid UTF-8 characters up
  164. * to @size bytes. Invalid sequences should be replaced by a
  165. * suitable replacement character. Except when (and only
  166. * when) ring buffer lost characters since last read, initial
  167. * continuation characters should be dropped.
  168. */
  169. read_data[size] = 0;
  170. data = (char *)read_data;
  171. }
  172. return data;
  173. }
  174. static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend,
  175. Error **errp)
  176. {
  177. int val;
  178. ChardevRingbuf *ringbuf;
  179. backend->type = CHARDEV_BACKEND_KIND_RINGBUF;
  180. ringbuf = backend->u.ringbuf.data = g_new0(ChardevRingbuf, 1);
  181. qemu_chr_parse_common(opts, qapi_ChardevRingbuf_base(ringbuf));
  182. val = qemu_opt_get_size(opts, "size", 0);
  183. if (val != 0) {
  184. ringbuf->has_size = true;
  185. ringbuf->size = val;
  186. }
  187. }
  188. static void char_ringbuf_class_init(ObjectClass *oc, void *data)
  189. {
  190. ChardevClass *cc = CHARDEV_CLASS(oc);
  191. cc->parse = qemu_chr_parse_ringbuf;
  192. cc->open = qemu_chr_open_ringbuf;
  193. cc->chr_write = ringbuf_chr_write;
  194. }
  195. static const TypeInfo char_ringbuf_type_info = {
  196. .name = TYPE_CHARDEV_RINGBUF,
  197. .parent = TYPE_CHARDEV,
  198. .class_init = char_ringbuf_class_init,
  199. .instance_size = sizeof(RingBufChardev),
  200. .instance_finalize = char_ringbuf_finalize,
  201. };
  202. /* Bug-compatibility: */
  203. static const TypeInfo char_memory_type_info = {
  204. .name = TYPE_CHARDEV_MEMORY,
  205. .parent = TYPE_CHARDEV_RINGBUF,
  206. };
  207. static void register_types(void)
  208. {
  209. type_register_static(&char_ringbuf_type_info);
  210. type_register_static(&char_memory_type_info);
  211. }
  212. type_init(register_types);