2
0

config.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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 slightly 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 system 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 "semihosting/semihost.h"
  25. #include "chardev/char.h"
  26. QemuOptsList qemu_semihosting_config_opts = {
  27. .name = "semihosting-config",
  28. .merge_lists = true,
  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 = "userspace",
  37. .type = QEMU_OPT_BOOL,
  38. }, {
  39. .name = "target",
  40. .type = QEMU_OPT_STRING,
  41. }, {
  42. .name = "chardev",
  43. .type = QEMU_OPT_STRING,
  44. }, {
  45. .name = "arg",
  46. .type = QEMU_OPT_STRING,
  47. },
  48. { /* end of list */ }
  49. },
  50. };
  51. typedef struct SemihostingConfig {
  52. bool enabled;
  53. bool userspace_enabled;
  54. SemihostingTarget target;
  55. char **argv;
  56. int argc;
  57. const char *cmdline; /* concatenated argv */
  58. } SemihostingConfig;
  59. static SemihostingConfig semihosting;
  60. static const char *semihost_chardev;
  61. bool semihosting_enabled(bool is_user)
  62. {
  63. return semihosting.enabled && (!is_user || semihosting.userspace_enabled);
  64. }
  65. SemihostingTarget semihosting_get_target(void)
  66. {
  67. return semihosting.target;
  68. }
  69. const char *semihosting_get_arg(int i)
  70. {
  71. if (i >= semihosting.argc) {
  72. return NULL;
  73. }
  74. return semihosting.argv[i];
  75. }
  76. int semihosting_get_argc(void)
  77. {
  78. return semihosting.argc;
  79. }
  80. const char *semihosting_get_cmdline(void)
  81. {
  82. if (semihosting.cmdline == NULL && semihosting.argc > 0) {
  83. semihosting.cmdline = g_strjoinv(" ", (gchar **)semihosting.argv);
  84. }
  85. return semihosting.cmdline;
  86. }
  87. static int add_semihosting_arg(void *opaque,
  88. const char *name, const char *val,
  89. Error **errp)
  90. {
  91. SemihostingConfig *s = opaque;
  92. if (strcmp(name, "arg") == 0) {
  93. s->argc++;
  94. /* one extra element as g_strjoinv() expects NULL-terminated array */
  95. s->argv = g_renew(char *, s->argv, s->argc + 1);
  96. s->argv[s->argc - 1] = g_strdup(val);
  97. s->argv[s->argc] = NULL;
  98. }
  99. return 0;
  100. }
  101. /* Use strings passed via -kernel/-append to initialize semihosting.argv[] */
  102. void semihosting_arg_fallback(const char *file, const char *cmd)
  103. {
  104. char *cmd_token;
  105. g_autofree char *cmd_dup = g_strdup(cmd);
  106. /* argv[0] */
  107. add_semihosting_arg(&semihosting, "arg", file, NULL);
  108. /* split -append and initialize argv[1..n] */
  109. cmd_token = strtok(cmd_dup, " ");
  110. while (cmd_token) {
  111. add_semihosting_arg(&semihosting, "arg", cmd_token, NULL);
  112. cmd_token = strtok(NULL, " ");
  113. }
  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 *optstr)
  121. {
  122. QemuOptsList *opt_list = qemu_find_opts("semihosting-config");
  123. QemuOpts *opts = qemu_opts_parse_noisily(opt_list, optstr, false);
  124. semihosting.enabled = true;
  125. if (opts != NULL) {
  126. semihosting.enabled = qemu_opt_get_bool(opts, "enable",
  127. true);
  128. semihosting.userspace_enabled = qemu_opt_get_bool(opts, "userspace",
  129. false);
  130. const char *target = qemu_opt_get(opts, "target");
  131. /* setup of chardev is deferred until they are initialised */
  132. semihost_chardev = qemu_opt_get(opts, "chardev");
  133. if (target != NULL) {
  134. if (strcmp("native", target) == 0) {
  135. semihosting.target = SEMIHOSTING_TARGET_NATIVE;
  136. } else if (strcmp("gdb", target) == 0) {
  137. semihosting.target = SEMIHOSTING_TARGET_GDB;
  138. } else if (strcmp("auto", target) == 0) {
  139. semihosting.target = SEMIHOSTING_TARGET_AUTO;
  140. } else {
  141. error_report("unsupported semihosting-config %s",
  142. optstr);
  143. return 1;
  144. }
  145. } else {
  146. semihosting.target = SEMIHOSTING_TARGET_AUTO;
  147. }
  148. /* Set semihosting argument count and vector */
  149. qemu_opt_foreach(opts, add_semihosting_arg,
  150. &semihosting, NULL);
  151. } else {
  152. error_report("unsupported semihosting-config %s", optstr);
  153. return 1;
  154. }
  155. return 0;
  156. }
  157. /* We had to defer this until chardevs were created */
  158. void qemu_semihosting_chardev_init(void)
  159. {
  160. Chardev *chr = NULL;
  161. if (semihost_chardev) {
  162. chr = qemu_chr_find(semihost_chardev);
  163. if (chr == NULL) {
  164. error_report("semihosting chardev '%s' not found",
  165. semihost_chardev);
  166. exit(1);
  167. }
  168. }
  169. qemu_semihosting_console_init(chr);
  170. }