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 | } | ... | ... |