xref: /qemu/target/mips/tcg/system/mips-semi.c (revision 8ec7e3c53d48c61e31dd251b84a2b8190a14542d)
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"
26*8ec7e3c5SRichard 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 
77d859a77dSPhilippe Mathieu-Daudé static int errno_mips(int host_errno)
78d859a77dSPhilippe Mathieu-Daudé {
792c44b19cSLeon Alrae     /* Errno values taken from asm-mips/errno.h */
80d859a77dSPhilippe Mathieu-Daudé     switch (host_errno) {
81d859a77dSPhilippe Mathieu-Daudé     case 0:             return 0;
82d859a77dSPhilippe Mathieu-Daudé     case ENAMETOOLONG:  return 78;
832c44b19cSLeon Alrae #ifdef EOVERFLOW
84d859a77dSPhilippe Mathieu-Daudé     case EOVERFLOW:     return 79;
852c44b19cSLeon Alrae #endif
862c44b19cSLeon Alrae #ifdef ELOOP
87d859a77dSPhilippe Mathieu-Daudé     case ELOOP:         return 90;
882c44b19cSLeon Alrae #endif
89d859a77dSPhilippe Mathieu-Daudé     default:            return EINVAL;
902c44b19cSLeon Alrae     }
912c44b19cSLeon Alrae }
922c44b19cSLeon Alrae 
933b3c1694SLeon Alrae static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,
943b3c1694SLeon Alrae                                target_ulong vaddr)
953b3c1694SLeon Alrae {
963b3c1694SLeon Alrae     hwaddr len = sizeof(struct UHIStat);
973b3c1694SLeon Alrae     UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
983b3c1694SLeon Alrae     if (!dst) {
993b3c1694SLeon Alrae         errno = EFAULT;
1003b3c1694SLeon Alrae         return -1;
1013b3c1694SLeon Alrae     }
1023b3c1694SLeon Alrae 
1033b3c1694SLeon Alrae     dst->uhi_st_dev = tswap16(src->st_dev);
1043b3c1694SLeon Alrae     dst->uhi_st_ino = tswap16(src->st_ino);
1053b3c1694SLeon Alrae     dst->uhi_st_mode = tswap32(src->st_mode);
1063b3c1694SLeon Alrae     dst->uhi_st_nlink = tswap16(src->st_nlink);
1073b3c1694SLeon Alrae     dst->uhi_st_uid = tswap16(src->st_uid);
1083b3c1694SLeon Alrae     dst->uhi_st_gid = tswap16(src->st_gid);
1093b3c1694SLeon Alrae     dst->uhi_st_rdev = tswap16(src->st_rdev);
1103b3c1694SLeon Alrae     dst->uhi_st_size = tswap64(src->st_size);
1113b3c1694SLeon Alrae     dst->uhi_st_atime = tswap64(src->st_atime);
1123b3c1694SLeon Alrae     dst->uhi_st_mtime = tswap64(src->st_mtime);
1133b3c1694SLeon Alrae     dst->uhi_st_ctime = tswap64(src->st_ctime);
1143b3c1694SLeon Alrae #ifdef _WIN32
1153b3c1694SLeon Alrae     dst->uhi_st_blksize = 0;
1163b3c1694SLeon Alrae     dst->uhi_st_blocks = 0;
1173b3c1694SLeon Alrae #else
1183b3c1694SLeon Alrae     dst->uhi_st_blksize = tswap64(src->st_blksize);
1193b3c1694SLeon Alrae     dst->uhi_st_blocks = tswap64(src->st_blocks);
1203b3c1694SLeon Alrae #endif
1213b3c1694SLeon Alrae     unlock_user(dst, vaddr, len);
1223b3c1694SLeon Alrae     return 0;
1233b3c1694SLeon Alrae }
1243b3c1694SLeon Alrae 
1253b3c1694SLeon Alrae static int get_open_flags(target_ulong target_flags)
1263b3c1694SLeon Alrae {
1273b3c1694SLeon Alrae     int open_flags = 0;
1283b3c1694SLeon Alrae 
1293b3c1694SLeon Alrae     if (target_flags & UHIOpen_RDWR) {
1303b3c1694SLeon Alrae         open_flags |= O_RDWR;
1313b3c1694SLeon Alrae     } else if (target_flags & UHIOpen_WRONLY) {
1323b3c1694SLeon Alrae         open_flags |= O_WRONLY;
1333b3c1694SLeon Alrae     } else {
1343b3c1694SLeon Alrae         open_flags |= O_RDONLY;
1353b3c1694SLeon Alrae     }
1363b3c1694SLeon Alrae 
1373b3c1694SLeon Alrae     open_flags |= (target_flags & UHIOpen_APPEND) ? O_APPEND : 0;
1383b3c1694SLeon Alrae     open_flags |= (target_flags & UHIOpen_CREAT)  ? O_CREAT  : 0;
1393b3c1694SLeon Alrae     open_flags |= (target_flags & UHIOpen_TRUNC)  ? O_TRUNC  : 0;
1403b3c1694SLeon Alrae     open_flags |= (target_flags & UHIOpen_EXCL)   ? O_EXCL   : 0;
1413b3c1694SLeon Alrae 
1423b3c1694SLeon Alrae     return open_flags;
1433b3c1694SLeon Alrae }
1443b3c1694SLeon Alrae 
1453b3c1694SLeon Alrae static int write_to_file(CPUMIPSState *env, target_ulong fd, target_ulong vaddr,
1463b3c1694SLeon Alrae                          target_ulong len, target_ulong offset)
1473b3c1694SLeon Alrae {
1483b3c1694SLeon Alrae     int num_of_bytes;
1493b3c1694SLeon Alrae     void *dst = lock_user(VERIFY_READ, vaddr, len, 1);
1503b3c1694SLeon Alrae     if (!dst) {
1513b3c1694SLeon Alrae         errno = EFAULT;
1523b3c1694SLeon Alrae         return -1;
1533b3c1694SLeon Alrae     }
1543b3c1694SLeon Alrae 
1553b3c1694SLeon Alrae     if (offset) {
1563b3c1694SLeon Alrae #ifdef _WIN32
1573b3c1694SLeon Alrae         num_of_bytes = 0;
1583b3c1694SLeon Alrae #else
1593b3c1694SLeon Alrae         num_of_bytes = pwrite(fd, dst, len, offset);
1603b3c1694SLeon Alrae #endif
1613b3c1694SLeon Alrae     } else {
1623b3c1694SLeon Alrae         num_of_bytes = write(fd, dst, len);
1633b3c1694SLeon Alrae     }
1643b3c1694SLeon Alrae 
1653b3c1694SLeon Alrae     unlock_user(dst, vaddr, 0);
1663b3c1694SLeon Alrae     return num_of_bytes;
1673b3c1694SLeon Alrae }
1683b3c1694SLeon Alrae 
1693b3c1694SLeon Alrae static int read_from_file(CPUMIPSState *env, target_ulong fd,
1703b3c1694SLeon Alrae                           target_ulong vaddr, target_ulong len,
1713b3c1694SLeon Alrae                           target_ulong offset)
1723b3c1694SLeon Alrae {
1733b3c1694SLeon Alrae     int num_of_bytes;
1743b3c1694SLeon Alrae     void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
1753b3c1694SLeon Alrae     if (!dst) {
1763b3c1694SLeon Alrae         errno = EFAULT;
1773b3c1694SLeon Alrae         return -1;
1783b3c1694SLeon Alrae     }
1793b3c1694SLeon Alrae 
1803b3c1694SLeon Alrae     if (offset) {
1813b3c1694SLeon Alrae #ifdef _WIN32
1823b3c1694SLeon Alrae         num_of_bytes = 0;
1833b3c1694SLeon Alrae #else
1843b3c1694SLeon Alrae         num_of_bytes = pread(fd, dst, len, offset);
1853b3c1694SLeon Alrae #endif
1863b3c1694SLeon Alrae     } else {
1873b3c1694SLeon Alrae         num_of_bytes = read(fd, dst, len);
1883b3c1694SLeon Alrae     }
1893b3c1694SLeon Alrae 
1903b3c1694SLeon Alrae     unlock_user(dst, vaddr, len);
1913b3c1694SLeon Alrae     return num_of_bytes;
1923b3c1694SLeon Alrae }
1933b3c1694SLeon Alrae 
1943b3c1694SLeon Alrae static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
1953b3c1694SLeon Alrae                                target_ulong vaddr)
1963b3c1694SLeon Alrae {
1973b3c1694SLeon Alrae     int strsize = strlen(semihosting_get_arg(arg_num)) + 1;
1983b3c1694SLeon Alrae     char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0);
1993b3c1694SLeon Alrae     if (!dst) {
2003b3c1694SLeon Alrae         return -1;
2013b3c1694SLeon Alrae     }
2023b3c1694SLeon Alrae 
2033b3c1694SLeon Alrae     strcpy(dst, semihosting_get_arg(arg_num));
2043b3c1694SLeon Alrae 
2053b3c1694SLeon Alrae     unlock_user(dst, vaddr, strsize);
2063b3c1694SLeon Alrae     return 0;
2073b3c1694SLeon Alrae }
2083b3c1694SLeon Alrae 
2093b3c1694SLeon Alrae #define GET_TARGET_STRING(p, addr)              \
2103b3c1694SLeon Alrae     do {                                        \
2113b3c1694SLeon Alrae         p = lock_user_string(addr);             \
2123b3c1694SLeon Alrae         if (!p) {                               \
2133b3c1694SLeon Alrae             gpr[2] = -1;                        \
2143b3c1694SLeon Alrae             gpr[3] = EFAULT;                    \
21554fc33fdSDaniel Henrique Barboza             return;                             \
2163b3c1694SLeon Alrae         }                                       \
2173b3c1694SLeon Alrae     } while (0)
2183b3c1694SLeon Alrae 
21926e7e982SLeon Alrae #define GET_TARGET_STRINGS_2(p, addr, p2, addr2)        \
22026e7e982SLeon Alrae     do {                                                \
22126e7e982SLeon Alrae         p = lock_user_string(addr);                     \
22226e7e982SLeon Alrae         if (!p) {                                       \
22326e7e982SLeon Alrae             gpr[2] = -1;                                \
22426e7e982SLeon Alrae             gpr[3] = EFAULT;                            \
22554fc33fdSDaniel Henrique Barboza             return;                                     \
22626e7e982SLeon Alrae         }                                               \
22726e7e982SLeon Alrae         p2 = lock_user_string(addr2);                   \
22826e7e982SLeon Alrae         if (!p2) {                                      \
22926e7e982SLeon Alrae             unlock_user(p, addr, 0);                    \
23026e7e982SLeon Alrae             gpr[2] = -1;                                \
23126e7e982SLeon Alrae             gpr[3] = EFAULT;                            \
23254fc33fdSDaniel Henrique Barboza             return;                                     \
23326e7e982SLeon Alrae         }                                               \
23426e7e982SLeon Alrae     } while (0)
23526e7e982SLeon Alrae 
2363b3c1694SLeon Alrae #define FREE_TARGET_STRING(p, gpr)              \
2373b3c1694SLeon Alrae     do {                                        \
2383b3c1694SLeon Alrae         unlock_user(p, gpr, 0);                 \
2393b3c1694SLeon Alrae     } while (0)
2403b3c1694SLeon Alrae 
241*8ec7e3c5SRichard Henderson void mips_semihosting(CPUMIPSState *env)
2423b3c1694SLeon Alrae {
2433b3c1694SLeon Alrae     target_ulong *gpr = env->active_tc.gpr;
2443b3c1694SLeon Alrae     const UHIOp op = gpr[25];
2453b3c1694SLeon Alrae     char *p, *p2;
2463b3c1694SLeon Alrae 
2473b3c1694SLeon Alrae     switch (op) {
2483b3c1694SLeon Alrae     case UHI_exit:
2493b3c1694SLeon Alrae         qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]);
2503b3c1694SLeon Alrae         exit(gpr[4]);
2513b3c1694SLeon Alrae     case UHI_open:
2523b3c1694SLeon Alrae         GET_TARGET_STRING(p, gpr[4]);
2533b3c1694SLeon Alrae         if (!strcmp("/dev/stdin", p)) {
2543b3c1694SLeon Alrae             gpr[2] = 0;
2553b3c1694SLeon Alrae         } else if (!strcmp("/dev/stdout", p)) {
2563b3c1694SLeon Alrae             gpr[2] = 1;
2573b3c1694SLeon Alrae         } else if (!strcmp("/dev/stderr", p)) {
2583b3c1694SLeon Alrae             gpr[2] = 2;
2593b3c1694SLeon Alrae         } else {
2603b3c1694SLeon Alrae             gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]);
2612c44b19cSLeon Alrae             gpr[3] = errno_mips(errno);
2623b3c1694SLeon Alrae         }
2633b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
2643b3c1694SLeon Alrae         break;
2653b3c1694SLeon Alrae     case UHI_close:
2663b3c1694SLeon Alrae         if (gpr[4] < 3) {
2673b3c1694SLeon Alrae             /* ignore closing stdin/stdout/stderr */
2683b3c1694SLeon Alrae             gpr[2] = 0;
26954fc33fdSDaniel Henrique Barboza             return;
2703b3c1694SLeon Alrae         }
2713b3c1694SLeon Alrae         gpr[2] = close(gpr[4]);
2722c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
2733b3c1694SLeon Alrae         break;
2743b3c1694SLeon Alrae     case UHI_read:
2753b3c1694SLeon Alrae         gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], 0);
2762c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
2773b3c1694SLeon Alrae         break;
2783b3c1694SLeon Alrae     case UHI_write:
2793b3c1694SLeon Alrae         gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], 0);
2802c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
2813b3c1694SLeon Alrae         break;
2823b3c1694SLeon Alrae     case UHI_lseek:
2833b3c1694SLeon Alrae         gpr[2] = lseek(gpr[4], gpr[5], gpr[6]);
2842c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
2853b3c1694SLeon Alrae         break;
2863b3c1694SLeon Alrae     case UHI_unlink:
2873b3c1694SLeon Alrae         GET_TARGET_STRING(p, gpr[4]);
2883b3c1694SLeon Alrae         gpr[2] = remove(p);
2892c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
2903b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
2913b3c1694SLeon Alrae         break;
2923b3c1694SLeon Alrae     case UHI_fstat:
2933b3c1694SLeon Alrae         {
2943b3c1694SLeon Alrae             struct stat sbuf;
2953b3c1694SLeon Alrae             memset(&sbuf, 0, sizeof(sbuf));
2963b3c1694SLeon Alrae             gpr[2] = fstat(gpr[4], &sbuf);
2972c44b19cSLeon Alrae             gpr[3] = errno_mips(errno);
2983b3c1694SLeon Alrae             if (gpr[2]) {
29954fc33fdSDaniel Henrique Barboza                 return;
3003b3c1694SLeon Alrae             }
3013b3c1694SLeon Alrae             gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]);
3022c44b19cSLeon Alrae             gpr[3] = errno_mips(errno);
3033b3c1694SLeon Alrae         }
3043b3c1694SLeon Alrae         break;
3053b3c1694SLeon Alrae     case UHI_argc:
3063b3c1694SLeon Alrae         gpr[2] = semihosting_get_argc();
3073b3c1694SLeon Alrae         break;
3083b3c1694SLeon Alrae     case UHI_argnlen:
3093b3c1694SLeon Alrae         if (gpr[4] >= semihosting_get_argc()) {
3103b3c1694SLeon Alrae             gpr[2] = -1;
31154fc33fdSDaniel Henrique Barboza             return;
3123b3c1694SLeon Alrae         }
3133b3c1694SLeon Alrae         gpr[2] = strlen(semihosting_get_arg(gpr[4]));
3143b3c1694SLeon Alrae         break;
3153b3c1694SLeon Alrae     case UHI_argn:
3163b3c1694SLeon Alrae         if (gpr[4] >= semihosting_get_argc()) {
3173b3c1694SLeon Alrae             gpr[2] = -1;
31854fc33fdSDaniel Henrique Barboza             return;
3193b3c1694SLeon Alrae         }
3203b3c1694SLeon Alrae         gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]);
3213b3c1694SLeon Alrae         break;
3223b3c1694SLeon Alrae     case UHI_plog:
3233b3c1694SLeon Alrae         GET_TARGET_STRING(p, gpr[4]);
3243b3c1694SLeon Alrae         p2 = strstr(p, "%d");
3253b3c1694SLeon Alrae         if (p2) {
3263b3c1694SLeon Alrae             int char_num = p2 - p;
32754eb6cdaSAlex Bennée             GString *s = g_string_new_len(p, char_num);
32854eb6cdaSAlex Bennée             g_string_append_printf(s, "%d%s", (int)gpr[5], p2 + 2);
32954eb6cdaSAlex Bennée             gpr[2] = qemu_semihosting_log_out(s->str, s->len);
33054eb6cdaSAlex Bennée             g_string_free(s, true);
3313b3c1694SLeon Alrae         } else {
33254eb6cdaSAlex Bennée             gpr[2] = qemu_semihosting_log_out(p, strlen(p));
3333b3c1694SLeon Alrae         }
3343b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
3353b3c1694SLeon Alrae         break;
3363b3c1694SLeon Alrae     case UHI_assert:
33726e7e982SLeon Alrae         GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
3383b3c1694SLeon Alrae         printf("assertion '");
3393b3c1694SLeon Alrae         printf("\"%s\"", p);
3403b3c1694SLeon Alrae         printf("': file \"%s\", line %d\n", p2, (int)gpr[6]);
3413b3c1694SLeon Alrae         FREE_TARGET_STRING(p2, gpr[5]);
3423b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
3433b3c1694SLeon Alrae         abort();
3443b3c1694SLeon Alrae         break;
3453b3c1694SLeon Alrae     case UHI_pread:
3463b3c1694SLeon Alrae         gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
3472c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3483b3c1694SLeon Alrae         break;
3493b3c1694SLeon Alrae     case UHI_pwrite:
3503b3c1694SLeon Alrae         gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]);
3512c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3523b3c1694SLeon Alrae         break;
3533b3c1694SLeon Alrae #ifndef _WIN32
3543b3c1694SLeon Alrae     case UHI_link:
35526e7e982SLeon Alrae         GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]);
3563b3c1694SLeon Alrae         gpr[2] = link(p, p2);
3572c44b19cSLeon Alrae         gpr[3] = errno_mips(errno);
3583b3c1694SLeon Alrae         FREE_TARGET_STRING(p2, gpr[5]);
3593b3c1694SLeon Alrae         FREE_TARGET_STRING(p, gpr[4]);
3603b3c1694SLeon Alrae         break;
3613b3c1694SLeon Alrae #endif
3623b3c1694SLeon Alrae     default:
3633b3c1694SLeon Alrae         fprintf(stderr, "Unknown UHI operation %d\n", op);
3643b3c1694SLeon Alrae         abort();
3653b3c1694SLeon Alrae     }
3663b3c1694SLeon Alrae     return;
3673b3c1694SLeon Alrae }
368