xref: /qemu/target/mips/tcg/system/mips-semi.c (revision 7ba6e53a9ddf9b4ae04ad5fc658105440889cf17)
13b3c1694SLeon Alrae /*
23b3c1694SLeon Alrae  * Unified Hosting Interface syscalls.
33b3c1694SLeon Alrae  *
43b3c1694SLeon Alrae  * Copyright (c) 2015 Imagination Technologies
53b3c1694SLeon Alrae  *
63b3c1694SLeon Alrae  * This library is free software; you can redistribute it and/or
73b3c1694SLeon Alrae  * modify it under the terms of the GNU Lesser General Public
83b3c1694SLeon Alrae  * License as published by the Free Software Foundation; either
989975214SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
103b3c1694SLeon Alrae  *
113b3c1694SLeon Alrae  * This library is distributed in the hope that it will be useful,
123b3c1694SLeon Alrae  * but WITHOUT ANY WARRANTY; without even the implied warranty of
133b3c1694SLeon Alrae  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
143b3c1694SLeon Alrae  * Lesser General Public License for more details.
153b3c1694SLeon Alrae  *
163b3c1694SLeon Alrae  * You should have received a copy of the GNU Lesser General Public
173b3c1694SLeon Alrae  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
183b3c1694SLeon Alrae  */
193b3c1694SLeon Alrae 
20c684822aSPeter Maydell #include "qemu/osdep.h"
213b3c1694SLeon Alrae #include "cpu.h"
2263c91552SPaolo Bonzini #include "qemu/log.h"
23c89a14adSRichard Henderson #include "semihosting/softmmu-uaccess.h"
246b5fe137SPhilippe Mathieu-Daudé #include "semihosting/semihost.h"
256b5fe137SPhilippe Mathieu-Daudé #include "semihosting/console.h"
268ec7e3c5SRichard Henderson #include "internal.h"
273b3c1694SLeon Alrae 
283b3c1694SLeon Alrae typedef enum UHIOp {
293b3c1694SLeon Alrae     UHI_exit = 1,
303b3c1694SLeon Alrae     UHI_open = 2,
313b3c1694SLeon Alrae     UHI_close = 3,
323b3c1694SLeon Alrae     UHI_read = 4,
333b3c1694SLeon Alrae     UHI_write = 5,
343b3c1694SLeon Alrae     UHI_lseek = 6,
353b3c1694SLeon Alrae     UHI_unlink = 7,
363b3c1694SLeon Alrae     UHI_fstat = 8,
373b3c1694SLeon Alrae     UHI_argc = 9,
383b3c1694SLeon Alrae     UHI_argnlen = 10,
393b3c1694SLeon Alrae     UHI_argn = 11,
403b3c1694SLeon Alrae     UHI_plog = 13,
413b3c1694SLeon Alrae     UHI_assert = 14,
423b3c1694SLeon Alrae     UHI_pread = 19,
433b3c1694SLeon Alrae     UHI_pwrite = 20,
443b3c1694SLeon Alrae     UHI_link = 22
453b3c1694SLeon Alrae } UHIOp;
463b3c1694SLeon Alrae 
473b3c1694SLeon Alrae typedef struct UHIStat {
483b3c1694SLeon Alrae     int16_t uhi_st_dev;
493b3c1694SLeon Alrae     uint16_t uhi_st_ino;
503b3c1694SLeon Alrae     uint32_t uhi_st_mode;
513b3c1694SLeon Alrae     uint16_t uhi_st_nlink;
523b3c1694SLeon Alrae     uint16_t uhi_st_uid;
533b3c1694SLeon Alrae     uint16_t uhi_st_gid;
543b3c1694SLeon Alrae     int16_t uhi_st_rdev;
553b3c1694SLeon Alrae     uint64_t uhi_st_size;
563b3c1694SLeon Alrae     uint64_t uhi_st_atime;
573b3c1694SLeon Alrae     uint64_t uhi_st_spare1;
583b3c1694SLeon Alrae     uint64_t uhi_st_mtime;
593b3c1694SLeon Alrae     uint64_t uhi_st_spare2;
603b3c1694SLeon Alrae     uint64_t uhi_st_ctime;
613b3c1694SLeon Alrae     uint64_t uhi_st_spare3;
623b3c1694SLeon Alrae     uint64_t uhi_st_blksize;
633b3c1694SLeon Alrae     uint64_t uhi_st_blocks;
643b3c1694SLeon Alrae     uint64_t uhi_st_spare4[2];
653b3c1694SLeon Alrae } UHIStat;
663b3c1694SLeon Alrae 
673b3c1694SLeon Alrae enum UHIOpenFlags {
683b3c1694SLeon Alrae     UHIOpen_RDONLY = 0x0,
693b3c1694SLeon Alrae     UHIOpen_WRONLY = 0x1,
703b3c1694SLeon Alrae     UHIOpen_RDWR   = 0x2,
713b3c1694SLeon Alrae     UHIOpen_APPEND = 0x8,
723b3c1694SLeon Alrae     UHIOpen_CREAT  = 0x200,
733b3c1694SLeon Alrae     UHIOpen_TRUNC  = 0x400,
743b3c1694SLeon Alrae     UHIOpen_EXCL   = 0x800
753b3c1694SLeon Alrae };
763b3c1694SLeon Alrae 
77*7ba6e53aSRichard Henderson enum UHIErrno {
78*7ba6e53aSRichard Henderson     UHI_EACCESS         = 13,
79*7ba6e53aSRichard Henderson     UHI_EAGAIN          = 11,
80*7ba6e53aSRichard Henderson     UHI_EBADF           = 9,
81*7ba6e53aSRichard Henderson     UHI_EBADMSG         = 77,
82*7ba6e53aSRichard Henderson     UHI_EBUSY           = 16,
83*7ba6e53aSRichard Henderson     UHI_ECONNRESET      = 104,
84*7ba6e53aSRichard Henderson     UHI_EEXIST          = 17,
85*7ba6e53aSRichard Henderson     UHI_EFBIG           = 27,
86*7ba6e53aSRichard Henderson     UHI_EINTR           = 4,
87*7ba6e53aSRichard Henderson     UHI_EINVAL          = 22,
88*7ba6e53aSRichard Henderson     UHI_EIO             = 5,
89*7ba6e53aSRichard Henderson     UHI_EISDIR          = 21,
90*7ba6e53aSRichard Henderson     UHI_ELOOP           = 92,
91*7ba6e53aSRichard Henderson     UHI_EMFILE          = 24,
92*7ba6e53aSRichard Henderson     UHI_EMLINK          = 31,
93*7ba6e53aSRichard Henderson     UHI_ENAMETOOLONG    = 91,
94*7ba6e53aSRichard Henderson     UHI_ENETDOWN        = 115,
95*7ba6e53aSRichard Henderson     UHI_ENETUNREACH     = 114,
96*7ba6e53aSRichard Henderson     UHI_ENFILE          = 23,
97*7ba6e53aSRichard Henderson     UHI_ENOBUFS         = 105,
98*7ba6e53aSRichard Henderson     UHI_ENOENT          = 2,
99*7ba6e53aSRichard Henderson     UHI_ENOMEM          = 12,
100*7ba6e53aSRichard Henderson     UHI_ENOSPC          = 28,
101*7ba6e53aSRichard Henderson     UHI_ENOSR           = 63,
102*7ba6e53aSRichard Henderson     UHI_ENOTCONN        = 128,
103*7ba6e53aSRichard Henderson     UHI_ENOTDIR         = 20,
104*7ba6e53aSRichard Henderson     UHI_ENXIO           = 6,
105*7ba6e53aSRichard Henderson     UHI_EOVERFLOW       = 139,
106*7ba6e53aSRichard Henderson     UHI_EPERM           = 1,
107*7ba6e53aSRichard Henderson     UHI_EPIPE           = 32,
108*7ba6e53aSRichard Henderson     UHI_ERANGE          = 34,
109*7ba6e53aSRichard Henderson     UHI_EROFS           = 30,
110*7ba6e53aSRichard Henderson     UHI_ESPIPE          = 29,
111*7ba6e53aSRichard Henderson     UHI_ETIMEDOUT       = 116,
112*7ba6e53aSRichard Henderson     UHI_ETXTBSY         = 26,
113*7ba6e53aSRichard Henderson     UHI_EWOULDBLOCK     = 11,
114*7ba6e53aSRichard Henderson     UHI_EXDEV           = 18,
115*7ba6e53aSRichard Henderson };
116*7ba6e53aSRichard Henderson 
117d859a77dSPhilippe Mathieu-Daudé static int errno_mips(int host_errno)
118d859a77dSPhilippe Mathieu-Daudé {
1192c44b19cSLeon Alrae     /* Errno values taken from asm-mips/errno.h */
120d859a77dSPhilippe Mathieu-Daudé     switch (host_errno) {
121d859a77dSPhilippe Mathieu-Daudé     case 0:             return 0;
122d859a77dSPhilippe Mathieu-Daudé     case ENAMETOOLONG:  return 78;
1232c44b19cSLeon Alrae #ifdef EOVERFLOW
124d859a77dSPhilippe Mathieu-Daudé     case EOVERFLOW:     return 79;
1252c44b19cSLeon Alrae #endif
1262c44b19cSLeon Alrae #ifdef ELOOP
127d859a77dSPhilippe Mathieu-Daudé     case ELOOP:         return 90;
1282c44b19cSLeon Alrae #endif
129d859a77dSPhilippe Mathieu-Daudé     default:            return EINVAL;
1302c44b19cSLeon Alrae     }
1312c44b19cSLeon Alrae }
1322c44b19cSLeon Alrae 
1333b3c1694SLeon Alrae static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,
1343b3c1694SLeon Alrae                                target_ulong vaddr)
1353b3c1694SLeon Alrae {
1363b3c1694SLeon Alrae     hwaddr len = sizeof(struct UHIStat);
1373b3c1694SLeon Alrae     UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
1383b3c1694SLeon Alrae     if (!dst) {
1393b3c1694SLeon Alrae         errno = EFAULT;
1403b3c1694SLeon Alrae         return -1;
1413b3c1694SLeon Alrae     }
1423b3c1694SLeon Alrae 
1433b3c1694SLeon Alrae     dst->uhi_st_dev = tswap16(src->st_dev);
1443b3c1694SLeon Alrae     dst->uhi_st_ino = tswap16(src->st_ino);
1453b3c1694SLeon Alrae     dst->uhi_st_mode = tswap32(src->st_mode);
1463b3c1694SLeon Alrae     dst->uhi_st_nlink = tswap16(src->st_nlink);
1473b3c1694SLeon Alrae     dst->uhi_st_uid = tswap16(src->st_uid);
1483b3c1694SLeon Alrae     dst->uhi_st_gid = tswap16(src->st_gid);
1493b3c1694SLeon Alrae     dst->uhi_st_rdev = tswap16(src->st_rdev);
1503b3c1694SLeon Alrae     dst->uhi_st_size = tswap64(src->st_size);
1513b3c1694SLeon Alrae     dst->uhi_st_atime = tswap64(src->st_atime);
1523b3c1694SLeon Alrae     dst->uhi_st_mtime = tswap64(src->st_mtime);
1533b3c1694SLeon Alrae     dst->uhi_st_ctime = tswap64(src->st_ctime);
1543b3c1694SLeon Alrae #ifdef _WIN32
1553b3c1694SLeon Alrae     dst->uhi_st_blksize = 0;
1563b3c1694SLeon Alrae     dst->uhi_st_blocks = 0;
1573b3c1694SLeon Alrae #else
1583b3c1694SLeon Alrae     dst->uhi_st_blksize = tswap64(src->st_blksize);
1593b3c1694SLeon Alrae     dst->uhi_st_blocks = tswap64(src->st_blocks);
1603b3c1694SLeon Alrae #endif
1613b3c1694SLeon Alrae     unlock_user(dst, vaddr, len);
1623b3c1694SLeon Alrae     return 0;
1633b3c1694SLeon Alrae }
1643b3c1694SLeon Alrae 
1653b3c1694SLeon Alrae static int get_open_flags(target_ulong target_flags)
1663b3c1694SLeon Alrae {
1673b3c1694SLeon Alrae     int open_flags = 0;
1683b3c1694SLeon Alrae 
1693b3c1694SLeon Alrae     if (target_flags & UHIOpen_RDWR) {
1703b3c1694SLeon Alrae         open_flags |= O_RDWR;
1713b3c1694SLeon Alrae     } else if (target_flags & UHIOpen_WRONLY) {
1723b3c1694SLeon Alrae         open_flags |= O_WRONLY;
1733b3c1694SLeon Alrae     } else {
1743b3c1694SLeon Alrae         open_flags |= O_RDONLY;
1753b3c1694SLeon Alrae     }
1763b3c1694SLeon Alrae 
1773b3c1694SLeon Alrae     open_flags |= (target_flags & UHIOpen_APPEND) ? O_APPEND : 0;
1783b3c1694SLeon Alrae     open_flags |= (target_flags & UHIOpen_CREAT)  ? O_CREAT  : 0;
1793b3c1694SLeon Alrae     open_flags |= (target_flags & UHIOpen_TRUNC)  ? O_TRUNC  : 0;
1803b3c1694SLeon Alrae     open_flags |= (target_flags & UHIOpen_EXCL)   ? O_EXCL   : 0;
1813b3c1694SLeon Alrae 
1823b3c1694SLeon Alrae     return open_flags;
1833b3c1694SLeon Alrae }
1843b3c1694SLeon Alrae 
1853b3c1694SLeon Alrae static int write_to_file(CPUMIPSState *env, target_ulong fd, target_ulong vaddr,
1863b3c1694SLeon Alrae                          target_ulong len, target_ulong offset)
1873b3c1694SLeon Alrae {
1883b3c1694SLeon Alrae     int num_of_bytes;
1893b3c1694SLeon Alrae     void *dst = lock_user(VERIFY_READ, vaddr, len, 1);
1903b3c1694SLeon Alrae     if (!dst) {
1913b3c1694SLeon Alrae         errno = EFAULT;
1923b3c1694SLeon Alrae         return -1;
1933b3c1694SLeon Alrae     }
1943b3c1694SLeon Alrae 
1953b3c1694SLeon Alrae     if (offset) {
1963b3c1694SLeon Alrae #ifdef _WIN32
1973b3c1694SLeon Alrae         num_of_bytes = 0;
1983b3c1694SLeon Alrae #else
1993b3c1694SLeon Alrae         num_of_bytes = pwrite(fd, dst, len, offset);
2003b3c1694SLeon Alrae #endif
2013b3c1694SLeon Alrae     } else {
2023b3c1694SLeon Alrae         num_of_bytes = write(fd, dst, len);
2033b3c1694SLeon Alrae     }
2043b3c1694SLeon Alrae 
2053b3c1694SLeon Alrae     unlock_user(dst, vaddr, 0);
2063b3c1694SLeon Alrae     return num_of_bytes;
2073b3c1694SLeon Alrae }
2083b3c1694SLeon Alrae 
2093b3c1694SLeon Alrae static int read_from_file(CPUMIPSState *env, target_ulong fd,
2103b3c1694SLeon Alrae                           target_ulong vaddr, target_ulong len,
2113b3c1694SLeon Alrae                           target_ulong offset)
2123b3c1694SLeon Alrae {
2133b3c1694SLeon Alrae     int num_of_bytes;
2143b3c1694SLeon Alrae     void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
2153b3c1694SLeon Alrae     if (!dst) {
2163b3c1694SLeon Alrae         errno = EFAULT;
2173b3c1694SLeon Alrae         return -1;
2183b3c1694SLeon Alrae     }
2193b3c1694SLeon Alrae 
2203b3c1694SLeon Alrae     if (offset) {
2213b3c1694SLeon Alrae #ifdef _WIN32
2223b3c1694SLeon Alrae         num_of_bytes = 0;
2233b3c1694SLeon Alrae #else
2243b3c1694SLeon Alrae         num_of_bytes = pread(fd, dst, len, offset);
2253b3c1694SLeon Alrae #endif
2263b3c1694SLeon Alrae     } else {
2273b3c1694SLeon Alrae         num_of_bytes = read(fd, dst, len);
2283b3c1694SLeon Alrae     }
2293b3c1694SLeon Alrae 
2303b3c1694SLeon Alrae     unlock_user(dst, vaddr, len);
2313b3c1694SLeon Alrae     return num_of_bytes;
2323b3c1694SLeon Alrae }
2333b3c1694SLeon Alrae 
2343b3c1694SLeon Alrae static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
2353b3c1694SLeon Alrae                                target_ulong vaddr)
2363b3c1694SLeon Alrae {
2373b3c1694SLeon Alrae     int strsize = strlen(semihosting_get_arg(arg_num)) + 1;
2383b3c1694SLeon Alrae     char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0);
2393b3c1694SLeon Alrae     if (!dst) {
2403b3c1694SLeon Alrae         return -1;
2413b3c1694SLeon Alrae     }
2423b3c1694SLeon Alrae 
2433b3c1694SLeon Alrae     strcpy(dst, semihosting_get_arg(arg_num));
2443b3c1694SLeon Alrae 
2453b3c1694SLeon Alrae     unlock_user(dst, vaddr, strsize);
2463b3c1694SLeon Alrae     return 0;
2473b3c1694SLeon Alrae }
2483b3c1694SLeon Alrae 
2493b3c1694SLeon Alrae #define GET_TARGET_STRING(p, addr)              \
2503b3c1694SLeon Alrae     do {                                        \
2513b3c1694SLeon Alrae         p = lock_user_string(addr);             \
2523b3c1694SLeon Alrae         if (!p) {                               \
2533b3c1694SLeon Alrae             gpr[2] = -1;                        \
2543b3c1694SLeon Alrae             gpr[3] = EFAULT;                    \
25554fc33fdSDaniel Henrique Barboza             return;                             \
2563b3c1694SLeon Alrae         }                                       \
2573b3c1694SLeon Alrae     } while (0)
2583b3c1694SLeon Alrae 
25926e7e982SLeon Alrae #define GET_TARGET_STRINGS_2(p, addr, p2, addr2)        \
26026e7e982SLeon Alrae     do {                                                \
26126e7e982SLeon Alrae         p = lock_user_string(addr);                     \
26226e7e982SLeon Alrae         if (!p) {                                       \
26326e7e982SLeon Alrae             gpr[2] = -1;                                \
26426e7e982SLeon Alrae             gpr[3] = EFAULT;                            \
26554fc33fdSDaniel Henrique Barboza             return;                                     \
26626e7e982SLeon Alrae         }                                               \
26726e7e982SLeon Alrae         p2 = lock_user_string(addr2);                   \
26826e7e982SLeon Alrae         if (!p2) {                                      \
26926e7e982SLeon Alrae             unlock_user(p, addr, 0);                    \
27026e7e982SLeon Alrae             gpr[2] = -1;                                \
27126e7e982SLeon Alrae             gpr[3] = EFAULT;                            \
27254fc33fdSDaniel Henrique Barboza             return;                                     \
27326e7e982SLeon Alrae         }                                               \
27426e7e982SLeon Alrae     } while (0)
27526e7e982SLeon Alrae 
2763b3c1694SLeon Alrae #define FREE_TARGET_STRING(p, gpr)              \
2773b3c1694SLeon Alrae     do {                                        \
2783b3c1694SLeon Alrae         unlock_user(p, gpr, 0);                 \
2793b3c1694SLeon Alrae     } while (0)
2803b3c1694SLeon Alrae 
2818ec7e3c5SRichard Henderson void mips_semihosting(CPUMIPSState *env)
2823b3c1694SLeon Alrae {
2833b3c1694SLeon Alrae     target_ulong *gpr = env->active_tc.gpr;
2843b3c1694SLeon Alrae     const UHIOp op = gpr[25];
2853b3c1694SLeon Alrae     char *p, *p2;
2863b3c1694SLeon Alrae 
2873b3c1694SLeon Alrae     switch (op) {
2883b3c1694SLeon Alrae     case UHI_exit:
2893b3c1694SLeon Alrae         qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]);
2903b3c1694SLeon Alrae         exit(gpr[4]);
2913b3c1694SLeon Alrae     case UHI_open:
2923b3c1694SLeon Alrae         GET_TARGET_STRING(p, gpr[4]);
2933b3c1694SLeon Alrae         if (!strcmp("/dev/stdin", p)) {
2943b3c1694SLeon Alrae             gpr[2] = 0;
2953b3c1694SLeon Alrae         } else if (!strcmp("/dev/stdout", p)) {
2963b3c1694SLeon Alrae             gpr[2] = 1;
2973b3c1694SLeon Alrae         } else if (!strcmp("/dev/stderr", p)) {
2983b3c1694SLeon Alrae             gpr[2] = 2;
2993b3c1694SLeon Alrae         } else {
3003b3c1694SLeon Alrae             gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]);
3012c44b19cSLeon Alrae             gpr[3] = errno_mips(errno);
3023b3c1694SLeon Alrae         }
3033b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
3043b3c1694SLeon Alrae         break;
3053b3c1694SLeon Alrae     case UHI_close:
3063b3c1694SLeon Alrae         if (gpr[4] < 3) {
3073b3c1694SLeon Alrae             /* ignore closing stdin/stdout/stderr */
3083b3c1694SLeon Alrae             gpr[2] = 0;
30954fc33fdSDaniel Henrique Barboza             return;
3103b3c1694SLeon Alrae         }
3113b3c1694SLeon Alrae         gpr[2] = close(gpr[4]);
3122c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3133b3c1694SLeon Alrae         break;
3143b3c1694SLeon Alrae     case UHI_read:
3153b3c1694SLeon Alrae         gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], 0);
3162c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3173b3c1694SLeon Alrae         break;
3183b3c1694SLeon Alrae     case UHI_write:
3193b3c1694SLeon Alrae         gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], 0);
3202c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3213b3c1694SLeon Alrae         break;
3223b3c1694SLeon Alrae     case UHI_lseek:
3233b3c1694SLeon Alrae         gpr[2] = lseek(gpr[4], gpr[5], gpr[6]);
3242c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3253b3c1694SLeon Alrae         break;
3263b3c1694SLeon Alrae     case UHI_unlink:
3273b3c1694SLeon Alrae         GET_TARGET_STRING(p, gpr[4]);
3283b3c1694SLeon Alrae         gpr[2] = remove(p);
3292c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3303b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
3313b3c1694SLeon Alrae         break;
3323b3c1694SLeon Alrae     case UHI_fstat:
3333b3c1694SLeon Alrae         {
3343b3c1694SLeon Alrae             struct stat sbuf;
3353b3c1694SLeon Alrae             memset(&sbuf, 0, sizeof(sbuf));
3363b3c1694SLeon Alrae             gpr[2] = fstat(gpr[4], &sbuf);
3372c44b19cSLeon Alrae             gpr[3] = errno_mips(errno);
3383b3c1694SLeon Alrae             if (gpr[2]) {
33954fc33fdSDaniel Henrique Barboza                 return;
3403b3c1694SLeon Alrae             }
3413b3c1694SLeon Alrae             gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]);
3422c44b19cSLeon Alrae             gpr[3] = errno_mips(errno);
3433b3c1694SLeon Alrae         }
3443b3c1694SLeon Alrae         break;
3453b3c1694SLeon Alrae     case UHI_argc:
3463b3c1694SLeon Alrae         gpr[2] = semihosting_get_argc();
3473b3c1694SLeon Alrae         break;
3483b3c1694SLeon Alrae     case UHI_argnlen:
3493b3c1694SLeon Alrae         if (gpr[4] >= semihosting_get_argc()) {
3503b3c1694SLeon Alrae             gpr[2] = -1;
35154fc33fdSDaniel Henrique Barboza             return;
3523b3c1694SLeon Alrae         }
3533b3c1694SLeon Alrae         gpr[2] = strlen(semihosting_get_arg(gpr[4]));
3543b3c1694SLeon Alrae         break;
3553b3c1694SLeon Alrae     case UHI_argn:
3563b3c1694SLeon Alrae         if (gpr[4] >= semihosting_get_argc()) {
3573b3c1694SLeon Alrae             gpr[2] = -1;
35854fc33fdSDaniel Henrique Barboza             return;
3593b3c1694SLeon Alrae         }
3603b3c1694SLeon Alrae         gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]);
3613b3c1694SLeon Alrae         break;
3623b3c1694SLeon Alrae     case UHI_plog:
3633b3c1694SLeon Alrae         GET_TARGET_STRING(p, gpr[4]);
3643b3c1694SLeon Alrae         p2 = strstr(p, "%d");
3653b3c1694SLeon Alrae         if (p2) {
3663b3c1694SLeon Alrae             int char_num = p2 - p;
36754eb6cdaSAlex Bennée             GString *s = g_string_new_len(p, char_num);
36854eb6cdaSAlex Bennée             g_string_append_printf(s, "%d%s", (int)gpr[5], p2 + 2);
36954eb6cdaSAlex Bennée             gpr[2] = qemu_semihosting_log_out(s->str, s->len);
37054eb6cdaSAlex Bennée             g_string_free(s, true);
3713b3c1694SLeon Alrae         } else {
37254eb6cdaSAlex Bennée             gpr[2] = qemu_semihosting_log_out(p, strlen(p));
3733b3c1694SLeon Alrae         }
3743b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
3753b3c1694SLeon Alrae         break;
3763b3c1694SLeon Alrae     case UHI_assert:
37726e7e982SLeon Alrae         GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
3783b3c1694SLeon Alrae         printf("assertion '");
3793b3c1694SLeon Alrae         printf("\"%s\"", p);
3803b3c1694SLeon Alrae         printf("': file \"%s\", line %d\n", p2, (int)gpr[6]);
3813b3c1694SLeon Alrae         FREE_TARGET_STRING(p2, gpr[5]);
3823b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
3833b3c1694SLeon Alrae         abort();
3843b3c1694SLeon Alrae         break;
3853b3c1694SLeon Alrae     case UHI_pread:
3863b3c1694SLeon Alrae         gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
3872c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3883b3c1694SLeon Alrae         break;
3893b3c1694SLeon Alrae     case UHI_pwrite:
3903b3c1694SLeon Alrae         gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
3912c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3923b3c1694SLeon Alrae         break;
3933b3c1694SLeon Alrae #ifndef _WIN32
3943b3c1694SLeon Alrae     case UHI_link:
39526e7e982SLeon Alrae         GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
3963b3c1694SLeon Alrae         gpr[2] = link(p, p2);
3972c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3983b3c1694SLeon Alrae         FREE_TARGET_STRING(p2, gpr[5]);
3993b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
4003b3c1694SLeon Alrae         break;
4013b3c1694SLeon Alrae #endif
4023b3c1694SLeon Alrae     default:
4033b3c1694SLeon Alrae         fprintf(stderr, "Unknown UHI operation %d\n", op);
4043b3c1694SLeon Alrae         abort();
4053b3c1694SLeon Alrae     }
4063b3c1694SLeon Alrae     return;
4073b3c1694SLeon Alrae }
408