Commit 5cd4393b14b68a4e80a3ffa74c04efff2b9590a5
1 parent
7ed601b7
first vm86 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@60 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
162 additions
and
33 deletions
linux-user/syscall.c
| ... | ... | @@ -103,10 +103,10 @@ extern int personality(int); |
| 103 | 103 | extern int flock(int, int); |
| 104 | 104 | extern int setfsuid(int); |
| 105 | 105 | extern int setfsgid(int); |
| 106 | -extern int setresuid(int,int,int); | |
| 107 | -extern int getresuid(int *,int *,int *); | |
| 108 | -extern int setresgid(int,int,int); | |
| 109 | -extern int getresgid(int *,int *,int *); | |
| 106 | +extern int setresuid(uid_t, uid_t, uid_t); | |
| 107 | +extern int getresuid(uid_t *, uid_t *, uid_t *); | |
| 108 | +extern int setresgid(gid_t, gid_t, gid_t); | |
| 109 | +extern int getresgid(gid_t *, gid_t *, gid_t *); | |
| 110 | 110 | |
| 111 | 111 | static inline long get_errno(long ret) |
| 112 | 112 | { |
| ... | ... | @@ -210,14 +210,14 @@ static inline void host_to_target_fds(target_long *target_fds, |
| 210 | 210 | } |
| 211 | 211 | |
| 212 | 212 | static inline void target_to_host_timeval(struct timeval *tv, |
| 213 | - struct target_timeval *target_tv) | |
| 213 | + const struct target_timeval *target_tv) | |
| 214 | 214 | { |
| 215 | 215 | tv->tv_sec = tswapl(target_tv->tv_sec); |
| 216 | 216 | tv->tv_usec = tswapl(target_tv->tv_usec); |
| 217 | 217 | } |
| 218 | 218 | |
| 219 | 219 | static inline void host_to_target_timeval(struct target_timeval *target_tv, |
| 220 | - struct timeval *tv) | |
| 220 | + const struct timeval *tv) | |
| 221 | 221 | { |
| 222 | 222 | target_tv->tv_sec = tswapl(tv->tv_sec); |
| 223 | 223 | target_tv->tv_usec = tswapl(tv->tv_usec); |
| ... | ... | @@ -238,8 +238,7 @@ static long do_select(long n, |
| 238 | 238 | efds_ptr = target_to_host_fds(&efds, target_efds, n); |
| 239 | 239 | |
| 240 | 240 | if (target_tv) { |
| 241 | - tv.tv_sec = tswapl(target_tv->tv_sec); | |
| 242 | - tv.tv_usec = tswapl(target_tv->tv_usec); | |
| 241 | + target_to_host_timeval(&tv, target_tv); | |
| 243 | 242 | tv_ptr = &tv; |
| 244 | 243 | } else { |
| 245 | 244 | tv_ptr = NULL; |
| ... | ... | @@ -251,8 +250,7 @@ static long do_select(long n, |
| 251 | 250 | host_to_target_fds(target_efds, efds_ptr, n); |
| 252 | 251 | |
| 253 | 252 | if (target_tv) { |
| 254 | - target_tv->tv_sec = tswapl(tv.tv_sec); | |
| 255 | - target_tv->tv_usec = tswapl(tv.tv_usec); | |
| 253 | + host_to_target_timeval(target_tv, &tv); | |
| 256 | 254 | } |
| 257 | 255 | } |
| 258 | 256 | return ret; |
| ... | ... | @@ -755,7 +753,7 @@ install: |
| 755 | 753 | } |
| 756 | 754 | |
| 757 | 755 | /* specific and weird i386 syscalls */ |
| 758 | -int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount) | |
| 756 | +int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount) | |
| 759 | 757 | { |
| 760 | 758 | int ret = -ENOSYS; |
| 761 | 759 | |
| ... | ... | @@ -773,6 +771,79 @@ int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecou |
| 773 | 771 | return ret; |
| 774 | 772 | } |
| 775 | 773 | |
| 774 | +/* vm86 emulation */ | |
| 775 | + | |
| 776 | +#define SAFE_MASK (0xDD5) | |
| 777 | + | |
| 778 | +int do_vm86(CPUX86State *env, long subfunction, | |
| 779 | + struct target_vm86plus_struct * target_v86) | |
| 780 | +{ | |
| 781 | + TaskState *ts = env->opaque; | |
| 782 | + int ret; | |
| 783 | + | |
| 784 | + switch (subfunction) { | |
| 785 | + case TARGET_VM86_REQUEST_IRQ: | |
| 786 | + case TARGET_VM86_FREE_IRQ: | |
| 787 | + case TARGET_VM86_GET_IRQ_BITS: | |
| 788 | + case TARGET_VM86_GET_AND_RESET_IRQ: | |
| 789 | + gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction); | |
| 790 | + ret = -EINVAL; | |
| 791 | + goto out; | |
| 792 | + case TARGET_VM86_PLUS_INSTALL_CHECK: | |
| 793 | + /* NOTE: on old vm86 stuff this will return the error | |
| 794 | + from verify_area(), because the subfunction is | |
| 795 | + interpreted as (invalid) address to vm86_struct. | |
| 796 | + So the installation check works. | |
| 797 | + */ | |
| 798 | + ret = 0; | |
| 799 | + goto out; | |
| 800 | + } | |
| 801 | + | |
| 802 | + ts->target_v86 = target_v86; | |
| 803 | + | |
| 804 | + /* save current CPU regs */ | |
| 805 | + ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */ | |
| 806 | + ts->vm86_saved_regs.ebx = env->regs[R_EBX]; | |
| 807 | + ts->vm86_saved_regs.ecx = env->regs[R_ECX]; | |
| 808 | + ts->vm86_saved_regs.edx = env->regs[R_EDX]; | |
| 809 | + ts->vm86_saved_regs.esi = env->regs[R_ESI]; | |
| 810 | + ts->vm86_saved_regs.edi = env->regs[R_EDI]; | |
| 811 | + ts->vm86_saved_regs.ebp = env->regs[R_EBP]; | |
| 812 | + ts->vm86_saved_regs.esp = env->regs[R_ESP]; | |
| 813 | + ts->vm86_saved_regs.eflags = env->eflags; | |
| 814 | + ts->vm86_saved_regs.eip = env->eip; | |
| 815 | + ts->vm86_saved_regs.cs = env->segs[R_CS]; | |
| 816 | + ts->vm86_saved_regs.ss = env->segs[R_SS]; | |
| 817 | + ts->vm86_saved_regs.ds = env->segs[R_DS]; | |
| 818 | + ts->vm86_saved_regs.es = env->segs[R_ES]; | |
| 819 | + ts->vm86_saved_regs.fs = env->segs[R_FS]; | |
| 820 | + ts->vm86_saved_regs.gs = env->segs[R_GS]; | |
| 821 | + | |
| 822 | + /* build vm86 CPU state */ | |
| 823 | + env->eflags = (env->eflags & ~SAFE_MASK) | | |
| 824 | + (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK; | |
| 825 | + | |
| 826 | + env->regs[R_EBX] = tswap32(target_v86->regs.ebx); | |
| 827 | + env->regs[R_ECX] = tswap32(target_v86->regs.ecx); | |
| 828 | + env->regs[R_EDX] = tswap32(target_v86->regs.edx); | |
| 829 | + env->regs[R_ESI] = tswap32(target_v86->regs.esi); | |
| 830 | + env->regs[R_EDI] = tswap32(target_v86->regs.edi); | |
| 831 | + env->regs[R_EBP] = tswap32(target_v86->regs.ebp); | |
| 832 | + env->regs[R_ESP] = tswap32(target_v86->regs.esp); | |
| 833 | + env->eip = tswap32(target_v86->regs.eip); | |
| 834 | + cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs)); | |
| 835 | + cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss)); | |
| 836 | + cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds)); | |
| 837 | + cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es)); | |
| 838 | + cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs)); | |
| 839 | + cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs)); | |
| 840 | + ret = tswap32(target_v86->regs.eax); /* eax will be restored at | |
| 841 | + the end of the syscall */ | |
| 842 | + /* now the virtual CPU is ready for vm86 execution ! */ | |
| 843 | + out: | |
| 844 | + return ret; | |
| 845 | +} | |
| 846 | + | |
| 776 | 847 | /* this stack is the equivalent of the kernel stack associated with a |
| 777 | 848 | thread/process */ |
| 778 | 849 | #define NEW_STACK_SIZE 8192 |
| ... | ... | @@ -788,19 +859,26 @@ static int clone_func(void *arg) |
| 788 | 859 | int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp) |
| 789 | 860 | { |
| 790 | 861 | int ret; |
| 862 | + TaskState *ts; | |
| 791 | 863 | uint8_t *new_stack; |
| 792 | 864 | CPUX86State *new_env; |
| 793 | 865 | |
| 794 | 866 | if (flags & CLONE_VM) { |
| 795 | 867 | if (!newsp) |
| 796 | 868 | newsp = env->regs[R_ESP]; |
| 797 | - new_stack = malloc(NEW_STACK_SIZE); | |
| 798 | - | |
| 869 | + ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE); | |
| 870 | + memset(ts, 0, sizeof(TaskState)); | |
| 871 | + new_stack = ts->stack; | |
| 872 | + ts->used = 1; | |
| 873 | + /* add in task state list */ | |
| 874 | + ts->next = first_task_state; | |
| 875 | + first_task_state = ts; | |
| 799 | 876 | /* we create a new CPU instance. */ |
| 800 | 877 | new_env = cpu_x86_init(); |
| 801 | 878 | memcpy(new_env, env, sizeof(CPUX86State)); |
| 802 | 879 | new_env->regs[R_ESP] = newsp; |
| 803 | 880 | new_env->regs[R_EAX] = 0; |
| 881 | + new_env->opaque = ts; | |
| 804 | 882 | ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env); |
| 805 | 883 | } else { |
| 806 | 884 | /* if no CLONE_VM, we consider it is a fork */ |
| ... | ... | @@ -1281,8 +1359,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1281 | 1359 | struct timeval tv; |
| 1282 | 1360 | ret = get_errno(gettimeofday(&tv, NULL)); |
| 1283 | 1361 | if (!is_error(ret)) { |
| 1284 | - target_tv->tv_sec = tswapl(tv.tv_sec); | |
| 1285 | - target_tv->tv_usec = tswapl(tv.tv_usec); | |
| 1362 | + host_to_target_timeval(target_tv, &tv); | |
| 1286 | 1363 | } |
| 1287 | 1364 | } |
| 1288 | 1365 | break; |
| ... | ... | @@ -1290,8 +1367,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1290 | 1367 | { |
| 1291 | 1368 | struct target_timeval *target_tv = (void *)arg1; |
| 1292 | 1369 | struct timeval tv; |
| 1293 | - tv.tv_sec = tswapl(target_tv->tv_sec); | |
| 1294 | - tv.tv_usec = tswapl(target_tv->tv_usec); | |
| 1370 | + target_to_host_timeval(&tv, target_tv); | |
| 1295 | 1371 | ret = get_errno(settimeofday(&tv, NULL)); |
| 1296 | 1372 | } |
| 1297 | 1373 | break; |
| ... | ... | @@ -1487,8 +1563,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1487 | 1563 | break; |
| 1488 | 1564 | case TARGET_NR_idle: |
| 1489 | 1565 | goto unimplemented; |
| 1490 | - case TARGET_NR_vm86old: | |
| 1491 | - goto unimplemented; | |
| 1492 | 1566 | case TARGET_NR_wait4: |
| 1493 | 1567 | { |
| 1494 | 1568 | int status; |
| ... | ... | @@ -1548,7 +1622,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1548 | 1622 | break; |
| 1549 | 1623 | #ifdef TARGET_I386 |
| 1550 | 1624 | case TARGET_NR_modify_ldt: |
| 1551 | - ret = get_errno(gemu_modify_ldt(cpu_env, arg1, (void *)arg2, arg3)); | |
| 1625 | + ret = get_errno(do_modify_ldt(cpu_env, arg1, (void *)arg2, arg3)); | |
| 1626 | + break; | |
| 1627 | + case TARGET_NR_vm86old: | |
| 1628 | + goto unimplemented; | |
| 1629 | + case TARGET_NR_vm86: | |
| 1630 | + ret = do_vm86(cpu_env, arg1, (void *)arg2); | |
| 1552 | 1631 | break; |
| 1553 | 1632 | #endif |
| 1554 | 1633 | case TARGET_NR_adjtimex: |
| ... | ... | @@ -1652,13 +1731,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1652 | 1731 | |
| 1653 | 1732 | pfd = alloca(sizeof(struct pollfd) * nfds); |
| 1654 | 1733 | for(i = 0; i < nfds; i++) { |
| 1655 | - pfd->fd = tswap32(target_pfd->fd); | |
| 1656 | - pfd->events = tswap16(target_pfd->events); | |
| 1734 | + pfd[i].fd = tswap32(target_pfd[i].fd); | |
| 1735 | + pfd[i].events = tswap16(target_pfd[i].events); | |
| 1657 | 1736 | } |
| 1658 | 1737 | ret = get_errno(poll(pfd, nfds, timeout)); |
| 1659 | 1738 | if (!is_error(ret)) { |
| 1660 | 1739 | for(i = 0; i < nfds; i++) { |
| 1661 | - target_pfd->revents = tswap16(pfd->revents); | |
| 1740 | + target_pfd[i].revents = tswap16(pfd[i].revents); | |
| 1662 | 1741 | } |
| 1663 | 1742 | } |
| 1664 | 1743 | } |
| ... | ... | @@ -1702,25 +1781,59 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1702 | 1781 | ret = get_errno(getsid(arg1)); |
| 1703 | 1782 | break; |
| 1704 | 1783 | case TARGET_NR_fdatasync: |
| 1705 | - goto unimplemented; | |
| 1784 | + ret = get_errno(fdatasync(arg1)); | |
| 1785 | + break; | |
| 1706 | 1786 | case TARGET_NR__sysctl: |
| 1707 | 1787 | goto unimplemented; |
| 1708 | 1788 | case TARGET_NR_sched_setparam: |
| 1709 | - goto unimplemented; | |
| 1789 | + { | |
| 1790 | + struct sched_param *target_schp = (void *)arg2; | |
| 1791 | + struct sched_param schp; | |
| 1792 | + schp.sched_priority = tswap32(target_schp->sched_priority); | |
| 1793 | + ret = get_errno(sched_setparam(arg1, &schp)); | |
| 1794 | + } | |
| 1795 | + break; | |
| 1710 | 1796 | case TARGET_NR_sched_getparam: |
| 1711 | - goto unimplemented; | |
| 1797 | + { | |
| 1798 | + struct sched_param *target_schp = (void *)arg2; | |
| 1799 | + struct sched_param schp; | |
| 1800 | + ret = get_errno(sched_getparam(arg1, &schp)); | |
| 1801 | + if (!is_error(ret)) { | |
| 1802 | + target_schp->sched_priority = tswap32(schp.sched_priority); | |
| 1803 | + } | |
| 1804 | + } | |
| 1805 | + break; | |
| 1712 | 1806 | case TARGET_NR_sched_setscheduler: |
| 1713 | - goto unimplemented; | |
| 1807 | + { | |
| 1808 | + struct sched_param *target_schp = (void *)arg3; | |
| 1809 | + struct sched_param schp; | |
| 1810 | + schp.sched_priority = tswap32(target_schp->sched_priority); | |
| 1811 | + ret = get_errno(sched_setscheduler(arg1, arg2, &schp)); | |
| 1812 | + } | |
| 1813 | + break; | |
| 1714 | 1814 | case TARGET_NR_sched_getscheduler: |
| 1715 | - goto unimplemented; | |
| 1815 | + ret = get_errno(sched_getscheduler(arg1)); | |
| 1816 | + break; | |
| 1716 | 1817 | case TARGET_NR_sched_yield: |
| 1717 | 1818 | ret = get_errno(sched_yield()); |
| 1718 | 1819 | break; |
| 1719 | 1820 | case TARGET_NR_sched_get_priority_max: |
| 1821 | + ret = get_errno(sched_get_priority_max(arg1)); | |
| 1822 | + break; | |
| 1720 | 1823 | case TARGET_NR_sched_get_priority_min: |
| 1824 | + ret = get_errno(sched_get_priority_min(arg1)); | |
| 1825 | + break; | |
| 1721 | 1826 | case TARGET_NR_sched_rr_get_interval: |
| 1722 | - goto unimplemented; | |
| 1723 | - | |
| 1827 | + { | |
| 1828 | + struct target_timespec *target_ts = (void *)arg2; | |
| 1829 | + struct timespec ts; | |
| 1830 | + ret = get_errno(sched_rr_get_interval(arg1, &ts)); | |
| 1831 | + if (!is_error(ret)) { | |
| 1832 | + target_ts->tv_sec = tswapl(ts.tv_sec); | |
| 1833 | + target_ts->tv_nsec = tswapl(ts.tv_nsec); | |
| 1834 | + } | |
| 1835 | + } | |
| 1836 | + break; | |
| 1724 | 1837 | case TARGET_NR_nanosleep: |
| 1725 | 1838 | { |
| 1726 | 1839 | struct target_timespec *target_req = (void *)arg1; |
| ... | ... | @@ -1767,11 +1880,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1767 | 1880 | } |
| 1768 | 1881 | } |
| 1769 | 1882 | break; |
| 1770 | - case TARGET_NR_vm86: | |
| 1771 | 1883 | case TARGET_NR_query_module: |
| 1884 | + goto unimplemented; | |
| 1772 | 1885 | case TARGET_NR_nfsservctl: |
| 1886 | + goto unimplemented; | |
| 1773 | 1887 | case TARGET_NR_prctl: |
| 1888 | + goto unimplemented; | |
| 1774 | 1889 | case TARGET_NR_pread: |
| 1890 | + goto unimplemented; | |
| 1775 | 1891 | case TARGET_NR_pwrite: |
| 1776 | 1892 | goto unimplemented; |
| 1777 | 1893 | case TARGET_NR_chown: |
| ... | ... | @@ -1781,16 +1897,24 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1781 | 1897 | ret = get_errno(sys_getcwd1((char *)arg1, arg2)); |
| 1782 | 1898 | break; |
| 1783 | 1899 | case TARGET_NR_capget: |
| 1900 | + goto unimplemented; | |
| 1784 | 1901 | case TARGET_NR_capset: |
| 1902 | + goto unimplemented; | |
| 1785 | 1903 | case TARGET_NR_sigaltstack: |
| 1904 | + goto unimplemented; | |
| 1786 | 1905 | case TARGET_NR_sendfile: |
| 1906 | + goto unimplemented; | |
| 1787 | 1907 | case TARGET_NR_getpmsg: |
| 1908 | + goto unimplemented; | |
| 1788 | 1909 | case TARGET_NR_putpmsg: |
| 1910 | + goto unimplemented; | |
| 1789 | 1911 | case TARGET_NR_vfork: |
| 1790 | 1912 | ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0)); |
| 1791 | 1913 | break; |
| 1792 | 1914 | case TARGET_NR_ugetrlimit: |
| 1915 | + goto unimplemented; | |
| 1793 | 1916 | case TARGET_NR_truncate64: |
| 1917 | + goto unimplemented; | |
| 1794 | 1918 | case TARGET_NR_ftruncate64: |
| 1795 | 1919 | goto unimplemented; |
| 1796 | 1920 | case TARGET_NR_stat64: |
| ... | ... | @@ -1919,6 +2043,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1919 | 2043 | ret = get_errno(gettid()); |
| 1920 | 2044 | break; |
| 1921 | 2045 | case TARGET_NR_readahead: |
| 2046 | + goto unimplemented; | |
| 1922 | 2047 | case TARGET_NR_setxattr: |
| 1923 | 2048 | case TARGET_NR_lsetxattr: |
| 1924 | 2049 | case TARGET_NR_fsetxattr: |
| ... | ... | @@ -1931,10 +2056,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, |
| 1931 | 2056 | case TARGET_NR_removexattr: |
| 1932 | 2057 | case TARGET_NR_lremovexattr: |
| 1933 | 2058 | case TARGET_NR_fremovexattr: |
| 1934 | - goto unimplemented; | |
| 2059 | + goto unimplemented_nowarn; | |
| 2060 | + case TARGET_NR_set_thread_area: | |
| 2061 | + case TARGET_NR_get_thread_area: | |
| 2062 | + goto unimplemented_nowarn; | |
| 1935 | 2063 | default: |
| 1936 | 2064 | unimplemented: |
| 1937 | - gemu_log("gemu: Unsupported syscall: %d\n", num); | |
| 2065 | + gemu_log("qemu: Unsupported syscall: %d\n", num); | |
| 2066 | + unimplemented_nowarn: | |
| 1938 | 2067 | ret = -ENOSYS; |
| 1939 | 2068 | break; |
| 1940 | 2069 | } | ... | ... |