diff options
Diffstat (limited to 'linux-user')
37 files changed, 17565 insertions, 0 deletions
diff --git a/linux-user/arm-semi.c b/linux-user/arm-semi.c new file mode 100644 index 0000000..250d5b7 --- /dev/null +++ b/linux-user/arm-semi.c @@ -0,0 +1,203 @@ +/* + * Arm "Angel" semihosting syscalls + * + * Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <time.h> + +#include "qemu.h" + +#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024) + +#define SYS_OPEN 0x01 +#define SYS_CLOSE 0x02 +#define SYS_WRITEC 0x03 +#define SYS_WRITE0 0x04 +#define SYS_WRITE 0x05 +#define SYS_READ 0x06 +#define SYS_READC 0x07 +#define SYS_ISTTY 0x09 +#define SYS_SEEK 0x0a +#define SYS_FLEN 0x0c +#define SYS_TMPNAM 0x0d +#define SYS_REMOVE 0x0e +#define SYS_RENAME 0x0f +#define SYS_CLOCK 0x10 +#define SYS_TIME 0x11 +#define SYS_SYSTEM 0x12 +#define SYS_ERRNO 0x13 +#define SYS_GET_CMDLINE 0x15 +#define SYS_HEAPINFO 0x16 +#define SYS_EXIT 0x18 + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +int open_modeflags[12] = { + O_RDONLY, + O_RDONLY | O_BINARY, + O_RDWR, + O_RDWR | O_BINARY, + O_WRONLY | O_CREAT | O_TRUNC, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + O_RDWR | O_CREAT | O_TRUNC, + O_RDWR | O_CREAT | O_TRUNC | O_BINARY, + O_WRONLY | O_CREAT | O_APPEND, + O_WRONLY | O_CREAT | O_APPEND | O_BINARY, + O_RDWR | O_CREAT | O_APPEND, + O_RDWR | O_CREAT | O_APPEND | O_BINARY +}; + +static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code) +{ + if (code == (uint32_t)-1) + ts->swi_errno = errno; + return code; +} + +#define ARG(n) tget32(args + n * 4) +uint32_t do_arm_semihosting(CPUState *env) +{ + target_ulong args; + char * s; + int nr; + uint32_t ret; + TaskState *ts = env->opaque; + + nr = env->regs[0]; + args = env->regs[1]; + switch (nr) { + case SYS_OPEN: + s = (char *)g2h(ARG(0)); + if (ARG(1) >= 12) + return (uint32_t)-1; + if (strcmp(s, ":tt") == 0) { + if (ARG(1) < 4) + return STDIN_FILENO; + else + return STDOUT_FILENO; + } + return set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644)); + case SYS_CLOSE: + return set_swi_errno(ts, close(ARG(0))); + case SYS_WRITEC: + { + char c = tget8(args); + /* Write to debug console. stderr is near enough. */ + return write(STDERR_FILENO, &c, 1); + } + case SYS_WRITE0: + s = lock_user_string(args); + ret = write(STDERR_FILENO, s, strlen(s)); + unlock_user(s, args, 0); + return ret; + case SYS_WRITE: + ret = set_swi_errno(ts, write(ARG(0), g2h(ARG(1)), ARG(2))); + if (ret == (uint32_t)-1) + return -1; + return ARG(2) - ret; + case SYS_READ: + ret = set_swi_errno(ts, read(ARG(0), g2h(ARG(1)), ARG(2))); + if (ret == (uint32_t)-1) + return -1; + return ARG(2) - ret; + case SYS_READC: + /* XXX: Read from debug cosole. Not implemented. */ + return 0; + case SYS_ISTTY: + return isatty(ARG(0)); + case SYS_SEEK: + ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET)); + if (ret == (uint32_t)-1) + return -1; + return 0; + case SYS_FLEN: + { + struct stat buf; + ret = set_swi_errno(ts, fstat(ARG(0), &buf)); + if (ret == (uint32_t)-1) + return -1; + return buf.st_size; + } + case SYS_TMPNAM: + /* XXX: Not implemented. */ + return -1; + case SYS_REMOVE: + return set_swi_errno(ts, remove((char *)g2h(ARG(0)))); + case SYS_RENAME: + return set_swi_errno(ts, rename((char *)g2h(ARG(0)), + (char *)g2h(ARG(2)))); + case SYS_CLOCK: + return clock() / (CLOCKS_PER_SEC / 100); + case SYS_TIME: + return set_swi_errno(ts, time(NULL)); + case SYS_SYSTEM: + return set_swi_errno(ts, system((char *)g2h(ARG(0)))); + case SYS_ERRNO: + return ts->swi_errno; + case SYS_GET_CMDLINE: + /* XXX: Not implemented. */ + s = (char *)g2h(ARG(0)); + *s = 0; + return -1; + case SYS_HEAPINFO: + { + uint32_t *ptr; + uint32_t limit; + + /* Some C llibraries assume the heap immediately follows .bss, so + allocate it using sbrk. */ + if (!ts->heap_limit) { + long ret; + + ts->heap_base = do_brk(0); + limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE; + /* Try a big heap, and reduce the size if that fails. */ + for (;;) { + ret = do_brk(limit); + if (ret != -1) + break; + limit = (ts->heap_base >> 1) + (limit >> 1); + } + ts->heap_limit = limit; + } + + page_unprotect_range (ARG(0), 32); + ptr = (uint32_t *)g2h(ARG(0)); + ptr[0] = tswap32(ts->heap_base); + ptr[1] = tswap32(ts->heap_limit); + ptr[2] = tswap32(ts->stack_base); + ptr[3] = tswap32(0); /* Stack limit. */ + return 0; + } + case SYS_EXIT: + exit(0); + default: + fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr); + cpu_dump_state(env, stderr, fprintf, 0); + abort(); + } +} + diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h new file mode 100644 index 0000000..1d508f0 --- /dev/null +++ b/linux-user/arm/syscall.h @@ -0,0 +1,42 @@ + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct target_pt_regs { + target_long uregs[18]; +}; + +#define ARM_cpsr uregs[16] +#define ARM_pc uregs[15] +#define ARM_lr uregs[14] +#define ARM_sp uregs[13] +#define ARM_ip uregs[12] +#define ARM_fp uregs[11] +#define ARM_r10 uregs[10] +#define ARM_r9 uregs[9] +#define ARM_r8 uregs[8] +#define ARM_r7 uregs[7] +#define ARM_r6 uregs[6] +#define ARM_r5 uregs[5] +#define ARM_r4 uregs[4] +#define ARM_r3 uregs[3] +#define ARM_r2 uregs[2] +#define ARM_r1 uregs[1] +#define ARM_r0 uregs[0] +#define ARM_ORIG_r0 uregs[17] + +#define ARM_SYSCALL_BASE 0x900000 +#define ARM_THUMB_SYSCALL 0 + +#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2) + +#define ARM_NR_semihosting 0x123456 +#define ARM_NR_thumb_semihosting 0xAB + +#if defined(TARGET_WORDS_BIGENDIAN) +#define UNAME_MACHINE "armv5teb" +#else +#define UNAME_MACHINE "armv5tel" +#endif + +uint32_t do_arm_semihosting(CPUState *); diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h new file mode 100644 index 0000000..195e459 --- /dev/null +++ b/linux-user/arm/syscall_nr.h @@ -0,0 +1,262 @@ +/* + * This file contains the system call numbers. + */ + +#define TARGET_NR_restart_syscall ( 0) +#define TARGET_NR_exit ( 1) +#define TARGET_NR_fork ( 2) +#define TARGET_NR_read ( 3) +#define TARGET_NR_write ( 4) +#define TARGET_NR_open ( 5) +#define TARGET_NR_close ( 6) +#define TARGET_NR_waitpid ( 7) /* removed */ +#define TARGET_NR_creat ( 8) +#define TARGET_NR_link ( 9) +#define TARGET_NR_unlink ( 10) +#define TARGET_NR_execve ( 11) +#define TARGET_NR_chdir ( 12) +#define TARGET_NR_time ( 13) +#define TARGET_NR_mknod ( 14) +#define TARGET_NR_chmod ( 15) +#define TARGET_NR_lchown ( 16) +#define TARGET_NR_break ( 17) /* removed */ + /* 18 was sys_stat */ +#define TARGET_NR_lseek ( 19) +#define TARGET_NR_getpid ( 20) +#define TARGET_NR_mount ( 21) +#define TARGET_NR_umount ( 22) +#define TARGET_NR_setuid ( 23) +#define TARGET_NR_getuid ( 24) +#define TARGET_NR_stime ( 25) +#define TARGET_NR_ptrace ( 26) +#define TARGET_NR_alarm ( 27) + +#define TARGET_NR_pause ( 29) +#define TARGET_NR_utime ( 30) +#define TARGET_NR_stty ( 31) /* removed */ +#define TARGET_NR_gtty ( 32) /* removed */ +#define TARGET_NR_access ( 33) +#define TARGET_NR_nice ( 34) +#define TARGET_NR_ftime ( 35) /* removed */ +#define TARGET_NR_sync ( 36) +#define TARGET_NR_kill ( 37) +#define TARGET_NR_rename ( 38) +#define TARGET_NR_mkdir ( 39) +#define TARGET_NR_rmdir ( 40) +#define TARGET_NR_dup ( 41) +#define TARGET_NR_pipe ( 42) +#define TARGET_NR_times ( 43) +#define TARGET_NR_prof ( 44) /* removed */ +#define TARGET_NR_brk ( 45) +#define TARGET_NR_setgid ( 46) +#define TARGET_NR_getgid ( 47) +#define TARGET_NR_signal ( 48) /* removed */ +#define TARGET_NR_geteuid ( 49) +#define TARGET_NR_getegid ( 50) +#define TARGET_NR_acct ( 51) +#define TARGET_NR_umount2 ( 52) +#define TARGET_NR_lock ( 53) /* removed */ +#define TARGET_NR_ioctl ( 54) +#define TARGET_NR_fcntl ( 55) +#define TARGET_NR_mpx ( 56) /* removed */ +#define TARGET_NR_setpgid ( 57) +#define TARGET_NR_ulimit ( 58) /* removed */ + /* 59 was sys_olduname */ +#define TARGET_NR_umask ( 60) +#define TARGET_NR_chroot ( 61) +#define TARGET_NR_ustat ( 62) +#define TARGET_NR_dup2 ( 63) +#define TARGET_NR_getppid ( 64) +#define TARGET_NR_getpgrp ( 65) +#define TARGET_NR_setsid ( 66) +#define TARGET_NR_sigaction ( 67) +#define TARGET_NR_sgetmask ( 68) /* removed */ +#define TARGET_NR_ssetmask ( 69) /* removed */ +#define TARGET_NR_setreuid ( 70) +#define TARGET_NR_setregid ( 71) +#define TARGET_NR_sigsuspend ( 72) +#define TARGET_NR_sigpending ( 73) +#define TARGET_NR_sethostname ( 74) +#define TARGET_NR_setrlimit ( 75) +#define TARGET_NR_getrlimit ( 76) /* Back compat 2GB limited rlimit */ +#define TARGET_NR_getrusage ( 77) +#define TARGET_NR_gettimeofday ( 78) +#define TARGET_NR_settimeofday ( 79) +#define TARGET_NR_getgroups ( 80) +#define TARGET_NR_setgroups ( 81) +#define TARGET_NR_select ( 82) +#define TARGET_NR_symlink ( 83) + /* 84 was sys_lstat */ +#define TARGET_NR_readlink ( 85) +#define TARGET_NR_uselib ( 86) +#define TARGET_NR_swapon ( 87) +#define TARGET_NR_reboot ( 88) +#define TARGET_NR_readdir ( 89) +#define TARGET_NR_mmap ( 90) +#define TARGET_NR_munmap ( 91) +#define TARGET_NR_truncate ( 92) +#define TARGET_NR_ftruncate ( 93) +#define TARGET_NR_fchmod ( 94) +#define TARGET_NR_fchown ( 95) +#define TARGET_NR_getpriority ( 96) +#define TARGET_NR_setpriority ( 97) +#define TARGET_NR_profil ( 98) /* removed */ +#define TARGET_NR_statfs ( 99) +#define TARGET_NR_fstatfs (100) +#define TARGET_NR_ioperm (101) +#define TARGET_NR_socketcall (102) +#define TARGET_NR_syslog (103) +#define TARGET_NR_setitimer (104) +#define TARGET_NR_getitimer (105) +#define TARGET_NR_stat (106) +#define TARGET_NR_lstat (107) +#define TARGET_NR_fstat (108) + /* 109 was sys_uname */ + /* 110 was sys_iopl */ +#define TARGET_NR_vhangup (111) +#define TARGET_NR_idle (112) +#define TARGET_NR_syscall (113) /* syscall to call a syscall! */ +#define TARGET_NR_wait4 (114) +#define TARGET_NR_swapoff (115) +#define TARGET_NR_sysinfo (116) +#define TARGET_NR_ipc (117) +#define TARGET_NR_fsync (118) +#define TARGET_NR_sigreturn (119) +#define TARGET_NR_clone (120) +#define TARGET_NR_setdomainname (121) +#define TARGET_NR_uname (122) +#define TARGET_NR_modify_ldt (123) +#define TARGET_NR_adjtimex (124) +#define TARGET_NR_mprotect (125) +#define TARGET_NR_sigprocmask (126) +#define TARGET_NR_create_module (127) /* removed */ +#define TARGET_NR_init_module (128) +#define TARGET_NR_delete_module (129) +#define TARGET_NR_get_kernel_syms (130) /* removed */ +#define TARGET_NR_quotactl (131) +#define TARGET_NR_getpgid (132) +#define TARGET_NR_fchdir (133) +#define TARGET_NR_bdflush (134) +#define TARGET_NR_sysfs (135) +#define TARGET_NR_personality (136) +#define TARGET_NR_afs_syscall (137) /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid (138) +#define TARGET_NR_setfsgid (139) +#define TARGET_NR__llseek (140) +#define TARGET_NR_getdents (141) +#define TARGET_NR__newselect (142) +#define TARGET_NR_flock (143) +#define TARGET_NR_msync (144) +#define TARGET_NR_readv (145) +#define TARGET_NR_writev (146) +#define TARGET_NR_getsid (147) +#define TARGET_NR_fdatasync (148) +#define TARGET_NR__sysctl (149) +#define TARGET_NR_mlock (150) +#define TARGET_NR_munlock (151) +#define TARGET_NR_mlockall (152) +#define TARGET_NR_munlockall (153) +#define TARGET_NR_sched_setparam (154) +#define TARGET_NR_sched_getparam (155) +#define TARGET_NR_sched_setscheduler (156) +#define TARGET_NR_sched_getscheduler (157) +#define TARGET_NR_sched_yield (158) +#define TARGET_NR_sched_get_priority_max (159) +#define TARGET_NR_sched_get_priority_min (160) +#define TARGET_NR_sched_rr_get_interval (161) +#define TARGET_NR_nanosleep (162) +#define TARGET_NR_mremap (163) +#define TARGET_NR_setresuid (164) +#define TARGET_NR_getresuid (165) +#define TARGET_NR_vm86 (166) /* removed */ +#define TARGET_NR_query_module (167) /* removed */ +#define TARGET_NR_poll (168) +#define TARGET_NR_nfsservctl (169) +#define TARGET_NR_setresgid (170) +#define TARGET_NR_getresgid (171) +#define TARGET_NR_prctl (172) +#define TARGET_NR_rt_sigreturn (173) +#define TARGET_NR_rt_sigaction (174) +#define TARGET_NR_rt_sigprocmask (175) +#define TARGET_NR_rt_sigpending (176) +#define TARGET_NR_rt_sigtimedwait (177) +#define TARGET_NR_rt_sigqueueinfo (178) +#define TARGET_NR_rt_sigsuspend (179) +#define TARGET_NR_pread (180) +#define TARGET_NR_pwrite (181) +#define TARGET_NR_chown (182) +#define TARGET_NR_getcwd (183) +#define TARGET_NR_capget (184) +#define TARGET_NR_capset (185) +#define TARGET_NR_sigaltstack (186) +#define TARGET_NR_sendfile (187) + /* 188 reserved */ + /* 189 reserved */ +#define TARGET_NR_vfork (190) +#define TARGET_NR_ugetrlimit (191) /* SuS compliant getrlimit */ +#define TARGET_NR_mmap2 (192) +#define TARGET_NR_truncate64 (193) +#define TARGET_NR_ftruncate64 (194) +#define TARGET_NR_stat64 (195) +#define TARGET_NR_lstat64 (196) +#define TARGET_NR_fstat64 (197) +#define TARGET_NR_lchown32 (198) +#define TARGET_NR_getuid32 (199) +#define TARGET_NR_getgid32 (200) +#define TARGET_NR_geteuid32 (201) +#define TARGET_NR_getegid32 (202) +#define TARGET_NR_setreuid32 (203) +#define TARGET_NR_setregid32 (204) +#define TARGET_NR_getgroups32 (205) +#define TARGET_NR_setgroups32 (206) +#define TARGET_NR_fchown32 (207) +#define TARGET_NR_setresuid32 (208) +#define TARGET_NR_getresuid32 (209) +#define TARGET_NR_setresgid32 (210) +#define TARGET_NR_getresgid32 (211) +#define TARGET_NR_chown32 (212) +#define TARGET_NR_setuid32 (213) +#define TARGET_NR_setgid32 (214) +#define TARGET_NR_setfsuid32 (215) +#define TARGET_NR_setfsgid32 (216) +#define TARGET_NR_getdents64 (217) +#define TARGET_NR_pivot_root (218) +#define TARGET_NR_mincore (219) +#define TARGET_NR_madvise (220) +#define TARGET_NR_fcntl64 (221) + /* 222 for tux */ + /* 223 is unused */ +#define TARGET_NR_gettid (224) +#define TARGET_NR_readahead (225) +#define TARGET_NR_setxattr (226) +#define TARGET_NR_lsetxattr (227) +#define TARGET_NR_fsetxattr (228) +#define TARGET_NR_getxattr (229) +#define TARGET_NR_lgetxattr (230) +#define TARGET_NR_fgetxattr (231) +#define TARGET_NR_listxattr (232) +#define TARGET_NR_llistxattr (233) +#define TARGET_NR_flistxattr (234) +#define TARGET_NR_removexattr (235) +#define TARGET_NR_lremovexattr (236) +#define TARGET_NR_fremovexattr (237) +#define TARGET_NR_tkill (238) +#define TARGET_NR_sendfile64 (239) +#define TARGET_NR_futex (240) +#define TARGET_NR_sched_setaffinity (241) +#define TARGET_NR_sched_getaffinity (242) +#define TARGET_NR_io_setup (243) +#define TARGET_NR_io_destroy (244) +#define TARGET_NR_io_getevents (245) +#define TARGET_NR_io_submit (246) +#define TARGET_NR_io_cancel (247) +#define TARGET_NR_exit_group (248) +#define TARGET_NR_lookup_dcookie (249) +#define TARGET_NR_epoll_create (250) +#define TARGET_NR_epoll_ctl (251) +#define TARGET_NR_epoll_wait (252) +#define TARGET_NR_remap_file_pages (253) + /* 254 for set_thread_area */ + /* 255 for get_thread_area */ + /* 256 for set_tid_address */ +#define TARGET_NR_utimes (269) diff --git a/linux-user/arm/termbits.h b/linux-user/arm/termbits.h new file mode 100644 index 0000000..36ead08 --- /dev/null +++ b/linux-user/arm/termbits.h @@ -0,0 +1,215 @@ +/* from asm/termbits.h */ +/* NOTE: exactly the same as i386 */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* ioctls */ + +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ TARGET_FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + diff --git a/linux-user/elfload.c b/linux-user/elfload.c new file mode 100644 index 0000000..57b5ed2 --- /dev/null +++ b/linux-user/elfload.c @@ -0,0 +1,1240 @@ +/* This is the Linux kernel elf-loading code, ported into user space */ + +#include <stdio.h> +#include <sys/types.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <sys/mman.h> +#include <stdlib.h> +#include <string.h> + +#include "qemu.h" +#include "disas.h" + +/* this flag is uneffective under linux too, should be deleted */ +#ifndef MAP_DENYWRITE +#define MAP_DENYWRITE 0 +#endif + +/* should probably go in elf.h */ +#ifndef ELIBBAD +#define ELIBBAD 80 +#endif + +#ifdef TARGET_I386 + +#define ELF_PLATFORM get_elf_platform() + +static const char *get_elf_platform(void) +{ + static char elf_platform[] = "i386"; + int family = (global_env->cpuid_version >> 8) & 0xff; + if (family > 6) + family = 6; + if (family >= 3) + elf_platform[1] = '0' + family; + return elf_platform; +} + +#define ELF_HWCAP get_elf_hwcap() + +static uint32_t get_elf_hwcap(void) +{ + return global_env->cpuid_features; +} + +#define ELF_START_MMAP 0x80000000 + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_386 + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->esp = infop->start_stack; + regs->eip = infop->entry; + + /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program + starts %edx contains a pointer to a function which might be + registered using `atexit'. This provides a mean for the + dynamic linker to call DT_FINI functions for shared libraries + that have been loaded before the code runs. + + A value of 0 tells we have no such handler. */ + regs->edx = 0; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + +#ifdef TARGET_ARM + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_ARM ) + +#define ELF_CLASS ELFCLASS32 +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_ARM + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + target_long stack = infop->start_stack; + memset(regs, 0, sizeof(*regs)); + regs->ARM_cpsr = 0x10; + if (infop->entry & 1) + regs->ARM_cpsr |= CPSR_T; + regs->ARM_pc = infop->entry & 0xfffffffe; + regs->ARM_sp = infop->start_stack; + regs->ARM_r2 = tgetl(stack + 8); /* envp */ + regs->ARM_r1 = tgetl(stack + 4); /* envp */ + /* XXX: it seems that r0 is zeroed after ! */ + regs->ARM_r0 = 0; + /* For uClinux PIC binaries. */ + regs->ARM_r10 = infop->start_data; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +enum +{ + ARM_HWCAP_ARM_SWP = 1 << 0, + ARM_HWCAP_ARM_HALF = 1 << 1, + ARM_HWCAP_ARM_THUMB = 1 << 2, + ARM_HWCAP_ARM_26BIT = 1 << 3, + ARM_HWCAP_ARM_FAST_MULT = 1 << 4, + ARM_HWCAP_ARM_FPA = 1 << 5, + ARM_HWCAP_ARM_VFP = 1 << 6, + ARM_HWCAP_ARM_EDSP = 1 << 7, +}; + +#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \ + | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \ + | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP) + +#endif + +#ifdef TARGET_SPARC +#ifdef TARGET_SPARC64 + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_SPARCV9 ) + +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_SPARCV9 + +#define STACK_BIAS 2047 + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->tstate = 0; + regs->pc = infop->entry; + regs->npc = regs->pc + 4; + regs->y = 0; + regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; +} + +#else +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_SPARC ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_SPARC + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->psr = 0; + regs->pc = infop->entry; + regs->npc = regs->pc + 4; + regs->y = 0; + regs->u_regs[14] = infop->start_stack - 16 * 4; +} + +#endif +#endif + +#ifdef TARGET_PPC + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_PPC ) + +#define ELF_CLASS ELFCLASS32 +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_PPC + +/* + * We need to put in some extra aux table entries to tell glibc what + * the cache block size is, so it can use the dcbz instruction safely. + */ +#define AT_DCACHEBSIZE 19 +#define AT_ICACHEBSIZE 20 +#define AT_UCACHEBSIZE 21 +/* A special ignored type value for PPC, for glibc compatibility. */ +#define AT_IGNOREPPC 22 +/* + * The requirements here are: + * - keep the final alignment of sp (sp & 0xf) + * - make sure the 32-bit value at the first 16 byte aligned position of + * AUXV is greater than 16 for glibc compatibility. + * AT_IGNOREPPC is used for that. + * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, + * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. + */ +#define DLINFO_ARCH_ITEMS 5 +#define ARCH_DLINFO \ +do { \ + NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \ + NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \ + /* \ + * Now handle glibc compatibility. \ + */ \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ + } while (0) + +static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) +{ + target_ulong pos = infop->start_stack; + target_ulong tmp; + + _regs->msr = 1 << MSR_PR; /* Set user mode */ + _regs->gpr[1] = infop->start_stack; + _regs->nip = infop->entry; + /* Note that isn't exactly what regular kernel does + * but this is what the ABI wants and is needed to allow + * execution of PPC BSD programs. + */ + _regs->gpr[3] = tgetl(pos); + pos += sizeof(target_ulong); + _regs->gpr[4] = pos; + for (tmp = 1; tmp != 0; pos += sizeof(target_ulong)) + tmp = ldl(pos); + _regs->gpr[5] = pos; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + +#ifdef TARGET_MIPS + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_MIPS ) + +#define ELF_CLASS ELFCLASS32 +#ifdef TARGET_WORDS_BIGENDIAN +#define ELF_DATA ELFDATA2MSB +#else +#define ELF_DATA ELFDATA2LSB +#endif +#define ELF_ARCH EM_MIPS + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->cp0_status = CP0St_UM; + regs->cp0_epc = infop->entry; + regs->regs[29] = infop->start_stack; +} + +#endif /* TARGET_MIPS */ + +#ifdef TARGET_SH4 + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_SH ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_SH + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + /* Check other registers XXXXX */ + regs->pc = infop->entry; + regs->regs[15] = infop->start_stack - 16 * 4; +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif + +#ifndef ELF_PLATFORM +#define ELF_PLATFORM (NULL) +#endif + +#ifndef ELF_HWCAP +#define ELF_HWCAP 0 +#endif + +#include "elf.h" + +struct exec +{ + unsigned int a_info; /* Use macros N_MAGIC, etc for access */ + unsigned int a_text; /* length of text, in bytes */ + unsigned int a_data; /* length of data, in bytes */ + unsigned int a_bss; /* length of uninitialized data area, in bytes */ + unsigned int a_syms; /* length of symbol table data in file, in bytes */ + unsigned int a_entry; /* start address */ + unsigned int a_trsize; /* length of relocation info for text, in bytes */ + unsigned int a_drsize; /* length of relocation info for data, in bytes */ +}; + + +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#define OMAGIC 0407 +#define NMAGIC 0410 +#define ZMAGIC 0413 +#define QMAGIC 0314 + +/* max code+data+bss space allocated to elf interpreter */ +#define INTERP_MAP_SIZE (32 * 1024 * 1024) + +/* max code+data+bss+brk space allocated to ET_DYN executables */ +#define ET_DYN_MAP_SIZE (128 * 1024 * 1024) + +/* from personality.h */ + +/* Flags for bug emulation. These occupy the top three bytes. */ +#define STICKY_TIMEOUTS 0x4000000 +#define WHOLE_SECONDS 0x2000000 + +/* Personality types. These go in the low byte. Avoid using the top bit, + * it will conflict with error returns. + */ +#define PER_MASK (0x00ff) +#define PER_LINUX (0x0000) +#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS) +#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS) +#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS) +#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS) +#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS) +#define PER_BSD (0x0006) +#define PER_XENIX (0x0007 | STICKY_TIMEOUTS) + +/* Necessary parameters */ +#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE +#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) +#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) + +#define INTERPRETER_NONE 0 +#define INTERPRETER_AOUT 1 +#define INTERPRETER_ELF 2 + +#define DLINFO_ITEMS 12 + +static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) +{ + memcpy(to, from, n); +} + +extern unsigned long x86_stack_size; + +static int load_aout_interp(void * exptr, int interp_fd); + +#ifdef BSWAP_NEEDED +static void bswap_ehdr(struct elfhdr *ehdr) +{ + bswap16s(&ehdr->e_type); /* Object file type */ + bswap16s(&ehdr->e_machine); /* Architecture */ + bswap32s(&ehdr->e_version); /* Object file version */ + bswaptls(&ehdr->e_entry); /* Entry point virtual address */ + bswaptls(&ehdr->e_phoff); /* Program header table file offset */ + bswaptls(&ehdr->e_shoff); /* Section header table file offset */ + bswap32s(&ehdr->e_flags); /* Processor-specific flags */ + bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ + bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ + bswap16s(&ehdr->e_phnum); /* Program header table entry count */ + bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ + bswap16s(&ehdr->e_shnum); /* Section header table entry count */ + bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ +} + +static void bswap_phdr(struct elf_phdr *phdr) +{ + bswap32s(&phdr->p_type); /* Segment type */ + bswaptls(&phdr->p_offset); /* Segment file offset */ + bswaptls(&phdr->p_vaddr); /* Segment virtual address */ + bswaptls(&phdr->p_paddr); /* Segment physical address */ + bswaptls(&phdr->p_filesz); /* Segment size in file */ + bswaptls(&phdr->p_memsz); /* Segment size in memory */ + bswap32s(&phdr->p_flags); /* Segment flags */ + bswaptls(&phdr->p_align); /* Segment alignment */ +} + +static void bswap_shdr(struct elf_shdr *shdr) +{ + bswap32s(&shdr->sh_name); + bswap32s(&shdr->sh_type); + bswaptls(&shdr->sh_flags); + bswaptls(&shdr->sh_addr); + bswaptls(&shdr->sh_offset); + bswaptls(&shdr->sh_size); + bswap32s(&shdr->sh_link); + bswap32s(&shdr->sh_info); + bswaptls(&shdr->sh_addralign); + bswaptls(&shdr->sh_entsize); +} + +static void bswap_sym(Elf32_Sym *sym) +{ + bswap32s(&sym->st_name); + bswap32s(&sym->st_value); + bswap32s(&sym->st_size); + bswap16s(&sym->st_shndx); +} +#endif + +/* + * 'copy_elf_strings()' copies argument/envelope strings from user + * memory to free pages in kernel mem. These are in a format ready + * to be put directly into the top of new user memory. + * + */ +static unsigned long copy_elf_strings(int argc,char ** argv, void **page, + unsigned long p) +{ + char *tmp, *tmp1, *pag = NULL; + int len, offset = 0; + + if (!p) { + return 0; /* bullet-proofing */ + } + while (argc-- > 0) { + tmp = argv[argc]; + if (!tmp) { + fprintf(stderr, "VFS: argc is wrong"); + exit(-1); + } + tmp1 = tmp; + while (*tmp++); + len = tmp - tmp1; + if (p < len) { /* this shouldn't happen - 128kB */ + return 0; + } + while (len) { + --p; --tmp; --len; + if (--offset < 0) { + offset = p % TARGET_PAGE_SIZE; + pag = (char *)page[p/TARGET_PAGE_SIZE]; + if (!pag) { + pag = (char *)malloc(TARGET_PAGE_SIZE); + page[p/TARGET_PAGE_SIZE] = pag; + if (!pag) + return 0; + } + } + if (len == 0 || offset == 0) { + *(pag + offset) = *tmp; + } + else { + int bytes_to_copy = (len > offset) ? offset : len; + tmp -= bytes_to_copy; + p -= bytes_to_copy; + offset -= bytes_to_copy; + len -= bytes_to_copy; + memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1); + } + } + } + return p; +} + +unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, + struct image_info * info) +{ + target_ulong stack_base, size, error; + int i; + + /* Create enough stack to hold everything. If we don't use + * it for args, we'll use it for something else... + */ + size = x86_stack_size; + if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) + size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; + error = target_mmap(0, + size + qemu_host_page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (error == -1) { + perror("stk mmap"); + exit(-1); + } + /* we reserve one extra page at the top of the stack as guard */ + target_mprotect(error + size, qemu_host_page_size, PROT_NONE); + + stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; + p += stack_base; + + for (i = 0 ; i < MAX_ARG_PAGES ; i++) { + if (bprm->page[i]) { + info->rss++; + + memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); + free(bprm->page[i]); + } + stack_base += TARGET_PAGE_SIZE; + } + return p; +} + +static void set_brk(unsigned long start, unsigned long end) +{ + /* page-align the start and end addresses... */ + start = HOST_PAGE_ALIGN(start); + end = HOST_PAGE_ALIGN(end); + if (end <= start) + return; + if(target_mmap(start, end - start, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) { + perror("cannot mmap brk"); + exit(-1); + } +} + + +/* We need to explicitly zero any fractional pages after the data + section (i.e. bss). This would contain the junk from the file that + should not be in memory. */ +static void padzero(unsigned long elf_bss) +{ + unsigned long nbyte; + + /* XXX: this is really a hack : if the real host page size is + smaller than the target page size, some pages after the end + of the file may not be mapped. A better fix would be to + patch target_mmap(), but it is more complicated as the file + size must be known */ + if (qemu_real_host_page_size < qemu_host_page_size) { + unsigned long end_addr, end_addr1; + end_addr1 = (elf_bss + qemu_real_host_page_size - 1) & + ~(qemu_real_host_page_size - 1); + end_addr = HOST_PAGE_ALIGN(elf_bss); + if (end_addr1 < end_addr) { + mmap((void *)end_addr1, end_addr - end_addr1, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + } + } + + nbyte = elf_bss & (qemu_host_page_size-1); + if (nbyte) { + nbyte = qemu_host_page_size - nbyte; + do { + tput8(elf_bss, 0); + elf_bss++; + } while (--nbyte); + } +} + + +static unsigned long create_elf_tables(target_ulong p, int argc, int envc, + struct elfhdr * exec, + unsigned long load_addr, + unsigned long load_bias, + unsigned long interp_load_addr, int ibcs, + struct image_info *info) +{ + target_ulong sp; + int size; + target_ulong u_platform; + const char *k_platform; + const int n = sizeof(target_ulong); + + sp = p; + u_platform = 0; + k_platform = ELF_PLATFORM; + if (k_platform) { + size_t len = strlen(k_platform) + 1; + sp -= (len + n - 1) & ~(n - 1); + u_platform = sp; + memcpy_to_target(sp, k_platform, len); + } + /* + * Force 16 byte _final_ alignment here for generality. + */ + sp = sp &~ (target_ulong)15; + size = (DLINFO_ITEMS + 1) * 2; + if (k_platform) + size += 2; +#ifdef DLINFO_ARCH_ITEMS + size += DLINFO_ARCH_ITEMS * 2; +#endif + size += envc + argc + 2; + size += (!ibcs ? 3 : 1); /* argc itself */ + size *= n; + if (size & 15) + sp -= 16 - (size & 15); + +#define NEW_AUX_ENT(id, val) do { \ + sp -= n; tputl(sp, val); \ + sp -= n; tputl(sp, id); \ + } while(0) + NEW_AUX_ENT (AT_NULL, 0); + + /* There must be exactly DLINFO_ITEMS entries here. */ + NEW_AUX_ENT(AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); + NEW_AUX_ENT(AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); + NEW_AUX_ENT(AT_PHNUM, (target_ulong)(exec->e_phnum)); + NEW_AUX_ENT(AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); + NEW_AUX_ENT(AT_BASE, (target_ulong)(interp_load_addr)); + NEW_AUX_ENT(AT_FLAGS, (target_ulong)0); + NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry); + NEW_AUX_ENT(AT_UID, (target_ulong) getuid()); + NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid()); + NEW_AUX_ENT(AT_GID, (target_ulong) getgid()); + NEW_AUX_ENT(AT_EGID, (target_ulong) getegid()); + NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP); + if (k_platform) + NEW_AUX_ENT(AT_PLATFORM, u_platform); +#ifdef ARCH_DLINFO + /* + * ARCH_DLINFO must come last so platform specific code can enforce + * special alignment requirements on the AUXV if necessary (eg. PPC). + */ + ARCH_DLINFO; +#endif +#undef NEW_AUX_ENT + + sp = loader_build_argptr(envc, argc, sp, p, !ibcs); + return sp; +} + + +static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, + int interpreter_fd, + unsigned long *interp_load_addr) +{ + struct elf_phdr *elf_phdata = NULL; + struct elf_phdr *eppnt; + unsigned long load_addr = 0; + int load_addr_set = 0; + int retval; + unsigned long last_bss, elf_bss; + unsigned long error; + int i; + + elf_bss = 0; + last_bss = 0; + error = 0; + +#ifdef BSWAP_NEEDED + bswap_ehdr(interp_elf_ex); +#endif + /* First of all, some simple consistency checks */ + if ((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || + !elf_check_arch(interp_elf_ex->e_machine)) { + return ~0UL; + } + + + /* Now read in all of the header information */ + + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) + return ~0UL; + + elf_phdata = (struct elf_phdr *) + malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + + if (!elf_phdata) + return ~0UL; + + /* + * If the size of this structure has changed, then punt, since + * we will be doing the wrong thing. + */ + if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { + free(elf_phdata); + return ~0UL; + } + + retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); + if(retval >= 0) { + retval = read(interpreter_fd, + (char *) elf_phdata, + sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + } + if (retval < 0) { + perror("load_elf_interp"); + exit(-1); + free (elf_phdata); + return retval; + } +#ifdef BSWAP_NEEDED + eppnt = elf_phdata; + for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) { + bswap_phdr(eppnt); + } +#endif + + if (interp_elf_ex->e_type == ET_DYN) { + /* in order to avoid harcoding the interpreter load + address in qemu, we allocate a big enough memory zone */ + error = target_mmap(0, INTERP_MAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0); + if (error == -1) { + perror("mmap"); + exit(-1); + } + load_addr = error; + load_addr_set = 1; + } + + eppnt = elf_phdata; + for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) + if (eppnt->p_type == PT_LOAD) { + int elf_type = MAP_PRIVATE | MAP_DENYWRITE; + int elf_prot = 0; + unsigned long vaddr = 0; + unsigned long k; + + if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; + if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) { + elf_type |= MAP_FIXED; + vaddr = eppnt->p_vaddr; + } + error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr), + eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), + elf_prot, + elf_type, + interpreter_fd, + eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); + + if (error == -1) { + /* Real error */ + close(interpreter_fd); + free(elf_phdata); + return ~0UL; + } + + if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { + load_addr = error; + load_addr_set = 1; + } + + /* + * Find the end of the file mapping for this phdr, and keep + * track of the largest address we see for this. + */ + k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; + if (k > elf_bss) elf_bss = k; + + /* + * Do the same thing for the memory mapping - between + * elf_bss and last_bss is the bss section. + */ + k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; + if (k > last_bss) last_bss = k; + } + + /* Now use mmap to map the library into memory. */ + + close(interpreter_fd); + + /* + * Now fill out the bss section. First pad the last page up + * to the page boundary, and then perform a mmap to make sure + * that there are zeromapped pages up to and including the last + * bss page. + */ + padzero(elf_bss); + elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ + + /* Map the last of the bss segment */ + if (last_bss > elf_bss) { + target_mmap(elf_bss, last_bss-elf_bss, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + } + free(elf_phdata); + + *interp_load_addr = load_addr; + return ((unsigned long) interp_elf_ex->e_entry) + load_addr; +} + +/* Best attempt to load symbols from this ELF object. */ +static void load_symbols(struct elfhdr *hdr, int fd) +{ + unsigned int i; + struct elf_shdr sechdr, symtab, strtab; + char *strings; + struct syminfo *s; + + lseek(fd, hdr->e_shoff, SEEK_SET); + for (i = 0; i < hdr->e_shnum; i++) { + if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) + return; +#ifdef BSWAP_NEEDED + bswap_shdr(&sechdr); +#endif + if (sechdr.sh_type == SHT_SYMTAB) { + symtab = sechdr; + lseek(fd, hdr->e_shoff + + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); + if (read(fd, &strtab, sizeof(strtab)) + != sizeof(strtab)) + return; +#ifdef BSWAP_NEEDED + bswap_shdr(&strtab); +#endif + goto found; + } + } + return; /* Shouldn't happen... */ + + found: + /* Now know where the strtab and symtab are. Snarf them. */ + s = malloc(sizeof(*s)); + s->disas_symtab = malloc(symtab.sh_size); + s->disas_strtab = strings = malloc(strtab.sh_size); + if (!s->disas_symtab || !s->disas_strtab) + return; + + lseek(fd, symtab.sh_offset, SEEK_SET); + if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size) + return; + +#ifdef BSWAP_NEEDED + for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) + bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i); +#endif + + lseek(fd, strtab.sh_offset, SEEK_SET); + if (read(fd, strings, strtab.sh_size) != strtab.sh_size) + return; + s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); + s->next = syminfos; + syminfos = s; +} + +int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info) +{ + struct elfhdr elf_ex; + struct elfhdr interp_elf_ex; + struct exec interp_ex; + int interpreter_fd = -1; /* avoid warning */ + unsigned long load_addr, load_bias; + int load_addr_set = 0; + unsigned int interpreter_type = INTERPRETER_NONE; + unsigned char ibcs2_interpreter; + int i; + unsigned long mapped_addr; + struct elf_phdr * elf_ppnt; + struct elf_phdr *elf_phdata; + unsigned long elf_bss, k, elf_brk; + int retval; + char * elf_interpreter; + unsigned long elf_entry, interp_load_addr = 0; + int status; + unsigned long start_code, end_code, end_data; + unsigned long elf_stack; + char passed_fileno[6]; + + ibcs2_interpreter = 0; + status = 0; + load_addr = 0; + load_bias = 0; + elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ +#ifdef BSWAP_NEEDED + bswap_ehdr(&elf_ex); +#endif + + /* First of all, some simple consistency checks */ + if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || + (! elf_check_arch(elf_ex.e_machine))) { + return -ENOEXEC; + } + + bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); + bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); + bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); + if (!bprm->p) { + retval = -E2BIG; + } + + /* Now read in all of the header information */ + elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum); + if (elf_phdata == NULL) { + return -ENOMEM; + } + + retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); + if(retval > 0) { + retval = read(bprm->fd, (char *) elf_phdata, + elf_ex.e_phentsize * elf_ex.e_phnum); + } + + if (retval < 0) { + perror("load_elf_binary"); + exit(-1); + free (elf_phdata); + return -errno; + } + +#ifdef BSWAP_NEEDED + elf_ppnt = elf_phdata; + for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) { + bswap_phdr(elf_ppnt); + } +#endif + elf_ppnt = elf_phdata; + + elf_bss = 0; + elf_brk = 0; + + + elf_stack = ~0UL; + elf_interpreter = NULL; + start_code = ~0UL; + end_code = 0; + end_data = 0; + + for(i=0;i < elf_ex.e_phnum; i++) { + if (elf_ppnt->p_type == PT_INTERP) { + if ( elf_interpreter != NULL ) + { + free (elf_phdata); + free(elf_interpreter); + close(bprm->fd); + return -EINVAL; + } + + /* This is the program interpreter used for + * shared libraries - for now assume that this + * is an a.out format binary + */ + + elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); + + if (elf_interpreter == NULL) { + free (elf_phdata); + close(bprm->fd); + return -ENOMEM; + } + + retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); + if(retval >= 0) { + retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); + } + if(retval < 0) { + perror("load_elf_binary2"); + exit(-1); + } + + /* If the program interpreter is one of these two, + then assume an iBCS2 image. Otherwise assume + a native linux image. */ + + /* JRP - Need to add X86 lib dir stuff here... */ + + if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || + strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { + ibcs2_interpreter = 1; + } + +#if 0 + printf("Using ELF interpreter %s\n", elf_interpreter); +#endif + if (retval >= 0) { + retval = open(path(elf_interpreter), O_RDONLY); + if(retval >= 0) { + interpreter_fd = retval; + } + else { + perror(elf_interpreter); + exit(-1); + /* retval = -errno; */ + } + } + + if (retval >= 0) { + retval = lseek(interpreter_fd, 0, SEEK_SET); + if(retval >= 0) { + retval = read(interpreter_fd,bprm->buf,128); + } + } + if (retval >= 0) { + interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */ + interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */ + } + if (retval < 0) { + perror("load_elf_binary3"); + exit(-1); + free (elf_phdata); + free(elf_interpreter); + close(bprm->fd); + return retval; + } + } + elf_ppnt++; + } + + /* Some simple consistency checks for the interpreter */ + if (elf_interpreter){ + interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; + + /* Now figure out which format our binary is */ + if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && + (N_MAGIC(interp_ex) != QMAGIC)) { + interpreter_type = INTERPRETER_ELF; + } + + if (interp_elf_ex.e_ident[0] != 0x7f || + strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) { + interpreter_type &= ~INTERPRETER_ELF; + } + + if (!interpreter_type) { + free(elf_interpreter); + free(elf_phdata); + close(bprm->fd); + return -ELIBBAD; + } + } + + /* OK, we are done with that, now set up the arg stuff, + and then start this sucker up */ + + { + char * passed_p; + + if (interpreter_type == INTERPRETER_AOUT) { + snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); + passed_p = passed_fileno; + + if (elf_interpreter) { + bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p); + bprm->argc++; + } + } + if (!bprm->p) { + if (elf_interpreter) { + free(elf_interpreter); + } + free (elf_phdata); + close(bprm->fd); + return -E2BIG; + } + } + + /* OK, This is the point of no return */ + info->end_data = 0; + info->end_code = 0; + info->start_mmap = (unsigned long)ELF_START_MMAP; + info->mmap = 0; + elf_entry = (unsigned long) elf_ex.e_entry; + + /* Do this so that we can load the interpreter, if need be. We will + change some of these later */ + info->rss = 0; + bprm->p = setup_arg_pages(bprm->p, bprm, info); + info->start_stack = bprm->p; + + /* Now we do a little grungy work by mmaping the ELF image into + * the correct location in memory. At this point, we assume that + * the image should be loaded at fixed address, not at a variable + * address. + */ + + for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { + int elf_prot = 0; + int elf_flags = 0; + unsigned long error; + + if (elf_ppnt->p_type != PT_LOAD) + continue; + + if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; + if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + elf_flags = MAP_PRIVATE | MAP_DENYWRITE; + if (elf_ex.e_type == ET_EXEC || load_addr_set) { + elf_flags |= MAP_FIXED; + } else if (elf_ex.e_type == ET_DYN) { + /* Try and get dynamic programs out of the way of the default mmap + base, as well as whatever program they might try to exec. This + is because the brk will follow the loader, and is not movable. */ + /* NOTE: for qemu, we do a big mmap to get enough space + without harcoding any address */ + error = target_mmap(0, ET_DYN_MAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0); + if (error == -1) { + perror("mmap"); + exit(-1); + } + load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr); + } + + error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr), + (elf_ppnt->p_filesz + + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), + elf_prot, + (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), + bprm->fd, + (elf_ppnt->p_offset - + TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); + if (error == -1) { + perror("mmap"); + exit(-1); + } + +#ifdef LOW_ELF_STACK + if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) + elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr); +#endif + + if (!load_addr_set) { + load_addr_set = 1; + load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; + if (elf_ex.e_type == ET_DYN) { + load_bias += error - + TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr); + load_addr += load_bias; + } + } + k = elf_ppnt->p_vaddr; + if (k < start_code) + start_code = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; + if (k > elf_bss) + elf_bss = k; + if ((elf_ppnt->p_flags & PF_X) && end_code < k) + end_code = k; + if (end_data < k) + end_data = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; + if (k > elf_brk) elf_brk = k; + } + + elf_entry += load_bias; + elf_bss += load_bias; + elf_brk += load_bias; + start_code += load_bias; + end_code += load_bias; + // start_data += load_bias; + end_data += load_bias; + + if (elf_interpreter) { + if (interpreter_type & 1) { + elf_entry = load_aout_interp(&interp_ex, interpreter_fd); + } + else if (interpreter_type & 2) { + elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd, + &interp_load_addr); + } + + close(interpreter_fd); + free(elf_interpreter); + + if (elf_entry == ~0UL) { + printf("Unable to load interpreter\n"); + free(elf_phdata); + exit(-1); + return 0; + } + } + + free(elf_phdata); + + if (loglevel) + load_symbols(&elf_ex, bprm->fd); + + if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd); + info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); + +#ifdef LOW_ELF_STACK + info->start_stack = bprm->p = elf_stack - 4; +#endif + bprm->p = create_elf_tables(bprm->p, + bprm->argc, + bprm->envc, + &elf_ex, + load_addr, load_bias, + interp_load_addr, + (interpreter_type == INTERPRETER_AOUT ? 0 : 1), + info); + info->start_brk = info->brk = elf_brk; + info->end_code = end_code; + info->start_code = start_code; + info->start_data = end_code; + info->end_data = end_data; + info->start_stack = bprm->p; + + /* Calling set_brk effectively mmaps the pages that we need for the bss and break + sections */ + set_brk(elf_bss, elf_brk); + + padzero(elf_bss); + +#if 0 + printf("(start_brk) %x\n" , info->start_brk); + printf("(end_code) %x\n" , info->end_code); + printf("(start_code) %x\n" , info->start_code); + printf("(end_data) %x\n" , info->end_data); + printf("(start_stack) %x\n" , info->start_stack); + printf("(brk) %x\n" , info->brk); +#endif + + if ( info->personality == PER_SVR4 ) + { + /* Why this, you ask??? Well SVr4 maps page 0 as read-only, + and some applications "depend" upon this behavior. + Since we do not have the power to recompile these, we + emulate the SVr4 behavior. Sigh. */ + mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, -1, 0); + } + + info->entry = elf_entry; + + return 0; +} + +static int load_aout_interp(void * exptr, int interp_fd) +{ + printf("a.out interpreter not yet supported\n"); + return(0); +} + +void do_init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + init_thread(regs, infop); +} diff --git a/linux-user/flat.h b/linux-user/flat.h new file mode 100644 index 0000000..b057b14 --- /dev/null +++ b/linux-user/flat.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2002-2003 David McCullough <davidm@snapgear.com> + * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> + * The Silver Hammer Group, Ltd. + * + * This file provides the definitions and structures needed to + * support uClinux flat-format executables. + */ + +#define FLAT_VERSION 0x00000004L + +#ifdef CONFIG_BINFMT_SHARED_FLAT +#define MAX_SHARED_LIBS (4) +#else +#define MAX_SHARED_LIBS (1) +#endif + +/* + * To make everything easier to port and manage cross platform + * development, all fields are in network byte order. + */ + +struct flat_hdr { + char magic[4]; + unsigned long rev; /* version (as above) */ + unsigned long entry; /* Offset of first executable instruction + with text segment from beginning of file */ + unsigned long data_start; /* Offset of data segment from beginning of + file */ + unsigned long data_end; /* Offset of end of data segment + from beginning of file */ + unsigned long bss_end; /* Offset of end of bss segment from beginning + of file */ + + /* (It is assumed that data_end through bss_end forms the bss segment.) */ + + unsigned long stack_size; /* Size of stack, in bytes */ + unsigned long reloc_start; /* Offset of relocation records from + beginning of file */ + unsigned long reloc_count; /* Number of relocation records */ + unsigned long flags; + unsigned long build_date; /* When the program/library was built */ + unsigned long filler[5]; /* Reservered, set to zero */ +}; + +#define FLAT_FLAG_RAM 0x0001 /* load program entirely into RAM */ +#define FLAT_FLAG_GOTPIC 0x0002 /* program is PIC with GOT */ +#define FLAT_FLAG_GZIP 0x0004 /* all but the header is compressed */ +#define FLAT_FLAG_GZDATA 0x0008 /* only data/relocs are compressed (for XIP) */ +#define FLAT_FLAG_KTRACE 0x0010 /* output useful kernel trace for debugging */ + + +/* + * While it would be nice to keep this header clean, users of older + * tools still need this support in the kernel. So this section is + * purely for compatibility with old tool chains. + * + * DO NOT make changes or enhancements to the old format please, just work + * with the format above, except to fix bugs with old format support. + */ + +#define OLD_FLAT_VERSION 0x00000002L +#define OLD_FLAT_RELOC_TYPE_TEXT 0 +#define OLD_FLAT_RELOC_TYPE_DATA 1 +#define OLD_FLAT_RELOC_TYPE_BSS 2 + +# define OLD_FLAT_FLAG_RAM 0x1 /* load program entirely into RAM */ diff --git a/linux-user/flatload.c b/linux-user/flatload.c new file mode 100644 index 0000000..bf55be2 --- /dev/null +++ b/linux-user/flatload.c @@ -0,0 +1,793 @@ +/****************************************************************************/ +/* + * QEMU bFLT binary loader. Based on linux/fs/binfmt_flat.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Copyright (C) 2006 CodeSourcery. + * Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com> + * Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com> + * Copyright (C) 2002 SnapGear, by Paul Dale <pauli@snapgear.com> + * Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm@lineo.com> + * based heavily on: + * + * linux/fs/binfmt_aout.c: + * Copyright (C) 1991, 1992, 1996 Linus Torvalds + * linux/fs/binfmt_flat.c for 2.0 kernel + * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> + * JAN/99 -- coded full program relocation (gerg@snapgear.com) + */ + +/* ??? ZFLAT and shared library support is currently disabled. */ + +/****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/mman.h> +#include <unistd.h> + +#include "qemu.h" +#include "flat.h" + +//#define DEBUG + +#ifdef DEBUG +#define DBG_FLT(a...) printf(a) +#else +#define DBG_FLT(a...) +#endif + +#define flat_reloc_valid(reloc, size) ((reloc) <= (size)) +#define flat_old_ram_flag(flag) (flag) +#ifdef TARGET_WORDS_BIGENDIAN +#define flat_get_relocate_addr(relval) (relval) +#else +#define flat_get_relocate_addr(relval) bswap32(relval) +#endif + +#define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */ +#define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */ + +struct lib_info { + target_ulong start_code; /* Start of text segment */ + target_ulong start_data; /* Start of data segment */ + target_ulong end_data; /* Start of bss section */ + target_ulong start_brk; /* End of data segment */ + target_ulong text_len; /* Length of text segment */ + target_ulong entry; /* Start address for this module */ + target_ulong build_date; /* When this one was compiled */ + short loaded; /* Has this library been loaded? */ +}; + +#ifdef CONFIG_BINFMT_SHARED_FLAT +static int load_flat_shared_library(int id, struct lib_info *p); +#endif + +struct linux_binprm; + +#define ntohl(x) be32_to_cpu(x) + +/****************************************************************************/ +/* + * create_flat_tables() parses the env- and arg-strings in new user + * memory and creates the pointer tables from them, and puts their + * addresses on the "stack", returning the new stack pointer value. + */ + +/* Push a block of strings onto the guest stack. */ +static target_ulong copy_strings(target_ulong p, int n, char **s) +{ + int len; + + while (n-- > 0) { + len = strlen(s[n]) + 1; + p -= len; + memcpy_to_target(p, s[n], len); + } + + return p; +} + +int target_pread(int fd, target_ulong ptr, target_ulong len, + target_ulong offset) +{ + void *buf; + int ret; + + buf = lock_user(ptr, len, 0); + ret = pread(fd, buf, len, offset); + unlock_user(buf, ptr, len); + return ret; +} +/****************************************************************************/ + +#ifdef CONFIG_BINFMT_ZFLAT + +#include <linux/zlib.h> + +#define LBUFSIZE 4000 + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +static int decompress_exec( + struct linux_binprm *bprm, + unsigned long offset, + char *dst, + long len, + int fd) +{ + unsigned char *buf; + z_stream strm; + loff_t fpos; + int ret, retval; + + DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, (int)dst, (int)len); + + memset(&strm, 0, sizeof(strm)); + strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); + if (strm.workspace == NULL) { + DBG_FLT("binfmt_flat: no memory for decompress workspace\n"); + return -ENOMEM; + } + buf = kmalloc(LBUFSIZE, GFP_KERNEL); + if (buf == NULL) { + DBG_FLT("binfmt_flat: no memory for read buffer\n"); + retval = -ENOMEM; + goto out_free; + } + + /* Read in first chunk of data and parse gzip header. */ + fpos = offset; + ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos); + + strm.next_in = buf; + strm.avail_in = ret; + strm.total_in = 0; + + retval = -ENOEXEC; + + /* Check minimum size -- gzip header */ + if (ret < 10) { + DBG_FLT("binfmt_flat: file too small?\n"); + goto out_free_buf; + } + + /* Check gzip magic number */ + if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) { + DBG_FLT("binfmt_flat: unknown compression magic?\n"); + goto out_free_buf; + } + + /* Check gzip method */ + if (buf[2] != 8) { + DBG_FLT("binfmt_flat: unknown compression method?\n"); + goto out_free_buf; + } + /* Check gzip flags */ + if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) || + (buf[3] & RESERVED)) { + DBG_FLT("binfmt_flat: unknown flags?\n"); + goto out_free_buf; + } + + ret = 10; + if (buf[3] & EXTRA_FIELD) { + ret += 2 + buf[10] + (buf[11] << 8); + if (unlikely(LBUFSIZE == ret)) { + DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n"); + goto out_free_buf; + } + } + if (buf[3] & ORIG_NAME) { + for (; ret < LBUFSIZE && (buf[ret] != 0); ret++) + ; + if (unlikely(LBUFSIZE == ret)) { + DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n"); + goto out_free_buf; + } + } + if (buf[3] & COMMENT) { + for (; ret < LBUFSIZE && (buf[ret] != 0); ret++) + ; + if (unlikely(LBUFSIZE == ret)) { + DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n"); + goto out_free_buf; + } + } + + strm.next_in += ret; + strm.avail_in -= ret; + + strm.next_out = dst; + strm.avail_out = len; + strm.total_out = 0; + + if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) { + DBG_FLT("binfmt_flat: zlib init failed?\n"); + goto out_free_buf; + } + + while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) { + ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos); + if (ret <= 0) + break; + if (ret >= (unsigned long) -4096) + break; + len -= ret; + + strm.next_in = buf; + strm.avail_in = ret; + strm.total_in = 0; + } + + if (ret < 0) { + DBG_FLT("binfmt_flat: decompression failed (%d), %s\n", + ret, strm.msg); + goto out_zlib; + } + + retval = 0; +out_zlib: + zlib_inflateEnd(&strm); +out_free_buf: + kfree(buf); +out_free: + kfree(strm.workspace); +out: + return retval; +} + +#endif /* CONFIG_BINFMT_ZFLAT */ + +/****************************************************************************/ + +static target_ulong +calc_reloc(target_ulong r, struct lib_info *p, int curid, int internalp) +{ + target_ulong addr; + int id; + target_ulong start_brk; + target_ulong start_data; + target_ulong text_len; + target_ulong start_code; + +#ifdef CONFIG_BINFMT_SHARED_FLAT +#error needs checking + if (r == 0) + id = curid; /* Relocs of 0 are always self referring */ + else { + id = (r >> 24) & 0xff; /* Find ID for this reloc */ + r &= 0x00ffffff; /* Trim ID off here */ + } + if (id >= MAX_SHARED_LIBS) { + fprintf(stderr, "BINFMT_FLAT: reference 0x%x to shared library %d\n", + (unsigned) r, id); + goto failed; + } + if (curid != id) { + if (internalp) { + fprintf(stderr, "BINFMT_FLAT: reloc address 0x%x not " + "in same module (%d != %d)\n", + (unsigned) r, curid, id); + goto failed; + } else if ( ! p[id].loaded && + load_flat_shared_library(id, p) > (unsigned long) -4096) { + fprintf(stderr, "BINFMT_FLAT: failed to load library %d\n", id); + goto failed; + } + /* Check versioning information (i.e. time stamps) */ + if (p[id].build_date && p[curid].build_date + && p[curid].build_date < p[id].build_date) { + fprintf(stderr, "BINFMT_FLAT: library %d is younger than %d\n", + id, curid); + goto failed; + } + } +#else + id = 0; +#endif + + start_brk = p[id].start_brk; + start_data = p[id].start_data; + start_code = p[id].start_code; + text_len = p[id].text_len; + + if (!flat_reloc_valid(r, start_brk - start_data + text_len)) { + fprintf(stderr, "BINFMT_FLAT: reloc outside program 0x%x " + "(0 - 0x%x/0x%x)\n", + (int) r,(int)(start_brk-start_code),(int)text_len); + goto failed; + } + + if (r < text_len) /* In text segment */ + addr = r + start_code; + else /* In data segment */ + addr = r - text_len + start_data; + + /* Range checked already above so doing the range tests is redundant...*/ + return(addr); + +failed: + abort(); + return RELOC_FAILED; +} + +/****************************************************************************/ + +/* ??? This does not handle endianness correctly. */ +void old_reloc(struct lib_info *libinfo, uint32_t rl) +{ +#ifdef DEBUG + char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; +#endif + uint32_t *ptr; + uint32_t offset; + int reloc_type; + + offset = rl & 0x3fffffff; + reloc_type = rl >> 30; + /* ??? How to handle this? */ +#if defined(CONFIG_COLDFIRE) + ptr = (uint32_t *) (libinfo->start_code + offset); +#else + ptr = (uint32_t *) (libinfo->start_data + offset); +#endif + +#ifdef DEBUG + fprintf(stderr, "Relocation of variable at DATASEG+%x " + "(address %p, currently %x) into segment %s\n", + offset, ptr, (int)*ptr, segment[reloc_type]); +#endif + + switch (reloc_type) { + case OLD_FLAT_RELOC_TYPE_TEXT: + *ptr += libinfo->start_code; + break; + case OLD_FLAT_RELOC_TYPE_DATA: + *ptr += libinfo->start_data; + break; + case OLD_FLAT_RELOC_TYPE_BSS: + *ptr += libinfo->end_data; + break; + default: + fprintf(stderr, "BINFMT_FLAT: Unknown relocation type=%x\n", + reloc_type); + break; + } + DBG_FLT("Relocation became %x\n", (int)*ptr); +} + +/****************************************************************************/ + +static int load_flat_file(struct linux_binprm * bprm, + struct lib_info *libinfo, int id, target_ulong *extra_stack) +{ + struct flat_hdr * hdr; + target_ulong textpos = 0, datapos = 0, result; + target_ulong realdatastart = 0; + target_ulong text_len, data_len, bss_len, stack_len, flags; + target_ulong memp = 0; /* for finding the brk area */ + target_ulong extra; + target_ulong reloc = 0, rp; + int i, rev, relocs = 0; + target_ulong fpos; + target_ulong start_code, end_code; + + hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ + + text_len = ntohl(hdr->data_start); + data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start); + bss_len = ntohl(hdr->bss_end) - ntohl(hdr->data_end); + stack_len = ntohl(hdr->stack_size); + if (extra_stack) { + stack_len += *extra_stack; + *extra_stack = stack_len; + } + relocs = ntohl(hdr->reloc_count); + flags = ntohl(hdr->flags); + rev = ntohl(hdr->rev); + + DBG_FLT("BINFMT_FLAT: Loading file: %s\n", bprm->filename); + + if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) { + fprintf(stderr, "BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n", + rev, (int) FLAT_VERSION); + return -ENOEXEC; + } + + /* Don't allow old format executables to use shared libraries */ + if (rev == OLD_FLAT_VERSION && id != 0) { + fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n"); + return -ENOEXEC; + } + + /* + * fix up the flags for the older format, there were all kinds + * of endian hacks, this only works for the simple cases + */ + if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags)) + flags = FLAT_FLAG_RAM; + +#ifndef CONFIG_BINFMT_ZFLAT + if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) { + fprintf(stderr, "Support for ZFLAT executables is not enabled\n"); + return -ENOEXEC; + } +#endif + + /* + * calculate the extra space we need to map in + */ + extra = relocs * sizeof(target_ulong); + if (extra < bss_len + stack_len) + extra = bss_len + stack_len; + + /* + * there are a couple of cases here, the separate code/data + * case, and then the fully copied to RAM case which lumps + * it all together. + */ + if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) { + /* + * this should give us a ROM ptr, but if it doesn't we don't + * really care + */ + DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n"); + + textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC, + MAP_PRIVATE, bprm->fd, 0); + if (textpos == -1) { + fprintf(stderr, "Unable to mmap process text\n"); + return -1; + } + + realdatastart = target_mmap(0, data_len + extra + + MAX_SHARED_LIBS * sizeof(target_ulong), + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (realdatastart == -1) { + fprintf(stderr, "Unable to allocate RAM for process data\n"); + return realdatastart; + } + datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong); + + DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n", + (int)(data_len + bss_len + stack_len), (int)datapos); + + fpos = ntohl(hdr->data_start); +#ifdef CONFIG_BINFMT_ZFLAT + if (flags & FLAT_FLAG_GZDATA) { + result = decompress_exec(bprm, fpos, (char *) datapos, + data_len + (relocs * sizeof(target_ulong))) + } else +#endif + { + result = target_pread(bprm->fd, datapos, + data_len + (relocs * sizeof(target_ulong)), + fpos); + } + if (result < 0) { + fprintf(stderr, "Unable to read data+bss\n"); + return result; + } + + reloc = datapos + (ntohl(hdr->reloc_start) - text_len); + memp = realdatastart; + + } else { + + textpos = target_mmap(0, text_len + data_len + extra + + MAX_SHARED_LIBS * sizeof(target_ulong), + PROT_READ | PROT_EXEC | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (textpos == -1 ) { + fprintf(stderr, "Unable to allocate RAM for process text/data\n"); + return -1; + } + + realdatastart = textpos + ntohl(hdr->data_start); + datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong); + reloc = (textpos + ntohl(hdr->reloc_start) + + MAX_SHARED_LIBS * sizeof(target_ulong)); + memp = textpos; + +#ifdef CONFIG_BINFMT_ZFLAT +#error code needs checking + /* + * load it all in and treat it like a RAM load from now on + */ + if (flags & FLAT_FLAG_GZIP) { + result = decompress_exec(bprm, sizeof (struct flat_hdr), + (((char *) textpos) + sizeof (struct flat_hdr)), + (text_len + data_len + (relocs * sizeof(unsigned long)) + - sizeof (struct flat_hdr)), + 0); + memmove((void *) datapos, (void *) realdatastart, + data_len + (relocs * sizeof(unsigned long))); + } else if (flags & FLAT_FLAG_GZDATA) { + fpos = 0; + result = bprm->file->f_op->read(bprm->file, + (char *) textpos, text_len, &fpos); + if (result < (unsigned long) -4096) + result = decompress_exec(bprm, text_len, (char *) datapos, + data_len + (relocs * sizeof(unsigned long)), 0); + } + else +#endif + { + result = target_pread(bprm->fd, textpos, + text_len, 0); + if (result >= 0) { + result = target_pread(bprm->fd, datapos, + data_len + (relocs * sizeof(target_ulong)), + ntohl(hdr->data_start)); + } + } + if (result < 0) { + fprintf(stderr, "Unable to read code+data+bss\n"); + return result; + } + } + + DBG_FLT("Mapping is 0x%x, Entry point is 0x%x, data_start is 0x%x\n", + (int)textpos, 0x00ffffff&ntohl(hdr->entry), + ntohl(hdr->data_start)); + + /* The main program needs a little extra setup in the task structure */ + start_code = textpos + sizeof (struct flat_hdr); + end_code = textpos + text_len; + + DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n", + id ? "Lib" : "Load", bprm->filename, + (int) start_code, (int) end_code, + (int) datapos, + (int) (datapos + data_len), + (int) (datapos + data_len), + (int) (((datapos + data_len + bss_len) + 3) & ~3)); + + text_len -= sizeof(struct flat_hdr); /* the real code len */ + + /* Store the current module values into the global library structure */ + libinfo[id].start_code = start_code; + libinfo[id].start_data = datapos; + libinfo[id].end_data = datapos + data_len; + libinfo[id].start_brk = datapos + data_len + bss_len; + libinfo[id].text_len = text_len; + libinfo[id].loaded = 1; + libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos; + libinfo[id].build_date = ntohl(hdr->build_date); + + /* + * We just load the allocations into some temporary memory to + * help simplify all this mumbo jumbo + * + * We've got two different sections of relocation entries. + * The first is the GOT which resides at the begining of the data segment + * and is terminated with a -1. This one can be relocated in place. + * The second is the extra relocation entries tacked after the image's + * data segment. These require a little more processing as the entry is + * really an offset into the image which contains an offset into the + * image. + */ + if (flags & FLAT_FLAG_GOTPIC) { + rp = datapos; + while (1) { + target_ulong addr; + addr = tgetl(rp); + if (addr == -1) + break; + if (addr) { + addr = calc_reloc(addr, libinfo, id, 0); + if (addr == RELOC_FAILED) + return -ENOEXEC; + tputl(rp, addr); + } + rp += sizeof(target_ulong); + } + } + + /* + * Now run through the relocation entries. + * We've got to be careful here as C++ produces relocatable zero + * entries in the constructor and destructor tables which are then + * tested for being not zero (which will always occur unless we're + * based from address zero). This causes an endless loop as __start + * is at zero. The solution used is to not relocate zero addresses. + * This has the negative side effect of not allowing a global data + * reference to be statically initialised to _stext (I've moved + * __start to address 4 so that is okay). + */ + if (rev > OLD_FLAT_VERSION) { + for (i = 0; i < relocs; i++) { + target_ulong addr, relval; + + /* Get the address of the pointer to be + relocated (of course, the address has to be + relocated first). */ + relval = tgetl(reloc + i * sizeof (target_ulong)); + addr = flat_get_relocate_addr(relval); + rp = calc_reloc(addr, libinfo, id, 1); + if (rp == RELOC_FAILED) + return -ENOEXEC; + + /* Get the pointer's value. */ + addr = tgetl(rp); + if (addr != 0) { + /* + * Do the relocation. PIC relocs in the data section are + * already in target order + */ + +#ifndef TARGET_WORDS_BIGENDIAN + if ((flags & FLAT_FLAG_GOTPIC) == 0) + addr = bswap32(addr); +#endif + addr = calc_reloc(addr, libinfo, id, 0); + if (addr == RELOC_FAILED) + return -ENOEXEC; + + /* Write back the relocated pointer. */ + tputl(rp, addr); + } + } + } else { + for (i = 0; i < relocs; i++) { + target_ulong relval; + relval = tgetl(reloc + i * sizeof (target_ulong)); + old_reloc(&libinfo[0], relval); + } + } + + /* zero the BSS. */ + memset((void*)(datapos + data_len), 0, bss_len); + + return 0; +} + + +/****************************************************************************/ +#ifdef CONFIG_BINFMT_SHARED_FLAT + +/* + * Load a shared library into memory. The library gets its own data + * segment (including bss) but not argv/argc/environ. + */ + +static int load_flat_shared_library(int id, struct lib_info *libs) +{ + struct linux_binprm bprm; + int res; + char buf[16]; + + /* Create the file name */ + sprintf(buf, "/lib/lib%d.so", id); + + /* Open the file up */ + bprm.filename = buf; + bprm.file = open_exec(bprm.filename); + res = PTR_ERR(bprm.file); + if (IS_ERR(bprm.file)) + return res; + + res = prepare_binprm(&bprm); + + if (res <= (unsigned long)-4096) + res = load_flat_file(&bprm, libs, id, NULL); + if (bprm.file) { + allow_write_access(bprm.file); + fput(bprm.file); + bprm.file = NULL; + } + return(res); +} + +#endif /* CONFIG_BINFMT_SHARED_FLAT */ + +int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info) +{ + struct lib_info libinfo[MAX_SHARED_LIBS]; + target_ulong p = bprm->p; + target_ulong stack_len; + target_ulong start_addr; + target_ulong sp; + int res; + int i, j; + + memset(libinfo, 0, sizeof(libinfo)); + /* + * We have to add the size of our arguments to our stack size + * otherwise it's too easy for users to create stack overflows + * by passing in a huge argument list. And yes, we have to be + * pedantic and include space for the argv/envp array as it may have + * a lot of entries. + */ +#define TOP_OF_ARGS (TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *)) + stack_len = TOP_OF_ARGS - bprm->p; /* the strings */ + stack_len += (bprm->argc + 1) * 4; /* the argv array */ + stack_len += (bprm->envc + 1) * 4; /* the envp array */ + + + res = load_flat_file(bprm, libinfo, 0, &stack_len); + if (res > (unsigned long)-4096) + return res; + + /* Update data segment pointers for all libraries */ + for (i=0; i<MAX_SHARED_LIBS; i++) { + if (libinfo[i].loaded) { + target_ulong p; + p = libinfo[i].start_data; + for (j=0; j<MAX_SHARED_LIBS; j++) { + p -= 4; + tput32(p, libinfo[j].loaded + ? libinfo[j].start_data + : UNLOADED_LIB); + } + } + } + + p = ((libinfo[0].start_brk + stack_len + 3) & ~3) - 4; + DBG_FLT("p=%x\n", (int)p); + + /* Copy argv/envp. */ + p = copy_strings(p, bprm->argc, bprm->argv); + p = copy_strings(p, bprm->envc, bprm->envp); + /* Align stack. */ + sp = p & ~(target_ulong)(sizeof(target_ulong) - 1); + sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1); + + /* Fake some return addresses to ensure the call chain will + * initialise library in order for us. We are required to call + * lib 1 first, then 2, ... and finally the main program (id 0). + */ + start_addr = libinfo[0].entry; + +#ifdef CONFIG_BINFMT_SHARED_FLAT +#error here + for (i = MAX_SHARED_LIBS-1; i>0; i--) { + if (libinfo[i].loaded) { + /* Push previos first to call address */ + --sp; put_user(start_addr, sp); + start_addr = libinfo[i].entry; + } + } +#endif + + /* Stash our initial stack pointer into the mm structure */ + info->start_code = libinfo[0].start_code; + info->end_code = libinfo[0].start_code = libinfo[0].text_len; + info->start_data = libinfo[0].start_data; + info->end_data = libinfo[0].end_data; + info->start_brk = libinfo[0].start_brk; + info->start_stack = sp; + info->entry = start_addr; + info->code_offset = info->start_code; + info->data_offset = info->start_data - libinfo[0].text_len; + + DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n", + (int)info->entry, (int)info->start_stack); + + return 0; +} diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h new file mode 100644 index 0000000..cc0942b --- /dev/null +++ b/linux-user/i386/syscall.h @@ -0,0 +1,221 @@ +/* default linux values for the selectors */ +#define __USER_CS (0x23) +#define __USER_DS (0x2B) + +struct target_pt_regs { + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long eax; + int xds; + int xes; + long orig_eax; + long eip; + int xcs; + long eflags; + long esp; + int xss; +}; + +/* ioctls */ + +#define TARGET_LDT_ENTRIES 8192 +#define TARGET_LDT_ENTRY_SIZE 8 + +#define TARGET_GDT_ENTRY_TLS_ENTRIES 3 +#define TARGET_GDT_ENTRY_TLS_MIN 6 +#define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1) + +struct target_modify_ldt_ldt_s { + unsigned int entry_number; + target_ulong base_addr; + unsigned int limit; + unsigned int flags; +}; + +/* vm86 defines */ + +#define TARGET_BIOSSEG 0x0f000 + +#define TARGET_CPU_086 0 +#define TARGET_CPU_186 1 +#define TARGET_CPU_286 2 +#define TARGET_CPU_386 3 +#define TARGET_CPU_486 4 +#define TARGET_CPU_586 5 + +#define TARGET_VM86_SIGNAL 0 /* return due to signal */ +#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */ +#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */ +#define TARGET_VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */ + +/* + * Additional return values when invoking new vm86() + */ +#define TARGET_VM86_PICRETURN 4 /* return due to pending PIC request */ +#define TARGET_VM86_TRAP 6 /* return due to DOS-debugger request */ + +/* + * function codes when invoking new vm86() + */ +#define TARGET_VM86_PLUS_INSTALL_CHECK 0 +#define TARGET_VM86_ENTER 1 +#define TARGET_VM86_ENTER_NO_BYPASS 2 +#define TARGET_VM86_REQUEST_IRQ 3 +#define TARGET_VM86_FREE_IRQ 4 +#define TARGET_VM86_GET_IRQ_BITS 5 +#define TARGET_VM86_GET_AND_RESET_IRQ 6 + +/* + * This is the stack-layout seen by the user space program when we have + * done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout + * is 'kernel_vm86_regs' (see below). + */ + +struct target_vm86_regs { +/* + * normal regs, with special meaning for the segment descriptors.. + */ + target_long ebx; + target_long ecx; + target_long edx; + target_long esi; + target_long edi; + target_long ebp; + target_long eax; + target_long __null_ds; + target_long __null_es; + target_long __null_fs; + target_long __null_gs; + target_long orig_eax; + target_long eip; + unsigned short cs, __csh; + target_long eflags; + target_long esp; + unsigned short ss, __ssh; +/* + * these are specific to v86 mode: + */ + unsigned short es, __esh; + unsigned short ds, __dsh; + unsigned short fs, __fsh; + unsigned short gs, __gsh; +}; + +struct target_revectored_struct { + target_ulong __map[8]; /* 256 bits */ +}; + +struct target_vm86_struct { + struct target_vm86_regs regs; + target_ulong flags; + target_ulong screen_bitmap; + target_ulong cpu_type; + struct target_revectored_struct int_revectored; + struct target_revectored_struct int21_revectored; +}; + +/* + * flags masks + */ +#define TARGET_VM86_SCREEN_BITMAP 0x0001 + +struct target_vm86plus_info_struct { + target_ulong flags; +#define TARGET_force_return_for_pic (1 << 0) +#define TARGET_vm86dbg_active (1 << 1) /* for debugger */ +#define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */ +#define TARGET_is_vm86pus (1 << 31) /* for vm86 internal use */ + unsigned char vm86dbg_intxxtab[32]; /* for debugger */ +}; + +struct target_vm86plus_struct { + struct target_vm86_regs regs; + target_ulong flags; + target_ulong screen_bitmap; + target_ulong cpu_type; + struct target_revectored_struct int_revectored; + struct target_revectored_struct int21_revectored; + struct target_vm86plus_info_struct vm86plus; +}; + +/* ipcs */ + +#define TARGET_SEMOP 1 +#define TARGET_SEMGET 2 +#define TARGET_SEMCTL 3 +#define TARGET_MSGSND 11 +#define TARGET_MSGRCV 12 +#define TARGET_MSGGET 13 +#define TARGET_MSGCTL 14 +#define TARGET_SHMAT 21 +#define TARGET_SHMDT 22 +#define TARGET_SHMGET 23 +#define TARGET_SHMCTL 24 + +struct target_msgbuf { + int mtype; + char mtext[1]; +}; + +struct target_ipc_kludge { + unsigned int msgp; /* Really (struct msgbuf *) */ + int msgtyp; +}; + +struct target_ipc_perm { + int key; + unsigned short uid; + unsigned short gid; + unsigned short cuid; + unsigned short cgid; + unsigned short mode; + unsigned short seq; +}; + +struct target_msqid_ds { + struct target_ipc_perm msg_perm; + unsigned int msg_first; /* really struct target_msg* */ + unsigned int msg_last; /* really struct target_msg* */ + unsigned int msg_stime; /* really target_time_t */ + unsigned int msg_rtime; /* really target_time_t */ + unsigned int msg_ctime; /* really target_time_t */ + unsigned int wwait; /* really struct wait_queue* */ + unsigned int rwait; /* really struct wait_queue* */ + unsigned short msg_cbytes; + unsigned short msg_qnum; + unsigned short msg_qbytes; + unsigned short msg_lspid; + unsigned short msg_lrpid; +}; + +struct target_shmid_ds { + struct target_ipc_perm shm_perm; + int shm_segsz; + unsigned int shm_atime; /* really target_time_t */ + unsigned int shm_dtime; /* really target_time_t */ + unsigned int shm_ctime; /* really target_time_t */ + unsigned short shm_cpid; + unsigned short shm_lpid; + short shm_nattch; + unsigned short shm_npages; + unsigned long *shm_pages; + void *attaches; /* really struct shm_desc * */ +}; + +#define TARGET_IPC_RMID 0 +#define TARGET_IPC_SET 1 +#define TARGET_IPC_STAT 2 + +union target_semun { + int val; + unsigned int buf; /* really struct semid_ds * */ + unsigned int array; /* really unsigned short * */ + unsigned int __buf; /* really struct seminfo * */ + unsigned int __pad; /* really void* */ +}; + +#define UNAME_MACHINE "i686" diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h new file mode 100644 index 0000000..9fa6be9 --- /dev/null +++ b/linux-user/i386/syscall_nr.h @@ -0,0 +1,274 @@ +/* + * This file contains the system call numbers. + */ + +#define TARGET_NR_restart_syscall 0 +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_lchown 16 +#define TARGET_NR_break 17 +#define TARGET_NR_oldstat 18 +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid 23 +#define TARGET_NR_getuid 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 +#define TARGET_NR_oldfstat 28 +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid 46 +#define TARGET_NR_getgid 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid 49 +#define TARGET_NR_getegid 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 +#define TARGET_NR_oldolduname 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid 70 +#define TARGET_NR_setregid 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups 80 +#define TARGET_NR_setgroups 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 +#define TARGET_NR_oldlstat 84 +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 +#define TARGET_NR_olduname 109 +#define TARGET_NR_iopl 110 +#define TARGET_NR_vhangup 111 +#define TARGET_NR_idle 112 +#define TARGET_NR_vm86old 113 +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid 138 +#define TARGET_NR_setfsgid 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid 164 +#define TARGET_NR_getresuid 165 +#define TARGET_NR_vm86 166 +#define TARGET_NR_query_module 167 +#define TARGET_NR_poll 168 +#define TARGET_NR_nfsservctl 169 +#define TARGET_NR_setresgid 170 +#define TARGET_NR_getresgid 171 +#define TARGET_NR_prctl 172 +#define TARGET_NR_rt_sigreturn 173 +#define TARGET_NR_rt_sigaction 174 +#define TARGET_NR_rt_sigprocmask 175 +#define TARGET_NR_rt_sigpending 176 +#define TARGET_NR_rt_sigtimedwait 177 +#define TARGET_NR_rt_sigqueueinfo 178 +#define TARGET_NR_rt_sigsuspend 179 +#define TARGET_NR_pread 180 +#define TARGET_NR_pwrite 181 +#define TARGET_NR_chown 182 +#define TARGET_NR_getcwd 183 +#define TARGET_NR_capget 184 +#define TARGET_NR_capset 185 +#define TARGET_NR_sigaltstack 186 +#define TARGET_NR_sendfile 187 +#define TARGET_NR_getpmsg 188 /* some people actually want streams */ +#define TARGET_NR_putpmsg 189 /* some people actually want streams */ +#define TARGET_NR_vfork 190 +#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */ +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_lchown32 198 +#define TARGET_NR_getuid32 199 +#define TARGET_NR_getgid32 200 +#define TARGET_NR_geteuid32 201 +#define TARGET_NR_getegid32 202 +#define TARGET_NR_setreuid32 203 +#define TARGET_NR_setregid32 204 +#define TARGET_NR_getgroups32 205 +#define TARGET_NR_setgroups32 206 +#define TARGET_NR_fchown32 207 +#define TARGET_NR_setresuid32 208 +#define TARGET_NR_getresuid32 209 +#define TARGET_NR_setresgid32 210 +#define TARGET_NR_getresgid32 211 +#define TARGET_NR_chown32 212 +#define TARGET_NR_setuid32 213 +#define TARGET_NR_setgid32 214 +#define TARGET_NR_setfsuid32 215 +#define TARGET_NR_setfsgid32 216 +#define TARGET_NR_pivot_root 217 +#define TARGET_NR_mincore 218 +#define TARGET_NR_madvise 219 +#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */ +#define TARGET_NR_getdents64 220 +#define TARGET_NR_fcntl64 221 +/* 223 is unused */ +#define TARGET_NR_gettid 224 +#define TARGET_NR_readahead 225 +#define TARGET_NR_setxattr 226 +#define TARGET_NR_lsetxattr 227 +#define TARGET_NR_fsetxattr 228 +#define TARGET_NR_getxattr 229 +#define TARGET_NR_lgetxattr 230 +#define TARGET_NR_fgetxattr 231 +#define TARGET_NR_listxattr 232 +#define TARGET_NR_llistxattr 233 +#define TARGET_NR_flistxattr 234 +#define TARGET_NR_removexattr 235 +#define TARGET_NR_lremovexattr 236 +#define TARGET_NR_fremovexattr 237 +#define TARGET_NR_tkill 238 +#define TARGET_NR_sendfile64 239 +#define TARGET_NR_futex 240 +#define TARGET_NR_sched_setaffinity 241 +#define TARGET_NR_sched_getaffinity 242 +#define TARGET_NR_set_thread_area 243 +#define TARGET_NR_get_thread_area 244 +#define TARGET_NR_io_setup 245 +#define TARGET_NR_io_destroy 246 +#define TARGET_NR_io_getevents 247 +#define TARGET_NR_io_submit 248 +#define TARGET_NR_io_cancel 249 +#define TARGET_NR_fadvise64 250 + +#define TARGET_NR_exit_group 252 +#define TARGET_NR_lookup_dcookie 253 +#define TARGET_NR_epoll_create 254 +#define TARGET_NR_epoll_ctl 255 +#define TARGET_NR_epoll_wait 256 +#define TARGET_NR_remap_file_pages 257 +#define TARGET_NR_set_tid_address 258 +#define TARGET_NR_timer_create 259 +#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1) +#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2) +#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3) +#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4) +#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5) +#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) +#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) +#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) + +#define TARGET_NR_utimes 271 diff --git a/linux-user/i386/termbits.h b/linux-user/i386/termbits.h new file mode 100644 index 0000000..adff802 --- /dev/null +++ b/linux-user/i386/termbits.h @@ -0,0 +1,214 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* ioctls */ + +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ TARGET_FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h new file mode 100644 index 0000000..dae3efa --- /dev/null +++ b/linux-user/ioctls.h @@ -0,0 +1,302 @@ + /* emulated ioctl list */ + + IOCTL(TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) + IOCTL(TCSETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) + IOCTL(TCSETSF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) + IOCTL(TCSETSW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) + IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize))) + IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize))) + IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TCGETA, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TCSETA, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TCSETAW, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TCSETAF, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TCSBRK, 0, TYPE_INT) + IOCTL(TCSBRKP, 0, TYPE_INT) + IOCTL(TCXONC, 0, TYPE_INT) + IOCTL(TCFLSH, 0, TYPE_INT) + IOCTL(TIOCEXCL, 0, TYPE_NULL) + IOCTL(TIOCNXCL, 0, TYPE_NULL) + IOCTL(TIOCSCTTY, 0, TYPE_INT) + IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TIOCGSOFTCAR, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TIOCSSOFTCAR, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TIOCLINUX, IOC_R | IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TIOCCONS, 0, TYPE_NULL) + IOCTL(TIOCGSERIAL, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TIOCSSERIAL, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TIOCPKT, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TIOCNOTTY, 0, TYPE_NULL) + IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TIOCGPTN, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TIOCSPTLCK, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(FIOCLEX, 0, TYPE_NULL) + IOCTL(FIONCLEX, 0, TYPE_NULL) + IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TIOCGLCKTRMIOS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios))) + IOCTL(TIOCSLCKTRMIOS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios))) + IOCTL(TIOCSERCONFIG, 0, TYPE_NULL) + IOCTL(TIOCSERGETLSR, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TIOCSERGETMULTI, IOC_R, MK_PTR(MK_STRUCT(STRUCT_serial_multiport_struct))) + IOCTL(TIOCSERSETMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_serial_multiport_struct))) + IOCTL(TIOCMIWAIT, 0, TYPE_INT) + IOCTL(TIOCGICOUNT, IOC_R, MK_PTR(MK_STRUCT(STRUCT_serial_icounter_struct))) + + IOCTL(KIOCSOUND, 0, TYPE_INT) + IOCTL(KDMKTONE, 0, TYPE_INT) + IOCTL(KDGKBTYPE, IOC_R, MK_PTR(TYPE_CHAR)) + IOCTL(KDGKBENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbentry))) + IOCTL(KDGKBSENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbsentry))) + + IOCTL(BLKROSET, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(BLKRRPART, 0, TYPE_NULL) + IOCTL(BLKGETSIZE, IOC_R, MK_PTR(TYPE_ULONG)) +#ifdef BLKGETSIZE64 + IOCTL(BLKGETSIZE64, IOC_R, MK_PTR(TYPE_ULONGLONG)) +#endif + IOCTL(BLKFLSBUF, 0, TYPE_NULL) + IOCTL(BLKRASET, 0, TYPE_INT) + IOCTL(BLKRAGET, IOC_R, MK_PTR(TYPE_LONG)) +#ifdef FIBMAP + IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG)) +#endif +#ifdef FIGETBSZ + IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG)) +#endif + + IOCTL(SIOCATMARK, 0, TYPE_NULL) + IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) + IOCTL(SIOCDELRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry))) + IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) + IOCTL(SIOCSIFFLAGS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) + IOCTL(SIOCGIFADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCSIFADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCGIFBRDADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCSIFBRDADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCGIFDSTADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCSIFDSTADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCGIFNETMASK, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCSIFNETMASK, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCGIFHWADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCSIFHWADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCGIFTXQLEN, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCSIFTXQLEN, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCGIFMETRIC, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_int_ifreq))) + IOCTL(SIOCSIFMETRIC, IOC_W, MK_PTR(MK_STRUCT(STRUCT_int_ifreq))) + IOCTL(SIOCGIFMTU, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_int_ifreq))) + IOCTL(SIOCSIFMTU, IOC_W, MK_PTR(MK_STRUCT(STRUCT_int_ifreq))) + IOCTL(SIOCGIFMAP, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifmap_ifreq))) + IOCTL(SIOCSIFMAP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ifmap_ifreq))) + IOCTL(SIOCGIFSLAVE, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_char_ifreq))) + IOCTL(SIOCSIFSLAVE, IOC_W, MK_PTR(MK_STRUCT(STRUCT_char_ifreq))) + IOCTL(SIOCGIFMEM, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ptr_ifreq))) + IOCTL(SIOCSIFMEM, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ptr_ifreq))) + IOCTL(SIOCADDMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCDELMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL(SIOCSIFLINK, 0, TYPE_NULL) + IOCTL(SIOCGIFCONF, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifconf))) + IOCTL(SIOCGIFENCAP, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SIOCSIFENCAP, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SIOCDARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq))) + IOCTL(SIOCSARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq))) + IOCTL(SIOCGARP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_arpreq))) + IOCTL(SIOCDRARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq))) + IOCTL(SIOCSRARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq))) + IOCTL(SIOCGRARP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_arpreq))) + + IOCTL(CDROMPAUSE, 0, TYPE_NULL) + IOCTL(CDROMSTART, 0, TYPE_NULL) + IOCTL(CDROMSTOP, 0, TYPE_NULL) + IOCTL(CDROMRESUME, 0, TYPE_NULL) + IOCTL(CDROMEJECT, 0, TYPE_NULL) + IOCTL(CDROMEJECT_SW, 0, TYPE_INT) + IOCTL(CDROMCLOSETRAY, 0, TYPE_NULL) + IOCTL(CDROMRESET, 0, TYPE_NULL) + IOCTL(CDROMPLAYMSF, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(CDROMPLAYTRKIND, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(CDROMREADTOCHDR, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(CDROMREADTOCENTRY, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(CDROMVOLCTRL, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(CDROMSUBCHNL, IOC_RW, MK_PTR(TYPE_INT)) + /* XXX: incorrect (need specific handling) */ + IOCTL(CDROMREADAUDIO, IOC_W, MK_PTR(MK_STRUCT(STRUCT_cdrom_read_audio))) + IOCTL(CDROMREADCOOKED, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(CDROMREADRAW, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(CDROMREADMODE1, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(CDROMREADMODE2, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(CDROMREADALL, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(CDROMMULTISESSION, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(CDROM_GET_UPC, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(CDROMVOLREAD, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(CDROMSEEK, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(CDROMPLAYBLK, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(CDROM_MEDIA_CHANGED, 0, TYPE_NULL) + IOCTL(CDROM_SET_OPTIONS, 0, TYPE_INT) + IOCTL(CDROM_CLEAR_OPTIONS, 0, TYPE_INT) + IOCTL(CDROM_SELECT_SPEED, 0, TYPE_INT) + IOCTL(CDROM_SELECT_DISC, 0, TYPE_INT) + IOCTL(CDROM_DRIVE_STATUS, 0, TYPE_NULL) + IOCTL(CDROM_DISC_STATUS, 0, TYPE_NULL) + IOCTL(CDROMAUDIOBUFSIZ, 0, TYPE_INT) + +#if 0 + IOCTL(SNDCTL_COPR_HALT, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_COPR_LOAD, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_COPR_RCODE, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_COPR_RCVMSG, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_COPR_RDATA, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_COPR_RESET, 0, TYPE_NULL) + IOCTL(SNDCTL_COPR_RUN, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_COPR_SENDMSG, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_COPR_WCODE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_COPR_WDATA, IOC_W, MK_PTR(TYPE_INT)) +#endif + IOCTL(SNDCTL_DSP_CHANNELS, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_GETBLKSIZE, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_GETCAPS, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_GETFMTS, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info))) + IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info))) + IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info))) + IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info))) + IOCTL(SNDCTL_DSP_GETTRIGGER, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_MAPINBUF, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_MAPOUTBUF, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_NONBLOCK, 0, TYPE_NULL) + IOCTL(SNDCTL_DSP_POST, 0, TYPE_NULL) + IOCTL(SNDCTL_DSP_RESET, 0, TYPE_NULL) + IOCTL(SNDCTL_DSP_SETDUPLEX, 0, TYPE_NULL) + IOCTL(SNDCTL_DSP_SETFMT, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_SETFRAGMENT, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_SETSYNCRO, 0, TYPE_NULL) + IOCTL(SNDCTL_DSP_SETTRIGGER, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_SPEED, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_STEREO, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_SUBDIVIDE, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_DSP_SYNC, 0, TYPE_NULL) +#if 0 + IOCTL(SNDCTL_FM_4OP_ENABLE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_FM_LOAD_INSTR, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_MIDI_INFO, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_MIDI_MPUCMD, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_MIDI_MPUMODE, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_MIDI_PRETIME, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_SEQ_CTRLRATE, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_SEQ_GETINCOUNT, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_SEQ_GETOUTCOUNT, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_SEQ_NRMIDIS, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_SEQ_NRSYNTHS, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_SEQ_OUTOFBAND, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_SEQ_PANIC, 0, TYPE_NULL) + IOCTL(SNDCTL_SEQ_PERCMODE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_SEQ_RESET, 0, TYPE_NULL) + IOCTL(SNDCTL_SEQ_RESETSAMPLES, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_SEQ_SYNC, 0, TYPE_NULL) + IOCTL(SNDCTL_SEQ_TESTMIDI, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_SEQ_THRESHOLD, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_SYNTH_INFO, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_SYNTH_MEMAVL, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_TMR_CONTINUE, 0, TYPE_NULL) + IOCTL(SNDCTL_TMR_METRONOME, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_TMR_SELECT, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_TMR_SOURCE, IOC_RW, MK_PTR(TYPE_INT)) +#if 0 + /* we invalidate these defines because they have a same number as + termios ioctls */ + IOCTL(SNDCTL_TMR_START, 0, TYPE_NULL) + IOCTL(SNDCTL_TMR_STOP, 0, TYPE_NULL) +#endif + IOCTL(SNDCTL_TMR_TEMPO, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SNDCTL_TMR_TIMEBASE, IOC_RW, MK_PTR(TYPE_INT)) + + IOCTL(SOUND_PCM_WRITE_FILTER, IOC_W | IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_PCM_READ_RATE, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_PCM_READ_CHANNELS, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_PCM_READ_BITS, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_PCM_READ_FILTER, IOC_R, MK_PTR(TYPE_INT)) +#endif + IOCTL(SOUND_MIXER_INFO, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_ACCESS, 0, TYPE_PTRVOID) + IOCTL(SOUND_MIXER_PRIVATE1, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_PRIVATE2, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_PRIVATE3, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_PRIVATE4, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_PRIVATE5, IOC_RW, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_VOLUME, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_BASS, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_TREBLE, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_SYNTH, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_PCM, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_SPEAKER, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_LINE, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_MIC, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_CD, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_IMIX, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_ALTPCM, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_RECLEV, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_IGAIN, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_OGAIN, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_LINE1, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_LINE2, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_LINE3, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_MUTE, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_ENHANCE, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_LOUD, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_RECSRC, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_DEVMASK, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_RECMASK, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_STEREODEVS, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_READ_CAPS, IOC_R, MK_PTR(TYPE_INT)) + + IOCTL(SOUND_MIXER_WRITE_VOLUME, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_BASS, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_TREBLE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_SYNTH, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_PCM, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_SPEAKER, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_LINE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_MIC, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_CD, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_IMIX, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_ALTPCM, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_RECLEV, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_IGAIN, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_OGAIN, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_LINE1, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_LINE2, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_LINE3, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_MUTE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_ENHANCE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_LOUD, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(SOUND_MIXER_WRITE_RECSRC, IOC_W, MK_PTR(TYPE_INT)) + + IOCTL(HDIO_GETGEO, IOC_R, MK_PTR(MK_STRUCT(STRUCT_hd_geometry))) + IOCTL(HDIO_GET_UNMASKINTR, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(HDIO_GET_MULTCOUNT, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(HDIO_GET_IDENTITY, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(HDIO_GET_KEEPSETTINGS, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(HDIO_GET_NOWERR, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(HDIO_GET_DMA, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(HDIO_GET_32BIT, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(HDIO_DRIVE_CMD, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(HDIO_SET_UNMASKINTR, 0, TYPE_INT) + IOCTL(HDIO_SET_MULTCOUNT, 0, TYPE_INT) + IOCTL(HDIO_SET_KEEPSETTINGS, 0, TYPE_INT) + IOCTL(HDIO_SET_NOWERR, 0, TYPE_INT) + IOCTL(HDIO_SET_DMA, 0, TYPE_INT) + IOCTL(HDIO_SET_32BIT, 0, TYPE_INT) + IOCTL(HDIO_SET_PIO_MODE, 0, TYPE_INT) + + IOCTL(VFAT_IOCTL_READDIR_BOTH, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2))) + IOCTL(VFAT_IOCTL_READDIR_SHORT, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2))) diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c new file mode 100644 index 0000000..ef5409b --- /dev/null +++ b/linux-user/linuxload.c @@ -0,0 +1,195 @@ +/* Code for loading Linux executables. Mostly linux kenrel code. */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> + +#include "qemu.h" + +#define NGROUPS 32 + +/* ??? This should really be somewhere else. */ +void memcpy_to_target(target_ulong dest, const void *src, + unsigned long len) +{ + void *host_ptr; + + host_ptr = lock_user(dest, len, 0); + memcpy(host_ptr, src, len); + unlock_user(host_ptr, dest, 1); +} + +static int in_group_p(gid_t g) +{ + /* return TRUE if we're in the specified group, FALSE otherwise */ + int ngroup; + int i; + gid_t grouplist[NGROUPS]; + + ngroup = getgroups(NGROUPS, grouplist); + for(i = 0; i < ngroup; i++) { + if(grouplist[i] == g) { + return 1; + } + } + return 0; +} + +static int count(char ** vec) +{ + int i; + + for(i = 0; *vec; i++) { + vec++; + } + + return(i); +} + +static int prepare_binprm(struct linux_binprm *bprm) +{ + struct stat st; + int mode; + int retval, id_change; + + if(fstat(bprm->fd, &st) < 0) { + return(-errno); + } + + mode = st.st_mode; + if(!S_ISREG(mode)) { /* Must be regular file */ + return(-EACCES); + } + if(!(mode & 0111)) { /* Must have at least one execute bit set */ + return(-EACCES); + } + + bprm->e_uid = geteuid(); + bprm->e_gid = getegid(); + id_change = 0; + + /* Set-uid? */ + if(mode & S_ISUID) { + bprm->e_uid = st.st_uid; + if(bprm->e_uid != geteuid()) { + id_change = 1; + } + } + + /* Set-gid? */ + /* + * If setgid is set but no group execute bit then this + * is a candidate for mandatory locking, not a setgid + * executable. + */ + if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { + bprm->e_gid = st.st_gid; + if (!in_group_p(bprm->e_gid)) { + id_change = 1; + } + } + + memset(bprm->buf, 0, sizeof(bprm->buf)); + retval = lseek(bprm->fd, 0L, SEEK_SET); + if(retval >= 0) { + retval = read(bprm->fd, bprm->buf, 128); + } + if(retval < 0) { + perror("prepare_binprm"); + exit(-1); + /* return(-errno); */ + } + else { + return(retval); + } +} + +/* Construct the envp and argv tables on the target stack. */ +target_ulong loader_build_argptr(int envc, int argc, target_ulong sp, + target_ulong stringp, int push_ptr) +{ + int n = sizeof(target_ulong); + target_ulong envp; + target_ulong argv; + + sp -= (envc + 1) * n; + envp = sp; + sp -= (argc + 1) * n; + argv = sp; + if (push_ptr) { + sp -= n; tputl(sp, envp); + sp -= n; tputl(sp, argv); + } + sp -= n; tputl(sp, argc); + + while (argc-- > 0) { + tputl(argv, stringp); argv += n; + stringp += target_strlen(stringp) + 1; + } + tputl(argv, 0); + while (envc-- > 0) { + tputl(envp, stringp); envp += n; + stringp += target_strlen(stringp) + 1; + } + tputl(envp, 0); + + return sp; +} + +int loader_exec(const char * filename, char ** argv, char ** envp, + struct target_pt_regs * regs, struct image_info *infop) +{ + struct linux_binprm bprm; + int retval; + int i; + + bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); + for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ + bprm.page[i] = 0; + retval = open(filename, O_RDONLY); + if (retval < 0) + return retval; + bprm.fd = retval; + bprm.filename = (char *)filename; + bprm.argc = count(argv); + bprm.argv = argv; + bprm.envc = count(envp); + bprm.envp = envp; + + retval = prepare_binprm(&bprm); + + if(retval>=0) { + if (bprm.buf[0] == 0x7f + && bprm.buf[1] == 'E' + && bprm.buf[2] == 'L' + && bprm.buf[3] == 'F') { + retval = load_elf_binary(&bprm,regs,infop); +#if defined(TARGET_HAS_BFLT) + } else if (bprm.buf[0] == 'b' + && bprm.buf[1] == 'F' + && bprm.buf[2] == 'L' + && bprm.buf[3] == 'T') { + retval = load_flt_binary(&bprm,regs,infop); +#endif + } else { + fprintf(stderr, "Unknown binary format\n"); + return -1; + } + } + + if(retval>=0) { + /* success. Initialize important registers */ + do_init_thread(regs, infop); + return retval; + } + + /* Something went wrong, return the inode and free the argument pages*/ + for (i=0 ; i<MAX_ARG_PAGES ; i++) { + free(bprm.page[i]); + } + return(retval); +} diff --git a/linux-user/main.c b/linux-user/main.c new file mode 100644 index 0000000..d169311 --- /dev/null +++ b/linux-user/main.c @@ -0,0 +1,1716 @@ +/* + * qemu user main + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> + +#include "qemu.h" + +#define DEBUG_LOGFILE "/tmp/qemu.log" + +#ifdef __APPLE__ +#include <crt_externs.h> +# define environ (*_NSGetEnviron()) +#endif + +static const char *interp_prefix = CONFIG_QEMU_PREFIX; +const char *qemu_uname_release = CONFIG_UNAME_RELEASE; + +#if defined(__i386__) && !defined(CONFIG_STATIC) +/* Force usage of an ELF interpreter even if it is an ELF shared + object ! */ +const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; +#endif + +/* for recent libc, we add these dummy symbols which are not declared + when generating a linked object (bug in ld ?) */ +#if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined(CONFIG_STATIC) +long __preinit_array_start[0]; +long __preinit_array_end[0]; +long __init_array_start[0]; +long __init_array_end[0]; +long __fini_array_start[0]; +long __fini_array_end[0]; +#endif + +/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so + we allocate a bigger stack. Need a better solution, for example + by remapping the process stack directly at the right place */ +unsigned long x86_stack_size = 512 * 1024; + +void gemu_log(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +void cpu_outb(CPUState *env, int addr, int val) +{ + fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); +} + +void cpu_outw(CPUState *env, int addr, int val) +{ + fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); +} + +void cpu_outl(CPUState *env, int addr, int val) +{ + fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); +} + +int cpu_inb(CPUState *env, int addr) +{ + fprintf(stderr, "inb: port=0x%04x\n", addr); + return 0; +} + +int cpu_inw(CPUState *env, int addr) +{ + fprintf(stderr, "inw: port=0x%04x\n", addr); + return 0; +} + +int cpu_inl(CPUState *env, int addr) +{ + fprintf(stderr, "inl: port=0x%04x\n", addr); + return 0; +} + +int cpu_get_pic_interrupt(CPUState *env) +{ + return -1; +} + +/* timers for rdtsc */ + +#if 0 + +static uint64_t emu_time; + +int64_t cpu_get_real_ticks(void) +{ + return emu_time++; +} + +#endif + +#ifdef TARGET_I386 +/***********************************************************/ +/* CPUX86 core interface */ + +uint64_t cpu_get_tsc(CPUX86State *env) +{ + return cpu_get_real_ticks(); +} + +static void write_dt(void *ptr, unsigned long addr, unsigned long limit, + int flags) +{ + unsigned int e1, e2; + uint32_t *p; + e1 = (addr << 16) | (limit & 0xffff); + e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); + e2 |= flags; + p = ptr; + p[0] = tswapl(e1); + p[1] = tswapl(e2); +} + +static void set_gate(void *ptr, unsigned int type, unsigned int dpl, + unsigned long addr, unsigned int sel) +{ + unsigned int e1, e2; + uint32_t *p; + e1 = (addr & 0xffff) | (sel << 16); + e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); + p = ptr; + p[0] = tswapl(e1); + p[1] = tswapl(e2); +} + +uint64_t gdt_table[6]; +uint64_t idt_table[256]; + +/* only dpl matters as we do only user space emulation */ +static void set_idt(int n, unsigned int dpl) +{ + set_gate(idt_table + n, 0, dpl, 0, 0); +} + +void cpu_loop(CPUX86State *env) +{ + int trapnr; + target_ulong pc; + target_siginfo_t info; + + for(;;) { + trapnr = cpu_x86_exec(env); + switch(trapnr) { + case 0x80: + /* linux syscall */ + env->regs[R_EAX] = do_syscall(env, + env->regs[R_EAX], + env->regs[R_EBX], + env->regs[R_ECX], + env->regs[R_EDX], + env->regs[R_ESI], + env->regs[R_EDI], + env->regs[R_EBP]); + break; + case EXCP0B_NOSEG: + case EXCP0C_STACK: + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = TARGET_SI_KERNEL; + info._sifields._sigfault._addr = 0; + queue_signal(info.si_signo, &info); + break; + case EXCP0D_GPF: + if (env->eflags & VM_MASK) { + handle_vm86_fault(env); + } else { + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SI_KERNEL; + info._sifields._sigfault._addr = 0; + queue_signal(info.si_signo, &info); + } + break; + case EXCP0E_PAGE: + info.si_signo = SIGSEGV; + info.si_errno = 0; + if (!(env->error_code & 1)) + info.si_code = TARGET_SEGV_MAPERR; + else + info.si_code = TARGET_SEGV_ACCERR; + info._sifields._sigfault._addr = env->cr[2]; + queue_signal(info.si_signo, &info); + break; + case EXCP00_DIVZ: + if (env->eflags & VM_MASK) { + handle_vm86_trap(env, trapnr); + } else { + /* division by zero */ + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = TARGET_FPE_INTDIV; + info._sifields._sigfault._addr = env->eip; + queue_signal(info.si_signo, &info); + } + break; + case EXCP01_SSTP: + case EXCP03_INT3: + if (env->eflags & VM_MASK) { + handle_vm86_trap(env, trapnr); + } else { + info.si_signo = SIGTRAP; + info.si_errno = 0; + if (trapnr == EXCP01_SSTP) { + info.si_code = TARGET_TRAP_BRKPT; + info._sifields._sigfault._addr = env->eip; + } else { + info.si_code = TARGET_SI_KERNEL; + info._sifields._sigfault._addr = 0; + } + queue_signal(info.si_signo, &info); + } + break; + case EXCP04_INTO: + case EXCP05_BOUND: + if (env->eflags & VM_MASK) { + handle_vm86_trap(env, trapnr); + } else { + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SI_KERNEL; + info._sifields._sigfault._addr = 0; + queue_signal(info.si_signo, &info); + } + break; + case EXCP06_ILLOP: + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->eip; + queue_signal(info.si_signo, &info); + break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; + default: + pc = env->segs[R_CS].base + env->eip; + fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", + (long)pc, trapnr); + abort(); + } + process_pending_signals(env); + } +} +#endif + +#ifdef TARGET_ARM + +/* XXX: find a better solution */ +extern void tb_invalidate_page_range(target_ulong start, target_ulong end); + +static void arm_cache_flush(target_ulong start, target_ulong last) +{ + target_ulong addr, last1; + + if (last < start) + return; + addr = start; + for(;;) { + last1 = ((addr + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK) - 1; + if (last1 > last) + last1 = last; + tb_invalidate_page_range(addr, last1 + 1); + if (last1 == last) + break; + addr = last1 + 1; + } +} + +void cpu_loop(CPUARMState *env) +{ + int trapnr; + unsigned int n, insn; + target_siginfo_t info; + uint32_t addr; + + for(;;) { + trapnr = cpu_arm_exec(env); + switch(trapnr) { + case EXCP_UDEF: + { + TaskState *ts = env->opaque; + uint32_t opcode; + + /* we handle the FPU emulation here, as Linux */ + /* we get the opcode */ + opcode = tget32(env->regs[15]); + + if (EmulateAll(opcode, &ts->fpa, env) == 0) { + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->regs[15]; + queue_signal(info.si_signo, &info); + } else { + /* increment PC */ + env->regs[15] += 4; + } + } + break; + case EXCP_SWI: + case EXCP_BKPT: + { + env->eabi = 1; + /* system call */ + if (trapnr == EXCP_BKPT) { + if (env->thumb) { + insn = tget16(env->regs[15]); + n = insn & 0xff; + env->regs[15] += 2; + } else { + insn = tget32(env->regs[15]); + n = (insn & 0xf) | ((insn >> 4) & 0xff0); + env->regs[15] += 4; + } + } else { + if (env->thumb) { + insn = tget16(env->regs[15] - 2); + n = insn & 0xff; + } else { + insn = tget32(env->regs[15] - 4); + n = insn & 0xffffff; + } + } + + if (n == ARM_NR_cacheflush) { + arm_cache_flush(env->regs[0], env->regs[1]); + } else if (n == ARM_NR_semihosting + || n == ARM_NR_thumb_semihosting) { + env->regs[0] = do_arm_semihosting (env); + } else if (n == 0 || n >= ARM_SYSCALL_BASE + || (env->thumb && n == ARM_THUMB_SYSCALL)) { + /* linux syscall */ + if (env->thumb || n == 0) { + n = env->regs[7]; + } else { + n -= ARM_SYSCALL_BASE; + env->eabi = 0; + } + env->regs[0] = do_syscall(env, + n, + env->regs[0], + env->regs[1], + env->regs[2], + env->regs[3], + env->regs[4], + env->regs[5]); + } else { + goto error; + } + } + break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCP_PREFETCH_ABORT: + addr = env->cp15.c6_data; + goto do_segv; + case EXCP_DATA_ABORT: + addr = env->cp15.c6_insn; + goto do_segv; + do_segv: + { + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* XXX: check env->error_code */ + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = addr; + queue_signal(info.si_signo, &info); + } + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; + default: + error: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + abort(); + } + process_pending_signals(env); + } +} + +#endif + +#ifdef TARGET_SPARC + +//#define DEBUG_WIN + +/* WARNING: dealing with register windows _is_ complicated. More info + can be found at http://www.sics.se/~psm/sparcstack.html */ +static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) +{ + index = (index + cwp * 16) & (16 * NWINDOWS - 1); + /* wrap handling : if cwp is on the last window, then we use the + registers 'after' the end */ + if (index < 8 && env->cwp == (NWINDOWS - 1)) + index += (16 * NWINDOWS); + return index; +} + +/* save the register window 'cwp1' */ +static inline void save_window_offset(CPUSPARCState *env, int cwp1) +{ + unsigned int i; + target_ulong sp_ptr; + + sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; +#if defined(DEBUG_WIN) + printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", + (int)sp_ptr, cwp1); +#endif + for(i = 0; i < 16; i++) { + tputl(sp_ptr, env->regbase[get_reg_index(env, cwp1, 8 + i)]); + sp_ptr += sizeof(target_ulong); + } +} + +static void save_window(CPUSPARCState *env) +{ +#ifndef TARGET_SPARC64 + unsigned int new_wim; + new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) & + ((1LL << NWINDOWS) - 1); + save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1)); + env->wim = new_wim; +#else + save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1)); + env->cansave++; + env->canrestore--; +#endif +} + +static void restore_window(CPUSPARCState *env) +{ + unsigned int new_wim, i, cwp1; + target_ulong sp_ptr; + + new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & + ((1LL << NWINDOWS) - 1); + + /* restore the invalid window */ + cwp1 = (env->cwp + 1) & (NWINDOWS - 1); + sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; +#if defined(DEBUG_WIN) + printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", + (int)sp_ptr, cwp1); +#endif + for(i = 0; i < 16; i++) { + env->regbase[get_reg_index(env, cwp1, 8 + i)] = tgetl(sp_ptr); + sp_ptr += sizeof(target_ulong); + } + env->wim = new_wim; +#ifdef TARGET_SPARC64 + env->canrestore++; + if (env->cleanwin < NWINDOWS - 1) + env->cleanwin++; + env->cansave--; +#endif +} + +static void flush_windows(CPUSPARCState *env) +{ + int offset, cwp1; + + offset = 1; + for(;;) { + /* if restore would invoke restore_window(), then we can stop */ + cwp1 = (env->cwp + offset) & (NWINDOWS - 1); + if (env->wim & (1 << cwp1)) + break; + save_window_offset(env, cwp1); + offset++; + } + /* set wim so that restore will reload the registers */ + cwp1 = (env->cwp + 1) & (NWINDOWS - 1); + env->wim = 1 << cwp1; +#if defined(DEBUG_WIN) + printf("flush_windows: nb=%d\n", offset - 1); +#endif +} + +void cpu_loop (CPUSPARCState *env) +{ + int trapnr, ret; + target_siginfo_t info; + + while (1) { + trapnr = cpu_sparc_exec (env); + + switch (trapnr) { +#ifndef TARGET_SPARC64 + case 0x88: + case 0x90: +#else + case 0x16d: +#endif + ret = do_syscall (env, env->gregs[1], + env->regwptr[0], env->regwptr[1], + env->regwptr[2], env->regwptr[3], + env->regwptr[4], env->regwptr[5]); + if ((unsigned int)ret >= (unsigned int)(-515)) { + env->psr |= PSR_CARRY; + ret = -ret; + } else { + env->psr &= ~PSR_CARRY; + } + env->regwptr[0] = ret; + /* next instruction */ + env->pc = env->npc; + env->npc = env->npc + 4; + break; + case 0x83: /* flush windows */ + flush_windows(env); + /* next instruction */ + env->pc = env->npc; + env->npc = env->npc + 4; + break; +#ifndef TARGET_SPARC64 + case TT_WIN_OVF: /* window overflow */ + save_window(env); + break; + case TT_WIN_UNF: /* window underflow */ + restore_window(env); + break; + case TT_TFAULT: + case TT_DFAULT: + { + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* XXX: check env->error_code */ + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = env->mmuregs[4]; + queue_signal(info.si_signo, &info); + } + break; +#else + case TT_SPILL: /* window overflow */ + save_window(env); + break; + case TT_FILL: /* window underflow */ + restore_window(env); + break; + // XXX +#endif + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; + default: + printf ("Unhandled trap: 0x%x\n", trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + exit (1); + } + process_pending_signals (env); + } +} + +#endif + +#ifdef TARGET_PPC + +static inline uint64_t cpu_ppc_get_tb (CPUState *env) +{ + /* TO FIX */ + return 0; +} + +uint32_t cpu_ppc_load_tbl (CPUState *env) +{ + return cpu_ppc_get_tb(env) & 0xFFFFFFFF; +} + +uint32_t cpu_ppc_load_tbu (CPUState *env) +{ + return cpu_ppc_get_tb(env) >> 32; +} + +static void cpu_ppc_store_tb (CPUState *env, uint64_t value) +{ + /* TO FIX */ +} + +void cpu_ppc_store_tbu (CPUState *env, uint32_t value) +{ + cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); +} + +void cpu_ppc_store_tbl (CPUState *env, uint32_t value) +{ + cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); +} + +uint32_t cpu_ppc_load_decr (CPUState *env) +{ + /* TO FIX */ + return -1; +} + +void cpu_ppc_store_decr (CPUState *env, uint32_t value) +{ + /* TO FIX */ +} + +void cpu_loop(CPUPPCState *env) +{ + target_siginfo_t info; + int trapnr; + uint32_t ret; + + for(;;) { + trapnr = cpu_ppc_exec(env); + if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH && + trapnr != EXCP_TRACE) { + if (loglevel > 0) { + cpu_dump_state(env, logfile, fprintf, 0); + } + } + switch(trapnr) { + case EXCP_NONE: + break; + case EXCP_SYSCALL_USER: + /* system call */ + /* WARNING: + * PPC ABI uses overflow flag in cr0 to signal an error + * in syscalls. + */ +#if 0 + printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0], + env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]); +#endif + env->crf[0] &= ~0x1; + ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6], env->gpr[7], + env->gpr[8]); + if (ret > (uint32_t)(-515)) { + env->crf[0] |= 0x1; + ret = -ret; + } + env->gpr[3] = ret; +#if 0 + printf("syscall returned 0x%08x (%d)\n", ret, ret); +#endif + break; + case EXCP_RESET: + /* Should not happen ! */ + fprintf(stderr, "RESET asked... Stop emulation\n"); + if (loglevel) + fprintf(logfile, "RESET asked... Stop emulation\n"); + abort(); + case EXCP_MACHINE_CHECK: + fprintf(stderr, "Machine check exeption... Stop emulation\n"); + if (loglevel) + fprintf(logfile, "RESET asked... Stop emulation\n"); + info.si_signo = TARGET_SIGBUS; + info.si_errno = 0; + info.si_code = TARGET_BUS_OBJERR; + info._sifields._sigfault._addr = env->nip - 4; + queue_signal(info.si_signo, &info); + case EXCP_DSI: + fprintf(stderr, "Invalid data memory access: 0x%08x\n", + env->spr[SPR_DAR]); + if (loglevel) { + fprintf(logfile, "Invalid data memory access: 0x%08x\n", + env->spr[SPR_DAR]); + } + switch (env->error_code & 0xFF000000) { + case 0x40000000: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + break; + case 0x04000000: + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLADR; + break; + case 0x08000000: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_ACCERR; + break; + default: + /* Let's send a regular segfault... */ + fprintf(stderr, "Invalid segfault errno (%02x)\n", + env->error_code); + if (loglevel) { + fprintf(logfile, "Invalid segfault errno (%02x)\n", + env->error_code); + } + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + break; + } + info._sifields._sigfault._addr = env->nip; + queue_signal(info.si_signo, &info); + break; + case EXCP_ISI: + fprintf(stderr, "Invalid instruction fetch\n"); + if (loglevel) + fprintf(logfile, "Invalid instruction fetch\n"); + switch (env->error_code & 0xFF000000) { + case 0x40000000: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + break; + case 0x10000000: + case 0x08000000: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_ACCERR; + break; + default: + /* Let's send a regular segfault... */ + fprintf(stderr, "Invalid segfault errno (%02x)\n", + env->error_code); + if (loglevel) { + fprintf(logfile, "Invalid segfault errno (%02x)\n", + env->error_code); + } + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + break; + } + info._sifields._sigfault._addr = env->nip - 4; + queue_signal(info.si_signo, &info); + break; + case EXCP_EXTERNAL: + /* Should not happen ! */ + fprintf(stderr, "External interruption... Stop emulation\n"); + if (loglevel) + fprintf(logfile, "External interruption... Stop emulation\n"); + abort(); + case EXCP_ALIGN: + fprintf(stderr, "Invalid unaligned memory access\n"); + if (loglevel) + fprintf(logfile, "Invalid unaligned memory access\n"); + info.si_signo = TARGET_SIGBUS; + info.si_errno = 0; + info.si_code = TARGET_BUS_ADRALN; + info._sifields._sigfault._addr = env->nip - 4; + queue_signal(info.si_signo, &info); + break; + case EXCP_PROGRAM: + switch (env->error_code & ~0xF) { + case EXCP_FP: + fprintf(stderr, "Program exception\n"); + if (loglevel) + fprintf(logfile, "Program exception\n"); + /* Set FX */ + env->fpscr[7] |= 0x8; + /* Finally, update FEX */ + if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & + ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) + env->fpscr[7] |= 0x4; + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case EXCP_FP_OX: + info.si_code = TARGET_FPE_FLTOVF; + break; + case EXCP_FP_UX: + info.si_code = TARGET_FPE_FLTUND; + break; + case EXCP_FP_ZX: + case EXCP_FP_VXZDZ: + info.si_code = TARGET_FPE_FLTDIV; + break; + case EXCP_FP_XX: + info.si_code = TARGET_FPE_FLTRES; + break; + case EXCP_FP_VXSOFT: + info.si_code = TARGET_FPE_FLTINV; + break; + case EXCP_FP_VXNAN: + case EXCP_FP_VXISI: + case EXCP_FP_VXIDI: + case EXCP_FP_VXIMZ: + case EXCP_FP_VXVC: + case EXCP_FP_VXSQRT: + case EXCP_FP_VXCVI: + info.si_code = TARGET_FPE_FLTSUB; + break; + default: + fprintf(stderr, "Unknown floating point exception " + "(%02x)\n", env->error_code); + if (loglevel) { + fprintf(logfile, "Unknown floating point exception " + "(%02x)\n", env->error_code & 0xF); + } + } + break; + case EXCP_INVAL: + fprintf(stderr, "Invalid instruction\n"); + if (loglevel) + fprintf(logfile, "Invalid instruction\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case EXCP_INVAL_INVAL: + info.si_code = TARGET_ILL_ILLOPC; + break; + case EXCP_INVAL_LSWX: + info.si_code = TARGET_ILL_ILLOPN; + break; + case EXCP_INVAL_SPR: + info.si_code = TARGET_ILL_PRVREG; + break; + case EXCP_INVAL_FP: + info.si_code = TARGET_ILL_COPROC; + break; + default: + fprintf(stderr, "Unknown invalid operation (%02x)\n", + env->error_code & 0xF); + if (loglevel) { + fprintf(logfile, "Unknown invalid operation (%02x)\n", + env->error_code & 0xF); + } + info.si_code = TARGET_ILL_ILLADR; + break; + } + break; + case EXCP_PRIV: + fprintf(stderr, "Privilege violation\n"); + if (loglevel) + fprintf(logfile, "Privilege violation\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + switch (env->error_code & 0xF) { + case EXCP_PRIV_OPC: + info.si_code = TARGET_ILL_PRVOPC; + break; + case EXCP_PRIV_REG: + info.si_code = TARGET_ILL_PRVREG; + break; + default: + fprintf(stderr, "Unknown privilege violation (%02x)\n", + env->error_code & 0xF); + info.si_code = TARGET_ILL_PRVOPC; + break; + } + break; + case EXCP_TRAP: + fprintf(stderr, "Tried to call a TRAP\n"); + if (loglevel) + fprintf(logfile, "Tried to call a TRAP\n"); + abort(); + default: + /* Should not happen ! */ + fprintf(stderr, "Unknown program exception (%02x)\n", + env->error_code); + if (loglevel) { + fprintf(logfile, "Unknwon program exception (%02x)\n", + env->error_code); + } + abort(); + } + info._sifields._sigfault._addr = env->nip - 4; + queue_signal(info.si_signo, &info); + break; + case EXCP_NO_FP: + fprintf(stderr, "No floating point allowed\n"); + if (loglevel) + fprintf(logfile, "No floating point allowed\n"); + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_COPROC; + info._sifields._sigfault._addr = env->nip - 4; + queue_signal(info.si_signo, &info); + break; + case EXCP_DECR: + /* Should not happen ! */ + fprintf(stderr, "Decrementer exception\n"); + if (loglevel) + fprintf(logfile, "Decrementer exception\n"); + abort(); + case EXCP_TRACE: + /* Do nothing: we use this to trace execution */ + break; + case EXCP_FP_ASSIST: + /* Should not happen ! */ + fprintf(stderr, "Floating point assist exception\n"); + if (loglevel) + fprintf(logfile, "Floating point assist exception\n"); + abort(); + case EXCP_MTMSR: + /* We reloaded the msr, just go on */ + if (msr_pr == 0) { + fprintf(stderr, "Tried to go into supervisor mode !\n"); + if (loglevel) + fprintf(logfile, "Tried to go into supervisor mode !\n"); + abort(); + } + break; + case EXCP_BRANCH: + /* We stopped because of a jump... */ + break; + case EXCP_INTERRUPT: + /* Don't know why this should ever happen... */ + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; + default: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + if (loglevel) { + fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - " + "0x%02x - aborting\n", trapnr, env->error_code); + } + abort(); + } + process_pending_signals(env); + } +} +#endif + +#ifdef TARGET_MIPS + +#define MIPS_SYS(name, args) args, + +static const uint8_t mips_syscall_args[] = { + MIPS_SYS(sys_syscall , 0) /* 4000 */ + MIPS_SYS(sys_exit , 1) + MIPS_SYS(sys_fork , 0) + MIPS_SYS(sys_read , 3) + MIPS_SYS(sys_write , 3) + MIPS_SYS(sys_open , 3) /* 4005 */ + MIPS_SYS(sys_close , 1) + MIPS_SYS(sys_waitpid , 3) + MIPS_SYS(sys_creat , 2) + MIPS_SYS(sys_link , 2) + MIPS_SYS(sys_unlink , 1) /* 4010 */ + MIPS_SYS(sys_execve , 0) + MIPS_SYS(sys_chdir , 1) + MIPS_SYS(sys_time , 1) + MIPS_SYS(sys_mknod , 3) + MIPS_SYS(sys_chmod , 2) /* 4015 */ + MIPS_SYS(sys_lchown , 3) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_ni_syscall , 0) /* was sys_stat */ + MIPS_SYS(sys_lseek , 3) + MIPS_SYS(sys_getpid , 0) /* 4020 */ + MIPS_SYS(sys_mount , 5) + MIPS_SYS(sys_oldumount , 1) + MIPS_SYS(sys_setuid , 1) + MIPS_SYS(sys_getuid , 0) + MIPS_SYS(sys_stime , 1) /* 4025 */ + MIPS_SYS(sys_ptrace , 4) + MIPS_SYS(sys_alarm , 1) + MIPS_SYS(sys_ni_syscall , 0) /* was sys_fstat */ + MIPS_SYS(sys_pause , 0) + MIPS_SYS(sys_utime , 2) /* 4030 */ + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_access , 2) + MIPS_SYS(sys_nice , 1) + MIPS_SYS(sys_ni_syscall , 0) /* 4035 */ + MIPS_SYS(sys_sync , 0) + MIPS_SYS(sys_kill , 2) + MIPS_SYS(sys_rename , 2) + MIPS_SYS(sys_mkdir , 2) + MIPS_SYS(sys_rmdir , 1) /* 4040 */ + MIPS_SYS(sys_dup , 1) + MIPS_SYS(sys_pipe , 0) + MIPS_SYS(sys_times , 1) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_brk , 1) /* 4045 */ + MIPS_SYS(sys_setgid , 1) + MIPS_SYS(sys_getgid , 0) + MIPS_SYS(sys_ni_syscall , 0) /* was signal(2) */ + MIPS_SYS(sys_geteuid , 0) + MIPS_SYS(sys_getegid , 0) /* 4050 */ + MIPS_SYS(sys_acct , 0) + MIPS_SYS(sys_umount , 2) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_ioctl , 3) + MIPS_SYS(sys_fcntl , 3) /* 4055 */ + MIPS_SYS(sys_ni_syscall , 2) + MIPS_SYS(sys_setpgid , 2) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_olduname , 1) + MIPS_SYS(sys_umask , 1) /* 4060 */ + MIPS_SYS(sys_chroot , 1) + MIPS_SYS(sys_ustat , 2) + MIPS_SYS(sys_dup2 , 2) + MIPS_SYS(sys_getppid , 0) + MIPS_SYS(sys_getpgrp , 0) /* 4065 */ + MIPS_SYS(sys_setsid , 0) + MIPS_SYS(sys_sigaction , 3) + MIPS_SYS(sys_sgetmask , 0) + MIPS_SYS(sys_ssetmask , 1) + MIPS_SYS(sys_setreuid , 2) /* 4070 */ + MIPS_SYS(sys_setregid , 2) + MIPS_SYS(sys_sigsuspend , 0) + MIPS_SYS(sys_sigpending , 1) + MIPS_SYS(sys_sethostname , 2) + MIPS_SYS(sys_setrlimit , 2) /* 4075 */ + MIPS_SYS(sys_getrlimit , 2) + MIPS_SYS(sys_getrusage , 2) + MIPS_SYS(sys_gettimeofday, 2) + MIPS_SYS(sys_settimeofday, 2) + MIPS_SYS(sys_getgroups , 2) /* 4080 */ + MIPS_SYS(sys_setgroups , 2) + MIPS_SYS(sys_ni_syscall , 0) /* old_select */ + MIPS_SYS(sys_symlink , 2) + MIPS_SYS(sys_ni_syscall , 0) /* was sys_lstat */ + MIPS_SYS(sys_readlink , 3) /* 4085 */ + MIPS_SYS(sys_uselib , 1) + MIPS_SYS(sys_swapon , 2) + MIPS_SYS(sys_reboot , 3) + MIPS_SYS(old_readdir , 3) + MIPS_SYS(old_mmap , 6) /* 4090 */ + MIPS_SYS(sys_munmap , 2) + MIPS_SYS(sys_truncate , 2) + MIPS_SYS(sys_ftruncate , 2) + MIPS_SYS(sys_fchmod , 2) + MIPS_SYS(sys_fchown , 3) /* 4095 */ + MIPS_SYS(sys_getpriority , 2) + MIPS_SYS(sys_setpriority , 3) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_statfs , 2) + MIPS_SYS(sys_fstatfs , 2) /* 4100 */ + MIPS_SYS(sys_ni_syscall , 0) /* was ioperm(2) */ + MIPS_SYS(sys_socketcall , 2) + MIPS_SYS(sys_syslog , 3) + MIPS_SYS(sys_setitimer , 3) + MIPS_SYS(sys_getitimer , 2) /* 4105 */ + MIPS_SYS(sys_newstat , 2) + MIPS_SYS(sys_newlstat , 2) + MIPS_SYS(sys_newfstat , 2) + MIPS_SYS(sys_uname , 1) + MIPS_SYS(sys_ni_syscall , 0) /* 4110 was iopl(2) */ + MIPS_SYS(sys_vhangup , 0) + MIPS_SYS(sys_ni_syscall , 0) /* was sys_idle() */ + MIPS_SYS(sys_ni_syscall , 0) /* was sys_vm86 */ + MIPS_SYS(sys_wait4 , 4) + MIPS_SYS(sys_swapoff , 1) /* 4115 */ + MIPS_SYS(sys_sysinfo , 1) + MIPS_SYS(sys_ipc , 6) + MIPS_SYS(sys_fsync , 1) + MIPS_SYS(sys_sigreturn , 0) + MIPS_SYS(sys_clone , 0) /* 4120 */ + MIPS_SYS(sys_setdomainname, 2) + MIPS_SYS(sys_newuname , 1) + MIPS_SYS(sys_ni_syscall , 0) /* sys_modify_ldt */ + MIPS_SYS(sys_adjtimex , 1) + MIPS_SYS(sys_mprotect , 3) /* 4125 */ + MIPS_SYS(sys_sigprocmask , 3) + MIPS_SYS(sys_ni_syscall , 0) /* was create_module */ + MIPS_SYS(sys_init_module , 5) + MIPS_SYS(sys_delete_module, 1) + MIPS_SYS(sys_ni_syscall , 0) /* 4130 was get_kernel_syms */ + MIPS_SYS(sys_quotactl , 0) + MIPS_SYS(sys_getpgid , 1) + MIPS_SYS(sys_fchdir , 1) + MIPS_SYS(sys_bdflush , 2) + MIPS_SYS(sys_sysfs , 3) /* 4135 */ + MIPS_SYS(sys_personality , 1) + MIPS_SYS(sys_ni_syscall , 0) /* for afs_syscall */ + MIPS_SYS(sys_setfsuid , 1) + MIPS_SYS(sys_setfsgid , 1) + MIPS_SYS(sys_llseek , 5) /* 4140 */ + MIPS_SYS(sys_getdents , 3) + MIPS_SYS(sys_select , 5) + MIPS_SYS(sys_flock , 2) + MIPS_SYS(sys_msync , 3) + MIPS_SYS(sys_readv , 3) /* 4145 */ + MIPS_SYS(sys_writev , 3) + MIPS_SYS(sys_cacheflush , 3) + MIPS_SYS(sys_cachectl , 3) + MIPS_SYS(sys_sysmips , 4) + MIPS_SYS(sys_ni_syscall , 0) /* 4150 */ + MIPS_SYS(sys_getsid , 1) + MIPS_SYS(sys_fdatasync , 0) + MIPS_SYS(sys_sysctl , 1) + MIPS_SYS(sys_mlock , 2) + MIPS_SYS(sys_munlock , 2) /* 4155 */ + MIPS_SYS(sys_mlockall , 1) + MIPS_SYS(sys_munlockall , 0) + MIPS_SYS(sys_sched_setparam, 2) + MIPS_SYS(sys_sched_getparam, 2) + MIPS_SYS(sys_sched_setscheduler, 3) /* 4160 */ + MIPS_SYS(sys_sched_getscheduler, 1) + MIPS_SYS(sys_sched_yield , 0) + MIPS_SYS(sys_sched_get_priority_max, 1) + MIPS_SYS(sys_sched_get_priority_min, 1) + MIPS_SYS(sys_sched_rr_get_interval, 2) /* 4165 */ + MIPS_SYS(sys_nanosleep, 2) + MIPS_SYS(sys_mremap , 4) + MIPS_SYS(sys_accept , 3) + MIPS_SYS(sys_bind , 3) + MIPS_SYS(sys_connect , 3) /* 4170 */ + MIPS_SYS(sys_getpeername , 3) + MIPS_SYS(sys_getsockname , 3) + MIPS_SYS(sys_getsockopt , 5) + MIPS_SYS(sys_listen , 2) + MIPS_SYS(sys_recv , 4) /* 4175 */ + MIPS_SYS(sys_recvfrom , 6) + MIPS_SYS(sys_recvmsg , 3) + MIPS_SYS(sys_send , 4) + MIPS_SYS(sys_sendmsg , 3) + MIPS_SYS(sys_sendto , 6) /* 4180 */ + MIPS_SYS(sys_setsockopt , 5) + MIPS_SYS(sys_shutdown , 2) + MIPS_SYS(sys_socket , 3) + MIPS_SYS(sys_socketpair , 4) + MIPS_SYS(sys_setresuid , 3) /* 4185 */ + MIPS_SYS(sys_getresuid , 3) + MIPS_SYS(sys_ni_syscall , 0) /* was sys_query_module */ + MIPS_SYS(sys_poll , 3) + MIPS_SYS(sys_nfsservctl , 3) + MIPS_SYS(sys_setresgid , 3) /* 4190 */ + MIPS_SYS(sys_getresgid , 3) + MIPS_SYS(sys_prctl , 5) + MIPS_SYS(sys_rt_sigreturn, 0) + MIPS_SYS(sys_rt_sigaction, 4) + MIPS_SYS(sys_rt_sigprocmask, 4) /* 4195 */ + MIPS_SYS(sys_rt_sigpending, 2) + MIPS_SYS(sys_rt_sigtimedwait, 4) + MIPS_SYS(sys_rt_sigqueueinfo, 3) + MIPS_SYS(sys_rt_sigsuspend, 0) + MIPS_SYS(sys_pread64 , 6) /* 4200 */ + MIPS_SYS(sys_pwrite64 , 6) + MIPS_SYS(sys_chown , 3) + MIPS_SYS(sys_getcwd , 2) + MIPS_SYS(sys_capget , 2) + MIPS_SYS(sys_capset , 2) /* 4205 */ + MIPS_SYS(sys_sigaltstack , 0) + MIPS_SYS(sys_sendfile , 4) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_mmap2 , 6) /* 4210 */ + MIPS_SYS(sys_truncate64 , 4) + MIPS_SYS(sys_ftruncate64 , 4) + MIPS_SYS(sys_stat64 , 2) + MIPS_SYS(sys_lstat64 , 2) + MIPS_SYS(sys_fstat64 , 2) /* 4215 */ + MIPS_SYS(sys_pivot_root , 2) + MIPS_SYS(sys_mincore , 3) + MIPS_SYS(sys_madvise , 3) + MIPS_SYS(sys_getdents64 , 3) + MIPS_SYS(sys_fcntl64 , 3) /* 4220 */ + MIPS_SYS(sys_ni_syscall , 0) + MIPS_SYS(sys_gettid , 0) + MIPS_SYS(sys_readahead , 5) + MIPS_SYS(sys_setxattr , 5) + MIPS_SYS(sys_lsetxattr , 5) /* 4225 */ + MIPS_SYS(sys_fsetxattr , 5) + MIPS_SYS(sys_getxattr , 4) + MIPS_SYS(sys_lgetxattr , 4) + MIPS_SYS(sys_fgetxattr , 4) + MIPS_SYS(sys_listxattr , 3) /* 4230 */ + MIPS_SYS(sys_llistxattr , 3) + MIPS_SYS(sys_flistxattr , 3) + MIPS_SYS(sys_removexattr , 2) + MIPS_SYS(sys_lremovexattr, 2) + MIPS_SYS(sys_fremovexattr, 2) /* 4235 */ + MIPS_SYS(sys_tkill , 2) + MIPS_SYS(sys_sendfile64 , 5) + MIPS_SYS(sys_futex , 2) + MIPS_SYS(sys_sched_setaffinity, 3) + MIPS_SYS(sys_sched_getaffinity, 3) /* 4240 */ + MIPS_SYS(sys_io_setup , 2) + MIPS_SYS(sys_io_destroy , 1) + MIPS_SYS(sys_io_getevents, 5) + MIPS_SYS(sys_io_submit , 3) + MIPS_SYS(sys_io_cancel , 3) /* 4245 */ + MIPS_SYS(sys_exit_group , 1) + MIPS_SYS(sys_lookup_dcookie, 3) + MIPS_SYS(sys_epoll_create, 1) + MIPS_SYS(sys_epoll_ctl , 4) + MIPS_SYS(sys_epoll_wait , 3) /* 4250 */ + MIPS_SYS(sys_remap_file_pages, 5) + MIPS_SYS(sys_set_tid_address, 1) + MIPS_SYS(sys_restart_syscall, 0) + MIPS_SYS(sys_fadvise64_64, 7) + MIPS_SYS(sys_statfs64 , 3) /* 4255 */ + MIPS_SYS(sys_fstatfs64 , 2) + MIPS_SYS(sys_timer_create, 3) + MIPS_SYS(sys_timer_settime, 4) + MIPS_SYS(sys_timer_gettime, 2) + MIPS_SYS(sys_timer_getoverrun, 1) /* 4260 */ + MIPS_SYS(sys_timer_delete, 1) + MIPS_SYS(sys_clock_settime, 2) + MIPS_SYS(sys_clock_gettime, 2) + MIPS_SYS(sys_clock_getres, 2) + MIPS_SYS(sys_clock_nanosleep, 4) /* 4265 */ + MIPS_SYS(sys_tgkill , 3) + MIPS_SYS(sys_utimes , 2) + MIPS_SYS(sys_mbind , 4) + MIPS_SYS(sys_ni_syscall , 0) /* sys_get_mempolicy */ + MIPS_SYS(sys_ni_syscall , 0) /* 4270 sys_set_mempolicy */ + MIPS_SYS(sys_mq_open , 4) + MIPS_SYS(sys_mq_unlink , 1) + MIPS_SYS(sys_mq_timedsend, 5) + MIPS_SYS(sys_mq_timedreceive, 5) + MIPS_SYS(sys_mq_notify , 2) /* 4275 */ + MIPS_SYS(sys_mq_getsetattr, 3) + MIPS_SYS(sys_ni_syscall , 0) /* sys_vserver */ + MIPS_SYS(sys_waitid , 4) + MIPS_SYS(sys_ni_syscall , 0) /* available, was setaltroot */ + MIPS_SYS(sys_add_key , 5) + MIPS_SYS(sys_request_key , 4) + MIPS_SYS(sys_keyctl , 5) +}; + +#undef MIPS_SYS + +void cpu_loop(CPUMIPSState *env) +{ + target_siginfo_t info; + int trapnr, ret, nb_args; + unsigned int syscall_num; + target_ulong arg5, arg6, sp_reg; + + for(;;) { + trapnr = cpu_mips_exec(env); + switch(trapnr) { + case EXCP_SYSCALL: + { + syscall_num = env->gpr[2] - 4000; + env->PC += 4; + if (syscall_num >= sizeof(mips_syscall_args)) { + ret = -ENOSYS; + } else { + nb_args = mips_syscall_args[syscall_num]; + if (nb_args >= 5) { + sp_reg = env->gpr[29]; + /* these arguments are taken from the stack */ + arg5 = tgetl(sp_reg + 16); + if (nb_args >= 6) { + arg6 = tgetl(sp_reg + 20); + } else { + arg6 = 0; + } + } else { + arg5 = 0; + arg6 = 0; + } + ret = do_syscall(env, + env->gpr[2], + env->gpr[4], + env->gpr[5], + env->gpr[6], + env->gpr[7], + arg5, + arg6); + } + if ((unsigned int)ret >= (unsigned int)(-1133)) { + env->gpr[7] = 1; /* error flag */ + ret = -ret; + env->gpr[0] = ret; + env->gpr[2] = ret; + } else { + env->gpr[7] = 0; /* error flag */ + env->gpr[2] = ret; + } + } + break; + case EXCP_CpU: + case EXCP_RI: + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = 0; + queue_signal(info.si_signo, &info); + break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + default: + // error: + fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + abort(); + } + process_pending_signals(env); + } +} +#endif + +#ifdef TARGET_SH4 +void cpu_loop (CPUState *env) +{ + int trapnr, ret; + target_siginfo_t info; + + while (1) { + trapnr = cpu_sh4_exec (env); + + switch (trapnr) { + case 0x160: + ret = do_syscall(env, + env->gregs[3], + env->gregs[4], + env->gregs[5], + env->gregs[6], + env->gregs[7], + env->gregs[0], + 0); + env->gregs[0] = ret; + env->pc += 2; + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(info.si_signo, &info); + } + } + break; + default: + printf ("Unhandled trap: 0x%x\n", trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + exit (1); + } + process_pending_signals (env); + } +} +#endif + +void usage(void) +{ + printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n" + "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n" + "Linux CPU emulator (compiled for %s emulation)\n" + "\n" + "-h print this help\n" + "-g port wait gdb connection to port\n" + "-L path set the elf interpreter prefix (default=%s)\n" + "-s size set the stack size in bytes (default=%ld)\n" + "\n" + "debug options:\n" +#ifdef USE_CODE_COPY + "-no-code-copy disable code copy acceleration\n" +#endif + "-d options activate log (logfile=%s)\n" + "-p pagesize set the host page size to 'pagesize'\n", + TARGET_ARCH, + interp_prefix, + x86_stack_size, + DEBUG_LOGFILE); + _exit(1); +} + +/* XXX: currently only used for async signals (see signal.c) */ +CPUState *global_env; + +/* used to free thread contexts */ +TaskState *first_task_state; + +int main(int argc, char **argv) +{ + const char *filename; + struct target_pt_regs regs1, *regs = ®s1; + struct image_info info1, *info = &info1; + TaskState ts1, *ts = &ts1; + CPUState *env; + int optind; + const char *r; + int gdbstub_port = 0; + + if (argc <= 1) + usage(); + + /* init debug */ + cpu_set_log_filename(DEBUG_LOGFILE); + + optind = 1; + for(;;) { + if (optind >= argc) + break; + r = argv[optind]; + if (r[0] != '-') + break; + optind++; + r++; + if (!strcmp(r, "-")) { + break; + } else if (!strcmp(r, "d")) { + int mask; + CPULogItem *item; + + if (optind >= argc) + break; + + r = argv[optind++]; + mask = cpu_str_to_log_mask(r); + if (!mask) { + printf("Log items (comma separated):\n"); + for(item = cpu_log_items; item->mask != 0; item++) { + printf("%-10s %s\n", item->name, item->help); + } + exit(1); + } + cpu_set_log(mask); + } else if (!strcmp(r, "s")) { + r = argv[optind++]; + x86_stack_size = strtol(r, (char **)&r, 0); + if (x86_stack_size <= 0) + usage(); + if (*r == 'M') + x86_stack_size *= 1024 * 1024; + else if (*r == 'k' || *r == 'K') + x86_stack_size *= 1024; + } else if (!strcmp(r, "L")) { + interp_prefix = argv[optind++]; + } else if (!strcmp(r, "p")) { + qemu_host_page_size = atoi(argv[optind++]); + if (qemu_host_page_size == 0 || + (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) { + fprintf(stderr, "page size must be a power of two\n"); + exit(1); + } + } else if (!strcmp(r, "g")) { + gdbstub_port = atoi(argv[optind++]); + } else if (!strcmp(r, "r")) { + qemu_uname_release = argv[optind++]; + } else +#ifdef USE_CODE_COPY + if (!strcmp(r, "no-code-copy")) { + code_copy_enabled = 0; + } else +#endif + { + usage(); + } + } + if (optind >= argc) + usage(); + filename = argv[optind]; + + /* Zero out regs */ + memset(regs, 0, sizeof(struct target_pt_regs)); + + /* Zero out image_info */ + memset(info, 0, sizeof(struct image_info)); + + /* Scan interp_prefix dir for replacement files. */ + init_paths(interp_prefix); + + /* NOTE: we need to init the CPU at this stage to get + qemu_host_page_size */ + env = cpu_init(); + global_env = env; + + if (loader_exec(filename, argv+optind, environ, regs, info) != 0) { + printf("Error loading %s\n", filename); + _exit(1); + } + + if (loglevel) { + page_dump(logfile); + + fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk); + fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); + fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); + fprintf(logfile, "start_data 0x%08lx\n" , info->start_data); + fprintf(logfile, "end_data 0x%08lx\n" , info->end_data); + fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack); + fprintf(logfile, "brk 0x%08lx\n" , info->brk); + fprintf(logfile, "entry 0x%08lx\n" , info->entry); + } + + target_set_brk(info->brk); + syscall_init(); + signal_init(); + + /* build Task State */ + memset(ts, 0, sizeof(TaskState)); + env->opaque = ts; + ts->used = 1; + ts->info = info; + env->user_mode_only = 1; + +#if defined(TARGET_I386) + cpu_x86_set_cpl(env, 3); + + env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; + env->hflags |= HF_PE_MASK; + if (env->cpuid_features & CPUID_SSE) { + env->cr[4] |= CR4_OSFXSR_MASK; + env->hflags |= HF_OSFXSR_MASK; + } + + /* flags setup : we activate the IRQs by default as in user mode */ + env->eflags |= IF_MASK; + + /* linux register setup */ + env->regs[R_EAX] = regs->eax; + env->regs[R_EBX] = regs->ebx; + env->regs[R_ECX] = regs->ecx; + env->regs[R_EDX] = regs->edx; + env->regs[R_ESI] = regs->esi; + env->regs[R_EDI] = regs->edi; + env->regs[R_EBP] = regs->ebp; + env->regs[R_ESP] = regs->esp; + env->eip = regs->eip; + + /* linux interrupt setup */ + env->idt.base = h2g(idt_table); + env->idt.limit = sizeof(idt_table) - 1; + set_idt(0, 0); + set_idt(1, 0); + set_idt(2, 0); + set_idt(3, 3); + set_idt(4, 3); + set_idt(5, 3); + set_idt(6, 0); + set_idt(7, 0); + set_idt(8, 0); + set_idt(9, 0); + set_idt(10, 0); + set_idt(11, 0); + set_idt(12, 0); + set_idt(13, 0); + set_idt(14, 0); + set_idt(15, 0); + set_idt(16, 0); + set_idt(17, 0); + set_idt(18, 0); + set_idt(19, 0); + set_idt(0x80, 3); + + /* linux segment setup */ + env->gdt.base = h2g(gdt_table); + env->gdt.limit = sizeof(gdt_table) - 1; + write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); + write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); + cpu_x86_load_seg(env, R_CS, __USER_CS); + cpu_x86_load_seg(env, R_DS, __USER_DS); + cpu_x86_load_seg(env, R_ES, __USER_DS); + cpu_x86_load_seg(env, R_SS, __USER_DS); + cpu_x86_load_seg(env, R_FS, __USER_DS); + cpu_x86_load_seg(env, R_GS, __USER_DS); + +#elif defined(TARGET_ARM) + { + int i; + cpu_arm_set_model(env, ARM_CPUID_ARM1026); + cpsr_write(env, regs->uregs[16], 0xffffffff); + for(i = 0; i < 16; i++) { + env->regs[i] = regs->uregs[i]; + } + ts->stack_base = info->start_stack; + ts->heap_base = info->brk; + /* This will be filled in on the first SYS_HEAPINFO call. */ + ts->heap_limit = 0; + } +#elif defined(TARGET_SPARC) + { + int i; + env->pc = regs->pc; + env->npc = regs->npc; + env->y = regs->y; + for(i = 0; i < 8; i++) + env->gregs[i] = regs->u_regs[i]; + for(i = 0; i < 8; i++) + env->regwptr[i] = regs->u_regs[i + 8]; + } +#elif defined(TARGET_PPC) + { + ppc_def_t *def; + int i; + + /* Choose and initialise CPU */ + /* XXX: CPU model (or PVR) should be provided on command line */ + // ppc_find_by_name("750gx", &def); + // ppc_find_by_name("750fx", &def); + // ppc_find_by_name("750p", &def); + ppc_find_by_name("750", &def); + // ppc_find_by_name("G3", &def); + // ppc_find_by_name("604r", &def); + // ppc_find_by_name("604e", &def); + // ppc_find_by_name("604", &def); + if (def == NULL) { + cpu_abort(env, + "Unable to find PowerPC CPU definition\n"); + } + cpu_ppc_register(env, def); + + for (i = 0; i < 32; i++) { + if (i != 12 && i != 6 && i != 13) + env->msr[i] = (regs->msr >> i) & 1; + } + env->nip = regs->nip; + for(i = 0; i < 32; i++) { + env->gpr[i] = regs->gpr[i]; + } + } +#elif defined(TARGET_MIPS) + { + int i; + + for(i = 0; i < 32; i++) { + env->gpr[i] = regs->regs[i]; + } + env->PC = regs->cp0_epc; +#ifdef MIPS_USES_FPU + env->CP0_Status |= (1 << CP0St_CU1); +#endif + } +#elif defined(TARGET_SH4) + { + int i; + + for(i = 0; i < 16; i++) { + env->gregs[i] = regs->regs[i]; + } + env->pc = regs->pc; + } +#else +#error unsupported target CPU +#endif + + if (gdbstub_port) { + gdbserver_start (gdbstub_port); + gdb_handlesig(env, 0); + } + cpu_loop(env); + /* never exits */ + return 0; +} diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h new file mode 100644 index 0000000..4b3c7d6 --- /dev/null +++ b/linux-user/mips/syscall.h @@ -0,0 +1,23 @@ + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct target_pt_regs { +#if 1 + /* Pad bytes for argument save space on the stack. */ + target_ulong pad0[6]; +#endif + + /* Saved main processor registers. */ + target_ulong regs[32]; + + /* Saved special registers. */ + target_ulong cp0_status; + target_ulong lo; + target_ulong hi; + target_ulong cp0_badvaddr; + target_ulong cp0_cause; + target_ulong cp0_epc; +}; + +#define UNAME_MACHINE "mips" diff --git a/linux-user/mips/syscall_nr.h b/linux-user/mips/syscall_nr.h new file mode 100644 index 0000000..3593e65 --- /dev/null +++ b/linux-user/mips/syscall_nr.h @@ -0,0 +1,288 @@ +/* + * Linux o32 style syscalls are in the range from 4000 to 4999. + */ +#define TARGET_NR_Linux 4000 +#define TARGET_NR_syscall (TARGET_NR_Linux + 0) +#define TARGET_NR_exit (TARGET_NR_Linux + 1) +#define TARGET_NR_fork (TARGET_NR_Linux + 2) +#define TARGET_NR_read (TARGET_NR_Linux + 3) +#define TARGET_NR_write (TARGET_NR_Linux + 4) +#define TARGET_NR_open (TARGET_NR_Linux + 5) +#define TARGET_NR_close (TARGET_NR_Linux + 6) +#define TARGET_NR_waitpid (TARGET_NR_Linux + 7) +#define TARGET_NR_creat (TARGET_NR_Linux + 8) +#define TARGET_NR_link (TARGET_NR_Linux + 9) +#define TARGET_NR_unlink (TARGET_NR_Linux + 10) +#define TARGET_NR_execve (TARGET_NR_Linux + 11) +#define TARGET_NR_chdir (TARGET_NR_Linux + 12) +#define TARGET_NR_time (TARGET_NR_Linux + 13) +#define TARGET_NR_mknod (TARGET_NR_Linux + 14) +#define TARGET_NR_chmod (TARGET_NR_Linux + 15) +#define TARGET_NR_lchown32 (TARGET_NR_Linux + 16) +#define TARGET_NR_break (TARGET_NR_Linux + 17) +#define TARGET_NR_unused18 (TARGET_NR_Linux + 18) +#define TARGET_NR_lseek (TARGET_NR_Linux + 19) +#define TARGET_NR_getpid (TARGET_NR_Linux + 20) +#define TARGET_NR_mount (TARGET_NR_Linux + 21) +#define TARGET_NR_umount (TARGET_NR_Linux + 22) +#define TARGET_NR_setuid32 (TARGET_NR_Linux + 23) +#define TARGET_NR_getuid32 (TARGET_NR_Linux + 24) +#define TARGET_NR_stime (TARGET_NR_Linux + 25) +#define TARGET_NR_ptrace (TARGET_NR_Linux + 26) +#define TARGET_NR_alarm (TARGET_NR_Linux + 27) +#define TARGET_NR_unused28 (TARGET_NR_Linux + 28) +#define TARGET_NR_pause (TARGET_NR_Linux + 29) +#define TARGET_NR_utime (TARGET_NR_Linux + 30) +#define TARGET_NR_stty (TARGET_NR_Linux + 31) +#define TARGET_NR_gtty (TARGET_NR_Linux + 32) +#define TARGET_NR_access (TARGET_NR_Linux + 33) +#define TARGET_NR_nice (TARGET_NR_Linux + 34) +#define TARGET_NR_ftime (TARGET_NR_Linux + 35) +#define TARGET_NR_sync (TARGET_NR_Linux + 36) +#define TARGET_NR_kill (TARGET_NR_Linux + 37) +#define TARGET_NR_rename (TARGET_NR_Linux + 38) +#define TARGET_NR_mkdir (TARGET_NR_Linux + 39) +#define TARGET_NR_rmdir (TARGET_NR_Linux + 40) +#define TARGET_NR_dup (TARGET_NR_Linux + 41) +#define TARGET_NR_pipe (TARGET_NR_Linux + 42) +#define TARGET_NR_times (TARGET_NR_Linux + 43) +#define TARGET_NR_prof (TARGET_NR_Linux + 44) +#define TARGET_NR_brk (TARGET_NR_Linux + 45) +#define TARGET_NR_setgid32 (TARGET_NR_Linux + 46) +#define TARGET_NR_getgid32 (TARGET_NR_Linux + 47) +#define TARGET_NR_signal (TARGET_NR_Linux + 48) +#define TARGET_NR_geteuid32 (TARGET_NR_Linux + 49) +#define TARGET_NR_getegid32 (TARGET_NR_Linux + 50) +#define TARGET_NR_acct (TARGET_NR_Linux + 51) +#define TARGET_NR_umount2 (TARGET_NR_Linux + 52) +#define TARGET_NR_lock (TARGET_NR_Linux + 53) +#define TARGET_NR_ioctl (TARGET_NR_Linux + 54) +#define TARGET_NR_fcntl (TARGET_NR_Linux + 55) +#define TARGET_NR_mpx (TARGET_NR_Linux + 56) +#define TARGET_NR_setpgid (TARGET_NR_Linux + 57) +#define TARGET_NR_ulimit (TARGET_NR_Linux + 58) +#define TARGET_NR_unused59 (TARGET_NR_Linux + 59) +#define TARGET_NR_umask (TARGET_NR_Linux + 60) +#define TARGET_NR_chroot (TARGET_NR_Linux + 61) +#define TARGET_NR_ustat (TARGET_NR_Linux + 62) +#define TARGET_NR_dup2 (TARGET_NR_Linux + 63) +#define TARGET_NR_getppid (TARGET_NR_Linux + 64) +#define TARGET_NR_getpgrp (TARGET_NR_Linux + 65) +#define TARGET_NR_setsid (TARGET_NR_Linux + 66) +#define TARGET_NR_sigaction (TARGET_NR_Linux + 67) +#define TARGET_NR_sgetmask (TARGET_NR_Linux + 68) +#define TARGET_NR_ssetmask (TARGET_NR_Linux + 69) +#define TARGET_NR_setreuid32 (TARGET_NR_Linux + 70) +#define TARGET_NR_setregid32 (TARGET_NR_Linux + 71) +#define TARGET_NR_sigsuspend (TARGET_NR_Linux + 72) +#define TARGET_NR_sigpending (TARGET_NR_Linux + 73) +#define TARGET_NR_sethostname (TARGET_NR_Linux + 74) +#define TARGET_NR_setrlimit (TARGET_NR_Linux + 75) +#define TARGET_NR_getrlimit (TARGET_NR_Linux + 76) +#define TARGET_NR_getrusage (TARGET_NR_Linux + 77) +#define TARGET_NR_gettimeofday (TARGET_NR_Linux + 78) +#define TARGET_NR_settimeofday (TARGET_NR_Linux + 79) +#define TARGET_NR_getgroups32 (TARGET_NR_Linux + 80) +#define TARGET_NR_setgroups32 (TARGET_NR_Linux + 81) +#define TARGET_NR_reserved82 (TARGET_NR_Linux + 82) +#define TARGET_NR_symlink (TARGET_NR_Linux + 83) +#define TARGET_NR_unused84 (TARGET_NR_Linux + 84) +#define TARGET_NR_readlink (TARGET_NR_Linux + 85) +#define TARGET_NR_uselib (TARGET_NR_Linux + 86) +#define TARGET_NR_swapon (TARGET_NR_Linux + 87) +#define TARGET_NR_reboot (TARGET_NR_Linux + 88) +#define TARGET_NR_readdir (TARGET_NR_Linux + 89) +#define TARGET_NR_mmap (TARGET_NR_Linux + 90) +#define TARGET_NR_munmap (TARGET_NR_Linux + 91) +#define TARGET_NR_truncate (TARGET_NR_Linux + 92) +#define TARGET_NR_ftruncate (TARGET_NR_Linux + 93) +#define TARGET_NR_fchmod (TARGET_NR_Linux + 94) +#define TARGET_NR_fchown32 (TARGET_NR_Linux + 95) +#define TARGET_NR_getpriority (TARGET_NR_Linux + 96) +#define TARGET_NR_setpriority (TARGET_NR_Linux + 97) +#define TARGET_NR_profil (TARGET_NR_Linux + 98) +#define TARGET_NR_statfs (TARGET_NR_Linux + 99) +#define TARGET_NR_fstatfs (TARGET_NR_Linux + 100) +#define TARGET_NR_ioperm (TARGET_NR_Linux + 101) +#define TARGET_NR_socketcall (TARGET_NR_Linux + 102) +#define TARGET_NR_syslog (TARGET_NR_Linux + 103) +#define TARGET_NR_setitimer (TARGET_NR_Linux + 104) +#define TARGET_NR_getitimer (TARGET_NR_Linux + 105) +#define TARGET_NR_stat (TARGET_NR_Linux + 106) +#define TARGET_NR_lstat (TARGET_NR_Linux + 107) +#define TARGET_NR_fstat (TARGET_NR_Linux + 108) +#define TARGET_NR_unused109 (TARGET_NR_Linux + 109) +#define TARGET_NR_iopl (TARGET_NR_Linux + 110) +#define TARGET_NR_vhangup (TARGET_NR_Linux + 111) +#define TARGET_NR_idle (TARGET_NR_Linux + 112) +#define TARGET_NR_vm86 (TARGET_NR_Linux + 113) +#define TARGET_NR_wait4 (TARGET_NR_Linux + 114) +#define TARGET_NR_swapoff (TARGET_NR_Linux + 115) +#define TARGET_NR_sysinfo (TARGET_NR_Linux + 116) +#define TARGET_NR_ipc (TARGET_NR_Linux + 117) +#define TARGET_NR_fsync (TARGET_NR_Linux + 118) +#define TARGET_NR_sigreturn (TARGET_NR_Linux + 119) +#define TARGET_NR_clone (TARGET_NR_Linux + 120) +#define TARGET_NR_setdomainname (TARGET_NR_Linux + 121) +#define TARGET_NR_uname (TARGET_NR_Linux + 122) +#define TARGET_NR_modify_ldt (TARGET_NR_Linux + 123) +#define TARGET_NR_adjtimex (TARGET_NR_Linux + 124) +#define TARGET_NR_mprotect (TARGET_NR_Linux + 125) +#define TARGET_NR_sigprocmask (TARGET_NR_Linux + 126) +#define TARGET_NR_create_module (TARGET_NR_Linux + 127) +#define TARGET_NR_init_module (TARGET_NR_Linux + 128) +#define TARGET_NR_delete_module (TARGET_NR_Linux + 129) +#define TARGET_NR_get_kernel_syms (TARGET_NR_Linux + 130) +#define TARGET_NR_quotactl (TARGET_NR_Linux + 131) +#define TARGET_NR_getpgid (TARGET_NR_Linux + 132) +#define TARGET_NR_fchdir (TARGET_NR_Linux + 133) +#define TARGET_NR_bdflush (TARGET_NR_Linux + 134) +#define TARGET_NR_sysfs (TARGET_NR_Linux + 135) +#define TARGET_NR_personality (TARGET_NR_Linux + 136) +#define TARGET_NR_afs_syscall (TARGET_NR_Linux + 137) /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid32 (TARGET_NR_Linux + 138) +#define TARGET_NR_setfsgid32 (TARGET_NR_Linux + 139) +#define TARGET_NR__llseek (TARGET_NR_Linux + 140) +#define TARGET_NR_getdents (TARGET_NR_Linux + 141) +#define TARGET_NR__newselect (TARGET_NR_Linux + 142) +#define TARGET_NR_flock (TARGET_NR_Linux + 143) +#define TARGET_NR_msync (TARGET_NR_Linux + 144) +#define TARGET_NR_readv (TARGET_NR_Linux + 145) +#define TARGET_NR_writev (TARGET_NR_Linux + 146) +#define TARGET_NR_cacheflush (TARGET_NR_Linux + 147) +#define TARGET_NR_cachectl (TARGET_NR_Linux + 148) +#define TARGET_NR_sysmips (TARGET_NR_Linux + 149) +#define TARGET_NR_unused150 (TARGET_NR_Linux + 150) +#define TARGET_NR_getsid (TARGET_NR_Linux + 151) +#define TARGET_NR_fdatasync (TARGET_NR_Linux + 152) +#define TARGET_NR__sysctl (TARGET_NR_Linux + 153) +#define TARGET_NR_mlock (TARGET_NR_Linux + 154) +#define TARGET_NR_munlock (TARGET_NR_Linux + 155) +#define TARGET_NR_mlockall (TARGET_NR_Linux + 156) +#define TARGET_NR_munlockall (TARGET_NR_Linux + 157) +#define TARGET_NR_sched_setparam (TARGET_NR_Linux + 158) +#define TARGET_NR_sched_getparam (TARGET_NR_Linux + 159) +#define TARGET_NR_sched_setscheduler (TARGET_NR_Linux + 160) +#define TARGET_NR_sched_getscheduler (TARGET_NR_Linux + 161) +#define TARGET_NR_sched_yield (TARGET_NR_Linux + 162) +#define TARGET_NR_sched_get_priority_max (TARGET_NR_Linux + 163) +#define TARGET_NR_sched_get_priority_min (TARGET_NR_Linux + 164) +#define TARGET_NR_sched_rr_get_interval (TARGET_NR_Linux + 165) +#define TARGET_NR_nanosleep (TARGET_NR_Linux + 166) +#define TARGET_NR_mremap (TARGET_NR_Linux + 167) +#define TARGET_NR_accept (TARGET_NR_Linux + 168) +#define TARGET_NR_bind (TARGET_NR_Linux + 169) +#define TARGET_NR_connect (TARGET_NR_Linux + 170) +#define TARGET_NR_getpeername (TARGET_NR_Linux + 171) +#define TARGET_NR_getsockname (TARGET_NR_Linux + 172) +#define TARGET_NR_getsockopt (TARGET_NR_Linux + 173) +#define TARGET_NR_listen (TARGET_NR_Linux + 174) +#define TARGET_NR_recv (TARGET_NR_Linux + 175) +#define TARGET_NR_recvfrom (TARGET_NR_Linux + 176) +#define TARGET_NR_recvmsg (TARGET_NR_Linux + 177) +#define TARGET_NR_send (TARGET_NR_Linux + 178) +#define TARGET_NR_sendmsg (TARGET_NR_Linux + 179) +#define TARGET_NR_sendto (TARGET_NR_Linux + 180) +#define TARGET_NR_setsockopt (TARGET_NR_Linux + 181) +#define TARGET_NR_shutdown (TARGET_NR_Linux + 182) +#define TARGET_NR_socket (TARGET_NR_Linux + 183) +#define TARGET_NR_socketpair (TARGET_NR_Linux + 184) +#define TARGET_NR_setresuid32 (TARGET_NR_Linux + 185) +#define TARGET_NR_getresuid32 (TARGET_NR_Linux + 186) +#define TARGET_NR_query_module (TARGET_NR_Linux + 187) +#define TARGET_NR_poll (TARGET_NR_Linux + 188) +#define TARGET_NR_nfsservctl (TARGET_NR_Linux + 189) +#define TARGET_NR_setresgid32 (TARGET_NR_Linux + 190) +#define TARGET_NR_getresgid32 (TARGET_NR_Linux + 191) +#define TARGET_NR_prctl (TARGET_NR_Linux + 192) +#define TARGET_NR_rt_sigreturn (TARGET_NR_Linux + 193) +#define TARGET_NR_rt_sigaction (TARGET_NR_Linux + 194) +#define TARGET_NR_rt_sigprocmask (TARGET_NR_Linux + 195) +#define TARGET_NR_rt_sigpending (TARGET_NR_Linux + 196) +#define TARGET_NR_rt_sigtimedwait (TARGET_NR_Linux + 197) +#define TARGET_NR_rt_sigqueueinfo (TARGET_NR_Linux + 198) +#define TARGET_NR_rt_sigsuspend (TARGET_NR_Linux + 199) +#define TARGET_NR_pread64 (TARGET_NR_Linux + 200) +#define TARGET_NR_pwrite64 (TARGET_NR_Linux + 201) +#define TARGET_NR_chown32 (TARGET_NR_Linux + 202) +#define TARGET_NR_getcwd (TARGET_NR_Linux + 203) +#define TARGET_NR_capget (TARGET_NR_Linux + 204) +#define TARGET_NR_capset (TARGET_NR_Linux + 205) +#define TARGET_NR_sigaltstack (TARGET_NR_Linux + 206) +#define TARGET_NR_sendfile (TARGET_NR_Linux + 207) +#define TARGET_NR_getpmsg (TARGET_NR_Linux + 208) +#define TARGET_NR_putpmsg (TARGET_NR_Linux + 209) +#define TARGET_NR_mmap2 (TARGET_NR_Linux + 210) +#define TARGET_NR_truncate64 (TARGET_NR_Linux + 211) +#define TARGET_NR_ftruncate64 (TARGET_NR_Linux + 212) +#define TARGET_NR_stat64 (TARGET_NR_Linux + 213) +#define TARGET_NR_lstat64 (TARGET_NR_Linux + 214) +#define TARGET_NR_fstat64 (TARGET_NR_Linux + 215) +#define TARGET_NR_pivot_root (TARGET_NR_Linux + 216) +#define TARGET_NR_mincore (TARGET_NR_Linux + 217) +#define TARGET_NR_madvise (TARGET_NR_Linux + 218) +#define TARGET_NR_getdents64 (TARGET_NR_Linux + 219) +#define TARGET_NR_fcntl64 (TARGET_NR_Linux + 220) +#define TARGET_NR_reserved221 (TARGET_NR_Linux + 221) +#define TARGET_NR_gettid (TARGET_NR_Linux + 222) +#define TARGET_NR_readahead (TARGET_NR_Linux + 223) +#define TARGET_NR_setxattr (TARGET_NR_Linux + 224) +#define TARGET_NR_lsetxattr (TARGET_NR_Linux + 225) +#define TARGET_NR_fsetxattr (TARGET_NR_Linux + 226) +#define TARGET_NR_getxattr (TARGET_NR_Linux + 227) +#define TARGET_NR_lgetxattr (TARGET_NR_Linux + 228) +#define TARGET_NR_fgetxattr (TARGET_NR_Linux + 229) +#define TARGET_NR_listxattr (TARGET_NR_Linux + 230) +#define TARGET_NR_llistxattr (TARGET_NR_Linux + 231) +#define TARGET_NR_flistxattr (TARGET_NR_Linux + 232) +#define TARGET_NR_removexattr (TARGET_NR_Linux + 233) +#define TARGET_NR_lremovexattr (TARGET_NR_Linux + 234) +#define TARGET_NR_fremovexattr (TARGET_NR_Linux + 235) +#define TARGET_NR_tkill (TARGET_NR_Linux + 236) +#define TARGET_NR_sendfile64 (TARGET_NR_Linux + 237) +#define TARGET_NR_futex (TARGET_NR_Linux + 238) +#define TARGET_NR_sched_setaffinity (TARGET_NR_Linux + 239) +#define TARGET_NR_sched_getaffinity (TARGET_NR_Linux + 240) +#define TARGET_NR_io_setup (TARGET_NR_Linux + 241) +#define TARGET_NR_io_destroy (TARGET_NR_Linux + 242) +#define TARGET_NR_io_getevents (TARGET_NR_Linux + 243) +#define TARGET_NR_io_submit (TARGET_NR_Linux + 244) +#define TARGET_NR_io_cancel (TARGET_NR_Linux + 245) +#define TARGET_NR_exit_group (TARGET_NR_Linux + 246) +#define TARGET_NR_lookup_dcookie (TARGET_NR_Linux + 247) +#define TARGET_NR_epoll_create (TARGET_NR_Linux + 248) +#define TARGET_NR_epoll_ctl (TARGET_NR_Linux + 249) +#define TARGET_NR_epoll_wait (TARGET_NR_Linux + 250) +#define TARGET_NR_remap_file_pages (TARGET_NR_Linux + 251) +#define TARGET_NR_set_tid_address (TARGET_NR_Linux + 252) +#define TARGET_NR_restart_syscall (TARGET_NR_Linux + 253) +#define TARGET_NR_fadvise64 (TARGET_NR_Linux + 254) +#define TARGET_NR_statfs64 (TARGET_NR_Linux + 255) +#define TARGET_NR_fstatfs64 (TARGET_NR_Linux + 256) +#define TARGET_NR_timer_create (TARGET_NR_Linux + 257) +#define TARGET_NR_timer_settime (TARGET_NR_Linux + 258) +#define TARGET_NR_timer_gettime (TARGET_NR_Linux + 259) +#define TARGET_NR_timer_getoverrun (TARGET_NR_Linux + 260) +#define TARGET_NR_timer_delete (TARGET_NR_Linux + 261) +#define TARGET_NR_clock_settime (TARGET_NR_Linux + 262) +#define TARGET_NR_clock_gettime (TARGET_NR_Linux + 263) +#define TARGET_NR_clock_getres (TARGET_NR_Linux + 264) +#define TARGET_NR_clock_nanosleep (TARGET_NR_Linux + 265) +#define TARGET_NR_tgkill (TARGET_NR_Linux + 266) +#define TARGET_NR_utimes (TARGET_NR_Linux + 267) +#define TARGET_NR_mbind (TARGET_NR_Linux + 268) +#define TARGET_NR_get_mempolicy (TARGET_NR_Linux + 269) +#define TARGET_NR_set_mempolicy (TARGET_NR_Linux + 270) +#define TARGET_NR_mq_open (TARGET_NR_Linux + 271) +#define TARGET_NR_mq_unlink (TARGET_NR_Linux + 272) +#define TARGET_NR_mq_timedsend (TARGET_NR_Linux + 273) +#define TARGET_NR_mq_timedreceive (TARGET_NR_Linux + 274) +#define TARGET_NR_mq_notify (TARGET_NR_Linux + 275) +#define TARGET_NR_mq_getsetattr (TARGET_NR_Linux + 276) +#define TARGET_NR_vserver (TARGET_NR_Linux + 277) +#define TARGET_NR_waitid (TARGET_NR_Linux + 278) +/* #define TARGET_NR_sys_setaltroot (TARGET_NR_Linux + 279) */ +#define TARGET_NR_add_key (TARGET_NR_Linux + 280) +#define TARGET_NR_request_key (TARGET_NR_Linux + 281) +#define TARGET_NR_keyctl (TARGET_NR_Linux + 282) + diff --git a/linux-user/mips/termbits.h b/linux-user/mips/termbits.h new file mode 100644 index 0000000..fea7940 --- /dev/null +++ b/linux-user/mips/termbits.h @@ -0,0 +1,229 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 23 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* ioctls */ + +#define TARGET_TCGETA 0x5401 +#define TARGET_TCSETA 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */ +#define TARGET_TCSETAW 0x5403 +#define TARGET_TCSETAF 0x5404 + +#define TARGET_TCSBRK 0x5405 +#define TARGET_TCXONC 0x5406 +#define TARGET_TCFLSH 0x5407 + +#define TARGET_TCGETS 0x540d +#define TARGET_TCSETS 0x540e +#define TARGET_TCSETSW 0x540f +#define TARGET_TCSETSF 0x5410 + +#define TARGET_TIOCEXCL 0x740d /* set exclusive use of tty */ +#define TARGET_TIOCNXCL 0x740e /* reset exclusive use of tty */ +#define TARGET_TIOCOUTQ 0x7472 /* output queue size */ +#define TARGET_TIOCSTI 0x5472 /* simulate terminal input */ +#define TARGET_TIOCMGET 0x741d /* get all modem bits */ +#define TARGET_TIOCMBIS 0x741b /* bis modem bits */ +#define TARGET_TIOCMBIC 0x741c /* bic modem bits */ +#define TARGET_TIOCMSET 0x741a /* set all modem bits */ +#define TARGET_TIOCPKT 0x5470 /* pty: set/clear packet mode */ +#define TARGET_TIOCPKT_DATA 0x00 /* data packet */ +#define TARGET_TIOCPKT_FLUSHREAD 0x01 /* flush packet */ +#define TARGET_TIOCPKT_FLUSHWRITE 0x02 /* flush packet */ +#define TARGET_TIOCPKT_STOP 0x04 /* stop output */ +#define TARGET_TIOCPKT_START 0x08 /* start output */ +#define TARGET_TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */ +#define TARGET_TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */ +/* #define TIOCPKT_IOCTL 0x40 state change of pty driver */ +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) /* set window size */ +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) /* get window size */ +#define TARGET_TIOCNOTTY 0x5471 /* void tty association */ +#define TARGET_TIOCSETD 0x7401 +#define TARGET_TIOCGETD 0x7400 + +#define TARGET_FIOCLEX 0x6601 +#define TARGET_FIONCLEX 0x6602 +#define TARGET_FIOASYNC 0x667d +#define TARGET_FIONBIO 0x667e +#define TARGET_FIOQSIZE 0x667f + +#define TARGET_TIOCGLTC 0x7474 /* get special local chars */ +#define TARGET_TIOCSLTC 0x7475 /* set special local chars */ +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) /* set pgrp of tty */ +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) /* get pgrp of tty */ +#define TARGET_TIOCCONS TARGET_IOW('t', 120, int) /* become virtual console */ + +#define TARGET_FIONREAD 0x467f +#define TARGET_TIOCINQ TARGET_FIONREAD + +#define TARGET_TIOCGETP 0x7408 +#define TARGET_TIOCSETP 0x7409 +#define TARGET_TIOCSETN 0x740a /* TIOCSETP wo flush */ + +/* #define TARGET_TIOCSETA TARGET_IOW('t', 20, struct termios) set termios struct */ +/* #define TARGET_TIOCSETAW TARGET_IOW('t', 21, struct termios) drain output, set */ +/* #define TARGET_TIOCSETAF TARGET_IOW('t', 22, struct termios) drn out, fls in, set */ +/* #define TARGET_TIOCGETD TARGET_IOR('t', 26, int) get line discipline */ +/* #define TARGET_TIOCSETD TARGET_IOW('t', 27, int) set line discipline */ + /* 127-124 compat */ + +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x7416 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +/* I hope the range from 0x5480 on is free ... */ +#define TARGET_TIOCSCTTY 0x5480 /* become controlling tty */ +#define TARGET_TIOCGSOFTCAR 0x5481 +#define TARGET_TIOCSSOFTCAR 0x5482 +#define TARGET_TIOCLINUX 0x5483 +#define TARGET_TIOCGSERIAL 0x5484 +#define TARGET_TIOCSSERIAL 0x5485 +#define TARGET_TCSBRKP 0x5486 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCSERCONFIG 0x5488 +#define TARGET_TIOCSERGWILD 0x5489 +#define TARGET_TIOCSERSWILD 0x548a +#define TARGET_TIOCGLCKTRMIOS 0x548b +#define TARGET_TIOCSLCKTRMIOS 0x548c +#define TARGET_TIOCSERGSTRUCT 0x548d /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x548e /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x548f /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x5490 /* Set multiport config */ +#define TARGET_TIOCMIWAIT 0x5491 /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x5492 /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x5493 /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x5494 /* Set Hayes ESP configuration */ diff --git a/linux-user/mmap.c b/linux-user/mmap.c new file mode 100644 index 0000000..0c90625 --- /dev/null +++ b/linux-user/mmap.c @@ -0,0 +1,417 @@ +/* + * mmap support for qemu + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/mman.h> + +#include "qemu.h" + +//#define DEBUG_MMAP + +/* NOTE: all the constants are the HOST ones, but addresses are target. */ +int target_mprotect(target_ulong start, target_ulong len, int prot) +{ + target_ulong end, host_start, host_end, addr; + int prot1, ret; + +#ifdef DEBUG_MMAP + printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len, + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-'); +#endif + + if ((start & ~TARGET_PAGE_MASK) != 0) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + end = start + len; + if (end < start) + return -EINVAL; + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return -EINVAL; + if (len == 0) + return 0; + + host_start = start & qemu_host_page_mask; + host_end = HOST_PAGE_ALIGN(end); + if (start > host_start) { + /* handle host page containing start */ + prot1 = prot; + for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + if (host_end == host_start + qemu_host_page_size) { + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + end = host_end; + } + ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS); + if (ret != 0) + return ret; + host_start += qemu_host_page_size; + } + if (end < host_end) { + prot1 = prot; + for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + prot1 |= page_get_flags(addr); + } + ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size, + prot1 & PAGE_BITS); + if (ret != 0) + return ret; + host_end -= qemu_host_page_size; + } + + /* handle the pages in the middle */ + if (host_start < host_end) { + ret = mprotect(g2h(host_start), host_end - host_start, prot); + if (ret != 0) + return ret; + } + page_set_flags(start, start + len, prot | PAGE_VALID); + return 0; +} + +/* map an incomplete host page */ +static int mmap_frag(target_ulong real_start, + target_ulong start, target_ulong end, + int prot, int flags, int fd, target_ulong offset) +{ + target_ulong real_end, ret, addr; + void *host_start; + int prot1, prot_new; + + real_end = real_start + qemu_host_page_size; + host_start = g2h(real_start); + + /* get the protection of the target pages outside the mapping */ + prot1 = 0; + for(addr = real_start; addr < real_end; addr++) { + if (addr < start || addr >= end) + prot1 |= page_get_flags(addr); + } + + if (prot1 == 0) { + /* no page was there, so we allocate one */ + ret = (long)mmap(host_start, qemu_host_page_size, prot, + flags | MAP_ANONYMOUS, -1, 0); + if (ret == -1) + return ret; + prot1 = prot; + } + prot1 &= PAGE_BITS; + + prot_new = prot | prot1; + if (!(flags & MAP_ANONYMOUS)) { + /* msync() won't work here, so we return an error if write is + possible while it is a shared mapping */ + if ((flags & MAP_TYPE) == MAP_SHARED && + (prot & PROT_WRITE)) + return -EINVAL; + + /* adjust protection to be able to read */ + if (!(prot1 & PROT_WRITE)) + mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE); + + /* read the corresponding file data */ + pread(fd, g2h(start), end - start, offset); + + /* put final protection */ + if (prot_new != (prot1 | PROT_WRITE)) + mprotect(host_start, qemu_host_page_size, prot_new); + } else { + /* just update the protection */ + if (prot_new != prot1) { + mprotect(host_start, qemu_host_page_size, prot_new); + } + } + return 0; +} + +/* NOTE: all the constants are the HOST ones */ +long target_mmap(target_ulong start, target_ulong len, int prot, + int flags, int fd, target_ulong offset) +{ + target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; + long host_start; +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ + defined(__ia64) + static target_ulong last_start = 0x40000000; +#elif defined(__CYGWIN__) + /* Cygwin doesn't have a whole lot of address space. */ + static target_ulong last_start = 0x18000000; +#endif + +#ifdef DEBUG_MMAP + { + printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=", + start, len, + prot & PROT_READ ? 'r' : '-', + prot & PROT_WRITE ? 'w' : '-', + prot & PROT_EXEC ? 'x' : '-'); + if (flags & MAP_FIXED) + printf("MAP_FIXED "); + if (flags & MAP_ANONYMOUS) + printf("MAP_ANON "); + switch(flags & MAP_TYPE) { + case MAP_PRIVATE: + printf("MAP_PRIVATE "); + break; + case MAP_SHARED: + printf("MAP_SHARED "); + break; + default: + printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE); + break; + } + printf("fd=%d offset=%lx\n", fd, offset); + } +#endif + + if (offset & ~TARGET_PAGE_MASK) { + errno = EINVAL; + return -1; + } + + len = TARGET_PAGE_ALIGN(len); + if (len == 0) + return start; + real_start = start & qemu_host_page_mask; + + if (!(flags & MAP_FIXED)) { +#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ + defined(__ia64) || defined(__CYGWIN__) + /* tell the kenel to search at the same place as i386 */ + if (real_start == 0) { + real_start = last_start; + last_start += HOST_PAGE_ALIGN(len); + } +#endif + if (qemu_host_page_size != qemu_real_host_page_size) { + /* NOTE: this code is only for debugging with '-p' option */ + /* ??? Can also occur when TARGET_PAGE_SIZE > host page size. */ + /* reserve a memory area */ + /* ??? This needs fixing for remapping. */ +abort(); + host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE; + real_start = (long)mmap(g2h(real_start), host_len, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (real_start == -1) + return real_start; + real_end = real_start + host_len; + start = HOST_PAGE_ALIGN(real_start); + end = start + HOST_PAGE_ALIGN(len); + if (start > real_start) + munmap((void *)real_start, start - real_start); + if (end < real_end) + munmap((void *)end, real_end - end); + /* use it as a fixed mapping */ + flags |= MAP_FIXED; + } else { + /* if not fixed, no need to do anything */ + host_offset = offset & qemu_host_page_mask; + host_len = len + offset - host_offset; + host_start = (long)mmap(real_start ? g2h(real_start) : NULL, + host_len, prot, flags, fd, host_offset); + if (host_start == -1) + return host_start; + /* update start so that it points to the file position at 'offset' */ + if (!(flags & MAP_ANONYMOUS)) + host_start += offset - host_offset; + start = h2g(host_start); + goto the_end1; + } + } + + if (start & ~TARGET_PAGE_MASK) { + errno = EINVAL; + return -1; + } + end = start + len; + real_end = HOST_PAGE_ALIGN(end); + + /* worst case: we cannot map the file because the offset is not + aligned, so we read it */ + if (!(flags & MAP_ANONYMOUS) && + (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { + /* msync() won't work here, so we return an error if write is + possible while it is a shared mapping */ + if ((flags & MAP_TYPE) == MAP_SHARED && + (prot & PROT_WRITE)) { + errno = EINVAL; + return -1; + } + retaddr = target_mmap(start, len, prot | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (retaddr == -1) + return retaddr; + pread(fd, g2h(start), len, offset); + if (!(prot & PROT_WRITE)) { + ret = target_mprotect(start, len, prot); + if (ret != 0) + return ret; + } + goto the_end; + } + + /* handle the start of the mapping */ + if (start > real_start) { + if (real_end == real_start + qemu_host_page_size) { + /* one single host page */ + ret = mmap_frag(real_start, start, end, + prot, flags, fd, offset); + if (ret == -1) + return ret; + goto the_end1; + } + ret = mmap_frag(real_start, start, real_start + qemu_host_page_size, + prot, flags, fd, offset); + if (ret == -1) + return ret; + real_start += qemu_host_page_size; + } + /* handle the end of the mapping */ + if (end < real_end) { + ret = mmap_frag(real_end - qemu_host_page_size, + real_end - qemu_host_page_size, real_end, + prot, flags, fd, + offset + real_end - qemu_host_page_size - start); + if (ret == -1) + return ret; + real_end -= qemu_host_page_size; + } + + /* map the middle (easier) */ + if (real_start < real_end) { + unsigned long offset1; + if (flags & MAP_ANONYMOUS) + offset1 = 0; + else + offset1 = offset + real_start - start; + ret = (long)mmap(g2h(real_start), real_end - real_start, + prot, flags, fd, offset1); + if (ret == -1) + return ret; + } + the_end1: + page_set_flags(start, start + len, prot | PAGE_VALID); + the_end: +#ifdef DEBUG_MMAP + printf("ret=0x%lx\n", (long)start); + page_dump(stdout); + printf("\n"); +#endif + return start; +} + +int target_munmap(target_ulong start, target_ulong len) +{ + target_ulong end, real_start, real_end, addr; + int prot, ret; + +#ifdef DEBUG_MMAP + printf("munmap: start=0x%lx len=0x%lx\n", start, len); +#endif + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + if (len == 0) + return -EINVAL; + end = start + len; + real_start = start & qemu_host_page_mask; + real_end = HOST_PAGE_ALIGN(end); + + if (start > real_start) { + /* handle host page containing start */ + prot = 0; + for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + if (real_end == real_start + qemu_host_page_size) { + for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + end = real_end; + } + if (prot != 0) + real_start += qemu_host_page_size; + } + if (end < real_end) { + prot = 0; + for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { + prot |= page_get_flags(addr); + } + if (prot != 0) + real_end -= qemu_host_page_size; + } + + /* unmap what we can */ + if (real_start < real_end) { + ret = munmap((void *)real_start, real_end - real_start); + if (ret != 0) + return ret; + } + + page_set_flags(start, start + len, 0); + return 0; +} + +/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED + blocks which have been allocated starting on a host page */ +long target_mremap(target_ulong old_addr, target_ulong old_size, + target_ulong new_size, unsigned long flags, + target_ulong new_addr) +{ + int prot; + + /* XXX: use 5 args syscall */ + new_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags); + if (new_addr == -1) + return new_addr; + new_addr = h2g(new_addr); + prot = page_get_flags(old_addr); + page_set_flags(old_addr, old_addr + old_size, 0); + page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); + return new_addr; +} + +int target_msync(target_ulong start, target_ulong len, int flags) +{ + target_ulong end; + + if (start & ~TARGET_PAGE_MASK) + return -EINVAL; + len = TARGET_PAGE_ALIGN(len); + end = start + len; + if (end < start) + return -EINVAL; + if (end == start) + return 0; + + start &= qemu_host_page_mask; + return msync(g2h(start), end - start, flags); +} + diff --git a/linux-user/path.c b/linux-user/path.c new file mode 100644 index 0000000..7680970 --- /dev/null +++ b/linux-user/path.c @@ -0,0 +1,147 @@ +/* Code to mangle pathnames into those matching a given prefix. + eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so"); + + The assumption is that this area does not change. +*/ +#include <sys/types.h> +#include <dirent.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include "qemu.h" + +struct pathelem +{ + /* Name of this, eg. lib */ + char *name; + /* Full path name, eg. /usr/gnemul/x86-linux/lib. */ + char *pathname; + struct pathelem *parent; + /* Children */ + unsigned int num_entries; + struct pathelem *entries[0]; +}; + +static struct pathelem *base; + +/* First N chars of S1 match S2, and S2 is N chars long. */ +static int strneq(const char *s1, unsigned int n, const char *s2) +{ + unsigned int i; + + for (i = 0; i < n; i++) + if (s1[i] != s2[i]) + return 0; + return s2[i] == 0; +} + +static struct pathelem *add_entry(struct pathelem *root, const char *name); + +static struct pathelem *new_entry(const char *root, + struct pathelem *parent, + const char *name) +{ + struct pathelem *new = malloc(sizeof(*new)); + new->name = strdup(name); + asprintf(&new->pathname, "%s/%s", root, name); + new->num_entries = 0; + return new; +} + +#define streq(a,b) (strcmp((a), (b)) == 0) + +static struct pathelem *add_dir_maybe(struct pathelem *path) +{ + DIR *dir; + + if ((dir = opendir(path->pathname)) != NULL) { + struct dirent *dirent; + + while ((dirent = readdir(dir)) != NULL) { + if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){ + path = add_entry(path, dirent->d_name); + } + } + closedir(dir); + } + return path; +} + +static struct pathelem *add_entry(struct pathelem *root, const char *name) +{ + root->num_entries++; + + root = realloc(root, sizeof(*root) + + sizeof(root->entries[0])*root->num_entries); + + root->entries[root->num_entries-1] = new_entry(root->pathname, root, name); + root->entries[root->num_entries-1] + = add_dir_maybe(root->entries[root->num_entries-1]); + return root; +} + +/* This needs to be done after tree is stabalized (ie. no more reallocs!). */ +static void set_parents(struct pathelem *child, struct pathelem *parent) +{ + unsigned int i; + + child->parent = parent; + for (i = 0; i < child->num_entries; i++) + set_parents(child->entries[i], child); +} + +void init_paths(const char *prefix) +{ + if (prefix[0] != '/' || + prefix[0] == '\0' || + !strcmp(prefix, "/")) + return; + + base = new_entry("", NULL, prefix+1); + base = add_dir_maybe(base); + if (base->num_entries == 0) { + free (base); + base = NULL; + } else { + set_parents(base, base); + } +} + +/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */ +static const char * +follow_path(const struct pathelem *cursor, const char *name) +{ + unsigned int i, namelen; + + name += strspn(name, "/"); + namelen = strcspn(name, "/"); + + if (namelen == 0) + return cursor->pathname; + + if (strneq(name, namelen, "..")) + return follow_path(cursor->parent, name + namelen); + + if (strneq(name, namelen, ".")) + return follow_path(cursor, name + namelen); + + for (i = 0; i < cursor->num_entries; i++) + if (strneq(name, namelen, cursor->entries[i]->name)) + return follow_path(cursor->entries[i], name + namelen); + + /* Not found */ + return NULL; +} + +/* Look for path in emulation dir, otherwise return name. */ +const char *path(const char *name) +{ + /* Only do absolute paths: quick and dirty, but should mostly be OK. + Could do relative by tracking cwd. */ + if (!base || name[0] != '/') + return name; + + return follow_path(base, name) ?: name; +} diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h new file mode 100644 index 0000000..eea8a7c --- /dev/null +++ b/linux-user/ppc/syscall.h @@ -0,0 +1,130 @@ +/* + * PPC emulation for qemu: syscall definitions. + * + * Copyright (c) 2003 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* XXX: ABSOLUTELY BUGGY: + * for now, this is quite just a cut-and-paste from i386 target... + */ + +/* default linux values for the selectors */ +#define __USER_DS (1) + +struct target_pt_regs { + unsigned long gpr[32]; + unsigned long nip; + unsigned long msr; + unsigned long orig_gpr3; /* Used for restarting system calls */ + unsigned long ctr; + unsigned long link; + unsigned long xer; + unsigned long ccr; + unsigned long mq; /* 601 only (not used at present) */ + /* Used on APUS to hold IPL value. */ + unsigned long trap; /* Reason for being here */ + unsigned long dar; /* Fault registers */ + unsigned long dsisr; + unsigned long result; /* Result of a system call */ +}; + +/* ioctls */ +struct target_revectored_struct { + target_ulong __map[8]; /* 256 bits */ +}; + +/* + * flags masks + */ + +/* ipcs */ + +#define TARGET_SEMOP 1 +#define TARGET_SEMGET 2 +#define TARGET_SEMCTL 3 +#define TARGET_MSGSND 11 +#define TARGET_MSGRCV 12 +#define TARGET_MSGGET 13 +#define TARGET_MSGCTL 14 +#define TARGET_SHMAT 21 +#define TARGET_SHMDT 22 +#define TARGET_SHMGET 23 +#define TARGET_SHMCTL 24 + +struct target_msgbuf { + int mtype; + char mtext[1]; +}; + +struct target_ipc_kludge { + unsigned int msgp; /* Really (struct msgbuf *) */ + int msgtyp; +}; + +struct target_ipc_perm { + int key; + unsigned short uid; + unsigned short gid; + unsigned short cuid; + unsigned short cgid; + unsigned short mode; + unsigned short seq; +}; + +struct target_msqid_ds { + struct target_ipc_perm msg_perm; + unsigned int msg_first; /* really struct target_msg* */ + unsigned int msg_last; /* really struct target_msg* */ + unsigned int msg_stime; /* really target_time_t */ + unsigned int msg_rtime; /* really target_time_t */ + unsigned int msg_ctime; /* really target_time_t */ + unsigned int wwait; /* really struct wait_queue* */ + unsigned int rwait; /* really struct wait_queue* */ + unsigned short msg_cbytes; + unsigned short msg_qnum; + unsigned short msg_qbytes; + unsigned short msg_lspid; + unsigned short msg_lrpid; +}; + +struct target_shmid_ds { + struct target_ipc_perm shm_perm; + int shm_segsz; + unsigned int shm_atime; /* really target_time_t */ + unsigned int shm_dtime; /* really target_time_t */ + unsigned int shm_ctime; /* really target_time_t */ + unsigned short shm_cpid; + unsigned short shm_lpid; + short shm_nattch; + unsigned short shm_npages; + unsigned long *shm_pages; + void *attaches; /* really struct shm_desc * */ +}; + +#define TARGET_IPC_RMID 0 +#define TARGET_IPC_SET 1 +#define TARGET_IPC_STAT 2 + +union target_semun { + int val; + unsigned int buf; /* really struct semid_ds * */ + unsigned int array; /* really unsigned short * */ + unsigned int __buf; /* really struct seminfo * */ + unsigned int __pad; /* really void* */ +}; + +#define UNAME_MACHINE "ppc" diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h new file mode 100644 index 0000000..b97189a --- /dev/null +++ b/linux-user/ppc/syscall_nr.h @@ -0,0 +1,258 @@ +/* + * This file contains the system call numbers. + */ +#define TARGET_NR_restart_syscall 0 +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_lchown32 16 +#define TARGET_NR_break 17 +#define TARGET_NR_oldstat 18 +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid32 23 +#define TARGET_NR_getuid32 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 +#define TARGET_NR_oldfstat 28 +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid32 46 +#define TARGET_NR_getgid32 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid32 49 +#define TARGET_NR_getegid32 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 +#define TARGET_NR_oldolduname 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid32 70 +#define TARGET_NR_setregid32 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups32 80 +#define TARGET_NR_setgroups32 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 +#define TARGET_NR_oldlstat 84 +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown32 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 +#define TARGET_NR_olduname 109 +#define TARGET_NR_iopl 110 +#define TARGET_NR_vhangup 111 +#define TARGET_NR_idle 112 +#define TARGET_NR_vm86 113 +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid32 138 +#define TARGET_NR_setfsgid32 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid32 164 +#define TARGET_NR_getresuid32 165 +#define TARGET_NR_query_module 166 +#define TARGET_NR_poll 167 +#define TARGET_NR_nfsservctl 168 +#define TARGET_NR_setresgid32 169 +#define TARGET_NR_getresgid32 170 +#define TARGET_NR_prctl 171 +#define TARGET_NR_rt_sigreturn 172 +#define TARGET_NR_rt_sigaction 173 +#define TARGET_NR_rt_sigprocmask 174 +#define TARGET_NR_rt_sigpending 175 +#define TARGET_NR_rt_sigtimedwait 176 +#define TARGET_NR_rt_sigqueueinfo 177 +#define TARGET_NR_rt_sigsuspend 178 +#define TARGET_NR_pread64 179 +#define TARGET_NR_pwrite64 180 +#define TARGET_NR_chown32 181 +#define TARGET_NR_getcwd 182 +#define TARGET_NR_capget 183 +#define TARGET_NR_capset 184 +#define TARGET_NR_sigaltstack 185 +#define TARGET_NR_sendfile 186 +#define TARGET_NR_getpmsg 187 /* some people actually want streams */ +#define TARGET_NR_putpmsg 188 /* some people actually want streams */ +#define TARGET_NR_vfork 189 +#define TARGET_NR_ugetrlimit 190 /* SuS compliant getrlimit */ +#define TARGET_NR_readahead 191 +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_pciconfig_read 198 +#define TARGET_NR_pciconfig_write 199 +#define TARGET_NR_pciconfig_iobase 200 +#define TARGET_NR_multiplexer 201 +#define TARGET_NR_getdents64 202 +#define TARGET_NR_pivot_root 203 +#define TARGET_NR_fcntl64 204 +#define TARGET_NR_madvise 205 +#define TARGET_NR_mincore 206 +#define TARGET_NR_gettid 207 +#define TARGET_NR_tkill 208 +#define TARGET_NR_setxattr 209 +#define TARGET_NR_lsetxattr 210 +#define TARGET_NR_fsetxattr 211 +#define TARGET_NR_getxattr 212 +#define TARGET_NR_lgetxattr 213 +#define TARGET_NR_fgetxattr 214 +#define TARGET_NR_listxattr 215 +#define TARGET_NR_llistxattr 216 +#define TARGET_NR_flistxattr 217 +#define TARGET_NR_removexattr 218 +#define TARGET_NR_lremovexattr 219 +#define TARGET_NR_fremovexattr 220 +#define TARGET_NR_futex 221 +#define TARGET_NR_sched_setaffinity 222 +#define TARGET_NR_sched_getaffinity 223 +/* 224 currently unused */ +#define TARGET_NR_tuxcall 225 +#define TARGET_NR_sendfile64 226 +#define TARGET_NR_io_setup 227 +#define TARGET_NR_io_destroy 228 +#define TARGET_NR_io_getevents 229 +#define TARGET_NR_io_submit 230 +#define TARGET_NR_io_cancel 231 +#define TARGET_NR_set_tid_address 232 +#define TARGET_NR_fadvise64 233 +#define TARGET_NR_exit_group 234 +#define TARGET_NR_lookup_dcookie 235 +#define TARGET_NR_epoll_create 236 +#define TARGET_NR_epoll_ctl 237 +#define TARGET_NR_epoll_wait 238 +#define TARGET_NR_remap_file_pages 239 +#define TARGET_NR_timer_create 240 +#define TARGET_NR_timer_settime 241 +#define TARGET_NR_timer_gettime 242 +#define TARGET_NR_timer_getoverrun 243 +#define TARGET_NR_timer_delete 244 +#define TARGET_NR_clock_settime 245 +#define TARGET_NR_clock_gettime 246 +#define TARGET_NR_clock_getres 247 +#define TARGET_NR_clock_nanosleep 248 +#define TARGET_NR_swapcontext 249 +#define TARGET_NR_tgkill 250 +#define TARGET_NR_utimes 251 +#define TARGET_NR_statfs64 252 +#define TARGET_NR_fstatfs64 253 +#define TARGET_NR_fadvise64_64 254 diff --git a/linux-user/ppc/termbits.h b/linux-user/ppc/termbits.h new file mode 100644 index 0000000..6326747 --- /dev/null +++ b/linux-user/ppc/termbits.h @@ -0,0 +1,235 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ + unsigned int c_ispeed; /* input speed */ + unsigned int c_ospeed; /* output speed */ +}; + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VMIN 5 +#define TARGET_VEOL 6 +#define TARGET_VTIME 7 +#define TARGET_VEOL2 8 +#define TARGET_VSWTC 9 + +#define TARGET_VWERASE 10 +#define TARGET_VREPRINT 11 +#define TARGET_VSUSP 12 +#define TARGET_VSTART 13 +#define TARGET_VSTOP 14 +#define TARGET_VLNEXT 15 +#define TARGET_VDISCARD 16 + +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IXON 0001000 +#define TARGET_IXOFF 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IUCLC 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_ONLCR 0000002 +#define TARGET_OLCUC 0000004 + +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 + +#define TARGET_OFILL 00000100 +#define TARGET_OFDEL 00000200 +#define TARGET_NLDLY 00001400 +#define TARGET_NL0 00000000 +#define TARGET_NL1 00000400 +#define TARGET_NL2 00001000 +#define TARGET_NL3 00001400 +#define TARGET_TABDLY 00006000 +#define TARGET_TAB0 00000000 +#define TARGET_TAB1 00002000 +#define TARGET_TAB2 00004000 +#define TARGET_TAB3 00006000 +#define TARGET_CRDLY 00030000 +#define TARGET_CR0 00000000 +#define TARGET_CR1 00010000 +#define TARGET_CR2 00020000 +#define TARGET_CR3 00030000 +#define TARGET_FFDLY 00040000 +#define TARGET_FF0 00000000 +#define TARGET_FF1 00040000 +#define TARGET_BSDLY 00100000 +#define TARGET_BS0 00000000 +#define TARGET_BS1 00100000 +#define TARGET_VTDLY 00200000 +#define TARGET_VT0 00000000 +#define TARGET_VT1 00200000 +#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */ + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0000377 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CBAUDEX 0000000 +#define TARGET_B57600 00020 +#define TARGET_B115200 00021 +#define TARGET_B230400 00022 +#define TARGET_B460800 00023 +#define TARGET_B500000 00024 +#define TARGET_B576000 00025 +#define TARGET_B921600 00026 +#define TARGET_B1000000 00027 +#define TARGET_B1152000 00030 +#define TARGET_B1500000 00031 +#define TARGET_B2000000 00032 +#define TARGET_B2500000 00033 +#define TARGET_B3000000 00034 +#define TARGET_B3500000 00035 +#define TARGET_B4000000 00036 + +#define TARGET_CSIZE 00001400 +#define TARGET_CS5 00000000 +#define TARGET_CS6 00000400 +#define TARGET_CS7 00001000 +#define TARGET_CS8 00001400 + +#define TARGET_CSTOPB 00002000 +#define TARGET_CREAD 00004000 +#define TARGET_PARENB 00010000 +#define TARGET_PARODD 00020000 +#define TARGET_HUPCL 00040000 + +#define TARGET_CLOCAL 00100000 +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0x00000080 +#define TARGET_ICANON 0x00000100 +#define TARGET_XCASE 0x00004000 +#define TARGET_ECHO 0x00000008 +#define TARGET_ECHOE 0x00000002 +#define TARGET_ECHOK 0x00000004 +#define TARGET_ECHONL 0x00000010 +#define TARGET_NOFLSH 0x80000000 +#define TARGET_TOSTOP 0x00400000 +#define TARGET_ECHOCTL 0x00000040 +#define TARGET_ECHOPRT 0x00000020 +#define TARGET_ECHOKE 0x00000001 +#define TARGET_FLUSHO 0x00800000 +#define TARGET_PENDIN 0x20000000 +#define TARGET_IEXTEN 0x00000400 + +/* ioctls */ + +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) +#define TARGET_TIOCINQ TARGET_FIONREAD +//#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t) + +#define TARGET_TCGETS TARGET_IOR('t', 19, struct target_termios) +#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios) +#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios) +#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios) + +#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio) +#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio) +#define TARGET_TCSETAW TARGET_IOW('t', 25, struct target_termio) +#define TARGET_TCSETAF TARGET_IOW('t', 28, struct target_termio) + +#define TARGET_TCSBRK TARGET_IO('t', 29) +#define TARGET_TCXONC TARGET_IO('t', 30) +#define TARGET_TCFLSH TARGET_IO('t', 31) + +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize) +#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */ +#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */ +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ + +#define TARGET_TIOCGLTC TARGET_IOR('t', 116, struct target_ltchars) +#define TARGET_TIOCSLTC TARGET_IOW('t', 117, struct target_ltchars) +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E + +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 + +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 + +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ + /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ +# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ + diff --git a/linux-user/qemu.h b/linux-user/qemu.h new file mode 100644 index 0000000..218e846 --- /dev/null +++ b/linux-user/qemu.h @@ -0,0 +1,308 @@ +#ifndef QEMU_H +#define QEMU_H + +#include "thunk.h" + +#include <signal.h> +#include <string.h> +#include "syscall_defs.h" + +#include "cpu.h" +#include "syscall.h" +#include "gdbstub.h" + +/* This struct is used to hold certain information about the image. + * Basically, it replicates in user space what would be certain + * task_struct fields in the kernel + */ +struct image_info { + unsigned long start_code; + unsigned long end_code; + unsigned long start_data; + unsigned long end_data; + unsigned long start_brk; + unsigned long brk; + unsigned long start_mmap; + unsigned long mmap; + unsigned long rss; + unsigned long start_stack; + unsigned long entry; + target_ulong code_offset; + target_ulong data_offset; + int personality; +}; + +#ifdef TARGET_I386 +/* Information about the current linux thread */ +struct vm86_saved_state { + uint32_t eax; /* return code */ + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esi; + uint32_t edi; + uint32_t ebp; + uint32_t esp; + uint32_t eflags; + uint32_t eip; + uint16_t cs, ss, ds, es, fs, gs; +}; +#endif + +#ifdef TARGET_ARM +/* FPU emulator */ +#include "nwfpe/fpa11.h" +#endif + +/* NOTE: we force a big alignment so that the stack stored after is + aligned too */ +typedef struct TaskState { + struct TaskState *next; +#ifdef TARGET_ARM + /* FPA state */ + FPA11 fpa; + /* Extra fields for semihosted binaries. */ + uint32_t stack_base; + uint32_t heap_base; + uint32_t heap_limit; + int swi_errno; +#endif +#ifdef TARGET_I386 + target_ulong target_v86; + struct vm86_saved_state vm86_saved_regs; + struct target_vm86plus_struct vm86plus; + uint32_t v86flags; + uint32_t v86mask; +#endif + int used; /* non zero if used */ + struct image_info *info; + uint8_t stack[0]; +} __attribute__((aligned(16))) TaskState; + +extern TaskState *first_task_state; +extern const char *qemu_uname_release; + +/* ??? See if we can avoid exposing so much of the loader internals. */ +/* + * MAX_ARG_PAGES defines the number of pages allocated for arguments + * and envelope for the new program. 32 should suffice, this gives + * a maximum env+arg of 128kB w/4KB pages! + */ +#define MAX_ARG_PAGES 32 + +/* + * This structure is used to hold the arguments that are + * used when loading binaries. + */ +struct linux_binprm { + char buf[128]; + void *page[MAX_ARG_PAGES]; + unsigned long p; + int fd; + int e_uid, e_gid; + int argc, envc; + char **argv; + char **envp; + char * filename; /* Name of binary */ +}; + +void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); +target_ulong loader_build_argptr(int envc, int argc, target_ulong sp, + target_ulong stringp, int push_ptr); +int loader_exec(const char * filename, char ** argv, char ** envp, + struct target_pt_regs * regs, struct image_info *infop); + +int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info); +int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, + struct image_info * info); + +void memcpy_to_target(target_ulong dest, const void *src, + unsigned long len); +void target_set_brk(target_ulong new_brk); +long do_brk(target_ulong new_brk); +void syscall_init(void); +long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6); +void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); +extern CPUState *global_env; +void cpu_loop(CPUState *env); +void init_paths(const char *prefix); +const char *path(const char *pathname); + +extern int loglevel; +extern FILE *logfile; + +/* signal.c */ +void process_pending_signals(void *cpu_env); +void signal_init(void); +int queue_signal(int sig, target_siginfo_t *info); +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); +long do_sigreturn(CPUState *env); +long do_rt_sigreturn(CPUState *env); + +#ifdef TARGET_I386 +/* vm86.c */ +void save_v86_state(CPUX86State *env); +void handle_vm86_trap(CPUX86State *env, int trapno); +void handle_vm86_fault(CPUX86State *env); +int do_vm86(CPUX86State *env, long subfunction, target_ulong v86_addr); +#endif + +/* mmap.c */ +int target_mprotect(target_ulong start, target_ulong len, int prot); +long target_mmap(target_ulong start, target_ulong len, int prot, + int flags, int fd, target_ulong offset); +int target_munmap(target_ulong start, target_ulong len); +long target_mremap(target_ulong old_addr, target_ulong old_size, + target_ulong new_size, unsigned long flags, + target_ulong new_addr); +int target_msync(target_ulong start, target_ulong len, int flags); + +/* user access */ + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +#define access_ok(type,addr,size) (1) + +/* NOTE get_user and put_user use host addresses. */ +#define __put_user(x,ptr)\ +({\ + int size = sizeof(*ptr);\ + switch(size) {\ + case 1:\ + *(uint8_t *)(ptr) = (typeof(*ptr))(x);\ + break;\ + case 2:\ + *(uint16_t *)(ptr) = tswap16((typeof(*ptr))(x));\ + break;\ + case 4:\ + *(uint32_t *)(ptr) = tswap32((typeof(*ptr))(x));\ + break;\ + case 8:\ + *(uint64_t *)(ptr) = tswap64((typeof(*ptr))(x));\ + break;\ + default:\ + abort();\ + }\ + 0;\ +}) + +#define __get_user(x, ptr) \ +({\ + int size = sizeof(*ptr);\ + switch(size) {\ + case 1:\ + x = (typeof(*ptr))*(uint8_t *)(ptr);\ + break;\ + case 2:\ + x = (typeof(*ptr))tswap16(*(uint16_t *)(ptr));\ + break;\ + case 4:\ + x = (typeof(*ptr))tswap32(*(uint32_t *)(ptr));\ + break;\ + case 8:\ + x = (typeof(*ptr))tswap64(*(uint64_t *)(ptr));\ + break;\ + default:\ + abort();\ + }\ + 0;\ +}) + +#define put_user(x,ptr)\ +({\ + int __ret;\ + if (access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))\ + __ret = __put_user(x, ptr);\ + else\ + __ret = -EFAULT;\ + __ret;\ +}) + +#define get_user(x,ptr)\ +({\ + int __ret;\ + if (access_ok(VERIFY_READ, ptr, sizeof(*ptr)))\ + __ret = __get_user(x, ptr);\ + else\ + __ret = -EFAULT;\ + __ret;\ +}) + +/* Functions for accessing guest memory. The tget and tput functions + read/write single values, byteswapping as neccessary. The lock_user + gets a pointer to a contiguous area of guest memory, but does not perform + and byteswapping. lock_user may return either a pointer to the guest + memory, or a temporary buffer. */ + +/* Lock an area of guest memory into the host. If copy is true then the + host area will have the same contents as the guest. */ +static inline void *lock_user(target_ulong guest_addr, long len, int copy) +{ +#ifdef DEBUG_REMAP + void *addr; + addr = malloc(len); + if (copy) + memcpy(addr, g2h(guest_addr), len); + else + memset(addr, 0, len); + return addr; +#else + return g2h(guest_addr); +#endif +} + +/* Unlock an area of guest memory. The first LEN bytes must be flushed back + to guest memory. */ +static inline void unlock_user(void *host_addr, target_ulong guest_addr, + long len) +{ +#ifdef DEBUG_REMAP + if (host_addr == g2h(guest_addr)) + return; + if (len > 0) + memcpy(g2h(guest_addr), host_addr, len); + free(host_addr); +#endif +} + +/* Return the length of a string in target memory. */ +static inline int target_strlen(target_ulong ptr) +{ + return strlen(g2h(ptr)); +} + +/* Like lock_user but for null terminated strings. */ +static inline void *lock_user_string(target_ulong guest_addr) +{ + long len; + len = target_strlen(guest_addr) + 1; + return lock_user(guest_addr, len, 1); +} + +/* Helper macros for locking/ulocking a target struct. */ +#define lock_user_struct(host_ptr, guest_addr, copy) \ + host_ptr = lock_user(guest_addr, sizeof(*host_ptr), copy) +#define unlock_user_struct(host_ptr, guest_addr, copy) \ + unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) + +#define tget8(addr) ldub(addr) +#define tput8(addr, val) stb(addr, val) +#define tget16(addr) lduw(addr) +#define tput16(addr, val) stw(addr, val) +#define tget32(addr) ldl(addr) +#define tput32(addr, val) stl(addr, val) +#define tget64(addr) ldq(addr) +#define tput64(addr, val) stq(addr, val) +#if TARGET_LONG_BITS == 64 +#define tgetl(addr) ldq(addr) +#define tputl(addr, val) stq(addr, val) +#else +#define tgetl(addr) ldl(addr) +#define tputl(addr, val) stl(addr, val) +#endif + +#endif /* QEMU_H */ diff --git a/linux-user/sh4/syscall.h b/linux-user/sh4/syscall.h new file mode 100644 index 0000000..014bf58 --- /dev/null +++ b/linux-user/sh4/syscall.h @@ -0,0 +1,12 @@ +struct target_pt_regs { + unsigned long regs[16]; + unsigned long pc; + unsigned long pr; + unsigned long sr; + unsigned long gbr; + unsigned long mach; + unsigned long macl; + long tra; +}; + +#define UNAME_MACHINE "sh4" diff --git a/linux-user/sh4/syscall_nr.h b/linux-user/sh4/syscall_nr.h new file mode 100644 index 0000000..c91ba1b --- /dev/null +++ b/linux-user/sh4/syscall_nr.h @@ -0,0 +1,292 @@ +/* + * This file contains the system call numbers. + */ + +#define TARGET_NR_restart_syscall 0 +#define TARGET_NR_exit 1 +#define TARGET_NR_fork 2 +#define TARGET_NR_read 3 +#define TARGET_NR_write 4 +#define TARGET_NR_open 5 +#define TARGET_NR_close 6 +#define TARGET_NR_waitpid 7 +#define TARGET_NR_creat 8 +#define TARGET_NR_link 9 +#define TARGET_NR_unlink 10 +#define TARGET_NR_execve 11 +#define TARGET_NR_chdir 12 +#define TARGET_NR_time 13 +#define TARGET_NR_mknod 14 +#define TARGET_NR_chmod 15 +#define TARGET_NR_lchown 16 +#define TARGET_NR_break 17 +#define TARGET_NR_oldstat 18 +#define TARGET_NR_lseek 19 +#define TARGET_NR_getpid 20 +#define TARGET_NR_mount 21 +#define TARGET_NR_umount 22 +#define TARGET_NR_setuid 23 +#define TARGET_NR_getuid 24 +#define TARGET_NR_stime 25 +#define TARGET_NR_ptrace 26 +#define TARGET_NR_alarm 27 +#define TARGET_NR_oldfstat 28 +#define TARGET_NR_pause 29 +#define TARGET_NR_utime 30 +#define TARGET_NR_stty 31 +#define TARGET_NR_gtty 32 +#define TARGET_NR_access 33 +#define TARGET_NR_nice 34 +#define TARGET_NR_ftime 35 +#define TARGET_NR_sync 36 +#define TARGET_NR_kill 37 +#define TARGET_NR_rename 38 +#define TARGET_NR_mkdir 39 +#define TARGET_NR_rmdir 40 +#define TARGET_NR_dup 41 +#define TARGET_NR_pipe 42 +#define TARGET_NR_times 43 +#define TARGET_NR_prof 44 +#define TARGET_NR_brk 45 +#define TARGET_NR_setgid 46 +#define TARGET_NR_getgid 47 +#define TARGET_NR_signal 48 +#define TARGET_NR_geteuid 49 +#define TARGET_NR_getegid 50 +#define TARGET_NR_acct 51 +#define TARGET_NR_umount2 52 +#define TARGET_NR_lock 53 +#define TARGET_NR_ioctl 54 +#define TARGET_NR_fcntl 55 +#define TARGET_NR_mpx 56 +#define TARGET_NR_setpgid 57 +#define TARGET_NR_ulimit 58 +#define TARGET_NR_oldolduname 59 +#define TARGET_NR_umask 60 +#define TARGET_NR_chroot 61 +#define TARGET_NR_ustat 62 +#define TARGET_NR_dup2 63 +#define TARGET_NR_getppid 64 +#define TARGET_NR_getpgrp 65 +#define TARGET_NR_setsid 66 +#define TARGET_NR_sigaction 67 +#define TARGET_NR_sgetmask 68 +#define TARGET_NR_ssetmask 69 +#define TARGET_NR_setreuid 70 +#define TARGET_NR_setregid 71 +#define TARGET_NR_sigsuspend 72 +#define TARGET_NR_sigpending 73 +#define TARGET_NR_sethostname 74 +#define TARGET_NR_setrlimit 75 +#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ +#define TARGET_NR_getrusage 77 +#define TARGET_NR_gettimeofday 78 +#define TARGET_NR_settimeofday 79 +#define TARGET_NR_getgroups 80 +#define TARGET_NR_setgroups 81 +#define TARGET_NR_select 82 +#define TARGET_NR_symlink 83 +#define TARGET_NR_oldlstat 84 +#define TARGET_NR_readlink 85 +#define TARGET_NR_uselib 86 +#define TARGET_NR_swapon 87 +#define TARGET_NR_reboot 88 +#define TARGET_NR_readdir 89 +#define TARGET_NR_mmap 90 +#define TARGET_NR_munmap 91 +#define TARGET_NR_truncate 92 +#define TARGET_NR_ftruncate 93 +#define TARGET_NR_fchmod 94 +#define TARGET_NR_fchown 95 +#define TARGET_NR_getpriority 96 +#define TARGET_NR_setpriority 97 +#define TARGET_NR_profil 98 +#define TARGET_NR_statfs 99 +#define TARGET_NR_fstatfs 100 +#define TARGET_NR_ioperm 101 +#define TARGET_NR_socketcall 102 +#define TARGET_NR_syslog 103 +#define TARGET_NR_setitimer 104 +#define TARGET_NR_getitimer 105 +#define TARGET_NR_stat 106 +#define TARGET_NR_lstat 107 +#define TARGET_NR_fstat 108 +#define TARGET_NR_olduname 109 +#define TARGET_NR_iopl 110 +#define TARGET_NR_vhangup 111 +#define TARGET_NR_idle 112 +#define TARGET_NR_vm86old 113 +#define TARGET_NR_wait4 114 +#define TARGET_NR_swapoff 115 +#define TARGET_NR_sysinfo 116 +#define TARGET_NR_ipc 117 +#define TARGET_NR_fsync 118 +#define TARGET_NR_sigreturn 119 +#define TARGET_NR_clone 120 +#define TARGET_NR_setdomainname 121 +#define TARGET_NR_uname 122 +#define TARGET_NR_modify_ldt 123 +#define TARGET_NR_adjtimex 124 +#define TARGET_NR_mprotect 125 +#define TARGET_NR_sigprocmask 126 +#define TARGET_NR_create_module 127 +#define TARGET_NR_init_module 128 +#define TARGET_NR_delete_module 129 +#define TARGET_NR_get_kernel_syms 130 +#define TARGET_NR_quotactl 131 +#define TARGET_NR_getpgid 132 +#define TARGET_NR_fchdir 133 +#define TARGET_NR_bdflush 134 +#define TARGET_NR_sysfs 135 +#define TARGET_NR_personality 136 +#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid 138 +#define TARGET_NR_setfsgid 139 +#define TARGET_NR__llseek 140 +#define TARGET_NR_getdents 141 +#define TARGET_NR__newselect 142 +#define TARGET_NR_flock 143 +#define TARGET_NR_msync 144 +#define TARGET_NR_readv 145 +#define TARGET_NR_writev 146 +#define TARGET_NR_getsid 147 +#define TARGET_NR_fdatasync 148 +#define TARGET_NR__sysctl 149 +#define TARGET_NR_mlock 150 +#define TARGET_NR_munlock 151 +#define TARGET_NR_mlockall 152 +#define TARGET_NR_munlockall 153 +#define TARGET_NR_sched_setparam 154 +#define TARGET_NR_sched_getparam 155 +#define TARGET_NR_sched_setscheduler 156 +#define TARGET_NR_sched_getscheduler 157 +#define TARGET_NR_sched_yield 158 +#define TARGET_NR_sched_get_priority_max 159 +#define TARGET_NR_sched_get_priority_min 160 +#define TARGET_NR_sched_rr_get_interval 161 +#define TARGET_NR_nanosleep 162 +#define TARGET_NR_mremap 163 +#define TARGET_NR_setresuid 164 +#define TARGET_NR_getresuid 165 +#define TARGET_NR_vm86 166 +#define TARGET_NR_query_module 167 +#define TARGET_NR_poll 168 +#define TARGET_NR_nfsservctl 169 +#define TARGET_NR_setresgid 170 +#define TARGET_NR_getresgid 171 +#define TARGET_NR_prctl 172 +#define TARGET_NR_rt_sigreturn 173 +#define TARGET_NR_rt_sigaction 174 +#define TARGET_NR_rt_sigprocmask 175 +#define TARGET_NR_rt_sigpending 176 +#define TARGET_NR_rt_sigtimedwait 177 +#define TARGET_NR_rt_sigqueueinfo 178 +#define TARGET_NR_rt_sigsuspend 179 +#define TARGET_NR_pread64 180 +#define TARGET_NR_pwrite64 181 +#define TARGET_NR_chown 182 +#define TARGET_NR_getcwd 183 +#define TARGET_NR_capget 184 +#define TARGET_NR_capset 185 +#define TARGET_NR_sigaltstack 186 +#define TARGET_NR_sendfile 187 +#define TARGET_NR_streams1 188 /* some people actually want it */ +#define TARGET_NR_streams2 189 /* some people actually want it */ +#define TARGET_NR_vfork 190 +#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */ +#define TARGET_NR_mmap2 192 +#define TARGET_NR_truncate64 193 +#define TARGET_NR_ftruncate64 194 +#define TARGET_NR_stat64 195 +#define TARGET_NR_lstat64 196 +#define TARGET_NR_fstat64 197 +#define TARGET_NR_lchown32 198 +#define TARGET_NR_getuid32 199 +#define TARGET_NR_getgid32 200 +#define TARGET_NR_geteuid32 201 +#define TARGET_NR_getegid32 202 +#define TARGET_NR_setreuid32 203 +#define TARGET_NR_setregid32 204 +#define TARGET_NR_getgroups32 205 +#define TARGET_NR_setgroups32 206 +#define TARGET_NR_fchown32 207 +#define TARGET_NR_setresuid32 208 +#define TARGET_NR_getresuid32 209 +#define TARGET_NR_setresgid32 210 +#define TARGET_NR_getresgid32 211 +#define TARGET_NR_chown32 212 +#define TARGET_NR_setuid32 213 +#define TARGET_NR_setgid32 214 +#define TARGET_NR_setfsuid32 215 +#define TARGET_NR_setfsgid32 216 +#define TARGET_NR_pivot_root 217 +#define TARGET_NR_mincore 218 +#define TARGET_NR_madvise 219 +#define TARGET_NR_getdents64 220 +#define TARGET_NR_fcntl64 221 +/* 223 is unused */ +#define TARGET_NR_gettid 224 +#define TARGET_NR_setxattr 226 +#define TARGET_NR_lsetxattr 227 +#define TARGET_NR_fsetxattr 228 +#define TARGET_NR_getxattr 229 +#define TARGET_NR_lgetxattr 230 +#define TARGET_NR_fgetxattr 231 +#define TARGET_NR_listxattr 232 +#define TARGET_NR_llistxattr 233 +#define TARGET_NR_flistxattr 234 +#define TARGET_NR_removexattr 235 +#define TARGET_NR_lremovexattr 236 +#define TARGET_NR_fremovexattr 237 +#define TARGET_NR_tkill 238 +#define TARGET_NR_sendfile64 239 +#define TARGET_NR_futex 240 +#define TARGET_NR_sched_setaffinity 241 +#define TARGET_NR_sched_getaffinity 242 +#define TARGET_NR_set_thread_area 243 +#define TARGET_NR_get_thread_area 244 +#define TARGET_NR_io_setup 245 +#define TARGET_NR_io_destroy 246 +#define TARGET_NR_io_getevents 247 +#define TARGET_NR_io_submit 248 +#define TARGET_NR_io_cancel 249 +#define TARGET_NR_fadvise64 250 + +#define TARGET_NR_exit_group 252 +#define TARGET_NR_lookup_dcookie 253 +#define TARGET_NR_epoll_create 254 +#define TARGET_NR_epoll_ctl 255 +#define TARGET_NR_epoll_wait 256 +#define TARGET_NR_remap_file_pages 257 +#define TARGET_NR_set_tid_address 258 +#define TARGET_NR_timer_create 259 +#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1) +#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2) +#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3) +#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4) +#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5) +#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) +#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) +#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) +#define TARGET_NR_statfs64 268 +#define TARGET_NR_fstatfs64 269 +#define TARGET_NR_tgkill 270 +#define TARGET_NR_utimes 271 +#define TARGET_NR_fadvise64_64 272 +#define TARGET_NR_vserver 273 +#define TARGET_NR_mbind 274 +#define TARGET_NR_get_mempolicy 275 +#define TARGET_NR_set_mempolicy 276 +#define TARGET_NR_mq_open 277 +#define TARGET_NR_mq_unlink (TARGET_NR_mq_open+1) +#define TARGET_NR_mq_timedsend (TARGET_NR_mq_open+2) +#define TARGET_NR_mq_timedreceive (TARGET_NR_mq_open+3) +#define TARGET_NR_mq_notify (TARGET_NR_mq_open+4) +#define TARGET_NR_mq_getsetattr (TARGET_NR_mq_open+5) +#define TARGET_NR_sys_kexec_load 283 +#define TARGET_NR_waitid 284 +#define TARGET_NR_add_key 285 +#define TARGET_NR_request_key 286 +#define TARGET_NR_keyctl 287 + +#define TARGET_NR_readahead 225 /* XXXXX */ diff --git a/linux-user/sh4/termbits.h b/linux-user/sh4/termbits.h new file mode 100644 index 0000000..6dd5845 --- /dev/null +++ b/linux-user/sh4/termbits.h @@ -0,0 +1,274 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_B500000 0010005 +#define TARGET_B576000 0010006 +#define TARGET_B921600 0010007 +#define TARGET_B1000000 0010010 +#define TARGET_B1152000 0010011 +#define TARGET_B1500000 0010012 +#define TARGET_B2000000 0010013 +#define TARGET_B2500000 0010014 +#define TARGET_B3000000 0010015 +#define TARGET_B3500000 0010016 +#define TARGET_B4000000 0010017 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* tcflow() and TCXONC use these */ +#define TARGET_TCOOFF 0 +#define TARGET_TCOON 1 +#define TARGET_TCIOFF 2 +#define TARGET_TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TARGET_TCIFLUSH 0 +#define TARGET_TCOFLUSH 1 +#define TARGET_TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TARGET_TCSANOW 0 +#define TARGET_TCSADRAIN 1 +#define TARGET_TARGET_TCSAFLUSH 2 + +/* ioctl */ +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) +#define TARGET_TIOCINQ TARGET_FIONREAD +#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t) +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA TARGET_IOR('t', 23, struct termio) +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) +#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */ +#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */ +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ + +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) + +#define TARGET_TCSETA TARGET_IOW('t', 24, struct termio) +#define TARGET_TCSETAW TARGET_IOW('t', 25, struct termio) +#define TARGET_TCSETAF TARGET_IOW('t', 28, struct termio) +#define TARGET_TCSBRK TARGET_IO('t', 29) +#define TARGET_TCXONC TARGET_IO('t', 30) +#define TARGET_TCFLSH TARGET_IO('t', 31) + +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) +#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */ +#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */ +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */ + +#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) +#define TARGET_TIOCEXCL TARGET_IO('T', 12) /* 0x540C */ +#define TARGET_TIOCNXCL TARGET_IO('T', 13) /* 0x540D */ +#define TARGET_TIOCSCTTY TARGET_IO('T', 14) /* 0x540E */ + +#define TARGET_TIOCSTI TARGET_IOW('T', 18, char) /* 0x5412 */ +#define TARGET_TIOCMGET TARGET_IOR('T', 21, unsigned int) /* 0x5415 */ +#define TARGET_TIOCMBIS TARGET_IOW('T', 22, unsigned int) /* 0x5416 */ +#define TARGET_TIOCMBIC TARGET_IOW('T', 23, unsigned int) /* 0x5417 */ +#define TARGET_TIOCMSET TARGET_IOW('T', 24, unsigned int) /* 0x5418 */ +#define TARGET_TIOCM_LE 0x001 +#define TARGET_TIOCM_DTR 0x002 +#define TARGET_TIOCM_RTS 0x004 +#define TARGET_TIOCM_ST 0x008 +#define TARGET_TIOCM_SR 0x010 +#define TARGET_TIOCM_CTS 0x020 +#define TARGET_TIOCM_CAR 0x040 +#define TARGET_TIOCM_RNG 0x080 +#define TARGET_TIOCM_DSR 0x100 +#define TARGET_TIOCM_CD TARGET_TIOCM_CAR +#define TARGET_TIOCM_RI TARGET_TIOCM_RNG + +#define TARGET_TIOCGSOFTCAR TARGET_IOR('T', 25, unsigned int) /* 0x5419 */ +#define TARGET_TIOCSSOFTCAR TARGET_IOW('T', 26, unsigned int) /* 0x541A */ +#define TARGET_TIOCLINUX TARGET_IOW('T', 28, char) /* 0x541C */ +#define TARGET_TIOCCONS TARGET_IO('T', 29) /* 0x541D */ +#define TARGET_TIOCGSERIAL TARGET_IOR('T', 30, int) /* 0x541E */ +#define TARGET_TIOCSSERIAL TARGET_IOW('T', 31, int) /* 0x541F */ +#define TARGET_TIOCPKT TARGET_IOW('T', 32, int) /* 0x5420 */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + + +#define TARGET_TIOCNOTTY TARGET_IO('T', 34) /* 0x5422 */ +#define TARGET_TIOCSETD TARGET_IOW('T', 35, int) /* 0x5423 */ +#define TARGET_TIOCGETD TARGET_IOR('T', 36, int) /* 0x5424 */ +#define TARGET_TCSBRKP TARGET_IOW('T', 37, int) /* 0x5425 */ /* Needed for POSIX tcse +ndbreak() */ +#define TARGET_TIOCSBRK TARGET_IO('T', 39) /* 0x5427 */ /* BSD compatibility */ +#define TARGET_TIOCCBRK TARGET_IO('T', 40) /* 0x5428 */ /* BSD compatibility */ +#define TARGET_TIOCGSID TARGET_IOR('T', 41, pid_t) /* 0x5429 */ /* Return the session +ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-m +ux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + + +#define TARGET_TIOCSERCONFIG TARGET_IO('T', 83) /* 0x5453 */ +#define TARGET_TIOCSERGWILD TARGET_IOR('T', 84, int) /* 0x5454 */ +#define TARGET_TIOCSERSWILD TARGET_IOW('T', 85, int) /* 0x5455 */ +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT TARGET_IOR('T', 88, int) /* 0x5458 */ /* For d +ebugging only */ +#define TARGET_TIOCSERGETLSR TARGET_IOR('T', 89, unsigned int) /* 0x5459 */ /* Get line sta +tus register */ + /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ +# define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ +#define TARGET_TIOCSERGETMULTI TARGET_IOR('T', 90, int) /* 0x545A +*/ /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI TARGET_IOW('T', 91, int) /* 0x545B +*/ /* Set multiport config */ + +#define TARGET_TIOCMIWAIT TARGET_IO('T', 92) /* 0x545C */ /* wait for a change on +serial input line(s) */ +#define TARGET_TIOCGICOUNT TARGET_IOR('T', 93, int) /* 0x545D */ /* read +serial port inline interrupt counts */ diff --git a/linux-user/signal.c b/linux-user/signal.c new file mode 100644 index 0000000..60f9eb7 --- /dev/null +++ b/linux-user/signal.c @@ -0,0 +1,2067 @@ +/* + * Emulation of Linux signals + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <sys/ucontext.h> + +#include "qemu.h" + +//#define DEBUG_SIGNAL + +#define MAX_SIGQUEUE_SIZE 1024 + +struct sigqueue { + struct sigqueue *next; + target_siginfo_t info; +}; + +struct emulated_sigaction { + struct target_sigaction sa; + int pending; /* true if signal is pending */ + struct sigqueue *first; + struct sigqueue info; /* in order to always have memory for the + first signal, we put it here */ +}; + +static struct emulated_sigaction sigact_table[TARGET_NSIG]; +static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ +static struct sigqueue *first_free; /* first free siginfo queue entry */ +static int signal_pending; /* non zero if a signal may be pending */ + +static void host_signal_handler(int host_signum, siginfo_t *info, + void *puc); + +static uint8_t host_to_target_signal_table[65] = { + [SIGHUP] = TARGET_SIGHUP, + [SIGINT] = TARGET_SIGINT, + [SIGQUIT] = TARGET_SIGQUIT, + [SIGILL] = TARGET_SIGILL, + [SIGTRAP] = TARGET_SIGTRAP, + [SIGABRT] = TARGET_SIGABRT, +/* [SIGIOT] = TARGET_SIGIOT,*/ + [SIGBUS] = TARGET_SIGBUS, + [SIGFPE] = TARGET_SIGFPE, + [SIGKILL] = TARGET_SIGKILL, + [SIGUSR1] = TARGET_SIGUSR1, + [SIGSEGV] = TARGET_SIGSEGV, + [SIGUSR2] = TARGET_SIGUSR2, + [SIGPIPE] = TARGET_SIGPIPE, + [SIGALRM] = TARGET_SIGALRM, + [SIGTERM] = TARGET_SIGTERM, +#ifdef SIGSTKFLT + [SIGSTKFLT] = TARGET_SIGSTKFLT, +#endif + [SIGCHLD] = TARGET_SIGCHLD, + [SIGCONT] = TARGET_SIGCONT, + [SIGSTOP] = TARGET_SIGSTOP, + [SIGTSTP] = TARGET_SIGTSTP, + [SIGTTIN] = TARGET_SIGTTIN, + [SIGTTOU] = TARGET_SIGTTOU, + [SIGURG] = TARGET_SIGURG, + [SIGXCPU] = TARGET_SIGXCPU, + [SIGXFSZ] = TARGET_SIGXFSZ, + [SIGVTALRM] = TARGET_SIGVTALRM, + [SIGPROF] = TARGET_SIGPROF, + [SIGWINCH] = TARGET_SIGWINCH, + [SIGIO] = TARGET_SIGIO, + [SIGPWR] = TARGET_SIGPWR, + [SIGSYS] = TARGET_SIGSYS, + /* next signals stay the same */ +}; +static uint8_t target_to_host_signal_table[65]; + +static inline int host_to_target_signal(int sig) +{ + return host_to_target_signal_table[sig]; +} + +static inline int target_to_host_signal(int sig) +{ + return target_to_host_signal_table[sig]; +} + +static void host_to_target_sigset_internal(target_sigset_t *d, + const sigset_t *s) +{ + int i; + unsigned long sigmask; + uint32_t target_sigmask; + + sigmask = ((unsigned long *)s)[0]; + target_sigmask = 0; + for(i = 0; i < 32; i++) { + if (sigmask & (1 << i)) + target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1); + } +#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32 + d->sig[0] = target_sigmask; + for(i = 1;i < TARGET_NSIG_WORDS; i++) { + d->sig[i] = ((unsigned long *)s)[i]; + } +#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 + d->sig[0] = target_sigmask; + d->sig[1] = sigmask >> 32; +#else +#warning host_to_target_sigset +#endif +} + +void host_to_target_sigset(target_sigset_t *d, const sigset_t *s) +{ + target_sigset_t d1; + int i; + + host_to_target_sigset_internal(&d1, s); + for(i = 0;i < TARGET_NSIG_WORDS; i++) + d->sig[i] = tswapl(d1.sig[i]); +} + +void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s) +{ + int i; + unsigned long sigmask; + target_ulong target_sigmask; + + target_sigmask = s->sig[0]; + sigmask = 0; + for(i = 0; i < 32; i++) { + if (target_sigmask & (1 << i)) + sigmask |= 1 << (target_to_host_signal(i + 1) - 1); + } +#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32 + ((unsigned long *)d)[0] = sigmask; + for(i = 1;i < TARGET_NSIG_WORDS; i++) { + ((unsigned long *)d)[i] = s->sig[i]; + } +#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2 + ((unsigned long *)d)[0] = sigmask | ((unsigned long)(s->sig[1]) << 32); +#else +#warning target_to_host_sigset +#endif /* TARGET_LONG_BITS */ +} + +void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) +{ + target_sigset_t s1; + int i; + + for(i = 0;i < TARGET_NSIG_WORDS; i++) + s1.sig[i] = tswapl(s->sig[i]); + target_to_host_sigset_internal(d, &s1); +} + +void host_to_target_old_sigset(target_ulong *old_sigset, + const sigset_t *sigset) +{ + target_sigset_t d; + host_to_target_sigset(&d, sigset); + *old_sigset = d.sig[0]; +} + +void target_to_host_old_sigset(sigset_t *sigset, + const target_ulong *old_sigset) +{ + target_sigset_t d; + int i; + + d.sig[0] = *old_sigset; + for(i = 1;i < TARGET_NSIG_WORDS; i++) + d.sig[i] = 0; + target_to_host_sigset(sigset, &d); +} + +/* siginfo conversion */ + +static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, + const siginfo_t *info) +{ + int sig; + sig = host_to_target_signal(info->si_signo); + tinfo->si_signo = sig; + tinfo->si_errno = 0; + tinfo->si_code = 0; + if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || + sig == SIGBUS || sig == SIGTRAP) { + /* should never come here, but who knows. The information for + the target is irrelevant */ + tinfo->_sifields._sigfault._addr = 0; + } else if (sig >= TARGET_SIGRTMIN) { + tinfo->_sifields._rt._pid = info->si_pid; + tinfo->_sifields._rt._uid = info->si_uid; + /* XXX: potential problem if 64 bit */ + tinfo->_sifields._rt._sigval.sival_ptr = + (target_ulong)info->si_value.sival_ptr; + } +} + +static void tswap_siginfo(target_siginfo_t *tinfo, + const target_siginfo_t *info) +{ + int sig; + sig = info->si_signo; + tinfo->si_signo = tswap32(sig); + tinfo->si_errno = tswap32(info->si_errno); + tinfo->si_code = tswap32(info->si_code); + if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || + sig == SIGBUS || sig == SIGTRAP) { + tinfo->_sifields._sigfault._addr = + tswapl(info->_sifields._sigfault._addr); + } else if (sig >= TARGET_SIGRTMIN) { + tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid); + tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid); + tinfo->_sifields._rt._sigval.sival_ptr = + tswapl(info->_sifields._rt._sigval.sival_ptr); + } +} + + +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info) +{ + host_to_target_siginfo_noswap(tinfo, info); + tswap_siginfo(tinfo, tinfo); +} + +/* XXX: we support only POSIX RT signals are used. */ +/* XXX: find a solution for 64 bit (additionnal malloced data is needed) */ +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) +{ + info->si_signo = tswap32(tinfo->si_signo); + info->si_errno = tswap32(tinfo->si_errno); + info->si_code = tswap32(tinfo->si_code); + info->si_pid = tswap32(tinfo->_sifields._rt._pid); + info->si_uid = tswap32(tinfo->_sifields._rt._uid); + info->si_value.sival_ptr = + (void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr); +} + +void signal_init(void) +{ + struct sigaction act; + int i, j; + + /* generate signal conversion tables */ + for(i = 1; i <= 64; i++) { + if (host_to_target_signal_table[i] == 0) + host_to_target_signal_table[i] = i; + } + for(i = 1; i <= 64; i++) { + j = host_to_target_signal_table[i]; + target_to_host_signal_table[j] = i; + } + + /* set all host signal handlers. ALL signals are blocked during + the handlers to serialize them. */ + sigfillset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + act.sa_sigaction = host_signal_handler; + for(i = 1; i < NSIG; i++) { + sigaction(i, &act, NULL); + } + + memset(sigact_table, 0, sizeof(sigact_table)); + + first_free = &sigqueue_table[0]; + for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) + sigqueue_table[i].next = &sigqueue_table[i + 1]; + sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL; +} + +/* signal queue handling */ + +static inline struct sigqueue *alloc_sigqueue(void) +{ + struct sigqueue *q = first_free; + if (!q) + return NULL; + first_free = q->next; + return q; +} + +static inline void free_sigqueue(struct sigqueue *q) +{ + q->next = first_free; + first_free = q; +} + +/* abort execution with signal */ +void __attribute((noreturn)) force_sig(int sig) +{ + int host_sig; + host_sig = target_to_host_signal(sig); + fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", + sig, strsignal(host_sig)); +#if 1 + _exit(-host_sig); +#else + { + struct sigaction act; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + act.sa_sigaction = SIG_DFL; + sigaction(SIGABRT, &act, NULL); + abort(); + } +#endif +} + +/* queue a signal so that it will be send to the virtual CPU as soon + as possible */ +int queue_signal(int sig, target_siginfo_t *info) +{ + struct emulated_sigaction *k; + struct sigqueue *q, **pq; + target_ulong handler; + +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "queue_signal: sig=%d\n", + sig); +#endif + k = &sigact_table[sig - 1]; + handler = k->sa._sa_handler; + if (handler == TARGET_SIG_DFL) { + /* default handler : ignore some signal. The other are fatal */ + if (sig != TARGET_SIGCHLD && + sig != TARGET_SIGURG && + sig != TARGET_SIGWINCH) { + force_sig(sig); + } else { + return 0; /* indicate ignored */ + } + } else if (handler == TARGET_SIG_IGN) { + /* ignore signal */ + return 0; + } else if (handler == TARGET_SIG_ERR) { + force_sig(sig); + } else { + pq = &k->first; + if (sig < TARGET_SIGRTMIN) { + /* if non real time signal, we queue exactly one signal */ + if (!k->pending) + q = &k->info; + else + return 0; + } else { + if (!k->pending) { + /* first signal */ + q = &k->info; + } else { + q = alloc_sigqueue(); + if (!q) + return -EAGAIN; + while (*pq != NULL) + pq = &(*pq)->next; + } + } + *pq = q; + q->info = *info; + q->next = NULL; + k->pending = 1; + /* signal that a new signal is pending */ + signal_pending = 1; + return 1; /* indicates that the signal was queued */ + } +} + +static void host_signal_handler(int host_signum, siginfo_t *info, + void *puc) +{ + int sig; + target_siginfo_t tinfo; + + /* the CPU emulator uses some host signals to detect exceptions, + we we forward to it some signals */ + if (host_signum == SIGSEGV || host_signum == SIGBUS +#if defined(TARGET_I386) && defined(USE_CODE_COPY) + || host_signum == SIGFPE +#endif + ) { + if (cpu_signal_handler(host_signum, info, puc)) + return; + } + + /* get target signal number */ + sig = host_to_target_signal(host_signum); + if (sig < 1 || sig > TARGET_NSIG) + return; +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "qemu: got signal %d\n", sig); +#endif + host_to_target_siginfo_noswap(&tinfo, info); + if (queue_signal(sig, &tinfo) == 1) { + /* interrupt the virtual CPU as soon as possible */ + cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); + } +} + +int do_sigaction(int sig, const struct target_sigaction *act, + struct target_sigaction *oact) +{ + struct emulated_sigaction *k; + struct sigaction act1; + int host_sig; + + if (sig < 1 || sig > TARGET_NSIG) + return -EINVAL; + k = &sigact_table[sig - 1]; +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n", + sig, (int)act, (int)oact); +#endif + if (oact) { + oact->_sa_handler = tswapl(k->sa._sa_handler); + oact->sa_flags = tswapl(k->sa.sa_flags); + #if !defined(TARGET_MIPS) + oact->sa_restorer = tswapl(k->sa.sa_restorer); + #endif + oact->sa_mask = k->sa.sa_mask; + } + if (act) { + k->sa._sa_handler = tswapl(act->_sa_handler); + k->sa.sa_flags = tswapl(act->sa_flags); + #if !defined(TARGET_MIPS) + k->sa.sa_restorer = tswapl(act->sa_restorer); + #endif + k->sa.sa_mask = act->sa_mask; + + /* we update the host linux signal state */ + host_sig = target_to_host_signal(sig); + if (host_sig != SIGSEGV && host_sig != SIGBUS) { + sigfillset(&act1.sa_mask); + act1.sa_flags = SA_SIGINFO; + if (k->sa.sa_flags & TARGET_SA_RESTART) + act1.sa_flags |= SA_RESTART; + /* NOTE: it is important to update the host kernel signal + ignore state to avoid getting unexpected interrupted + syscalls */ + if (k->sa._sa_handler == TARGET_SIG_IGN) { + act1.sa_sigaction = (void *)SIG_IGN; + } else if (k->sa._sa_handler == TARGET_SIG_DFL) { + act1.sa_sigaction = (void *)SIG_DFL; + } else { + act1.sa_sigaction = host_signal_handler; + } + sigaction(host_sig, &act1, NULL); + } + } + return 0; +} + +#ifndef offsetof +#define offsetof(type, field) ((size_t) &((type *)0)->field) +#endif + +static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, + const target_siginfo_t *info) +{ + tswap_siginfo(tinfo, info); + return 0; +} + +#ifdef TARGET_I386 + +/* from the Linux kernel */ + +struct target_fpreg { + uint16_t significand[4]; + uint16_t exponent; +}; + +struct target_fpxreg { + uint16_t significand[4]; + uint16_t exponent; + uint16_t padding[3]; +}; + +struct target_xmmreg { + target_ulong element[4]; +}; + +struct target_fpstate { + /* Regular FPU environment */ + target_ulong cw; + target_ulong sw; + target_ulong tag; + target_ulong ipoff; + target_ulong cssel; + target_ulong dataoff; + target_ulong datasel; + struct target_fpreg _st[8]; + uint16_t status; + uint16_t magic; /* 0xffff = regular FPU data only */ + + /* FXSR FPU environment */ + target_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */ + target_ulong mxcsr; + target_ulong reserved; + struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */ + struct target_xmmreg _xmm[8]; + target_ulong padding[56]; +}; + +#define X86_FXSR_MAGIC 0x0000 + +struct target_sigcontext { + uint16_t gs, __gsh; + uint16_t fs, __fsh; + uint16_t es, __esh; + uint16_t ds, __dsh; + target_ulong edi; + target_ulong esi; + target_ulong ebp; + target_ulong esp; + target_ulong ebx; + target_ulong edx; + target_ulong ecx; + target_ulong eax; + target_ulong trapno; + target_ulong err; + target_ulong eip; + uint16_t cs, __csh; + target_ulong eflags; + target_ulong esp_at_signal; + uint16_t ss, __ssh; + target_ulong fpstate; /* pointer */ + target_ulong oldmask; + target_ulong cr2; +}; + +typedef struct target_sigaltstack { + target_ulong ss_sp; + int ss_flags; + target_ulong ss_size; +} target_stack_t; + +struct target_ucontext { + target_ulong tuc_flags; + target_ulong tuc_link; + target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; /* mask last for extensibility */ +}; + +struct sigframe +{ + target_ulong pretcode; + int sig; + struct target_sigcontext sc; + struct target_fpstate fpstate; + target_ulong extramask[TARGET_NSIG_WORDS-1]; + char retcode[8]; +}; + +struct rt_sigframe +{ + target_ulong pretcode; + int sig; + target_ulong pinfo; + target_ulong puc; + struct target_siginfo info; + struct target_ucontext uc; + struct target_fpstate fpstate; + char retcode[8]; +}; + +/* + * Set up a signal frame. + */ + +/* XXX: save x87 state */ +static int +setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, + CPUX86State *env, unsigned long mask) +{ + int err = 0; + + err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs); + err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs); + err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es); + err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds); + err |= __put_user(env->regs[R_EDI], &sc->edi); + err |= __put_user(env->regs[R_ESI], &sc->esi); + err |= __put_user(env->regs[R_EBP], &sc->ebp); + err |= __put_user(env->regs[R_ESP], &sc->esp); + err |= __put_user(env->regs[R_EBX], &sc->ebx); + err |= __put_user(env->regs[R_EDX], &sc->edx); + err |= __put_user(env->regs[R_ECX], &sc->ecx); + err |= __put_user(env->regs[R_EAX], &sc->eax); + err |= __put_user(env->exception_index, &sc->trapno); + err |= __put_user(env->error_code, &sc->err); + err |= __put_user(env->eip, &sc->eip); + err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs); + err |= __put_user(env->eflags, &sc->eflags); + err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal); + err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss); + + cpu_x86_fsave(env, (void *)fpstate, 1); + fpstate->status = fpstate->sw; + err |= __put_user(0xffff, &fpstate->magic); + err |= __put_user(fpstate, &sc->fpstate); + + /* non-iBCS2 extensions.. */ + err |= __put_user(mask, &sc->oldmask); + err |= __put_user(env->cr[2], &sc->cr2); + return err; +} + +/* + * Determine which stack to use.. + */ + +static inline void * +get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size) +{ + unsigned long esp; + + /* Default to using normal stack */ + esp = env->regs[R_ESP]; +#if 0 + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (sas_ss_flags(esp) == 0) + esp = current->sas_ss_sp + current->sas_ss_size; + } + + /* This is the legacy signal stack switching. */ + else +#endif + if ((env->segs[R_SS].selector & 0xffff) != __USER_DS && + !(ka->sa.sa_flags & TARGET_SA_RESTORER) && + ka->sa.sa_restorer) { + esp = (unsigned long) ka->sa.sa_restorer; + } + return g2h((esp - frame_size) & -8ul); +} + +static void setup_frame(int sig, struct emulated_sigaction *ka, + target_sigset_t *set, CPUX86State *env) +{ + struct sigframe *frame; + int i, err = 0; + + frame = get_sigframe(ka, env, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + err |= __put_user((/*current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : */ sig), + &frame->sig); + if (err) + goto give_sigsegv; + + setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0]); + if (err) + goto give_sigsegv; + + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + if (__put_user(set->sig[i], &frame->extramask[i - 1])) + goto give_sigsegv; + } + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & TARGET_SA_RESTORER) { + err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); + } else { + err |= __put_user(frame->retcode, &frame->pretcode); + /* This is popl %eax ; movl $,%eax ; int $0x80 */ + err |= __put_user(0xb858, (short *)(frame->retcode+0)); + err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2)); + err |= __put_user(0x80cd, (short *)(frame->retcode+6)); + } + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + env->regs[R_ESP] = h2g(frame); + env->eip = (unsigned long) ka->sa._sa_handler; + + cpu_x86_load_seg(env, R_DS, __USER_DS); + cpu_x86_load_seg(env, R_ES, __USER_DS); + cpu_x86_load_seg(env, R_SS, __USER_DS); + cpu_x86_load_seg(env, R_CS, __USER_CS); + env->eflags &= ~TF_MASK; + + return; + +give_sigsegv: + if (sig == TARGET_SIGSEGV) + ka->sa._sa_handler = TARGET_SIG_DFL; + force_sig(TARGET_SIGSEGV /* , current */); +} + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUX86State *env) +{ + struct rt_sigframe *frame; + int i, err = 0; + + frame = get_sigframe(ka, env, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + err |= __put_user((/*current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : */sig), + &frame->sig); + err |= __put_user((target_ulong)&frame->info, &frame->pinfo); + err |= __put_user((target_ulong)&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + if (err) + goto give_sigsegv; + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.tuc_flags); + err |= __put_user(0, &frame->uc.tuc_link); + err |= __put_user(/*current->sas_ss_sp*/ 0, + &frame->uc.tuc_stack.ss_sp); + err |= __put_user(/* sas_ss_flags(regs->esp) */ 0, + &frame->uc.tuc_stack.ss_flags); + err |= __put_user(/* current->sas_ss_size */ 0, + &frame->uc.tuc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, + env, set->sig[0]); + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) + goto give_sigsegv; + } + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & TARGET_SA_RESTORER) { + err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); + } else { + err |= __put_user(frame->retcode, &frame->pretcode); + /* This is movl $,%eax ; int $0x80 */ + err |= __put_user(0xb8, (char *)(frame->retcode+0)); + err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1)); + err |= __put_user(0x80cd, (short *)(frame->retcode+5)); + } + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + env->regs[R_ESP] = (unsigned long) frame; + env->eip = (unsigned long) ka->sa._sa_handler; + + cpu_x86_load_seg(env, R_DS, __USER_DS); + cpu_x86_load_seg(env, R_ES, __USER_DS); + cpu_x86_load_seg(env, R_SS, __USER_DS); + cpu_x86_load_seg(env, R_CS, __USER_CS); + env->eflags &= ~TF_MASK; + + return; + +give_sigsegv: + if (sig == TARGET_SIGSEGV) + ka->sa._sa_handler = TARGET_SIG_DFL; + force_sig(TARGET_SIGSEGV /* , current */); +} + +static int +restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax) +{ + unsigned int err = 0; + + cpu_x86_load_seg(env, R_GS, lduw(&sc->gs)); + cpu_x86_load_seg(env, R_FS, lduw(&sc->fs)); + cpu_x86_load_seg(env, R_ES, lduw(&sc->es)); + cpu_x86_load_seg(env, R_DS, lduw(&sc->ds)); + + env->regs[R_EDI] = ldl(&sc->edi); + env->regs[R_ESI] = ldl(&sc->esi); + env->regs[R_EBP] = ldl(&sc->ebp); + env->regs[R_ESP] = ldl(&sc->esp); + env->regs[R_EBX] = ldl(&sc->ebx); + env->regs[R_EDX] = ldl(&sc->edx); + env->regs[R_ECX] = ldl(&sc->ecx); + env->eip = ldl(&sc->eip); + + cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3); + cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3); + + { + unsigned int tmpflags; + tmpflags = ldl(&sc->eflags); + env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); + // regs->orig_eax = -1; /* disable syscall checks */ + } + + { + struct _fpstate * buf; + buf = (void *)ldl(&sc->fpstate); + if (buf) { +#if 0 + if (verify_area(VERIFY_READ, buf, sizeof(*buf))) + goto badframe; +#endif + cpu_x86_frstor(env, (void *)buf, 1); + } + } + + *peax = ldl(&sc->eax); + return err; +#if 0 +badframe: + return 1; +#endif +} + +long do_sigreturn(CPUX86State *env) +{ + struct sigframe *frame = (struct sigframe *)g2h(env->regs[R_ESP] - 8); + target_sigset_t target_set; + sigset_t set; + int eax, i; + +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "do_sigreturn\n"); +#endif + /* set blocked signals */ + if (__get_user(target_set.sig[0], &frame->sc.oldmask)) + goto badframe; + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + if (__get_user(target_set.sig[i], &frame->extramask[i - 1])) + goto badframe; + } + + target_to_host_sigset_internal(&set, &target_set); + sigprocmask(SIG_SETMASK, &set, NULL); + + /* restore registers */ + if (restore_sigcontext(env, &frame->sc, &eax)) + goto badframe; + return eax; + +badframe: + force_sig(TARGET_SIGSEGV); + return 0; +} + +long do_rt_sigreturn(CPUX86State *env) +{ + struct rt_sigframe *frame = (struct rt_sigframe *)g2h(env->regs[R_ESP] - 4); + sigset_t set; + // stack_t st; + int eax; + +#if 0 + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; +#endif + target_to_host_sigset(&set, &frame->uc.tuc_sigmask); + sigprocmask(SIG_SETMASK, &set, NULL); + + if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax)) + goto badframe; + +#if 0 + if (__copy_from_user(&st, &frame->uc.tuc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, regs->esp); +#endif + return eax; + +badframe: + force_sig(TARGET_SIGSEGV); + return 0; +} + +#elif defined(TARGET_ARM) + +struct target_sigcontext { + target_ulong trap_no; + target_ulong error_code; + target_ulong oldmask; + target_ulong arm_r0; + target_ulong arm_r1; + target_ulong arm_r2; + target_ulong arm_r3; + target_ulong arm_r4; + target_ulong arm_r5; + target_ulong arm_r6; + target_ulong arm_r7; + target_ulong arm_r8; + target_ulong arm_r9; + target_ulong arm_r10; + target_ulong arm_fp; + target_ulong arm_ip; + target_ulong arm_sp; + target_ulong arm_lr; + target_ulong arm_pc; + target_ulong arm_cpsr; + target_ulong fault_address; +}; + +typedef struct target_sigaltstack { + target_ulong ss_sp; + int ss_flags; + target_ulong ss_size; +} target_stack_t; + +struct target_ucontext { + target_ulong tuc_flags; + target_ulong tuc_link; + target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; /* mask last for extensibility */ +}; + +struct sigframe +{ + struct target_sigcontext sc; + target_ulong extramask[TARGET_NSIG_WORDS-1]; + target_ulong retcode; +}; + +struct rt_sigframe +{ + struct target_siginfo *pinfo; + void *puc; + struct target_siginfo info; + struct target_ucontext uc; + target_ulong retcode; +}; + +#define TARGET_CONFIG_CPU_32 1 + +/* + * For ARM syscalls, we encode the syscall number into the instruction. + */ +#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE)) +#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE)) + +/* + * For Thumb syscalls, we pass the syscall number via r7. We therefore + * need two 16-bit instructions. + */ +#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn)) +#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn)) + +static const target_ulong retcodes[4] = { + SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, + SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN +}; + + +#define __put_user_error(x,p,e) __put_user(x, p) +#define __get_user_error(x,p,e) __get_user(x, p) + +static inline int valid_user_regs(CPUState *regs) +{ + return 1; +} + +static int +setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ + CPUState *env, unsigned long mask) +{ + int err = 0; + + __put_user_error(env->regs[0], &sc->arm_r0, err); + __put_user_error(env->regs[1], &sc->arm_r1, err); + __put_user_error(env->regs[2], &sc->arm_r2, err); + __put_user_error(env->regs[3], &sc->arm_r3, err); + __put_user_error(env->regs[4], &sc->arm_r4, err); + __put_user_error(env->regs[5], &sc->arm_r5, err); + __put_user_error(env->regs[6], &sc->arm_r6, err); + __put_user_error(env->regs[7], &sc->arm_r7, err); + __put_user_error(env->regs[8], &sc->arm_r8, err); + __put_user_error(env->regs[9], &sc->arm_r9, err); + __put_user_error(env->regs[10], &sc->arm_r10, err); + __put_user_error(env->regs[11], &sc->arm_fp, err); + __put_user_error(env->regs[12], &sc->arm_ip, err); + __put_user_error(env->regs[13], &sc->arm_sp, err); + __put_user_error(env->regs[14], &sc->arm_lr, err); + __put_user_error(env->regs[15], &sc->arm_pc, err); +#ifdef TARGET_CONFIG_CPU_32 + __put_user_error(cpsr_read(env), &sc->arm_cpsr, err); +#endif + + __put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err); + __put_user_error(/* current->thread.error_code */ 0, &sc->error_code, err); + __put_user_error(/* current->thread.address */ 0, &sc->fault_address, err); + __put_user_error(mask, &sc->oldmask, err); + + return err; +} + +static inline void * +get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) +{ + unsigned long sp = regs->regs[13]; + +#if 0 + /* + * This is the X/Open sanctioned signal stack switching. + */ + if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; +#endif + /* + * ATPCS B01 mandates 8-byte alignment + */ + return g2h((sp - framesize) & ~7); +} + +static int +setup_return(CPUState *env, struct emulated_sigaction *ka, + target_ulong *rc, void *frame, int usig) +{ + target_ulong handler = (target_ulong)ka->sa._sa_handler; + target_ulong retcode; + int thumb = 0; +#if defined(TARGET_CONFIG_CPU_32) +#if 0 + target_ulong cpsr = env->cpsr; + + /* + * Maybe we need to deliver a 32-bit signal to a 26-bit task. + */ + if (ka->sa.sa_flags & SA_THIRTYTWO) + cpsr = (cpsr & ~MODE_MASK) | USR_MODE; + +#ifdef CONFIG_ARM_THUMB + if (elf_hwcap & HWCAP_THUMB) { + /* + * The LSB of the handler determines if we're going to + * be using THUMB or ARM mode for this signal handler. + */ + thumb = handler & 1; + + if (thumb) + cpsr |= T_BIT; + else + cpsr &= ~T_BIT; + } +#endif +#endif +#endif /* TARGET_CONFIG_CPU_32 */ + + if (ka->sa.sa_flags & TARGET_SA_RESTORER) { + retcode = (target_ulong)ka->sa.sa_restorer; + } else { + unsigned int idx = thumb; + + if (ka->sa.sa_flags & TARGET_SA_SIGINFO) + idx += 2; + + if (__put_user(retcodes[idx], rc)) + return 1; +#if 0 + flush_icache_range((target_ulong)rc, + (target_ulong)(rc + 1)); +#endif + retcode = ((target_ulong)rc) + thumb; + } + + env->regs[0] = usig; + env->regs[13] = h2g(frame); + env->regs[14] = retcode; + env->regs[15] = handler & (thumb ? ~1 : ~3); + +#if 0 +#ifdef TARGET_CONFIG_CPU_32 + env->cpsr = cpsr; +#endif +#endif + + return 0; +} + +static void setup_frame(int usig, struct emulated_sigaction *ka, + target_sigset_t *set, CPUState *regs) +{ + struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame)); + int i, err = 0; + + err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); + + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + if (__put_user(set->sig[i], &frame->extramask[i - 1])) + return; + } + + if (err == 0) + err = setup_return(regs, ka, &frame->retcode, frame, usig); + // return err; +} + +static void setup_rt_frame(int usig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame)); + int i, err = 0; + + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + return /* 1 */; + + __put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err); + __put_user_error(&frame->uc, (target_ulong *)&frame->puc, err); + err |= copy_siginfo_to_user(&frame->info, info); + + /* Clear all the bits of the ucontext we don't use. */ + memset(&frame->uc, 0, offsetof(struct target_ucontext, tuc_mcontext)); + + err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/ + env, set->sig[0]); + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) + return; + } + + if (err == 0) + err = setup_return(env, ka, &frame->retcode, frame, usig); + + if (err == 0) { + /* + * For realtime signals we must also set the second and third + * arguments for the signal handler. + * -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06 + */ + env->regs[1] = (target_ulong)frame->pinfo; + env->regs[2] = (target_ulong)frame->puc; + } + + // return err; +} + +static int +restore_sigcontext(CPUState *env, struct target_sigcontext *sc) +{ + int err = 0; + uint32_t cpsr; + + __get_user_error(env->regs[0], &sc->arm_r0, err); + __get_user_error(env->regs[1], &sc->arm_r1, err); + __get_user_error(env->regs[2], &sc->arm_r2, err); + __get_user_error(env->regs[3], &sc->arm_r3, err); + __get_user_error(env->regs[4], &sc->arm_r4, err); + __get_user_error(env->regs[5], &sc->arm_r5, err); + __get_user_error(env->regs[6], &sc->arm_r6, err); + __get_user_error(env->regs[7], &sc->arm_r7, err); + __get_user_error(env->regs[8], &sc->arm_r8, err); + __get_user_error(env->regs[9], &sc->arm_r9, err); + __get_user_error(env->regs[10], &sc->arm_r10, err); + __get_user_error(env->regs[11], &sc->arm_fp, err); + __get_user_error(env->regs[12], &sc->arm_ip, err); + __get_user_error(env->regs[13], &sc->arm_sp, err); + __get_user_error(env->regs[14], &sc->arm_lr, err); + __get_user_error(env->regs[15], &sc->arm_pc, err); +#ifdef TARGET_CONFIG_CPU_32 + __get_user_error(cpsr, &sc->arm_cpsr, err); + cpsr_write(env, cpsr, 0xffffffff); +#endif + + err |= !valid_user_regs(env); + + return err; +} + +long do_sigreturn(CPUState *env) +{ + struct sigframe *frame; + target_sigset_t set; + sigset_t host_set; + int i; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (env->regs[13] & 7) + goto badframe; + + frame = (struct sigframe *)g2h(env->regs[13]); + +#if 0 + if (verify_area(VERIFY_READ, frame, sizeof (*frame))) + goto badframe; +#endif + if (__get_user(set.sig[0], &frame->sc.oldmask)) + goto badframe; + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + if (__get_user(set.sig[i], &frame->extramask[i - 1])) + goto badframe; + } + + target_to_host_sigset_internal(&host_set, &set); + sigprocmask(SIG_SETMASK, &host_set, NULL); + + if (restore_sigcontext(env, &frame->sc)) + goto badframe; + +#if 0 + /* Send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt(current)) + send_sig(SIGTRAP, current, 1); +#endif + return env->regs[0]; + +badframe: + force_sig(SIGSEGV /* , current */); + return 0; +} + +long do_rt_sigreturn(CPUState *env) +{ + struct rt_sigframe *frame; + sigset_t host_set; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (env->regs[13] & 7) + goto badframe; + + frame = (struct rt_sigframe *)env->regs[13]; + +#if 0 + if (verify_area(VERIFY_READ, frame, sizeof (*frame))) + goto badframe; +#endif + target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask); + sigprocmask(SIG_SETMASK, &host_set, NULL); + + if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) + goto badframe; + +#if 0 + /* Send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt(current)) + send_sig(SIGTRAP, current, 1); +#endif + return env->regs[0]; + +badframe: + force_sig(SIGSEGV /* , current */); + return 0; +} + +#elif defined(TARGET_SPARC) + +#define __SUNOS_MAXWIN 31 + +/* This is what SunOS does, so shall I. */ +struct target_sigcontext { + target_ulong sigc_onstack; /* state to restore */ + + target_ulong sigc_mask; /* sigmask to restore */ + target_ulong sigc_sp; /* stack pointer */ + target_ulong sigc_pc; /* program counter */ + target_ulong sigc_npc; /* next program counter */ + target_ulong sigc_psr; /* for condition codes etc */ + target_ulong sigc_g1; /* User uses these two registers */ + target_ulong sigc_o0; /* within the trampoline code. */ + + /* Now comes information regarding the users window set + * at the time of the signal. + */ + target_ulong sigc_oswins; /* outstanding windows */ + + /* stack ptrs for each regwin buf */ + char *sigc_spbuf[__SUNOS_MAXWIN]; + + /* Windows to restore after signal */ + struct { + target_ulong locals[8]; + target_ulong ins[8]; + } sigc_wbuf[__SUNOS_MAXWIN]; +}; +/* A Sparc stack frame */ +struct sparc_stackf { + target_ulong locals[8]; + target_ulong ins[6]; + struct sparc_stackf *fp; + target_ulong callers_pc; + char *structptr; + target_ulong xargs[6]; + target_ulong xxargs[1]; +}; + +typedef struct { + struct { + target_ulong psr; + target_ulong pc; + target_ulong npc; + target_ulong y; + target_ulong u_regs[16]; /* globals and ins */ + } si_regs; + int si_mask; +} __siginfo_t; + +typedef struct { + unsigned long si_float_regs [32]; + unsigned long si_fsr; + unsigned long si_fpqdepth; + struct { + unsigned long *insn_addr; + unsigned long insn; + } si_fpqueue [16]; +} qemu_siginfo_fpu_t; + + +struct target_signal_frame { + struct sparc_stackf ss; + __siginfo_t info; + qemu_siginfo_fpu_t *fpu_save; + target_ulong insns[2] __attribute__ ((aligned (8))); + target_ulong extramask[TARGET_NSIG_WORDS - 1]; + target_ulong extra_size; /* Should be 0 */ + qemu_siginfo_fpu_t fpu_state; +}; +struct target_rt_signal_frame { + struct sparc_stackf ss; + siginfo_t info; + target_ulong regs[20]; + sigset_t mask; + qemu_siginfo_fpu_t *fpu_save; + unsigned int insns[2]; + stack_t stack; + unsigned int extra_size; /* Should be 0 */ + qemu_siginfo_fpu_t fpu_state; +}; + +#define UREG_O0 16 +#define UREG_O6 22 +#define UREG_I0 0 +#define UREG_I1 1 +#define UREG_I2 2 +#define UREG_I6 6 +#define UREG_I7 7 +#define UREG_L0 8 +#define UREG_FP UREG_I6 +#define UREG_SP UREG_O6 + +static inline void *get_sigframe(struct emulated_sigaction *sa, CPUState *env, unsigned long framesize) +{ + unsigned long sp; + + sp = env->regwptr[UREG_FP]; +#if 0 + + /* This is the X/Open sanctioned signal stack switching. */ + if (sa->sa_flags & TARGET_SA_ONSTACK) { + if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7)) + sp = current->sas_ss_sp + current->sas_ss_size; + } +#endif + return g2h(sp - framesize); +} + +static int +setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask) +{ + int err = 0, i; + + err |= __put_user(env->psr, &si->si_regs.psr); + err |= __put_user(env->pc, &si->si_regs.pc); + err |= __put_user(env->npc, &si->si_regs.npc); + err |= __put_user(env->y, &si->si_regs.y); + for (i=0; i < 8; i++) { + err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]); + } + for (i=0; i < 8; i++) { + err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]); + } + err |= __put_user(mask, &si->si_mask); + return err; +} + +#if 0 +static int +setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ + CPUState *env, unsigned long mask) +{ + int err = 0; + + err |= __put_user(mask, &sc->sigc_mask); + err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp); + err |= __put_user(env->pc, &sc->sigc_pc); + err |= __put_user(env->npc, &sc->sigc_npc); + err |= __put_user(env->psr, &sc->sigc_psr); + err |= __put_user(env->gregs[1], &sc->sigc_g1); + err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0); + + return err; +} +#endif +#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7))) + +static void setup_frame(int sig, struct emulated_sigaction *ka, + target_sigset_t *set, CPUState *env) +{ + struct target_signal_frame *sf; + int sigframe_size, err, i; + + /* 1. Make sure everything is clean */ + //synchronize_user_stack(); + + sigframe_size = NF_ALIGNEDSZ; + + sf = (struct target_signal_frame *) + get_sigframe(ka, env, sigframe_size); + + //fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); +#if 0 + if (invalid_frame_pointer(sf, sigframe_size)) + goto sigill_and_return; +#endif + /* 2. Save the current process state */ + err = setup___siginfo(&sf->info, env, set->sig[0]); + err |= __put_user(0, &sf->extra_size); + + //err |= save_fpu_state(regs, &sf->fpu_state); + //err |= __put_user(&sf->fpu_state, &sf->fpu_save); + + err |= __put_user(set->sig[0], &sf->info.si_mask); + for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { + err |= __put_user(set->sig[i + 1], &sf->extramask[i]); + } + + for (i = 0; i < 8; i++) { + err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]); + } + for (i = 0; i < 8; i++) { + err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]); + } + if (err) + goto sigsegv; + + /* 3. signal handler back-trampoline and parameters */ + env->regwptr[UREG_FP] = h2g(sf); + env->regwptr[UREG_I0] = sig; + env->regwptr[UREG_I1] = h2g(&sf->info); + env->regwptr[UREG_I2] = h2g(&sf->info); + + /* 4. signal handler */ + env->pc = (unsigned long) ka->sa._sa_handler; + env->npc = (env->pc + 4); + /* 5. return to kernel instructions */ + if (ka->sa.sa_restorer) + env->regwptr[UREG_I7] = (unsigned long)ka->sa.sa_restorer; + else { + env->regwptr[UREG_I7] = h2g(&(sf->insns[0]) - 2); + + /* mov __NR_sigreturn, %g1 */ + err |= __put_user(0x821020d8, &sf->insns[0]); + + /* t 0x10 */ + err |= __put_user(0x91d02010, &sf->insns[1]); + if (err) + goto sigsegv; + + /* Flush instruction space. */ + //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); + // tb_flush(env); + } + return; + + //sigill_and_return: + force_sig(TARGET_SIGILL); +sigsegv: + //fprintf(stderr, "force_sig\n"); + force_sig(TARGET_SIGSEGV); +} +static inline int +restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu) +{ + int err; +#if 0 +#ifdef CONFIG_SMP + if (current->flags & PF_USEDFPU) + regs->psr &= ~PSR_EF; +#else + if (current == last_task_used_math) { + last_task_used_math = 0; + regs->psr &= ~PSR_EF; + } +#endif + current->used_math = 1; + current->flags &= ~PF_USEDFPU; +#endif +#if 0 + if (verify_area (VERIFY_READ, fpu, sizeof(*fpu))) + return -EFAULT; +#endif + + err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0], + (sizeof(unsigned long) * 32)); + err |= __get_user(env->fsr, &fpu->si_fsr); +#if 0 + err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth); + if (current->thread.fpqdepth != 0) + err |= __copy_from_user(¤t->thread.fpqueue[0], + &fpu->si_fpqueue[0], + ((sizeof(unsigned long) + + (sizeof(unsigned long *)))*16)); +#endif + return err; +} + + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_rt_frame: not implemented\n"); +} + +long do_sigreturn(CPUState *env) +{ + struct target_signal_frame *sf; + uint32_t up_psr, pc, npc; + target_sigset_t set; + sigset_t host_set; + target_ulong fpu_save; + int err, i; + + sf = (struct target_signal_frame *)g2h(env->regwptr[UREG_FP]); +#if 0 + fprintf(stderr, "sigreturn\n"); + fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]); +#endif + //cpu_dump_state(env, stderr, fprintf, 0); + + /* 1. Make sure we are not getting garbage from the user */ +#if 0 + if (verify_area (VERIFY_READ, sf, sizeof (*sf))) + goto segv_and_exit; +#endif + + if (((uint) sf) & 3) + goto segv_and_exit; + + err = __get_user(pc, &sf->info.si_regs.pc); + err |= __get_user(npc, &sf->info.si_regs.npc); + + if ((pc | npc) & 3) + goto segv_and_exit; + + /* 2. Restore the state */ + err |= __get_user(up_psr, &sf->info.si_regs.psr); + + /* User can only change condition codes and FPU enabling in %psr. */ + env->psr = (up_psr & (PSR_ICC /* | PSR_EF */)) + | (env->psr & ~(PSR_ICC /* | PSR_EF */)); + + env->pc = pc; + env->npc = npc; + err |= __get_user(env->y, &sf->info.si_regs.y); + for (i=0; i < 8; i++) { + err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]); + } + for (i=0; i < 8; i++) { + err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]); + } + + err |= __get_user(fpu_save, (target_ulong *)&sf->fpu_save); + + //if (fpu_save) + // err |= restore_fpu_state(env, fpu_save); + + /* This is pretty much atomic, no amount locking would prevent + * the races which exist anyways. + */ + err |= __get_user(set.sig[0], &sf->info.si_mask); + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + err |= (__get_user(set.sig[i], &sf->extramask[i - 1])); + } + + target_to_host_sigset_internal(&host_set, &set); + sigprocmask(SIG_SETMASK, &host_set, NULL); + + if (err) + goto segv_and_exit; + + return env->regwptr[0]; + +segv_and_exit: + force_sig(TARGET_SIGSEGV); +} + +long do_rt_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_rt_sigreturn: not implemented\n"); + return -ENOSYS; +} + +#elif defined(TARGET_MIPS) + +struct target_sigcontext { + uint32_t sc_regmask; /* Unused */ + uint32_t sc_status; + uint64_t sc_pc; + uint64_t sc_regs[32]; + uint64_t sc_fpregs[32]; + uint32_t sc_ownedfp; /* Unused */ + uint32_t sc_fpc_csr; + uint32_t sc_fpc_eir; /* Unused */ + uint32_t sc_used_math; + uint32_t sc_dsp; /* dsp status, was sc_ssflags */ + uint64_t sc_mdhi; + uint64_t sc_mdlo; + target_ulong sc_hi1; /* Was sc_cause */ + target_ulong sc_lo1; /* Was sc_badvaddr */ + target_ulong sc_hi2; /* Was sc_sigset[4] */ + target_ulong sc_lo2; + target_ulong sc_hi3; + target_ulong sc_lo3; +}; + +struct sigframe { + uint32_t sf_ass[4]; /* argument save space for o32 */ + uint32_t sf_code[2]; /* signal trampoline */ + struct target_sigcontext sf_sc; + target_sigset_t sf_mask; +}; + +/* Install trampoline to jump back from signal handler */ +static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall) +{ + int err; + + /* + * Set up the return code ... + * + * li v0, __NR__foo_sigreturn + * syscall + */ + + err = __put_user(0x24020000 + syscall, tramp + 0); + err |= __put_user(0x0000000c , tramp + 1); + /* flush_cache_sigtramp((unsigned long) tramp); */ + return err; +} + +static inline int +setup_sigcontext(CPUState *regs, struct target_sigcontext *sc) +{ + int err = 0; + + err |= __put_user(regs->PC, &sc->sc_pc); + + #define save_gp_reg(i) do { \ + err |= __put_user(regs->gpr[i], &sc->sc_regs[i]); \ + } while(0) + __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); + save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); + save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); + save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); + save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); + save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); + save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); + save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); + save_gp_reg(31); + #undef save_gp_reg + + err |= __put_user(regs->HI, &sc->sc_mdhi); + err |= __put_user(regs->LO, &sc->sc_mdlo); + + /* Not used yet, but might be useful if we ever have DSP suppport */ +#if 0 + if (cpu_has_dsp) { + err |= __put_user(mfhi1(), &sc->sc_hi1); + err |= __put_user(mflo1(), &sc->sc_lo1); + err |= __put_user(mfhi2(), &sc->sc_hi2); + err |= __put_user(mflo2(), &sc->sc_lo2); + err |= __put_user(mfhi3(), &sc->sc_hi3); + err |= __put_user(mflo3(), &sc->sc_lo3); + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + } + /* same with 64 bit */ + #ifdef CONFIG_64BIT + err |= __put_user(regs->hi, &sc->sc_hi[0]); + err |= __put_user(regs->lo, &sc->sc_lo[0]); + if (cpu_has_dsp) { + err |= __put_user(mfhi1(), &sc->sc_hi[1]); + err |= __put_user(mflo1(), &sc->sc_lo[1]); + err |= __put_user(mfhi2(), &sc->sc_hi[2]); + err |= __put_user(mflo2(), &sc->sc_lo[2]); + err |= __put_user(mfhi3(), &sc->sc_hi[3]); + err |= __put_user(mflo3(), &sc->sc_lo[3]); + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + } + #endif + + + #endif + + + #if 0 + err |= __put_user(!!used_math(), &sc->sc_used_math); + + if (!used_math()) + goto out; + + /* + * Save FPU state to signal context. Signal handler will "inherit" + * current FPU state. + */ + preempt_disable(); + + if (!is_fpu_owner()) { + own_fpu(); + restore_fp(current); + } + err |= save_fp_context(sc); + + preempt_enable(); + out: +#endif + return err; +} + +static inline int +restore_sigcontext(CPUState *regs, struct target_sigcontext *sc) +{ + int err = 0; + + err |= __get_user(regs->CP0_EPC, &sc->sc_pc); + + err |= __get_user(regs->HI, &sc->sc_mdhi); + err |= __get_user(regs->LO, &sc->sc_mdlo); + + #define restore_gp_reg(i) do { \ + err |= __get_user(regs->gpr[i], &sc->sc_regs[i]); \ + } while(0) + restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); + restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); + restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); + restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); + restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); + restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); + restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); + restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); + restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); + restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); + restore_gp_reg(31); + #undef restore_gp_reg + +#if 0 + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); + err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); + err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } + #ifdef CONFIG_64BIT + err |= __get_user(regs->hi, &sc->sc_hi[0]); + err |= __get_user(regs->lo, &sc->sc_lo[0]); + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg); + err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg); + err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } + #endif + + err |= __get_user(used_math, &sc->sc_used_math); + conditional_used_math(used_math); + + preempt_disable(); + + if (used_math()) { + /* restore fpu context if we have used it before */ + own_fpu(); + err |= restore_fp_context(sc); + } else { + /* signal handler may have used FPU. Give it up. */ + lose_fpu(); + } + + preempt_enable(); +#endif + return err; +} +/* + * Determine which stack to use.. + */ +static inline void * +get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) +{ + unsigned long sp; + + /* Default to using normal stack */ + sp = regs->gpr[29]; + + /* + * FPU emulator may have it's own trampoline active just + * above the user stack, 16-bytes before the next lowest + * 16 byte boundary. Try to avoid trashing it. + */ + sp -= 32; + +#if 0 + /* This is the X/Open sanctioned signal stack switching. */ + if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) + sp = current->sas_ss_sp + current->sas_ss_size; +#endif + + return g2h((sp - frame_size) & ~7); +} + +static void setup_frame(int sig, struct emulated_sigaction * ka, + target_sigset_t *set, CPUState *regs) +{ + struct sigframe *frame; + int i; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + goto give_sigsegv; + + install_sigtramp(frame->sf_code, TARGET_NR_sigreturn); + + if(setup_sigcontext(regs, &frame->sf_sc)) + goto give_sigsegv; + + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + if(__put_user(set->sig[i], &frame->sf_mask.sig[i])) + goto give_sigsegv; + } + + /* + * Arguments to signal handler: + * + * a0 = signal number + * a1 = 0 (should be cause) + * a2 = pointer to struct sigcontext + * + * $25 and PC point to the signal handler, $29 points to the + * struct sigframe. + */ + regs->gpr[ 4] = sig; + regs->gpr[ 5] = 0; + regs->gpr[ 6] = h2g(&frame->sf_sc); + regs->gpr[29] = h2g(frame); + regs->gpr[31] = h2g(frame->sf_code); + /* The original kernel code sets CP0_EPC to the handler + * since it returns to userland using eret + * we cannot do this here, and we must set PC directly */ + regs->PC = regs->gpr[25] = ka->sa._sa_handler; + return; + +give_sigsegv: + force_sig(TARGET_SIGSEGV/*, current*/); + return; +} + +long do_sigreturn(CPUState *regs) +{ + struct sigframe *frame; + sigset_t blocked; + target_sigset_t target_set; + int i; + +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "do_sigreturn\n"); +#endif + frame = (struct sigframe *) regs->gpr[29]; + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i])) + goto badframe; + } + + target_to_host_sigset_internal(&blocked, &target_set); + sigprocmask(SIG_SETMASK, &blocked, NULL); + + if (restore_sigcontext(regs, &frame->sf_sc)) + goto badframe; + +#if 0 + /* + * Don't let your children do this ... + */ + __asm__ __volatile__( + "move\t$29, %0\n\t" + "j\tsyscall_exit" + :/* no outputs */ + :"r" (®s)); + /* Unreached */ +#endif + + regs->PC = regs->CP0_EPC; + /* I am not sure this is right, but it seems to work + * maybe a problem with nested signals ? */ + regs->CP0_EPC = 0; + return 0; + +badframe: + force_sig(TARGET_SIGSEGV/*, current*/); + return 0; + +} + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_rt_frame: not implemented\n"); +} + +long do_rt_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_rt_sigreturn: not implemented\n"); + return -ENOSYS; +} + +#else + +static void setup_frame(int sig, struct emulated_sigaction *ka, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_frame: not implemented\n"); +} + +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "setup_rt_frame: not implemented\n"); +} + +long do_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_sigreturn: not implemented\n"); + return -ENOSYS; +} + +long do_rt_sigreturn(CPUState *env) +{ + fprintf(stderr, "do_rt_sigreturn: not implemented\n"); + return -ENOSYS; +} + +#endif + +void process_pending_signals(void *cpu_env) +{ + int sig; + target_ulong handler; + sigset_t set, old_set; + target_sigset_t target_old_set; + struct emulated_sigaction *k; + struct sigqueue *q; + + if (!signal_pending) + return; + + k = sigact_table; + for(sig = 1; sig <= TARGET_NSIG; sig++) { + if (k->pending) + goto handle_signal; + k++; + } + /* if no signal is pending, just return */ + signal_pending = 0; + return; + + handle_signal: +#ifdef DEBUG_SIGNAL + fprintf(stderr, "qemu: process signal %d\n", sig); +#endif + /* dequeue signal */ + q = k->first; + k->first = q->next; + if (!k->first) + k->pending = 0; + + sig = gdb_handlesig (cpu_env, sig); + if (!sig) { + fprintf (stderr, "Lost signal\n"); + abort(); + } + + handler = k->sa._sa_handler; + if (handler == TARGET_SIG_DFL) { + /* default handler : ignore some signal. The other are fatal */ + if (sig != TARGET_SIGCHLD && + sig != TARGET_SIGURG && + sig != TARGET_SIGWINCH) { + force_sig(sig); + } + } else if (handler == TARGET_SIG_IGN) { + /* ignore sig */ + } else if (handler == TARGET_SIG_ERR) { + force_sig(sig); + } else { + /* compute the blocked signals during the handler execution */ + target_to_host_sigset(&set, &k->sa.sa_mask); + /* SA_NODEFER indicates that the current signal should not be + blocked during the handler */ + if (!(k->sa.sa_flags & TARGET_SA_NODEFER)) + sigaddset(&set, target_to_host_signal(sig)); + + /* block signals in the handler using Linux */ + sigprocmask(SIG_BLOCK, &set, &old_set); + /* save the previous blocked signal state to restore it at the + end of the signal execution (see do_sigreturn) */ + host_to_target_sigset_internal(&target_old_set, &old_set); + + /* if the CPU is in VM86 mode, we restore the 32 bit values */ +#ifdef TARGET_I386 + { + CPUX86State *env = cpu_env; + if (env->eflags & VM_MASK) + save_v86_state(env); + } +#endif + /* prepare the stack frame of the virtual CPU */ + if (k->sa.sa_flags & TARGET_SA_SIGINFO) + setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env); + else + setup_frame(sig, k, &target_old_set, cpu_env); + if (k->sa.sa_flags & TARGET_SA_RESETHAND) + k->sa._sa_handler = TARGET_SIG_DFL; + } + if (q != &k->info) + free_sigqueue(q); +} + + diff --git a/linux-user/socket.h b/linux-user/socket.h new file mode 100644 index 0000000..f13ca45 --- /dev/null +++ b/linux-user/socket.h @@ -0,0 +1,138 @@ + +#if defined(TARGET_MIPS) + // MIPS special values for constants + + /* + * For setsockopt(2) + * + * This defines are ABI conformant as far as Linux supports these ... + */ + #define TARGET_SOL_SOCKET 0xffff + + #define TARGET_SO_DEBUG 0x0001 /* Record debugging information. */ + #define TARGET_SO_REUSEADDR 0x0004 /* Allow reuse of local addresses. */ + #define TARGET_SO_KEEPALIVE 0x0008 /* Keep connections alive and send + SIGPIPE when they die. */ + #define TARGET_SO_DONTROUTE 0x0010 /* Don't do local routing. */ + #define TARGET_SO_BROADCAST 0x0020 /* Allow transmission of + broadcast messages. */ + #define TARGET_SO_LINGER 0x0080 /* Block on close of a reliable + socket to transmit pending data. */ + #define TARGET_SO_OOBINLINE 0x0100 /* Receive out-of-band data in-band. */ + #if 0 + To add: #define TARGET_SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ + #endif + + #define TARGET_SO_TYPE 0x1008 /* Compatible name for SO_STYLE. */ + #define TARGET_SO_STYLE SO_TYPE /* Synonym */ + #define TARGET_SO_ERROR 0x1007 /* get error status and clear */ + #define TARGET_SO_SNDBUF 0x1001 /* Send buffer size. */ + #define TARGET_SO_RCVBUF 0x1002 /* Receive buffer. */ + #define TARGET_SO_SNDLOWAT 0x1003 /* send low-water mark */ + #define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */ + #define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */ + #define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */ + #define TARGET_SO_ACCEPTCONN 0x1009 + + /* linux-specific, might as well be the same as on i386 */ + #define TARGET_SO_NO_CHECK 11 + #define TARGET_SO_PRIORITY 12 + #define TARGET_SO_BSDCOMPAT 14 + + #define TARGET_SO_PASSCRED 17 + #define TARGET_SO_PEERCRED 18 + + /* Security levels - as per NRL IPv6 - don't actually do anything */ + #define TARGET_SO_SECURITY_AUTHENTICATION 22 + #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23 + #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24 + + #define TARGET_SO_BINDTODEVICE 25 + + /* Socket filtering */ + #define TARGET_SO_ATTACH_FILTER 26 + #define TARGET_SO_DETACH_FILTER 27 + + #define TARGET_SO_PEERNAME 28 + #define TARGET_SO_TIMESTAMP 29 + #define SCM_TIMESTAMP SO_TIMESTAMP + + #define TARGET_SO_PEERSEC 30 + #define TARGET_SO_SNDBUFFORCE 31 + #define TARGET_SO_RCVBUFFORCE 33 + + /** sock_type - Socket types + * + * Please notice that for binary compat reasons MIPS has to + * override the enum sock_type in include/linux/net.h, so + * we define ARCH_HAS_SOCKET_TYPES here. + * + * @SOCK_DGRAM - datagram (conn.less) socket + * @SOCK_STREAM - stream (connection) socket + * @SOCK_RAW - raw socket + * @SOCK_RDM - reliably-delivered message + * @SOCK_SEQPACKET - sequential packet socket + * @SOCK_PACKET - linux specific way of getting packets at the dev level. + * For writing rarp and other similar things on the user level. + */ + enum sock_type { + TARGET_SOCK_DGRAM = 1, + TARGET_SOCK_STREAM = 2, + TARGET_SOCK_RAW = 3, + TARGET_SOCK_RDM = 4, + TARGET_SOCK_SEQPACKET = 5, + TARGET_SOCK_DCCP = 6, + TARGET_SOCK_PACKET = 10, + }; + + #define TARGET_SOCK_MAX (SOCK_PACKET + 1) + +#else + + /* For setsockopt(2) */ + #define TARGET_SOL_SOCKET 1 + + #define TARGET_SO_DEBUG 1 + #define TARGET_SO_REUSEADDR 2 + #define TARGET_SO_TYPE 3 + #define TARGET_SO_ERROR 4 + #define TARGET_SO_DONTROUTE 5 + #define TARGET_SO_BROADCAST 6 + #define TARGET_SO_SNDBUF 7 + #define TARGET_SO_RCVBUF 8 + #define TARGET_SO_SNDBUFFORCE 32 + #define TARGET_SO_RCVBUFFORCE 33 + #define TARGET_SO_KEEPALIVE 9 + #define TARGET_SO_OOBINLINE 10 + #define TARGET_SO_NO_CHECK 11 + #define TARGET_SO_PRIORITY 12 + #define TARGET_SO_LINGER 13 + #define TARGET_SO_BSDCOMPAT 14 + /* To add :#define TARGET_SO_REUSEPORT 15 */ + #define TARGET_SO_PASSCRED 16 + #define TARGET_SO_PEERCRED 17 + #define TARGET_SO_RCVLOWAT 18 + #define TARGET_SO_SNDLOWAT 19 + #define TARGET_SO_RCVTIMEO 20 + #define TARGET_SO_SNDTIMEO 21 + + /* Security levels - as per NRL IPv6 - don't actually do anything */ + #define TARGET_SO_SECURITY_AUTHENTICATION 22 + #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23 + #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24 + + #define TARGET_SO_BINDTODEVICE 25 + + /* Socket filtering */ + #define TARGET_SO_ATTACH_FILTER 26 + #define TARGET_SO_DETACH_FILTER 27 + + #define TARGET_SO_PEERNAME 28 + #define TARGET_SO_TIMESTAMP 29 + #define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP + + #define TARGET_SO_ACCEPTCONN 30 + + #define TARGET_SO_PEERSEC 31 + +#endif diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h new file mode 100644 index 0000000..5be90fa --- /dev/null +++ b/linux-user/sparc/syscall.h @@ -0,0 +1,9 @@ +struct target_pt_regs { + target_ulong psr; + target_ulong pc; + target_ulong npc; + target_ulong y; + target_ulong u_regs[16]; +}; + +#define UNAME_MACHINE "sun4" diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h new file mode 100644 index 0000000..afb364f --- /dev/null +++ b/linux-user/sparc/syscall_nr.h @@ -0,0 +1,220 @@ +#define TARGET_NR_exit 1 /* Common */ +#define TARGET_NR_fork 2 /* Common */ +#define TARGET_NR_read 3 /* Common */ +#define TARGET_NR_write 4 /* Common */ +#define TARGET_NR_open 5 /* Common */ +#define TARGET_NR_close 6 /* Common */ +#define TARGET_NR_wait4 7 /* Common */ +#define TARGET_NR_creat 8 /* Common */ +#define TARGET_NR_link 9 /* Common */ +#define TARGET_NR_unlink 10 /* Common */ +#define TARGET_NR_execv 11 /* SunOS Specific */ +#define TARGET_NR_chdir 12 /* Common */ +#define TARGET_NR_chown 13 /* Common */ +#define TARGET_NR_mknod 14 /* Common */ +#define TARGET_NR_chmod 15 /* Common */ +#define TARGET_NR_lchown 16 /* Common */ +#define TARGET_NR_brk 17 /* Common */ +#define TARGET_NR_perfctr 18 /* Performance counter operations */ +#define TARGET_NR_lseek 19 /* Common */ +#define TARGET_NR_getpid 20 /* Common */ +#define TARGET_NR_capget 21 /* Linux Specific */ +#define TARGET_NR_capset 22 /* Linux Specific */ +#define TARGET_NR_setuid 23 /* Implemented via setreuid in SunOS */ +#define TARGET_NR_getuid 24 /* Common */ +#define TARGET_NR_ptrace 26 /* Common */ +#define TARGET_NR_alarm 27 /* Implemented via setitimer in SunOS */ +#define TARGET_NR_sigaltstack 28 /* Common */ +#define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */ +#define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */ +#define TARGET_NR_lchown32 31 /* Linux sparc32 specific */ +#define TARGET_NR_fchown32 32 /* Linux sparc32 specific */ +#define TARGET_NR_access 33 /* Common */ +#define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */ +#define TARGET_NR_chown32 35 /* Linux sparc32 specific */ +#define TARGET_NR_sync 36 /* Common */ +#define TARGET_NR_kill 37 /* Common */ +#define TARGET_NR_stat 38 /* Common */ +#define TARGET_NR_sendfile 39 /* Linux Specific */ +#define TARGET_NR_lstat 40 /* Common */ +#define TARGET_NR_dup 41 /* Common */ +#define TARGET_NR_pipe 42 /* Common */ +#define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */ +#define TARGET_NR_getuid32 44 /* Linux sparc32 specific */ +#define TARGET_NR_umount2 45 /* Linux Specific */ +#define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */ +#define TARGET_NR_getgid 47 /* Common */ +#define TARGET_NR_signal 48 /* Implemented via sigvec() in SunOS */ +#define TARGET_NR_geteuid 49 /* SunOS calls getuid() */ +#define TARGET_NR_getegid 50 /* SunOS calls getgid() */ +#define TARGET_NR_acct 51 /* Common */ +#define TARGET_NR_getgid32 53 /* Linux sparc32 specific */ +#define TARGET_NR_ioctl 54 /* Common */ +#define TARGET_NR_reboot 55 /* Common */ +#define TARGET_NR_mmap2 56 /* Linux sparc32 Specific */ +#define TARGET_NR_symlink 57 /* Common */ +#define TARGET_NR_readlink 58 /* Common */ +#define TARGET_NR_execve 59 /* Common */ +#define TARGET_NR_umask 60 /* Common */ +#define TARGET_NR_chroot 61 /* Common */ +#define TARGET_NR_fstat 62 /* Common */ +#define TARGET_NR_fstat64 63 /* Linux sparc32 Specific */ +#define TARGET_NR_getpagesize 64 /* Common */ +#define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */ +#define TARGET_NR_vfork 66 /* Common */ +#define TARGET_NR_pread 67 /* Linux Specific */ +#define TARGET_NR_pwrite 68 /* Linux Specific */ +#define TARGET_NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */ +#define TARGET_NR_getegid32 70 /* Linux sparc32, sstk under SunOS */ +#define TARGET_NR_mmap 71 /* Common */ +#define TARGET_NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */ +#define TARGET_NR_munmap 73 /* Common */ +#define TARGET_NR_mprotect 74 /* Common */ +#define TARGET_NR_madvise 75 /* Common */ +#define TARGET_NR_vhangup 76 /* Common */ +#define TARGET_NR_truncate64 77 /* Linux sparc32 Specific */ +#define TARGET_NR_mincore 78 /* Common */ +#define TARGET_NR_getgroups 79 /* Common */ +#define TARGET_NR_setgroups 80 /* Common */ +#define TARGET_NR_getpgrp 81 /* Common */ +#define TARGET_NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */ +#define TARGET_NR_setitimer 83 /* Common */ +#define TARGET_NR_ftruncate64 84 /* Linux sparc32 Specific */ +#define TARGET_NR_swapon 85 /* Common */ +#define TARGET_NR_getitimer 86 /* Common */ +#define TARGET_NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */ +#define TARGET_NR_sethostname 88 /* Common */ +#define TARGET_NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */ +#define TARGET_NR_dup2 90 /* Common */ +#define TARGET_NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */ +#define TARGET_NR_fcntl 92 /* Common */ +#define TARGET_NR_select 93 /* Common */ +#define TARGET_NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */ +#define TARGET_NR_fsync 95 /* Common */ +#define TARGET_NR_setpriority 96 /* Common */ +#define TARGET_NR_socket 97 /* Common */ +#define TARGET_NR_connect 98 /* Common */ +#define TARGET_NR_accept 99 /* Common */ +#define TARGET_NR_getpriority 100 /* Common */ +#define TARGET_NR_rt_sigreturn 101 /* Linux Specific */ +#define TARGET_NR_rt_sigaction 102 /* Linux Specific */ +#define TARGET_NR_rt_sigprocmask 103 /* Linux Specific */ +#define TARGET_NR_rt_sigpending 104 /* Linux Specific */ +#define TARGET_NR_rt_sigtimedwait 105 /* Linux Specific */ +#define TARGET_NR_rt_sigqueueinfo 106 /* Linux Specific */ +#define TARGET_NR_rt_sigsuspend 107 /* Linux Specific */ +#define TARGET_NR_setresuid32 108 /* Linux Specific, sigvec under SunOS */ +#define TARGET_NR_getresuid32 109 /* Linux Specific, sigblock under SunOS */ +#define TARGET_NR_setresgid32 110 /* Linux Specific, sigsetmask under SunOS */ +#define TARGET_NR_getresgid32 111 /* Linux Specific, sigpause under SunOS */ +#define TARGET_NR_setregid32 112 /* Linux sparc32, sigstack under SunOS */ +#define TARGET_NR_recvmsg 113 /* Common */ +#define TARGET_NR_sendmsg 114 /* Common */ +#define TARGET_NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */ +#define TARGET_NR_gettimeofday 116 /* Common */ +#define TARGET_NR_getrusage 117 /* Common */ +#define TARGET_NR_getsockopt 118 /* Common */ +#define TARGET_NR_getcwd 119 /* Linux Specific */ +#define TARGET_NR_readv 120 /* Common */ +#define TARGET_NR_writev 121 /* Common */ +#define TARGET_NR_settimeofday 122 /* Common */ +#define TARGET_NR_fchown 123 /* Common */ +#define TARGET_NR_fchmod 124 /* Common */ +#define TARGET_NR_recvfrom 125 /* Common */ +#define TARGET_NR_setreuid 126 /* Common */ +#define TARGET_NR_setregid 127 /* Common */ +#define TARGET_NR_rename 128 /* Common */ +#define TARGET_NR_truncate 129 /* Common */ +#define TARGET_NR_ftruncate 130 /* Common */ +#define TARGET_NR_flock 131 /* Common */ +#define TARGET_NR_lstat64 132 /* Linux sparc32 Specific */ +#define TARGET_NR_sendto 133 /* Common */ +#define TARGET_NR_shutdown 134 /* Common */ +#define TARGET_NR_socketpair 135 /* Common */ +#define TARGET_NR_mkdir 136 /* Common */ +#define TARGET_NR_rmdir 137 /* Common */ +#define TARGET_NR_utimes 138 /* SunOS Specific */ +#define TARGET_NR_stat64 139 /* Linux sparc32 Specific */ +#define TARGET_NR_getpeername 141 /* Common */ +#define TARGET_NR_gettid 143 /* ENOSYS under SunOS */ +#define TARGET_NR_getrlimit 144 /* Common */ +#define TARGET_NR_setrlimit 145 /* Common */ +#define TARGET_NR_pivot_root 146 /* Linux Specific, killpg under SunOS */ +#define TARGET_NR_prctl 147 /* ENOSYS under SunOS */ +#define TARGET_NR_pciconfig_read 148 /* ENOSYS under SunOS */ +#define TARGET_NR_pciconfig_write 149 /* ENOSYS under SunOS */ +#define TARGET_NR_getsockname 150 /* Common */ +#define TARGET_NR_poll 153 /* Common */ +#define TARGET_NR_getdents64 154 /* Linux specific */ +#define TARGET_NR_fcntl64 155 /* Linux sparc32 Specific */ +#define TARGET_NR_statfs 157 /* Common */ +#define TARGET_NR_fstatfs 158 /* Common */ +#define TARGET_NR_umount 159 /* Common */ +#define TARGET_NR_getdomainname 162 /* SunOS Specific */ +#define TARGET_NR_setdomainname 163 /* Common */ +#define TARGET_NR_quotactl 165 /* Common */ +#define TARGET_NR_mount 167 /* Common */ +#define TARGET_NR_ustat 168 /* Common */ +#define TARGET_NR_getdents 174 /* Common */ +#define TARGET_NR_setsid 175 /* Common */ +#define TARGET_NR_fchdir 176 /* Common */ +#define TARGET_NR_sigpending 183 /* Common */ +#define TARGET_NR_query_module 184 /* Linux Specific */ +#define TARGET_NR_setpgid 185 /* Common */ +#define TARGET_NR_tkill 187 /* SunOS: fpathconf */ +#define TARGET_NR_exit_group 188 /* Linux specific, sysconf undef SunOS */ +#define TARGET_NR_uname 189 /* Linux Specific */ +#define TARGET_NR_init_module 190 /* Linux Specific */ +#define TARGET_NR_personality 191 /* Linux Specific */ +#define TARGET_NR_getppid 197 /* Linux Specific */ +#define TARGET_NR_sigaction 198 /* Linux Specific */ +#define TARGET_NR_sgetmask 199 /* Linux Specific */ +#define TARGET_NR_ssetmask 200 /* Linux Specific */ +#define TARGET_NR_sigsuspend 201 /* Linux Specific */ +#define TARGET_NR_oldlstat 202 /* Linux Specific */ +#define TARGET_NR_uselib 203 /* Linux Specific */ +#define TARGET_NR_readdir 204 /* Linux Specific */ +#define TARGET_NR_readahead 205 /* Linux Specific */ +#define TARGET_NR_socketcall 206 /* Linux Specific */ +#define TARGET_NR_syslog 207 /* Linux Specific */ +#define TARGET_NR_waitpid 212 /* Linux Specific */ +#define TARGET_NR_swapoff 213 /* Linux Specific */ +#define TARGET_NR_sysinfo 214 /* Linux Specific */ +#define TARGET_NR_ipc 215 /* Linux Specific */ +#define TARGET_NR_sigreturn 216 /* Linux Specific */ +#define TARGET_NR_clone 217 /* Linux Specific */ +#define TARGET_NR_adjtimex 219 /* Linux Specific */ +#define TARGET_NR_sigprocmask 220 /* Linux Specific */ +#define TARGET_NR_create_module 221 /* Linux Specific */ +#define TARGET_NR_delete_module 222 /* Linux Specific */ +#define TARGET_NR_get_kernel_syms 223 /* Linux Specific */ +#define TARGET_NR_getpgid 224 /* Linux Specific */ +#define TARGET_NR_bdflush 225 /* Linux Specific */ +#define TARGET_NR_sysfs 226 /* Linux Specific */ +#define TARGET_NR_afs_syscall 227 /* Linux Specific */ +#define TARGET_NR_setfsuid 228 /* Linux Specific */ +#define TARGET_NR_setfsgid 229 /* Linux Specific */ +#define TARGET_NR__newselect 230 /* Linux Specific */ +#define TARGET_NR_time 231 /* Linux Specific */ +#define TARGET_NR_stime 233 /* Linux Specific */ +#define TARGET_NR__llseek 236 /* Linux Specific */ +#define TARGET_NR_mlock 237 +#define TARGET_NR_munlock 238 +#define TARGET_NR_mlockall 239 +#define TARGET_NR_munlockall 240 +#define TARGET_NR_sched_setparam 241 +#define TARGET_NR_sched_getparam 242 +#define TARGET_NR_sched_setscheduler 243 +#define TARGET_NR_sched_getscheduler 244 +#define TARGET_NR_sched_yield 245 +#define TARGET_NR_sched_get_priority_max 246 +#define TARGET_NR_sched_get_priority_min 247 +#define TARGET_NR_sched_rr_get_interval 248 +#define TARGET_NR_nanosleep 249 +#define TARGET_NR_mremap 250 +#define TARGET_NR__sysctl 251 +#define TARGET_NR_getsid 252 +#define TARGET_NR_fdatasync 253 +#define TARGET_NR_nfsservctl 254 +#define TARGET_NR_aplib 255 +#define TARGET_NR__exit TARGET_NR_exit diff --git a/linux-user/sparc/termbits.h b/linux-user/sparc/termbits.h new file mode 100644 index 0000000..cad45b2 --- /dev/null +++ b/linux-user/sparc/termbits.h @@ -0,0 +1,279 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VEOL 5 +#define TARGET_VEOL2 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 + +#define TARGET_VSUSP 10 +#define TARGET_VDSUSP 11 /* SunOS POSIX nicety I do believe... */ +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 + +/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is + * shared with eof/eol + */ +#define TARGET_VMIN TARGET_VEOF +#define TARGET_VTIME TARGET_VEOL + +/* c_iflag bits */ +#define TARGET_IGNBRK 0x00000001 +#define TARGET_BRKINT 0x00000002 +#define TARGET_IGNPAR 0x00000004 +#define TARGET_PARMRK 0x00000008 +#define TARGET_INPCK 0x00000010 +#define TARGET_ISTRIP 0x00000020 +#define TARGET_INLCR 0x00000040 +#define TARGET_IGNCR 0x00000080 +#define TARGET_ICRNL 0x00000100 +#define TARGET_IUCLC 0x00000200 +#define TARGET_IXON 0x00000400 +#define TARGET_IXANY 0x00000800 +#define TARGET_IXOFF 0x00001000 +#define TARGET_IMAXBEL 0x00002000 + +/* c_oflag bits */ +#define TARGET_OPOST 0x00000001 +#define TARGET_OLCUC 0x00000002 +#define TARGET_ONLCR 0x00000004 +#define TARGET_OCRNL 0x00000008 +#define TARGET_ONOCR 0x00000010 +#define TARGET_ONLRET 0x00000020 +#define TARGET_OFILL 0x00000040 +#define TARGET_OFDEL 0x00000080 +#define TARGET_NLDLY 0x00000100 +#define TARGET_NL0 0x00000000 +#define TARGET_NL1 0x00000100 +#define TARGET_CRDLY 0x00000600 +#define TARGET_CR0 0x00000000 +#define TARGET_CR1 0x00000200 +#define TARGET_CR2 0x00000400 +#define TARGET_CR3 0x00000600 +#define TARGET_TABDLY 0x00001800 +#define TARGET_TAB0 0x00000000 +#define TARGET_TAB1 0x00000800 +#define TARGET_TAB2 0x00001000 +#define TARGET_TAB3 0x00001800 +#define TARGET_XTABS 0x00001800 +#define TARGET_BSDLY 0x00002000 +#define TARGET_BS0 0x00000000 +#define TARGET_BS1 0x00002000 +#define TARGET_VTDLY 0x00004000 +#define TARGET_VT0 0x00000000 +#define TARGET_VT1 0x00004000 +#define TARGET_FFDLY 0x00008000 +#define TARGET_FF0 0x00000000 +#define TARGET_FF1 0x00008000 +#define TARGET_PAGEOUT 0x00010000 /* SUNOS specific */ +#define TARGET_WRAP 0x00020000 /* SUNOS specific */ + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0x0000100f +#define TARGET_B0 0x00000000 /* hang up */ +#define TARGET_B50 0x00000001 +#define TARGET_B75 0x00000002 +#define TARGET_B110 0x00000003 +#define TARGET_B134 0x00000004 +#define TARGET_B150 0x00000005 +#define TARGET_B200 0x00000006 +#define TARGET_B300 0x00000007 +#define TARGET_B600 0x00000008 +#define TARGET_B1200 0x00000009 +#define TARGET_B1800 0x0000000a +#define TARGET_B2400 0x0000000b +#define TARGET_B4800 0x0000000c +#define TARGET_B9600 0x0000000d +#define TARGET_B19200 0x0000000e +#define TARGET_B38400 0x0000000f +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0x00000030 +#define TARGET_CS5 0x00000000 +#define TARGET_CS6 0x00000010 +#define TARGET_CS7 0x00000020 +#define TARGET_CS8 0x00000030 +#define TARGET_CSTOPB 0x00000040 +#define TARGET_CREAD 0x00000080 +#define TARGET_PARENB 0x00000100 +#define TARGET_PARODD 0x00000200 +#define TARGET_HUPCL 0x00000400 +#define TARGET_CLOCAL 0x00000800 +#define TARGET_CBAUDEX 0x00001000 +/* We'll never see these speeds with the Zilogs, but for completeness... */ +#define TARGET_B57600 0x00001001 +#define TARGET_B115200 0x00001002 +#define TARGET_B230400 0x00001003 +#define TARGET_B460800 0x00001004 +/* This is what we can do with the Zilogs. */ +#define TARGET_B76800 0x00001005 +/* This is what we can do with the SAB82532. */ +#define TARGET_B153600 0x00001006 +#define TARGET_B307200 0x00001007 +#define TARGET_B614400 0x00001008 +#define TARGET_B921600 0x00001009 +/* And these are the rest... */ +#define TARGET_B500000 0x0000100a +#define TARGET_B576000 0x0000100b +#define TARGET_B1000000 0x0000100c +#define TARGET_B1152000 0x0000100d +#define TARGET_B1500000 0x0000100e +#define TARGET_B2000000 0x0000100f +/* These have totally bogus values and nobody uses them + so far. Later on we'd have to use say 0x10000x and + adjust CBAUD constant and drivers accordingly. +#define B2500000 0x00001010 +#define B3000000 0x00001011 +#define B3500000 0x00001012 +#define B4000000 0x00001013 */ +#define TARGET_CIBAUD 0x100f0000 /* input baud rate (not used) */ +#define TARGET_CMSPAR 0x40000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 0x80000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0x00000001 +#define TARGET_ICANON 0x00000002 +#define TARGET_XCASE 0x00000004 +#define TARGET_ECHO 0x00000008 +#define TARGET_ECHOE 0x00000010 +#define TARGET_ECHOK 0x00000020 +#define TARGET_ECHONL 0x00000040 +#define TARGET_NOFLSH 0x00000080 +#define TARGET_TOSTOP 0x00000100 +#define TARGET_ECHOCTL 0x00000200 +#define TARGET_ECHOPRT 0x00000400 +#define TARGET_ECHOKE 0x00000800 +#define TARGET_DEFECHO 0x00001000 /* SUNOS thing, what is it? */ +#define TARGET_FLUSHO 0x00002000 +#define TARGET_PENDIN 0x00004000 +#define TARGET_IEXTEN 0x00008000 + +/* ioctls */ + +/* Big T */ +#define TARGET_TCGETA TARGET_IOR('T', 1, struct target_termio) +#define TARGET_TCSETA TARGET_IOW('T', 2, struct target_termio) +#define TARGET_TCSETAW TARGET_IOW('T', 3, struct target_termio) +#define TARGET_TCSETAF TARGET_IOW('T', 4, struct target_termio) +#define TARGET_TCSBRK TARGET_IO('T', 5) +#define TARGET_TCXONC TARGET_IO('T', 6) +#define TARGET_TCFLSH TARGET_IO('T', 7) +#define TARGET_TCGETS TARGET_IOR('T', 8, struct target_termios) +#define TARGET_TCSETS TARGET_IOW('T', 9, struct target_termios) +#define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios) +#define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios) + +/* Note that all the ioctls that are not available in Linux have a + * double underscore on the front to: a) avoid some programs to + * thing we support some ioctls under Linux (autoconfiguration stuff) + */ +/* Little t */ +#define TARGET_TIOCGETD TARGET_IOR('t', 0, int) +#define TARGET_TIOCSETD TARGET_IOW('t', 1, int) +//#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */ +//#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */ +//#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */ +//#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */ +//#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */ +//#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */ +#define TARGET_TIOCEXCL TARGET_IO('t', 13) +#define TARGET_TIOCNXCL TARGET_IO('t', 14) +//#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */ +//#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */ +//#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */ +//#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */ +//#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */ +//#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */ +//#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */ +#define TARGET_TIOCCONS TARGET_IO('t', 36) +//#define __TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */ +//#define __TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */ +#define TARGET_TIOCGSOFTCAR TARGET_IOR('t', 100, int) +#define TARGET_TIOCSSOFTCAR TARGET_IOW('t', 101, int) +//#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */ +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) +//#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */ +#define TARGET_TIOCMGET TARGET_IOR('t', 106, int) +#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) +#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) +#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) +#define TARGET_TIOCSTART TARGET_IO('t', 110) +#define TARGET_TIOCSTOP TARGET_IO('t', 111) +#define TARGET_TIOCPKT TARGET_IOW('t', 112, int) +#define TARGET_TIOCNOTTY TARGET_IO('t', 113) +#define TARGET_TIOCSTI TARGET_IOW('t', 114, char) +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) +//#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */ +//#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */ +/* 118 is the non-posix setpgrp tty ioctl */ +/* 119 is the non-posix getpgrp tty ioctl */ +//#define __TIOCCDTR TARGET_IO('t', 120) /* SunOS Specific */ +//#define __TIOCSDTR TARGET_IO('t', 121) /* SunOS Specific */ +#define TARGET_TIOCCBRK TARGET_IO('t', 122) +#define TARGET_TIOCSBRK TARGET_IO('t', 123) +//#define __TIOCLGET TARGET_IOW('t', 124, int) /* SunOS Specific */ +//#define __TIOCLSET TARGET_IOW('t', 125, int) /* SunOS Specific */ +//#define __TIOCLBIC TARGET_IOW('t', 126, int) /* SunOS Specific */ +//#define __TIOCLBIS TARGET_IOW('t', 127, int) /* SunOS Specific */ +//#define __TIOCISPACE TARGET_IOR('t', 128, int) /* SunOS Specific */ +//#define __TIOCISIZE TARGET_IOR('t', 129, int) /* SunOS Specific */ +#define TARGET_TIOCSPGRP TARGET_IOW('t', 130, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 131, int) +#define TARGET_TIOCSCTTY TARGET_IO('t', 132) +#define TARGET_TIOCGSID TARGET_IOR('t', 133, int) +/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */ +#define TARGET_TIOCGPTN TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */ +#define TARGET_TIOCSPTLCK TARGET_IOW('t', 135, int) /* Lock/unlock PTY */ + +/* Little f */ +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) +#define TARGET_TIOCINQ TARGET_FIONREAD + +/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it + * someday. This is completely bogus, I know... + */ +//#define __TCGETSTAT TARGET_IO('T', 200) /* Rutgers specific */ +//#define __TCSETSTAT TARGET_IO('T', 201) /* Rutgers specific */ + +/* Linux specific, no SunOS equivalent. */ +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TCSBRKP 0x5425 +#define TARGET_TIOCTTYGSTRUCT 0x5426 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ +#define TARGET_TIOCMIWAIT 0x545C /* Wait input */ +#define TARGET_TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */ + diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h new file mode 100644 index 0000000..c361558 --- /dev/null +++ b/linux-user/sparc64/syscall.h @@ -0,0 +1,10 @@ +struct target_pt_regs { + target_ulong u_regs[16]; + target_ulong tstate; + target_ulong pc; + target_ulong npc; + target_ulong y; + target_ulong fprs; +}; + +#define UNAME_MACHINE "sun4u" diff --git a/linux-user/sparc64/syscall_nr.h b/linux-user/sparc64/syscall_nr.h new file mode 100644 index 0000000..9274c85 --- /dev/null +++ b/linux-user/sparc64/syscall_nr.h @@ -0,0 +1,286 @@ +#define TARGET_NR_restart_syscall 0 /* Linux Specific */ +#define TARGET_NR_exit 1 /* Common */ +#define TARGET_NR_fork 2 /* Common */ +#define TARGET_NR_read 3 /* Common */ +#define TARGET_NR_write 4 /* Common */ +#define TARGET_NR_open 5 /* Common */ +#define TARGET_NR_close 6 /* Common */ +#define TARGET_NR_wait4 7 /* Common */ +#define TARGET_NR_creat 8 /* Common */ +#define TARGET_NR_link 9 /* Common */ +#define TARGET_NR_unlink 10 /* Common */ +#define TARGET_NR_execv 11 /* SunOS Specific */ +#define TARGET_NR_chdir 12 /* Common */ +#define TARGET_NR_chown 13 /* Common */ +#define TARGET_NR_mknod 14 /* Common */ +#define TARGET_NR_chmod 15 /* Common */ +#define TARGET_NR_lchown 16 /* Common */ +#define TARGET_NR_brk 17 /* Common */ +#define TARGET_NR_perfctr 18 /* Performance counter operations */ +#define TARGET_NR_lseek 19 /* Common */ +#define TARGET_NR_getpid 20 /* Common */ +#define TARGET_NR_capget 21 /* Linux Specific */ +#define TARGET_NR_capset 22 /* Linux Specific */ +#define TARGET_NR_setuid 23 /* Implemented via setreuid in SunOS */ +#define TARGET_NR_getuid 24 /* Common */ +/* #define TARGET_NR_time alias 25 ENOSYS under SunOS */ +#define TARGET_NR_ptrace 26 /* Common */ +#define TARGET_NR_alarm 27 /* Implemented via setitimer in SunOS */ +#define TARGET_NR_sigaltstack 28 /* Common */ +#define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */ +#define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */ +/* #define TARGET_NR_lchown32 31 Linux sparc32 specific */ +/* #define TARGET_NR_fchown32 32 Linux sparc32 specific */ +#define TARGET_NR_access 33 /* Common */ +#define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */ +/* #define TARGET_NR_chown32 35 Linux sparc32 specific */ +#define TARGET_NR_sync 36 /* Common */ +#define TARGET_NR_kill 37 /* Common */ +#define TARGET_NR_stat 38 /* Common */ +#define TARGET_NR_sendfile 39 /* Linux Specific */ +#define TARGET_NR_lstat 40 /* Common */ +#define TARGET_NR_dup 41 /* Common */ +#define TARGET_NR_pipe 42 /* Common */ +#define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */ +/* #define TARGET_NR_getuid32 44 Linux sparc32 specific */ +#define TARGET_NR_umount2 45 /* Linux Specific */ +#define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */ +#define TARGET_NR_getgid 47 /* Common */ +#define TARGET_NR_signal 48 /* Implemented via sigvec() in SunOS */ +#define TARGET_NR_geteuid 49 /* SunOS calls getuid() */ +#define TARGET_NR_getegid 50 /* SunOS calls getgid() */ +#define TARGET_NR_acct 51 /* Common */ +#define TARGET_NR_memory_ordering 52 /* Linux Specific */ +/* #define TARGET_NR_getgid32 53 Linux sparc32 specific */ +#define TARGET_NR_ioctl 54 /* Common */ +#define TARGET_NR_reboot 55 /* Common */ +/* #define TARGET_NR_mmap2 56 Linux sparc32 Specific */ +#define TARGET_NR_symlink 57 /* Common */ +#define TARGET_NR_readlink 58 /* Common */ +#define TARGET_NR_execve 59 /* Common */ +#define TARGET_NR_umask 60 /* Common */ +#define TARGET_NR_chroot 61 /* Common */ +#define TARGET_NR_fstat 62 /* Common */ +/* #define TARGET_NR_fstat64 63 Linux sparc32 Specific */ +#define TARGET_NR_getpagesize 64 /* Common */ +#define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */ +#define TARGET_NR_vfork 66 /* Common */ +#define TARGET_NR_pread64 67 /* Linux Specific */ +#define TARGET_NR_pwrite64 68 /* Linux Specific */ +/* #define TARGET_NR_geteuid32 69 Linux sparc32, sbrk under SunOS */ +/* #define TARGET_NR_getegid32 70 Linux sparc32, sstk under SunOS */ +#define TARGET_NR_mmap 71 /* Common */ +/* #define TARGET_NR_setreuid32 72 Linux sparc32, vadvise under SunOS */ +#define TARGET_NR_munmap 73 /* Common */ +#define TARGET_NR_mprotect 74 /* Common */ +#define TARGET_NR_madvise 75 /* Common */ +#define TARGET_NR_vhangup 76 /* Common */ +/* #define TARGET_NR_truncate64 77 Linux sparc32 Specific */ +#define TARGET_NR_mincore 78 /* Common */ +#define TARGET_NR_getgroups 79 /* Common */ +#define TARGET_NR_setgroups 80 /* Common */ +#define TARGET_NR_getpgrp 81 /* Common */ +/* #define TARGET_NR_setgroups32 82 Linux sparc32, setpgrp under SunOS */ +#define TARGET_NR_setitimer 83 /* Common */ +/* #define TARGET_NR_ftruncate64 84 Linux sparc32 Specific */ +#define TARGET_NR_swapon 85 /* Common */ +#define TARGET_NR_getitimer 86 /* Common */ +/* #define TARGET_NR_setuid32 87 Linux sparc32, gethostname under SunOS */ +#define TARGET_NR_sethostname 88 /* Common */ +/* #define TARGET_NR_setgid32 89 Linux sparc32, getdtablesize under SunOS */ +#define TARGET_NR_dup2 90 /* Common */ +/* #define TARGET_NR_setfsuid32 91 Linux sparc32, getdopt under SunOS */ +#define TARGET_NR_fcntl 92 /* Common */ +#define TARGET_NR_select 93 /* Common */ +/* #define TARGET_NR_setfsgid32 94 Linux sparc32, setdopt under SunOS */ +#define TARGET_NR_fsync 95 /* Common */ +#define TARGET_NR_setpriority 96 /* Common */ +#define TARGET_NR_socket 97 /* Common */ +#define TARGET_NR_connect 98 /* Common */ +#define TARGET_NR_accept 99 /* Common */ +#define TARGET_NR_getpriority 100 /* Common */ +#define TARGET_NR_rt_sigreturn 101 /* Linux Specific */ +#define TARGET_NR_rt_sigaction 102 /* Linux Specific */ +#define TARGET_NR_rt_sigprocmask 103 /* Linux Specific */ +#define TARGET_NR_rt_sigpending 104 /* Linux Specific */ +#define TARGET_NR_rt_sigtimedwait 105 /* Linux Specific */ +#define TARGET_NR_rt_sigqueueinfo 106 /* Linux Specific */ +#define TARGET_NR_rt_sigsuspend 107 /* Linux Specific */ +#define TARGET_NR_setresuid 108 /* Linux Specific, sigvec under SunOS */ +#define TARGET_NR_getresuid 109 /* Linux Specific, sigblock under SunOS */ +#define TARGET_NR_setresgid 110 /* Linux Specific, sigsetmask under SunOS */ +#define TARGET_NR_getresgid 111 /* Linux Specific, sigpause under SunOS */ +/* #define TARGET_NR_setregid32 75 Linux sparc32, sigstack under SunOS */ +#define TARGET_NR_recvmsg 113 /* Common */ +#define TARGET_NR_sendmsg 114 /* Common */ +/* #define TARGET_NR_getgroups32 115 Linux sparc32, vtrace under SunOS */ +#define TARGET_NR_gettimeofday 116 /* Common */ +#define TARGET_NR_getrusage 117 /* Common */ +#define TARGET_NR_getsockopt 118 /* Common */ +#define TARGET_NR_getcwd 119 /* Linux Specific */ +#define TARGET_NR_readv 120 /* Common */ +#define TARGET_NR_writev 121 /* Common */ +#define TARGET_NR_settimeofday 122 /* Common */ +#define TARGET_NR_fchown 123 /* Common */ +#define TARGET_NR_fchmod 124 /* Common */ +#define TARGET_NR_recvfrom 125 /* Common */ +#define TARGET_NR_setreuid 126 /* Common */ +#define TARGET_NR_setregid 127 /* Common */ +#define TARGET_NR_rename 128 /* Common */ +#define TARGET_NR_truncate 129 /* Common */ +#define TARGET_NR_ftruncate 130 /* Common */ +#define TARGET_NR_flock 131 /* Common */ +/* #define TARGET_NR_lstat64 132 Linux sparc32 Specific */ +#define TARGET_NR_sendto 133 /* Common */ +#define TARGET_NR_shutdown 134 /* Common */ +#define TARGET_NR_socketpair 135 /* Common */ +#define TARGET_NR_mkdir 136 /* Common */ +#define TARGET_NR_rmdir 137 /* Common */ +#define TARGET_NR_utimes 138 /* SunOS Specific */ +/* #define TARGET_NR_stat64 139 Linux sparc32 Specific */ +#define TARGET_NR_sendfile64 140 /* adjtime under SunOS */ +#define TARGET_NR_getpeername 141 /* Common */ +#define TARGET_NR_futex 142 /* gethostid under SunOS */ +#define TARGET_NR_gettid 143 /* ENOSYS under SunOS */ +#define TARGET_NR_getrlimit 144 /* Common */ +#define TARGET_NR_setrlimit 145 /* Common */ +#define TARGET_NR_pivot_root 146 /* Linux Specific, killpg under SunOS */ +#define TARGET_NR_prctl 147 /* ENOSYS under SunOS */ +#define TARGET_NR_pciconfig_read 148 /* ENOSYS under SunOS */ +#define TARGET_NR_pciconfig_write 149 /* ENOSYS under SunOS */ +#define TARGET_NR_getsockname 150 /* Common */ +/* #define TARGET_NR_getmsg 151 SunOS Specific */ +/* #define TARGET_NR_putmsg 152 SunOS Specific */ +#define TARGET_NR_poll 153 /* Common */ +#define TARGET_NR_getdents64 154 /* Linux specific */ +/* #define TARGET_NR_fcntl64 155 Linux sparc32 Specific */ +/* #define TARGET_NR_getdirentries 156 SunOS Specific */ +#define TARGET_NR_statfs 157 /* Common */ +#define TARGET_NR_fstatfs 158 /* Common */ +#define TARGET_NR_umount 159 /* Common */ +#define TARGET_NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS */ +#define TARGET_NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS */ +#define TARGET_NR_getdomainname 162 /* SunOS Specific */ +#define TARGET_NR_setdomainname 163 /* Common */ +#define TARGET_NR_utrap_install 164 /* SYSV ABI/v9 required */ +#define TARGET_NR_quotactl 165 /* Common */ +#define TARGET_NR_set_tid_address 166 /* Linux specific, exportfs under SunOS */ +#define TARGET_NR_mount 167 /* Common */ +#define TARGET_NR_ustat 168 /* Common */ +#define TARGET_NR_setxattr 169 /* SunOS: semsys */ +#define TARGET_NR_lsetxattr 170 /* SunOS: msgsys */ +#define TARGET_NR_fsetxattr 171 /* SunOS: shmsys */ +#define TARGET_NR_getxattr 172 /* SunOS: auditsys */ +#define TARGET_NR_lgetxattr 173 /* SunOS: rfssys */ +#define TARGET_NR_getdents 174 /* Common */ +#define TARGET_NR_setsid 175 /* Common */ +#define TARGET_NR_fchdir 176 /* Common */ +#define TARGET_NR_fgetxattr 177 /* SunOS: fchroot */ +#define TARGET_NR_listxattr 178 /* SunOS: vpixsys */ +#define TARGET_NR_llistxattr 179 /* SunOS: aioread */ +#define TARGET_NR_flistxattr 180 /* SunOS: aiowrite */ +#define TARGET_NR_removexattr 181 /* SunOS: aiowait */ +#define TARGET_NR_lremovexattr 182 /* SunOS: aiocancel */ +#define TARGET_NR_sigpending 183 /* Common */ +#define TARGET_NR_query_module 184 /* Linux Specific */ +#define TARGET_NR_setpgid 185 /* Common */ +#define TARGET_NR_fremovexattr 186 /* SunOS: pathconf */ +#define TARGET_NR_tkill 187 /* SunOS: fpathconf */ +#define TARGET_NR_exit_group 188 /* Linux specific, sysconf undef SunOS */ +#define TARGET_NR_uname 189 /* Linux Specific */ +#define TARGET_NR_init_module 190 /* Linux Specific */ +#define TARGET_NR_personality 191 /* Linux Specific */ +#define TARGET_NR_remap_file_pages 192 /* Linux Specific */ +#define TARGET_NR_epoll_create 193 /* Linux Specific */ +#define TARGET_NR_epoll_ctl 194 /* Linux Specific */ +#define TARGET_NR_epoll_wait 195 /* Linux Specific */ +/* #define TARGET_NR_ulimit 196 Linux Specific */ +#define TARGET_NR_getppid 197 /* Linux Specific */ +#define TARGET_NR_sigaction 198 /* Linux Specific */ +#define TARGET_NR_sgetmask 199 /* Linux Specific */ +#define TARGET_NR_ssetmask 200 /* Linux Specific */ +#define TARGET_NR_sigsuspend 201 /* Linux Specific */ +#define TARGET_NR_oldlstat 202 /* Linux Specific */ +#define TARGET_NR_uselib 203 /* Linux Specific */ +#define TARGET_NR_readdir 204 /* Linux Specific */ +#define TARGET_NR_readahead 205 /* Linux Specific */ +#define TARGET_NR_socketcall 206 /* Linux Specific */ +#define TARGET_NR_syslog 207 /* Linux Specific */ +#define TARGET_NR_lookup_dcookie 208 /* Linux Specific */ +#define TARGET_NR_fadvise64 209 /* Linux Specific */ +#define TARGET_NR_fadvise64_64 210 /* Linux Specific */ +#define TARGET_NR_tgkill 211 /* Linux Specific */ +#define TARGET_NR_waitpid 212 /* Linux Specific */ +#define TARGET_NR_swapoff 213 /* Linux Specific */ +#define TARGET_NR_sysinfo 214 /* Linux Specific */ +#define TARGET_NR_ipc 215 /* Linux Specific */ +#define TARGET_NR_sigreturn 216 /* Linux Specific */ +#define TARGET_NR_clone 217 /* Linux Specific */ +/* #define TARGET_NR_modify_ldt 218 Linux Specific - i386 specific, unused */ +#define TARGET_NR_adjtimex 219 /* Linux Specific */ +#define TARGET_NR_sigprocmask 220 /* Linux Specific */ +#define TARGET_NR_create_module 221 /* Linux Specific */ +#define TARGET_NR_delete_module 222 /* Linux Specific */ +#define TARGET_NR_get_kernel_syms 223 /* Linux Specific */ +#define TARGET_NR_getpgid 224 /* Linux Specific */ +#define TARGET_NR_bdflush 225 /* Linux Specific */ +#define TARGET_NR_sysfs 226 /* Linux Specific */ +#define TARGET_NR_afs_syscall 227 /* Linux Specific */ +#define TARGET_NR_setfsuid 228 /* Linux Specific */ +#define TARGET_NR_setfsgid 229 /* Linux Specific */ +#define TARGET_NR__newselect 230 /* Linux Specific */ +#ifdef __KERNEL__ +#define TARGET_NR_time 231 /* Linux sparc32 */ +#endif +/* #define TARGET_NR_oldstat 232 Linux Specific */ +#define TARGET_NR_stime 233 /* Linux Specific */ +#define TARGET_NR_statfs64 234 /* Linux Specific */ +#define TARGET_NR_fstatfs64 235 /* Linux Specific */ +#define TARGET_NR__llseek 236 /* Linux Specific */ +#define TARGET_NR_mlock 237 +#define TARGET_NR_munlock 238 +#define TARGET_NR_mlockall 239 +#define TARGET_NR_munlockall 240 +#define TARGET_NR_sched_setparam 241 +#define TARGET_NR_sched_getparam 242 +#define TARGET_NR_sched_setscheduler 243 +#define TARGET_NR_sched_getscheduler 244 +#define TARGET_NR_sched_yield 245 +#define TARGET_NR_sched_get_priority_max 246 +#define TARGET_NR_sched_get_priority_min 247 +#define TARGET_NR_sched_rr_get_interval 248 +#define TARGET_NR_nanosleep 249 +#define TARGET_NR_mremap 250 +#define TARGET_NR__sysctl 251 +#define TARGET_NR_getsid 252 +#define TARGET_NR_fdatasync 253 +#define TARGET_NR_nfsservctl 254 +#define TARGET_NR_aplib 255 +#define TARGET_NR_clock_settime 256 +#define TARGET_NR_clock_gettime 257 +#define TARGET_NR_clock_getres 258 +#define TARGET_NR_clock_nanosleep 259 +#define TARGET_NR_sched_getaffinity 260 +#define TARGET_NR_sched_setaffinity 261 +#define TARGET_NR_timer_settime 262 +#define TARGET_NR_timer_gettime 263 +#define TARGET_NR_timer_getoverrun 264 +#define TARGET_NR_timer_delete 265 +#define TARGET_NR_timer_create 266 +/* #define TARGET_NR_vserver 267 Reserved for VSERVER */ +#define TARGET_NR_io_setup 268 +#define TARGET_NR_io_destroy 269 +#define TARGET_NR_io_submit 270 +#define TARGET_NR_io_cancel 271 +#define TARGET_NR_io_getevents 272 +#define TARGET_NR_mq_open 273 +#define TARGET_NR_mq_unlink 274 +#define TARGET_NR_mq_timedsend 275 +#define TARGET_NR_mq_timedreceive 276 +#define TARGET_NR_mq_notify 277 +#define TARGET_NR_mq_getsetattr 278 +#define TARGET_NR_waitid 279 +/*#define TARGET_NR_sys_setaltroot 280 available (was setaltroot) */ +#define TARGET_NR_add_key 281 +#define TARGET_NR_request_key 282 +#define TARGET_NR_keyctl 283 diff --git a/linux-user/sparc64/termbits.h b/linux-user/sparc64/termbits.h new file mode 100644 index 0000000..cad45b2 --- /dev/null +++ b/linux-user/sparc64/termbits.h @@ -0,0 +1,279 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VEOL 5 +#define TARGET_VEOL2 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 + +#define TARGET_VSUSP 10 +#define TARGET_VDSUSP 11 /* SunOS POSIX nicety I do believe... */ +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 + +/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is + * shared with eof/eol + */ +#define TARGET_VMIN TARGET_VEOF +#define TARGET_VTIME TARGET_VEOL + +/* c_iflag bits */ +#define TARGET_IGNBRK 0x00000001 +#define TARGET_BRKINT 0x00000002 +#define TARGET_IGNPAR 0x00000004 +#define TARGET_PARMRK 0x00000008 +#define TARGET_INPCK 0x00000010 +#define TARGET_ISTRIP 0x00000020 +#define TARGET_INLCR 0x00000040 +#define TARGET_IGNCR 0x00000080 +#define TARGET_ICRNL 0x00000100 +#define TARGET_IUCLC 0x00000200 +#define TARGET_IXON 0x00000400 +#define TARGET_IXANY 0x00000800 +#define TARGET_IXOFF 0x00001000 +#define TARGET_IMAXBEL 0x00002000 + +/* c_oflag bits */ +#define TARGET_OPOST 0x00000001 +#define TARGET_OLCUC 0x00000002 +#define TARGET_ONLCR 0x00000004 +#define TARGET_OCRNL 0x00000008 +#define TARGET_ONOCR 0x00000010 +#define TARGET_ONLRET 0x00000020 +#define TARGET_OFILL 0x00000040 +#define TARGET_OFDEL 0x00000080 +#define TARGET_NLDLY 0x00000100 +#define TARGET_NL0 0x00000000 +#define TARGET_NL1 0x00000100 +#define TARGET_CRDLY 0x00000600 +#define TARGET_CR0 0x00000000 +#define TARGET_CR1 0x00000200 +#define TARGET_CR2 0x00000400 +#define TARGET_CR3 0x00000600 +#define TARGET_TABDLY 0x00001800 +#define TARGET_TAB0 0x00000000 +#define TARGET_TAB1 0x00000800 +#define TARGET_TAB2 0x00001000 +#define TARGET_TAB3 0x00001800 +#define TARGET_XTABS 0x00001800 +#define TARGET_BSDLY 0x00002000 +#define TARGET_BS0 0x00000000 +#define TARGET_BS1 0x00002000 +#define TARGET_VTDLY 0x00004000 +#define TARGET_VT0 0x00000000 +#define TARGET_VT1 0x00004000 +#define TARGET_FFDLY 0x00008000 +#define TARGET_FF0 0x00000000 +#define TARGET_FF1 0x00008000 +#define TARGET_PAGEOUT 0x00010000 /* SUNOS specific */ +#define TARGET_WRAP 0x00020000 /* SUNOS specific */ + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0x0000100f +#define TARGET_B0 0x00000000 /* hang up */ +#define TARGET_B50 0x00000001 +#define TARGET_B75 0x00000002 +#define TARGET_B110 0x00000003 +#define TARGET_B134 0x00000004 +#define TARGET_B150 0x00000005 +#define TARGET_B200 0x00000006 +#define TARGET_B300 0x00000007 +#define TARGET_B600 0x00000008 +#define TARGET_B1200 0x00000009 +#define TARGET_B1800 0x0000000a +#define TARGET_B2400 0x0000000b +#define TARGET_B4800 0x0000000c +#define TARGET_B9600 0x0000000d +#define TARGET_B19200 0x0000000e +#define TARGET_B38400 0x0000000f +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0x00000030 +#define TARGET_CS5 0x00000000 +#define TARGET_CS6 0x00000010 +#define TARGET_CS7 0x00000020 +#define TARGET_CS8 0x00000030 +#define TARGET_CSTOPB 0x00000040 +#define TARGET_CREAD 0x00000080 +#define TARGET_PARENB 0x00000100 +#define TARGET_PARODD 0x00000200 +#define TARGET_HUPCL 0x00000400 +#define TARGET_CLOCAL 0x00000800 +#define TARGET_CBAUDEX 0x00001000 +/* We'll never see these speeds with the Zilogs, but for completeness... */ +#define TARGET_B57600 0x00001001 +#define TARGET_B115200 0x00001002 +#define TARGET_B230400 0x00001003 +#define TARGET_B460800 0x00001004 +/* This is what we can do with the Zilogs. */ +#define TARGET_B76800 0x00001005 +/* This is what we can do with the SAB82532. */ +#define TARGET_B153600 0x00001006 +#define TARGET_B307200 0x00001007 +#define TARGET_B614400 0x00001008 +#define TARGET_B921600 0x00001009 +/* And these are the rest... */ +#define TARGET_B500000 0x0000100a +#define TARGET_B576000 0x0000100b +#define TARGET_B1000000 0x0000100c +#define TARGET_B1152000 0x0000100d +#define TARGET_B1500000 0x0000100e +#define TARGET_B2000000 0x0000100f +/* These have totally bogus values and nobody uses them + so far. Later on we'd have to use say 0x10000x and + adjust CBAUD constant and drivers accordingly. +#define B2500000 0x00001010 +#define B3000000 0x00001011 +#define B3500000 0x00001012 +#define B4000000 0x00001013 */ +#define TARGET_CIBAUD 0x100f0000 /* input baud rate (not used) */ +#define TARGET_CMSPAR 0x40000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 0x80000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0x00000001 +#define TARGET_ICANON 0x00000002 +#define TARGET_XCASE 0x00000004 +#define TARGET_ECHO 0x00000008 +#define TARGET_ECHOE 0x00000010 +#define TARGET_ECHOK 0x00000020 +#define TARGET_ECHONL 0x00000040 +#define TARGET_NOFLSH 0x00000080 +#define TARGET_TOSTOP 0x00000100 +#define TARGET_ECHOCTL 0x00000200 +#define TARGET_ECHOPRT 0x00000400 +#define TARGET_ECHOKE 0x00000800 +#define TARGET_DEFECHO 0x00001000 /* SUNOS thing, what is it? */ +#define TARGET_FLUSHO 0x00002000 +#define TARGET_PENDIN 0x00004000 +#define TARGET_IEXTEN 0x00008000 + +/* ioctls */ + +/* Big T */ +#define TARGET_TCGETA TARGET_IOR('T', 1, struct target_termio) +#define TARGET_TCSETA TARGET_IOW('T', 2, struct target_termio) +#define TARGET_TCSETAW TARGET_IOW('T', 3, struct target_termio) +#define TARGET_TCSETAF TARGET_IOW('T', 4, struct target_termio) +#define TARGET_TCSBRK TARGET_IO('T', 5) +#define TARGET_TCXONC TARGET_IO('T', 6) +#define TARGET_TCFLSH TARGET_IO('T', 7) +#define TARGET_TCGETS TARGET_IOR('T', 8, struct target_termios) +#define TARGET_TCSETS TARGET_IOW('T', 9, struct target_termios) +#define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios) +#define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios) + +/* Note that all the ioctls that are not available in Linux have a + * double underscore on the front to: a) avoid some programs to + * thing we support some ioctls under Linux (autoconfiguration stuff) + */ +/* Little t */ +#define TARGET_TIOCGETD TARGET_IOR('t', 0, int) +#define TARGET_TIOCSETD TARGET_IOW('t', 1, int) +//#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */ +//#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */ +//#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */ +//#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */ +//#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */ +//#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */ +#define TARGET_TIOCEXCL TARGET_IO('t', 13) +#define TARGET_TIOCNXCL TARGET_IO('t', 14) +//#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */ +//#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */ +//#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */ +//#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */ +//#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */ +//#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */ +//#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */ +#define TARGET_TIOCCONS TARGET_IO('t', 36) +//#define __TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */ +//#define __TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */ +#define TARGET_TIOCGSOFTCAR TARGET_IOR('t', 100, int) +#define TARGET_TIOCSSOFTCAR TARGET_IOW('t', 101, int) +//#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */ +#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) +#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) +//#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */ +#define TARGET_TIOCMGET TARGET_IOR('t', 106, int) +#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) +#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) +#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) +#define TARGET_TIOCSTART TARGET_IO('t', 110) +#define TARGET_TIOCSTOP TARGET_IO('t', 111) +#define TARGET_TIOCPKT TARGET_IOW('t', 112, int) +#define TARGET_TIOCNOTTY TARGET_IO('t', 113) +#define TARGET_TIOCSTI TARGET_IOW('t', 114, char) +#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) +//#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */ +//#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */ +/* 118 is the non-posix setpgrp tty ioctl */ +/* 119 is the non-posix getpgrp tty ioctl */ +//#define __TIOCCDTR TARGET_IO('t', 120) /* SunOS Specific */ +//#define __TIOCSDTR TARGET_IO('t', 121) /* SunOS Specific */ +#define TARGET_TIOCCBRK TARGET_IO('t', 122) +#define TARGET_TIOCSBRK TARGET_IO('t', 123) +//#define __TIOCLGET TARGET_IOW('t', 124, int) /* SunOS Specific */ +//#define __TIOCLSET TARGET_IOW('t', 125, int) /* SunOS Specific */ +//#define __TIOCLBIC TARGET_IOW('t', 126, int) /* SunOS Specific */ +//#define __TIOCLBIS TARGET_IOW('t', 127, int) /* SunOS Specific */ +//#define __TIOCISPACE TARGET_IOR('t', 128, int) /* SunOS Specific */ +//#define __TIOCISIZE TARGET_IOR('t', 129, int) /* SunOS Specific */ +#define TARGET_TIOCSPGRP TARGET_IOW('t', 130, int) +#define TARGET_TIOCGPGRP TARGET_IOR('t', 131, int) +#define TARGET_TIOCSCTTY TARGET_IO('t', 132) +#define TARGET_TIOCGSID TARGET_IOR('t', 133, int) +/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */ +#define TARGET_TIOCGPTN TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */ +#define TARGET_TIOCSPTLCK TARGET_IOW('t', 135, int) /* Lock/unlock PTY */ + +/* Little f */ +#define TARGET_FIOCLEX TARGET_IO('f', 1) +#define TARGET_FIONCLEX TARGET_IO('f', 2) +#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) +#define TARGET_FIONBIO TARGET_IOW('f', 126, int) +#define TARGET_FIONREAD TARGET_IOR('f', 127, int) +#define TARGET_TIOCINQ TARGET_FIONREAD + +/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it + * someday. This is completely bogus, I know... + */ +//#define __TCGETSTAT TARGET_IO('T', 200) /* Rutgers specific */ +//#define __TCSETSTAT TARGET_IO('T', 201) /* Rutgers specific */ + +/* Linux specific, no SunOS equivalent. */ +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TCSBRKP 0x5425 +#define TARGET_TIOCTTYGSTRUCT 0x5426 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ +#define TARGET_TIOCMIWAIT 0x545C /* Wait input */ +#define TARGET_TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */ + diff --git a/linux-user/syscall.c b/linux-user/syscall.c new file mode 100644 index 0000000..60ed9a6 --- /dev/null +++ b/linux-user/syscall.c @@ -0,0 +1,3841 @@ +/* + * Linux syscalls + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <elf.h> +#include <endian.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <sys/mount.h> +#include <sys/resource.h> +#include <sys/mman.h> +#include <sys/swap.h> +#include <signal.h> +#include <sched.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/poll.h> +#include <sys/times.h> +#include <sys/shm.h> +#include <sys/statfs.h> +#include <utime.h> +#include <sys/sysinfo.h> +//#include <sys/user.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> + +#define termios host_termios +#define winsize host_winsize +#define termio host_termio +#define sgttyb host_sgttyb /* same as target */ +#define tchars host_tchars /* same as target */ +#define ltchars host_ltchars /* same as target */ + +#include <linux/termios.h> +#include <linux/unistd.h> +#include <linux/utsname.h> +#include <linux/cdrom.h> +#include <linux/hdreg.h> +#include <linux/soundcard.h> +#include <linux/dirent.h> +#include <linux/kd.h> + +#include "qemu.h" + +//#define DEBUG + +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) +/* 16 bit uid wrappers emulation */ +#define USE_UID16 +#endif + +//#include <linux/msdos_fs.h> +#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2]) +#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2]) + + +#undef _syscall0 +#undef _syscall1 +#undef _syscall2 +#undef _syscall3 +#undef _syscall4 +#undef _syscall5 +#undef _syscall6 + +#define _syscall0(type,name) \ +type name (void) \ +{ \ + return syscall(__NR_##name); \ +} + +#define _syscall1(type,name,type1,arg1) \ +type name (type1 arg1) \ +{ \ + return syscall(__NR_##name, arg1); \ +} + +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +type name (type1 arg1,type2 arg2) \ +{ \ + return syscall(__NR_##name, arg1, arg2); \ +} + +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name (type1 arg1,type2 arg2,type3 arg3) \ +{ \ + return syscall(__NR_##name, arg1, arg2, arg3); \ +} + +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \ +{ \ + return syscall(__NR_##name, arg1, arg2, arg3, arg4); \ +} + +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ +{ \ + return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \ +} + + +#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ +{ \ + return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \ +} + + +#define __NR_sys_uname __NR_uname +#define __NR_sys_getcwd1 __NR_getcwd +#define __NR_sys_getdents __NR_getdents +#define __NR_sys_getdents64 __NR_getdents64 +#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo + +#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) +#define __NR__llseek __NR_lseek +#endif + +#ifdef __NR_gettid +_syscall0(int, gettid) +#else +static int gettid(void) { + return -ENOSYS; +} +#endif +_syscall1(int,sys_uname,struct new_utsname *,buf) +_syscall2(int,sys_getcwd1,char *,buf,size_t,size) +_syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count); +_syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count); +_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, + loff_t *, res, uint, wh); +_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) +#ifdef __NR_exit_group +_syscall1(int,exit_group,int,error_code) +#endif + +extern int personality(int); +extern int flock(int, int); +extern int setfsuid(int); +extern int setfsgid(int); +extern int setresuid(uid_t, uid_t, uid_t); +extern int getresuid(uid_t *, uid_t *, uid_t *); +extern int setresgid(gid_t, gid_t, gid_t); +extern int getresgid(gid_t *, gid_t *, gid_t *); +extern int setgroups(int, gid_t *); + +static inline long get_errno(long ret) +{ + if (ret == -1) + return -errno; + else + return ret; +} + +static inline int is_error(long ret) +{ + return (unsigned long)ret >= (unsigned long)(-4096); +} + +static target_ulong target_brk; +static target_ulong target_original_brk; + +void target_set_brk(target_ulong new_brk) +{ + target_original_brk = target_brk = new_brk; +} + +long do_brk(target_ulong new_brk) +{ + target_ulong brk_page; + long mapped_addr; + int new_alloc_size; + + if (!new_brk) + return target_brk; + if (new_brk < target_original_brk) + return -ENOMEM; + + brk_page = HOST_PAGE_ALIGN(target_brk); + + /* If the new brk is less than this, set it and we're done... */ + if (new_brk < brk_page) { + target_brk = new_brk; + return target_brk; + } + + /* We need to allocate more memory after the brk... */ + new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); + mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, + PROT_READ|PROT_WRITE, + MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0)); + if (is_error(mapped_addr)) { + return mapped_addr; + } else { + target_brk = new_brk; + return target_brk; + } +} + +static inline fd_set *target_to_host_fds(fd_set *fds, + target_long *target_fds, int n) +{ +#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) + return (fd_set *)target_fds; +#else + int i, b; + if (target_fds) { + FD_ZERO(fds); + for(i = 0;i < n; i++) { + b = (tswapl(target_fds[i / TARGET_LONG_BITS]) >> + (i & (TARGET_LONG_BITS - 1))) & 1; + if (b) + FD_SET(i, fds); + } + return fds; + } else { + return NULL; + } +#endif +} + +static inline void host_to_target_fds(target_long *target_fds, + fd_set *fds, int n) +{ +#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) + /* nothing to do */ +#else + int i, nw, j, k; + target_long v; + + if (target_fds) { + nw = (n + TARGET_LONG_BITS - 1) / TARGET_LONG_BITS; + k = 0; + for(i = 0;i < nw; i++) { + v = 0; + for(j = 0; j < TARGET_LONG_BITS; j++) { + v |= ((FD_ISSET(k, fds) != 0) << j); + k++; + } + target_fds[i] = tswapl(v); + } + } +#endif +} + +#if defined(__alpha__) +#define HOST_HZ 1024 +#else +#define HOST_HZ 100 +#endif + +static inline long host_to_target_clock_t(long ticks) +{ +#if HOST_HZ == TARGET_HZ + return ticks; +#else + return ((int64_t)ticks * TARGET_HZ) / HOST_HZ; +#endif +} + +static inline void host_to_target_rusage(target_ulong target_addr, + const struct rusage *rusage) +{ + struct target_rusage *target_rusage; + + lock_user_struct(target_rusage, target_addr, 0); + target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec); + target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec); + target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec); + target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec); + target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss); + target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss); + target_rusage->ru_idrss = tswapl(rusage->ru_idrss); + target_rusage->ru_isrss = tswapl(rusage->ru_isrss); + target_rusage->ru_minflt = tswapl(rusage->ru_minflt); + target_rusage->ru_majflt = tswapl(rusage->ru_majflt); + target_rusage->ru_nswap = tswapl(rusage->ru_nswap); + target_rusage->ru_inblock = tswapl(rusage->ru_inblock); + target_rusage->ru_oublock = tswapl(rusage->ru_oublock); + target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd); + target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv); + target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals); + target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw); + target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw); + unlock_user_struct(target_rusage, target_addr, 1); +} + +static inline void target_to_host_timeval(struct timeval *tv, + target_ulong target_addr) +{ + struct target_timeval *target_tv; + + lock_user_struct(target_tv, target_addr, 1); + tv->tv_sec = tswapl(target_tv->tv_sec); + tv->tv_usec = tswapl(target_tv->tv_usec); + unlock_user_struct(target_tv, target_addr, 0); +} + +static inline void host_to_target_timeval(target_ulong target_addr, + const struct timeval *tv) +{ + struct target_timeval *target_tv; + + lock_user_struct(target_tv, target_addr, 0); + target_tv->tv_sec = tswapl(tv->tv_sec); + target_tv->tv_usec = tswapl(tv->tv_usec); + unlock_user_struct(target_tv, target_addr, 1); +} + + +static long do_select(long n, + target_ulong rfd_p, target_ulong wfd_p, + target_ulong efd_p, target_ulong target_tv) +{ + fd_set rfds, wfds, efds; + fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; + target_long *target_rfds, *target_wfds, *target_efds; + struct timeval tv, *tv_ptr; + long ret; + int ok; + + if (rfd_p) { + target_rfds = lock_user(rfd_p, sizeof(target_long) * n, 1); + rfds_ptr = target_to_host_fds(&rfds, target_rfds, n); + } else { + target_rfds = NULL; + rfds_ptr = NULL; + } + if (wfd_p) { + target_wfds = lock_user(wfd_p, sizeof(target_long) * n, 1); + wfds_ptr = target_to_host_fds(&wfds, target_wfds, n); + } else { + target_wfds = NULL; + wfds_ptr = NULL; + } + if (efd_p) { + target_efds = lock_user(efd_p, sizeof(target_long) * n, 1); + efds_ptr = target_to_host_fds(&efds, target_efds, n); + } else { + target_efds = NULL; + efds_ptr = NULL; + } + + if (target_tv) { + target_to_host_timeval(&tv, target_tv); + tv_ptr = &tv; + } else { + tv_ptr = NULL; + } + ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr)); + ok = !is_error(ret); + + if (ok) { + host_to_target_fds(target_rfds, rfds_ptr, n); + host_to_target_fds(target_wfds, wfds_ptr, n); + host_to_target_fds(target_efds, efds_ptr, n); + + if (target_tv) { + host_to_target_timeval(target_tv, &tv); + } + } + if (target_rfds) + unlock_user(target_rfds, rfd_p, ok ? sizeof(target_long) * n : 0); + if (target_wfds) + unlock_user(target_wfds, wfd_p, ok ? sizeof(target_long) * n : 0); + if (target_efds) + unlock_user(target_efds, efd_p, ok ? sizeof(target_long) * n : 0); + + return ret; +} + +static inline void target_to_host_sockaddr(struct sockaddr *addr, + target_ulong target_addr, + socklen_t len) +{ + struct target_sockaddr *target_saddr; + + target_saddr = lock_user(target_addr, len, 1); + memcpy(addr, target_saddr, len); + addr->sa_family = tswap16(target_saddr->sa_family); + unlock_user(target_saddr, target_addr, 0); +} + +static inline void host_to_target_sockaddr(target_ulong target_addr, + struct sockaddr *addr, + socklen_t len) +{ + struct target_sockaddr *target_saddr; + + target_saddr = lock_user(target_addr, len, 0); + memcpy(target_saddr, addr, len); + target_saddr->sa_family = tswap16(addr->sa_family); + unlock_user(target_saddr, target_addr, len); +} + +/* ??? Should this also swap msgh->name? */ +static inline void target_to_host_cmsg(struct msghdr *msgh, + struct target_msghdr *target_msgh) +{ + struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); + struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh); + socklen_t space = 0; + + while (cmsg && target_cmsg) { + void *data = CMSG_DATA(cmsg); + void *target_data = TARGET_CMSG_DATA(target_cmsg); + + int len = tswapl(target_cmsg->cmsg_len) + - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr)); + + space += CMSG_SPACE(len); + if (space > msgh->msg_controllen) { + space -= CMSG_SPACE(len); + gemu_log("Host cmsg overflow\n"); + break; + } + + cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level); + cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type); + cmsg->cmsg_len = CMSG_LEN(len); + + if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { + gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); + memcpy(data, target_data, len); + } else { + int *fd = (int *)data; + int *target_fd = (int *)target_data; + int i, numfds = len / sizeof(int); + + for (i = 0; i < numfds; i++) + fd[i] = tswap32(target_fd[i]); + } + + cmsg = CMSG_NXTHDR(msgh, cmsg); + target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); + } + + msgh->msg_controllen = space; +} + +/* ??? Should this also swap msgh->name? */ +static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, + struct msghdr *msgh) +{ + struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); + struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh); + socklen_t space = 0; + + while (cmsg && target_cmsg) { + void *data = CMSG_DATA(cmsg); + void *target_data = TARGET_CMSG_DATA(target_cmsg); + + int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr)); + + space += TARGET_CMSG_SPACE(len); + if (space > tswapl(target_msgh->msg_controllen)) { + space -= TARGET_CMSG_SPACE(len); + gemu_log("Target cmsg overflow\n"); + break; + } + + target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level); + target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type); + target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len)); + + if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { + gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); + memcpy(target_data, data, len); + } else { + int *fd = (int *)data; + int *target_fd = (int *)target_data; + int i, numfds = len / sizeof(int); + + for (i = 0; i < numfds; i++) + target_fd[i] = tswap32(fd[i]); + } + + cmsg = CMSG_NXTHDR(msgh, cmsg); + target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); + } + + msgh->msg_controllen = tswapl(space); +} + +static long do_setsockopt(int sockfd, int level, int optname, + target_ulong optval, socklen_t optlen) +{ + int val, ret; + + switch(level) { + case SOL_TCP: + /* TCP options all take an 'int' value. */ + if (optlen < sizeof(uint32_t)) + return -EINVAL; + + val = tget32(optval); + ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); + break; + case SOL_IP: + switch(optname) { + case IP_TOS: + case IP_TTL: + case IP_HDRINCL: + case IP_ROUTER_ALERT: + case IP_RECVOPTS: + case IP_RETOPTS: + case IP_PKTINFO: + case IP_MTU_DISCOVER: + case IP_RECVERR: + case IP_RECVTOS: +#ifdef IP_FREEBIND + case IP_FREEBIND: +#endif + case IP_MULTICAST_TTL: + case IP_MULTICAST_LOOP: + val = 0; + if (optlen >= sizeof(uint32_t)) { + val = tget32(optval); + } else if (optlen >= 1) { + val = tget8(optval); + } + ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); + break; + default: + goto unimplemented; + } + break; + case TARGET_SOL_SOCKET: + switch (optname) { + /* Options with 'int' argument. */ + case TARGET_SO_DEBUG: + optname = SO_DEBUG; + break; + case TARGET_SO_REUSEADDR: + optname = SO_REUSEADDR; + break; + case TARGET_SO_TYPE: + optname = SO_TYPE; + break; + case TARGET_SO_ERROR: + optname = SO_ERROR; + break; + case TARGET_SO_DONTROUTE: + optname = SO_DONTROUTE; + break; + case TARGET_SO_BROADCAST: + optname = SO_BROADCAST; + break; + case TARGET_SO_SNDBUF: + optname = SO_SNDBUF; + break; + case TARGET_SO_RCVBUF: + optname = SO_RCVBUF; + break; + case TARGET_SO_KEEPALIVE: + optname = SO_KEEPALIVE; + break; + case TARGET_SO_OOBINLINE: + optname = SO_OOBINLINE; + break; + case TARGET_SO_NO_CHECK: + optname = SO_NO_CHECK; + break; + case TARGET_SO_PRIORITY: + optname = SO_PRIORITY; + break; +#ifdef SO_BSDCOMPAT + case TARGET_SO_BSDCOMPAT: + optname = SO_BSDCOMPAT; + break; +#endif + case TARGET_SO_PASSCRED: + optname = SO_PASSCRED; + break; + case TARGET_SO_TIMESTAMP: + optname = SO_TIMESTAMP; + break; + case TARGET_SO_RCVLOWAT: + optname = SO_RCVLOWAT; + break; + case TARGET_SO_RCVTIMEO: + optname = SO_RCVTIMEO; + break; + case TARGET_SO_SNDTIMEO: + optname = SO_SNDTIMEO; + break; + break; + default: + goto unimplemented; + } + if (optlen < sizeof(uint32_t)) + return -EINVAL; + + val = tget32(optval); + ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val))); + break; + default: + unimplemented: + gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname); + ret = -ENOSYS; + } + return ret; +} + +static long do_getsockopt(int sockfd, int level, int optname, + target_ulong optval, target_ulong optlen) +{ + int len, lv, val, ret; + + switch(level) { + case TARGET_SOL_SOCKET: + level = SOL_SOCKET; + switch (optname) { + case TARGET_SO_LINGER: + case TARGET_SO_RCVTIMEO: + case TARGET_SO_SNDTIMEO: + case TARGET_SO_PEERCRED: + case TARGET_SO_PEERNAME: + /* These don't just return a single integer */ + goto unimplemented; + default: + goto int_case; + } + break; + case SOL_TCP: + /* TCP options all take an 'int' value. */ + int_case: + len = tget32(optlen); + if (len < 0) + return -EINVAL; + lv = sizeof(int); + ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); + if (ret < 0) + return ret; + val = tswap32(val); + if (len > lv) + len = lv; + if (len == 4) + tput32(optval, val); + else + tput8(optval, val); + tput32(optlen, len); + break; + case SOL_IP: + switch(optname) { + case IP_TOS: + case IP_TTL: + case IP_HDRINCL: + case IP_ROUTER_ALERT: + case IP_RECVOPTS: + case IP_RETOPTS: + case IP_PKTINFO: + case IP_MTU_DISCOVER: + case IP_RECVERR: + case IP_RECVTOS: +#ifdef IP_FREEBIND + case IP_FREEBIND: +#endif + case IP_MULTICAST_TTL: + case IP_MULTICAST_LOOP: + len = tget32(optlen); + if (len < 0) + return -EINVAL; + lv = sizeof(int); + ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); + if (ret < 0) + return ret; + if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { + len = 1; + tput32(optlen, len); + tput8(optval, val); + } else { + if (len > sizeof(int)) + len = sizeof(int); + tput32(optlen, len); + tput32(optval, val); + } + break; + default: + goto unimplemented; + } + break; + default: + unimplemented: + gemu_log("getsockopt level=%d optname=%d not yet supported\n", + level, optname); + ret = -ENOSYS; + break; + } + return ret; +} + +static void lock_iovec(struct iovec *vec, target_ulong target_addr, + int count, int copy) +{ + struct target_iovec *target_vec; + target_ulong base; + int i; + + target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1); + for(i = 0;i < count; i++) { + base = tswapl(target_vec[i].iov_base); + vec[i].iov_len = tswapl(target_vec[i].iov_len); + vec[i].iov_base = lock_user(base, vec[i].iov_len, copy); + } + unlock_user (target_vec, target_addr, 0); +} + +static void unlock_iovec(struct iovec *vec, target_ulong target_addr, + int count, int copy) +{ + struct target_iovec *target_vec; + target_ulong base; + int i; + + target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1); + for(i = 0;i < count; i++) { + base = tswapl(target_vec[i].iov_base); + unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); + } + unlock_user (target_vec, target_addr, 0); +} + +static long do_socket(int domain, int type, int protocol) +{ +#if defined(TARGET_MIPS) + switch(type) { + case TARGET_SOCK_DGRAM: + type = SOCK_DGRAM; + break; + case TARGET_SOCK_STREAM: + type = SOCK_STREAM; + break; + case TARGET_SOCK_RAW: + type = SOCK_RAW; + break; + case TARGET_SOCK_RDM: + type = SOCK_RDM; + break; + case TARGET_SOCK_SEQPACKET: + type = SOCK_SEQPACKET; + break; + case TARGET_SOCK_PACKET: + type = SOCK_PACKET; + break; + } +#endif + return get_errno(socket(domain, type, protocol)); +} + +static long do_bind(int sockfd, target_ulong target_addr, + socklen_t addrlen) +{ + void *addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, addrlen); + return get_errno(bind(sockfd, addr, addrlen)); +} + +static long do_connect(int sockfd, target_ulong target_addr, + socklen_t addrlen) +{ + void *addr = alloca(addrlen); + + target_to_host_sockaddr(addr, target_addr, addrlen); + return get_errno(connect(sockfd, addr, addrlen)); +} + +static long do_sendrecvmsg(int fd, target_ulong target_msg, + int flags, int send) +{ + long ret; + struct target_msghdr *msgp; + struct msghdr msg; + int count; + struct iovec *vec; + target_ulong target_vec; + + lock_user_struct(msgp, target_msg, 1); + if (msgp->msg_name) { + msg.msg_namelen = tswap32(msgp->msg_namelen); + msg.msg_name = alloca(msg.msg_namelen); + target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name), + msg.msg_namelen); + } else { + msg.msg_name = NULL; + msg.msg_namelen = 0; + } + msg.msg_controllen = 2 * tswapl(msgp->msg_controllen); + msg.msg_control = alloca(msg.msg_controllen); + msg.msg_flags = tswap32(msgp->msg_flags); + + count = tswapl(msgp->msg_iovlen); + vec = alloca(count * sizeof(struct iovec)); + target_vec = tswapl(msgp->msg_iov); + lock_iovec(vec, target_vec, count, send); + msg.msg_iovlen = count; + msg.msg_iov = vec; + + if (send) { + target_to_host_cmsg(&msg, msgp); + ret = get_errno(sendmsg(fd, &msg, flags)); + } else { + ret = get_errno(recvmsg(fd, &msg, flags)); + if (!is_error(ret)) + host_to_target_cmsg(msgp, &msg); + } + unlock_iovec(vec, target_vec, count, !send); + return ret; +} + +static long do_socketcall(int num, target_ulong vptr) +{ + long ret; + const int n = sizeof(target_ulong); + + switch(num) { + case SOCKOP_socket: + { + int domain = tgetl(vptr); + int type = tgetl(vptr + n); + int protocol = tgetl(vptr + 2 * n); + ret = do_socket(domain, type, protocol); + } + break; + case SOCKOP_bind: + { + int sockfd = tgetl(vptr); + target_ulong target_addr = tgetl(vptr + n); + socklen_t addrlen = tgetl(vptr + 2 * n); + ret = do_bind(sockfd, target_addr, addrlen); + } + break; + case SOCKOP_connect: + { + int sockfd = tgetl(vptr); + target_ulong target_addr = tgetl(vptr + n); + socklen_t addrlen = tgetl(vptr + 2 * n); + ret = do_connect(sockfd, target_addr, addrlen); + } + break; + case SOCKOP_listen: + { + int sockfd = tgetl(vptr); + int backlog = tgetl(vptr + n); + ret = get_errno(listen(sockfd, backlog)); + } + break; + case SOCKOP_accept: + { + int sockfd = tgetl(vptr); + target_ulong target_addr = tgetl(vptr + n); + target_ulong target_addrlen = tgetl(vptr + 2 * n); + socklen_t addrlen = tget32(target_addrlen); + void *addr = alloca(addrlen); + + ret = get_errno(accept(sockfd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + tput32(target_addrlen, addrlen); + } + } + break; + case SOCKOP_getsockname: + { + int sockfd = tgetl(vptr); + target_ulong target_addr = tgetl(vptr + n); + target_ulong target_addrlen = tgetl(vptr + 2 * n); + socklen_t addrlen = tget32(target_addrlen); + void *addr = alloca(addrlen); + + ret = get_errno(getsockname(sockfd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + tput32(target_addrlen, addrlen); + } + } + break; + case SOCKOP_getpeername: + { + int sockfd = tgetl(vptr); + target_ulong target_addr = tgetl(vptr + n); + target_ulong target_addrlen = tgetl(vptr + 2 * n); + socklen_t addrlen = tget32(target_addrlen); + void *addr = alloca(addrlen); + + ret = get_errno(getpeername(sockfd, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + tput32(target_addrlen, addrlen); + } + } + break; + case SOCKOP_socketpair: + { + int domain = tgetl(vptr); + int type = tgetl(vptr + n); + int protocol = tgetl(vptr + 2 * n); + target_ulong target_tab = tgetl(vptr + 3 * n); + int tab[2]; + + ret = get_errno(socketpair(domain, type, protocol, tab)); + if (!is_error(ret)) { + tput32(target_tab, tab[0]); + tput32(target_tab + 4, tab[1]); + } + } + break; + case SOCKOP_send: + { + int sockfd = tgetl(vptr); + target_ulong msg = tgetl(vptr + n); + size_t len = tgetl(vptr + 2 * n); + int flags = tgetl(vptr + 3 * n); + void *host_msg; + + host_msg = lock_user(msg, len, 1); + ret = get_errno(send(sockfd, host_msg, len, flags)); + unlock_user(host_msg, msg, 0); + } + break; + case SOCKOP_recv: + { + int sockfd = tgetl(vptr); + target_ulong msg = tgetl(vptr + n); + size_t len = tgetl(vptr + 2 * n); + int flags = tgetl(vptr + 3 * n); + void *host_msg; + + host_msg = lock_user(msg, len, 0); + ret = get_errno(recv(sockfd, host_msg, len, flags)); + unlock_user(host_msg, msg, ret); + } + break; + case SOCKOP_sendto: + { + int sockfd = tgetl(vptr); + target_ulong msg = tgetl(vptr + n); + size_t len = tgetl(vptr + 2 * n); + int flags = tgetl(vptr + 3 * n); + target_ulong target_addr = tgetl(vptr + 4 * n); + socklen_t addrlen = tgetl(vptr + 5 * n); + void *addr = alloca(addrlen); + void *host_msg; + + host_msg = lock_user(msg, len, 1); + target_to_host_sockaddr(addr, target_addr, addrlen); + ret = get_errno(sendto(sockfd, host_msg, len, flags, addr, addrlen)); + unlock_user(host_msg, msg, 0); + } + break; + case SOCKOP_recvfrom: + { + int sockfd = tgetl(vptr); + target_ulong msg = tgetl(vptr + n); + size_t len = tgetl(vptr + 2 * n); + int flags = tgetl(vptr + 3 * n); + target_ulong target_addr = tgetl(vptr + 4 * n); + target_ulong target_addrlen = tgetl(vptr + 5 * n); + socklen_t addrlen = tget32(target_addrlen); + void *addr = alloca(addrlen); + void *host_msg; + + host_msg = lock_user(msg, len, 0); + ret = get_errno(recvfrom(sockfd, host_msg, len, flags, addr, &addrlen)); + if (!is_error(ret)) { + host_to_target_sockaddr(target_addr, addr, addrlen); + tput32(target_addrlen, addrlen); + unlock_user(host_msg, msg, len); + } else { + unlock_user(host_msg, msg, 0); + } + } + break; + case SOCKOP_shutdown: + { + int sockfd = tgetl(vptr); + int how = tgetl(vptr + n); + + ret = get_errno(shutdown(sockfd, how)); + } + break; + case SOCKOP_sendmsg: + case SOCKOP_recvmsg: + { + int fd; + target_ulong target_msg; + int flags; + + fd = tgetl(vptr); + target_msg = tgetl(vptr + n); + flags = tgetl(vptr + 2 * n); + + ret = do_sendrecvmsg(fd, target_msg, flags, + (num == SOCKOP_sendmsg)); + } + break; + case SOCKOP_setsockopt: + { + int sockfd = tgetl(vptr); + int level = tgetl(vptr + n); + int optname = tgetl(vptr + 2 * n); + target_ulong optval = tgetl(vptr + 3 * n); + socklen_t optlen = tgetl(vptr + 4 * n); + + ret = do_setsockopt(sockfd, level, optname, optval, optlen); + } + break; + case SOCKOP_getsockopt: + { + int sockfd = tgetl(vptr); + int level = tgetl(vptr + n); + int optname = tgetl(vptr + 2 * n); + target_ulong optval = tgetl(vptr + 3 * n); + target_ulong poptlen = tgetl(vptr + 4 * n); + + ret = do_getsockopt(sockfd, level, optname, optval, poptlen); + } + break; + default: + gemu_log("Unsupported socketcall: %d\n", num); + ret = -ENOSYS; + break; + } + return ret; +} + +/* XXX: suppress this function and call directly the related socket + functions */ +static long do_socketcallwrapper(int num, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6) +{ + target_long args[6]; + + tputl(args, arg1); + tputl(args+1, arg2); + tputl(args+2, arg3); + tputl(args+3, arg4); + tputl(args+4, arg5); + tputl(args+5, arg6); + + return do_socketcall(num, (target_ulong) args); +} + +#define N_SHM_REGIONS 32 + +static struct shm_region { + uint32_t start; + uint32_t size; +} shm_regions[N_SHM_REGIONS]; + +/* ??? This only works with linear mappings. */ +static long do_ipc(long call, long first, long second, long third, + long ptr, long fifth) +{ + int version; + long ret = 0; + unsigned long raddr; + struct shmid_ds shm_info; + int i; + + version = call >> 16; + call &= 0xffff; + + switch (call) { + case IPCOP_shmat: + /* SHM_* flags are the same on all linux platforms */ + ret = get_errno((long) shmat(first, (void *) ptr, second)); + if (is_error(ret)) + break; + raddr = ret; + /* find out the length of the shared memory segment */ + + ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); + if (is_error(ret)) { + /* can't get length, bail out */ + shmdt((void *) raddr); + break; + } + page_set_flags(raddr, raddr + shm_info.shm_segsz, + PAGE_VALID | PAGE_READ | + ((second & SHM_RDONLY)? 0: PAGE_WRITE)); + for (i = 0; i < N_SHM_REGIONS; ++i) { + if (shm_regions[i].start == 0) { + shm_regions[i].start = raddr; + shm_regions[i].size = shm_info.shm_segsz; + break; + } + } + if (put_user(raddr, (uint32_t *)third)) + return -EFAULT; + ret = 0; + break; + case IPCOP_shmdt: + for (i = 0; i < N_SHM_REGIONS; ++i) { + if (shm_regions[i].start == ptr) { + shm_regions[i].start = 0; + page_set_flags(ptr, shm_regions[i].size, 0); + break; + } + } + ret = get_errno(shmdt((void *) ptr)); + break; + + case IPCOP_shmget: + /* IPC_* flag values are the same on all linux platforms */ + ret = get_errno(shmget(first, second, third)); + break; + + /* IPC_* and SHM_* command values are the same on all linux platforms */ + case IPCOP_shmctl: + switch(second) { + case IPC_RMID: + case SHM_LOCK: + case SHM_UNLOCK: + ret = get_errno(shmctl(first, second, NULL)); + break; + default: + goto unimplemented; + } + break; + default: + unimplemented: + gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version); + ret = -ENOSYS; + break; + } + return ret; +} + +/* kernel structure types definitions */ +#define IFNAMSIZ 16 + +#define STRUCT(name, list...) STRUCT_ ## name, +#define STRUCT_SPECIAL(name) STRUCT_ ## name, +enum { +#include "syscall_types.h" +}; +#undef STRUCT +#undef STRUCT_SPECIAL + +#define STRUCT(name, list...) const argtype struct_ ## name ## _def[] = { list, TYPE_NULL }; +#define STRUCT_SPECIAL(name) +#include "syscall_types.h" +#undef STRUCT +#undef STRUCT_SPECIAL + +typedef struct IOCTLEntry { + unsigned int target_cmd; + unsigned int host_cmd; + const char *name; + int access; + const argtype arg_type[5]; +} IOCTLEntry; + +#define IOC_R 0x0001 +#define IOC_W 0x0002 +#define IOC_RW (IOC_R | IOC_W) + +#define MAX_STRUCT_SIZE 4096 + +IOCTLEntry ioctl_entries[] = { +#define IOCTL(cmd, access, types...) \ + { TARGET_ ## cmd, cmd, #cmd, access, { types } }, +#include "ioctls.h" + { 0, 0, }, +}; + +/* ??? Implement proper locking for ioctls. */ +static long do_ioctl(long fd, long cmd, long arg) +{ + const IOCTLEntry *ie; + const argtype *arg_type; + long ret; + uint8_t buf_temp[MAX_STRUCT_SIZE]; + int target_size; + void *argptr; + + ie = ioctl_entries; + for(;;) { + if (ie->target_cmd == 0) { + gemu_log("Unsupported ioctl: cmd=0x%04lx\n", cmd); + return -ENOSYS; + } + if (ie->target_cmd == cmd) + break; + ie++; + } + arg_type = ie->arg_type; +#if defined(DEBUG) + gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name); +#endif + switch(arg_type[0]) { + case TYPE_NULL: + /* no argument */ + ret = get_errno(ioctl(fd, ie->host_cmd)); + break; + case TYPE_PTRVOID: + case TYPE_INT: + /* int argment */ + ret = get_errno(ioctl(fd, ie->host_cmd, arg)); + break; + case TYPE_PTR: + arg_type++; + target_size = thunk_type_size(arg_type, 0); + switch(ie->access) { + case IOC_R: + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + if (!is_error(ret)) { + argptr = lock_user(arg, target_size, 0); + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); + unlock_user(argptr, arg, target_size); + } + break; + case IOC_W: + argptr = lock_user(arg, target_size, 1); + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + break; + default: + case IOC_RW: + argptr = lock_user(arg, target_size, 1); + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); + if (!is_error(ret)) { + argptr = lock_user(arg, target_size, 0); + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); + unlock_user(argptr, arg, target_size); + } + break; + } + break; + default: + gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", cmd, arg_type[0]); + ret = -ENOSYS; + break; + } + return ret; +} + +bitmask_transtbl iflag_tbl[] = { + { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK }, + { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT }, + { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR }, + { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK }, + { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK }, + { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP }, + { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR }, + { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR }, + { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL }, + { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC }, + { TARGET_IXON, TARGET_IXON, IXON, IXON }, + { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY }, + { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF }, + { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL }, + { 0, 0, 0, 0 } +}; + +bitmask_transtbl oflag_tbl[] = { + { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST }, + { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC }, + { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR }, + { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL }, + { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR }, + { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET }, + { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL }, + { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL }, + { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 }, + { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 }, + { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 }, + { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 }, + { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 }, + { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 }, + { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 }, + { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 }, + { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 }, + { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 }, + { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 }, + { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 }, + { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 }, + { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 }, + { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 }, + { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 }, + { 0, 0, 0, 0 } +}; + +bitmask_transtbl cflag_tbl[] = { + { TARGET_CBAUD, TARGET_B0, CBAUD, B0 }, + { TARGET_CBAUD, TARGET_B50, CBAUD, B50 }, + { TARGET_CBAUD, TARGET_B75, CBAUD, B75 }, + { TARGET_CBAUD, TARGET_B110, CBAUD, B110 }, + { TARGET_CBAUD, TARGET_B134, CBAUD, B134 }, + { TARGET_CBAUD, TARGET_B150, CBAUD, B150 }, + { TARGET_CBAUD, TARGET_B200, CBAUD, B200 }, + { TARGET_CBAUD, TARGET_B300, CBAUD, B300 }, + { TARGET_CBAUD, TARGET_B600, CBAUD, B600 }, + { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 }, + { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 }, + { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 }, + { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 }, + { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 }, + { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 }, + { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 }, + { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 }, + { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 }, + { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 }, + { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 }, + { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 }, + { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 }, + { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 }, + { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 }, + { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB }, + { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD }, + { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB }, + { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD }, + { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL }, + { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL }, + { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS }, + { 0, 0, 0, 0 } +}; + +bitmask_transtbl lflag_tbl[] = { + { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG }, + { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON }, + { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE }, + { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO }, + { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE }, + { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK }, + { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL }, + { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH }, + { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP }, + { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL }, + { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT }, + { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE }, + { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO }, + { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN }, + { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN }, + { 0, 0, 0, 0 } +}; + +static void target_to_host_termios (void *dst, const void *src) +{ + struct host_termios *host = dst; + const struct target_termios *target = src; + + host->c_iflag = + target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl); + host->c_oflag = + target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl); + host->c_cflag = + target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl); + host->c_lflag = + target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl); + host->c_line = target->c_line; + + host->c_cc[VINTR] = target->c_cc[TARGET_VINTR]; + host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT]; + host->c_cc[VERASE] = target->c_cc[TARGET_VERASE]; + host->c_cc[VKILL] = target->c_cc[TARGET_VKILL]; + host->c_cc[VEOF] = target->c_cc[TARGET_VEOF]; + host->c_cc[VTIME] = target->c_cc[TARGET_VTIME]; + host->c_cc[VMIN] = target->c_cc[TARGET_VMIN]; + host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC]; + host->c_cc[VSTART] = target->c_cc[TARGET_VSTART]; + host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP]; + host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP]; + host->c_cc[VEOL] = target->c_cc[TARGET_VEOL]; + host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT]; + host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD]; + host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE]; + host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT]; + host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2]; +} + +static void host_to_target_termios (void *dst, const void *src) +{ + struct target_termios *target = dst; + const struct host_termios *host = src; + + target->c_iflag = + tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl)); + target->c_oflag = + tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl)); + target->c_cflag = + tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl)); + target->c_lflag = + tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl)); + target->c_line = host->c_line; + + target->c_cc[TARGET_VINTR] = host->c_cc[VINTR]; + target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT]; + target->c_cc[TARGET_VERASE] = host->c_cc[VERASE]; + target->c_cc[TARGET_VKILL] = host->c_cc[VKILL]; + target->c_cc[TARGET_VEOF] = host->c_cc[VEOF]; + target->c_cc[TARGET_VTIME] = host->c_cc[VTIME]; + target->c_cc[TARGET_VMIN] = host->c_cc[VMIN]; + target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC]; + target->c_cc[TARGET_VSTART] = host->c_cc[VSTART]; + target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP]; + target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP]; + target->c_cc[TARGET_VEOL] = host->c_cc[VEOL]; + target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT]; + target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD]; + target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE]; + target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT]; + target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2]; +} + +StructEntry struct_termios_def = { + .convert = { host_to_target_termios, target_to_host_termios }, + .size = { sizeof(struct target_termios), sizeof(struct host_termios) }, + .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) }, +}; + +static bitmask_transtbl mmap_flags_tbl[] = { + { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED }, + { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE }, + { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED }, + { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS }, + { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN }, + { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE }, + { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE }, + { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED }, + { 0, 0, 0, 0 } +}; + +static bitmask_transtbl fcntl_flags_tbl[] = { + { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, }, + { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, }, + { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, }, + { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, }, + { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, }, + { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, }, + { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, }, + { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, }, + { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, }, + { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, }, + { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, }, + { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, }, + { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, }, +#if defined(O_DIRECT) + { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, }, +#endif + { 0, 0, 0, 0 } +}; + +#if defined(TARGET_I386) + +/* NOTE: there is really one LDT for all the threads */ +uint8_t *ldt_table; + +static int read_ldt(target_ulong ptr, unsigned long bytecount) +{ + int size; + void *p; + + if (!ldt_table) + return 0; + size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE; + if (size > bytecount) + size = bytecount; + p = lock_user(ptr, size, 0); + /* ??? Shoudl this by byteswapped? */ + memcpy(p, ldt_table, size); + unlock_user(p, ptr, size); + return size; +} + +/* XXX: add locking support */ +static int write_ldt(CPUX86State *env, + target_ulong ptr, unsigned long bytecount, int oldmode) +{ + struct target_modify_ldt_ldt_s ldt_info; + struct target_modify_ldt_ldt_s *target_ldt_info; + int seg_32bit, contents, read_exec_only, limit_in_pages; + int seg_not_present, useable; + uint32_t *lp, entry_1, entry_2; + + if (bytecount != sizeof(ldt_info)) + return -EINVAL; + lock_user_struct(target_ldt_info, ptr, 1); + ldt_info.entry_number = tswap32(target_ldt_info->entry_number); + ldt_info.base_addr = tswapl(target_ldt_info->base_addr); + ldt_info.limit = tswap32(target_ldt_info->limit); + ldt_info.flags = tswap32(target_ldt_info->flags); + unlock_user_struct(target_ldt_info, ptr, 0); + + if (ldt_info.entry_number >= TARGET_LDT_ENTRIES) + return -EINVAL; + seg_32bit = ldt_info.flags & 1; + contents = (ldt_info.flags >> 1) & 3; + read_exec_only = (ldt_info.flags >> 3) & 1; + limit_in_pages = (ldt_info.flags >> 4) & 1; + seg_not_present = (ldt_info.flags >> 5) & 1; + useable = (ldt_info.flags >> 6) & 1; + + if (contents == 3) { + if (oldmode) + return -EINVAL; + if (seg_not_present == 0) + return -EINVAL; + } + /* allocate the LDT */ + if (!ldt_table) { + ldt_table = malloc(TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); + if (!ldt_table) + return -ENOMEM; + memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); + env->ldt.base = h2g(ldt_table); + env->ldt.limit = 0xffff; + } + + /* NOTE: same code as Linux kernel */ + /* Allow LDTs to be cleared by the user. */ + if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { + if (oldmode || + (contents == 0 && + read_exec_only == 1 && + seg_32bit == 0 && + limit_in_pages == 0 && + seg_not_present == 1 && + useable == 0 )) { + entry_1 = 0; + entry_2 = 0; + goto install; + } + } + + entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | + (ldt_info.limit & 0x0ffff); + entry_2 = (ldt_info.base_addr & 0xff000000) | + ((ldt_info.base_addr & 0x00ff0000) >> 16) | + (ldt_info.limit & 0xf0000) | + ((read_exec_only ^ 1) << 9) | + (contents << 10) | + ((seg_not_present ^ 1) << 15) | + (seg_32bit << 22) | + (limit_in_pages << 23) | + 0x7000; + if (!oldmode) + entry_2 |= (useable << 20); + + /* Install the new entry ... */ +install: + lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3)); + lp[0] = tswap32(entry_1); + lp[1] = tswap32(entry_2); + return 0; +} + +/* specific and weird i386 syscalls */ +int do_modify_ldt(CPUX86State *env, int func, target_ulong ptr, unsigned long bytecount) +{ + int ret = -ENOSYS; + + switch (func) { + case 0: + ret = read_ldt(ptr, bytecount); + break; + case 1: + ret = write_ldt(env, ptr, bytecount, 1); + break; + case 0x11: + ret = write_ldt(env, ptr, bytecount, 0); + break; + } + return ret; +} + +#endif /* defined(TARGET_I386) */ + +/* this stack is the equivalent of the kernel stack associated with a + thread/process */ +#define NEW_STACK_SIZE 8192 + +static int clone_func(void *arg) +{ + CPUState *env = arg; + cpu_loop(env); + /* never exits */ + return 0; +} + +int do_fork(CPUState *env, unsigned int flags, unsigned long newsp) +{ + int ret; + TaskState *ts; + uint8_t *new_stack; + CPUState *new_env; + + if (flags & CLONE_VM) { + ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE); + memset(ts, 0, sizeof(TaskState)); + new_stack = ts->stack; + ts->used = 1; + /* add in task state list */ + ts->next = first_task_state; + first_task_state = ts; + /* we create a new CPU instance. */ + new_env = cpu_init(); + memcpy(new_env, env, sizeof(CPUState)); +#if defined(TARGET_I386) + if (!newsp) + newsp = env->regs[R_ESP]; + new_env->regs[R_ESP] = newsp; + new_env->regs[R_EAX] = 0; +#elif defined(TARGET_ARM) + if (!newsp) + newsp = env->regs[13]; + new_env->regs[13] = newsp; + new_env->regs[0] = 0; +#elif defined(TARGET_SPARC) + if (!newsp) + newsp = env->regwptr[22]; + new_env->regwptr[22] = newsp; + new_env->regwptr[0] = 0; + /* XXXXX */ + printf ("HELPME: %s:%d\n", __FILE__, __LINE__); +#elif defined(TARGET_MIPS) + printf ("HELPME: %s:%d\n", __FILE__, __LINE__); +#elif defined(TARGET_PPC) + if (!newsp) + newsp = env->gpr[1]; + new_env->gpr[1] = newsp; + { + int i; + for (i = 7; i < 32; i++) + new_env->gpr[i] = 0; + } +#elif defined(TARGET_SH4) + if (!newsp) + newsp = env->gregs[15]; + new_env->gregs[15] = newsp; + /* XXXXX */ +#else +#error unsupported target CPU +#endif + new_env->opaque = ts; +#ifdef __ia64__ + ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); +#else + ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); +#endif + } else { + /* if no CLONE_VM, we consider it is a fork */ + if ((flags & ~CSIGNAL) != 0) + return -EINVAL; + ret = fork(); + } + return ret; +} + +static long do_fcntl(int fd, int cmd, target_ulong arg) +{ + struct flock fl; + struct target_flock *target_fl; + long ret; + + switch(cmd) { + case TARGET_F_GETLK: + ret = fcntl(fd, cmd, &fl); + if (ret == 0) { + lock_user_struct(target_fl, arg, 0); + target_fl->l_type = tswap16(fl.l_type); + target_fl->l_whence = tswap16(fl.l_whence); + target_fl->l_start = tswapl(fl.l_start); + target_fl->l_len = tswapl(fl.l_len); + target_fl->l_pid = tswapl(fl.l_pid); + unlock_user_struct(target_fl, arg, 1); + } + break; + + case TARGET_F_SETLK: + case TARGET_F_SETLKW: + lock_user_struct(target_fl, arg, 1); + fl.l_type = tswap16(target_fl->l_type); + fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswapl(target_fl->l_start); + fl.l_len = tswapl(target_fl->l_len); + fl.l_pid = tswapl(target_fl->l_pid); + unlock_user_struct(target_fl, arg, 0); + ret = fcntl(fd, cmd, &fl); + break; + + case TARGET_F_GETLK64: + case TARGET_F_SETLK64: + case TARGET_F_SETLKW64: + ret = -1; + errno = EINVAL; + break; + + case F_GETFL: + ret = fcntl(fd, cmd, arg); + ret = host_to_target_bitmask(ret, fcntl_flags_tbl); + break; + + case F_SETFL: + ret = fcntl(fd, cmd, target_to_host_bitmask(arg, fcntl_flags_tbl)); + break; + + default: + ret = fcntl(fd, cmd, arg); + break; + } + return ret; +} + +#ifdef USE_UID16 + +static inline int high2lowuid(int uid) +{ + if (uid > 65535) + return 65534; + else + return uid; +} + +static inline int high2lowgid(int gid) +{ + if (gid > 65535) + return 65534; + else + return gid; +} + +static inline int low2highuid(int uid) +{ + if ((int16_t)uid == -1) + return -1; + else + return uid; +} + +static inline int low2highgid(int gid) +{ + if ((int16_t)gid == -1) + return -1; + else + return gid; +} + +#endif /* USE_UID16 */ + +void syscall_init(void) +{ + IOCTLEntry *ie; + const argtype *arg_type; + int size; + +#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); +#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def); +#include "syscall_types.h" +#undef STRUCT +#undef STRUCT_SPECIAL + + /* we patch the ioctl size if necessary. We rely on the fact that + no ioctl has all the bits at '1' in the size field */ + ie = ioctl_entries; + while (ie->target_cmd != 0) { + if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) == + TARGET_IOC_SIZEMASK) { + arg_type = ie->arg_type; + if (arg_type[0] != TYPE_PTR) { + fprintf(stderr, "cannot patch size for ioctl 0x%x\n", + ie->target_cmd); + exit(1); + } + arg_type++; + size = thunk_type_size(arg_type, 0); + ie->target_cmd = (ie->target_cmd & + ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) | + (size << TARGET_IOC_SIZESHIFT); + } + /* automatic consistency check if same arch */ +#if defined(__i386__) && defined(TARGET_I386) + if (ie->target_cmd != ie->host_cmd) { + fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n", + ie->target_cmd, ie->host_cmd); + } +#endif + ie++; + } +} + +static inline uint64_t target_offset64(uint32_t word0, uint32_t word1) +{ +#ifdef TARGET_WORDS_BIG_ENDIAN + return ((uint64_t)word0 << 32) | word1; +#else + return ((uint64_t)word1 << 32) | word0; +#endif +} + +#ifdef TARGET_NR_truncate64 +static inline long target_truncate64(void *cpu_env, const char *arg1, + long arg2, long arg3, long arg4) +{ +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) + { + arg2 = arg3; + arg3 = arg4; + } +#endif + return get_errno(truncate64(arg1, target_offset64(arg2, arg3))); +} +#endif + +#ifdef TARGET_NR_ftruncate64 +static inline long target_ftruncate64(void *cpu_env, long arg1, long arg2, + long arg3, long arg4) +{ +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) + { + arg2 = arg3; + arg3 = arg4; + } +#endif + return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3))); +} +#endif + +static inline void target_to_host_timespec(struct timespec *host_ts, + target_ulong target_addr) +{ + struct target_timespec *target_ts; + + lock_user_struct(target_ts, target_addr, 1); + host_ts->tv_sec = tswapl(target_ts->tv_sec); + host_ts->tv_nsec = tswapl(target_ts->tv_nsec); + unlock_user_struct(target_ts, target_addr, 0); +} + +static inline void host_to_target_timespec(target_ulong target_addr, + struct timespec *host_ts) +{ + struct target_timespec *target_ts; + + lock_user_struct(target_ts, target_addr, 0); + target_ts->tv_sec = tswapl(host_ts->tv_sec); + target_ts->tv_nsec = tswapl(host_ts->tv_nsec); + unlock_user_struct(target_ts, target_addr, 1); +} + +long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6) +{ + long ret; + struct stat st; + struct statfs stfs; + void *p; + +#ifdef DEBUG + gemu_log("syscall %d", num); +#endif + switch(num) { + case TARGET_NR_exit: +#ifdef HAVE_GPROF + _mcleanup(); +#endif + gdb_exit(cpu_env, arg1); + /* XXX: should free thread stack and CPU env */ + _exit(arg1); + ret = 0; /* avoid warning */ + break; + case TARGET_NR_read: + page_unprotect_range(arg2, arg3); + p = lock_user(arg2, arg3, 0); + ret = get_errno(read(arg1, p, arg3)); + unlock_user(p, arg2, ret); + break; + case TARGET_NR_write: + p = lock_user(arg2, arg3, 1); + ret = get_errno(write(arg1, p, arg3)); + unlock_user(p, arg2, 0); + break; + case TARGET_NR_open: + p = lock_user_string(arg1); + ret = get_errno(open(path(p), + target_to_host_bitmask(arg2, fcntl_flags_tbl), + arg3)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_close: + ret = get_errno(close(arg1)); + break; + case TARGET_NR_brk: + ret = do_brk(arg1); + break; + case TARGET_NR_fork: + ret = get_errno(do_fork(cpu_env, SIGCHLD, 0)); + break; + case TARGET_NR_waitpid: + { + int status; + ret = get_errno(waitpid(arg1, &status, arg3)); + if (!is_error(ret) && arg2) + tput32(arg2, status); + } + break; + case TARGET_NR_creat: + p = lock_user_string(arg1); + ret = get_errno(creat(p, arg2)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_link: + { + void * p2; + p = lock_user_string(arg1); + p2 = lock_user_string(arg2); + ret = get_errno(link(p, p2)); + unlock_user(p2, arg2, 0); + unlock_user(p, arg1, 0); + } + break; + case TARGET_NR_unlink: + p = lock_user_string(arg1); + ret = get_errno(unlink(p)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_execve: + { + char **argp, **envp; + int argc, envc; + target_ulong gp; + target_ulong guest_argp; + target_ulong guest_envp; + target_ulong addr; + char **q; + + argc = 0; + guest_argp = arg2; + for (gp = guest_argp; tgetl(gp); gp++) + argc++; + envc = 0; + guest_envp = arg3; + for (gp = guest_envp; tgetl(gp); gp++) + envc++; + + argp = alloca((argc + 1) * sizeof(void *)); + envp = alloca((envc + 1) * sizeof(void *)); + + for (gp = guest_argp, q = argp; ; + gp += sizeof(target_ulong), q++) { + addr = tgetl(gp); + if (!addr) + break; + *q = lock_user_string(addr); + } + *q = NULL; + + for (gp = guest_envp, q = envp; ; + gp += sizeof(target_ulong), q++) { + addr = tgetl(gp); + if (!addr) + break; + *q = lock_user_string(addr); + } + *q = NULL; + + p = lock_user_string(arg1); + ret = get_errno(execve(p, argp, envp)); + unlock_user(p, arg1, 0); + + for (gp = guest_argp, q = argp; *q; + gp += sizeof(target_ulong), q++) { + addr = tgetl(gp); + unlock_user(*q, addr, 0); + } + for (gp = guest_envp, q = envp; *q; + gp += sizeof(target_ulong), q++) { + addr = tgetl(gp); + unlock_user(*q, addr, 0); + } + } + break; + case TARGET_NR_chdir: + p = lock_user_string(arg1); + ret = get_errno(chdir(p)); + unlock_user(p, arg1, 0); + break; +#ifdef TARGET_NR_time + case TARGET_NR_time: + { + time_t host_time; + ret = get_errno(time(&host_time)); + if (!is_error(ret) && arg1) + tputl(arg1, host_time); + } + break; +#endif + case TARGET_NR_mknod: + p = lock_user_string(arg1); + ret = get_errno(mknod(p, arg2, arg3)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_chmod: + p = lock_user_string(arg1); + ret = get_errno(chmod(p, arg2)); + unlock_user(p, arg1, 0); + break; +#ifdef TARGET_NR_break + case TARGET_NR_break: + goto unimplemented; +#endif +#ifdef TARGET_NR_oldstat + case TARGET_NR_oldstat: + goto unimplemented; +#endif + case TARGET_NR_lseek: + ret = get_errno(lseek(arg1, arg2, arg3)); + break; + case TARGET_NR_getpid: + ret = get_errno(getpid()); + break; + case TARGET_NR_mount: + /* need to look at the data field */ + goto unimplemented; + case TARGET_NR_umount: + p = lock_user_string(arg1); + ret = get_errno(umount(p)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_stime: + { + time_t host_time; + host_time = tgetl(arg1); + ret = get_errno(stime(&host_time)); + } + break; + case TARGET_NR_ptrace: + goto unimplemented; + case TARGET_NR_alarm: + ret = alarm(arg1); + break; +#ifdef TARGET_NR_oldfstat + case TARGET_NR_oldfstat: + goto unimplemented; +#endif + case TARGET_NR_pause: + ret = get_errno(pause()); + break; + case TARGET_NR_utime: + { + struct utimbuf tbuf, *host_tbuf; + struct target_utimbuf *target_tbuf; + if (arg2) { + lock_user_struct(target_tbuf, arg2, 1); + tbuf.actime = tswapl(target_tbuf->actime); + tbuf.modtime = tswapl(target_tbuf->modtime); + unlock_user_struct(target_tbuf, arg2, 0); + host_tbuf = &tbuf; + } else { + host_tbuf = NULL; + } + p = lock_user_string(arg1); + ret = get_errno(utime(p, host_tbuf)); + unlock_user(p, arg1, 0); + } + break; + case TARGET_NR_utimes: + { + struct timeval *tvp, tv[2]; + if (arg2) { + target_to_host_timeval(&tv[0], arg2); + target_to_host_timeval(&tv[1], + arg2 + sizeof (struct target_timeval)); + tvp = tv; + } else { + tvp = NULL; + } + p = lock_user_string(arg1); + ret = get_errno(utimes(p, tvp)); + unlock_user(p, arg1, 0); + } + break; +#ifdef TARGET_NR_stty + case TARGET_NR_stty: + goto unimplemented; +#endif +#ifdef TARGET_NR_gtty + case TARGET_NR_gtty: + goto unimplemented; +#endif + case TARGET_NR_access: + p = lock_user_string(arg1); + ret = get_errno(access(p, arg2)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_nice: + ret = get_errno(nice(arg1)); + break; +#ifdef TARGET_NR_ftime + case TARGET_NR_ftime: + goto unimplemented; +#endif + case TARGET_NR_sync: + sync(); + ret = 0; + break; + case TARGET_NR_kill: + ret = get_errno(kill(arg1, arg2)); + break; + case TARGET_NR_rename: + { + void *p2; + p = lock_user_string(arg1); + p2 = lock_user_string(arg2); + ret = get_errno(rename(p, p2)); + unlock_user(p2, arg2, 0); + unlock_user(p, arg1, 0); + } + break; + case TARGET_NR_mkdir: + p = lock_user_string(arg1); + ret = get_errno(mkdir(p, arg2)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_rmdir: + p = lock_user_string(arg1); + ret = get_errno(rmdir(p)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_dup: + ret = get_errno(dup(arg1)); + break; + case TARGET_NR_pipe: + { + int host_pipe[2]; + ret = get_errno(pipe(host_pipe)); + if (!is_error(ret)) { + tput32(arg1, host_pipe[0]); + tput32(arg1 + 4, host_pipe[1]); + } + } + break; + case TARGET_NR_times: + { + struct target_tms *tmsp; + struct tms tms; + ret = get_errno(times(&tms)); + if (arg1) { + tmsp = lock_user(arg1, sizeof(struct target_tms), 0); + tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime)); + tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime)); + tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime)); + tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime)); + } + if (!is_error(ret)) + ret = host_to_target_clock_t(ret); + } + break; +#ifdef TARGET_NR_prof + case TARGET_NR_prof: + goto unimplemented; +#endif + case TARGET_NR_signal: + goto unimplemented; + + case TARGET_NR_acct: + p = lock_user_string(arg1); + ret = get_errno(acct(path(p))); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_umount2: + p = lock_user_string(arg1); + ret = get_errno(umount2(p, arg2)); + unlock_user(p, arg1, 0); + break; +#ifdef TARGET_NR_lock + case TARGET_NR_lock: + goto unimplemented; +#endif + case TARGET_NR_ioctl: + ret = do_ioctl(arg1, arg2, arg3); + break; + case TARGET_NR_fcntl: + ret = get_errno(do_fcntl(arg1, arg2, arg3)); + break; +#ifdef TARGET_NR_mpx + case TARGET_NR_mpx: + goto unimplemented; +#endif + case TARGET_NR_setpgid: + ret = get_errno(setpgid(arg1, arg2)); + break; +#ifdef TARGET_NR_ulimit + case TARGET_NR_ulimit: + goto unimplemented; +#endif +#ifdef TARGET_NR_oldolduname + case TARGET_NR_oldolduname: + goto unimplemented; +#endif + case TARGET_NR_umask: + ret = get_errno(umask(arg1)); + break; + case TARGET_NR_chroot: + p = lock_user_string(arg1); + ret = get_errno(chroot(p)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_ustat: + goto unimplemented; + case TARGET_NR_dup2: + ret = get_errno(dup2(arg1, arg2)); + break; + case TARGET_NR_getppid: + ret = get_errno(getppid()); + break; + case TARGET_NR_getpgrp: + ret = get_errno(getpgrp()); + break; + case TARGET_NR_setsid: + ret = get_errno(setsid()); + break; + case TARGET_NR_sigaction: + { + #if !defined(TARGET_MIPS) + struct target_old_sigaction *old_act; + struct target_sigaction act, oact, *pact; + if (arg2) { + lock_user_struct(old_act, arg2, 1); + act._sa_handler = old_act->_sa_handler; + target_siginitset(&act.sa_mask, old_act->sa_mask); + act.sa_flags = old_act->sa_flags; + act.sa_restorer = old_act->sa_restorer; + unlock_user_struct(old_act, arg2, 0); + pact = &act; + } else { + pact = NULL; + } + ret = get_errno(do_sigaction(arg1, pact, &oact)); + if (!is_error(ret) && arg3) { + lock_user_struct(old_act, arg3, 0); + old_act->_sa_handler = oact._sa_handler; + old_act->sa_mask = oact.sa_mask.sig[0]; + old_act->sa_flags = oact.sa_flags; + old_act->sa_restorer = oact.sa_restorer; + unlock_user_struct(old_act, arg3, 1); + } + #else + struct target_sigaction act, oact, *pact, *old_act; + + if (arg2) { + lock_user_struct(old_act, arg2, 1); + act._sa_handler = old_act->_sa_handler; + target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]); + act.sa_flags = old_act->sa_flags; + unlock_user_struct(old_act, arg2, 0); + pact = &act; + } else { + pact = NULL; + } + + ret = get_errno(do_sigaction(arg1, pact, &oact)); + + if (!is_error(ret) && arg3) { + lock_user_struct(old_act, arg3, 0); + old_act->_sa_handler = oact._sa_handler; + old_act->sa_flags = oact.sa_flags; + old_act->sa_mask.sig[0] = oact.sa_mask.sig[0]; + old_act->sa_mask.sig[1] = 0; + old_act->sa_mask.sig[2] = 0; + old_act->sa_mask.sig[3] = 0; + unlock_user_struct(old_act, arg3, 1); + } + #endif + } + break; + case TARGET_NR_rt_sigaction: + { + struct target_sigaction *act; + struct target_sigaction *oact; + + if (arg2) + lock_user_struct(act, arg2, 1); + else + act = NULL; + if (arg3) + lock_user_struct(oact, arg3, 0); + else + oact = NULL; + ret = get_errno(do_sigaction(arg1, act, oact)); + if (arg2) + unlock_user_struct(act, arg2, 0); + if (arg3) + unlock_user_struct(oact, arg3, 1); + } + break; + case TARGET_NR_sgetmask: + { + sigset_t cur_set; + target_ulong target_set; + sigprocmask(0, NULL, &cur_set); + host_to_target_old_sigset(&target_set, &cur_set); + ret = target_set; + } + break; + case TARGET_NR_ssetmask: + { + sigset_t set, oset, cur_set; + target_ulong target_set = arg1; + sigprocmask(0, NULL, &cur_set); + target_to_host_old_sigset(&set, &target_set); + sigorset(&set, &set, &cur_set); + sigprocmask(SIG_SETMASK, &set, &oset); + host_to_target_old_sigset(&target_set, &oset); + ret = target_set; + } + break; + case TARGET_NR_sigprocmask: + { + int how = arg1; + sigset_t set, oldset, *set_ptr; + + if (arg2) { + switch(how) { + case TARGET_SIG_BLOCK: + how = SIG_BLOCK; + break; + case TARGET_SIG_UNBLOCK: + how = SIG_UNBLOCK; + break; + case TARGET_SIG_SETMASK: + how = SIG_SETMASK; + break; + default: + ret = -EINVAL; + goto fail; + } + p = lock_user(arg2, sizeof(target_sigset_t), 1); + target_to_host_old_sigset(&set, p); + unlock_user(p, arg2, 0); + set_ptr = &set; + } else { + how = 0; + set_ptr = NULL; + } + ret = get_errno(sigprocmask(arg1, set_ptr, &oldset)); + if (!is_error(ret) && arg3) { + p = lock_user(arg3, sizeof(target_sigset_t), 0); + host_to_target_old_sigset(p, &oldset); + unlock_user(p, arg3, sizeof(target_sigset_t)); + } + } + break; + case TARGET_NR_rt_sigprocmask: + { + int how = arg1; + sigset_t set, oldset, *set_ptr; + + if (arg2) { + switch(how) { + case TARGET_SIG_BLOCK: + how = SIG_BLOCK; + break; + case TARGET_SIG_UNBLOCK: + how = SIG_UNBLOCK; + break; + case TARGET_SIG_SETMASK: + how = SIG_SETMASK; + break; + default: + ret = -EINVAL; + goto fail; + } + p = lock_user(arg2, sizeof(target_sigset_t), 1); + target_to_host_sigset(&set, p); + unlock_user(p, arg2, 0); + set_ptr = &set; + } else { + how = 0; + set_ptr = NULL; + } + ret = get_errno(sigprocmask(how, set_ptr, &oldset)); + if (!is_error(ret) && arg3) { + p = lock_user(arg3, sizeof(target_sigset_t), 0); + host_to_target_sigset(p, &oldset); + unlock_user(p, arg3, sizeof(target_sigset_t)); + } + } + break; + case TARGET_NR_sigpending: + { + sigset_t set; + ret = get_errno(sigpending(&set)); + if (!is_error(ret)) { + p = lock_user(arg1, sizeof(target_sigset_t), 0); + host_to_target_old_sigset(p, &set); + unlock_user(p, arg1, sizeof(target_sigset_t)); + } + } + break; + case TARGET_NR_rt_sigpending: + { + sigset_t set; + ret = get_errno(sigpending(&set)); + if (!is_error(ret)) { + p = lock_user(arg1, sizeof(target_sigset_t), 0); + host_to_target_sigset(p, &set); + unlock_user(p, arg1, sizeof(target_sigset_t)); + } + } + break; + case TARGET_NR_sigsuspend: + { + sigset_t set; + p = lock_user(arg1, sizeof(target_sigset_t), 1); + target_to_host_old_sigset(&set, p); + unlock_user(p, arg1, 0); + ret = get_errno(sigsuspend(&set)); + } + break; + case TARGET_NR_rt_sigsuspend: + { + sigset_t set; + p = lock_user(arg1, sizeof(target_sigset_t), 1); + target_to_host_sigset(&set, p); + unlock_user(p, arg1, 0); + ret = get_errno(sigsuspend(&set)); + } + break; + case TARGET_NR_rt_sigtimedwait: + { + sigset_t set; + struct timespec uts, *puts; + siginfo_t uinfo; + + p = lock_user(arg1, sizeof(target_sigset_t), 1); + target_to_host_sigset(&set, p); + unlock_user(p, arg1, 0); + if (arg3) { + puts = &uts; + target_to_host_timespec(puts, arg3); + } else { + puts = NULL; + } + ret = get_errno(sigtimedwait(&set, &uinfo, puts)); + if (!is_error(ret) && arg2) { + p = lock_user(arg2, sizeof(target_sigset_t), 0); + host_to_target_siginfo(p, &uinfo); + unlock_user(p, arg2, sizeof(target_sigset_t)); + } + } + break; + case TARGET_NR_rt_sigqueueinfo: + { + siginfo_t uinfo; + p = lock_user(arg3, sizeof(target_sigset_t), 1); + target_to_host_siginfo(&uinfo, p); + unlock_user(p, arg1, 0); + ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo)); + } + break; + case TARGET_NR_sigreturn: + /* NOTE: ret is eax, so not transcoding must be done */ + ret = do_sigreturn(cpu_env); + break; + case TARGET_NR_rt_sigreturn: + /* NOTE: ret is eax, so not transcoding must be done */ + ret = do_rt_sigreturn(cpu_env); + break; + case TARGET_NR_sethostname: + p = lock_user_string(arg1); + ret = get_errno(sethostname(p, arg2)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_setrlimit: + { + /* XXX: convert resource ? */ + int resource = arg1; + struct target_rlimit *target_rlim; + struct rlimit rlim; + lock_user_struct(target_rlim, arg2, 1); + rlim.rlim_cur = tswapl(target_rlim->rlim_cur); + rlim.rlim_max = tswapl(target_rlim->rlim_max); + unlock_user_struct(target_rlim, arg2, 0); + ret = get_errno(setrlimit(resource, &rlim)); + } + break; + case TARGET_NR_getrlimit: + { + /* XXX: convert resource ? */ + int resource = arg1; + struct target_rlimit *target_rlim; + struct rlimit rlim; + + ret = get_errno(getrlimit(resource, &rlim)); + if (!is_error(ret)) { + lock_user_struct(target_rlim, arg2, 0); + rlim.rlim_cur = tswapl(target_rlim->rlim_cur); + rlim.rlim_max = tswapl(target_rlim->rlim_max); + unlock_user_struct(target_rlim, arg2, 1); + } + } + break; + case TARGET_NR_getrusage: + { + struct rusage rusage; + ret = get_errno(getrusage(arg1, &rusage)); + if (!is_error(ret)) { + host_to_target_rusage(arg2, &rusage); + } + } + break; + case TARGET_NR_gettimeofday: + { + struct timeval tv; + ret = get_errno(gettimeofday(&tv, NULL)); + if (!is_error(ret)) { + host_to_target_timeval(arg1, &tv); + } + } + break; + case TARGET_NR_settimeofday: + { + struct timeval tv; + target_to_host_timeval(&tv, arg1); + ret = get_errno(settimeofday(&tv, NULL)); + } + break; +#ifdef TARGET_NR_select + case TARGET_NR_select: + { + struct target_sel_arg_struct *sel; + target_ulong inp, outp, exp, tvp; + long nsel; + + lock_user_struct(sel, arg1, 1); + nsel = tswapl(sel->n); + inp = tswapl(sel->inp); + outp = tswapl(sel->outp); + exp = tswapl(sel->exp); + tvp = tswapl(sel->tvp); + unlock_user_struct(sel, arg1, 0); + ret = do_select(nsel, inp, outp, exp, tvp); + } + break; +#endif + case TARGET_NR_symlink: + { + void *p2; + p = lock_user_string(arg1); + p2 = lock_user_string(arg2); + ret = get_errno(symlink(p, p2)); + unlock_user(p2, arg2, 0); + unlock_user(p, arg1, 0); + } + break; +#ifdef TARGET_NR_oldlstat + case TARGET_NR_oldlstat: + goto unimplemented; +#endif + case TARGET_NR_readlink: + { + void *p2; + p = lock_user_string(arg1); + p2 = lock_user(arg2, arg3, 0); + ret = get_errno(readlink(path(p), p2, arg3)); + unlock_user(p2, arg2, ret); + unlock_user(p, arg1, 0); + } + break; + case TARGET_NR_uselib: + goto unimplemented; + case TARGET_NR_swapon: + p = lock_user_string(arg1); + ret = get_errno(swapon(p, arg2)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_reboot: + goto unimplemented; + case TARGET_NR_readdir: + goto unimplemented; + case TARGET_NR_mmap: +#if defined(TARGET_I386) || defined(TARGET_ARM) + { + target_ulong *v; + target_ulong v1, v2, v3, v4, v5, v6; + v = lock_user(arg1, 6 * sizeof(target_ulong), 1); + v1 = tswapl(v[0]); + v2 = tswapl(v[1]); + v3 = tswapl(v[2]); + v4 = tswapl(v[3]); + v5 = tswapl(v[4]); + v6 = tswapl(v[5]); + unlock_user(v, arg1, 0); + ret = get_errno(target_mmap(v1, v2, v3, + target_to_host_bitmask(v4, mmap_flags_tbl), + v5, v6)); + } +#else + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6)); +#endif + break; +#ifdef TARGET_NR_mmap2 + case TARGET_NR_mmap2: +#if defined(TARGET_SPARC) +#define MMAP_SHIFT 12 +#else +#define MMAP_SHIFT TARGET_PAGE_BITS +#endif + ret = get_errno(target_mmap(arg1, arg2, arg3, + target_to_host_bitmask(arg4, mmap_flags_tbl), + arg5, + arg6 << MMAP_SHIFT)); + break; +#endif + case TARGET_NR_munmap: + ret = get_errno(target_munmap(arg1, arg2)); + break; + case TARGET_NR_mprotect: + ret = get_errno(target_mprotect(arg1, arg2, arg3)); + break; + case TARGET_NR_mremap: + ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5)); + break; + /* ??? msync/mlock/munlock are broken for softmmu. */ + case TARGET_NR_msync: + ret = get_errno(msync(g2h(arg1), arg2, arg3)); + break; + case TARGET_NR_mlock: + ret = get_errno(mlock(g2h(arg1), arg2)); + break; + case TARGET_NR_munlock: + ret = get_errno(munlock(g2h(arg1), arg2)); + break; + case TARGET_NR_mlockall: + ret = get_errno(mlockall(arg1)); + break; + case TARGET_NR_munlockall: + ret = get_errno(munlockall()); + break; + case TARGET_NR_truncate: + p = lock_user_string(arg1); + ret = get_errno(truncate(p, arg2)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_ftruncate: + ret = get_errno(ftruncate(arg1, arg2)); + break; + case TARGET_NR_fchmod: + ret = get_errno(fchmod(arg1, arg2)); + break; + case TARGET_NR_getpriority: + ret = get_errno(getpriority(arg1, arg2)); + break; + case TARGET_NR_setpriority: + ret = get_errno(setpriority(arg1, arg2, arg3)); + break; +#ifdef TARGET_NR_profil + case TARGET_NR_profil: + goto unimplemented; +#endif + case TARGET_NR_statfs: + p = lock_user_string(arg1); + ret = get_errno(statfs(path(p), &stfs)); + unlock_user(p, arg1, 0); + convert_statfs: + if (!is_error(ret)) { + struct target_statfs *target_stfs; + + lock_user_struct(target_stfs, arg2, 0); + /* ??? put_user is probably wrong. */ + put_user(stfs.f_type, &target_stfs->f_type); + put_user(stfs.f_bsize, &target_stfs->f_bsize); + put_user(stfs.f_blocks, &target_stfs->f_blocks); + put_user(stfs.f_bfree, &target_stfs->f_bfree); + put_user(stfs.f_bavail, &target_stfs->f_bavail); + put_user(stfs.f_files, &target_stfs->f_files); + put_user(stfs.f_ffree, &target_stfs->f_ffree); + put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid); + put_user(stfs.f_namelen, &target_stfs->f_namelen); + unlock_user_struct(target_stfs, arg2, 1); + } + break; + case TARGET_NR_fstatfs: + ret = get_errno(fstatfs(arg1, &stfs)); + goto convert_statfs; +#ifdef TARGET_NR_statfs64 + case TARGET_NR_statfs64: + p = lock_user_string(arg1); + ret = get_errno(statfs(path(p), &stfs)); + unlock_user(p, arg1, 0); + convert_statfs64: + if (!is_error(ret)) { + struct target_statfs64 *target_stfs; + + lock_user_struct(target_stfs, arg3, 0); + /* ??? put_user is probably wrong. */ + put_user(stfs.f_type, &target_stfs->f_type); + put_user(stfs.f_bsize, &target_stfs->f_bsize); + put_user(stfs.f_blocks, &target_stfs->f_blocks); + put_user(stfs.f_bfree, &target_stfs->f_bfree); + put_user(stfs.f_bavail, &target_stfs->f_bavail); + put_user(stfs.f_files, &target_stfs->f_files); + put_user(stfs.f_ffree, &target_stfs->f_ffree); + put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid); + put_user(stfs.f_namelen, &target_stfs->f_namelen); + unlock_user_struct(target_stfs, arg3, 0); + } + break; + case TARGET_NR_fstatfs64: + ret = get_errno(fstatfs(arg1, &stfs)); + goto convert_statfs64; +#endif +#ifdef TARGET_NR_ioperm + case TARGET_NR_ioperm: + goto unimplemented; +#endif + case TARGET_NR_socketcall: + ret = do_socketcall(arg1, arg2); + break; + +#ifdef TARGET_NR_accept + case TARGET_NR_accept: + ret = do_socketcallwrapper(SOCKOP_accept, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_bind + case TARGET_NR_bind: + ret = do_bind(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_connect + case TARGET_NR_connect: + ret = do_connect(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_getpeername + case TARGET_NR_getpeername: + ret = do_socketcallwrapper(SOCKOP_getpeername, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_getsockname + case TARGET_NR_getsockname: + ret = do_socketcallwrapper(SOCKOP_getsockname, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_getsockopt + case TARGET_NR_getsockopt: + ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5); + break; +#endif +#ifdef TARGET_NR_listen + case TARGET_NR_listen: + ret = do_socketcallwrapper(SOCKOP_listen, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_recv + case TARGET_NR_recv: + ret = do_socketcallwrapper(SOCKOP_recv, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_recvfrom + case TARGET_NR_recvfrom: + ret = do_socketcallwrapper(SOCKOP_recvfrom, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_recvmsg + case TARGET_NR_recvmsg: + ret = do_sendrecvmsg(arg1, arg2, arg3, 0); + break; +#endif +#ifdef TARGET_NR_send + case TARGET_NR_send: + ret = do_socketcallwrapper(SOCKOP_send, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_sendmsg + case TARGET_NR_sendmsg: + ret = do_sendrecvmsg(arg1, arg2, arg3, 1); + break; +#endif +#ifdef TARGET_NR_sendto + case TARGET_NR_sendto: + ret = do_socketcallwrapper(SOCKOP_sendto, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_shutdown + case TARGET_NR_shutdown: + ret = do_socketcallwrapper(SOCKOP_shutdown, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_socket + case TARGET_NR_socket: + ret = do_socket(arg1, arg2, arg3); + break; +#endif +#ifdef TARGET_NR_socketpair + case TARGET_NR_socketpair: + ret = do_socketcallwrapper(SOCKOP_socketpair, arg1, arg2, arg3, arg4, arg5, arg6); + break; +#endif +#ifdef TARGET_NR_setsockopt + case TARGET_NR_setsockopt: + ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5); + break; +#endif + + case TARGET_NR_syslog: + goto unimplemented; + case TARGET_NR_setitimer: + { + struct itimerval value, ovalue, *pvalue; + + if (arg2) { + pvalue = &value; + target_to_host_timeval(&pvalue->it_interval, + arg2); + target_to_host_timeval(&pvalue->it_value, + arg2 + sizeof(struct target_timeval)); + } else { + pvalue = NULL; + } + ret = get_errno(setitimer(arg1, pvalue, &ovalue)); + if (!is_error(ret) && arg3) { + host_to_target_timeval(arg3, + &ovalue.it_interval); + host_to_target_timeval(arg3 + sizeof(struct target_timeval), + &ovalue.it_value); + } + } + break; + case TARGET_NR_getitimer: + { + struct itimerval value; + + ret = get_errno(getitimer(arg1, &value)); + if (!is_error(ret) && arg2) { + host_to_target_timeval(arg2, + &value.it_interval); + host_to_target_timeval(arg2 + sizeof(struct target_timeval), + &value.it_value); + } + } + break; + case TARGET_NR_stat: + p = lock_user_string(arg1); + ret = get_errno(stat(path(p), &st)); + unlock_user(p, arg1, 0); + goto do_stat; + case TARGET_NR_lstat: + p = lock_user_string(arg1); + ret = get_errno(lstat(path(p), &st)); + unlock_user(p, arg1, 0); + goto do_stat; + case TARGET_NR_fstat: + { + ret = get_errno(fstat(arg1, &st)); + do_stat: + if (!is_error(ret)) { + struct target_stat *target_st; + + lock_user_struct(target_st, arg2, 0); + target_st->st_dev = tswap16(st.st_dev); + target_st->st_ino = tswapl(st.st_ino); +#if defined(TARGET_PPC) + target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */ + target_st->st_uid = tswap32(st.st_uid); + target_st->st_gid = tswap32(st.st_gid); +#else + target_st->st_mode = tswap16(st.st_mode); + target_st->st_uid = tswap16(st.st_uid); + target_st->st_gid = tswap16(st.st_gid); +#endif + target_st->st_nlink = tswap16(st.st_nlink); + target_st->st_rdev = tswap16(st.st_rdev); + target_st->st_size = tswapl(st.st_size); + target_st->st_blksize = tswapl(st.st_blksize); + target_st->st_blocks = tswapl(st.st_blocks); + target_st->target_st_atime = tswapl(st.st_atime); + target_st->target_st_mtime = tswapl(st.st_mtime); + target_st->target_st_ctime = tswapl(st.st_ctime); + unlock_user_struct(target_st, arg2, 1); + } + } + break; +#ifdef TARGET_NR_olduname + case TARGET_NR_olduname: + goto unimplemented; +#endif +#ifdef TARGET_NR_iopl + case TARGET_NR_iopl: + goto unimplemented; +#endif + case TARGET_NR_vhangup: + ret = get_errno(vhangup()); + break; +#ifdef TARGET_NR_idle + case TARGET_NR_idle: + goto unimplemented; +#endif +#ifdef TARGET_NR_syscall + case TARGET_NR_syscall: + ret = do_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); + break; +#endif + case TARGET_NR_wait4: + { + int status; + target_long status_ptr = arg2; + struct rusage rusage, *rusage_ptr; + target_ulong target_rusage = arg4; + if (target_rusage) + rusage_ptr = &rusage; + else + rusage_ptr = NULL; + ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr)); + if (!is_error(ret)) { + if (status_ptr) + tputl(status_ptr, status); + if (target_rusage) { + host_to_target_rusage(target_rusage, &rusage); + } + } + } + break; + case TARGET_NR_swapoff: + p = lock_user_string(arg1); + ret = get_errno(swapoff(p)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_sysinfo: + { + struct target_sysinfo *target_value; + struct sysinfo value; + ret = get_errno(sysinfo(&value)); + if (!is_error(ret) && arg1) + { + /* ??? __put_user is probably wrong. */ + lock_user_struct(target_value, arg1, 0); + __put_user(value.uptime, &target_value->uptime); + __put_user(value.loads[0], &target_value->loads[0]); + __put_user(value.loads[1], &target_value->loads[1]); + __put_user(value.loads[2], &target_value->loads[2]); + __put_user(value.totalram, &target_value->totalram); + __put_user(value.freeram, &target_value->freeram); + __put_user(value.sharedram, &target_value->sharedram); + __put_user(value.bufferram, &target_value->bufferram); + __put_user(value.totalswap, &target_value->totalswap); + __put_user(value.freeswap, &target_value->freeswap); + __put_user(value.procs, &target_value->procs); + __put_user(value.totalhigh, &target_value->totalhigh); + __put_user(value.freehigh, &target_value->freehigh); + __put_user(value.mem_unit, &target_value->mem_unit); + unlock_user_struct(target_value, arg1, 1); + } + } + break; + case TARGET_NR_ipc: + ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6); + break; + case TARGET_NR_fsync: + ret = get_errno(fsync(arg1)); + break; + case TARGET_NR_clone: + ret = get_errno(do_fork(cpu_env, arg1, arg2)); + break; +#ifdef __NR_exit_group + /* new thread calls */ + case TARGET_NR_exit_group: + gdb_exit(cpu_env, arg1); + ret = get_errno(exit_group(arg1)); + break; +#endif + case TARGET_NR_setdomainname: + p = lock_user_string(arg1); + ret = get_errno(setdomainname(p, arg2)); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_uname: + /* no need to transcode because we use the linux syscall */ + { + struct new_utsname * buf; + + lock_user_struct(buf, arg1, 0); + ret = get_errno(sys_uname(buf)); + if (!is_error(ret)) { + /* Overrite the native machine name with whatever is being + emulated. */ + strcpy (buf->machine, UNAME_MACHINE); + /* Allow the user to override the reported release. */ + if (qemu_uname_release && *qemu_uname_release) + strcpy (buf->release, qemu_uname_release); + } + unlock_user_struct(buf, arg1, 1); + } + break; +#ifdef TARGET_I386 + case TARGET_NR_modify_ldt: + ret = get_errno(do_modify_ldt(cpu_env, arg1, arg2, arg3)); + break; + case TARGET_NR_vm86old: + goto unimplemented; + case TARGET_NR_vm86: + ret = do_vm86(cpu_env, arg1, arg2); + break; +#endif + case TARGET_NR_adjtimex: + goto unimplemented; + case TARGET_NR_create_module: + case TARGET_NR_init_module: + case TARGET_NR_delete_module: + case TARGET_NR_get_kernel_syms: + goto unimplemented; + case TARGET_NR_quotactl: + goto unimplemented; + case TARGET_NR_getpgid: + ret = get_errno(getpgid(arg1)); + break; + case TARGET_NR_fchdir: + ret = get_errno(fchdir(arg1)); + break; + case TARGET_NR_bdflush: + goto unimplemented; + case TARGET_NR_sysfs: + goto unimplemented; + case TARGET_NR_personality: + ret = get_errno(personality(arg1)); + break; + case TARGET_NR_afs_syscall: + goto unimplemented; + case TARGET_NR__llseek: + { +#if defined (__x86_64__) + ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5)); + tput64(arg4, ret); +#else + int64_t res; + ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5)); + tput64(arg4, res); +#endif + } + break; + case TARGET_NR_getdents: +#if TARGET_LONG_SIZE != 4 + goto unimplemented; +#warning not supported +#elif TARGET_LONG_SIZE == 4 && HOST_LONG_SIZE == 8 + { + struct target_dirent *target_dirp; + struct dirent *dirp; + long count = arg3; + + dirp = malloc(count); + if (!dirp) + return -ENOMEM; + + ret = get_errno(sys_getdents(arg1, dirp, count)); + if (!is_error(ret)) { + struct dirent *de; + struct target_dirent *tde; + int len = ret; + int reclen, treclen; + int count1, tnamelen; + + count1 = 0; + de = dirp; + target_dirp = lock_user(arg2, count, 0); + tde = target_dirp; + while (len > 0) { + reclen = de->d_reclen; + treclen = reclen - (2 * (sizeof(long) - sizeof(target_long))); + tde->d_reclen = tswap16(treclen); + tde->d_ino = tswapl(de->d_ino); + tde->d_off = tswapl(de->d_off); + tnamelen = treclen - (2 * sizeof(target_long) + 2); + if (tnamelen > 256) + tnamelen = 256; + /* XXX: may not be correct */ + strncpy(tde->d_name, de->d_name, tnamelen); + de = (struct dirent *)((char *)de + reclen); + len -= reclen; + tde = (struct dirent *)((char *)tde + treclen); + count1 += treclen; + } + ret = count1; + } + unlock_user(target_dirp, arg2, ret); + free(dirp); + } +#else + { + struct dirent *dirp; + long count = arg3; + + dirp = lock_user(arg2, count, 0); + ret = get_errno(sys_getdents(arg1, dirp, count)); + if (!is_error(ret)) { + struct dirent *de; + int len = ret; + int reclen; + de = dirp; + while (len > 0) { + reclen = de->d_reclen; + if (reclen > len) + break; + de->d_reclen = tswap16(reclen); + tswapls(&de->d_ino); + tswapls(&de->d_off); + de = (struct dirent *)((char *)de + reclen); + len -= reclen; + } + } + unlock_user(dirp, arg2, ret); + } +#endif + break; +#ifdef TARGET_NR_getdents64 + case TARGET_NR_getdents64: + { + struct dirent64 *dirp; + long count = arg3; + dirp = lock_user(arg2, count, 0); + ret = get_errno(sys_getdents64(arg1, dirp, count)); + if (!is_error(ret)) { + struct dirent64 *de; + int len = ret; + int reclen; + de = dirp; + while (len > 0) { + reclen = de->d_reclen; + if (reclen > len) + break; + de->d_reclen = tswap16(reclen); + tswap64s(&de->d_ino); + tswap64s(&de->d_off); + de = (struct dirent64 *)((char *)de + reclen); + len -= reclen; + } + } + unlock_user(dirp, arg2, ret); + } + break; +#endif /* TARGET_NR_getdents64 */ + case TARGET_NR__newselect: + ret = do_select(arg1, arg2, arg3, arg4, arg5); + break; + case TARGET_NR_poll: + { + struct target_pollfd *target_pfd; + unsigned int nfds = arg2; + int timeout = arg3; + struct pollfd *pfd; + unsigned int i; + + target_pfd = lock_user(arg1, sizeof(struct target_pollfd) * nfds, 1); + pfd = alloca(sizeof(struct pollfd) * nfds); + for(i = 0; i < nfds; i++) { + pfd[i].fd = tswap32(target_pfd[i].fd); + pfd[i].events = tswap16(target_pfd[i].events); + } + ret = get_errno(poll(pfd, nfds, timeout)); + if (!is_error(ret)) { + for(i = 0; i < nfds; i++) { + target_pfd[i].revents = tswap16(pfd[i].revents); + } + ret += nfds * (sizeof(struct target_pollfd) + - sizeof(struct pollfd)); + } + unlock_user(target_pfd, arg1, ret); + } + break; + case TARGET_NR_flock: + /* NOTE: the flock constant seems to be the same for every + Linux platform */ + ret = get_errno(flock(arg1, arg2)); + break; + case TARGET_NR_readv: + { + int count = arg3; + struct iovec *vec; + + vec = alloca(count * sizeof(struct iovec)); + lock_iovec(vec, arg2, count, 0); + ret = get_errno(readv(arg1, vec, count)); + unlock_iovec(vec, arg2, count, 1); + } + break; + case TARGET_NR_writev: + { + int count = arg3; + struct iovec *vec; + + vec = alloca(count * sizeof(struct iovec)); + lock_iovec(vec, arg2, count, 1); + ret = get_errno(writev(arg1, vec, count)); + unlock_iovec(vec, arg2, count, 0); + } + break; + case TARGET_NR_getsid: + ret = get_errno(getsid(arg1)); + break; + case TARGET_NR_fdatasync: + ret = get_errno(fdatasync(arg1)); + break; + case TARGET_NR__sysctl: + /* We don't implement this, but ENODIR is always a safe + return value. */ + return -ENOTDIR; + case TARGET_NR_sched_setparam: + { + struct sched_param *target_schp; + struct sched_param schp; + + lock_user_struct(target_schp, arg2, 1); + schp.sched_priority = tswap32(target_schp->sched_priority); + unlock_user_struct(target_schp, arg2, 0); + ret = get_errno(sched_setparam(arg1, &schp)); + } + break; + case TARGET_NR_sched_getparam: + { + struct sched_param *target_schp; + struct sched_param schp; + ret = get_errno(sched_getparam(arg1, &schp)); + if (!is_error(ret)) { + lock_user_struct(target_schp, arg2, 0); + target_schp->sched_priority = tswap32(schp.sched_priority); + unlock_user_struct(target_schp, arg2, 1); + } + } + break; + case TARGET_NR_sched_setscheduler: + { + struct sched_param *target_schp; + struct sched_param schp; + lock_user_struct(target_schp, arg3, 1); + schp.sched_priority = tswap32(target_schp->sched_priority); + unlock_user_struct(target_schp, arg3, 0); + ret = get_errno(sched_setscheduler(arg1, arg2, &schp)); + } + break; + case TARGET_NR_sched_getscheduler: + ret = get_errno(sched_getscheduler(arg1)); + break; + case TARGET_NR_sched_yield: + ret = get_errno(sched_yield()); + break; + case TARGET_NR_sched_get_priority_max: + ret = get_errno(sched_get_priority_max(arg1)); + break; + case TARGET_NR_sched_get_priority_min: + ret = get_errno(sched_get_priority_min(arg1)); + break; + case TARGET_NR_sched_rr_get_interval: + { + struct timespec ts; + ret = get_errno(sched_rr_get_interval(arg1, &ts)); + if (!is_error(ret)) { + host_to_target_timespec(arg2, &ts); + } + } + break; + case TARGET_NR_nanosleep: + { + struct timespec req, rem; + target_to_host_timespec(&req, arg1); + ret = get_errno(nanosleep(&req, &rem)); + if (is_error(ret) && arg2) { + host_to_target_timespec(arg2, &rem); + } + } + break; + case TARGET_NR_query_module: + goto unimplemented; + case TARGET_NR_nfsservctl: + goto unimplemented; + case TARGET_NR_prctl: + goto unimplemented; +#ifdef TARGET_NR_pread + case TARGET_NR_pread: + page_unprotect_range(arg2, arg3); + p = lock_user(arg2, arg3, 0); + ret = get_errno(pread(arg1, p, arg3, arg4)); + unlock_user(p, arg2, ret); + break; + case TARGET_NR_pwrite: + p = lock_user(arg2, arg3, 1); + ret = get_errno(pwrite(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); + break; +#endif + case TARGET_NR_getcwd: + p = lock_user(arg1, arg2, 0); + ret = get_errno(sys_getcwd1(p, arg2)); + unlock_user(p, arg1, ret); + break; + case TARGET_NR_capget: + goto unimplemented; + case TARGET_NR_capset: + goto unimplemented; + case TARGET_NR_sigaltstack: + goto unimplemented; + case TARGET_NR_sendfile: + goto unimplemented; +#ifdef TARGET_NR_getpmsg + case TARGET_NR_getpmsg: + goto unimplemented; +#endif +#ifdef TARGET_NR_putpmsg + case TARGET_NR_putpmsg: + goto unimplemented; +#endif +#ifdef TARGET_NR_vfork + case TARGET_NR_vfork: + ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0)); + break; +#endif +#ifdef TARGET_NR_ugetrlimit + case TARGET_NR_ugetrlimit: + { + struct rlimit rlim; + ret = get_errno(getrlimit(arg1, &rlim)); + if (!is_error(ret)) { + struct target_rlimit *target_rlim; + lock_user_struct(target_rlim, arg2, 0); + target_rlim->rlim_cur = tswapl(rlim.rlim_cur); + target_rlim->rlim_max = tswapl(rlim.rlim_max); + unlock_user_struct(target_rlim, arg2, 1); + } + break; + } +#endif +#ifdef TARGET_NR_truncate64 + case TARGET_NR_truncate64: + p = lock_user_string(arg1); + ret = target_truncate64(cpu_env, p, arg2, arg3, arg4); + unlock_user(p, arg1, 0); + break; +#endif +#ifdef TARGET_NR_ftruncate64 + case TARGET_NR_ftruncate64: + ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4); + break; +#endif +#ifdef TARGET_NR_stat64 + case TARGET_NR_stat64: + p = lock_user_string(arg1); + ret = get_errno(stat(path(p), &st)); + unlock_user(p, arg1, 0); + goto do_stat64; +#endif +#ifdef TARGET_NR_lstat64 + case TARGET_NR_lstat64: + p = lock_user_string(arg1); + ret = get_errno(lstat(path(p), &st)); + unlock_user(p, arg1, 0); + goto do_stat64; +#endif +#ifdef TARGET_NR_fstat64 + case TARGET_NR_fstat64: + { + ret = get_errno(fstat(arg1, &st)); + do_stat64: + if (!is_error(ret)) { +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) { + struct target_eabi_stat64 *target_st; + lock_user_struct(target_st, arg2, 1); + memset(target_st, 0, sizeof(struct target_eabi_stat64)); + /* put_user is probably wrong. */ + put_user(st.st_dev, &target_st->st_dev); + put_user(st.st_ino, &target_st->st_ino); +#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO + put_user(st.st_ino, &target_st->__st_ino); +#endif + put_user(st.st_mode, &target_st->st_mode); + put_user(st.st_nlink, &target_st->st_nlink); + put_user(st.st_uid, &target_st->st_uid); + put_user(st.st_gid, &target_st->st_gid); + put_user(st.st_rdev, &target_st->st_rdev); + /* XXX: better use of kernel struct */ + put_user(st.st_size, &target_st->st_size); + put_user(st.st_blksize, &target_st->st_blksize); + put_user(st.st_blocks, &target_st->st_blocks); + put_user(st.st_atime, &target_st->target_st_atime); + put_user(st.st_mtime, &target_st->target_st_mtime); + put_user(st.st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, arg2, 0); + } else +#endif + { + struct target_stat64 *target_st; + lock_user_struct(target_st, arg2, 1); + memset(target_st, 0, sizeof(struct target_stat64)); + /* ??? put_user is probably wrong. */ + put_user(st.st_dev, &target_st->st_dev); + put_user(st.st_ino, &target_st->st_ino); +#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO + put_user(st.st_ino, &target_st->__st_ino); +#endif + put_user(st.st_mode, &target_st->st_mode); + put_user(st.st_nlink, &target_st->st_nlink); + put_user(st.st_uid, &target_st->st_uid); + put_user(st.st_gid, &target_st->st_gid); + put_user(st.st_rdev, &target_st->st_rdev); + /* XXX: better use of kernel struct */ + put_user(st.st_size, &target_st->st_size); + put_user(st.st_blksize, &target_st->st_blksize); + put_user(st.st_blocks, &target_st->st_blocks); + put_user(st.st_atime, &target_st->target_st_atime); + put_user(st.st_mtime, &target_st->target_st_mtime); + put_user(st.st_ctime, &target_st->target_st_ctime); + unlock_user_struct(target_st, arg2, 0); + } + } + } + break; +#endif +#ifdef USE_UID16 + case TARGET_NR_lchown: + p = lock_user_string(arg1); + ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3))); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_getuid: + ret = get_errno(high2lowuid(getuid())); + break; + case TARGET_NR_getgid: + ret = get_errno(high2lowgid(getgid())); + break; + case TARGET_NR_geteuid: + ret = get_errno(high2lowuid(geteuid())); + break; + case TARGET_NR_getegid: + ret = get_errno(high2lowgid(getegid())); + break; + case TARGET_NR_setreuid: + ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2))); + break; + case TARGET_NR_setregid: + ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2))); + break; + case TARGET_NR_getgroups: + { + int gidsetsize = arg1; + uint16_t *target_grouplist; + gid_t *grouplist; + int i; + + grouplist = alloca(gidsetsize * sizeof(gid_t)); + ret = get_errno(getgroups(gidsetsize, grouplist)); + if (!is_error(ret)) { + target_grouplist = lock_user(arg2, gidsetsize * 2, 0); + for(i = 0;i < gidsetsize; i++) + target_grouplist[i] = tswap16(grouplist[i]); + unlock_user(target_grouplist, arg2, gidsetsize * 2); + } + } + break; + case TARGET_NR_setgroups: + { + int gidsetsize = arg1; + uint16_t *target_grouplist; + gid_t *grouplist; + int i; + + grouplist = alloca(gidsetsize * sizeof(gid_t)); + target_grouplist = lock_user(arg2, gidsetsize * 2, 1); + for(i = 0;i < gidsetsize; i++) + grouplist[i] = tswap16(target_grouplist[i]); + unlock_user(target_grouplist, arg2, 0); + ret = get_errno(setgroups(gidsetsize, grouplist)); + } + break; + case TARGET_NR_fchown: + ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3))); + break; +#ifdef TARGET_NR_setresuid + case TARGET_NR_setresuid: + ret = get_errno(setresuid(low2highuid(arg1), + low2highuid(arg2), + low2highuid(arg3))); + break; +#endif +#ifdef TARGET_NR_getresuid + case TARGET_NR_getresuid: + { + uid_t ruid, euid, suid; + ret = get_errno(getresuid(&ruid, &euid, &suid)); + if (!is_error(ret)) { + tput16(arg1, tswap16(high2lowuid(ruid))); + tput16(arg2, tswap16(high2lowuid(euid))); + tput16(arg3, tswap16(high2lowuid(suid))); + } + } + break; +#endif +#ifdef TARGET_NR_getresgid + case TARGET_NR_setresgid: + ret = get_errno(setresgid(low2highgid(arg1), + low2highgid(arg2), + low2highgid(arg3))); + break; +#endif +#ifdef TARGET_NR_getresgid + case TARGET_NR_getresgid: + { + gid_t rgid, egid, sgid; + ret = get_errno(getresgid(&rgid, &egid, &sgid)); + if (!is_error(ret)) { + tput16(arg1, tswap16(high2lowgid(rgid))); + tput16(arg2, tswap16(high2lowgid(egid))); + tput16(arg3, tswap16(high2lowgid(sgid))); + } + } + break; +#endif + case TARGET_NR_chown: + p = lock_user_string(arg1); + ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3))); + unlock_user(p, arg1, 0); + break; + case TARGET_NR_setuid: + ret = get_errno(setuid(low2highuid(arg1))); + break; + case TARGET_NR_setgid: + ret = get_errno(setgid(low2highgid(arg1))); + break; + case TARGET_NR_setfsuid: + ret = get_errno(setfsuid(arg1)); + break; + case TARGET_NR_setfsgid: + ret = get_errno(setfsgid(arg1)); + break; +#endif /* USE_UID16 */ + +#ifdef TARGET_NR_lchown32 + case TARGET_NR_lchown32: + p = lock_user_string(arg1); + ret = get_errno(lchown(p, arg2, arg3)); + unlock_user(p, arg1, 0); + break; +#endif +#ifdef TARGET_NR_getuid32 + case TARGET_NR_getuid32: + ret = get_errno(getuid()); + break; +#endif +#ifdef TARGET_NR_getgid32 + case TARGET_NR_getgid32: + ret = get_errno(getgid()); + break; +#endif +#ifdef TARGET_NR_geteuid32 + case TARGET_NR_geteuid32: + ret = get_errno(geteuid()); + break; +#endif +#ifdef TARGET_NR_getegid32 + case TARGET_NR_getegid32: + ret = get_errno(getegid()); + break; +#endif +#ifdef TARGET_NR_setreuid32 + case TARGET_NR_setreuid32: + ret = get_errno(setreuid(arg1, arg2)); + break; +#endif +#ifdef TARGET_NR_setregid32 + case TARGET_NR_setregid32: + ret = get_errno(setregid(arg1, arg2)); + break; +#endif +#ifdef TARGET_NR_getgroups32 + case TARGET_NR_getgroups32: + { + int gidsetsize = arg1; + uint32_t *target_grouplist; + gid_t *grouplist; + int i; + + grouplist = alloca(gidsetsize * sizeof(gid_t)); + ret = get_errno(getgroups(gidsetsize, grouplist)); + if (!is_error(ret)) { + target_grouplist = lock_user(arg2, gidsetsize * 4, 0); + for(i = 0;i < gidsetsize; i++) + target_grouplist[i] = tswap32(grouplist[i]); + unlock_user(target_grouplist, arg2, gidsetsize * 4); + } + } + break; +#endif +#ifdef TARGET_NR_setgroups32 + case TARGET_NR_setgroups32: + { + int gidsetsize = arg1; + uint32_t *target_grouplist; + gid_t *grouplist; + int i; + + grouplist = alloca(gidsetsize * sizeof(gid_t)); + target_grouplist = lock_user(arg2, gidsetsize * 4, 1); + for(i = 0;i < gidsetsize; i++) + grouplist[i] = tswap32(target_grouplist[i]); + unlock_user(target_grouplist, arg2, 0); + ret = get_errno(setgroups(gidsetsize, grouplist)); + } + break; +#endif +#ifdef TARGET_NR_fchown32 + case TARGET_NR_fchown32: + ret = get_errno(fchown(arg1, arg2, arg3)); + break; +#endif +#ifdef TARGET_NR_setresuid32 + case TARGET_NR_setresuid32: + ret = get_errno(setresuid(arg1, arg2, arg3)); + break; +#endif +#ifdef TARGET_NR_getresuid32 + case TARGET_NR_getresuid32: + { + uid_t ruid, euid, suid; + ret = get_errno(getresuid(&ruid, &euid, &suid)); + if (!is_error(ret)) { + tput32(arg1, tswap32(ruid)); + tput32(arg2, tswap32(euid)); + tput32(arg3, tswap32(suid)); + } + } + break; +#endif +#ifdef TARGET_NR_setresgid32 + case TARGET_NR_setresgid32: + ret = get_errno(setresgid(arg1, arg2, arg3)); + break; +#endif +#ifdef TARGET_NR_getresgid32 + case TARGET_NR_getresgid32: + { + gid_t rgid, egid, sgid; + ret = get_errno(getresgid(&rgid, &egid, &sgid)); + if (!is_error(ret)) { + tput32(arg1, tswap32(rgid)); + tput32(arg2, tswap32(egid)); + tput32(arg3, tswap32(sgid)); + } + } + break; +#endif +#ifdef TARGET_NR_chown32 + case TARGET_NR_chown32: + p = lock_user_string(arg1); + ret = get_errno(chown(p, arg2, arg3)); + unlock_user(p, arg1, 0); + break; +#endif +#ifdef TARGET_NR_setuid32 + case TARGET_NR_setuid32: + ret = get_errno(setuid(arg1)); + break; +#endif +#ifdef TARGET_NR_setgid32 + case TARGET_NR_setgid32: + ret = get_errno(setgid(arg1)); + break; +#endif +#ifdef TARGET_NR_setfsuid32 + case TARGET_NR_setfsuid32: + ret = get_errno(setfsuid(arg1)); + break; +#endif +#ifdef TARGET_NR_setfsgid32 + case TARGET_NR_setfsgid32: + ret = get_errno(setfsgid(arg1)); + break; +#endif + + case TARGET_NR_pivot_root: + goto unimplemented; +#ifdef TARGET_NR_mincore + case TARGET_NR_mincore: + goto unimplemented; +#endif +#ifdef TARGET_NR_madvise + case TARGET_NR_madvise: + /* A straight passthrough may not be safe because qemu sometimes + turns private flie-backed mappings into anonymous mappings. + This will break MADV_DONTNEED. + This is a hint, so ignoring and returning success is ok. */ + ret = get_errno(0); + break; +#endif +#if TARGET_LONG_BITS == 32 + case TARGET_NR_fcntl64: + { + struct flock64 fl; + struct target_flock64 *target_fl; +#ifdef TARGET_ARM + struct target_eabi_flock64 *target_efl; +#endif + + switch(arg2) { + case F_GETLK64: + ret = get_errno(fcntl(arg1, arg2, &fl)); + if (ret == 0) { +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) { + lock_user_struct(target_efl, arg3, 0); + target_efl->l_type = tswap16(fl.l_type); + target_efl->l_whence = tswap16(fl.l_whence); + target_efl->l_start = tswap64(fl.l_start); + target_efl->l_len = tswap64(fl.l_len); + target_efl->l_pid = tswapl(fl.l_pid); + unlock_user_struct(target_efl, arg3, 1); + } else +#endif + { + lock_user_struct(target_fl, arg3, 0); + target_fl->l_type = tswap16(fl.l_type); + target_fl->l_whence = tswap16(fl.l_whence); + target_fl->l_start = tswap64(fl.l_start); + target_fl->l_len = tswap64(fl.l_len); + target_fl->l_pid = tswapl(fl.l_pid); + unlock_user_struct(target_fl, arg3, 1); + } + } + break; + + case F_SETLK64: + case F_SETLKW64: +#ifdef TARGET_ARM + if (((CPUARMState *)cpu_env)->eabi) { + lock_user_struct(target_efl, arg3, 1); + fl.l_type = tswap16(target_efl->l_type); + fl.l_whence = tswap16(target_efl->l_whence); + fl.l_start = tswap64(target_efl->l_start); + fl.l_len = tswap64(target_efl->l_len); + fl.l_pid = tswapl(target_efl->l_pid); + unlock_user_struct(target_efl, arg3, 0); + } else +#endif + { + lock_user_struct(target_fl, arg3, 1); + fl.l_type = tswap16(target_fl->l_type); + fl.l_whence = tswap16(target_fl->l_whence); + fl.l_start = tswap64(target_fl->l_start); + fl.l_len = tswap64(target_fl->l_len); + fl.l_pid = tswapl(target_fl->l_pid); + unlock_user_struct(target_fl, arg3, 0); + } + ret = get_errno(fcntl(arg1, arg2, &fl)); + break; + default: + ret = get_errno(do_fcntl(arg1, arg2, arg3)); + break; + } + break; + } +#endif +#ifdef TARGET_NR_security + case TARGET_NR_security: + goto unimplemented; +#endif +#ifdef TARGET_NR_getpagesize + case TARGET_NR_getpagesize: + ret = TARGET_PAGE_SIZE; + break; +#endif + case TARGET_NR_gettid: + ret = get_errno(gettid()); + break; + case TARGET_NR_readahead: + goto unimplemented; +#ifdef TARGET_NR_setxattr + case TARGET_NR_setxattr: + case TARGET_NR_lsetxattr: + case TARGET_NR_fsetxattr: + case TARGET_NR_getxattr: + case TARGET_NR_lgetxattr: + case TARGET_NR_fgetxattr: + case TARGET_NR_listxattr: + case TARGET_NR_llistxattr: + case TARGET_NR_flistxattr: + case TARGET_NR_removexattr: + case TARGET_NR_lremovexattr: + case TARGET_NR_fremovexattr: + goto unimplemented_nowarn; +#endif +#ifdef TARGET_NR_set_thread_area + case TARGET_NR_set_thread_area: + case TARGET_NR_get_thread_area: + goto unimplemented_nowarn; +#endif +#ifdef TARGET_NR_getdomainname + case TARGET_NR_getdomainname: + goto unimplemented_nowarn; +#endif + default: + unimplemented: + gemu_log("qemu: Unsupported syscall: %d\n", num); +#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_set_thread_area) || defined(TARGET_NR_getdomainname) + unimplemented_nowarn: +#endif + ret = -ENOSYS; + break; + } + fail: +#ifdef DEBUG + gemu_log(" = %ld\n", ret); +#endif + return ret; +} + diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h new file mode 100644 index 0000000..73a5c42 --- /dev/null +++ b/linux-user/syscall_defs.h @@ -0,0 +1,1516 @@ +/* common syscall defines for all architectures */ + +/* Note: although the syscall numbers change between architectures, + most of them stay the same, so we handle it by puting ifdefs if + necessary */ + +#include "syscall_nr.h" + +#define SOCKOP_socket 1 +#define SOCKOP_bind 2 +#define SOCKOP_connect 3 +#define SOCKOP_listen 4 +#define SOCKOP_accept 5 +#define SOCKOP_getsockname 6 +#define SOCKOP_getpeername 7 +#define SOCKOP_socketpair 8 +#define SOCKOP_send 9 +#define SOCKOP_recv 10 +#define SOCKOP_sendto 11 +#define SOCKOP_recvfrom 12 +#define SOCKOP_shutdown 13 +#define SOCKOP_setsockopt 14 +#define SOCKOP_getsockopt 15 +#define SOCKOP_sendmsg 16 +#define SOCKOP_recvmsg 17 + +#define IPCOP_semop 1 +#define IPCOP_semget 2 +#define IPCOP_semctl 3 +#define IPCOP_semtimedop 4 +#define IPCOP_msgsnd 11 +#define IPCOP_msgrcv 12 +#define IPCOP_msgget 13 +#define IPCOP_msgctl 14 +#define IPCOP_shmat 21 +#define IPCOP_shmdt 22 +#define IPCOP_shmget 23 +#define IPCOP_shmctl 24 + +/* + * The following is for compatibility across the various Linux + * platforms. The i386 ioctl numbering scheme doesn't really enforce + * a type field. De facto, however, the top 8 bits of the lower 16 + * bits are indeed used as a type field, so we might just as well make + * this explicit here. Please be sure to use the decoding macros + * below from now on. + */ +#define TARGET_IOC_NRBITS 8 +#define TARGET_IOC_TYPEBITS 8 + +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) + +#define TARGET_IOC_SIZEBITS 14 +#define TARGET_IOC_DIRBITS 2 + +#define TARGET_IOC_NONE 0U +#define TARGET_IOC_WRITE 1U +#define TARGET_IOC_READ 2U + +#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || \ + defined(TARGET_SPARC) || defined(TARGET_MIPS) + +#define TARGET_IOC_SIZEBITS 13 +#define TARGET_IOC_DIRBITS 3 + +#define TARGET_IOC_NONE 1U +#define TARGET_IOC_READ 2U +#define TARGET_IOC_WRITE 4U + +#else +#error unsupported CPU +#endif + +#define TARGET_IOC_NRMASK ((1 << TARGET_IOC_NRBITS)-1) +#define TARGET_IOC_TYPEMASK ((1 << TARGET_IOC_TYPEBITS)-1) +#define TARGET_IOC_SIZEMASK ((1 << TARGET_IOC_SIZEBITS)-1) +#define TARGET_IOC_DIRMASK ((1 << TARGET_IOC_DIRBITS)-1) + +#define TARGET_IOC_NRSHIFT 0 +#define TARGET_IOC_TYPESHIFT (TARGET_IOC_NRSHIFT+TARGET_IOC_NRBITS) +#define TARGET_IOC_SIZESHIFT (TARGET_IOC_TYPESHIFT+TARGET_IOC_TYPEBITS) +#define TARGET_IOC_DIRSHIFT (TARGET_IOC_SIZESHIFT+TARGET_IOC_SIZEBITS) + +#define TARGET_IOC(dir,type,nr,size) \ + (((dir) << TARGET_IOC_DIRSHIFT) | \ + ((type) << TARGET_IOC_TYPESHIFT) | \ + ((nr) << TARGET_IOC_NRSHIFT) | \ + ((size) << TARGET_IOC_SIZESHIFT)) + +/* used to create numbers */ +#define TARGET_IO(type,nr) TARGET_IOC(TARGET_IOC_NONE,(type),(nr),0) +#define TARGET_IOR(type,nr,size) TARGET_IOC(TARGET_IOC_READ,(type),(nr),sizeof(size)) +#define TARGET_IOW(type,nr,size) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),sizeof(size)) +#define TARGET_IOWR(type,nr,size) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),sizeof(size)) + +/* the size is automatically computed for these defines */ +#define TARGET_IORU(type,nr) TARGET_IOC(TARGET_IOC_READ,(type),(nr),TARGET_IOC_SIZEMASK) +#define TARGET_IOWU(type,nr) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),TARGET_IOC_SIZEMASK) +#define TARGET_IOWRU(type,nr) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),TARGET_IOC_SIZEMASK) + +struct target_sockaddr { + uint16_t sa_family; + uint8_t sa_data[14]; +}; + +struct target_timeval { + target_long tv_sec; + target_long tv_usec; +}; + +struct target_timespec { + target_long tv_sec; + target_long tv_nsec; +}; + +struct target_itimerval { + struct target_timeval it_interval; + struct target_timeval it_value; +}; + +typedef target_long target_clock_t; + +#define TARGET_HZ 100 + +struct target_tms { + target_clock_t tms_utime; + target_clock_t tms_stime; + target_clock_t tms_cutime; + target_clock_t tms_cstime; +}; + +struct target_utimbuf { + target_long actime; + target_long modtime; +}; + +struct target_sel_arg_struct { + target_long n; + target_long inp, outp, exp; + target_long tvp; +}; + +struct target_iovec { + target_long iov_base; /* Starting address */ + target_long iov_len; /* Number of bytes */ +}; + +struct target_msghdr { + target_long msg_name; /* Socket name */ + int msg_namelen; /* Length of name */ + target_long msg_iov; /* Data blocks */ + target_long msg_iovlen; /* Number of blocks */ + target_long msg_control; /* Per protocol magic (eg BSD file descriptor passing) */ + target_long msg_controllen; /* Length of cmsg list */ + unsigned int msg_flags; +}; + +struct target_cmsghdr { + target_long cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +#define TARGET_CMSG_DATA(cmsg) ((unsigned char *) ((struct target_cmsghdr *) (cmsg) + 1)) +#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr (mhdr, cmsg) +#define TARGET_CMSG_FIRSTHDR(mhdr) \ + ((size_t) tswapl((mhdr)->msg_controllen) >= sizeof (struct target_cmsghdr) \ + ? (struct target_cmsghdr *) tswapl((mhdr)->msg_control) : (struct target_cmsghdr *) NULL) +#define TARGET_CMSG_ALIGN(len) (((len) + sizeof (target_long) - 1) \ + & (size_t) ~(sizeof (target_long) - 1)) +#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \ + + TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr))) +#define TARGET_CMSG_LEN(len) (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len)) + +static __inline__ struct target_cmsghdr * +__target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg) +{ + if (tswapl(__cmsg->cmsg_len) < sizeof (struct target_cmsghdr)) + /* The kernel header does this so there may be a reason. */ + return 0; + + __cmsg = (struct target_cmsghdr *) ((unsigned char *) __cmsg + + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len))); + if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) tswapl(__mhdr->msg_control) + + tswapl(__mhdr->msg_controllen)) + || ((unsigned char *) __cmsg + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)) + > ((unsigned char *) tswapl(__mhdr->msg_control) + + tswapl(__mhdr->msg_controllen)))) + /* No more entries. */ + return 0; + return __cmsg; +} + + +struct target_rusage { + struct target_timeval ru_utime; /* user time used */ + struct target_timeval ru_stime; /* system time used */ + target_long ru_maxrss; /* maximum resident set size */ + target_long ru_ixrss; /* integral shared memory size */ + target_long ru_idrss; /* integral unshared data size */ + target_long ru_isrss; /* integral unshared stack size */ + target_long ru_minflt; /* page reclaims */ + target_long ru_majflt; /* page faults */ + target_long ru_nswap; /* swaps */ + target_long ru_inblock; /* block input operations */ + target_long ru_oublock; /* block output operations */ + target_long ru_msgsnd; /* messages sent */ + target_long ru_msgrcv; /* messages received */ + target_long ru_nsignals; /* signals received */ + target_long ru_nvcsw; /* voluntary context switches */ + target_long ru_nivcsw; /* involuntary " */ +}; + +typedef struct { + int val[2]; +} kernel_fsid_t; + +struct kernel_statfs { + int f_type; + int f_bsize; + int f_blocks; + int f_bfree; + int f_bavail; + int f_files; + int f_ffree; + kernel_fsid_t f_fsid; + int f_namelen; + int f_spare[6]; +}; + +struct target_dirent { + target_long d_ino; + target_long d_off; + unsigned short d_reclen; + char d_name[256]; /* We must not include limits.h! */ +}; + +struct target_dirent64 { + uint64_t d_ino; + int64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256]; +}; + + +/* mostly generic signal stuff */ +#define TARGET_SIG_DFL ((target_long)0) /* default signal handling */ +#define TARGET_SIG_IGN ((target_long)1) /* ignore signal */ +#define TARGET_SIG_ERR ((target_long)-1) /* error return from signal */ + +#ifdef TARGET_MIPS +#define TARGET_NSIG 128 +#else +#define TARGET_NSIG 64 +#endif +#define TARGET_NSIG_BPW TARGET_LONG_BITS +#define TARGET_NSIG_WORDS (TARGET_NSIG / TARGET_NSIG_BPW) + +typedef struct { + target_ulong sig[TARGET_NSIG_WORDS]; +} target_sigset_t; + +#ifdef BSWAP_NEEDED +static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s) +{ + int i; + for(i = 0;i < TARGET_NSIG_WORDS; i++) + d->sig[i] = tswapl(s->sig[i]); +} +#else +static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s) +{ + *d = *s; +} +#endif + +static inline void target_siginitset(target_sigset_t *d, target_ulong set) +{ + int i; + d->sig[0] = set; + for(i = 1;i < TARGET_NSIG_WORDS; i++) + d->sig[i] = 0; +} + +void host_to_target_sigset(target_sigset_t *d, const sigset_t *s); +void target_to_host_sigset(sigset_t *d, const target_sigset_t *s); +void host_to_target_old_sigset(target_ulong *old_sigset, + const sigset_t *sigset); +void target_to_host_old_sigset(sigset_t *sigset, + const target_ulong *old_sigset); +struct target_sigaction; +int do_sigaction(int sig, const struct target_sigaction *act, + struct target_sigaction *oact); + +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) + +#if defined(TARGET_SPARC) +#define TARGET_SA_NOCLDSTOP 8u +#define TARGET_SA_NOCLDWAIT 0x100u +#define TARGET_SA_SIGINFO 0x200u +#define TARGET_SA_ONSTACK 1u +#define TARGET_SA_RESTART 2u +#define TARGET_SA_NODEFER 0x20u +#define TARGET_SA_RESETHAND 4u +#elif defined(TARGET_MIPS) +#define TARGET_SA_NOCLDSTOP 0x00000001 +#define TARGET_SA_NOCLDWAIT 0x00010000 +#define TARGET_SA_SIGINFO 0x00000008 +#define TARGET_SA_ONSTACK 0x08000000 +#define TARGET_SA_NODEFER 0x40000000 +#define TARGET_SA_RESTART 0x10000000 +#define TARGET_SA_RESETHAND 0x80000000 +#define TARGET_SA_RESTORER 0x04000000 /* Only for o32 */ +#else +#define TARGET_SA_NOCLDSTOP 0x00000001 +#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */ +#define TARGET_SA_SIGINFO 0x00000004 +#define TARGET_SA_ONSTACK 0x08000000 +#define TARGET_SA_RESTART 0x10000000 +#define TARGET_SA_NODEFER 0x40000000 +#define TARGET_SA_RESETHAND 0x80000000 +#define TARGET_SA_RESTORER 0x04000000 +#endif + +#if defined(TARGET_SPARC) + +#define TARGET_SIGHUP 1 +#define TARGET_SIGINT 2 +#define TARGET_SIGQUIT 3 +#define TARGET_SIGILL 4 +#define TARGET_SIGTRAP 5 +#define TARGET_SIGABRT 6 +#define TARGET_SIGIOT 6 +#define TARGET_SIGSTKFLT 7 /* actually EMT */ +#define TARGET_SIGFPE 8 +#define TARGET_SIGKILL 9 +#define TARGET_SIGBUS 10 +#define TARGET_SIGSEGV 11 +#define TARGET_SIGSYS 12 +#define TARGET_SIGPIPE 13 +#define TARGET_SIGALRM 14 +#define TARGET_SIGTERM 15 +#define TARGET_SIGURG 16 +#define TARGET_SIGSTOP 17 +#define TARGET_SIGTSTP 18 +#define TARGET_SIGCONT 19 +#define TARGET_SIGCHLD 20 +#define TARGET_SIGTTIN 21 +#define TARGET_SIGTTOU 22 +#define TARGET_SIGIO 23 +#define TARGET_SIGXCPU 24 +#define TARGET_SIGXFSZ 25 +#define TARGET_SIGVTALRM 26 +#define TARGET_SIGPROF 27 +#define TARGET_SIGWINCH 28 +#define TARGET_SIGPWR 29 +#define TARGET_SIGUSR1 30 +#define TARGET_SIGUSR2 31 +#define TARGET_SIGRTMIN 32 + +#define TARGET_SIG_BLOCK 0x01 /* for blocking signals */ +#define TARGET_SIG_UNBLOCK 0x02 /* for unblocking signals */ +#define TARGET_SIG_SETMASK 0x04 /* for setting the signal mask */ + +#elif defined(TARGET_MIPS) + +#define TARGET_SIGHUP 1 /* Hangup (POSIX). */ +#define TARGET_SIGINT 2 /* Interrupt (ANSI). */ +#define TARGET_SIGQUIT 3 /* Quit (POSIX). */ +#define TARGET_SIGILL 4 /* Illegal instruction (ANSI). */ +#define TARGET_SIGTRAP 5 /* Trace trap (POSIX). */ +#define TARGET_SIGIOT 6 /* IOT trap (4.2 BSD). */ +#define TARGET_SIGABRT TARGET_SIGIOT /* Abort (ANSI). */ +#define TARGET_SIGEMT 7 +#define TARGET_SIGSTKFLT 7 /* XXX: incorrect */ +#define TARGET_SIGFPE 8 /* Floating-point exception (ANSI). */ +#define TARGET_SIGKILL 9 /* Kill, unblockable (POSIX). */ +#define TARGET_SIGBUS 10 /* BUS error (4.2 BSD). */ +#define TARGET_SIGSEGV 11 /* Segmentation violation (ANSI). */ +#define TARGET_SIGSYS 12 +#define TARGET_SIGPIPE 13 /* Broken pipe (POSIX). */ +#define TARGET_SIGALRM 14 /* Alarm clock (POSIX). */ +#define TARGET_SIGTERM 15 /* Termination (ANSI). */ +#define TARGET_SIGUSR1 16 /* User-defined signal 1 (POSIX). */ +#define TARGET_SIGUSR2 17 /* User-defined signal 2 (POSIX). */ +#define TARGET_SIGCHLD 18 /* Child status has changed (POSIX). */ +#define TARGET_SIGCLD TARGET_SIGCHLD /* Same as TARGET_SIGCHLD (System V). */ +#define TARGET_SIGPWR 19 /* Power failure restart (System V). */ +#define TARGET_SIGWINCH 20 /* Window size change (4.3 BSD, Sun). */ +#define TARGET_SIGURG 21 /* Urgent condition on socket (4.2 BSD). */ +#define TARGET_SIGIO 22 /* I/O now possible (4.2 BSD). */ +#define TARGET_SIGPOLL TARGET_SIGIO /* Pollable event occurred (System V). */ +#define TARGET_SIGSTOP 23 /* Stop, unblockable (POSIX). */ +#define TARGET_SIGTSTP 24 /* Keyboard stop (POSIX). */ +#define TARGET_SIGCONT 25 /* Continue (POSIX). */ +#define TARGET_SIGTTIN 26 /* Background read from tty (POSIX). */ +#define TARGET_SIGTTOU 27 /* Background write to tty (POSIX). */ +#define TARGET_SIGVTALRM 28 /* Virtual alarm clock (4.2 BSD). */ +#define TARGET_SIGPROF 29 /* Profiling alarm clock (4.2 BSD). */ +#define TARGET_SIGXCPU 30 /* CPU limit exceeded (4.2 BSD). */ +#define TARGET_SIGXFSZ 31 /* File size limit exceeded (4.2 BSD). */ +#define TARGET_SIGRTMIN 32 + +#define TARGET_SIG_BLOCK 1 /* for blocking signals */ +#define TARGET_SIG_UNBLOCK 2 /* for unblocking signals */ +#define TARGET_SIG_SETMASK 3 /* for setting the signal mask */ + +#else + +#define TARGET_SIGHUP 1 +#define TARGET_SIGINT 2 +#define TARGET_SIGQUIT 3 +#define TARGET_SIGILL 4 +#define TARGET_SIGTRAP 5 +#define TARGET_SIGABRT 6 +#define TARGET_SIGIOT 6 +#define TARGET_SIGBUS 7 +#define TARGET_SIGFPE 8 +#define TARGET_SIGKILL 9 +#define TARGET_SIGUSR1 10 +#define TARGET_SIGSEGV 11 +#define TARGET_SIGUSR2 12 +#define TARGET_SIGPIPE 13 +#define TARGET_SIGALRM 14 +#define TARGET_SIGTERM 15 +#define TARGET_SIGSTKFLT 16 +#define TARGET_SIGCHLD 17 +#define TARGET_SIGCONT 18 +#define TARGET_SIGSTOP 19 +#define TARGET_SIGTSTP 20 +#define TARGET_SIGTTIN 21 +#define TARGET_SIGTTOU 22 +#define TARGET_SIGURG 23 +#define TARGET_SIGXCPU 24 +#define TARGET_SIGXFSZ 25 +#define TARGET_SIGVTALRM 26 +#define TARGET_SIGPROF 27 +#define TARGET_SIGWINCH 28 +#define TARGET_SIGIO 29 +#define TARGET_SIGPWR 30 +#define TARGET_SIGSYS 31 +#define TARGET_SIGRTMIN 32 + +#define TARGET_SIG_BLOCK 0 /* for blocking signals */ +#define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */ +#define TARGET_SIG_SETMASK 2 /* for setting the signal mask */ + +#endif + +#if defined(TARGET_MIPS) + +struct target_sigaction { + target_ulong sa_flags; + target_ulong _sa_handler; + target_sigset_t sa_mask; +}; + +#else +struct target_old_sigaction { + target_ulong _sa_handler; + target_ulong sa_mask; + target_ulong sa_flags; + target_ulong sa_restorer; +}; + +struct target_sigaction { + target_ulong _sa_handler; + target_ulong sa_flags; + target_ulong sa_restorer; + target_sigset_t sa_mask; +}; +#endif + +typedef union target_sigval { + int sival_int; + target_ulong sival_ptr; +} target_sigval_t; +#if 0 +#if defined (TARGET_SPARC) +typedef struct { + struct { + target_ulong psr; + target_ulong pc; + target_ulong npc; + target_ulong y; + target_ulong u_regs[16]; /* globals and ins */ + } si_regs; + int si_mask; +} __siginfo_t; + +typedef struct { + unsigned long si_float_regs [32]; + unsigned long si_fsr; + unsigned long si_fpqdepth; + struct { + unsigned long *insn_addr; + unsigned long insn; + } si_fpqueue [16]; +} __siginfo_fpu_t; +#endif +#endif + +#define TARGET_SI_MAX_SIZE 128 +#define TARGET_SI_PAD_SIZE ((TARGET_SI_MAX_SIZE/sizeof(int)) - 3) + +typedef struct target_siginfo { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[TARGET_SI_PAD_SIZE]; + + /* kill() */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + unsigned int _timer1; + unsigned int _timer2; + } _timer; + + /* POSIX.1b signals */ + struct { + pid_t _pid; /* sender's pid */ + uid_t _uid; /* sender's uid */ + target_sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct { + pid_t _pid; /* which child */ + uid_t _uid; /* sender's uid */ + int _status; /* exit code */ + target_clock_t _utime; + target_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + target_ulong _addr; /* faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} target_siginfo_t; + +/* + * si_code values + * Digital reserves positive values for kernel-generated signals. + */ +#define TARGET_SI_USER 0 /* sent by kill, sigsend, raise */ +#define TARGET_SI_KERNEL 0x80 /* sent by the kernel from somewhere */ +#define TARGET_SI_QUEUE -1 /* sent by sigqueue */ +#define TARGET_SI_TIMER -2 /* sent by timer expiration */ +#define TARGET_SI_MESGQ -3 /* sent by real time mesq state change */ +#define TARGET_SI_ASYNCIO -4 /* sent by AIO completion */ +#define TARGET_SI_SIGIO -5 /* sent by queued SIGIO */ + +/* + * SIGILL si_codes + */ +#define TARGET_ILL_ILLOPC (1) /* illegal opcode */ +#define TARGET_ILL_ILLOPN (2) /* illegal operand */ +#define TARGET_ILL_ILLADR (3) /* illegal addressing mode */ +#define TARGET_ILL_ILLTRP (4) /* illegal trap */ +#define TARGET_ILL_PRVOPC (5) /* privileged opcode */ +#define TARGET_ILL_PRVREG (6) /* privileged register */ +#define TARGET_ILL_COPROC (7) /* coprocessor error */ +#define TARGET_ILL_BADSTK (8) /* internal stack error */ + +/* + * SIGFPE si_codes + */ +#define TARGET_FPE_INTDIV (1) /* integer divide by zero */ +#define TARGET_FPE_INTOVF (2) /* integer overflow */ +#define TARGET_FPE_FLTDIV (3) /* floating point divide by zero */ +#define TARGET_FPE_FLTOVF (4) /* floating point overflow */ +#define TARGET_FPE_FLTUND (5) /* floating point underflow */ +#define TARGET_FPE_FLTRES (6) /* floating point inexact result */ +#define TARGET_FPE_FLTINV (7) /* floating point invalid operation */ +#define TARGET_FPE_FLTSUB (8) /* subscript out of range */ +#define TARGET_NSIGFPE 8 + +/* + * SIGSEGV si_codes + */ +#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */ +#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */ + +/* + * SIGBUS si_codes + */ +#define TARGET_BUS_ADRALN (1) /* invalid address alignment */ +#define TARGET_BUS_ADRERR (2) /* non-existant physical address */ +#define TARGET_BUS_OBJERR (3) /* object specific hardware error */ + +/* + * SIGTRAP si_codes + */ +#define TARGET_TRAP_BRKPT (1) /* process breakpoint */ +#define TARGET_TRAP_TRACE (2) /* process trace trap */ + +#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */ + +struct target_rlimit { + target_ulong rlim_cur; + target_ulong rlim_max; +}; + +struct target_pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; + +/* virtual terminal ioctls */ +#define TARGET_KIOCSOUND 0x4B2F /* start sound generation (0 for off) */ +#define TARGET_KDMKTONE 0x4B30 /* generate tone */ +#define TARGET_KDGKBTYPE 0x4b33 +#define TARGET_KDGKBENT 0x4B46 /* gets one entry in translation table */ +#define TARGET_KDGKBSENT 0x4B48 /* gets one function key string entry */ + +#define TARGET_SIOCATMARK 0x8905 + +/* Networking ioctls */ +#define TARGET_SIOCADDRT 0x890B /* add routing table entry */ +#define TARGET_SIOCDELRT 0x890C /* delete routing table entry */ +#define TARGET_SIOCGIFNAME 0x8910 /* get iface name */ +#define TARGET_SIOCSIFLINK 0x8911 /* set iface channel */ +#define TARGET_SIOCGIFCONF 0x8912 /* get iface list */ +#define TARGET_SIOCGIFFLAGS 0x8913 /* get flags */ +#define TARGET_SIOCSIFFLAGS 0x8914 /* set flags */ +#define TARGET_SIOCGIFADDR 0x8915 /* get PA address */ +#define TARGET_SIOCSIFADDR 0x8916 /* set PA address */ +#define TARGET_SIOCGIFDSTADDR 0x8917 /* get remote PA address */ +#define TARGET_SIOCSIFDSTADDR 0x8918 /* set remote PA address */ +#define TARGET_SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */ +#define TARGET_SIOCSIFBRDADDR 0x891a /* set broadcast PA address */ +#define TARGET_SIOCGIFNETMASK 0x891b /* get network PA mask */ +#define TARGET_SIOCSIFNETMASK 0x891c /* set network PA mask */ +#define TARGET_SIOCGIFMETRIC 0x891d /* get metric */ +#define TARGET_SIOCSIFMETRIC 0x891e /* set metric */ +#define TARGET_SIOCGIFMEM 0x891f /* get memory address (BSD) */ +#define TARGET_SIOCSIFMEM 0x8920 /* set memory address (BSD) */ +#define TARGET_SIOCGIFMTU 0x8921 /* get MTU size */ +#define TARGET_SIOCSIFMTU 0x8922 /* set MTU size */ +#define TARGET_SIOCSIFHWADDR 0x8924 /* set hardware address (NI) */ +#define TARGET_SIOCGIFENCAP 0x8925 /* get/set slip encapsulation */ +#define TARGET_SIOCSIFENCAP 0x8926 +#define TARGET_SIOCGIFHWADDR 0x8927 /* Get hardware address */ +#define TARGET_SIOCGIFSLAVE 0x8929 /* Driver slaving support */ +#define TARGET_SIOCSIFSLAVE 0x8930 +#define TARGET_SIOCADDMULTI 0x8931 /* Multicast address lists */ +#define TARGET_SIOCDELMULTI 0x8932 + +/* Bridging control calls */ +#define TARGET_SIOCGIFBR 0x8940 /* Bridging support */ +#define TARGET_SIOCSIFBR 0x8941 /* Set bridging options */ + +#define TARGET_SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */ +#define TARGET_SIOCSIFTXQLEN 0x8943 /* Set the tx queue length */ + +/* ARP cache control calls. */ +#define TARGET_OLD_SIOCDARP 0x8950 /* old delete ARP table entry */ +#define TARGET_OLD_SIOCGARP 0x8951 /* old get ARP table entry */ +#define TARGET_OLD_SIOCSARP 0x8952 /* old set ARP table entry */ +#define TARGET_SIOCDARP 0x8953 /* delete ARP table entry */ +#define TARGET_SIOCGARP 0x8954 /* get ARP table entry */ +#define TARGET_SIOCSARP 0x8955 /* set ARP table entry */ + +/* RARP cache control calls. */ +#define TARGET_SIOCDRARP 0x8960 /* delete RARP table entry */ +#define TARGET_SIOCGRARP 0x8961 /* get RARP table entry */ +#define TARGET_SIOCSRARP 0x8962 /* set RARP table entry */ + +/* Driver configuration calls */ +#define TARGET_SIOCGIFMAP 0x8970 /* Get device parameters */ +#define TARGET_SIOCSIFMAP 0x8971 /* Set device parameters */ + +/* DLCI configuration calls */ +#define TARGET_SIOCADDDLCI 0x8980 /* Create new DLCI device */ +#define TARGET_SIOCDELDLCI 0x8981 /* Delete DLCI device */ + + +/* From <linux/fs.h> */ + +#define TARGET_BLKROSET TARGET_IO(0x12,93) /* set device read-only (0 = read-write) */ +#define TARGET_BLKROGET TARGET_IO(0x12,94) /* get read-only status (0 = read_write) */ +#define TARGET_BLKRRPART TARGET_IO(0x12,95) /* re-read partition table */ +#define TARGET_BLKGETSIZE TARGET_IO(0x12,96) /* return device size /512 (long *arg) */ +#define TARGET_BLKFLSBUF TARGET_IO(0x12,97) /* flush buffer cache */ +#define TARGET_BLKRASET TARGET_IO(0x12,98) /* Set read ahead for block device */ +#define TARGET_BLKRAGET TARGET_IO(0x12,99) /* get current read ahead setting */ +#define TARGET_BLKFRASET TARGET_IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */ +#define TARGET_BLKFRAGET TARGET_IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */ +#define TARGET_BLKSECTSET TARGET_IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */ +#define TARGET_BLKSECTGET TARGET_IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */ +#define TARGET_BLKSSZGET TARGET_IO(0x12,104)/* get block device sector size */ +/* A jump here: 108-111 have been used for various private purposes. */ +#define TARGET_BLKBSZGET TARGET_IOR(0x12,112,sizeof(int)) +#define TARGET_BLKBSZSET TARGET_IOW(0x12,113,sizeof(int)) +#define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */ +#define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */ +#define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */ + +/* cdrom commands */ +#define TARGET_CDROMPAUSE 0x5301 /* Pause Audio Operation */ +#define TARGET_CDROMRESUME 0x5302 /* Resume paused Audio Operation */ +#define TARGET_CDROMPLAYMSF 0x5303 /* Play Audio MSF (struct cdrom_msf) */ +#define TARGET_CDROMPLAYTRKIND 0x5304 /* Play Audio Track/index + (struct cdrom_ti) */ +#define TARGET_CDROMREADTOCHDR 0x5305 /* Read TOC header + (struct cdrom_tochdr) */ +#define TARGET_CDROMREADTOCENTRY 0x5306 /* Read TOC entry + (struct cdrom_tocentry) */ +#define TARGET_CDROMSTOP 0x5307 /* Stop the cdrom drive */ +#define TARGET_CDROMSTART 0x5308 /* Start the cdrom drive */ +#define TARGET_CDROMEJECT 0x5309 /* Ejects the cdrom media */ +#define TARGET_CDROMVOLCTRL 0x530a /* Control output volume + (struct cdrom_volctrl) */ +#define TARGET_CDROMSUBCHNL 0x530b /* Read subchannel data + (struct cdrom_subchnl) */ +#define TARGET_CDROMREADMODE2 0x530c /* Read TARGET_CDROM mode 2 data (2336 Bytes) + (struct cdrom_read) */ +#define TARGET_CDROMREADMODE1 0x530d /* Read TARGET_CDROM mode 1 data (2048 Bytes) + (struct cdrom_read) */ +#define TARGET_CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */ +#define TARGET_CDROMEJECT_SW 0x530f /* enable(1)/disable(0) auto-ejecting */ +#define TARGET_CDROMMULTISESSION 0x5310 /* Obtain the start-of-last-session + address of multi session disks + (struct cdrom_multisession) */ +#define TARGET_CDROM_GET_MCN 0x5311 /* Obtain the "Universal Product Code" + if available (struct cdrom_mcn) */ +#define TARGET_CDROM_GET_UPC TARGET_CDROM_GET_MCN /* This one is depricated, + but here anyway for compatability */ +#define TARGET_CDROMRESET 0x5312 /* hard-reset the drive */ +#define TARGET_CDROMVOLREAD 0x5313 /* Get the drive's volume setting + (struct cdrom_volctrl) */ +#define TARGET_CDROMREADRAW 0x5314 /* read data in raw mode (2352 Bytes) + (struct cdrom_read) */ +/* + * These ioctls are used only used in aztcd.c and optcd.c + */ +#define TARGET_CDROMREADCOOKED 0x5315 /* read data in cooked mode */ +#define TARGET_CDROMSEEK 0x5316 /* seek msf address */ + +/* + * This ioctl is only used by the scsi-cd driver. + It is for playing audio in logical block addressing mode. + */ +#define TARGET_CDROMPLAYBLK 0x5317 /* (struct cdrom_blk) */ + +/* + * These ioctls are only used in optcd.c + */ +#define TARGET_CDROMREADALL 0x5318 /* read all 2646 bytes */ + +/* + * These ioctls are (now) only in ide-cd.c for controlling + * drive spindown time. They should be implemented in the + * Uniform driver, via generic packet commands, GPCMD_MODE_SELECT_10, + * GPCMD_MODE_SENSE_10 and the GPMODE_POWER_PAGE... + * -Erik + */ +#define TARGET_CDROMGETSPINDOWN 0x531d +#define TARGET_CDROMSETSPINDOWN 0x531e + +/* + * These ioctls are implemented through the uniform CD-ROM driver + * They _will_ be adopted by all CD-ROM drivers, when all the CD-ROM + * drivers are eventually ported to the uniform CD-ROM driver interface. + */ +#define TARGET_CDROMCLOSETRAY 0x5319 /* pendant of CDROMEJECT */ +#define TARGET_CDROM_SET_OPTIONS 0x5320 /* Set behavior options */ +#define TARGET_CDROM_CLEAR_OPTIONS 0x5321 /* Clear behavior options */ +#define TARGET_CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */ +#define TARGET_CDROM_SELECT_DISC 0x5323 /* Select disc (for juke-boxes) */ +#define TARGET_CDROM_MEDIA_CHANGED 0x5325 /* Check is media changed */ +#define TARGET_CDROM_DRIVE_STATUS 0x5326 /* Get tray position, etc. */ +#define TARGET_CDROM_DISC_STATUS 0x5327 /* Get disc type, etc. */ +#define TARGET_CDROM_CHANGER_NSLOTS 0x5328 /* Get number of slots */ +#define TARGET_CDROM_LOCKDOOR 0x5329 /* lock or unlock door */ +#define TARGET_CDROM_DEBUG 0x5330 /* Turn debug messages on/off */ +#define TARGET_CDROM_GET_CAPABILITY 0x5331 /* get capabilities */ + +/* Note that scsi/scsi_ioctl.h also uses 0x5382 - 0x5386. + * Future CDROM ioctls should be kept below 0x537F + */ + +/* This ioctl is only used by sbpcd at the moment */ +#define TARGET_CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ + /* conflict with SCSI_IOCTL_GET_IDLUN */ + +/* DVD-ROM Specific ioctls */ +#define TARGET_DVD_READ_STRUCT 0x5390 /* Read structure */ +#define TARGET_DVD_WRITE_STRUCT 0x5391 /* Write structure */ +#define TARGET_DVD_AUTH 0x5392 /* Authentication */ + +#define TARGET_CDROM_SEND_PACKET 0x5393 /* send a packet to the drive */ +#define TARGET_CDROM_NEXT_WRITABLE 0x5394 /* get next writable block */ +#define TARGET_CDROM_LAST_WRITTEN 0x5395 /* get last block written on disc */ + +/* HD commands */ + +/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */ +#define TARGET_HDIO_GETGEO 0x0301 /* get device geometry */ +#define TARGET_HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */ +#define TARGET_HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */ +#define TARGET_HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */ +#define TARGET_HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */ +#define TARGET_HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */ +#define TARGET_HDIO_GET_DMA 0x030b /* get use-dma flag */ +#define TARGET_HDIO_GET_IDENTITY 0x030d /* get IDE identification info */ +#define TARGET_HDIO_DRIVE_CMD 0x031f /* execute a special drive command */ + +/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */ +#define TARGET_HDIO_SET_MULTCOUNT 0x0321 /* change IDE blockmode */ +#define TARGET_HDIO_SET_UNMASKINTR 0x0322 /* permit other irqs during I/O */ +#define TARGET_HDIO_SET_KEEPSETTINGS 0x0323 /* keep ioctl settings on reset */ +#define TARGET_HDIO_SET_32BIT 0x0324 /* change io_32bit flags */ +#define TARGET_HDIO_SET_NOWERR 0x0325 /* change ignore-write-error flag */ +#define TARGET_HDIO_SET_DMA 0x0326 /* change use-dma flag */ +#define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */ + + +/* from asm/termbits.h */ + +#define TARGET_NCC 8 +struct target_termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCC]; /* control characters */ +}; + +struct target_winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#include "termbits.h" + +#define TARGET_MAP_SHARED 0x01 /* Share changes */ +#define TARGET_MAP_PRIVATE 0x02 /* Changes are private */ +#define TARGET_MAP_TYPE 0x0f /* Mask for type of mapping */ +#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */ +#if defined(TARGET_MIPS) +#define TARGET_MAP_ANONYMOUS 0x0800 /* don't use a file */ +#define TARGET_MAP_GROWSDOWN 0x1000 /* stack-like segment */ +#define TARGET_MAP_DENYWRITE 0x2000 /* ETXTBSY */ +#define TARGET_MAP_EXECUTABLE 0x4000 /* mark it as an executable */ +#define TARGET_MAP_LOCKED 0x8000 /* pages are locked */ +#define TARGET_MAP_NORESERVE 0x0400 /* don't check for reservations */ +#else +#define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */ +#define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */ +#define TARGET_MAP_LOCKED 0x2000 /* pages are locked */ +#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */ +#endif + +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) +struct target_stat { + unsigned short st_dev; + unsigned short __pad1; + target_ulong st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + target_ulong st_size; + target_ulong st_blksize; + target_ulong st_blocks; + target_ulong target_st_atime; + target_ulong __unused1; + target_ulong target_st_mtime; + target_ulong __unused2; + target_ulong target_st_ctime; + target_ulong __unused3; + target_ulong __unused4; + target_ulong __unused5; +}; + +/* This matches struct stat64 in glibc2.1, hence the absolutely + * insane amounts of padding around dev_t's. + */ +struct target_stat64 { + unsigned short st_dev; + unsigned char __pad0[10]; + +#define TARGET_STAT64_HAS_BROKEN_ST_INO 1 + target_ulong __st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + target_ulong st_uid; + target_ulong st_gid; + + unsigned short st_rdev; + unsigned char __pad3[10]; + + long long st_size; + target_ulong st_blksize; + + target_ulong st_blocks; /* Number 512-byte blocks allocated. */ + target_ulong __pad4; /* future possible st_blocks high bits */ + + target_ulong target_st_atime; + target_ulong __pad5; + + target_ulong target_st_mtime; + target_ulong __pad6; + + target_ulong target_st_ctime; + target_ulong __pad7; /* will be high 32 bits of ctime someday */ + + unsigned long long st_ino; +} __attribute__((packed)); + +#ifdef TARGET_ARM +struct target_eabi_stat64 { + unsigned long long st_dev; + unsigned int __pad1; + unsigned long __st_ino; + unsigned int st_mode; + unsigned int st_nlink; + + unsigned long st_uid; + unsigned long st_gid; + + unsigned long long st_rdev; + unsigned int __pad2[2]; + + long long st_size; + unsigned long st_blksize; + unsigned int __pad3; + unsigned long long st_blocks; + + unsigned long target_st_atime; + unsigned long target_st_atime_nsec; + + unsigned long target_st_mtime; + unsigned long target_st_mtime_nsec; + + unsigned long target_st_ctime; + unsigned long target_st_ctime_nsec; + + unsigned long long st_ino; +} __attribute__ ((packed)); +#endif + +#elif defined(TARGET_SPARC) + +struct target_stat { + unsigned short st_dev; + target_ulong st_ino; + unsigned short st_mode; + short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + target_long st_size; + target_long target_st_atime; + target_ulong __unused1; + target_long target_st_mtime; + target_ulong __unused2; + target_long target_st_ctime; + target_ulong __unused3; + target_long st_blksize; + target_long st_blocks; + target_ulong __unused4[2]; +}; + +struct target_stat64 { + unsigned char __pad0[6]; + unsigned short st_dev; + + uint64_t st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + unsigned int st_uid; + unsigned int st_gid; + + unsigned char __pad2[6]; + unsigned short st_rdev; + + unsigned char __pad3[8]; + + int64_t st_size; + unsigned int st_blksize; + + unsigned char __pad4[8]; + unsigned int st_blocks; + + unsigned int target_st_atime; + unsigned int __unused1; + + unsigned int target_st_mtime; + unsigned int __unused2; + + unsigned int target_st_ctime; + unsigned int __unused3; + + unsigned int __unused4; + unsigned int __unused5; +}; + +#elif defined(TARGET_PPC) + +struct target_stat { + unsigned short st_dev; + target_ulong st_ino; + unsigned int st_mode; + unsigned short st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned short st_rdev; + target_ulong st_size; + target_ulong st_blksize; + target_ulong st_blocks; + target_ulong target_st_atime; + target_ulong __unused1; + target_ulong target_st_mtime; + target_ulong __unused2; + target_ulong target_st_ctime; + target_ulong __unused3; + target_ulong __unused4; + target_ulong __unused5; +}; + +struct target_stat64 { + unsigned long long st_dev; + unsigned long long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned long long st_rdev; + long long pad0; + long long st_size; + target_ulong st_blksize; + target_ulong pad1; + long long st_blocks; /* Number 512-byte blocks allocated. */ + target_ulong target_st_atime; + target_ulong target_st_atime_nsec; + target_ulong target_st_mtime; + target_ulong target_st_mtime_nsec; + target_ulong target_st_ctime; + target_ulong target_st_ctime_nsec; + target_ulong __unused4; + target_ulong __unused5; +}; + +#elif defined(TARGET_MIPS) + +struct target_stat { + unsigned st_dev; + target_long st_pad1[3]; /* Reserved for network id */ + target_ulong st_ino; + unsigned int st_mode; + unsigned int st_nlink; + int st_uid; + int st_gid; + unsigned st_rdev; + target_long st_pad2[2]; + target_long st_size; + target_long st_pad3; + /* + * Actually this should be timestruc_t st_atime, st_mtime and st_ctime + * but we don't have it under Linux. + */ + target_long target_st_atime; + target_long target_st_atime_nsec; + target_long target_st_mtime; + target_long target_st_mtime_nsec; + target_long target_st_ctime; + target_long target_st_ctime_nsec; + target_long st_blksize; + target_long st_blocks; + target_long st_pad4[14]; +}; + +/* + * This matches struct stat64 in glibc2.1, hence the absolutely insane + * amounts of padding around dev_t's. The memory layout is the same as of + * struct stat of the 64-bit kernel. + */ + +struct target_stat64 { + target_ulong st_dev; + target_ulong st_pad0[3]; /* Reserved for st_dev expansion */ + + uint64_t st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + int st_uid; + int st_gid; + + target_ulong st_rdev; + target_ulong st_pad1[3]; /* Reserved for st_rdev expansion */ + + int64_t st_size; + + /* + * Actually this should be timestruc_t st_atime, st_mtime and st_ctime + * but we don't have it under Linux. + */ + target_long target_st_atime; + target_ulong target_st_atime_nsec; /* Reserved for st_atime expansion */ + + target_long target_st_mtime; + target_ulong target_st_mtime_nsec; /* Reserved for st_mtime expansion */ + + target_long target_st_ctime; + target_ulong target_st_ctime_nsec; /* Reserved for st_ctime expansion */ + + target_ulong st_blksize; + target_ulong st_pad2; + + int64_t st_blocks; +}; +#else +#error unsupported CPU +#endif + +#ifdef TARGET_MIPS +struct target_statfs { + target_long f_type; + target_long f_bsize; + target_long f_frsize; /* Fragment size - unsupported */ + target_long f_blocks; + target_long f_bfree; + target_long f_files; + target_long f_ffree; + target_long f_bavail; + + /* Linux specials */ + int f_fsid; + target_long f_namelen; + target_long f_spare[6]; +}; + +struct target_statfs64 { + uint32_t f_type; + uint32_t f_bsize; + uint32_t f_frsize; /* Fragment size - unsupported */ + uint32_t __pad; + uint64_t f_blocks; + uint64_t f_bfree; + uint64_t f_files; + uint64_t f_ffree; + uint64_t f_bavail; + int f_fsid; + uint32_t f_namelen; + uint32_t f_spare[6]; +}; +#else +struct target_statfs { + uint32_t f_type; + uint32_t f_bsize; + uint32_t f_blocks; + uint32_t f_bfree; + uint32_t f_bavail; + uint32_t f_files; + uint32_t f_ffree; + int f_fsid; + uint32_t f_namelen; + uint32_t f_frsize; + uint32_t f_spare[5]; +}; + +struct target_statfs64 { + uint32_t f_type; + uint32_t f_bsize; + uint64_t f_blocks; + uint64_t f_bfree; + uint64_t f_bavail; + uint64_t f_files; + uint64_t f_ffree; + int f_fsid; + uint32_t f_namelen; + uint32_t f_frsize; + uint32_t f_spare[5]; +}; +#endif + + +#define TARGET_F_DUPFD 0 /* dup */ +#define TARGET_F_GETFD 1 /* get close_on_exec */ +#define TARGET_F_SETFD 2 /* set/clear close_on_exec */ +#define TARGET_F_GETFL 3 /* get file->f_flags */ +#define TARGET_F_SETFL 4 /* set file->f_flags */ + +#if defined(TARGET_ALPHA) +#define TARGET_F_GETLK 7 +#define TARGET_F_SETLK 8 +#define TARGET_F_SETLKW 9 +#define TARGET_F_SETOWN 5 /* for sockets. */ +#define TARGET_F_GETOWN 6 /* for sockets. */ +#else +#define TARGET_F_GETLK 5 +#define TARGET_F_SETLK 6 +#define TARGET_F_SETLKW 7 +#define TARGET_F_SETOWN 8 /* for sockets. */ +#define TARGET_F_GETOWN 9 /* for sockets. */ +#endif + +#define TARGET_F_SETSIG 10 /* for sockets. */ +#define TARGET_F_GETSIG 11 /* for sockets. */ + +#define TARGET_F_GETLK64 12 /* using 'struct flock64' */ +#define TARGET_F_SETLK64 13 +#define TARGET_F_SETLKW64 14 + +#if defined (TARGET_ARM) +#define TARGET_O_ACCMODE 0003 +#define TARGET_O_RDONLY 00 +#define TARGET_O_WRONLY 01 +#define TARGET_O_RDWR 02 +#define TARGET_O_CREAT 0100 /* not fcntl */ +#define TARGET_O_EXCL 0200 /* not fcntl */ +#define TARGET_O_NOCTTY 0400 /* not fcntl */ +#define TARGET_O_TRUNC 01000 /* not fcntl */ +#define TARGET_O_APPEND 02000 +#define TARGET_O_NONBLOCK 04000 +#define TARGET_O_NDELAY TARGET_O_NONBLOCK +#define TARGET_O_SYNC 010000 +#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */ +#define TARGET_O_DIRECTORY 040000 /* must be a directory */ +#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */ +#define TARGET_O_DIRECT 0200000 /* direct disk access hint */ +#define TARGET_O_LARGEFILE 0400000 +#elif defined (TARGET_PPC) +#define TARGET_O_ACCMODE 0003 +#define TARGET_O_RDONLY 00 +#define TARGET_O_WRONLY 01 +#define TARGET_O_RDWR 02 +#define TARGET_O_CREAT 0100 /* not fcntl */ +#define TARGET_O_EXCL 0200 /* not fcntl */ +#define TARGET_O_NOCTTY 0400 /* not fcntl */ +#define TARGET_O_TRUNC 01000 /* not fcntl */ +#define TARGET_O_APPEND 02000 +#define TARGET_O_NONBLOCK 04000 +#define TARGET_O_NDELAY TARGET_O_NONBLOCK +#define TARGET_O_SYNC 010000 +#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */ +#define TARGET_O_DIRECTORY 040000 /* must be a directory */ +#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */ +#define TARGET_O_LARGEFILE 0200000 +#define TARGET_O_DIRECT 0400000 /* direct disk access hint */ +#elif defined (TARGET_SPARC) +#define TARGET_O_RDONLY 0x0000 +#define TARGET_O_WRONLY 0x0001 +#define TARGET_O_RDWR 0x0002 +#define TARGET_O_ACCMODE 0x0003 +#define TARGET_O_APPEND 0x0008 +#define TARGET_FASYNC 0x0040 /* fcntl, for BSD compatibility */ +#define TARGET_O_CREAT 0x0200 /* not fcntl */ +#define TARGET_O_TRUNC 0x0400 /* not fcntl */ +#define TARGET_O_EXCL 0x0800 /* not fcntl */ +#define TARGET_O_SYNC 0x2000 +#define TARGET_O_NONBLOCK 0x4000 +#define TARGET_O_NDELAY (0x0004 | TARGET_O_NONBLOCK) +#define TARGET_O_NOCTTY 0x8000 /* not fcntl */ +#define TARGET_O_DIRECTORY 0x10000 /* must be a directory */ +#define TARGET_O_NOFOLLOW 0x20000 /* don't follow links */ +#define TARGET_O_LARGEFILE 0x40000 +#define TARGET_O_DIRECT 0x100000 /* direct disk access hint */ +#elif defined(TARGET_MIPS) +#define TARGET_O_ACCMODE 0x0003 +#define TARGET_O_RDONLY 0x0000 +#define TARGET_O_WRONLY 0x0001 +#define TARGET_O_RDWR 0x0002 +#define TARGET_O_APPEND 0x0008 +#define TARGET_O_SYNC 0x0010 +#define TARGET_O_NONBLOCK 0x0080 +#define TARGET_O_CREAT 0x0100 /* not fcntl */ +#define TARGET_O_TRUNC 0x0200 /* not fcntl */ +#define TARGET_O_EXCL 0x0400 /* not fcntl */ +#define TARGET_O_NOCTTY 0x0800 /* not fcntl */ +#define TARGET_FASYNC 0x1000 /* fcntl, for BSD compatibility */ +#define TARGET_O_LARGEFILE 0x2000 /* allow large file opens */ +#define TARGET_O_DIRECT 0x8000 /* direct disk access hint */ +#define TARGET_O_DIRECTORY 0x10000 /* must be a directory */ +#define TARGET_O_NOFOLLOW 0x20000 /* don't follow links */ +#define TARGET_O_NOATIME 0x40000 +#define TARGET_O_NDELAY TARGET_O_NONBLOCK +#else +#define TARGET_O_ACCMODE 0003 +#define TARGET_O_RDONLY 00 +#define TARGET_O_WRONLY 01 +#define TARGET_O_RDWR 02 +#define TARGET_O_CREAT 0100 /* not fcntl */ +#define TARGET_O_EXCL 0200 /* not fcntl */ +#define TARGET_O_NOCTTY 0400 /* not fcntl */ +#define TARGET_O_TRUNC 01000 /* not fcntl */ +#define TARGET_O_APPEND 02000 +#define TARGET_O_NONBLOCK 04000 +#define TARGET_O_NDELAY TARGET_O_NONBLOCK +#define TARGET_O_SYNC 010000 +#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */ +#define TARGET_O_DIRECT 040000 /* direct disk access hint */ +#define TARGET_O_LARGEFILE 0100000 +#define TARGET_O_DIRECTORY 0200000 /* must be a directory */ +#define TARGET_O_NOFOLLOW 0400000 /* don't follow links */ +#endif + +struct target_flock { + short l_type; + short l_whence; + target_ulong l_start; + target_ulong l_len; + int l_pid; +}; + +struct target_flock64 { + short l_type; + short l_whence; + unsigned long long l_start; + unsigned long long l_len; + int l_pid; +}__attribute__((packed)); + +#ifdef TARGET_ARM +struct target_eabi_flock64 { + short l_type; + short l_whence; + int __pad; + unsigned long long l_start; + unsigned long long l_len; + int l_pid; +}__attribute__((packed)); +#endif + +/* soundcard defines */ +/* XXX: convert them all to arch indepedent entries */ +#define TARGET_SNDCTL_COPR_HALT TARGET_IOWR('C', 7, int); +#define TARGET_SNDCTL_COPR_LOAD 0xcfb04301 +#define TARGET_SNDCTL_COPR_RCODE 0xc0144303 +#define TARGET_SNDCTL_COPR_RCVMSG 0x8fa44309 +#define TARGET_SNDCTL_COPR_RDATA 0xc0144302 +#define TARGET_SNDCTL_COPR_RESET 0x00004300 +#define TARGET_SNDCTL_COPR_RUN 0xc0144306 +#define TARGET_SNDCTL_COPR_SENDMSG 0xcfa44308 +#define TARGET_SNDCTL_COPR_WCODE 0x40144305 +#define TARGET_SNDCTL_COPR_WDATA 0x40144304 +#define TARGET_SNDCTL_DSP_RESET TARGET_IO('P', 0) +#define TARGET_SNDCTL_DSP_SYNC TARGET_IO('P', 1) +#define TARGET_SNDCTL_DSP_SPEED TARGET_IOWR('P', 2, int) +#define TARGET_SNDCTL_DSP_STEREO TARGET_IOWR('P', 3, int) +#define TARGET_SNDCTL_DSP_GETBLKSIZE TARGET_IOWR('P', 4, int) +#define TARGET_SNDCTL_DSP_SETFMT TARGET_IOWR('P', 5, int) +#define TARGET_SNDCTL_DSP_CHANNELS TARGET_IOWR('P', 6, int) +#define TARGET_SOUND_PCM_WRITE_FILTER TARGET_IOWR('P', 7, int) +#define TARGET_SNDCTL_DSP_POST TARGET_IO('P', 8) +#define TARGET_SNDCTL_DSP_SUBDIVIDE TARGET_IOWR('P', 9, int) +#define TARGET_SNDCTL_DSP_SETFRAGMENT TARGET_IOWR('P',10, int) +#define TARGET_SNDCTL_DSP_GETFMTS TARGET_IOR('P', 11, int) +#define TARGET_SNDCTL_DSP_GETOSPACE TARGET_IORU('P',12) +#define TARGET_SNDCTL_DSP_GETISPACE TARGET_IORU('P',13) +#define TARGET_SNDCTL_DSP_GETCAPS TARGET_IOR('P', 15, int) +#define TARGET_SNDCTL_DSP_GETTRIGGER TARGET_IOR('P',16, int) +#define TARGET_SNDCTL_DSP_GETIPTR TARGET_IORU('P',17) +#define TARGET_SNDCTL_DSP_GETOPTR TARGET_IORU('P',18) +#define TARGET_SNDCTL_DSP_MAPINBUF 0x80085013 +#define TARGET_SNDCTL_DSP_MAPOUTBUF 0x80085014 +#define TARGET_SNDCTL_DSP_NONBLOCK 0x0000500e +#define TARGET_SNDCTL_DSP_SAMPLESIZE 0xc0045005 +#define TARGET_SNDCTL_DSP_SETDUPLEX 0x00005016 +#define TARGET_SNDCTL_DSP_SETSYNCRO 0x00005015 +#define TARGET_SNDCTL_DSP_SETTRIGGER 0x40045010 +#define TARGET_SNDCTL_FM_4OP_ENABLE 0x4004510f +#define TARGET_SNDCTL_FM_LOAD_INSTR 0x40285107 +#define TARGET_SNDCTL_MIDI_INFO 0xc074510c +#define TARGET_SNDCTL_MIDI_MPUCMD 0xc0216d02 +#define TARGET_SNDCTL_MIDI_MPUMODE 0xc0046d01 +#define TARGET_SNDCTL_MIDI_PRETIME 0xc0046d00 +#define TARGET_SNDCTL_PMGR_ACCESS 0xcfb85110 +#define TARGET_SNDCTL_PMGR_IFACE 0xcfb85001 +#define TARGET_SNDCTL_SEQ_CTRLRATE 0xc0045103 +#define TARGET_SNDCTL_SEQ_GETINCOUNT 0x80045105 +#define TARGET_SNDCTL_SEQ_GETOUTCOUNT 0x80045104 +#define TARGET_SNDCTL_SEQ_NRMIDIS 0x8004510b +#define TARGET_SNDCTL_SEQ_NRSYNTHS 0x8004510a +#define TARGET_SNDCTL_SEQ_OUTOFBAND 0x40085112 +#define TARGET_SNDCTL_SEQ_PANIC 0x00005111 +#define TARGET_SNDCTL_SEQ_PERCMODE 0x40045106 +#define TARGET_SNDCTL_SEQ_RESET 0x00005100 +#define TARGET_SNDCTL_SEQ_RESETSAMPLES 0x40045109 +#define TARGET_SNDCTL_SEQ_SYNC 0x00005101 +#define TARGET_SNDCTL_SEQ_TESTMIDI 0x40045108 +#define TARGET_SNDCTL_SEQ_THRESHOLD 0x4004510d +#define TARGET_SNDCTL_SEQ_TRESHOLD 0x4004510d +#define TARGET_SNDCTL_SYNTH_INFO 0xc08c5102 +#define TARGET_SNDCTL_SYNTH_MEMAVL 0xc004510e +#define TARGET_SNDCTL_TMR_CONTINUE 0x00005404 +#define TARGET_SNDCTL_TMR_METRONOME 0x40045407 +#define TARGET_SNDCTL_TMR_SELECT 0x40045408 +#define TARGET_SNDCTL_TMR_SOURCE 0xc0045406 +#define TARGET_SNDCTL_TMR_START 0x00005402 +#define TARGET_SNDCTL_TMR_STOP 0x00005403 +#define TARGET_SNDCTL_TMR_TEMPO 0xc0045405 +#define TARGET_SNDCTL_TMR_TIMEBASE 0xc0045401 +#define TARGET_SOUND_PCM_READ_RATE 0x80045002 +#define TARGET_SOUND_PCM_READ_CHANNELS 0x80045006 +#define TARGET_SOUND_PCM_READ_BITS 0x80045005 +#define TARGET_SOUND_PCM_READ_FILTER 0x80045007 +#define TARGET_SOUND_MIXER_INFO TARGET_IOR ('M', 101, mixer_info) +#define TARGET_SOUND_MIXER_ACCESS 0xc0804d66 +#define TARGET_SOUND_MIXER_PRIVATE1 TARGET_IOWR('M', 111, int) +#define TARGET_SOUND_MIXER_PRIVATE2 TARGET_IOWR('M', 112, int) +#define TARGET_SOUND_MIXER_PRIVATE3 TARGET_IOWR('M', 113, int) +#define TARGET_SOUND_MIXER_PRIVATE4 TARGET_IOWR('M', 114, int) +#define TARGET_SOUND_MIXER_PRIVATE5 TARGET_IOWR('M', 115, int) + +#define TARGET_MIXER_READ(dev) TARGET_IOR('M', dev, int) + +#define TARGET_SOUND_MIXER_READ_VOLUME TARGET_MIXER_READ(SOUND_MIXER_VOLUME) +#define TARGET_SOUND_MIXER_READ_BASS TARGET_MIXER_READ(SOUND_MIXER_BASS) +#define TARGET_SOUND_MIXER_READ_TREBLE TARGET_MIXER_READ(SOUND_MIXER_TREBLE) +#define TARGET_SOUND_MIXER_READ_SYNTH TARGET_MIXER_READ(SOUND_MIXER_SYNTH) +#define TARGET_SOUND_MIXER_READ_PCM TARGET_MIXER_READ(SOUND_MIXER_PCM) +#define TARGET_SOUND_MIXER_READ_SPEAKER TARGET_MIXER_READ(SOUND_MIXER_SPEAKER) +#define TARGET_SOUND_MIXER_READ_LINE TARGET_MIXER_READ(SOUND_MIXER_LINE) +#define TARGET_SOUND_MIXER_READ_MIC TARGET_MIXER_READ(SOUND_MIXER_MIC) +#define TARGET_SOUND_MIXER_READ_CD TARGET_MIXER_READ(SOUND_MIXER_CD) +#define TARGET_SOUND_MIXER_READ_IMIX TARGET_MIXER_READ(SOUND_MIXER_IMIX) +#define TARGET_SOUND_MIXER_READ_ALTPCM TARGET_MIXER_READ(SOUND_MIXER_ALTPCM) +#define TARGET_SOUND_MIXER_READ_RECLEV TARGET_MIXER_READ(SOUND_MIXER_RECLEV) +#define TARGET_SOUND_MIXER_READ_IGAIN TARGET_MIXER_READ(SOUND_MIXER_IGAIN) +#define TARGET_SOUND_MIXER_READ_OGAIN TARGET_MIXER_READ(SOUND_MIXER_OGAIN) +#define TARGET_SOUND_MIXER_READ_LINE1 TARGET_MIXER_READ(SOUND_MIXER_LINE1) +#define TARGET_SOUND_MIXER_READ_LINE2 TARGET_MIXER_READ(SOUND_MIXER_LINE2) +#define TARGET_SOUND_MIXER_READ_LINE3 TARGET_MIXER_READ(SOUND_MIXER_LINE3) + +/* Obsolete macros */ +#define TARGET_SOUND_MIXER_READ_MUTE TARGET_MIXER_READ(SOUND_MIXER_MUTE) +#define TARGET_SOUND_MIXER_READ_ENHANCE TARGET_MIXER_READ(SOUND_MIXER_ENHANCE) +#define TARGET_SOUND_MIXER_READ_LOUD TARGET_MIXER_READ(SOUND_MIXER_LOUD) + +#define TARGET_SOUND_MIXER_READ_RECSRC TARGET_MIXER_READ(SOUND_MIXER_RECSRC) +#define TARGET_SOUND_MIXER_READ_DEVMASK TARGET_MIXER_READ(SOUND_MIXER_DEVMASK) +#define TARGET_SOUND_MIXER_READ_RECMASK TARGET_MIXER_READ(SOUND_MIXER_RECMASK) +#define TARGET_SOUND_MIXER_READ_STEREODEVS TARGET_MIXER_READ(SOUND_MIXER_STEREODEVS) +#define TARGET_SOUND_MIXER_READ_CAPS TARGET_MIXER_READ(SOUND_MIXER_CAPS) + +#define TARGET_MIXER_WRITE(dev) TARGET_IOWR('M', dev, int) + +#define TARGET_SOUND_MIXER_WRITE_VOLUME TARGET_MIXER_WRITE(SOUND_MIXER_VOLUME) +#define TARGET_SOUND_MIXER_WRITE_BASS TARGET_MIXER_WRITE(SOUND_MIXER_BASS) +#define TARGET_SOUND_MIXER_WRITE_TREBLE TARGET_MIXER_WRITE(SOUND_MIXER_TREBLE) +#define TARGET_SOUND_MIXER_WRITE_SYNTH TARGET_MIXER_WRITE(SOUND_MIXER_SYNTH) +#define TARGET_SOUND_MIXER_WRITE_PCM TARGET_MIXER_WRITE(SOUND_MIXER_PCM) +#define TARGET_SOUND_MIXER_WRITE_SPEAKER TARGET_MIXER_WRITE(SOUND_MIXER_SPEAKER) +#define TARGET_SOUND_MIXER_WRITE_LINE TARGET_MIXER_WRITE(SOUND_MIXER_LINE) +#define TARGET_SOUND_MIXER_WRITE_MIC TARGET_MIXER_WRITE(SOUND_MIXER_MIC) +#define TARGET_SOUND_MIXER_WRITE_CD TARGET_MIXER_WRITE(SOUND_MIXER_CD) +#define TARGET_SOUND_MIXER_WRITE_IMIX TARGET_MIXER_WRITE(SOUND_MIXER_IMIX) +#define TARGET_SOUND_MIXER_WRITE_ALTPCM TARGET_MIXER_WRITE(SOUND_MIXER_ALTPCM) +#define TARGET_SOUND_MIXER_WRITE_RECLEV TARGET_MIXER_WRITE(SOUND_MIXER_RECLEV) +#define TARGET_SOUND_MIXER_WRITE_IGAIN TARGET_MIXER_WRITE(SOUND_MIXER_IGAIN) +#define TARGET_SOUND_MIXER_WRITE_OGAIN TARGET_MIXER_WRITE(SOUND_MIXER_OGAIN) +#define TARGET_SOUND_MIXER_WRITE_LINE1 TARGET_MIXER_WRITE(SOUND_MIXER_LINE1) +#define TARGET_SOUND_MIXER_WRITE_LINE2 TARGET_MIXER_WRITE(SOUND_MIXER_LINE2) +#define TARGET_SOUND_MIXER_WRITE_LINE3 TARGET_MIXER_WRITE(SOUND_MIXER_LINE3) + +/* Obsolete macros */ +#define TARGET_SOUND_MIXER_WRITE_MUTE TARGET_MIXER_WRITE(SOUND_MIXER_MUTE) +#define TARGET_SOUND_MIXER_WRITE_ENHANCE TARGET_MIXER_WRITE(SOUND_MIXER_ENHANCE) +#define TARGET_SOUND_MIXER_WRITE_LOUD TARGET_MIXER_WRITE(SOUND_MIXER_LOUD) + +#define TARGET_SOUND_MIXER_WRITE_RECSRC TARGET_MIXER_WRITE(SOUND_MIXER_RECSRC) + +/* vfat ioctls */ +#define TARGET_VFAT_IOCTL_READDIR_BOTH TARGET_IORU('r', 1) +#define TARGET_VFAT_IOCTL_READDIR_SHORT TARGET_IORU('r', 2) + +struct target_sysinfo { + target_long uptime; /* Seconds since boot */ + target_ulong loads[3]; /* 1, 5, and 15 minute load averages */ + target_ulong totalram; /* Total usable main memory size */ + target_ulong freeram; /* Available memory size */ + target_ulong sharedram; /* Amount of shared memory */ + target_ulong bufferram; /* Memory used by buffers */ + target_ulong totalswap; /* Total swap space size */ + target_ulong freeswap; /* swap space still available */ + unsigned short procs; /* Number of current processes */ + unsigned short pad; /* explicit padding for m68k */ + target_ulong totalhigh; /* Total high memory size */ + target_ulong freehigh; /* Available high memory size */ + unsigned int mem_unit; /* Memory unit size in bytes */ + char _f[20-2*sizeof(target_long)-sizeof(int)]; /* Padding: libc5 uses this.. */ +}; + +#include "socket.h" diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h new file mode 100644 index 0000000..308da48 --- /dev/null +++ b/linux-user/syscall_types.h @@ -0,0 +1,81 @@ +STRUCT_SPECIAL(termios) + +STRUCT(winsize, + TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT) + +STRUCT(serial_multiport_struct, + TYPE_INT, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR, + TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, + MK_ARRAY(TYPE_INT, 32)) + +STRUCT(serial_icounter_struct, + TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_INT, 16)) + +STRUCT(sockaddr, + TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 14)) + +STRUCT(rtentry, + TYPE_ULONG, MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), + TYPE_SHORT, TYPE_SHORT, TYPE_ULONG, TYPE_PTRVOID, TYPE_SHORT, TYPE_PTRVOID, + TYPE_ULONG, TYPE_ULONG, TYPE_SHORT) + +STRUCT(ifmap, + TYPE_ULONG, TYPE_ULONG, TYPE_SHORT, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, + /* Spare 3 bytes */ + TYPE_CHAR, TYPE_CHAR, TYPE_CHAR) + +/* The *_ifreq_list arrays deal with the fact that struct ifreq has unions */ + +STRUCT(sockaddr_ifreq, + MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT_sockaddr)) + +STRUCT(short_ifreq, + MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_SHORT) + +STRUCT(int_ifreq, + MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT) + +STRUCT(ifmap_ifreq, + MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT_ifmap)) + +STRUCT(char_ifreq, + MK_ARRAY(TYPE_CHAR, IFNAMSIZ), + MK_ARRAY(TYPE_CHAR, IFNAMSIZ)) + +STRUCT(ptr_ifreq, + MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_PTRVOID) + +STRUCT(ifconf, + TYPE_INT, TYPE_PTRVOID) + +STRUCT(arpreq, + MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), TYPE_INT, MK_STRUCT(STRUCT_sockaddr), + MK_ARRAY(TYPE_CHAR, 16)) + +STRUCT(arpreq_old, + MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), TYPE_INT, MK_STRUCT(STRUCT_sockaddr)) + +STRUCT(cdrom_read_audio, + TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_PTRVOID, + TYPE_NULL) + +STRUCT(hd_geometry, + TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG) + +STRUCT(dirent, + TYPE_LONG, TYPE_LONG, TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 256)) + +STRUCT(kbentry, + TYPE_CHAR, TYPE_CHAR, TYPE_SHORT) + +STRUCT(kbsentry, + TYPE_CHAR, MK_ARRAY(TYPE_CHAR, 512)) + +STRUCT(audio_buf_info, + TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT) + +STRUCT(count_info, + TYPE_INT, TYPE_INT, TYPE_INT) + +STRUCT(mixer_info, + MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10)) diff --git a/linux-user/vm86.c b/linux-user/vm86.c new file mode 100644 index 0000000..b28eea6 --- /dev/null +++ b/linux-user/vm86.c @@ -0,0 +1,482 @@ +/* + * vm86 linux syscall support + * + * Copyright (c) 2003 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> + +#include "qemu.h" + +//#define DEBUG_VM86 + +#define set_flags(X,new,mask) \ +((X) = ((X) & ~(mask)) | ((new) & (mask))) + +#define SAFE_MASK (0xDD5) +#define RETURN_MASK (0xDFF) + +static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) +{ + return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1; +} + +static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val) +{ + stw(segptr + (reg16 & 0xffff), val); +} + +static inline void vm_putl(uint8_t *segptr, unsigned int reg16, unsigned int val) +{ + stl(segptr + (reg16 & 0xffff), val); +} + +static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16) +{ + return lduw(segptr + (reg16 & 0xffff)); +} + +static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16) +{ + return ldl(segptr + (reg16 & 0xffff)); +} + +void save_v86_state(CPUX86State *env) +{ + TaskState *ts = env->opaque; + struct target_vm86plus_struct * target_v86; + + lock_user_struct(target_v86, ts->target_v86, 0); + /* put the VM86 registers in the userspace register structure */ + target_v86->regs.eax = tswap32(env->regs[R_EAX]); + target_v86->regs.ebx = tswap32(env->regs[R_EBX]); + target_v86->regs.ecx = tswap32(env->regs[R_ECX]); + target_v86->regs.edx = tswap32(env->regs[R_EDX]); + target_v86->regs.esi = tswap32(env->regs[R_ESI]); + target_v86->regs.edi = tswap32(env->regs[R_EDI]); + target_v86->regs.ebp = tswap32(env->regs[R_EBP]); + target_v86->regs.esp = tswap32(env->regs[R_ESP]); + target_v86->regs.eip = tswap32(env->eip); + target_v86->regs.cs = tswap16(env->segs[R_CS].selector); + target_v86->regs.ss = tswap16(env->segs[R_SS].selector); + target_v86->regs.ds = tswap16(env->segs[R_DS].selector); + target_v86->regs.es = tswap16(env->segs[R_ES].selector); + target_v86->regs.fs = tswap16(env->segs[R_FS].selector); + target_v86->regs.gs = tswap16(env->segs[R_GS].selector); + set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask); + target_v86->regs.eflags = tswap32(env->eflags); + unlock_user_struct(target_v86, ts->target_v86, 1); +#ifdef DEBUG_VM86 + fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n", + env->eflags, env->segs[R_CS].selector, env->eip); +#endif + + /* restore 32 bit registers */ + env->regs[R_EAX] = ts->vm86_saved_regs.eax; + env->regs[R_EBX] = ts->vm86_saved_regs.ebx; + env->regs[R_ECX] = ts->vm86_saved_regs.ecx; + env->regs[R_EDX] = ts->vm86_saved_regs.edx; + env->regs[R_ESI] = ts->vm86_saved_regs.esi; + env->regs[R_EDI] = ts->vm86_saved_regs.edi; + env->regs[R_EBP] = ts->vm86_saved_regs.ebp; + env->regs[R_ESP] = ts->vm86_saved_regs.esp; + env->eflags = ts->vm86_saved_regs.eflags; + env->eip = ts->vm86_saved_regs.eip; + + cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs); + cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss); + cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds); + cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es); + cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs); + cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs); +} + +/* return from vm86 mode to 32 bit. The vm86() syscall will return + 'retval' */ +static inline void return_to_32bit(CPUX86State *env, int retval) +{ +#ifdef DEBUG_VM86 + fprintf(logfile, "return_to_32bit: ret=0x%x\n", retval); +#endif + save_v86_state(env); + env->regs[R_EAX] = retval; +} + +static inline int set_IF(CPUX86State *env) +{ + TaskState *ts = env->opaque; + + ts->v86flags |= VIF_MASK; + if (ts->v86flags & VIP_MASK) { + return_to_32bit(env, TARGET_VM86_STI); + return 1; + } + return 0; +} + +static inline void clear_IF(CPUX86State *env) +{ + TaskState *ts = env->opaque; + + ts->v86flags &= ~VIF_MASK; +} + +static inline void clear_TF(CPUX86State *env) +{ + env->eflags &= ~TF_MASK; +} + +static inline void clear_AC(CPUX86State *env) +{ + env->eflags &= ~AC_MASK; +} + +static inline int set_vflags_long(unsigned long eflags, CPUX86State *env) +{ + TaskState *ts = env->opaque; + + set_flags(ts->v86flags, eflags, ts->v86mask); + set_flags(env->eflags, eflags, SAFE_MASK); + if (eflags & IF_MASK) + return set_IF(env); + else + clear_IF(env); + return 0; +} + +static inline int set_vflags_short(unsigned short flags, CPUX86State *env) +{ + TaskState *ts = env->opaque; + + set_flags(ts->v86flags, flags, ts->v86mask & 0xffff); + set_flags(env->eflags, flags, SAFE_MASK); + if (flags & IF_MASK) + return set_IF(env); + else + clear_IF(env); + return 0; +} + +static inline unsigned int get_vflags(CPUX86State *env) +{ + TaskState *ts = env->opaque; + unsigned int flags; + + flags = env->eflags & RETURN_MASK; + if (ts->v86flags & VIF_MASK) + flags |= IF_MASK; + flags |= IOPL_MASK; + return flags | (ts->v86flags & ts->v86mask); +} + +#define ADD16(reg, val) reg = (reg & ~0xffff) | ((reg + (val)) & 0xffff) + +/* handle VM86 interrupt (NOTE: the CPU core currently does not + support TSS interrupt revectoring, so this code is always executed) */ +static void do_int(CPUX86State *env, int intno) +{ + TaskState *ts = env->opaque; + uint32_t *int_ptr, segoffs; + uint8_t *ssp; + unsigned int sp; + + if (env->segs[R_CS].selector == TARGET_BIOSSEG) + goto cannot_handle; + if (is_revectored(intno, &ts->vm86plus.int_revectored)) + goto cannot_handle; + if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, + &ts->vm86plus.int21_revectored)) + goto cannot_handle; + int_ptr = (uint32_t *)(intno << 2); + segoffs = tswap32(*int_ptr); + if ((segoffs >> 16) == TARGET_BIOSSEG) + goto cannot_handle; +#if defined(DEBUG_VM86) + fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", + intno, segoffs >> 16, segoffs & 0xffff); +#endif + /* save old state */ + ssp = (uint8_t *)(env->segs[R_SS].selector << 4); + sp = env->regs[R_ESP] & 0xffff; + vm_putw(ssp, sp - 2, get_vflags(env)); + vm_putw(ssp, sp - 4, env->segs[R_CS].selector); + vm_putw(ssp, sp - 6, env->eip); + ADD16(env->regs[R_ESP], -6); + /* goto interrupt handler */ + env->eip = segoffs & 0xffff; + cpu_x86_load_seg(env, R_CS, segoffs >> 16); + clear_TF(env); + clear_IF(env); + clear_AC(env); + return; + cannot_handle: +#if defined(DEBUG_VM86) + fprintf(logfile, "VM86: return to 32 bits int 0x%x\n", intno); +#endif + return_to_32bit(env, TARGET_VM86_INTx | (intno << 8)); +} + +void handle_vm86_trap(CPUX86State *env, int trapno) +{ + if (trapno == 1 || trapno == 3) { + return_to_32bit(env, TARGET_VM86_TRAP + (trapno << 8)); + } else { + do_int(env, trapno); + } +} + +#define CHECK_IF_IN_TRAP() \ + if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \ + (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \ + newflags |= TF_MASK + +#define VM86_FAULT_RETURN \ + if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \ + (ts->v86flags & (IF_MASK | VIF_MASK))) \ + return_to_32bit(env, TARGET_VM86_PICRETURN); \ + return + +void handle_vm86_fault(CPUX86State *env) +{ + TaskState *ts = env->opaque; + uint8_t *csp, *pc, *ssp; + unsigned int ip, sp, newflags, newip, newcs, opcode, intno; + int data32, pref_done; + + csp = (uint8_t *)(env->segs[R_CS].selector << 4); + ip = env->eip & 0xffff; + pc = csp + ip; + + ssp = (uint8_t *)(env->segs[R_SS].selector << 4); + sp = env->regs[R_ESP] & 0xffff; + +#if defined(DEBUG_VM86) + fprintf(logfile, "VM86 exception %04x:%08x %02x %02x\n", + env->segs[R_CS].selector, env->eip, pc[0], pc[1]); +#endif + + data32 = 0; + pref_done = 0; + do { + opcode = csp[ip]; + ADD16(ip, 1); + switch (opcode) { + case 0x66: /* 32-bit data */ data32=1; break; + case 0x67: /* 32-bit address */ break; + case 0x2e: /* CS */ break; + case 0x3e: /* DS */ break; + case 0x26: /* ES */ break; + case 0x36: /* SS */ break; + case 0x65: /* GS */ break; + case 0x64: /* FS */ break; + case 0xf2: /* repnz */ break; + case 0xf3: /* rep */ break; + default: pref_done = 1; + } + } while (!pref_done); + + /* VM86 mode */ + switch(opcode) { + case 0x9c: /* pushf */ + if (data32) { + vm_putl(ssp, sp - 4, get_vflags(env)); + ADD16(env->regs[R_ESP], -4); + } else { + vm_putw(ssp, sp - 2, get_vflags(env)); + ADD16(env->regs[R_ESP], -2); + } + env->eip = ip; + VM86_FAULT_RETURN; + + case 0x9d: /* popf */ + if (data32) { + newflags = vm_getl(ssp, sp); + ADD16(env->regs[R_ESP], 4); + } else { + newflags = vm_getw(ssp, sp); + ADD16(env->regs[R_ESP], 2); + } + env->eip = ip; + CHECK_IF_IN_TRAP(); + if (data32) { + if (set_vflags_long(newflags, env)) + return; + } else { + if (set_vflags_short(newflags, env)) + return; + } + VM86_FAULT_RETURN; + + case 0xcd: /* int */ + intno = csp[ip]; + ADD16(ip, 1); + env->eip = ip; + if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) { + if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >> + (intno &7)) & 1) { + return_to_32bit(env, TARGET_VM86_INTx + (intno << 8)); + return; + } + } + do_int(env, intno); + break; + + case 0xcf: /* iret */ + if (data32) { + newip = vm_getl(ssp, sp) & 0xffff; + newcs = vm_getl(ssp, sp + 4) & 0xffff; + newflags = vm_getl(ssp, sp + 8); + ADD16(env->regs[R_ESP], 12); + } else { + newip = vm_getw(ssp, sp); + newcs = vm_getw(ssp, sp + 2); + newflags = vm_getw(ssp, sp + 4); + ADD16(env->regs[R_ESP], 6); + } + env->eip = newip; + cpu_x86_load_seg(env, R_CS, newcs); + CHECK_IF_IN_TRAP(); + if (data32) { + if (set_vflags_long(newflags, env)) + return; + } else { + if (set_vflags_short(newflags, env)) + return; + } + VM86_FAULT_RETURN; + + case 0xfa: /* cli */ + env->eip = ip; + clear_IF(env); + VM86_FAULT_RETURN; + + case 0xfb: /* sti */ + env->eip = ip; + if (set_IF(env)) + return; + VM86_FAULT_RETURN; + + default: + /* real VM86 GPF exception */ + return_to_32bit(env, TARGET_VM86_UNKNOWN); + break; + } +} + +int do_vm86(CPUX86State *env, long subfunction, target_ulong vm86_addr) +{ + TaskState *ts = env->opaque; + struct target_vm86plus_struct * target_v86; + int ret; + + switch (subfunction) { + case TARGET_VM86_REQUEST_IRQ: + case TARGET_VM86_FREE_IRQ: + case TARGET_VM86_GET_IRQ_BITS: + case TARGET_VM86_GET_AND_RESET_IRQ: + gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction); + ret = -EINVAL; + goto out; + case TARGET_VM86_PLUS_INSTALL_CHECK: + /* NOTE: on old vm86 stuff this will return the error + from verify_area(), because the subfunction is + interpreted as (invalid) address to vm86_struct. + So the installation check works. + */ + ret = 0; + goto out; + } + + /* save current CPU regs */ + ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */ + ts->vm86_saved_regs.ebx = env->regs[R_EBX]; + ts->vm86_saved_regs.ecx = env->regs[R_ECX]; + ts->vm86_saved_regs.edx = env->regs[R_EDX]; + ts->vm86_saved_regs.esi = env->regs[R_ESI]; + ts->vm86_saved_regs.edi = env->regs[R_EDI]; + ts->vm86_saved_regs.ebp = env->regs[R_EBP]; + ts->vm86_saved_regs.esp = env->regs[R_ESP]; + ts->vm86_saved_regs.eflags = env->eflags; + ts->vm86_saved_regs.eip = env->eip; + ts->vm86_saved_regs.cs = env->segs[R_CS].selector; + ts->vm86_saved_regs.ss = env->segs[R_SS].selector; + ts->vm86_saved_regs.ds = env->segs[R_DS].selector; + ts->vm86_saved_regs.es = env->segs[R_ES].selector; + ts->vm86_saved_regs.fs = env->segs[R_FS].selector; + ts->vm86_saved_regs.gs = env->segs[R_GS].selector; + + ts->target_v86 = vm86_addr; + lock_user_struct(target_v86, vm86_addr, 1); + /* build vm86 CPU state */ + ts->v86flags = tswap32(target_v86->regs.eflags); + env->eflags = (env->eflags & ~SAFE_MASK) | + (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK; + + ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type); + switch (ts->vm86plus.cpu_type) { + case TARGET_CPU_286: + ts->v86mask = 0; + break; + case TARGET_CPU_386: + ts->v86mask = NT_MASK | IOPL_MASK; + break; + case TARGET_CPU_486: + ts->v86mask = AC_MASK | NT_MASK | IOPL_MASK; + break; + default: + ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK; + break; + } + + env->regs[R_EBX] = tswap32(target_v86->regs.ebx); + env->regs[R_ECX] = tswap32(target_v86->regs.ecx); + env->regs[R_EDX] = tswap32(target_v86->regs.edx); + env->regs[R_ESI] = tswap32(target_v86->regs.esi); + env->regs[R_EDI] = tswap32(target_v86->regs.edi); + env->regs[R_EBP] = tswap32(target_v86->regs.ebp); + env->regs[R_ESP] = tswap32(target_v86->regs.esp); + env->eip = tswap32(target_v86->regs.eip); + cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs)); + cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss)); + cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds)); + cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es)); + cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs)); + cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs)); + ret = tswap32(target_v86->regs.eax); /* eax will be restored at + the end of the syscall */ + memcpy(&ts->vm86plus.int_revectored, + &target_v86->int_revectored, 32); + memcpy(&ts->vm86plus.int21_revectored, + &target_v86->int21_revectored, 32); + ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags); + memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab, + target_v86->vm86plus.vm86dbg_intxxtab, 32); + unlock_user_struct(target_v86, vm86_addr, 0); + +#ifdef DEBUG_VM86 + fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", + env->segs[R_CS].selector, env->eip); +#endif + /* now the virtual CPU is ready for vm86 execution ! */ + out: + return ret; +} + |