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