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