config.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * Semihosting configuration
  3. *
  4. * Copyright (c) 2015 Imagination Technologies
  5. * Copyright (c) 2019 Linaro Ltd
  6. *
  7. * This controls the configuration of semihosting for all guest
  8. * targets that support it. Architecture specific handling is handled
  9. * in target/HW/HW-semi.c
  10. *
  11. * Semihosting is sightly strange in that it is also supported by some
  12. * linux-user targets. However in that use case no configuration of
  13. * the outputs and command lines is supported.
  14. *
  15. * The config module is common to all softmmu targets however as vl.c
  16. * needs to link against the helpers.
  17. *
  18. * SPDX-License-Identifier: GPL-2.0-or-later
  19. */
  20. #include "qemu/osdep.h"
  21. #include "qemu/option.h"
  22. #include "qemu/config-file.h"
  23. #include "qemu/error-report.h"
  24. #include "hw/semihosting/semihost.h"
  25. #include "chardev/char.h"
  26. #include "sysemu/sysemu.h"
  27. QemuOptsList qemu_semihosting_config_opts = {
  28. .name = "semihosting-config",
  29. .implied_opt_name = "enable",
  30. .head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head),
  31. .desc = {
  32. {
  33. .name = "enable",
  34. .type = QEMU_OPT_BOOL,
  35. }, {
  36. .name = "target",
  37. .type = QEMU_OPT_STRING,
  38. }, {
  39. .name = "chardev",
  40. .type = QEMU_OPT_STRING,
  41. }, {
  42. .name = "arg",
  43. .type = QEMU_OPT_STRING,
  44. },
  45. { /* end of list */ }
  46. },
  47. };
  48. typedef struct SemihostingConfig {
  49. bool enabled;
  50. SemihostingTarget target;
  51. Chardev *chardev;
  52. const char **argv;
  53. int argc;
  54. const char *cmdline; /* concatenated argv */
  55. } SemihostingConfig;
  56. static SemihostingConfig semihosting;
  57. static const char *semihost_chardev;
  58. bool semihosting_enabled(void)
  59. {
  60. return semihosting.enabled;
  61. }
  62. SemihostingTarget semihosting_get_target(void)
  63. {
  64. return semihosting.target;
  65. }
  66. const char *semihosting_get_arg(int i)
  67. {
  68. if (i >= semihosting.argc) {
  69. return NULL;
  70. }
  71. return semihosting.argv[i];
  72. }
  73. int semihosting_get_argc(void)
  74. {
  75. return semihosting.argc;
  76. }
  77. const char *semihosting_get_cmdline(void)
  78. {
  79. if (semihosting.cmdline == NULL && semihosting.argc > 0) {
  80. semihosting.cmdline = g_strjoinv(" ", (gchar **)semihosting.argv);
  81. }
  82. return semihosting.cmdline;
  83. }
  84. static int add_semihosting_arg(void *opaque,
  85. const char *name, const char *val,
  86. Error **errp)
  87. {
  88. SemihostingConfig *s = opaque;
  89. if (strcmp(name, "arg") == 0) {
  90. s->argc++;
  91. /* one extra element as g_strjoinv() expects NULL-terminated array */
  92. s->argv = g_realloc(s->argv, (s->argc + 1) * sizeof(void *));
  93. s->argv[s->argc - 1] = val;
  94. s->argv[s->argc] = NULL;
  95. }
  96. return 0;
  97. }
  98. /* Use strings passed via -kernel/-append to initialize semihosting.argv[] */
  99. void semihosting_arg_fallback(const char *file, const char *cmd)
  100. {
  101. char *cmd_token;
  102. /* argv[0] */
  103. add_semihosting_arg(&semihosting, "arg", file, NULL);
  104. /* split -append and initialize argv[1..n] */
  105. cmd_token = strtok(g_strdup(cmd), " ");
  106. while (cmd_token) {
  107. add_semihosting_arg(&semihosting, "arg", cmd_token, NULL);
  108. cmd_token = strtok(NULL, " ");
  109. }
  110. }
  111. Chardev *semihosting_get_chardev(void)
  112. {
  113. return semihosting.chardev;
  114. }
  115. void qemu_semihosting_enable(void)
  116. {
  117. semihosting.enabled = true;
  118. semihosting.target = SEMIHOSTING_TARGET_AUTO;
  119. }
  120. int qemu_semihosting_config_options(const char *optarg)
  121. {
  122. QemuOptsList *opt_list = qemu_find_opts("semihosting-config");
  123. QemuOpts *opts = qemu_opts_parse_noisily(opt_list, optarg, false);
  124. semihosting.enabled = true;
  125. if (opts != NULL) {
  126. semihosting.enabled = qemu_opt_get_bool(opts, "enable",
  127. true);
  128. const char *target = qemu_opt_get(opts, "target");
  129. /* setup of chardev is deferred until they are initialised */
  130. semihost_chardev = qemu_opt_get(opts, "chardev");
  131. if (target != NULL) {
  132. if (strcmp("native", target) == 0) {
  133. semihosting.target = SEMIHOSTING_TARGET_NATIVE;
  134. } else if (strcmp("gdb", target) == 0) {
  135. semihosting.target = SEMIHOSTING_TARGET_GDB;
  136. } else if (strcmp("auto", target) == 0) {
  137. semihosting.target = SEMIHOSTING_TARGET_AUTO;
  138. } else {
  139. error_report("unsupported semihosting-config %s",
  140. optarg);
  141. return 1;
  142. }
  143. } else {
  144. semihosting.target = SEMIHOSTING_TARGET_AUTO;
  145. }
  146. /* Set semihosting argument count and vector */
  147. qemu_opt_foreach(opts, add_semihosting_arg,
  148. &semihosting, NULL);
  149. } else {
  150. error_report("unsupported semihosting-config %s", optarg);
  151. return 1;
  152. }
  153. return 0;
  154. }
  155. void qemu_semihosting_connect_chardevs(void)
  156. {
  157. /* We had to defer this until chardevs were created */
  158. if (semihost_chardev) {
  159. Chardev *chr = qemu_chr_find(semihost_chardev);
  160. if (chr == NULL) {
  161. error_report("semihosting chardev '%s' not found",
  162. semihost_chardev);
  163. exit(1);
  164. }
  165. semihosting.chardev = chr;
  166. }
  167. }