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 93b3c1694SLeon Alrae * version 2 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 203b3c1694SLeon Alrae #include <sys/stat.h> 213b3c1694SLeon Alrae #include "cpu.h" 223b3c1694SLeon Alrae #include "exec/helper-proto.h" 233b3c1694SLeon Alrae #include "exec/softmmu-semi.h" 243b3c1694SLeon Alrae #include "exec/semihost.h" 253b3c1694SLeon Alrae 263b3c1694SLeon Alrae typedef enum UHIOp { 273b3c1694SLeon Alrae UHI_exit = 1, 283b3c1694SLeon Alrae UHI_open = 2, 293b3c1694SLeon Alrae UHI_close = 3, 303b3c1694SLeon Alrae UHI_read = 4, 313b3c1694SLeon Alrae UHI_write = 5, 323b3c1694SLeon Alrae UHI_lseek = 6, 333b3c1694SLeon Alrae UHI_unlink = 7, 343b3c1694SLeon Alrae UHI_fstat = 8, 353b3c1694SLeon Alrae UHI_argc = 9, 363b3c1694SLeon Alrae UHI_argnlen = 10, 373b3c1694SLeon Alrae UHI_argn = 11, 383b3c1694SLeon Alrae UHI_plog = 13, 393b3c1694SLeon Alrae UHI_assert = 14, 403b3c1694SLeon Alrae UHI_pread = 19, 413b3c1694SLeon Alrae UHI_pwrite = 20, 423b3c1694SLeon Alrae UHI_link = 22 433b3c1694SLeon Alrae } UHIOp; 443b3c1694SLeon Alrae 453b3c1694SLeon Alrae typedef struct UHIStat { 463b3c1694SLeon Alrae int16_t uhi_st_dev; 473b3c1694SLeon Alrae uint16_t uhi_st_ino; 483b3c1694SLeon Alrae uint32_t uhi_st_mode; 493b3c1694SLeon Alrae uint16_t uhi_st_nlink; 503b3c1694SLeon Alrae uint16_t uhi_st_uid; 513b3c1694SLeon Alrae uint16_t uhi_st_gid; 523b3c1694SLeon Alrae int16_t uhi_st_rdev; 533b3c1694SLeon Alrae uint64_t uhi_st_size; 543b3c1694SLeon Alrae uint64_t uhi_st_atime; 553b3c1694SLeon Alrae uint64_t uhi_st_spare1; 563b3c1694SLeon Alrae uint64_t uhi_st_mtime; 573b3c1694SLeon Alrae uint64_t uhi_st_spare2; 583b3c1694SLeon Alrae uint64_t uhi_st_ctime; 593b3c1694SLeon Alrae uint64_t uhi_st_spare3; 603b3c1694SLeon Alrae uint64_t uhi_st_blksize; 613b3c1694SLeon Alrae uint64_t uhi_st_blocks; 623b3c1694SLeon Alrae uint64_t uhi_st_spare4[2]; 633b3c1694SLeon Alrae } UHIStat; 643b3c1694SLeon Alrae 653b3c1694SLeon Alrae enum UHIOpenFlags { 663b3c1694SLeon Alrae UHIOpen_RDONLY = 0x0, 673b3c1694SLeon Alrae UHIOpen_WRONLY = 0x1, 683b3c1694SLeon Alrae UHIOpen_RDWR = 0x2, 693b3c1694SLeon Alrae UHIOpen_APPEND = 0x8, 703b3c1694SLeon Alrae UHIOpen_CREAT = 0x200, 713b3c1694SLeon Alrae UHIOpen_TRUNC = 0x400, 723b3c1694SLeon Alrae UHIOpen_EXCL = 0x800 733b3c1694SLeon Alrae }; 743b3c1694SLeon Alrae 752c44b19cSLeon Alrae /* Errno values taken from asm-mips/errno.h */ 762c44b19cSLeon Alrae static uint16_t host_to_mips_errno[] = { 772c44b19cSLeon Alrae [ENAMETOOLONG] = 78, 782c44b19cSLeon Alrae #ifdef EOVERFLOW 792c44b19cSLeon Alrae [EOVERFLOW] = 79, 802c44b19cSLeon Alrae #endif 812c44b19cSLeon Alrae #ifdef ELOOP 822c44b19cSLeon Alrae [ELOOP] = 90, 832c44b19cSLeon Alrae #endif 842c44b19cSLeon Alrae }; 852c44b19cSLeon Alrae 862c44b19cSLeon Alrae static int errno_mips(int err) 872c44b19cSLeon Alrae { 882c44b19cSLeon Alrae if (err < 0 || err >= ARRAY_SIZE(host_to_mips_errno)) { 892c44b19cSLeon Alrae return EINVAL; 902c44b19cSLeon Alrae } else if (host_to_mips_errno[err]) { 912c44b19cSLeon Alrae return host_to_mips_errno[err]; 922c44b19cSLeon Alrae } else { 932c44b19cSLeon Alrae return err; 942c44b19cSLeon Alrae } 952c44b19cSLeon Alrae } 962c44b19cSLeon Alrae 973b3c1694SLeon Alrae static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src, 983b3c1694SLeon Alrae target_ulong vaddr) 993b3c1694SLeon Alrae { 1003b3c1694SLeon Alrae hwaddr len = sizeof(struct UHIStat); 1013b3c1694SLeon Alrae UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0); 1023b3c1694SLeon Alrae if (!dst) { 1033b3c1694SLeon Alrae errno = EFAULT; 1043b3c1694SLeon Alrae return -1; 1053b3c1694SLeon Alrae } 1063b3c1694SLeon Alrae 1073b3c1694SLeon Alrae dst->uhi_st_dev = tswap16(src->st_dev); 1083b3c1694SLeon Alrae dst->uhi_st_ino = tswap16(src->st_ino); 1093b3c1694SLeon Alrae dst->uhi_st_mode = tswap32(src->st_mode); 1103b3c1694SLeon Alrae dst->uhi_st_nlink = tswap16(src->st_nlink); 1113b3c1694SLeon Alrae dst->uhi_st_uid = tswap16(src->st_uid); 1123b3c1694SLeon Alrae dst->uhi_st_gid = tswap16(src->st_gid); 1133b3c1694SLeon Alrae dst->uhi_st_rdev = tswap16(src->st_rdev); 1143b3c1694SLeon Alrae dst->uhi_st_size = tswap64(src->st_size); 1153b3c1694SLeon Alrae dst->uhi_st_atime = tswap64(src->st_atime); 1163b3c1694SLeon Alrae dst->uhi_st_mtime = tswap64(src->st_mtime); 1173b3c1694SLeon Alrae dst->uhi_st_ctime = tswap64(src->st_ctime); 1183b3c1694SLeon Alrae #ifdef _WIN32 1193b3c1694SLeon Alrae dst->uhi_st_blksize = 0; 1203b3c1694SLeon Alrae dst->uhi_st_blocks = 0; 1213b3c1694SLeon Alrae #else 1223b3c1694SLeon Alrae dst->uhi_st_blksize = tswap64(src->st_blksize); 1233b3c1694SLeon Alrae dst->uhi_st_blocks = tswap64(src->st_blocks); 1243b3c1694SLeon Alrae #endif 1253b3c1694SLeon Alrae unlock_user(dst, vaddr, len); 1263b3c1694SLeon Alrae return 0; 1273b3c1694SLeon Alrae } 1283b3c1694SLeon Alrae 1293b3c1694SLeon Alrae static int get_open_flags(target_ulong target_flags) 1303b3c1694SLeon Alrae { 1313b3c1694SLeon Alrae int open_flags = 0; 1323b3c1694SLeon Alrae 1333b3c1694SLeon Alrae if (target_flags & UHIOpen_RDWR) { 1343b3c1694SLeon Alrae open_flags |= O_RDWR; 1353b3c1694SLeon Alrae } else if (target_flags & UHIOpen_WRONLY) { 1363b3c1694SLeon Alrae open_flags |= O_WRONLY; 1373b3c1694SLeon Alrae } else { 1383b3c1694SLeon Alrae open_flags |= O_RDONLY; 1393b3c1694SLeon Alrae } 1403b3c1694SLeon Alrae 1413b3c1694SLeon Alrae open_flags |= (target_flags & UHIOpen_APPEND) ? O_APPEND : 0; 1423b3c1694SLeon Alrae open_flags |= (target_flags & UHIOpen_CREAT) ? O_CREAT : 0; 1433b3c1694SLeon Alrae open_flags |= (target_flags & UHIOpen_TRUNC) ? O_TRUNC : 0; 1443b3c1694SLeon Alrae open_flags |= (target_flags & UHIOpen_EXCL) ? O_EXCL : 0; 1453b3c1694SLeon Alrae 1463b3c1694SLeon Alrae return open_flags; 1473b3c1694SLeon Alrae } 1483b3c1694SLeon Alrae 1493b3c1694SLeon Alrae static int write_to_file(CPUMIPSState *env, target_ulong fd, target_ulong vaddr, 1503b3c1694SLeon Alrae target_ulong len, target_ulong offset) 1513b3c1694SLeon Alrae { 1523b3c1694SLeon Alrae int num_of_bytes; 1533b3c1694SLeon Alrae void *dst = lock_user(VERIFY_READ, vaddr, len, 1); 1543b3c1694SLeon Alrae if (!dst) { 1553b3c1694SLeon Alrae errno = EFAULT; 1563b3c1694SLeon Alrae return -1; 1573b3c1694SLeon Alrae } 1583b3c1694SLeon Alrae 1593b3c1694SLeon Alrae if (offset) { 1603b3c1694SLeon Alrae #ifdef _WIN32 1613b3c1694SLeon Alrae num_of_bytes = 0; 1623b3c1694SLeon Alrae #else 1633b3c1694SLeon Alrae num_of_bytes = pwrite(fd, dst, len, offset); 1643b3c1694SLeon Alrae #endif 1653b3c1694SLeon Alrae } else { 1663b3c1694SLeon Alrae num_of_bytes = write(fd, dst, len); 1673b3c1694SLeon Alrae } 1683b3c1694SLeon Alrae 1693b3c1694SLeon Alrae unlock_user(dst, vaddr, 0); 1703b3c1694SLeon Alrae return num_of_bytes; 1713b3c1694SLeon Alrae } 1723b3c1694SLeon Alrae 1733b3c1694SLeon Alrae static int read_from_file(CPUMIPSState *env, target_ulong fd, 1743b3c1694SLeon Alrae target_ulong vaddr, target_ulong len, 1753b3c1694SLeon Alrae target_ulong offset) 1763b3c1694SLeon Alrae { 1773b3c1694SLeon Alrae int num_of_bytes; 1783b3c1694SLeon Alrae void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0); 1793b3c1694SLeon Alrae if (!dst) { 1803b3c1694SLeon Alrae errno = EFAULT; 1813b3c1694SLeon Alrae return -1; 1823b3c1694SLeon Alrae } 1833b3c1694SLeon Alrae 1843b3c1694SLeon Alrae if (offset) { 1853b3c1694SLeon Alrae #ifdef _WIN32 1863b3c1694SLeon Alrae num_of_bytes = 0; 1873b3c1694SLeon Alrae #else 1883b3c1694SLeon Alrae num_of_bytes = pread(fd, dst, len, offset); 1893b3c1694SLeon Alrae #endif 1903b3c1694SLeon Alrae } else { 1913b3c1694SLeon Alrae num_of_bytes = read(fd, dst, len); 1923b3c1694SLeon Alrae } 1933b3c1694SLeon Alrae 1943b3c1694SLeon Alrae unlock_user(dst, vaddr, len); 1953b3c1694SLeon Alrae return num_of_bytes; 1963b3c1694SLeon Alrae } 1973b3c1694SLeon Alrae 1983b3c1694SLeon Alrae static int copy_argn_to_target(CPUMIPSState *env, int arg_num, 1993b3c1694SLeon Alrae target_ulong vaddr) 2003b3c1694SLeon Alrae { 2013b3c1694SLeon Alrae int strsize = strlen(semihosting_get_arg(arg_num)) + 1; 2023b3c1694SLeon Alrae char *dst = lock_user(VERIFY_WRITE, vaddr, strsize, 0); 2033b3c1694SLeon Alrae if (!dst) { 2043b3c1694SLeon Alrae return -1; 2053b3c1694SLeon Alrae } 2063b3c1694SLeon Alrae 2073b3c1694SLeon Alrae strcpy(dst, semihosting_get_arg(arg_num)); 2083b3c1694SLeon Alrae 2093b3c1694SLeon Alrae unlock_user(dst, vaddr, strsize); 2103b3c1694SLeon Alrae return 0; 2113b3c1694SLeon Alrae } 2123b3c1694SLeon Alrae 2133b3c1694SLeon Alrae #define GET_TARGET_STRING(p, addr) \ 2143b3c1694SLeon Alrae do { \ 2153b3c1694SLeon Alrae p = lock_user_string(addr); \ 2163b3c1694SLeon Alrae if (!p) { \ 2173b3c1694SLeon Alrae gpr[2] = -1; \ 2183b3c1694SLeon Alrae gpr[3] = EFAULT; \ 2193b3c1694SLeon Alrae goto uhi_done; \ 2203b3c1694SLeon Alrae } \ 2213b3c1694SLeon Alrae } while (0) 2223b3c1694SLeon Alrae 22326e7e982SLeon Alrae #define GET_TARGET_STRINGS_2(p, addr, p2, addr2) \ 22426e7e982SLeon Alrae do { \ 22526e7e982SLeon Alrae p = lock_user_string(addr); \ 22626e7e982SLeon Alrae if (!p) { \ 22726e7e982SLeon Alrae gpr[2] = -1; \ 22826e7e982SLeon Alrae gpr[3] = EFAULT; \ 22926e7e982SLeon Alrae goto uhi_done; \ 23026e7e982SLeon Alrae } \ 23126e7e982SLeon Alrae p2 = lock_user_string(addr2); \ 23226e7e982SLeon Alrae if (!p2) { \ 23326e7e982SLeon Alrae unlock_user(p, addr, 0); \ 23426e7e982SLeon Alrae gpr[2] = -1; \ 23526e7e982SLeon Alrae gpr[3] = EFAULT; \ 23626e7e982SLeon Alrae goto uhi_done; \ 23726e7e982SLeon Alrae } \ 23826e7e982SLeon Alrae } while (0) 23926e7e982SLeon Alrae 2403b3c1694SLeon Alrae #define FREE_TARGET_STRING(p, gpr) \ 2413b3c1694SLeon Alrae do { \ 2423b3c1694SLeon Alrae unlock_user(p, gpr, 0); \ 2433b3c1694SLeon Alrae } while (0) 2443b3c1694SLeon Alrae 2453b3c1694SLeon Alrae void helper_do_semihosting(CPUMIPSState *env) 2463b3c1694SLeon Alrae { 2473b3c1694SLeon Alrae target_ulong *gpr = env->active_tc.gpr; 2483b3c1694SLeon Alrae const UHIOp op = gpr[25]; 2493b3c1694SLeon Alrae char *p, *p2; 2503b3c1694SLeon Alrae 2513b3c1694SLeon Alrae switch (op) { 2523b3c1694SLeon Alrae case UHI_exit: 2533b3c1694SLeon Alrae qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]); 2543b3c1694SLeon Alrae exit(gpr[4]); 2553b3c1694SLeon Alrae case UHI_open: 2563b3c1694SLeon Alrae GET_TARGET_STRING(p, gpr[4]); 2573b3c1694SLeon Alrae if (!strcmp("/dev/stdin", p)) { 2583b3c1694SLeon Alrae gpr[2] = 0; 2593b3c1694SLeon Alrae } else if (!strcmp("/dev/stdout", p)) { 2603b3c1694SLeon Alrae gpr[2] = 1; 2613b3c1694SLeon Alrae } else if (!strcmp("/dev/stderr", p)) { 2623b3c1694SLeon Alrae gpr[2] = 2; 2633b3c1694SLeon Alrae } else { 2643b3c1694SLeon Alrae gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]); 2652c44b19cSLeon Alrae gpr[3] = errno_mips(errno); 2663b3c1694SLeon Alrae } 2673b3c1694SLeon Alrae FREE_TARGET_STRING(p, gpr[4]); 2683b3c1694SLeon Alrae break; 2693b3c1694SLeon Alrae case UHI_close: 2703b3c1694SLeon Alrae if (gpr[4] < 3) { 2713b3c1694SLeon Alrae /* ignore closing stdin/stdout/stderr */ 2723b3c1694SLeon Alrae gpr[2] = 0; 2733b3c1694SLeon Alrae goto uhi_done; 2743b3c1694SLeon Alrae } 2753b3c1694SLeon Alrae gpr[2] = close(gpr[4]); 2762c44b19cSLeon Alrae gpr[3] = errno_mips(errno); 2773b3c1694SLeon Alrae break; 2783b3c1694SLeon Alrae case UHI_read: 2793b3c1694SLeon Alrae gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], 0); 2802c44b19cSLeon Alrae gpr[3] = errno_mips(errno); 2813b3c1694SLeon Alrae break; 2823b3c1694SLeon Alrae case UHI_write: 2833b3c1694SLeon Alrae gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], 0); 2842c44b19cSLeon Alrae gpr[3] = errno_mips(errno); 2853b3c1694SLeon Alrae break; 2863b3c1694SLeon Alrae case UHI_lseek: 2873b3c1694SLeon Alrae gpr[2] = lseek(gpr[4], gpr[5], gpr[6]); 2882c44b19cSLeon Alrae gpr[3] = errno_mips(errno); 2893b3c1694SLeon Alrae break; 2903b3c1694SLeon Alrae case UHI_unlink: 2913b3c1694SLeon Alrae GET_TARGET_STRING(p, gpr[4]); 2923b3c1694SLeon Alrae gpr[2] = remove(p); 2932c44b19cSLeon Alrae gpr[3] = errno_mips(errno); 2943b3c1694SLeon Alrae FREE_TARGET_STRING(p, gpr[4]); 2953b3c1694SLeon Alrae break; 2963b3c1694SLeon Alrae case UHI_fstat: 2973b3c1694SLeon Alrae { 2983b3c1694SLeon Alrae struct stat sbuf; 2993b3c1694SLeon Alrae memset(&sbuf, 0, sizeof(sbuf)); 3003b3c1694SLeon Alrae gpr[2] = fstat(gpr[4], &sbuf); 3012c44b19cSLeon Alrae gpr[3] = errno_mips(errno); 3023b3c1694SLeon Alrae if (gpr[2]) { 3033b3c1694SLeon Alrae goto uhi_done; 3043b3c1694SLeon Alrae } 3053b3c1694SLeon Alrae gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]); 3062c44b19cSLeon Alrae gpr[3] = errno_mips(errno); 3073b3c1694SLeon Alrae } 3083b3c1694SLeon Alrae break; 3093b3c1694SLeon Alrae case UHI_argc: 3103b3c1694SLeon Alrae gpr[2] = semihosting_get_argc(); 3113b3c1694SLeon Alrae break; 3123b3c1694SLeon Alrae case UHI_argnlen: 3133b3c1694SLeon Alrae if (gpr[4] >= semihosting_get_argc()) { 3143b3c1694SLeon Alrae gpr[2] = -1; 3153b3c1694SLeon Alrae goto uhi_done; 3163b3c1694SLeon Alrae } 3173b3c1694SLeon Alrae gpr[2] = strlen(semihosting_get_arg(gpr[4])); 3183b3c1694SLeon Alrae break; 3193b3c1694SLeon Alrae case UHI_argn: 3203b3c1694SLeon Alrae if (gpr[4] >= semihosting_get_argc()) { 3213b3c1694SLeon Alrae gpr[2] = -1; 3223b3c1694SLeon Alrae goto uhi_done; 3233b3c1694SLeon Alrae } 3243b3c1694SLeon Alrae gpr[2] = copy_argn_to_target(env, gpr[4], gpr[5]); 3253b3c1694SLeon Alrae break; 3263b3c1694SLeon Alrae case UHI_plog: 3273b3c1694SLeon Alrae GET_TARGET_STRING(p, gpr[4]); 3283b3c1694SLeon Alrae p2 = strstr(p, "%d"); 3293b3c1694SLeon Alrae if (p2) { 3303b3c1694SLeon Alrae int char_num = p2 - p; 3313b3c1694SLeon Alrae char *buf = g_malloc(char_num + 1); 3323b3c1694SLeon Alrae strncpy(buf, p, char_num); 3333b3c1694SLeon Alrae buf[char_num] = '\0'; 3343b3c1694SLeon Alrae gpr[2] = printf("%s%d%s", buf, (int)gpr[5], p2 + 2); 3353b3c1694SLeon Alrae g_free(buf); 3363b3c1694SLeon Alrae } else { 3373b3c1694SLeon Alrae gpr[2] = printf("%s", p); 3383b3c1694SLeon Alrae } 3393b3c1694SLeon Alrae FREE_TARGET_STRING(p, gpr[4]); 3403b3c1694SLeon Alrae break; 3413b3c1694SLeon Alrae case UHI_assert: 34226e7e982SLeon Alrae GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]); 3433b3c1694SLeon Alrae printf("assertion '"); 3443b3c1694SLeon Alrae printf("\"%s\"", p); 3453b3c1694SLeon Alrae printf("': file \"%s\", line %d\n", p2, (int)gpr[6]); 3463b3c1694SLeon Alrae FREE_TARGET_STRING(p2, gpr[5]); 3473b3c1694SLeon Alrae FREE_TARGET_STRING(p, gpr[4]); 3483b3c1694SLeon Alrae abort(); 3493b3c1694SLeon Alrae break; 3503b3c1694SLeon Alrae case UHI_pread: 3513b3c1694SLeon Alrae gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6], gpr[7]); 3522c44b19cSLeon Alrae gpr[3] = errno_mips(errno); 3533b3c1694SLeon Alrae break; 3543b3c1694SLeon Alrae case UHI_pwrite: 3553b3c1694SLeon Alrae gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6], gpr[7]); 3562c44b19cSLeon Alrae gpr[3] = errno_mips(errno); 3573b3c1694SLeon Alrae break; 3583b3c1694SLeon Alrae #ifndef _WIN32 3593b3c1694SLeon Alrae case UHI_link: 36026e7e982SLeon Alrae GET_TARGET_STRINGS_2(p, gpr[4], p2, gpr[5]); 3613b3c1694SLeon Alrae gpr[2] = link(p, p2); 3622c44b19cSLeon Alrae gpr[3] = errno_mips(errno); 3633b3c1694SLeon Alrae FREE_TARGET_STRING(p2, gpr[5]); 3643b3c1694SLeon Alrae FREE_TARGET_STRING(p, gpr[4]); 3653b3c1694SLeon Alrae break; 3663b3c1694SLeon Alrae #endif 3673b3c1694SLeon Alrae default: 3683b3c1694SLeon Alrae fprintf(stderr, "Unknown UHI operation %d\n", op); 3693b3c1694SLeon Alrae abort(); 3703b3c1694SLeon Alrae } 3713b3c1694SLeon Alrae uhi_done: 3723b3c1694SLeon Alrae return; 3733b3c1694SLeon Alrae } 374