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