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