Commit 106ec87921a41752777781f073092301d4477567
1 parent
951f1351
initial MIPS signal handling (initial patch by Raphael Rigo)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2031 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
376 additions
and
3 deletions
linux-user/main.c
| @@ -1302,6 +1302,7 @@ void cpu_loop(CPUMIPSState *env) | @@ -1302,6 +1302,7 @@ void cpu_loop(CPUMIPSState *env) | ||
| 1302 | case EXCP_SYSCALL: | 1302 | case EXCP_SYSCALL: |
| 1303 | { | 1303 | { |
| 1304 | syscall_num = env->gpr[2] - 4000; | 1304 | syscall_num = env->gpr[2] - 4000; |
| 1305 | + env->PC += 4; | ||
| 1305 | if (syscall_num >= sizeof(mips_syscall_args)) { | 1306 | if (syscall_num >= sizeof(mips_syscall_args)) { |
| 1306 | ret = -ENOSYS; | 1307 | ret = -ENOSYS; |
| 1307 | } else { | 1308 | } else { |
| @@ -1328,7 +1329,6 @@ void cpu_loop(CPUMIPSState *env) | @@ -1328,7 +1329,6 @@ void cpu_loop(CPUMIPSState *env) | ||
| 1328 | arg5, | 1329 | arg5, |
| 1329 | arg6); | 1330 | arg6); |
| 1330 | } | 1331 | } |
| 1331 | - env->PC += 4; | ||
| 1332 | if ((unsigned int)ret >= (unsigned int)(-1133)) { | 1332 | if ((unsigned int)ret >= (unsigned int)(-1133)) { |
| 1333 | env->gpr[7] = 1; /* error flag */ | 1333 | env->gpr[7] = 1; /* error flag */ |
| 1334 | ret = -ret; | 1334 | ret = -ret; |
| @@ -1347,6 +1347,9 @@ void cpu_loop(CPUMIPSState *env) | @@ -1347,6 +1347,9 @@ void cpu_loop(CPUMIPSState *env) | ||
| 1347 | info.si_code = 0; | 1347 | info.si_code = 0; |
| 1348 | queue_signal(info.si_signo, &info); | 1348 | queue_signal(info.si_signo, &info); |
| 1349 | break; | 1349 | break; |
| 1350 | + case EXCP_INTERRUPT: | ||
| 1351 | + /* just indicate that signals should be handled asap */ | ||
| 1352 | + break; | ||
| 1350 | default: | 1353 | default: |
| 1351 | // error: | 1354 | // error: |
| 1352 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", | 1355 | fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", |
linux-user/signal.c
| @@ -432,13 +432,17 @@ int do_sigaction(int sig, const struct target_sigaction *act, | @@ -432,13 +432,17 @@ int do_sigaction(int sig, const struct target_sigaction *act, | ||
| 432 | if (oact) { | 432 | if (oact) { |
| 433 | oact->_sa_handler = tswapl(k->sa._sa_handler); | 433 | oact->_sa_handler = tswapl(k->sa._sa_handler); |
| 434 | oact->sa_flags = tswapl(k->sa.sa_flags); | 434 | oact->sa_flags = tswapl(k->sa.sa_flags); |
| 435 | - oact->sa_restorer = tswapl(k->sa.sa_restorer); | 435 | + #if !defined(TARGET_MIPS) |
| 436 | + oact->sa_restorer = tswapl(k->sa.sa_restorer); | ||
| 437 | + #endif | ||
| 436 | oact->sa_mask = k->sa.sa_mask; | 438 | oact->sa_mask = k->sa.sa_mask; |
| 437 | } | 439 | } |
| 438 | if (act) { | 440 | if (act) { |
| 439 | k->sa._sa_handler = tswapl(act->_sa_handler); | 441 | k->sa._sa_handler = tswapl(act->_sa_handler); |
| 440 | k->sa.sa_flags = tswapl(act->sa_flags); | 442 | k->sa.sa_flags = tswapl(act->sa_flags); |
| 441 | - k->sa.sa_restorer = tswapl(act->sa_restorer); | 443 | + #if !defined(TARGET_MIPS) |
| 444 | + k->sa.sa_restorer = tswapl(act->sa_restorer); | ||
| 445 | + #endif | ||
| 442 | k->sa.sa_mask = act->sa_mask; | 446 | k->sa.sa_mask = act->sa_mask; |
| 443 | 447 | ||
| 444 | /* we update the host linux signal state */ | 448 | /* we update the host linux signal state */ |
| @@ -1618,6 +1622,334 @@ long do_rt_sigreturn(CPUState *env) | @@ -1618,6 +1622,334 @@ long do_rt_sigreturn(CPUState *env) | ||
| 1618 | return -ENOSYS; | 1622 | return -ENOSYS; |
| 1619 | } | 1623 | } |
| 1620 | 1624 | ||
| 1625 | +#elif defined(TARGET_MIPS) | ||
| 1626 | + | ||
| 1627 | +struct target_sigcontext { | ||
| 1628 | + uint32_t sc_regmask; /* Unused */ | ||
| 1629 | + uint32_t sc_status; | ||
| 1630 | + uint64_t sc_pc; | ||
| 1631 | + uint64_t sc_regs[32]; | ||
| 1632 | + uint64_t sc_fpregs[32]; | ||
| 1633 | + uint32_t sc_ownedfp; /* Unused */ | ||
| 1634 | + uint32_t sc_fpc_csr; | ||
| 1635 | + uint32_t sc_fpc_eir; /* Unused */ | ||
| 1636 | + uint32_t sc_used_math; | ||
| 1637 | + uint32_t sc_dsp; /* dsp status, was sc_ssflags */ | ||
| 1638 | + uint64_t sc_mdhi; | ||
| 1639 | + uint64_t sc_mdlo; | ||
| 1640 | + target_ulong sc_hi1; /* Was sc_cause */ | ||
| 1641 | + target_ulong sc_lo1; /* Was sc_badvaddr */ | ||
| 1642 | + target_ulong sc_hi2; /* Was sc_sigset[4] */ | ||
| 1643 | + target_ulong sc_lo2; | ||
| 1644 | + target_ulong sc_hi3; | ||
| 1645 | + target_ulong sc_lo3; | ||
| 1646 | +}; | ||
| 1647 | + | ||
| 1648 | +struct sigframe { | ||
| 1649 | + uint32_t sf_ass[4]; /* argument save space for o32 */ | ||
| 1650 | + uint32_t sf_code[2]; /* signal trampoline */ | ||
| 1651 | + struct target_sigcontext sf_sc; | ||
| 1652 | + target_sigset_t sf_mask; | ||
| 1653 | +}; | ||
| 1654 | + | ||
| 1655 | +/* Install trampoline to jump back from signal handler */ | ||
| 1656 | +static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall) | ||
| 1657 | +{ | ||
| 1658 | + int err; | ||
| 1659 | + | ||
| 1660 | + /* | ||
| 1661 | + * Set up the return code ... | ||
| 1662 | + * | ||
| 1663 | + * li v0, __NR__foo_sigreturn | ||
| 1664 | + * syscall | ||
| 1665 | + */ | ||
| 1666 | + | ||
| 1667 | + err = __put_user(0x24020000 + syscall, tramp + 0); | ||
| 1668 | + err |= __put_user(0x0000000c , tramp + 1); | ||
| 1669 | + /* flush_cache_sigtramp((unsigned long) tramp); */ | ||
| 1670 | + return err; | ||
| 1671 | +} | ||
| 1672 | + | ||
| 1673 | +static inline int | ||
| 1674 | +setup_sigcontext(CPUState *regs, struct target_sigcontext *sc) | ||
| 1675 | +{ | ||
| 1676 | + int err = 0; | ||
| 1677 | + | ||
| 1678 | + err |= __put_user(regs->PC, &sc->sc_pc); | ||
| 1679 | + | ||
| 1680 | + #define save_gp_reg(i) do { \ | ||
| 1681 | + err |= __put_user(regs->gpr[i], &sc->sc_regs[i]); \ | ||
| 1682 | + } while(0) | ||
| 1683 | + __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); | ||
| 1684 | + save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); | ||
| 1685 | + save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); | ||
| 1686 | + save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); | ||
| 1687 | + save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); | ||
| 1688 | + save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); | ||
| 1689 | + save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); | ||
| 1690 | + save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); | ||
| 1691 | + save_gp_reg(31); | ||
| 1692 | + #undef save_gp_reg | ||
| 1693 | + | ||
| 1694 | + err |= __put_user(regs->HI, &sc->sc_mdhi); | ||
| 1695 | + err |= __put_user(regs->LO, &sc->sc_mdlo); | ||
| 1696 | + | ||
| 1697 | + /* Not used yet, but might be useful if we ever have DSP suppport */ | ||
| 1698 | +#if 0 | ||
| 1699 | + if (cpu_has_dsp) { | ||
| 1700 | + err |= __put_user(mfhi1(), &sc->sc_hi1); | ||
| 1701 | + err |= __put_user(mflo1(), &sc->sc_lo1); | ||
| 1702 | + err |= __put_user(mfhi2(), &sc->sc_hi2); | ||
| 1703 | + err |= __put_user(mflo2(), &sc->sc_lo2); | ||
| 1704 | + err |= __put_user(mfhi3(), &sc->sc_hi3); | ||
| 1705 | + err |= __put_user(mflo3(), &sc->sc_lo3); | ||
| 1706 | + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); | ||
| 1707 | + } | ||
| 1708 | + /* same with 64 bit */ | ||
| 1709 | + #ifdef CONFIG_64BIT | ||
| 1710 | + err |= __put_user(regs->hi, &sc->sc_hi[0]); | ||
| 1711 | + err |= __put_user(regs->lo, &sc->sc_lo[0]); | ||
| 1712 | + if (cpu_has_dsp) { | ||
| 1713 | + err |= __put_user(mfhi1(), &sc->sc_hi[1]); | ||
| 1714 | + err |= __put_user(mflo1(), &sc->sc_lo[1]); | ||
| 1715 | + err |= __put_user(mfhi2(), &sc->sc_hi[2]); | ||
| 1716 | + err |= __put_user(mflo2(), &sc->sc_lo[2]); | ||
| 1717 | + err |= __put_user(mfhi3(), &sc->sc_hi[3]); | ||
| 1718 | + err |= __put_user(mflo3(), &sc->sc_lo[3]); | ||
| 1719 | + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); | ||
| 1720 | + } | ||
| 1721 | + #endif | ||
| 1722 | + | ||
| 1723 | + | ||
| 1724 | + #endif | ||
| 1725 | + | ||
| 1726 | + | ||
| 1727 | + #if 0 | ||
| 1728 | + err |= __put_user(!!used_math(), &sc->sc_used_math); | ||
| 1729 | + | ||
| 1730 | + if (!used_math()) | ||
| 1731 | + goto out; | ||
| 1732 | + | ||
| 1733 | + /* | ||
| 1734 | + * Save FPU state to signal context. Signal handler will "inherit" | ||
| 1735 | + * current FPU state. | ||
| 1736 | + */ | ||
| 1737 | + preempt_disable(); | ||
| 1738 | + | ||
| 1739 | + if (!is_fpu_owner()) { | ||
| 1740 | + own_fpu(); | ||
| 1741 | + restore_fp(current); | ||
| 1742 | + } | ||
| 1743 | + err |= save_fp_context(sc); | ||
| 1744 | + | ||
| 1745 | + preempt_enable(); | ||
| 1746 | + out: | ||
| 1747 | +#endif | ||
| 1748 | + return err; | ||
| 1749 | +} | ||
| 1750 | + | ||
| 1751 | +static inline int | ||
| 1752 | +restore_sigcontext(CPUState *regs, struct target_sigcontext *sc) | ||
| 1753 | +{ | ||
| 1754 | + int err = 0; | ||
| 1755 | + | ||
| 1756 | + err |= __get_user(regs->CP0_EPC, &sc->sc_pc); | ||
| 1757 | + | ||
| 1758 | + err |= __get_user(regs->HI, &sc->sc_mdhi); | ||
| 1759 | + err |= __get_user(regs->LO, &sc->sc_mdlo); | ||
| 1760 | + | ||
| 1761 | + #define restore_gp_reg(i) do { \ | ||
| 1762 | + err |= __get_user(regs->gpr[i], &sc->sc_regs[i]); \ | ||
| 1763 | + } while(0) | ||
| 1764 | + restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); | ||
| 1765 | + restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); | ||
| 1766 | + restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); | ||
| 1767 | + restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); | ||
| 1768 | + restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); | ||
| 1769 | + restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); | ||
| 1770 | + restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); | ||
| 1771 | + restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); | ||
| 1772 | + restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); | ||
| 1773 | + restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); | ||
| 1774 | + restore_gp_reg(31); | ||
| 1775 | + #undef restore_gp_reg | ||
| 1776 | + | ||
| 1777 | +#if 0 | ||
| 1778 | + if (cpu_has_dsp) { | ||
| 1779 | + err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); | ||
| 1780 | + err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); | ||
| 1781 | + err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); | ||
| 1782 | + err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); | ||
| 1783 | + err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); | ||
| 1784 | + err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); | ||
| 1785 | + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); | ||
| 1786 | + } | ||
| 1787 | + #ifdef CONFIG_64BIT | ||
| 1788 | + err |= __get_user(regs->hi, &sc->sc_hi[0]); | ||
| 1789 | + err |= __get_user(regs->lo, &sc->sc_lo[0]); | ||
| 1790 | + if (cpu_has_dsp) { | ||
| 1791 | + err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg); | ||
| 1792 | + err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg); | ||
| 1793 | + err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg); | ||
| 1794 | + err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg); | ||
| 1795 | + err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg); | ||
| 1796 | + err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg); | ||
| 1797 | + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); | ||
| 1798 | + } | ||
| 1799 | + #endif | ||
| 1800 | + | ||
| 1801 | + err |= __get_user(used_math, &sc->sc_used_math); | ||
| 1802 | + conditional_used_math(used_math); | ||
| 1803 | + | ||
| 1804 | + preempt_disable(); | ||
| 1805 | + | ||
| 1806 | + if (used_math()) { | ||
| 1807 | + /* restore fpu context if we have used it before */ | ||
| 1808 | + own_fpu(); | ||
| 1809 | + err |= restore_fp_context(sc); | ||
| 1810 | + } else { | ||
| 1811 | + /* signal handler may have used FPU. Give it up. */ | ||
| 1812 | + lose_fpu(); | ||
| 1813 | + } | ||
| 1814 | + | ||
| 1815 | + preempt_enable(); | ||
| 1816 | +#endif | ||
| 1817 | + return err; | ||
| 1818 | +} | ||
| 1819 | +/* | ||
| 1820 | + * Determine which stack to use.. | ||
| 1821 | + */ | ||
| 1822 | +static inline void * | ||
| 1823 | +get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size) | ||
| 1824 | +{ | ||
| 1825 | + unsigned long sp; | ||
| 1826 | + | ||
| 1827 | + /* Default to using normal stack */ | ||
| 1828 | + sp = regs->gpr[29]; | ||
| 1829 | + | ||
| 1830 | + /* | ||
| 1831 | + * FPU emulator may have it's own trampoline active just | ||
| 1832 | + * above the user stack, 16-bytes before the next lowest | ||
| 1833 | + * 16 byte boundary. Try to avoid trashing it. | ||
| 1834 | + */ | ||
| 1835 | + sp -= 32; | ||
| 1836 | + | ||
| 1837 | +#if 0 | ||
| 1838 | + /* This is the X/Open sanctioned signal stack switching. */ | ||
| 1839 | + if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) | ||
| 1840 | + sp = current->sas_ss_sp + current->sas_ss_size; | ||
| 1841 | +#endif | ||
| 1842 | + | ||
| 1843 | + return g2h((sp - frame_size) & ~7); | ||
| 1844 | +} | ||
| 1845 | + | ||
| 1846 | +static void setup_frame(int sig, struct emulated_sigaction * ka, | ||
| 1847 | + target_sigset_t *set, CPUState *regs) | ||
| 1848 | +{ | ||
| 1849 | + struct sigframe *frame; | ||
| 1850 | + int i; | ||
| 1851 | + | ||
| 1852 | + frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
| 1853 | + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) | ||
| 1854 | + goto give_sigsegv; | ||
| 1855 | + | ||
| 1856 | + install_sigtramp(frame->sf_code, TARGET_NR_sigreturn); | ||
| 1857 | + | ||
| 1858 | + if(setup_sigcontext(regs, &frame->sf_sc)) | ||
| 1859 | + goto give_sigsegv; | ||
| 1860 | + | ||
| 1861 | + for(i = 0; i < TARGET_NSIG_WORDS; i++) { | ||
| 1862 | + if(__put_user(set->sig[i], &frame->sf_mask.sig[i])) | ||
| 1863 | + goto give_sigsegv; | ||
| 1864 | + } | ||
| 1865 | + | ||
| 1866 | + /* | ||
| 1867 | + * Arguments to signal handler: | ||
| 1868 | + * | ||
| 1869 | + * a0 = signal number | ||
| 1870 | + * a1 = 0 (should be cause) | ||
| 1871 | + * a2 = pointer to struct sigcontext | ||
| 1872 | + * | ||
| 1873 | + * $25 and PC point to the signal handler, $29 points to the | ||
| 1874 | + * struct sigframe. | ||
| 1875 | + */ | ||
| 1876 | + regs->gpr[ 4] = sig; | ||
| 1877 | + regs->gpr[ 5] = 0; | ||
| 1878 | + regs->gpr[ 6] = h2g(&frame->sf_sc); | ||
| 1879 | + regs->gpr[29] = h2g(frame); | ||
| 1880 | + regs->gpr[31] = h2g(frame->sf_code); | ||
| 1881 | + /* The original kernel code sets CP0_EPC to the handler | ||
| 1882 | + * since it returns to userland using eret | ||
| 1883 | + * we cannot do this here, and we must set PC directly */ | ||
| 1884 | + regs->PC = regs->gpr[25] = ka->sa._sa_handler; | ||
| 1885 | + return; | ||
| 1886 | + | ||
| 1887 | +give_sigsegv: | ||
| 1888 | + force_sig(TARGET_SIGSEGV/*, current*/); | ||
| 1889 | + return; | ||
| 1890 | +} | ||
| 1891 | + | ||
| 1892 | +long do_sigreturn(CPUState *regs) | ||
| 1893 | +{ | ||
| 1894 | + struct sigframe *frame; | ||
| 1895 | + sigset_t blocked; | ||
| 1896 | + target_sigset_t target_set; | ||
| 1897 | + int i; | ||
| 1898 | + | ||
| 1899 | +#if defined(DEBUG_SIGNAL) | ||
| 1900 | + fprintf(stderr, "do_sigreturn\n"); | ||
| 1901 | +#endif | ||
| 1902 | + frame = (struct sigframe *) regs->gpr[29]; | ||
| 1903 | + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
| 1904 | + goto badframe; | ||
| 1905 | + | ||
| 1906 | + for(i = 0; i < TARGET_NSIG_WORDS; i++) { | ||
| 1907 | + if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i])) | ||
| 1908 | + goto badframe; | ||
| 1909 | + } | ||
| 1910 | + | ||
| 1911 | + target_to_host_sigset_internal(&blocked, &target_set); | ||
| 1912 | + sigprocmask(SIG_SETMASK, &blocked, NULL); | ||
| 1913 | + | ||
| 1914 | + if (restore_sigcontext(regs, &frame->sf_sc)) | ||
| 1915 | + goto badframe; | ||
| 1916 | + | ||
| 1917 | +#if 0 | ||
| 1918 | + /* | ||
| 1919 | + * Don't let your children do this ... | ||
| 1920 | + */ | ||
| 1921 | + __asm__ __volatile__( | ||
| 1922 | + "move\t$29, %0\n\t" | ||
| 1923 | + "j\tsyscall_exit" | ||
| 1924 | + :/* no outputs */ | ||
| 1925 | + :"r" (®s)); | ||
| 1926 | + /* Unreached */ | ||
| 1927 | +#endif | ||
| 1928 | + | ||
| 1929 | + regs->PC = regs->CP0_EPC; | ||
| 1930 | + /* I am not sure this is right, but it seems to work | ||
| 1931 | + * maybe a problem with nested signals ? */ | ||
| 1932 | + regs->CP0_EPC = 0; | ||
| 1933 | + return 0; | ||
| 1934 | + | ||
| 1935 | +badframe: | ||
| 1936 | + force_sig(TARGET_SIGSEGV/*, current*/); | ||
| 1937 | + return 0; | ||
| 1938 | + | ||
| 1939 | +} | ||
| 1940 | + | ||
| 1941 | +static void setup_rt_frame(int sig, struct emulated_sigaction *ka, | ||
| 1942 | + target_siginfo_t *info, | ||
| 1943 | + target_sigset_t *set, CPUState *env) | ||
| 1944 | +{ | ||
| 1945 | + fprintf(stderr, "setup_rt_frame: not implemented\n"); | ||
| 1946 | +} | ||
| 1947 | + | ||
| 1948 | +long do_rt_sigreturn(CPUState *env) | ||
| 1949 | +{ | ||
| 1950 | + fprintf(stderr, "do_rt_sigreturn: not implemented\n"); | ||
| 1951 | + return -ENOSYS; | ||
| 1952 | +} | ||
| 1621 | 1953 | ||
| 1622 | #else | 1954 | #else |
| 1623 | 1955 |
linux-user/syscall.c
| @@ -2246,6 +2246,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, | @@ -2246,6 +2246,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, | ||
| 2246 | break; | 2246 | break; |
| 2247 | case TARGET_NR_sigaction: | 2247 | case TARGET_NR_sigaction: |
| 2248 | { | 2248 | { |
| 2249 | + #if !defined(TARGET_MIPS) | ||
| 2249 | struct target_old_sigaction *old_act; | 2250 | struct target_old_sigaction *old_act; |
| 2250 | struct target_sigaction act, oact, *pact; | 2251 | struct target_sigaction act, oact, *pact; |
| 2251 | if (arg2) { | 2252 | if (arg2) { |
| @@ -2268,6 +2269,33 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, | @@ -2268,6 +2269,33 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, | ||
| 2268 | old_act->sa_restorer = oact.sa_restorer; | 2269 | old_act->sa_restorer = oact.sa_restorer; |
| 2269 | unlock_user_struct(old_act, arg3, 1); | 2270 | unlock_user_struct(old_act, arg3, 1); |
| 2270 | } | 2271 | } |
| 2272 | + #else | ||
| 2273 | + struct target_sigaction act, oact, *pact, *old_act; | ||
| 2274 | + | ||
| 2275 | + if (arg2) { | ||
| 2276 | + lock_user_struct(old_act, arg2, 1); | ||
| 2277 | + act._sa_handler = old_act->_sa_handler; | ||
| 2278 | + target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]); | ||
| 2279 | + act.sa_flags = old_act->sa_flags; | ||
| 2280 | + unlock_user_struct(old_act, arg2, 0); | ||
| 2281 | + pact = &act; | ||
| 2282 | + } else { | ||
| 2283 | + pact = NULL; | ||
| 2284 | + } | ||
| 2285 | + | ||
| 2286 | + ret = get_errno(do_sigaction(arg1, pact, &oact)); | ||
| 2287 | + | ||
| 2288 | + if (!is_error(ret) && arg3) { | ||
| 2289 | + lock_user_struct(old_act, arg3, 0); | ||
| 2290 | + old_act->_sa_handler = oact._sa_handler; | ||
| 2291 | + old_act->sa_flags = oact.sa_flags; | ||
| 2292 | + old_act->sa_mask.sig[0] = oact.sa_mask.sig[0]; | ||
| 2293 | + old_act->sa_mask.sig[1] = 0; | ||
| 2294 | + old_act->sa_mask.sig[2] = 0; | ||
| 2295 | + old_act->sa_mask.sig[3] = 0; | ||
| 2296 | + unlock_user_struct(old_act, arg3, 1); | ||
| 2297 | + } | ||
| 2298 | + #endif | ||
| 2271 | } | 2299 | } |
| 2272 | break; | 2300 | break; |
| 2273 | case TARGET_NR_rt_sigaction: | 2301 | case TARGET_NR_rt_sigaction: |
linux-user/syscall_defs.h
| @@ -448,6 +448,15 @@ int do_sigaction(int sig, const struct target_sigaction *act, | @@ -448,6 +448,15 @@ int do_sigaction(int sig, const struct target_sigaction *act, | ||
| 448 | 448 | ||
| 449 | #endif | 449 | #endif |
| 450 | 450 | ||
| 451 | +#if defined(TARGET_MIPS) | ||
| 452 | + | ||
| 453 | +struct target_sigaction { | ||
| 454 | + target_ulong sa_flags; | ||
| 455 | + target_ulong _sa_handler; | ||
| 456 | + target_sigset_t sa_mask; | ||
| 457 | +}; | ||
| 458 | + | ||
| 459 | +#else | ||
| 451 | struct target_old_sigaction { | 460 | struct target_old_sigaction { |
| 452 | target_ulong _sa_handler; | 461 | target_ulong _sa_handler; |
| 453 | target_ulong sa_mask; | 462 | target_ulong sa_mask; |
| @@ -461,6 +470,7 @@ struct target_sigaction { | @@ -461,6 +470,7 @@ struct target_sigaction { | ||
| 461 | target_ulong sa_restorer; | 470 | target_ulong sa_restorer; |
| 462 | target_sigset_t sa_mask; | 471 | target_sigset_t sa_mask; |
| 463 | }; | 472 | }; |
| 473 | +#endif | ||
| 464 | 474 | ||
| 465 | typedef union target_sigval { | 475 | typedef union target_sigval { |
| 466 | int sival_int; | 476 | int sival_int; |