2
0

guestfd.c 4.1 KB

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