xref: /qemu/target/mips/tcg/system/mips-semi.c (revision d53a3ed44605f7f070add30729e93bc7971ff6b1)
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 
777ba6e53aSRichard Henderson enum UHIErrno {
787ba6e53aSRichard Henderson     UHI_EACCESS         = 13,
797ba6e53aSRichard Henderson     UHI_EAGAIN          = 11,
807ba6e53aSRichard Henderson     UHI_EBADF           = 9,
817ba6e53aSRichard Henderson     UHI_EBADMSG         = 77,
827ba6e53aSRichard Henderson     UHI_EBUSY           = 16,
837ba6e53aSRichard Henderson     UHI_ECONNRESET      = 104,
847ba6e53aSRichard Henderson     UHI_EEXIST          = 17,
857ba6e53aSRichard Henderson     UHI_EFBIG           = 27,
867ba6e53aSRichard Henderson     UHI_EINTR           = 4,
877ba6e53aSRichard Henderson     UHI_EINVAL          = 22,
887ba6e53aSRichard Henderson     UHI_EIO             = 5,
897ba6e53aSRichard Henderson     UHI_EISDIR          = 21,
907ba6e53aSRichard Henderson     UHI_ELOOP           = 92,
917ba6e53aSRichard Henderson     UHI_EMFILE          = 24,
927ba6e53aSRichard Henderson     UHI_EMLINK          = 31,
937ba6e53aSRichard Henderson     UHI_ENAMETOOLONG    = 91,
947ba6e53aSRichard Henderson     UHI_ENETDOWN        = 115,
957ba6e53aSRichard Henderson     UHI_ENETUNREACH     = 114,
967ba6e53aSRichard Henderson     UHI_ENFILE          = 23,
977ba6e53aSRichard Henderson     UHI_ENOBUFS         = 105,
987ba6e53aSRichard Henderson     UHI_ENOENT          = 2,
997ba6e53aSRichard Henderson     UHI_ENOMEM          = 12,
1007ba6e53aSRichard Henderson     UHI_ENOSPC          = 28,
1017ba6e53aSRichard Henderson     UHI_ENOSR           = 63,
1027ba6e53aSRichard Henderson     UHI_ENOTCONN        = 128,
1037ba6e53aSRichard Henderson     UHI_ENOTDIR         = 20,
1047ba6e53aSRichard Henderson     UHI_ENXIO           = 6,
1057ba6e53aSRichard Henderson     UHI_EOVERFLOW       = 139,
1067ba6e53aSRichard Henderson     UHI_EPERM           = 1,
1077ba6e53aSRichard Henderson     UHI_EPIPE           = 32,
1087ba6e53aSRichard Henderson     UHI_ERANGE          = 34,
1097ba6e53aSRichard Henderson     UHI_EROFS           = 30,
1107ba6e53aSRichard Henderson     UHI_ESPIPE          = 29,
1117ba6e53aSRichard Henderson     UHI_ETIMEDOUT       = 116,
1127ba6e53aSRichard Henderson     UHI_ETXTBSY         = 26,
1137ba6e53aSRichard Henderson     UHI_EWOULDBLOCK     = 11,
1147ba6e53aSRichard Henderson     UHI_EXDEV           = 18,
1157ba6e53aSRichard Henderson };
1167ba6e53aSRichard Henderson 
117*d53a3ed4SRichard Henderson static void report_fault(CPUMIPSState *env)
118*d53a3ed4SRichard Henderson {
119*d53a3ed4SRichard Henderson     int op = env->active_tc.gpr[25];
120*d53a3ed4SRichard Henderson     error_report("Fault during UHI operation %d", op);
121*d53a3ed4SRichard Henderson     abort();
122*d53a3ed4SRichard Henderson }
123*d53a3ed4SRichard Henderson 
124d859a77dSPhilippe Mathieu-Daudé static int errno_mips(int host_errno)
125d859a77dSPhilippe Mathieu-Daudé {
1262c44b19cSLeon Alrae     /* Errno values taken from asm-mips/errno.h */
127d859a77dSPhilippe Mathieu-Daudé     switch (host_errno) {
128d859a77dSPhilippe Mathieu-Daudé     case 0:             return 0;
129d859a77dSPhilippe Mathieu-Daudé     case ENAMETOOLONG:  return 78;
1302c44b19cSLeon Alrae #ifdef EOVERFLOW
131d859a77dSPhilippe Mathieu-Daudé     case EOVERFLOW:     return 79;
1322c44b19cSLeon Alrae #endif
1332c44b19cSLeon Alrae #ifdef ELOOP
134d859a77dSPhilippe Mathieu-Daudé     case ELOOP:         return 90;
1352c44b19cSLeon Alrae #endif
136d859a77dSPhilippe Mathieu-Daudé     default:            return EINVAL;
1372c44b19cSLeon Alrae     }
1382c44b19cSLeon Alrae }
1392c44b19cSLeon Alrae 
1403b3c1694SLeon Alrae static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,
1413b3c1694SLeon Alrae                                target_ulong vaddr)
1423b3c1694SLeon Alrae {
1433b3c1694SLeon Alrae     hwaddr len = sizeof(struct UHIStat);
1443b3c1694SLeon Alrae     UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
1453b3c1694SLeon Alrae     if (!dst) {
146*d53a3ed4SRichard Henderson         report_fault(env);
1473b3c1694SLeon Alrae     }
1483b3c1694SLeon Alrae 
1493b3c1694SLeon Alrae     dst->uhi_st_dev = tswap16(src->st_dev);
1503b3c1694SLeon Alrae     dst->uhi_st_ino = tswap16(src->st_ino);
1513b3c1694SLeon Alrae     dst->uhi_st_mode = tswap32(src->st_mode);
1523b3c1694SLeon Alrae     dst->uhi_st_nlink = tswap16(src->st_nlink);
1533b3c1694SLeon Alrae     dst->uhi_st_uid = tswap16(src->st_uid);
1543b3c1694SLeon Alrae     dst->uhi_st_gid = tswap16(src->st_gid);
1553b3c1694SLeon Alrae     dst->uhi_st_rdev = tswap16(src->st_rdev);
1563b3c1694SLeon Alrae     dst->uhi_st_size = tswap64(src->st_size);
1573b3c1694SLeon Alrae     dst->uhi_st_atime = tswap64(src->st_atime);
1583b3c1694SLeon Alrae     dst->uhi_st_mtime = tswap64(src->st_mtime);
1593b3c1694SLeon Alrae     dst->uhi_st_ctime = tswap64(src->st_ctime);
1603b3c1694SLeon Alrae #ifdef _WIN32
1613b3c1694SLeon Alrae     dst->uhi_st_blksize = 0;
1623b3c1694SLeon Alrae     dst->uhi_st_blocks = 0;
1633b3c1694SLeon Alrae #else
1643b3c1694SLeon Alrae     dst->uhi_st_blksize = tswap64(src->st_blksize);
1653b3c1694SLeon Alrae     dst->uhi_st_blocks = tswap64(src->st_blocks);
1663b3c1694SLeon Alrae #endif
1673b3c1694SLeon Alrae     unlock_user(dst, vaddr, len);
1683b3c1694SLeon Alrae     return 0;
1693b3c1694SLeon Alrae }
1703b3c1694SLeon Alrae 
1713b3c1694SLeon Alrae static int get_open_flags(target_ulong target_flags)
1723b3c1694SLeon Alrae {
1733b3c1694SLeon Alrae     int open_flags = 0;
1743b3c1694SLeon Alrae 
1753b3c1694SLeon Alrae     if (target_flags & UHIOpen_RDWR) {
1763b3c1694SLeon Alrae         open_flags |= O_RDWR;
1773b3c1694SLeon Alrae     } else if (target_flags & UHIOpen_WRONLY) {
1783b3c1694SLeon Alrae         open_flags |= O_WRONLY;
1793b3c1694SLeon Alrae     } else {
1803b3c1694SLeon Alrae         open_flags |= O_RDONLY;
1813b3c1694SLeon Alrae     }
1823b3c1694SLeon Alrae 
1833b3c1694SLeon Alrae     open_flags |= (target_flags & UHIOpen_APPEND) ? O_APPEND : 0;
1843b3c1694SLeon Alrae     open_flags |= (target_flags & UHIOpen_CREAT)  ? O_CREAT  : 0;
1853b3c1694SLeon Alrae     open_flags |= (target_flags & UHIOpen_TRUNC)  ? O_TRUNC  : 0;
1863b3c1694SLeon Alrae     open_flags |= (target_flags & UHIOpen_EXCL)   ? O_EXCL   : 0;
1873b3c1694SLeon Alrae 
1883b3c1694SLeon Alrae     return open_flags;
1893b3c1694SLeon Alrae }
1903b3c1694SLeon Alrae 
1916863e92dSRichard Henderson static int write_to_file(CPUMIPSState *env, target_ulong fd,
1926863e92dSRichard Henderson                          target_ulong vaddr, target_ulong len)
1933b3c1694SLeon Alrae {
1943b3c1694SLeon Alrae     int num_of_bytes;
1953b3c1694SLeon Alrae     void *dst = lock_user(VERIFY_READ, vaddr, len, 1);
1963b3c1694SLeon Alrae     if (!dst) {
197*d53a3ed4SRichard Henderson         report_fault(env);
1983b3c1694SLeon Alrae     }
1993b3c1694SLeon Alrae 
2003b3c1694SLeon Alrae     num_of_bytes = write(fd, dst, len);
2013b3c1694SLeon Alrae 
2023b3c1694SLeon Alrae     unlock_user(dst, vaddr, 0);
2033b3c1694SLeon Alrae     return num_of_bytes;
2043b3c1694SLeon Alrae }
2053b3c1694SLeon Alrae 
2063b3c1694SLeon Alrae static int read_from_file(CPUMIPSState *env, target_ulong fd,
2076863e92dSRichard Henderson                           target_ulong vaddr, target_ulong len)
2083b3c1694SLeon Alrae {
2093b3c1694SLeon Alrae     int num_of_bytes;
2103b3c1694SLeon Alrae     void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
2113b3c1694SLeon Alrae     if (!dst) {
212*d53a3ed4SRichard Henderson         report_fault(env);
2133b3c1694SLeon Alrae     }
2143b3c1694SLeon Alrae 
2153b3c1694SLeon Alrae     num_of_bytes = read(fd, dst, len);
2163b3c1694SLeon Alrae 
2173b3c1694SLeon Alrae     unlock_user(dst, vaddr, len);
2183b3c1694SLeon Alrae     return num_of_bytes;
2193b3c1694SLeon Alrae }
2203b3c1694SLeon Alrae 
2213b3c1694SLeon Alrae static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
2223b3c1694SLeon Alrae                                target_ulong vaddr)
2233b3c1694SLeon Alrae {
2243b3c1694SLeon Alrae     int strsize = strlen(semihosting_get_arg(arg_num)) + 1;
2253b3c1694SLeon Alrae     char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0);
2263b3c1694SLeon Alrae     if (!dst) {
227*d53a3ed4SRichard Henderson         report_fault(env);
2283b3c1694SLeon Alrae     }
2293b3c1694SLeon Alrae 
2303b3c1694SLeon Alrae     strcpy(dst, semihosting_get_arg(arg_num));
2313b3c1694SLeon Alrae 
2323b3c1694SLeon Alrae     unlock_user(dst, vaddr, strsize);
2333b3c1694SLeon Alrae     return 0;
2343b3c1694SLeon Alrae }
2353b3c1694SLeon Alrae 
2363b3c1694SLeon Alrae #define GET_TARGET_STRING(p, addr)              \
2373b3c1694SLeon Alrae     do {                                        \
2383b3c1694SLeon Alrae         p = lock_user_string(addr);             \
2393b3c1694SLeon Alrae         if (!p) {                               \
240*d53a3ed4SRichard Henderson             report_fault(env);                  \
2413b3c1694SLeon Alrae         }                                       \
2423b3c1694SLeon Alrae     } while (0)
2433b3c1694SLeon Alrae 
24426e7e982SLeon Alrae #define GET_TARGET_STRINGS_2(p, addr, p2, addr2)        \
24526e7e982SLeon Alrae     do {                                                \
24626e7e982SLeon Alrae         p = lock_user_string(addr);                     \
24726e7e982SLeon Alrae         if (!p) {                                       \
248*d53a3ed4SRichard Henderson             report_fault(env);                          \
24926e7e982SLeon Alrae         }                                               \
25026e7e982SLeon Alrae         p2 = lock_user_string(addr2);                   \
25126e7e982SLeon Alrae         if (!p2) {                                      \
252*d53a3ed4SRichard Henderson             report_fault(env);                          \
25326e7e982SLeon Alrae         }                                               \
25426e7e982SLeon Alrae     } while (0)
25526e7e982SLeon Alrae 
2563b3c1694SLeon Alrae #define FREE_TARGET_STRING(p, gpr)              \
2573b3c1694SLeon Alrae     do {                                        \
2583b3c1694SLeon Alrae         unlock_user(p, gpr, 0);                 \
2593b3c1694SLeon Alrae     } while (0)
2603b3c1694SLeon Alrae 
2618ec7e3c5SRichard Henderson void mips_semihosting(CPUMIPSState *env)
2623b3c1694SLeon Alrae {
2633b3c1694SLeon Alrae     target_ulong *gpr = env->active_tc.gpr;
2643b3c1694SLeon Alrae     const UHIOp op = gpr[25];
2653b3c1694SLeon Alrae     char *p, *p2;
2663b3c1694SLeon Alrae 
2673b3c1694SLeon Alrae     switch (op) {
2683b3c1694SLeon Alrae     case UHI_exit:
2693b3c1694SLeon Alrae         qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]);
2703b3c1694SLeon Alrae         exit(gpr[4]);
2713b3c1694SLeon Alrae     case UHI_open:
2723b3c1694SLeon Alrae         GET_TARGET_STRING(p, gpr[4]);
2733b3c1694SLeon Alrae         if (!strcmp("/dev/stdin", p)) {
2743b3c1694SLeon Alrae             gpr[2] = 0;
2753b3c1694SLeon Alrae         } else if (!strcmp("/dev/stdout", p)) {
2763b3c1694SLeon Alrae             gpr[2] = 1;
2773b3c1694SLeon Alrae         } else if (!strcmp("/dev/stderr", p)) {
2783b3c1694SLeon Alrae             gpr[2] = 2;
2793b3c1694SLeon Alrae         } else {
2803b3c1694SLeon Alrae             gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]);
2812c44b19cSLeon Alrae             gpr[3] = errno_mips(errno);
2823b3c1694SLeon Alrae         }
2833b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
2843b3c1694SLeon Alrae         break;
2853b3c1694SLeon Alrae     case UHI_close:
2863b3c1694SLeon Alrae         if (gpr[4] < 3) {
2873b3c1694SLeon Alrae             /* ignore closing stdin/stdout/stderr */
2883b3c1694SLeon Alrae             gpr[2] = 0;
28954fc33fdSDaniel Henrique Barboza             return;
2903b3c1694SLeon Alrae         }
2913b3c1694SLeon Alrae         gpr[2] = close(gpr[4]);
2922c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
2933b3c1694SLeon Alrae         break;
2943b3c1694SLeon Alrae     case UHI_read:
2956863e92dSRichard Henderson         gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6]);
2962c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
2973b3c1694SLeon Alrae         break;
2983b3c1694SLeon Alrae     case UHI_write:
2996863e92dSRichard Henderson         gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6]);
3002c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3013b3c1694SLeon Alrae         break;
3023b3c1694SLeon Alrae     case UHI_lseek:
3033b3c1694SLeon Alrae         gpr[2] = lseek(gpr[4], gpr[5], gpr[6]);
3042c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3053b3c1694SLeon Alrae         break;
3063b3c1694SLeon Alrae     case UHI_unlink:
3073b3c1694SLeon Alrae         GET_TARGET_STRING(p, gpr[4]);
3083b3c1694SLeon Alrae         gpr[2] = remove(p);
3092c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3103b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
3113b3c1694SLeon Alrae         break;
3123b3c1694SLeon Alrae     case UHI_fstat:
3133b3c1694SLeon Alrae         {
3143b3c1694SLeon Alrae             struct stat sbuf;
3153b3c1694SLeon Alrae             memset(&sbuf, 0, sizeof(sbuf));
3163b3c1694SLeon Alrae             gpr[2] = fstat(gpr[4], &sbuf);
3172c44b19cSLeon Alrae             gpr[3] = errno_mips(errno);
3183b3c1694SLeon Alrae             if (gpr[2]) {
31954fc33fdSDaniel Henrique Barboza                 return;
3203b3c1694SLeon Alrae             }
3213b3c1694SLeon Alrae             gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]);
3222c44b19cSLeon Alrae             gpr[3] = errno_mips(errno);
3233b3c1694SLeon Alrae         }
3243b3c1694SLeon Alrae         break;
3253b3c1694SLeon Alrae     case UHI_argc:
3263b3c1694SLeon Alrae         gpr[2] = semihosting_get_argc();
3273b3c1694SLeon Alrae         break;
3283b3c1694SLeon Alrae     case UHI_argnlen:
3293b3c1694SLeon Alrae         if (gpr[4] >= semihosting_get_argc()) {
3303b3c1694SLeon Alrae             gpr[2] = -1;
33154fc33fdSDaniel Henrique Barboza             return;
3323b3c1694SLeon Alrae         }
3333b3c1694SLeon Alrae         gpr[2] = strlen(semihosting_get_arg(gpr[4]));
3343b3c1694SLeon Alrae         break;
3353b3c1694SLeon Alrae     case UHI_argn:
3363b3c1694SLeon Alrae         if (gpr[4] >= semihosting_get_argc()) {
3373b3c1694SLeon Alrae             gpr[2] = -1;
33854fc33fdSDaniel Henrique Barboza             return;
3393b3c1694SLeon Alrae         }
3403b3c1694SLeon Alrae         gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]);
3413b3c1694SLeon Alrae         break;
3423b3c1694SLeon Alrae     case UHI_plog:
3433b3c1694SLeon Alrae         GET_TARGET_STRING(p, gpr[4]);
3443b3c1694SLeon Alrae         p2 = strstr(p, "%d");
3453b3c1694SLeon Alrae         if (p2) {
3463b3c1694SLeon Alrae             int char_num = p2 - p;
34754eb6cdaSAlex Bennée             GString *s = g_string_new_len(p, char_num);
34854eb6cdaSAlex Bennée             g_string_append_printf(s, "%d%s", (int)gpr[5], p2 + 2);
34954eb6cdaSAlex Bennée             gpr[2] = qemu_semihosting_log_out(s->str, s->len);
35054eb6cdaSAlex Bennée             g_string_free(s, true);
3513b3c1694SLeon Alrae         } else {
35254eb6cdaSAlex Bennée             gpr[2] = qemu_semihosting_log_out(p, strlen(p));
3533b3c1694SLeon Alrae         }
3543b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
3553b3c1694SLeon Alrae         break;
3563b3c1694SLeon Alrae     case UHI_assert:
35726e7e982SLeon Alrae         GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
3583b3c1694SLeon Alrae         printf("assertion '");
3593b3c1694SLeon Alrae         printf("\"%s\"", p);
3603b3c1694SLeon Alrae         printf("': file \"%s\", line %d\n", p2, (int)gpr[6]);
3613b3c1694SLeon Alrae         FREE_TARGET_STRING(p2, gpr[5]);
3623b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
3633b3c1694SLeon Alrae         abort();
3643b3c1694SLeon Alrae         break;
3653b3c1694SLeon Alrae #ifndef _WIN32
3663b3c1694SLeon Alrae     case UHI_link:
36726e7e982SLeon Alrae         GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
3683b3c1694SLeon Alrae         gpr[2] = link(p, p2);
3692c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3703b3c1694SLeon Alrae         FREE_TARGET_STRING(p2, gpr[5]);
3713b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
3723b3c1694SLeon Alrae         break;
3733b3c1694SLeon Alrae #endif
3743b3c1694SLeon Alrae     default:
375*d53a3ed4SRichard Henderson         error_report("Unknown UHI operation %d", op);
3763b3c1694SLeon Alrae         abort();
3773b3c1694SLeon Alrae     }
3783b3c1694SLeon Alrae     return;
3793b3c1694SLeon Alrae }
380