Commit 106ec87921a41752777781f073092301d4477567

Authored by bellard
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
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" (&regs));
  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;