Revision 5cd4393b
b/linux-user/syscall.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 |
} |
Also available in: Unified diff