/*************************************************************** __CPU_SYSCALLS.C This file contains source code of MCPU system calls. PART OF : CPU - library . USAGE : Internal only . NOTE : NONE . Copyright (C) 2026 by Andrew V.Kosteltsev. All Rights Reserved. ***************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #define __NR_brk 10 #define __NR_gettimeofday 0x01c #define __NR_clock_getres 0x021 #define __NR_clock_gettime 0x022 #define __NR_nanosleep 0x030 #define __NR_clock_nanosleep 0x031 #define __NR_read 0x100 #define __NR_write 0x101 #define __NR_lseek 0x102 #define __NR_open 0x103 #define __NR_creat 0x104 #define __NR_close 0x105 #define __NR_link 0x106 #define __NR_unlink 0x107 #define __NR_chdir 0x108 #define __NR_mkdir 0x109 #define __NR_chmod 0x10b #define __NR_chown 0x10c #define __NR_access 0x10f #define __NR_rename 0x111 #define __NR_rmdir 0x112 #define __NR_symlink 0x113 #define __NR_readlink 0x114 #define __NR_stat 0x115 #define __NR_fstat 0x116 #define __NR_lstat 0x117 #define __NR_fcntl 0x119 #define __NR_pipe2 0x11a #define __NR_getdents 0x11d #define __NR_select 0x11e #define __NR_fsync 0x120 #define __NR_truncate 0x121 #define __NR_ftruncate 0x122 #define __NR_fchmod 0x123 #define __NR_fchown 0x124 #define __NR_fchdir 0x125 #define __NR_dup 0x126 #define __NR_dup2 0x127 #define CPU_PATH_MAX 4096U static __mpu_uint64_t __cpu_syscall_error( int error ) { __mpu_int64_t ret = -(__mpu_int64_t)error; return( (__mpu_uint64_t)ret ); } /* End of __cpu_syscall_error() */ static __mpu_uint32_t __cpu_syscall_nargs( void ) { return( __cpu_data_get_u32( __cpu_reg_ptr( 32, CPU_SYSCALL_NARGS_ADDR ) ) ); } /* End of __cpu_syscall_nargs() */ static __mpu_uint64_t __cpu_syscall_arg( unsigned int n ) { static const __mpu_uint32_t address[CPU_SYSCALL_MAX_ARGS] = { CPU_SYSCALL_ARG0_ADDR, CPU_SYSCALL_ARG1_ADDR, CPU_SYSCALL_ARG2_ADDR, CPU_SYSCALL_ARG3_ADDR, CPU_SYSCALL_ARG4_ADDR, CPU_SYSCALL_ARG5_ADDR }; if( n >= CPU_SYSCALL_MAX_ARGS ) return( 0 ); return( __cpu_data_get_u64( __cpu_reg_ptr( 64, address[n] ) ) ); } /* End of __cpu_syscall_arg() */ static int __cpu_memory_resolve( __mpu_uint64_t ptr, __mpu_uint64_t size, int write, __mpu_UNIT_t **memory ) { __mpu_UNIT_t *base = (__mpu_UNIT_t *)0; __mpu_uint64_t limit = 0; __mpu_uint64_t offset; unsigned int segment; if( !memory ) return( __MCPU_EFAULT ); *memory = (__mpu_UNIT_t *)0; if( ptr == CPU_NULL_PTR ) return( __MCPU_EFAULT ); segment = __cpu_ptr_segment( ptr ); offset = __cpu_ptr_offset( ptr ); switch( segment ) { case CPU_PTR_SEG_DATA: base = __DATA; limit = __DSIZE; break; case CPU_PTR_SEG_STACK: base = __STACK; limit = __SSIZE; break; case CPU_PTR_SEG_PROGRAM: if( write ) return( __MCPU_EFAULT ); base = __PROGRAM; limit = __PSIZE; break; case CPU_PTR_SEG_CONTROL: if( write ) return( __MCPU_EFAULT ); base = __CONTROL; limit = __CSIZE; break; case CPU_PTR_SEG_INPUT: if( write ) return( __MCPU_EFAULT ); base = __INPUT; limit = __ISIZE; break; case CPU_PTR_SEG_OUTPUT: base = __OUTPUT; limit = __OSIZE; break; case CPU_PTR_SEG_TRACE: base = __TRACE; limit = __TSIZE; break; case CPU_PTR_SEG_HEAP: base = __HEAP; limit = __HBRK; if( offset < CPU_HEAP_BEGIN ) return( __MCPU_EFAULT ); break; default: return( __MCPU_EFAULT ); } if( !base || offset > limit || size > limit - offset ) return( __MCPU_EFAULT ); *memory = base + offset; return( 0 ); } /* End of __cpu_memory_resolve() */ static int __cpu_copyin( void *dst, __mpu_uint64_t src, __mpu_uint64_t size ) { __mpu_UNIT_t *memory; int error; if( !size ) return( 0 ); if( !dst ) return( __MCPU_EFAULT ); error = __cpu_memory_resolve( src, size, 0, &memory ); if( error ) return( error ); memcpy( dst, memory, (size_t)size ); return( 0 ); } /* End of __cpu_copyin() */ static int __cpu_copyout( __mpu_uint64_t dst, const void *src, __mpu_uint64_t size ) { __mpu_UNIT_t *memory; int error; if( !size ) return( 0 ); if( !src ) return( __MCPU_EFAULT ); error = __cpu_memory_resolve( dst, size, 1, &memory ); if( error ) return( error ); memcpy( memory, src, (size_t)size ); return( 0 ); } /* End of __cpu_copyout() */ static int __cpu_utf8_valid( const unsigned char *s, size_t n ) { size_t i = 0; while( i < n ) { unsigned int c = s[i++]; if( c < 0x80U ) continue; if( c >= 0xc2U && c <= 0xdfU ) { if( i >= n || ( s[i] & 0xc0U ) != 0x80U ) return( 0 ); ++i; continue; } if( c == 0xe0U ) { if( i + 1 >= n || s[i] < 0xa0U || s[i] > 0xbfU || ( s[i + 1] & 0xc0U ) != 0x80U ) return( 0 ); i += 2; continue; } if( c >= 0xe1U && c <= 0xecU ) { if( i + 1 >= n || ( s[i] & 0xc0U ) != 0x80U || ( s[i + 1] & 0xc0U ) != 0x80U ) return( 0 ); i += 2; continue; } if( c == 0xedU ) { if( i + 1 >= n || s[i] < 0x80U || s[i] > 0x9fU || ( s[i + 1] & 0xc0U ) != 0x80U ) return( 0 ); i += 2; continue; } if( c >= 0xeeU && c <= 0xefU ) { if( i + 1 >= n || ( s[i] & 0xc0U ) != 0x80U || ( s[i + 1] & 0xc0U ) != 0x80U ) return( 0 ); i += 2; continue; } if( c == 0xf0U ) { if( i + 2 >= n || s[i] < 0x90U || s[i] > 0xbfU || ( s[i + 1] & 0xc0U ) != 0x80U || ( s[i + 2] & 0xc0U ) != 0x80U ) return( 0 ); i += 3; continue; } if( c >= 0xf1U && c <= 0xf3U ) { if( i + 2 >= n || ( s[i] & 0xc0U ) != 0x80U || ( s[i + 1] & 0xc0U ) != 0x80U || ( s[i + 2] & 0xc0U ) != 0x80U ) return( 0 ); i += 3; continue; } if( c == 0xf4U ) { if( i + 2 >= n || s[i] < 0x80U || s[i] > 0x8fU || ( s[i + 1] & 0xc0U ) != 0x80U || ( s[i + 2] & 0xc0U ) != 0x80U ) return( 0 ); i += 3; continue; } return( 0 ); } return( 1 ); } /* End of __cpu_utf8_valid() */ static int __cpu_copyinstr( char **dst, __mpu_uint64_t src ) { __mpu_UNIT_t *memory; __mpu_uint64_t offset; __mpu_uint64_t limit; __mpu_uint64_t n; unsigned int segment; char *s; if( !dst ) return( __MCPU_EFAULT ); *dst = (char *)0; if( src == CPU_NULL_PTR ) return( __MCPU_EFAULT ); segment = __cpu_ptr_segment( src ); offset = __cpu_ptr_offset( src ); if( __cpu_memory_resolve( src, 1, 0, &memory ) != 0 ) return( __MCPU_EFAULT ); switch( segment ) { case CPU_PTR_SEG_DATA: limit = __DSIZE; break; case CPU_PTR_SEG_STACK: limit = __SSIZE; break; case CPU_PTR_SEG_PROGRAM: limit = __PSIZE; break; case CPU_PTR_SEG_CONTROL: limit = __CSIZE; break; case CPU_PTR_SEG_INPUT: limit = __ISIZE; break; case CPU_PTR_SEG_OUTPUT: limit = __OSIZE; break; case CPU_PTR_SEG_TRACE: limit = __TSIZE; break; case CPU_PTR_SEG_HEAP: limit = __HBRK; break; default: return( __MCPU_EFAULT ); } n = 0; while( offset + n < limit && n < CPU_PATH_MAX ) { if( memory[n] == 0 ) break; ++n; } if( offset + n >= limit || n >= CPU_PATH_MAX ) return( __MCPU_ENAMETOOLONG ); if( !__cpu_utf8_valid( memory, (size_t)n ) ) return( __MCPU_EILSEQ ); s = (char *)malloc( (size_t)n + 1U ); if( !s ) return( __MCPU_ENOMEM ); memcpy( s, memory, (size_t)n ); s[n] = '\0'; *dst = s; return( 0 ); } /* End of __cpu_copyinstr() */ void __cpu_fd_context_init( void ) { unsigned int i; if( !pcctx ) return; for( i = 0; i < CPU_GUEST_FD_MAX; ++i ) { pcctx->_fd[i].host_fd = -1; pcctx->_fd[i].owned = 0; pcctx->_fd[i].flags = 0; } pcctx->_fd[0].host_fd = 0; pcctx->_fd[1].host_fd = 1; pcctx->_fd[2].host_fd = 2; pcctx->_fd[0].flags = 0; pcctx->_fd[1].flags = 0; pcctx->_fd[2].flags = 0; pcctx->_fd_initialized = 1; } /* End of __cpu_fd_context_init() */ void __cpu_fd_context_free( void ) { unsigned int i; if( !pcctx || !pcctx->_fd_initialized ) return; for( i = 0; i < CPU_GUEST_FD_MAX; ++i ) { if( pcctx->_fd[i].host_fd >= 0 && pcctx->_fd[i].owned ) (void)__cpu_sys_close( pcctx->_fd[i].host_fd ); pcctx->_fd[i].host_fd = -1; pcctx->_fd[i].owned = 0; pcctx->_fd[i].flags = 0; } pcctx->_fd_initialized = 0; } /* End of __cpu_fd_context_free() */ void __cpu_cwd_context_init( void ) { __mpu_int64_t ret; if( !pcctx ) return; pcctx->_cwd_fd = -1; pcctx->_cwd_initialized = 0; ret = __cpu_sys_cwd_init(); if( ret < 0 ) return; pcctx->_cwd_fd = (int)ret; pcctx->_cwd_initialized = 1; } /* End of __cpu_cwd_context_init() */ void __cpu_cwd_context_free( void ) { if( !pcctx || !pcctx->_cwd_initialized ) return; if( pcctx->_cwd_fd >= 0 ) (void)__cpu_sys_close( pcctx->_cwd_fd ); pcctx->_cwd_fd = -1; pcctx->_cwd_initialized = 0; } /* End of __cpu_cwd_context_free() */ static int __cpu_fd_get( __mpu_uint64_t fd, int *host_fd ) { if( !pcctx || !pcctx->_fd_initialized || fd >= CPU_GUEST_FD_MAX || pcctx->_fd[fd].host_fd < 0 ) return( __MCPU_EBADF ); if( host_fd ) *host_fd = pcctx->_fd[fd].host_fd; return( 0 ); } /* End of __cpu_fd_get() */ static int __cpu_fd_find_from( __mpu_uint64_t minimum ) { unsigned int fd; if( !pcctx || !pcctx->_fd_initialized || minimum >= CPU_GUEST_FD_MAX ) return( -1 ); for( fd = (unsigned int)minimum; fd < CPU_GUEST_FD_MAX; ++fd ) if( pcctx->_fd[fd].host_fd < 0 ) return( (int)fd ); return( -1 ); } /* End of __cpu_fd_find_from() */ static int __cpu_fd_install_from( int host_fd, __mpu_uint64_t minimum, unsigned int flags ) { int fd; if( host_fd < 0 ) return( -1 ); fd = __cpu_fd_find_from( minimum ); if( fd < 0 ) return( -1 ); pcctx->_fd[fd].host_fd = host_fd; pcctx->_fd[fd].owned = 1; pcctx->_fd[fd].flags = flags; return( fd ); } /* End of __cpu_fd_install_from() */ static int __cpu_fd_install( int host_fd ) { return( __cpu_fd_install_from( host_fd, 3, 0 ) ); } /* End of __cpu_fd_install() */ static __mpu_uint64_t __cpu_stat_i64_bits( __mpu_int64_t value ) { __mpu_uint64_t bits; memcpy( &bits, &value, sizeof( bits ) ); return( bits ); } /* End of __cpu_stat_i64_bits() */ static int __cpu_stat_copyout( __mpu_uint64_t ptr, const struct __cpu_stat *st ) { __mpu_UNIT_t data[__CPU_STAT_SIZE]; if( !st ) return( __MCPU_EFAULT ); memset( data, 0, sizeof( data ) ); __cpu_data_put_u64( data + __CPU_STAT_ST_DEV, st->st_dev ); __cpu_data_put_u64( data + __CPU_STAT_ST_INO, st->st_ino ); __cpu_data_put_u64( data + __CPU_STAT_ST_MODE, st->st_mode ); __cpu_data_put_u64( data + __CPU_STAT_ST_NLINK, st->st_nlink ); __cpu_data_put_u64( data + __CPU_STAT_ST_UID, st->st_uid ); __cpu_data_put_u64( data + __CPU_STAT_ST_GID, st->st_gid ); __cpu_data_put_u64( data + __CPU_STAT_ST_RDEV, st->st_rdev ); __cpu_data_put_u64( data + __CPU_STAT_ST_SIZE, __cpu_stat_i64_bits( st->st_size ) ); __cpu_data_put_u64( data + __CPU_STAT_ST_BLKSIZE, __cpu_stat_i64_bits( st->st_blksize ) ); __cpu_data_put_u64( data + __CPU_STAT_ST_BLOCKS, __cpu_stat_i64_bits( st->st_blocks ) ); __cpu_data_put_u64( data + __CPU_STAT_ST_ATIME_SEC, __cpu_stat_i64_bits( st->st_atime_sec ) ); __cpu_data_put_u64( data + __CPU_STAT_ST_ATIME_NSEC, st->st_atime_nsec ); __cpu_data_put_u64( data + __CPU_STAT_ST_MTIME_SEC, __cpu_stat_i64_bits( st->st_mtime_sec ) ); __cpu_data_put_u64( data + __CPU_STAT_ST_MTIME_NSEC, st->st_mtime_nsec ); __cpu_data_put_u64( data + __CPU_STAT_ST_CTIME_SEC, __cpu_stat_i64_bits( st->st_ctime_sec ) ); __cpu_data_put_u64( data + __CPU_STAT_ST_CTIME_NSEC, st->st_ctime_nsec ); return( __cpu_copyout( ptr, data, sizeof( data ) ) ); } /* End of __cpu_stat_copyout() */ static __mpu_uint64_t __cpu_dirent_i64_bits( __mpu_int64_t value ) { __mpu_uint64_t bits; memcpy( &bits, &value, sizeof( bits ) ); return( bits ); } /* End of __cpu_dirent_i64_bits() */ static int __cpu_dirent_copyout( __mpu_uint64_t ptr, const struct __cpu_dirent *de, __mpu_uint64_t count ) { __mpu_UNIT_t *data; __mpu_uint64_t nrecords; __mpu_uint64_t i; int error; if( !de && count ) return( __MCPU_EFAULT ); if( count % __CPU_DIRENT_SIZE != 0 ) return( __MCPU_EINVAL ); if( count > (__mpu_uint64_t)(size_t)-1 ) return( __MCPU_EINVAL ); if( !count ) return( 0 ); data = (__mpu_UNIT_t *)calloc( 1, (size_t)count ); if( !data ) return( __MCPU_ENOMEM ); nrecords = count / __CPU_DIRENT_SIZE; for( i = 0; i < nrecords; ++i ) { __mpu_UNIT_t *record = data + i * __CPU_DIRENT_SIZE; __cpu_data_put_u64( record + __CPU_DIRENT_D_INO, de[i].d_ino ); __cpu_data_put_u64( record + __CPU_DIRENT_D_OFF, __cpu_dirent_i64_bits( de[i].d_off ) ); __cpu_data_put_u64( record + __CPU_DIRENT_D_RECLEN, de[i].d_reclen ); __cpu_data_put_u64( record + __CPU_DIRENT_D_TYPE, de[i].d_type ); memcpy( record + __CPU_DIRENT_D_NAME, de[i].d_name, __CPU_DIRENT_NAME_SIZE ); } error = __cpu_copyout( ptr, data, count ); free( data ); return( error ); } /* End of __cpu_dirent_copyout() */ static __mpu_int64_t __cpu_select_i64_from_bits( __mpu_uint64_t bits ) { __mpu_int64_t value; memcpy( &value, &bits, sizeof( value ) ); return( value ); } /* End of __cpu_select_i64_from_bits() */ static int __cpu_fdset_load( __mpu_uint64_t ptr, __mpu_uint64_t words[__CPU_FD_SET_WORDS] ) { __mpu_UNIT_t data[__CPU_FD_SET_SIZE]; __mpu_UNIT_t *memory; unsigned int i; int error; error = __cpu_memory_resolve( ptr, __CPU_FD_SET_SIZE, 1, &memory ); if( error ) return( error ); (void)memory; error = __cpu_copyin( data, ptr, sizeof( data ) ); if( error ) return( error ); for( i = 0; i < __CPU_FD_SET_WORDS; ++i ) words[i] = __cpu_data_get_u64( data + i * 8U ); return( 0 ); } /* End of __cpu_fdset_load() */ static int __cpu_fdset_store( __mpu_uint64_t ptr, const __mpu_uint64_t words[__CPU_FD_SET_WORDS] ) { __mpu_UNIT_t data[__CPU_FD_SET_SIZE]; unsigned int i; memset( data, 0, sizeof( data ) ); for( i = 0; i < __CPU_FD_SET_WORDS; ++i ) __cpu_data_put_u64( data + i * 8U, words[i] ); return( __cpu_copyout( ptr, data, sizeof( data ) ) ); } /* End of __cpu_fdset_store() */ static int __cpu_fdset_isset( const __mpu_uint64_t words[__CPU_FD_SET_WORDS], unsigned int fd ) { unsigned int word = fd / 64U; unsigned int bit = fd % 64U; return( ( words[word] & ( (__mpu_uint64_t)1U << bit ) ) != 0 ); } /* End of __cpu_fdset_isset() */ static void __cpu_fdset_set( __mpu_uint64_t words[__CPU_FD_SET_WORDS], unsigned int fd ) { unsigned int word = fd / 64U; unsigned int bit = fd % 64U; words[word] |= ( (__mpu_uint64_t)1U << bit ); } /* End of __cpu_fdset_set() */ static int __cpu_timeval_load( __mpu_uint64_t ptr, struct __cpu_timeval *timeout ) { __mpu_UNIT_t data[__CPU_TIMEVAL_SIZE]; int error; if( !timeout ) return( __MCPU_EFAULT ); error = __cpu_copyin( data, ptr, sizeof( data ) ); if( error ) return( error ); timeout->tv_sec = __cpu_select_i64_from_bits( __cpu_data_get_u64( data + __CPU_TIMEVAL_TV_SEC ) ); timeout->tv_usec = __cpu_select_i64_from_bits( __cpu_data_get_u64( data + __CPU_TIMEVAL_TV_USEC ) ); if( timeout->tv_sec < 0 || timeout->tv_usec < 0 || timeout->tv_usec > 999999 ) return( __MCPU_EINVAL ); return( 0 ); } /* End of __cpu_timeval_load() */ static int __cpu_timespec_load( __mpu_uint64_t ptr, struct __cpu_timespec *ts ) { __mpu_UNIT_t data[__CPU_TIMESPEC_SIZE]; int error; if( !ts ) return( __MCPU_EFAULT ); error = __cpu_copyin( data, ptr, sizeof( data ) ); if( error ) return( error ); ts->tv_sec = __cpu_select_i64_from_bits( __cpu_data_get_u64( data + __CPU_TIMESPEC_TV_SEC ) ); ts->tv_nsec = __cpu_select_i64_from_bits( __cpu_data_get_u64( data + __CPU_TIMESPEC_TV_NSEC ) ); if( ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec > 999999999 ) return( __MCPU_EINVAL ); return( 0 ); } /* End of __cpu_timespec_load() */ static __mpu_uint64_t __cpu_time_i64_bits( __mpu_int64_t value ) { __mpu_uint64_t bits; memcpy( &bits, &value, sizeof( bits ) ); return( bits ); } /* End of __cpu_time_i64_bits() */ static int __cpu_timeval_copyout( __mpu_uint64_t ptr, const struct __cpu_timeval *tv ) { __mpu_UNIT_t data[__CPU_TIMEVAL_SIZE]; if( !tv ) return( __MCPU_EFAULT ); memset( data, 0, sizeof( data ) ); __cpu_data_put_u64( data + __CPU_TIMEVAL_TV_SEC, __cpu_time_i64_bits( tv->tv_sec ) ); __cpu_data_put_u64( data + __CPU_TIMEVAL_TV_USEC, __cpu_time_i64_bits( tv->tv_usec ) ); return( __cpu_copyout( ptr, data, sizeof( data ) ) ); } /* End of __cpu_timeval_copyout() */ static int __cpu_timespec_copyout( __mpu_uint64_t ptr, const struct __cpu_timespec *ts ) { __mpu_UNIT_t data[__CPU_TIMESPEC_SIZE]; if( !ts ) return( __MCPU_EFAULT ); memset( data, 0, sizeof( data ) ); __cpu_data_put_u64( data + __CPU_TIMESPEC_TV_SEC, __cpu_time_i64_bits( ts->tv_sec ) ); __cpu_data_put_u64( data + __CPU_TIMESPEC_TV_NSEC, __cpu_time_i64_bits( ts->tv_nsec ) ); return( __cpu_copyout( ptr, data, sizeof( data ) ) ); } /* End of __cpu_timespec_copyout() */ static __mpu_uint64_t __cpu_current_brk( void ) { __mpu_uint64_t ptr = CPU_NULL_PTR; if( !__HEAP || __HLIMIT < CPU_HEAP_BEGIN || __HBRK < CPU_HEAP_BEGIN ) return( CPU_NULL_PTR ); if( __cpu_ptr_make( &ptr, CPU_PTR_SEG_HEAP, __HBRK ) != 0 ) return( CPU_NULL_PTR ); return( ptr ); } /* End of __cpu_current_brk() */ __mpu_uint64_t __cpu_SYS_brk( __mpu_uint32_t sysno ) { __mpu_uint64_t arg; __mpu_uint64_t brk; __mpu_uint64_t ptr = CPU_NULL_PTR; (void)sysno; if( __cpu_syscall_nargs() != 1 ) return( __cpu_current_brk() ); arg = __cpu_syscall_arg( 0 ); if( arg == CPU_NULL_PTR ) return( __cpu_current_brk() ); if( __cpu_ptr_segment( arg ) != CPU_PTR_SEG_HEAP ) return( __cpu_current_brk() ); brk = __cpu_heap_brk( __cpu_ptr_offset( arg ) ); if( brk < CPU_HEAP_BEGIN || __cpu_ptr_make( &ptr, CPU_PTR_SEG_HEAP, brk ) != 0 ) return( CPU_NULL_PTR ); return( ptr ); } /* End of __cpu_SYS_brk() */ __mpu_uint64_t __cpu_SYS_close( __mpu_uint32_t sysno ) { __mpu_uint64_t fd; __mpu_int64_t ret; int host_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); if( pcctx->_fd[fd].owned ) { ret = __cpu_sys_close( host_fd ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); } pcctx->_fd[fd].host_fd = -1; pcctx->_fd[fd].owned = 0; pcctx->_fd[fd].flags = 0; return( 0 ); } /* End of __cpu_SYS_close() */ __mpu_uint64_t __cpu_SYS_dup( __mpu_uint32_t sysno ) { __mpu_uint64_t fd; __mpu_int64_t ret; int host_fd; int new_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); new_fd = __cpu_fd_find_from( 0 ); if( new_fd < 0 ) return( __cpu_syscall_error( __MCPU_EMFILE ) ); ret = __cpu_sys_dup( host_fd ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); pcctx->_fd[new_fd].host_fd = (int)ret; pcctx->_fd[new_fd].owned = 1; pcctx->_fd[new_fd].flags = 0; return( (__mpu_uint64_t)new_fd ); } /* End of __cpu_SYS_dup() */ __mpu_uint64_t __cpu_SYS_dup2( __mpu_uint32_t sysno ) { __mpu_uint64_t old_fd; __mpu_uint64_t new_fd; __mpu_int64_t ret; int host_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); old_fd = __cpu_syscall_arg( 0 ); new_fd = __cpu_syscall_arg( 1 ); error = __cpu_fd_get( old_fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); if( new_fd >= CPU_GUEST_FD_MAX ) return( __cpu_syscall_error( __MCPU_EBADF ) ); if( old_fd == new_fd ) return( new_fd ); ret = __cpu_sys_dup( host_fd ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); if( pcctx->_fd[new_fd].host_fd >= 0 && pcctx->_fd[new_fd].owned ) (void)__cpu_sys_close( pcctx->_fd[new_fd].host_fd ); pcctx->_fd[new_fd].host_fd = (int)ret; pcctx->_fd[new_fd].owned = 1; pcctx->_fd[new_fd].flags = 0; return( new_fd ); } /* End of __cpu_SYS_dup2() */ __mpu_uint64_t __cpu_SYS_write( __mpu_uint32_t sysno ) { __mpu_uint64_t fd; __mpu_uint64_t ptr; __mpu_uint64_t count; __mpu_int64_t ret; unsigned char *buf = (unsigned char *)0; int host_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); ptr = __cpu_syscall_arg( 1 ); count = __cpu_syscall_arg( 2 ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); if( count ) { if( count > (__mpu_uint64_t)(size_t)-1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); buf = (unsigned char *)malloc( (size_t)count ); if( !buf ) return( __cpu_syscall_error( __MCPU_ENOMEM ) ); error = __cpu_copyin( buf, ptr, count ); if( error ) { free( buf ); return( __cpu_syscall_error( error ) ); } } ret = __cpu_sys_write( host_fd, buf, count ); free( buf ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_write() */ __mpu_uint64_t __cpu_SYS_read( __mpu_uint32_t sysno ) { __mpu_uint64_t fd; __mpu_uint64_t ptr; __mpu_uint64_t count; __mpu_int64_t ret; unsigned char *buf = (unsigned char *)0; int host_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); ptr = __cpu_syscall_arg( 1 ); count = __cpu_syscall_arg( 2 ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); if( count ) { __mpu_UNIT_t *memory; if( count > (__mpu_uint64_t)(size_t)-1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_memory_resolve( ptr, count, 1, &memory ); if( error ) return( __cpu_syscall_error( error ) ); buf = (unsigned char *)malloc( (size_t)count ); if( !buf ) return( __cpu_syscall_error( __MCPU_ENOMEM ) ); } ret = __cpu_sys_read( host_fd, buf, count ); if( ret > 0 ) { error = __cpu_copyout( ptr, buf, (__mpu_uint64_t)ret ); if( error ) ret = -(__mpu_int64_t)error; } free( buf ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_read() */ __mpu_uint64_t __cpu_SYS_lseek( __mpu_uint32_t sysno ) { __mpu_uint64_t fd; __mpu_uint64_t bits; __mpu_int64_t offset; __mpu_int64_t ret; int host_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); bits = __cpu_syscall_arg( 1 ); memcpy( &offset, &bits, sizeof( offset ) ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_lseek( host_fd, offset, __cpu_syscall_arg( 2 ) ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_lseek() */ __mpu_uint64_t __cpu_SYS_open( __mpu_uint32_t sysno ) { char *path = (char *)0; __mpu_int64_t ret; int fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_open( pcctx->_cwd_fd, path, __cpu_syscall_arg( 1 ), __cpu_syscall_arg( 2 ) ); free( path ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); fd = __cpu_fd_install( (int)ret ); if( fd < 0 ) { (void)__cpu_sys_close( (int)ret ); return( __cpu_syscall_error( __MCPU_EMFILE ) ); } return( (__mpu_uint64_t)fd ); } /* End of __cpu_SYS_open() */ __mpu_uint64_t __cpu_SYS_creat( __mpu_uint32_t sysno ) { char *path = (char *)0; __mpu_int64_t ret; int fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_creat( pcctx->_cwd_fd, path, __cpu_syscall_arg( 1 ) ); free( path ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); fd = __cpu_fd_install( (int)ret ); if( fd < 0 ) { (void)__cpu_sys_close( (int)ret ); return( __cpu_syscall_error( __MCPU_EMFILE ) ); } return( (__mpu_uint64_t)fd ); } /* End of __cpu_SYS_creat() */ __mpu_uint64_t __cpu_SYS_link( __mpu_uint32_t sysno ) { char *oldpath = (char *)0; char *newpath = (char *)0; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &oldpath, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); error = __cpu_copyinstr( &newpath, __cpu_syscall_arg( 1 ) ); if( error ) { free( oldpath ); return( __cpu_syscall_error( error ) ); } ret = __cpu_sys_link( pcctx->_cwd_fd, oldpath, newpath ); free( newpath ); free( oldpath ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_link() */ __mpu_uint64_t __cpu_SYS_unlink( __mpu_uint32_t sysno ) { char *path = (char *)0; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_unlink( pcctx->_cwd_fd, path ); free( path ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_unlink() */ __mpu_uint64_t __cpu_SYS_chdir( __mpu_uint32_t sysno ) { char *path = (char *)0; __mpu_int64_t ret; int old_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_chdir( pcctx->_cwd_fd, path ); free( path ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); old_fd = pcctx->_cwd_fd; pcctx->_cwd_fd = (int)ret; pcctx->_cwd_initialized = 1; if( old_fd >= 0 ) (void)__cpu_sys_close( old_fd ); return( 0 ); } /* End of __cpu_SYS_chdir() */ __mpu_uint64_t __cpu_SYS_fchdir( __mpu_uint32_t sysno ) { __mpu_uint64_t fd; __mpu_int64_t ret; int host_fd; int old_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_fchdir( host_fd ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); old_fd = pcctx->_cwd_fd; pcctx->_cwd_fd = (int)ret; pcctx->_cwd_initialized = 1; if( old_fd >= 0 ) (void)__cpu_sys_close( old_fd ); return( 0 ); } /* End of __cpu_SYS_fchdir() */ __mpu_uint64_t __cpu_SYS_rename( __mpu_uint32_t sysno ) { char *oldpath = (char *)0; char *newpath = (char *)0; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &oldpath, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); error = __cpu_copyinstr( &newpath, __cpu_syscall_arg( 1 ) ); if( error ) { free( oldpath ); return( __cpu_syscall_error( error ) ); } ret = __cpu_sys_rename( pcctx->_cwd_fd, oldpath, newpath ); free( newpath ); free( oldpath ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_rename() */ __mpu_uint64_t __cpu_SYS_mkdir( __mpu_uint32_t sysno ) { char *path = (char *)0; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_mkdir( pcctx->_cwd_fd, path, __cpu_syscall_arg( 1 ) ); free( path ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_mkdir() */ __mpu_uint64_t __cpu_SYS_chmod( __mpu_uint32_t sysno ) { char *path = (char *)0; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_chmod( pcctx->_cwd_fd, path, __cpu_syscall_arg( 1 ) ); free( path ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_chmod() */ __mpu_uint64_t __cpu_SYS_chown( __mpu_uint32_t sysno ) { char *path = (char *)0; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_chown( pcctx->_cwd_fd, path, __cpu_syscall_arg( 1 ), __cpu_syscall_arg( 2 ) ); free( path ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_chown() */ __mpu_uint64_t __cpu_SYS_access( __mpu_uint32_t sysno ) { char *path = (char *)0; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_access( pcctx->_cwd_fd, path, __cpu_syscall_arg( 1 ) ); free( path ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_access() */ __mpu_uint64_t __cpu_SYS_rmdir( __mpu_uint32_t sysno ) { char *path = (char *)0; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_rmdir( pcctx->_cwd_fd, path ); free( path ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_rmdir() */ __mpu_uint64_t __cpu_SYS_symlink( __mpu_uint32_t sysno ) { char *target = (char *)0; char *linkpath = (char *)0; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &target, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); error = __cpu_copyinstr( &linkpath, __cpu_syscall_arg( 1 ) ); if( error ) { free( target ); return( __cpu_syscall_error( error ) ); } ret = __cpu_sys_symlink( pcctx->_cwd_fd, target, linkpath ); free( linkpath ); free( target ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_symlink() */ __mpu_uint64_t __cpu_SYS_readlink( __mpu_uint32_t sysno ) { char *path = (char *)0; __mpu_uint64_t ptr; __mpu_uint64_t count; __mpu_int64_t ret; unsigned char *buf = (unsigned char *)0; int error; (void)sysno; if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); ptr = __cpu_syscall_arg( 1 ); count = __cpu_syscall_arg( 2 ); if( count ) { __mpu_UNIT_t *memory; if( count > (__mpu_uint64_t)(size_t)-1 ) { free( path ); return( __cpu_syscall_error( __MCPU_EINVAL ) ); } error = __cpu_memory_resolve( ptr, count, 1, &memory ); if( error ) { free( path ); return( __cpu_syscall_error( error ) ); } buf = (unsigned char *)malloc( (size_t)count ); if( !buf ) { free( path ); return( __cpu_syscall_error( __MCPU_ENOMEM ) ); } } ret = __cpu_sys_readlink( pcctx->_cwd_fd, path, buf, count ); free( path ); if( ret > 0 ) { error = __cpu_copyout( ptr, buf, (__mpu_uint64_t)ret ); if( error ) ret = -(__mpu_int64_t)error; } free( buf ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_readlink() */ __mpu_uint64_t __cpu_SYS_stat( __mpu_uint32_t sysno ) { struct __cpu_stat st; char *path = (char *)0; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_stat( pcctx->_cwd_fd, path, &st ); free( path ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); error = __cpu_stat_copyout( __cpu_syscall_arg( 1 ), &st ); if( error ) return( __cpu_syscall_error( error ) ); return( 0 ); } /* End of __cpu_SYS_stat() */ __mpu_uint64_t __cpu_SYS_fstat( __mpu_uint32_t sysno ) { struct __cpu_stat st; __mpu_uint64_t fd; __mpu_int64_t ret; int host_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_fstat( host_fd, &st ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); error = __cpu_stat_copyout( __cpu_syscall_arg( 1 ), &st ); if( error ) return( __cpu_syscall_error( error ) ); return( 0 ); } /* End of __cpu_SYS_fstat() */ __mpu_uint64_t __cpu_SYS_lstat( __mpu_uint32_t sysno ) { struct __cpu_stat st; char *path = (char *)0; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_lstat( pcctx->_cwd_fd, path, &st ); free( path ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); error = __cpu_stat_copyout( __cpu_syscall_arg( 1 ), &st ); if( error ) return( __cpu_syscall_error( error ) ); return( 0 ); } /* End of __cpu_SYS_lstat() */ __mpu_uint64_t __cpu_SYS_getdents( __mpu_uint32_t sysno ) { __mpu_uint64_t fd; __mpu_uint64_t ptr; __mpu_uint64_t count; __mpu_uint64_t usable; __mpu_int64_t ret; struct __cpu_dirent *buf = (struct __cpu_dirent *)0; __mpu_UNIT_t *memory; int host_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); ptr = __cpu_syscall_arg( 1 ); count = __cpu_syscall_arg( 2 ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); if( count < __CPU_DIRENT_SIZE ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); if( count > (__mpu_uint64_t)(size_t)-1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_memory_resolve( ptr, count, 1, &memory ); if( error ) return( __cpu_syscall_error( error ) ); usable = ( count / __CPU_DIRENT_SIZE ) * __CPU_DIRENT_SIZE; buf = (struct __cpu_dirent *)calloc( (size_t)( usable / __CPU_DIRENT_SIZE ), sizeof( *buf ) ); if( !buf ) return( __cpu_syscall_error( __MCPU_ENOMEM ) ); ret = __cpu_sys_getdents( host_fd, buf, usable ); if( ret > 0 ) { error = __cpu_dirent_copyout( ptr, buf, (__mpu_uint64_t)ret ); if( error ) ret = -(__mpu_int64_t)error; } free( buf ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_getdents() */ __mpu_uint64_t __cpu_SYS_fcntl( __mpu_uint32_t sysno ) { __mpu_uint64_t fd; __mpu_uint64_t cmd; __mpu_uint64_t arg; __mpu_int64_t ret; int host_fd; int new_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); cmd = __cpu_syscall_arg( 1 ); arg = __cpu_syscall_arg( 2 ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); switch( cmd ) { case __CPU_F_DUPFD: if( arg >= CPU_GUEST_FD_MAX ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); new_fd = __cpu_fd_find_from( arg ); if( new_fd < 0 ) return( __cpu_syscall_error( __MCPU_EMFILE ) ); ret = __cpu_sys_fcntl( host_fd, cmd, 0 ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); pcctx->_fd[new_fd].host_fd = (int)ret; pcctx->_fd[new_fd].owned = 1; pcctx->_fd[new_fd].flags = 0; return( (__mpu_uint64_t)new_fd ); case __CPU_F_GETFD: if( arg != 0 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); return( (__mpu_uint64_t)( pcctx->_fd[fd].flags & __CPU_FD_SUPPORTED ) ); case __CPU_F_SETFD: if( arg & ~(__mpu_uint64_t)__CPU_FD_SUPPORTED ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); pcctx->_fd[fd].flags = (unsigned int)arg; return( 0 ); case __CPU_F_GETFL: if( arg != 0 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); ret = __cpu_sys_fcntl( host_fd, cmd, 0 ); return( (__mpu_uint64_t)ret ); case __CPU_F_SETFL: ret = __cpu_sys_fcntl( host_fd, cmd, arg ); return( (__mpu_uint64_t)ret ); default: return( __cpu_syscall_error( __MCPU_EINVAL ) ); } } /* End of __cpu_SYS_fcntl() */ __mpu_uint64_t __cpu_SYS_pipe2( __mpu_uint32_t sysno ) { __mpu_uint64_t ptr; __mpu_uint64_t flags; __mpu_UNIT_t data[__CPU_PIPEFD_SIZE]; __mpu_UNIT_t *memory; __mpu_int64_t ret; unsigned int fd_flags; int host_pipe[2] = { -1, -1 }; int read_fd; int write_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); ptr = __cpu_syscall_arg( 0 ); flags = __cpu_syscall_arg( 1 ); if( flags & ~(__mpu_uint64_t)__CPU_PIPE2_SUPPORTED ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_memory_resolve( ptr, __CPU_PIPEFD_SIZE, 1, &memory ); if( error ) return( __cpu_syscall_error( error ) ); (void)memory; read_fd = __cpu_fd_find_from( 3 ); if( read_fd < 0 ) return( __cpu_syscall_error( __MCPU_EMFILE ) ); write_fd = __cpu_fd_find_from( (__mpu_uint64_t)read_fd + 1U ); if( write_fd < 0 ) return( __cpu_syscall_error( __MCPU_EMFILE ) ); ret = __cpu_sys_pipe2( host_pipe, flags & __CPU_O_NONBLOCK ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); memset( data, 0, sizeof( data ) ); __cpu_data_put_u64( data + __CPU_PIPEFD_READ, (__mpu_uint64_t)read_fd ); __cpu_data_put_u64( data + __CPU_PIPEFD_WRITE, (__mpu_uint64_t)write_fd ); error = __cpu_copyout( ptr, data, sizeof( data ) ); if( error ) { (void)__cpu_sys_close( host_pipe[0] ); (void)__cpu_sys_close( host_pipe[1] ); return( __cpu_syscall_error( error ) ); } fd_flags = ( flags & __CPU_O_CLOEXEC ) ? __CPU_FD_CLOEXEC : 0U; pcctx->_fd[read_fd].host_fd = host_pipe[0]; pcctx->_fd[read_fd].owned = 1; pcctx->_fd[read_fd].flags = fd_flags; pcctx->_fd[write_fd].host_fd = host_pipe[1]; pcctx->_fd[write_fd].owned = 1; pcctx->_fd[write_fd].flags = fd_flags; return( 0 ); } /* End of __cpu_SYS_pipe2() */ __mpu_uint64_t __cpu_SYS_select( __mpu_uint32_t sysno ) { __mpu_uint64_t nfds; __mpu_uint64_t read_ptr; __mpu_uint64_t write_ptr; __mpu_uint64_t except_ptr; __mpu_uint64_t timeout_ptr; __mpu_uint64_t read_in[__CPU_FD_SET_WORDS] = { 0, 0, 0, 0 }; __mpu_uint64_t write_in[__CPU_FD_SET_WORDS] = { 0, 0, 0, 0 }; __mpu_uint64_t except_in[__CPU_FD_SET_WORDS] = { 0, 0, 0, 0 }; __mpu_uint64_t read_out[__CPU_FD_SET_WORDS] = { 0, 0, 0, 0 }; __mpu_uint64_t write_out[__CPU_FD_SET_WORDS] = { 0, 0, 0, 0 }; __mpu_uint64_t except_out[__CPU_FD_SET_WORDS] = { 0, 0, 0, 0 }; struct __cpu_select_entry entries[CPU_GUEST_FD_MAX]; struct __cpu_timeval timeout; const struct __cpu_timeval *ptimeout = (const struct __cpu_timeval *)0; __mpu_int64_t ret; __mpu_uint64_t nentries = 0; __mpu_uint64_t ready = 0; unsigned int fd; int host_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 5 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); nfds = __cpu_syscall_arg( 0 ); read_ptr = __cpu_syscall_arg( 1 ); write_ptr = __cpu_syscall_arg( 2 ); except_ptr = __cpu_syscall_arg( 3 ); timeout_ptr = __cpu_syscall_arg( 4 ); if( nfds > CPU_GUEST_FD_MAX ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); if( read_ptr != CPU_NULL_PTR ) { error = __cpu_fdset_load( read_ptr, read_in ); if( error ) return( __cpu_syscall_error( error ) ); } if( write_ptr != CPU_NULL_PTR ) { error = __cpu_fdset_load( write_ptr, write_in ); if( error ) return( __cpu_syscall_error( error ) ); } if( except_ptr != CPU_NULL_PTR ) { error = __cpu_fdset_load( except_ptr, except_in ); if( error ) return( __cpu_syscall_error( error ) ); } if( timeout_ptr != CPU_NULL_PTR ) { error = __cpu_timeval_load( timeout_ptr, &timeout ); if( error ) return( __cpu_syscall_error( error ) ); ptimeout = &timeout; } memset( entries, 0, sizeof( entries ) ); for( fd = 0; fd < (unsigned int)nfds; ++fd ) { unsigned int events = 0; if( read_ptr != CPU_NULL_PTR && __cpu_fdset_isset( read_in, fd ) ) events |= __CPU_SELECT_READ; if( write_ptr != CPU_NULL_PTR && __cpu_fdset_isset( write_in, fd ) ) events |= __CPU_SELECT_WRITE; if( except_ptr != CPU_NULL_PTR && __cpu_fdset_isset( except_in, fd ) ) events |= __CPU_SELECT_EXCEPT; if( !events ) continue; error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); entries[nentries].guest_fd = fd; entries[nentries].host_fd = host_fd; entries[nentries].events = events; entries[nentries].revents = 0; ++nentries; } ret = __cpu_sys_select( entries, nentries, ptimeout ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); for( nfds = 0; nfds < nentries; ++nfds ) { fd = entries[nfds].guest_fd; if( ( entries[nfds].revents & __CPU_SELECT_READ ) && read_ptr != CPU_NULL_PTR ) { __cpu_fdset_set( read_out, fd ); ++ready; } if( ( entries[nfds].revents & __CPU_SELECT_WRITE ) && write_ptr != CPU_NULL_PTR ) { __cpu_fdset_set( write_out, fd ); ++ready; } if( ( entries[nfds].revents & __CPU_SELECT_EXCEPT ) && except_ptr != CPU_NULL_PTR ) { __cpu_fdset_set( except_out, fd ); ++ready; } } if( read_ptr != CPU_NULL_PTR ) { error = __cpu_fdset_store( read_ptr, read_out ); if( error ) return( __cpu_syscall_error( error ) ); } if( write_ptr != CPU_NULL_PTR ) { error = __cpu_fdset_store( write_ptr, write_out ); if( error ) return( __cpu_syscall_error( error ) ); } if( except_ptr != CPU_NULL_PTR ) { error = __cpu_fdset_store( except_ptr, except_out ); if( error ) return( __cpu_syscall_error( error ) ); } return( ready ); } /* End of __cpu_SYS_select() */ __mpu_uint64_t __cpu_SYS_gettimeofday( __mpu_uint32_t sysno ) { struct __cpu_timespec ts; struct __cpu_timeval tv; __mpu_uint64_t tv_ptr; __mpu_uint64_t tz_ptr; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); tv_ptr = __cpu_syscall_arg( 0 ); tz_ptr = __cpu_syscall_arg( 1 ); if( tv_ptr == CPU_NULL_PTR ) return( __cpu_syscall_error( __MCPU_EFAULT ) ); if( tz_ptr != CPU_NULL_PTR ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); ret = __cpu_sys_clock_gettime( __CPU_CLOCK_REALTIME, &ts ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); tv.tv_sec = ts.tv_sec; tv.tv_usec = ts.tv_nsec / 1000; error = __cpu_timeval_copyout( tv_ptr, &tv ); if( error ) return( __cpu_syscall_error( error ) ); return( 0 ); } /* End of __cpu_SYS_gettimeofday() */ __mpu_uint64_t __cpu_SYS_clock_getres( __mpu_uint32_t sysno ) { struct __cpu_timespec res; __mpu_uint64_t clockid; __mpu_uint64_t res_ptr; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); clockid = __cpu_syscall_arg( 0 ); res_ptr = __cpu_syscall_arg( 1 ); ret = __cpu_sys_clock_getres( clockid, res_ptr == CPU_NULL_PTR ? (struct __cpu_timespec *)0 : &res ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); if( res_ptr != CPU_NULL_PTR ) { error = __cpu_timespec_copyout( res_ptr, &res ); if( error ) return( __cpu_syscall_error( error ) ); } return( 0 ); } /* End of __cpu_SYS_clock_getres() */ __mpu_uint64_t __cpu_SYS_clock_gettime( __mpu_uint32_t sysno ) { struct __cpu_timespec ts; __mpu_uint64_t clockid; __mpu_uint64_t tp_ptr; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); clockid = __cpu_syscall_arg( 0 ); tp_ptr = __cpu_syscall_arg( 1 ); if( tp_ptr == CPU_NULL_PTR ) return( __cpu_syscall_error( __MCPU_EFAULT ) ); ret = __cpu_sys_clock_gettime( clockid, &ts ); if( ret < 0 ) return( (__mpu_uint64_t)ret ); error = __cpu_timespec_copyout( tp_ptr, &ts ); if( error ) return( __cpu_syscall_error( error ) ); return( 0 ); } /* End of __cpu_SYS_clock_gettime() */ __mpu_uint64_t __cpu_SYS_nanosleep( __mpu_uint32_t sysno ) { struct __cpu_timespec req; struct __cpu_timespec rem; __mpu_uint64_t req_ptr; __mpu_uint64_t rem_ptr; __mpu_UNIT_t *memory; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); req_ptr = __cpu_syscall_arg( 0 ); rem_ptr = __cpu_syscall_arg( 1 ); if( req_ptr == CPU_NULL_PTR ) return( __cpu_syscall_error( __MCPU_EFAULT ) ); error = __cpu_timespec_load( req_ptr, &req ); if( error ) return( __cpu_syscall_error( error ) ); if( rem_ptr != CPU_NULL_PTR ) { error = __cpu_memory_resolve( rem_ptr, __CPU_TIMESPEC_SIZE, 1, &memory ); if( error ) return( __cpu_syscall_error( error ) ); (void)memory; } ret = __cpu_sys_clock_nanosleep( __CPU_CLOCK_MONOTONIC, 0, &req, rem_ptr == CPU_NULL_PTR ? (struct __cpu_timespec *)0 : &rem ); if( ret == -(__mpu_int64_t)__MCPU_EINTR && rem_ptr != CPU_NULL_PTR ) { error = __cpu_timespec_copyout( rem_ptr, &rem ); if( error ) return( __cpu_syscall_error( error ) ); } return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_nanosleep() */ __mpu_uint64_t __cpu_SYS_clock_nanosleep( __mpu_uint32_t sysno ) { struct __cpu_timespec req; struct __cpu_timespec rem; __mpu_uint64_t clockid; __mpu_uint64_t flags; __mpu_uint64_t req_ptr; __mpu_uint64_t rem_ptr; __mpu_UNIT_t *memory; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 4 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); clockid = __cpu_syscall_arg( 0 ); flags = __cpu_syscall_arg( 1 ); req_ptr = __cpu_syscall_arg( 2 ); rem_ptr = __cpu_syscall_arg( 3 ); if( flags & ~(__mpu_uint64_t)__CPU_TIMER_ABSTIME ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); if( req_ptr == CPU_NULL_PTR ) return( __cpu_syscall_error( __MCPU_EFAULT ) ); error = __cpu_timespec_load( req_ptr, &req ); if( error ) return( __cpu_syscall_error( error ) ); if( !( flags & __CPU_TIMER_ABSTIME ) && rem_ptr != CPU_NULL_PTR ) { error = __cpu_memory_resolve( rem_ptr, __CPU_TIMESPEC_SIZE, 1, &memory ); if( error ) return( __cpu_syscall_error( error ) ); (void)memory; } ret = __cpu_sys_clock_nanosleep( clockid, flags, &req, ( flags & __CPU_TIMER_ABSTIME ) || rem_ptr == CPU_NULL_PTR ? (struct __cpu_timespec *)0 : &rem ); if( ret == -(__mpu_int64_t)__MCPU_EINTR && !( flags & __CPU_TIMER_ABSTIME ) && rem_ptr != CPU_NULL_PTR ) { error = __cpu_timespec_copyout( rem_ptr, &rem ); if( error ) return( __cpu_syscall_error( error ) ); } return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_clock_nanosleep() */ __mpu_uint64_t __cpu_SYS_fsync( __mpu_uint32_t sysno ) { __mpu_uint64_t fd; __mpu_int64_t ret; int host_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 1 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_fsync( host_fd ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_fsync() */ __mpu_uint64_t __cpu_SYS_truncate( __mpu_uint32_t sysno ) { char *path = (char *)0; __mpu_uint64_t bits; __mpu_int64_t length; __mpu_int64_t ret; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); error = __cpu_copyinstr( &path, __cpu_syscall_arg( 0 ) ); if( error ) return( __cpu_syscall_error( error ) ); bits = __cpu_syscall_arg( 1 ); memcpy( &length, &bits, sizeof( length ) ); ret = __cpu_sys_truncate( pcctx->_cwd_fd, path, length ); free( path ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_truncate() */ __mpu_uint64_t __cpu_SYS_ftruncate( __mpu_uint32_t sysno ) { __mpu_uint64_t fd; __mpu_uint64_t bits; __mpu_int64_t length; __mpu_int64_t ret; int host_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); bits = __cpu_syscall_arg( 1 ); memcpy( &length, &bits, sizeof( length ) ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_ftruncate( host_fd, length ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_ftruncate() */ __mpu_uint64_t __cpu_SYS_fchmod( __mpu_uint32_t sysno ) { __mpu_uint64_t fd; __mpu_int64_t ret; int host_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 2 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_fchmod( host_fd, __cpu_syscall_arg( 1 ) ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_fchmod() */ __mpu_uint64_t __cpu_SYS_fchown( __mpu_uint32_t sysno ) { __mpu_uint64_t fd; __mpu_int64_t ret; int host_fd; int error; (void)sysno; if( __cpu_syscall_nargs() != 3 ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); fd = __cpu_syscall_arg( 0 ); error = __cpu_fd_get( fd, &host_fd ); if( error ) return( __cpu_syscall_error( error ) ); ret = __cpu_sys_fchown( host_fd, __cpu_syscall_arg( 1 ), __cpu_syscall_arg( 2 ) ); return( (__mpu_uint64_t)ret ); } /* End of __cpu_SYS_fchown() */ static const __cpu_syscall_handler_t __syscalls[] = { [__NR_brk] = __cpu_SYS_brk, [__NR_gettimeofday] = __cpu_SYS_gettimeofday, [__NR_clock_getres] = __cpu_SYS_clock_getres, [__NR_clock_gettime] = __cpu_SYS_clock_gettime, [__NR_nanosleep] = __cpu_SYS_nanosleep, [__NR_clock_nanosleep] = __cpu_SYS_clock_nanosleep, [__NR_read] = __cpu_SYS_read, [__NR_write] = __cpu_SYS_write, [__NR_lseek] = __cpu_SYS_lseek, [__NR_open] = __cpu_SYS_open, [__NR_creat] = __cpu_SYS_creat, [__NR_close] = __cpu_SYS_close, [__NR_link] = __cpu_SYS_link, [__NR_unlink] = __cpu_SYS_unlink, [__NR_chdir] = __cpu_SYS_chdir, [__NR_mkdir] = __cpu_SYS_mkdir, [__NR_chmod] = __cpu_SYS_chmod, [__NR_chown] = __cpu_SYS_chown, [__NR_access] = __cpu_SYS_access, [__NR_rename] = __cpu_SYS_rename, [__NR_rmdir] = __cpu_SYS_rmdir, [__NR_symlink] = __cpu_SYS_symlink, [__NR_readlink] = __cpu_SYS_readlink, [__NR_stat] = __cpu_SYS_stat, [__NR_fstat] = __cpu_SYS_fstat, [__NR_lstat] = __cpu_SYS_lstat, [__NR_fcntl] = __cpu_SYS_fcntl, [__NR_pipe2] = __cpu_SYS_pipe2, [__NR_getdents] = __cpu_SYS_getdents, [__NR_select] = __cpu_SYS_select, [__NR_fsync] = __cpu_SYS_fsync, [__NR_truncate] = __cpu_SYS_truncate, [__NR_ftruncate] = __cpu_SYS_ftruncate, [__NR_fchmod] = __cpu_SYS_fchmod, [__NR_fchown] = __cpu_SYS_fchown, [__NR_fchdir] = __cpu_SYS_fchdir, [__NR_dup] = __cpu_SYS_dup, [__NR_dup2] = __cpu_SYS_dup2, }; __mpu_uint64_t __cpu_syscall_dispatch( void ) { __mpu_uint32_t sysno; sysno = __cpu_data_get_u32( __cpu_reg_ptr( 32, CPU_SYSCALL_SYSNO_ADDR ) ); if( __cpu_syscall_nargs() > CPU_SYSCALL_MAX_ARGS ) return( __cpu_syscall_error( __MCPU_EINVAL ) ); if( sysno >= sizeof( __syscalls ) / sizeof( __syscalls[0] ) || __syscalls[sysno] == (__cpu_syscall_handler_t)0 ) return( __cpu_syscall_error( __MCPU_ENOSYS ) ); return( __syscalls[sysno]( sysno ) ); } /* End of __cpu_syscall_dispatch() */