guestfd.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * Hosted file support for semihosting syscalls.
  3. *
  4. * Copyright (c) 2005, 2007 CodeSourcery.
  5. * Copyright (c) 2019 Linaro
  6. * Copyright © 2020 by Keith Packard <keithp@keithp.com>
  7. *
  8. * SPDX-License-Identifier: GPL-2.0-or-later
  9. */
  10. #include "qemu/osdep.h"
  11. #include "gdbstub/syscalls.h"
  12. #include "semihosting/semihost.h"
  13. #include "semihosting/guestfd.h"
  14. #ifndef CONFIG_USER_ONLY
  15. #include CONFIG_DEVICES
  16. #endif
  17. static GArray *guestfd_array;
  18. #ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
  19. GuestFD console_in_gf;
  20. GuestFD console_out_gf;
  21. #endif
  22. void qemu_semihosting_guestfd_init(void)
  23. {
  24. /* New entries zero-initialized, i.e. type GuestFDUnused */
  25. guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
  26. #ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
  27. /* For ARM-compat, the console is in a separate namespace. */
  28. if (use_gdb_syscalls()) {
  29. console_in_gf.type = GuestFDGDB;
  30. console_in_gf.hostfd = 0;
  31. console_out_gf.type = GuestFDGDB;
  32. console_out_gf.hostfd = 2;
  33. } else {
  34. console_in_gf.type = GuestFDConsole;
  35. console_out_gf.type = GuestFDConsole;
  36. }
  37. #else
  38. /* Otherwise, the stdio file descriptors apply. */
  39. guestfd_array = g_array_set_size(guestfd_array, 3);
  40. #ifndef CONFIG_USER_ONLY
  41. if (!use_gdb_syscalls()) {
  42. GuestFD *gf = &g_array_index(guestfd_array, GuestFD, 0);
  43. gf[0].type = GuestFDConsole;
  44. gf[1].type = GuestFDConsole;
  45. gf[2].type = GuestFDConsole;
  46. return;
  47. }
  48. #endif
  49. associate_guestfd(0, 0);
  50. associate_guestfd(1, 1);
  51. associate_guestfd(2, 2);
  52. #endif
  53. }
  54. /*
  55. * Allocate a new guest file descriptor and return it; if we
  56. * couldn't allocate a new fd then return -1.
  57. * This is a fairly simplistic implementation because we don't
  58. * expect that most semihosting guest programs will make very
  59. * heavy use of opening and closing fds.
  60. */
  61. int alloc_guestfd(void)
  62. {
  63. guint i;
  64. /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */
  65. for (i = 1; i < guestfd_array->len; i++) {
  66. GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
  67. if (gf->type == GuestFDUnused) {
  68. return i;
  69. }
  70. }
  71. /* All elements already in use: expand the array */
  72. g_array_set_size(guestfd_array, i + 1);
  73. return i;
  74. }
  75. static void do_dealloc_guestfd(GuestFD *gf)
  76. {
  77. gf->type = GuestFDUnused;
  78. }
  79. /*
  80. * Look up the guestfd in the data structure; return NULL
  81. * for out of bounds, but don't check whether the slot is unused.
  82. * This is used internally by the other guestfd functions.
  83. */
  84. static GuestFD *do_get_guestfd(int guestfd)
  85. {
  86. if (guestfd < 0 || guestfd >= guestfd_array->len) {
  87. return NULL;
  88. }
  89. return &g_array_index(guestfd_array, GuestFD, guestfd);
  90. }
  91. /*
  92. * Given a guest file descriptor, get the associated struct.
  93. * If the fd is not valid, return NULL. This is the function
  94. * used by the various semihosting calls to validate a handle
  95. * from the guest.
  96. * Note: calling alloc_guestfd() or dealloc_guestfd() will
  97. * invalidate any GuestFD* obtained by calling this function.
  98. */
  99. GuestFD *get_guestfd(int guestfd)
  100. {
  101. GuestFD *gf = do_get_guestfd(guestfd);
  102. if (!gf || gf->type == GuestFDUnused) {
  103. return NULL;
  104. }
  105. return gf;
  106. }
  107. /*
  108. * Associate the specified guest fd (which must have been
  109. * allocated via alloc_fd() and not previously used) with
  110. * the specified host/gdb fd.
  111. */
  112. void associate_guestfd(int guestfd, int hostfd)
  113. {
  114. GuestFD *gf = do_get_guestfd(guestfd);
  115. assert(gf);
  116. gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
  117. gf->hostfd = hostfd;
  118. }
  119. void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len)
  120. {
  121. GuestFD *gf = do_get_guestfd(guestfd);
  122. assert(gf);
  123. gf->type = GuestFDStatic;
  124. gf->staticfile.data = data;
  125. gf->staticfile.len = len;
  126. gf->staticfile.off = 0;
  127. }
  128. /*
  129. * Deallocate the specified guest file descriptor. This doesn't
  130. * close the host fd, it merely undoes the work of alloc_fd().
  131. */
  132. void dealloc_guestfd(int guestfd)
  133. {
  134. GuestFD *gf = do_get_guestfd(guestfd);
  135. assert(gf);
  136. do_dealloc_guestfd(gf);
  137. }