11c6ff720SRichard Henderson /* 21c6ff720SRichard Henderson * Hosted file support for semihosting syscalls. 31c6ff720SRichard Henderson * 41c6ff720SRichard Henderson * Copyright (c) 2005, 2007 CodeSourcery. 51c6ff720SRichard Henderson * Copyright (c) 2019 Linaro 61c6ff720SRichard Henderson * Copyright © 2020 by Keith Packard <keithp@keithp.com> 71c6ff720SRichard Henderson * 81c6ff720SRichard Henderson * SPDX-License-Identifier: GPL-2.0-or-later 91c6ff720SRichard Henderson */ 101c6ff720SRichard Henderson 111c6ff720SRichard Henderson #include "qemu/osdep.h" 121c6ff720SRichard Henderson #include "exec/gdbstub.h" 13*e4a4aaa5SRichard Henderson #include "semihosting/semihost.h" 141c6ff720SRichard Henderson #include "semihosting/guestfd.h" 155b3f39cbSRichard Henderson #ifdef CONFIG_USER_ONLY 165b3f39cbSRichard Henderson #include "qemu.h" 175b3f39cbSRichard Henderson #else 185b3f39cbSRichard Henderson #include "semihosting/softmmu-uaccess.h" 19*e4a4aaa5SRichard Henderson #include CONFIG_DEVICES 205b3f39cbSRichard Henderson #endif 211c6ff720SRichard Henderson 221c6ff720SRichard Henderson static GArray *guestfd_array; 231c6ff720SRichard Henderson 24*e4a4aaa5SRichard Henderson #ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING 25*e4a4aaa5SRichard Henderson GuestFD console_in_gf; 26*e4a4aaa5SRichard Henderson GuestFD console_out_gf; 27*e4a4aaa5SRichard Henderson #endif 28*e4a4aaa5SRichard Henderson 29*e4a4aaa5SRichard Henderson void qemu_semihosting_guestfd_init(void) 30*e4a4aaa5SRichard Henderson { 31*e4a4aaa5SRichard Henderson /* New entries zero-initialized, i.e. type GuestFDUnused */ 32*e4a4aaa5SRichard Henderson guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD)); 33*e4a4aaa5SRichard Henderson 34*e4a4aaa5SRichard Henderson #ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING 35*e4a4aaa5SRichard Henderson /* For ARM-compat, the console is in a separate namespace. */ 36*e4a4aaa5SRichard Henderson if (use_gdb_syscalls()) { 37*e4a4aaa5SRichard Henderson console_in_gf.type = GuestFDGDB; 38*e4a4aaa5SRichard Henderson console_in_gf.hostfd = 0; 39*e4a4aaa5SRichard Henderson console_out_gf.type = GuestFDGDB; 40*e4a4aaa5SRichard Henderson console_out_gf.hostfd = 2; 41*e4a4aaa5SRichard Henderson } else { 42*e4a4aaa5SRichard Henderson console_in_gf.type = GuestFDConsole; 43*e4a4aaa5SRichard Henderson console_out_gf.type = GuestFDConsole; 44*e4a4aaa5SRichard Henderson } 45*e4a4aaa5SRichard Henderson #else 46*e4a4aaa5SRichard Henderson /* Otherwise, the stdio file descriptors apply. */ 47*e4a4aaa5SRichard Henderson guestfd_array = g_array_set_size(guestfd_array, 3); 48*e4a4aaa5SRichard Henderson #ifndef CONFIG_USER_ONLY 49*e4a4aaa5SRichard Henderson if (!use_gdb_syscalls()) { 50*e4a4aaa5SRichard Henderson GuestFD *gf = &g_array_index(guestfd_array, GuestFD, 0); 51*e4a4aaa5SRichard Henderson gf[0].type = GuestFDConsole; 52*e4a4aaa5SRichard Henderson gf[1].type = GuestFDConsole; 53*e4a4aaa5SRichard Henderson gf[2].type = GuestFDConsole; 54*e4a4aaa5SRichard Henderson return; 55*e4a4aaa5SRichard Henderson } 56*e4a4aaa5SRichard Henderson #endif 57*e4a4aaa5SRichard Henderson associate_guestfd(0, 0); 58*e4a4aaa5SRichard Henderson associate_guestfd(1, 1); 59*e4a4aaa5SRichard Henderson associate_guestfd(2, 2); 60*e4a4aaa5SRichard Henderson #endif 61*e4a4aaa5SRichard Henderson } 62*e4a4aaa5SRichard Henderson 631c6ff720SRichard Henderson /* 641c6ff720SRichard Henderson * Allocate a new guest file descriptor and return it; if we 651c6ff720SRichard Henderson * couldn't allocate a new fd then return -1. 661c6ff720SRichard Henderson * This is a fairly simplistic implementation because we don't 671c6ff720SRichard Henderson * expect that most semihosting guest programs will make very 681c6ff720SRichard Henderson * heavy use of opening and closing fds. 691c6ff720SRichard Henderson */ 701c6ff720SRichard Henderson int alloc_guestfd(void) 711c6ff720SRichard Henderson { 721c6ff720SRichard Henderson guint i; 731c6ff720SRichard Henderson 741c6ff720SRichard Henderson /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */ 751c6ff720SRichard Henderson for (i = 1; i < guestfd_array->len; i++) { 761c6ff720SRichard Henderson GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i); 771c6ff720SRichard Henderson 781c6ff720SRichard Henderson if (gf->type == GuestFDUnused) { 791c6ff720SRichard Henderson return i; 801c6ff720SRichard Henderson } 811c6ff720SRichard Henderson } 821c6ff720SRichard Henderson 831c6ff720SRichard Henderson /* All elements already in use: expand the array */ 841c6ff720SRichard Henderson g_array_set_size(guestfd_array, i + 1); 851c6ff720SRichard Henderson return i; 861c6ff720SRichard Henderson } 871c6ff720SRichard Henderson 885eadbbfcSRichard Henderson static void do_dealloc_guestfd(GuestFD *gf) 895eadbbfcSRichard Henderson { 905eadbbfcSRichard Henderson gf->type = GuestFDUnused; 915eadbbfcSRichard Henderson } 925eadbbfcSRichard Henderson 931c6ff720SRichard Henderson /* 941c6ff720SRichard Henderson * Look up the guestfd in the data structure; return NULL 951c6ff720SRichard Henderson * for out of bounds, but don't check whether the slot is unused. 961c6ff720SRichard Henderson * This is used internally by the other guestfd functions. 971c6ff720SRichard Henderson */ 981c6ff720SRichard Henderson static GuestFD *do_get_guestfd(int guestfd) 991c6ff720SRichard Henderson { 100*e4a4aaa5SRichard Henderson if (guestfd < 0 || guestfd >= guestfd_array->len) { 1011c6ff720SRichard Henderson return NULL; 1021c6ff720SRichard Henderson } 1031c6ff720SRichard Henderson 1041c6ff720SRichard Henderson return &g_array_index(guestfd_array, GuestFD, guestfd); 1051c6ff720SRichard Henderson } 1061c6ff720SRichard Henderson 1071c6ff720SRichard Henderson /* 1081c6ff720SRichard Henderson * Given a guest file descriptor, get the associated struct. 1091c6ff720SRichard Henderson * If the fd is not valid, return NULL. This is the function 1101c6ff720SRichard Henderson * used by the various semihosting calls to validate a handle 1111c6ff720SRichard Henderson * from the guest. 1121c6ff720SRichard Henderson * Note: calling alloc_guestfd() or dealloc_guestfd() will 1131c6ff720SRichard Henderson * invalidate any GuestFD* obtained by calling this function. 1141c6ff720SRichard Henderson */ 1151c6ff720SRichard Henderson GuestFD *get_guestfd(int guestfd) 1161c6ff720SRichard Henderson { 1171c6ff720SRichard Henderson GuestFD *gf = do_get_guestfd(guestfd); 1181c6ff720SRichard Henderson 1191c6ff720SRichard Henderson if (!gf || gf->type == GuestFDUnused) { 1201c6ff720SRichard Henderson return NULL; 1211c6ff720SRichard Henderson } 1221c6ff720SRichard Henderson return gf; 1231c6ff720SRichard Henderson } 1241c6ff720SRichard Henderson 1251c6ff720SRichard Henderson /* 1261c6ff720SRichard Henderson * Associate the specified guest fd (which must have been 1271c6ff720SRichard Henderson * allocated via alloc_fd() and not previously used) with 1281c6ff720SRichard Henderson * the specified host/gdb fd. 1291c6ff720SRichard Henderson */ 1301c6ff720SRichard Henderson void associate_guestfd(int guestfd, int hostfd) 1311c6ff720SRichard Henderson { 1321c6ff720SRichard Henderson GuestFD *gf = do_get_guestfd(guestfd); 1331c6ff720SRichard Henderson 1341c6ff720SRichard Henderson assert(gf); 1351c6ff720SRichard Henderson gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost; 1361c6ff720SRichard Henderson gf->hostfd = hostfd; 1371c6ff720SRichard Henderson } 1381c6ff720SRichard Henderson 1391c6ff720SRichard Henderson void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len) 1401c6ff720SRichard Henderson { 1411c6ff720SRichard Henderson GuestFD *gf = do_get_guestfd(guestfd); 1421c6ff720SRichard Henderson 1431c6ff720SRichard Henderson assert(gf); 1441c6ff720SRichard Henderson gf->type = GuestFDStatic; 1451c6ff720SRichard Henderson gf->staticfile.data = data; 1461c6ff720SRichard Henderson gf->staticfile.len = len; 1471c6ff720SRichard Henderson gf->staticfile.off = 0; 1481c6ff720SRichard Henderson } 1491c6ff720SRichard Henderson 1501c6ff720SRichard Henderson /* 1511c6ff720SRichard Henderson * Deallocate the specified guest file descriptor. This doesn't 1521c6ff720SRichard Henderson * close the host fd, it merely undoes the work of alloc_fd(). 1531c6ff720SRichard Henderson */ 1541c6ff720SRichard Henderson void dealloc_guestfd(int guestfd) 1551c6ff720SRichard Henderson { 1561c6ff720SRichard Henderson GuestFD *gf = do_get_guestfd(guestfd); 1571c6ff720SRichard Henderson 1581c6ff720SRichard Henderson assert(gf); 1595eadbbfcSRichard Henderson do_dealloc_guestfd(gf); 1601c6ff720SRichard Henderson } 161