qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

guestfd.c (4188B)


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