1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369
|
/* CRIS exception, interrupt, and trap (EIT) support
Copyright (C) 2004-2021 Free Software Foundation, Inc.
Contributed by Axis Communications.
This file is part of the GNU simulators.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "sim-main.h"
#include "sim-syscall.h"
#include "sim-options.h"
#include "bfd.h"
/* FIXME: get rid of targ-vals.h usage everywhere else. */
#include <stdarg.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
/* For PATH_MAX, originally. */
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
/* From ld/sysdep.h. */
#ifdef PATH_MAX
# define SIM_PATHMAX PATH_MAX
#else
# ifdef MAXPATHLEN
# define SIM_PATHMAX MAXPATHLEN
# else
# define SIM_PATHMAX 1024
# endif
#endif
/* The verbatim values are from asm-cris/unistd.h. */
#define TARGET_SYS_exit 1
#define TARGET_SYS_read 3
#define TARGET_SYS_write 4
#define TARGET_SYS_open 5
#define TARGET_SYS_close 6
#define TARGET_SYS_unlink 10
#define TARGET_SYS_time 13
#define TARGET_SYS_lseek 19
#define TARGET_SYS_getpid 20
#define TARGET_SYS_access 33
#define TARGET_SYS_kill 37
#define TARGET_SYS_rename 38
#define TARGET_SYS_pipe 42
#define TARGET_SYS_brk 45
#define TARGET_SYS_ioctl 54
#define TARGET_SYS_fcntl 55
#define TARGET_SYS_getppid 64
#define TARGET_SYS_setrlimit 75
#define TARGET_SYS_gettimeofday 78
#define TARGET_SYS_readlink 85
#define TARGET_SYS_munmap 91
#define TARGET_SYS_truncate 92
#define TARGET_SYS_ftruncate 93
#define TARGET_SYS_socketcall 102
#define TARGET_SYS_stat 106
#define TARGET_SYS_fstat 108
#define TARGET_SYS_wait4 114
#define TARGET_SYS_sigreturn 119
#define TARGET_SYS_clone 120
#define TARGET_SYS_uname 122
#define TARGET_SYS_mprotect 125
#define TARGET_SYS_llseek 140
#define TARGET_SYS_writev 146
#define TARGET_SYS__sysctl 149
#define TARGET_SYS_sched_setparam 154
#define TARGET_SYS_sched_getparam 155
#define TARGET_SYS_sched_setscheduler 156
#define TARGET_SYS_sched_getscheduler 157
#define TARGET_SYS_sched_yield 158
#define TARGET_SYS_sched_get_priority_max 159
#define TARGET_SYS_sched_get_priority_min 160
#define TARGET_SYS_mremap 163
#define TARGET_SYS_poll 168
#define TARGET_SYS_rt_sigaction 174
#define TARGET_SYS_rt_sigprocmask 175
#define TARGET_SYS_rt_sigsuspend 179
#define TARGET_SYS_getcwd 183
#define TARGET_SYS_ugetrlimit 191
#define TARGET_SYS_mmap2 192
#define TARGET_SYS_stat64 195
#define TARGET_SYS_lstat64 196
#define TARGET_SYS_fstat64 197
#define TARGET_SYS_geteuid32 201
#define TARGET_SYS_getuid32 199
#define TARGET_SYS_getegid32 202
#define TARGET_SYS_getgid32 200
#define TARGET_SYS_fcntl64 221
#define TARGET_SYS_set_thread_area 243
#define TARGET_SYS_exit_group 252
#define TARGET_PROT_READ 0x1
#define TARGET_PROT_WRITE 0x2
#define TARGET_PROT_EXEC 0x4
#define TARGET_PROT_NONE 0x0
#define TARGET_MAP_SHARED 0x01
#define TARGET_MAP_PRIVATE 0x02
#define TARGET_MAP_TYPE 0x0f
#define TARGET_MAP_FIXED 0x10
#define TARGET_MAP_ANONYMOUS 0x20
#define TARGET_MAP_DENYWRITE 0x800
#define TARGET_CTL_KERN 1
#define TARGET_CTL_VM 2
#define TARGET_CTL_NET 3
#define TARGET_CTL_PROC 4
#define TARGET_CTL_FS 5
#define TARGET_CTL_DEBUG 6
#define TARGET_CTL_DEV 7
#define TARGET_CTL_BUS 8
#define TARGET_CTL_ABI 9
#define TARGET_CTL_KERN_VERSION 4
/* linux/mman.h */
#define TARGET_MREMAP_MAYMOVE 1
#define TARGET_MREMAP_FIXED 2
#define TARGET_TCGETS 0x5401
#define TARGET_UTSNAME "#7 Thu Jan 1 00:00:00 MET 2009"
/* Seconds since 1970-01-01 to the above date + 10 minutes;
'date -d "Thu Jan 1 00:00:10 MET 2009" +%s'. */
#define TARGET_EPOCH 1230764410
/* Milliseconds since start of run. We use the number of syscalls to
avoid introducing noise in the execution time. */
#define TARGET_TIME_MS(cpu) ((cpu)->syscalls)
/* Seconds as in time(2). */
#define TARGET_TIME(cpu) (TARGET_EPOCH + TARGET_TIME_MS (cpu) / 1000)
#define TARGET_SCHED_OTHER 0
#define TARGET_RLIMIT_STACK 3
#define TARGET_RLIMIT_NOFILE 7
#define SIM_TARGET_MAX_THREADS 64
#define SIM_MAX_ALLOC_CHUNK (512*1024*1024)
/* From linux/sched.h. */
#define TARGET_CSIGNAL 0x000000ff
#define TARGET_CLONE_VM 0x00000100
#define TARGET_CLONE_FS 0x00000200
#define TARGET_CLONE_FILES 0x00000400
#define TARGET_CLONE_SIGHAND 0x00000800
#define TARGET_CLONE_PID 0x00001000
#define TARGET_CLONE_PTRACE 0x00002000
#define TARGET_CLONE_VFORK 0x00004000
#define TARGET_CLONE_PARENT 0x00008000
#define TARGET_CLONE_THREAD 0x00010000
#define TARGET_CLONE_SIGNAL (TARGET_CLONE_SIGHAND | TARGET_CLONE_THREAD)
/* From asm-cris/poll.h. */
#define TARGET_POLLIN 1
/* From asm-cris/signal.h. */
#define TARGET_SIG_BLOCK 0
#define TARGET_SIG_UNBLOCK 1
#define TARGET_SIG_SETMASK 2
#define TARGET_SIG_DFL 0
#define TARGET_SIG_IGN 1
#define TARGET_SIG_ERR ((USI)-1)
#define TARGET_SIGHUP 1
#define TARGET_SIGINT 2
#define TARGET_SIGQUIT 3
#define TARGET_SIGILL 4
#define TARGET_SIGTRAP 5
#define TARGET_SIGABRT 6
#define TARGET_SIGIOT 6
#define TARGET_SIGBUS 7
#define TARGET_SIGFPE 8
#define TARGET_SIGKILL 9
#define TARGET_SIGUSR1 10
#define TARGET_SIGSEGV 11
#define TARGET_SIGUSR2 12
#define TARGET_SIGPIPE 13
#define TARGET_SIGALRM 14
#define TARGET_SIGTERM 15
#define TARGET_SIGSTKFLT 16
#define TARGET_SIGCHLD 17
#define TARGET_SIGCONT 18
#define TARGET_SIGSTOP 19
#define TARGET_SIGTSTP 20
#define TARGET_SIGTTIN 21
#define TARGET_SIGTTOU 22
#define TARGET_SIGURG 23
#define TARGET_SIGXCPU 24
#define TARGET_SIGXFSZ 25
#define TARGET_SIGVTALRM 26
#define TARGET_SIGPROF 27
#define TARGET_SIGWINCH 28
#define TARGET_SIGIO 29
#define TARGET_SIGPOLL SIGIO
/* Actually commented out in the kernel header. */
#define TARGET_SIGLOST 29
#define TARGET_SIGPWR 30
#define TARGET_SIGSYS 31
/* From include/asm-cris/signal.h. */
#define TARGET_SA_NOCLDSTOP 0x00000001
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
#define TARGET_SA_SIGINFO 0x00000004
#define TARGET_SA_ONSTACK 0x08000000
#define TARGET_SA_RESTART 0x10000000
#define TARGET_SA_NODEFER 0x40000000
#define TARGET_SA_RESETHAND 0x80000000
#define TARGET_SA_INTERRUPT 0x20000000 /* dummy -- ignored */
#define TARGET_SA_RESTORER 0x04000000
/* From linux/wait.h. */
#define TARGET_WNOHANG 1
#define TARGET_WUNTRACED 2
#define TARGET___WNOTHREAD 0x20000000
#define TARGET___WALL 0x40000000
#define TARGET___WCLONE 0x80000000
/* From linux/limits.h. */
#define TARGET_PIPE_BUF 4096
/* From unistd.h. */
#define TARGET_R_OK 4
#define TARGET_W_OK 2
#define TARGET_X_OK 1
#define TARGET_F_OK 0
static const char stat_map[] =
"st_dev,2:space,10:space,4:st_mode,4:st_nlink,4:st_uid,4"
":st_gid,4:st_rdev,2:space,10:st_size,8:st_blksize,4:st_blocks,4"
":space,4:st_atime,4:space,4:st_mtime,4:space,4:st_ctime,4:space,4"
":st_ino,8";
static const CB_TARGET_DEFS_MAP syscall_map[] =
{
{ "open", CB_SYS_open, TARGET_SYS_open },
{ "close", CB_SYS_close, TARGET_SYS_close },
{ "read", CB_SYS_read, TARGET_SYS_read },
{ "write", CB_SYS_write, TARGET_SYS_write },
{ "lseek", CB_SYS_lseek, TARGET_SYS_lseek },
{ "unlink", CB_SYS_unlink, TARGET_SYS_unlink },
{ "getpid", CB_SYS_getpid, TARGET_SYS_getpid },
{ "fstat", CB_SYS_fstat, TARGET_SYS_fstat64 },
{ "lstat", CB_SYS_lstat, TARGET_SYS_lstat64 },
{ "stat", CB_SYS_stat, TARGET_SYS_stat64 },
{ "pipe", CB_SYS_pipe, TARGET_SYS_pipe },
{ "rename", CB_SYS_rename, TARGET_SYS_rename },
{ "truncate", CB_SYS_truncate, TARGET_SYS_truncate },
{ "ftruncate", CB_SYS_ftruncate, TARGET_SYS_ftruncate },
{ 0, -1, -1 }
};
/* An older, 32-bit-only stat mapping. */
static const char stat32_map[] =
"st_dev,2:space,2:st_ino,4:st_mode,2:st_nlink,2:st_uid,2"
":st_gid,2:st_rdev,2:space,2:st_size,4:st_blksize,4:st_blocks,4"
":st_atime,4:space,4:st_mtime,4:space,4:st_ctime,4:space,12";
/* Map for calls using the 32-bit struct stat. Primarily used by the
newlib Linux mapping. */
static const CB_TARGET_DEFS_MAP syscall_stat32_map[] =
{
{ "fstat", CB_SYS_fstat, TARGET_SYS_fstat },
{ "stat", CB_SYS_stat, TARGET_SYS_stat },
{ 0, -1, -1 }
};
/* Giving the true value for the running sim process will lead to
non-time-invariant behavior. */
#define TARGET_PID 42
/* Unfortunately, we don't get this from cris.cpu at the moment, and if
we did, we'd still don't get a register number with the "16" offset. */
#define TARGET_SRP_REGNUM (16+11)
/* Extracted by applying
awk '/^#define/ { printf "#ifdef %s\n { %s, %s },\n#endif\n", $2, $2, $3;}'
on .../include/asm/errno.h in a GNU/Linux/CRIS installation and
adjusting the synonyms. */
static const CB_TARGET_DEFS_MAP errno_map[] =
{
#ifdef EPERM
{ "EPERM", EPERM, 1 },
#endif
#ifdef ENOENT
{ "ENOENT", ENOENT, 2 },
#endif
#ifdef ESRCH
{ "ESRCH", ESRCH, 3 },
#endif
#ifdef EINTR
{ "EINTR", EINTR, 4 },
#endif
#ifdef EIO
{ "EIO", EIO, 5 },
#endif
#ifdef ENXIO
{ "ENXIO", ENXIO, 6 },
#endif
#ifdef E2BIG
{ "E2BIG", E2BIG, 7 },
#endif
#ifdef ENOEXEC
{ "ENOEXEC", ENOEXEC, 8 },
#endif
#ifdef EBADF
{ "EBADF", EBADF, 9 },
#endif
#ifdef ECHILD
{ "ECHILD", ECHILD, 10 },
#endif
#ifdef EAGAIN
{ "EAGAIN", EAGAIN, 11 },
#endif
#ifdef ENOMEM
{ "ENOMEM", ENOMEM, 12 },
#endif
#ifdef EACCES
{ "EACCES", EACCES, 13 },
#endif
#ifdef EFAULT
{ "EFAULT", EFAULT, 14 },
#endif
#ifdef ENOTBLK
{ "ENOTBLK", ENOTBLK, 15 },
#endif
#ifdef EBUSY
{ "EBUSY", EBUSY, 16 },
#endif
#ifdef EEXIST
{ "EEXIST", EEXIST, 17 },
#endif
#ifdef EXDEV
{ "EXDEV", EXDEV, 18 },
#endif
#ifdef ENODEV
{ "ENODEV", ENODEV, 19 },
#endif
#ifdef ENOTDIR
{ "ENOTDIR", ENOTDIR, 20 },
#endif
#ifdef EISDIR
{ "EISDIR", EISDIR, 21 },
#endif
#ifdef EINVAL
{ "EINVAL", EINVAL, 22 },
#endif
#ifdef ENFILE
{ "ENFILE", ENFILE, 23 },
#endif
#ifdef EMFILE
{ "EMFILE", EMFILE, 24 },
#endif
#ifdef ENOTTY
{ "ENOTTY", ENOTTY, 25 },
#endif
#ifdef ETXTBSY
{ "ETXTBSY", ETXTBSY, 26 },
#endif
#ifdef EFBIG
{ "EFBIG", EFBIG, 27 },
#endif
#ifdef ENOSPC
{ "ENOSPC", ENOSPC, 28 },
#endif
#ifdef ESPIPE
{ "ESPIPE", ESPIPE, 29 },
#endif
#ifdef EROFS
{ "EROFS", EROFS, 30 },
#endif
#ifdef EMLINK
{ "EMLINK", EMLINK, 31 },
#endif
#ifdef EPIPE
{ "EPIPE", EPIPE, 32 },
#endif
#ifdef EDOM
{ "EDOM", EDOM, 33 },
#endif
#ifdef ERANGE
{ "ERANGE", ERANGE, 34 },
#endif
#ifdef EDEADLK
{ "EDEADLK", EDEADLK, 35 },
#endif
#ifdef ENAMETOOLONG
{ "ENAMETOOLONG", ENAMETOOLONG, 36 },
#endif
#ifdef ENOLCK
{ "ENOLCK", ENOLCK, 37 },
#endif
#ifdef ENOSYS
{ "ENOSYS", ENOSYS, 38 },
#endif
#ifdef ENOTEMPTY
{ "ENOTEMPTY", ENOTEMPTY, 39 },
#endif
#ifdef ELOOP
{ "ELOOP", ELOOP, 40 },
#endif
#ifdef EWOULDBLOCK
{ "EWOULDBLOCK", EWOULDBLOCK, 11 },
#endif
#ifdef ENOMSG
{ "ENOMSG", ENOMSG, 42 },
#endif
#ifdef EIDRM
{ "EIDRM", EIDRM, 43 },
#endif
#ifdef ECHRNG
{ "ECHRNG", ECHRNG, 44 },
#endif
#ifdef EL2NSYNC
{ "EL2NSYNC", EL2NSYNC, 45 },
#endif
#ifdef EL3HLT
{ "EL3HLT", EL3HLT, 46 },
#endif
#ifdef EL3RST
{ "EL3RST", EL3RST, 47 },
#endif
#ifdef ELNRNG
{ "ELNRNG", ELNRNG, 48 },
#endif
#ifdef EUNATCH
{ "EUNATCH", EUNATCH, 49 },
#endif
#ifdef ENOCSI
{ "ENOCSI", ENOCSI, 50 },
#endif
#ifdef EL2HLT
{ "EL2HLT", EL2HLT, 51 },
#endif
#ifdef EBADE
{ "EBADE", EBADE, 52 },
#endif
#ifdef EBADR
{ "EBADR", EBADR, 53 },
#endif
#ifdef EXFULL
{ "EXFULL", EXFULL, 54 },
#endif
#ifdef ENOANO
{ "ENOANO", ENOANO, 55 },
#endif
#ifdef EBADRQC
{ "EBADRQC", EBADRQC, 56 },
#endif
#ifdef EBADSLT
{ "EBADSLT", EBADSLT, 57 },
#endif
#ifdef EDEADLOCK
{ "EDEADLOCK", EDEADLOCK, 35 },
#endif
#ifdef EBFONT
{ "EBFONT", EBFONT, 59 },
#endif
#ifdef ENOSTR
{ "ENOSTR", ENOSTR, 60 },
#endif
#ifdef ENODATA
{ "ENODATA", ENODATA, 61 },
#endif
#ifdef ETIME
{ "ETIME", ETIME, 62 },
#endif
#ifdef ENOSR
{ "ENOSR", ENOSR, 63 },
#endif
#ifdef ENONET
{ "ENONET", ENONET, 64 },
#endif
#ifdef ENOPKG
{ "ENOPKG", ENOPKG, 65 },
#endif
#ifdef EREMOTE
{ "EREMOTE", EREMOTE, 66 },
#endif
#ifdef ENOLINK
{ "ENOLINK", ENOLINK, 67 },
#endif
#ifdef EADV
{ "EADV", EADV, 68 },
#endif
#ifdef ESRMNT
{ "ESRMNT", ESRMNT, 69 },
#endif
#ifdef ECOMM
{ "ECOMM", ECOMM, 70 },
#endif
#ifdef EPROTO
{ "EPROTO", EPROTO, 71 },
#endif
#ifdef EMULTIHOP
{ "EMULTIHOP", EMULTIHOP, 72 },
#endif
#ifdef EDOTDOT
{ "EDOTDOT", EDOTDOT, 73 },
#endif
#ifdef EBADMSG
{ "EBADMSG", EBADMSG, 74 },
#endif
#ifdef EOVERFLOW
{ "EOVERFLOW", EOVERFLOW, 75 },
#endif
#ifdef ENOTUNIQ
{ "ENOTUNIQ", ENOTUNIQ, 76 },
#endif
#ifdef EBADFD
{ "EBADFD", EBADFD, 77 },
#endif
#ifdef EREMCHG
{ "EREMCHG", EREMCHG, 78 },
#endif
#ifdef ELIBACC
{ "ELIBACC", ELIBACC, 79 },
#endif
#ifdef ELIBBAD
{ "ELIBBAD", ELIBBAD, 80 },
#endif
#ifdef ELIBSCN
{ "ELIBSCN", ELIBSCN, 81 },
#endif
#ifdef ELIBMAX
{ "ELIBMAX", ELIBMAX, 82 },
#endif
#ifdef ELIBEXEC
{ "ELIBEXEC", ELIBEXEC, 83 },
#endif
#ifdef EILSEQ
{ "EILSEQ", EILSEQ, 84 },
#endif
#ifdef ERESTART
{ "ERESTART", ERESTART, 85 },
#endif
#ifdef ESTRPIPE
{ "ESTRPIPE", ESTRPIPE, 86 },
#endif
#ifdef EUSERS
{ "EUSERS", EUSERS, 87 },
#endif
#ifdef ENOTSOCK
{ "ENOTSOCK", ENOTSOCK, 88 },
#endif
#ifdef EDESTADDRREQ
{ "EDESTADDRREQ", EDESTADDRREQ, 89 },
#endif
#ifdef EMSGSIZE
{ "EMSGSIZE", EMSGSIZE, 90 },
#endif
#ifdef EPROTOTYPE
{ "EPROTOTYPE", EPROTOTYPE, 91 },
#endif
#ifdef ENOPROTOOPT
{ "ENOPROTOOPT", ENOPROTOOPT, 92 },
#endif
#ifdef EPROTONOSUPPORT
{ "EPROTONOSUPPORT", EPROTONOSUPPORT, 93 },
#endif
#ifdef ESOCKTNOSUPPORT
{ "ESOCKTNOSUPPORT", ESOCKTNOSUPPORT, 94 },
#endif
#ifdef EOPNOTSUPP
{ "EOPNOTSUPP", EOPNOTSUPP, 95 },
#endif
#ifdef EPFNOSUPPORT
{ "EPFNOSUPPORT", EPFNOSUPPORT, 96 },
#endif
#ifdef EAFNOSUPPORT
{ "EAFNOSUPPORT", EAFNOSUPPORT, 97 },
#endif
#ifdef EADDRINUSE
{ "EADDRINUSE", EADDRINUSE, 98 },
#endif
#ifdef EADDRNOTAVAIL
{ "EADDRNOTAVAIL", EADDRNOTAVAIL, 99 },
#endif
#ifdef ENETDOWN
{ "ENETDOWN", ENETDOWN, 100 },
#endif
#ifdef ENETUNREACH
{ "ENETUNREACH", ENETUNREACH, 101 },
#endif
#ifdef ENETRESET
{ "ENETRESET", ENETRESET, 102 },
#endif
#ifdef ECONNABORTED
{ "ECONNABORTED", ECONNABORTED, 103 },
#endif
#ifdef ECONNRESET
{ "ECONNRESET", ECONNRESET, 104 },
#endif
#ifdef ENOBUFS
{ "ENOBUFS", ENOBUFS, 105 },
#endif
#ifdef EISCONN
{ "EISCONN", EISCONN, 106 },
#endif
#ifdef ENOTCONN
{ "ENOTCONN", ENOTCONN, 107 },
#endif
#ifdef ESHUTDOWN
{ "ESHUTDOWN", ESHUTDOWN, 108 },
#endif
#ifdef ETOOMANYREFS
{ "ETOOMANYREFS", ETOOMANYREFS, 109 },
#endif
#ifdef ETIMEDOUT
{ "ETIMEDOUT", ETIMEDOUT, 110 },
#endif
#ifdef ECONNREFUSED
{ "ECONNREFUSED", ECONNREFUSED, 111 },
#endif
#ifdef EHOSTDOWN
{ "EHOSTDOWN", EHOSTDOWN, 112 },
#endif
#ifdef EHOSTUNREACH
{ "EHOSTUNREACH", EHOSTUNREACH, 113 },
#endif
#ifdef EALREADY
{ "EALREADY", EALREADY, 114 },
#endif
#ifdef EINPROGRESS
{ "EINPROGRESS", EINPROGRESS, 115 },
#endif
#ifdef ESTALE
{ "ESTALE", ESTALE, 116 },
#endif
#ifdef EUCLEAN
{ "EUCLEAN", EUCLEAN, 117 },
#endif
#ifdef ENOTNAM
{ "ENOTNAM", ENOTNAM, 118 },
#endif
#ifdef ENAVAIL
{ "ENAVAIL", ENAVAIL, 119 },
#endif
#ifdef EISNAM
{ "EISNAM", EISNAM, 120 },
#endif
#ifdef EREMOTEIO
{ "EREMOTEIO", EREMOTEIO, 121 },
#endif
#ifdef EDQUOT
{ "EDQUOT", EDQUOT, 122 },
#endif
#ifdef ENOMEDIUM
{ "ENOMEDIUM", ENOMEDIUM, 123 },
#endif
#ifdef EMEDIUMTYPE
{ "EMEDIUMTYPE", EMEDIUMTYPE, 124 },
#endif
{ 0, 0, 0 }
};
/* Extracted by applying
perl -ne 'if ($_ =~ /^#define/) { split;
printf "#ifdef $_[1]\n { %s, 0x%x },\n#endif\n",
$_[1], $_[2] =~ /^0/ ? oct($_[2]) : $_[2];}'
on pertinent parts of .../include/asm/fcntl.h in a GNU/Linux/CRIS
installation and removing synonyms and unnecessary items. Don't
forget the end-marker. */
/* These we treat specially, as they're used in the fcntl F_GETFL
syscall. For consistency, open_map is also manually edited to use
these macros. */
#define TARGET_O_ACCMODE 0x3
#define TARGET_O_RDONLY 0x0
#define TARGET_O_WRONLY 0x1
static const CB_TARGET_DEFS_MAP open_map[] = {
#ifdef O_ACCMODE
{ "O_ACCMODE", O_ACCMODE, TARGET_O_ACCMODE },
#endif
#ifdef O_RDONLY
{ "O_RDONLY", O_RDONLY, TARGET_O_RDONLY },
#endif
#ifdef O_WRONLY
{ "O_WRONLY", O_WRONLY, TARGET_O_WRONLY },
#endif
#ifdef O_RDWR
{ "O_RDWR", O_RDWR, 0x2 },
#endif
#ifdef O_CREAT
{ "O_CREAT", O_CREAT, 0x40 },
#endif
#ifdef O_EXCL
{ "O_EXCL", O_EXCL, 0x80 },
#endif
#ifdef O_NOCTTY
{ "O_NOCTTY", O_NOCTTY, 0x100 },
#endif
#ifdef O_TRUNC
{ "O_TRUNC", O_TRUNC, 0x200 },
#endif
#ifdef O_APPEND
{ "O_APPEND", O_APPEND, 0x400 },
#endif
#ifdef O_NONBLOCK
{ "O_NONBLOCK", O_NONBLOCK, 0x800 },
#endif
#ifdef O_NDELAY
{ "O_NDELAY", O_NDELAY, 0x0 },
#endif
#ifdef O_SYNC
{ "O_SYNC", O_SYNC, 0x1000 },
#endif
#ifdef FASYNC
{ "FASYNC", FASYNC, 0x2000 },
#endif
#ifdef O_DIRECT
{ "O_DIRECT", O_DIRECT, 0x4000 },
#endif
#ifdef O_LARGEFILE
{ "O_LARGEFILE", O_LARGEFILE, 0x8000 },
#endif
#ifdef O_DIRECTORY
{ "O_DIRECTORY", O_DIRECTORY, 0x10000 },
#endif
#ifdef O_NOFOLLOW
{ "O_NOFOLLOW", O_NOFOLLOW, 0x20000 },
#endif
{ 0, -1, -1 }
};
/* Let's be less drastic and more traceable. FIXME: mark as noreturn. */
#define abort() \
sim_io_error (sd, "simulator unhandled condition at %s:%d", \
__FUNCTION__, __LINE__)
/* Needed for the cris_pipe_nonempty and cris_pipe_empty syscalls. */
static SIM_CPU *current_cpu_for_cb_callback;
static USI create_map (SIM_DESC, struct cris_sim_mmapped_page **,
USI addr, USI len);
static USI unmap_pages (SIM_DESC, struct cris_sim_mmapped_page **,
USI addr, USI len);
static USI is_mapped (SIM_DESC, struct cris_sim_mmapped_page **,
USI addr, USI len);
static void dump_statistics (SIM_CPU *current_cpu);
static void make_first_thread (SIM_CPU *current_cpu);
/* When we risk running self-modified code (as in trampolines), this is
called from special-case insns. The silicon CRIS CPU:s have enough
cache snooping implemented making this a simulator-only issue. Tests:
gcc.c-torture/execute/931002-1.c execution, -O3 -g
gcc.c-torture/execute/931002-1.c execution, -O3 -fomit-frame-pointer. */
void
cris_flush_simulator_decode_cache (SIM_CPU *current_cpu,
USI pc ATTRIBUTE_UNUSED)
{
SIM_DESC sd = CPU_STATE (current_cpu);
#if WITH_SCACHE
if (USING_SCACHE_P (sd))
scache_flush_cpu (current_cpu);
#endif
}
/* Output statistics at the end of a run. */
static void
dump_statistics (SIM_CPU *current_cpu)
{
SIM_DESC sd = CPU_STATE (current_cpu);
CRIS_MISC_PROFILE *profp
= CPU_CRIS_MISC_PROFILE (current_cpu);
unsigned64 total = profp->basic_cycle_count;
const char *textmsg = "Basic clock cycles, total @: %llu\n";
/* The --cris-stats={basic|unaligned|schedulable|all} counts affect
what's included in the "total" count only. */
switch (CPU_CRIS_MISC_PROFILE (current_cpu)->flags
& FLAG_CRIS_MISC_PROFILE_ALL)
{
case FLAG_CRIS_MISC_PROFILE_SIMPLE:
break;
case (FLAG_CRIS_MISC_PROFILE_UNALIGNED | FLAG_CRIS_MISC_PROFILE_SIMPLE):
textmsg
= "Clock cycles including stall cycles for unaligned accesses @: %llu\n";
total += profp->unaligned_mem_dword_count;
break;
case (FLAG_CRIS_MISC_PROFILE_SCHEDULABLE | FLAG_CRIS_MISC_PROFILE_SIMPLE):
textmsg = "Schedulable clock cycles, total @: %llu\n";
total
+= (profp->memsrc_stall_count
+ profp->memraw_stall_count
+ profp->movemsrc_stall_count
+ profp->movemdst_stall_count
+ profp->mulsrc_stall_count
+ profp->jumpsrc_stall_count
+ profp->unaligned_mem_dword_count);
break;
case FLAG_CRIS_MISC_PROFILE_ALL:
textmsg = "All accounted clock cycles, total @: %llu\n";
total
+= (profp->memsrc_stall_count
+ profp->memraw_stall_count
+ profp->movemsrc_stall_count
+ profp->movemdst_stall_count
+ profp->movemaddr_stall_count
+ profp->mulsrc_stall_count
+ profp->jumpsrc_stall_count
+ profp->branch_stall_count
+ profp->jumptarget_stall_count
+ profp->unaligned_mem_dword_count);
break;
default:
abort ();
sim_io_eprintf (sd,
"Internal inconsistency at %s:%d",
__FILE__, __LINE__);
sim_engine_halt (sd, current_cpu, NULL, 0,
sim_stopped, SIM_SIGILL);
}
/* Historically, these messages have gone to stderr, so we'll keep it
that way. It's also easier to then tell it from normal program
output. FIXME: Add redirect option like "run -e file". */
sim_io_eprintf (sd, textmsg, total);
/* For v32, unaligned_mem_dword_count should always be 0. For
v10, memsrc_stall_count should always be 0. */
sim_io_eprintf (sd, "Memory source stall cycles: %llu\n",
(unsigned long long) (profp->memsrc_stall_count
+ profp->unaligned_mem_dword_count));
sim_io_eprintf (sd, "Memory read-after-write stall cycles: %llu\n",
(unsigned long long) profp->memraw_stall_count);
sim_io_eprintf (sd, "Movem source stall cycles: %llu\n",
(unsigned long long) profp->movemsrc_stall_count);
sim_io_eprintf (sd, "Movem destination stall cycles: %llu\n",
(unsigned long long) profp->movemdst_stall_count);
sim_io_eprintf (sd, "Movem address stall cycles: %llu\n",
(unsigned long long) profp->movemaddr_stall_count);
sim_io_eprintf (sd, "Multiplication source stall cycles: %llu\n",
(unsigned long long) profp->mulsrc_stall_count);
sim_io_eprintf (sd, "Jump source stall cycles: %llu\n",
(unsigned long long) profp->jumpsrc_stall_count);
sim_io_eprintf (sd, "Branch misprediction stall cycles: %llu\n",
(unsigned long long) profp->branch_stall_count);
sim_io_eprintf (sd, "Jump target stall cycles: %llu\n",
(unsigned long long) profp->jumptarget_stall_count);
}
/* Check whether any part of [addr .. addr + len - 1] is already mapped.
Return 1 if a overlap detected, 0 otherwise. */
static USI
is_mapped (SIM_DESC sd ATTRIBUTE_UNUSED,
struct cris_sim_mmapped_page **rootp,
USI addr, USI len)
{
struct cris_sim_mmapped_page *mapp;
if (len == 0 || (len & 8191))
abort ();
/* Iterate over the reverse-address sorted pages until we find a page in
or lower than the checked area. */
for (mapp = *rootp; mapp != NULL && mapp->addr >= addr; mapp = mapp->prev)
if (mapp->addr < addr + len && mapp->addr >= addr)
return 1;
return 0;
}
/* Check whether any part of [addr .. addr + len - 1] is *un*mapped.
Return 1 if the whole area is mapped, 0 otherwise. */
static USI
is_mapped_only (SIM_DESC sd ATTRIBUTE_UNUSED,
struct cris_sim_mmapped_page **rootp,
USI addr, USI len)
{
struct cris_sim_mmapped_page *mapp;
if (len == 0 || (len & 8191))
abort ();
/* Iterate over the reverse-address sorted pages until we find a page
lower than the checked area. */
for (mapp = *rootp; mapp != NULL && mapp->addr >= addr; mapp = mapp->prev)
if (addr == mapp->addr && len == 8192)
return 1;
else if (addr + len > mapp->addr)
len -= 8192;
return 0;
}
/* Debug helper; to be run from gdb. */
void
cris_dump_map (SIM_CPU *current_cpu)
{
struct cris_sim_mmapped_page *mapp;
USI start, end;
for (mapp = current_cpu->highest_mmapped_page,
start = mapp == NULL ? 0 : mapp->addr + 8192,
end = mapp == NULL ? 0 : mapp->addr + 8191;
mapp != NULL;
mapp = mapp->prev)
{
if (mapp->addr != start - 8192)
{
sim_io_eprintf (CPU_STATE (current_cpu), "0x%x..0x%x\n", start, end);
end = mapp->addr + 8191;
}
start = mapp->addr;
}
if (current_cpu->highest_mmapped_page != NULL)
sim_io_eprintf (CPU_STATE (current_cpu), "0x%x..0x%x\n", start, end);
}
/* Create mmapped memory. ADDR is -1 if any address will do. Caller
must make sure that the address isn't already mapped. */
static USI
create_map (SIM_DESC sd, struct cris_sim_mmapped_page **rootp, USI addr,
USI len)
{
struct cris_sim_mmapped_page *mapp;
struct cris_sim_mmapped_page **higher_prevp = rootp;
USI new_addr = 0x40000000;
if (addr != (USI) -1)
new_addr = addr;
else if (*rootp && rootp[0]->addr >= new_addr)
new_addr = rootp[0]->addr + 8192;
if (len != 8192)
{
USI page_addr;
if (len & 8191)
/* Which is better: return an error for this, or just round it up? */
abort ();
/* Do a recursive call for each page in the request. */
for (page_addr = new_addr; len != 0; page_addr += 8192, len -= 8192)
if (create_map (sd, rootp, page_addr, 8192) >= (USI) -8191)
abort ();
return new_addr;
}
for (mapp = *rootp;
mapp != NULL && mapp->addr > new_addr;
mapp = mapp->prev)
higher_prevp = &mapp->prev;
/* Assert for consistency that we don't create duplicate maps. */
if (is_mapped (sd, rootp, new_addr, len))
abort ();
/* Allocate the new page, on the next higher page from the last one
allocated, and link in the new descriptor before previous ones. */
mapp = malloc (sizeof (*mapp));
if (mapp == NULL)
return (USI) -ENOMEM;
sim_core_attach (sd, NULL, 0, access_read_write_exec, 0,
new_addr, len,
0, NULL, NULL);
mapp->addr = new_addr;
mapp->prev = *higher_prevp;
*higher_prevp = mapp;
return new_addr;
}
/* Unmap one or more pages. */
static USI
unmap_pages (SIM_DESC sd, struct cris_sim_mmapped_page **rootp, USI addr,
USI len)
{
struct cris_sim_mmapped_page *mapp;
struct cris_sim_mmapped_page **higher_prevp = rootp;
if (len != 8192)
{
USI page_addr;
int ret = 0;
if (len & 8191)
/* Which is better: return an error for this, or just round it up? */
abort ();
/* Loop backwards to make each call is O(1) over the number of pages
allocated, if we're unmapping from the high end of the pages. */
for (page_addr = addr + len - 8192;
page_addr > addr;
page_addr -= 8192)
if (unmap_pages (sd, rootp, page_addr, 8192))
ret = EINVAL;
if (unmap_pages (sd, rootp, addr, 8192))
ret = EINVAL;
return ret;
}
for (mapp = *rootp; mapp != NULL && mapp->addr > addr; mapp = mapp->prev)
higher_prevp = &mapp->prev;
if (mapp == NULL || mapp->addr != addr)
return EINVAL;
*higher_prevp = mapp->prev;
sim_core_detach (sd, NULL, 0, 0, addr);
free (mapp);
return 0;
}
/* The semantic code invokes this for illegal (unrecognized) instructions. */
SEM_PC
sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
{
SIM_DESC sd = CPU_STATE (current_cpu);
sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL);
return vpc;
}
/* Handlers from the CGEN description that should not be called. */
USI
cris_bmod_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
UINT srcreg ATTRIBUTE_UNUSED,
USI dstreg ATTRIBUTE_UNUSED)
{
SIM_DESC sd = CPU_STATE (current_cpu);
abort ();
}
void
h_supr_set_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
UINT index ATTRIBUTE_UNUSED,
USI page ATTRIBUTE_UNUSED,
USI newval ATTRIBUTE_UNUSED)
{
SIM_DESC sd = CPU_STATE (current_cpu);
abort ();
}
USI
h_supr_get_handler (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
UINT index ATTRIBUTE_UNUSED,
USI page ATTRIBUTE_UNUSED)
{
SIM_DESC sd = CPU_STATE (current_cpu);
abort ();
}
/* Swap one context for another. */
static void
schedule (SIM_CPU *current_cpu, int next)
{
/* Need to mark context-switches in the trace output. */
if ((CPU_CRIS_MISC_PROFILE (current_cpu)->flags
& FLAG_CRIS_MISC_PROFILE_XSIM_TRACE))
cris_trace_printf (CPU_STATE (current_cpu), current_cpu,
"\t#:%d\n", next);
/* Copy the current context (if there is one) to its slot. */
if (current_cpu->thread_data[current_cpu->threadno].cpu_context)
memcpy (current_cpu->thread_data[current_cpu->threadno].cpu_context,
¤t_cpu->cpu_data_placeholder,
current_cpu->thread_cpu_data_size);
/* Copy the new context from its slot. */
memcpy (¤t_cpu->cpu_data_placeholder,
current_cpu->thread_data[next].cpu_context,
current_cpu->thread_cpu_data_size);
/* Update needed stuff to indicate the new context. */
current_cpu->threadno = next;
/* Handle pending signals. */
if (current_cpu->thread_data[next].sigpending
/* We don't run nested signal handlers. This means that pause(2)
and sigsuspend(2) do not work in sighandlers, but that
shouldn't be too hard a restriction. It also greatly
simplifies the code. */
&& current_cpu->thread_data[next].cpu_context_atsignal == NULL)
{
int sig;
/* See if there's really a pending, non-blocked handler. We don't
queue signals, so just use the first one in ascending order. */
for (sig = 0; sig < 64; sig++)
if (current_cpu->thread_data[next].sigdata[sig].pending
&& !current_cpu->thread_data[next].sigdata[sig].blocked)
{
bfd_byte regbuf[4];
USI sp;
int i;
USI blocked;
USI pc = sim_pc_get (current_cpu);
/* It's simpler to save the CPU context inside the simulator
than on the stack. */
current_cpu->thread_data[next].cpu_context_atsignal
= (*current_cpu
->make_thread_cpu_data) (current_cpu,
current_cpu->thread_data[next]
.cpu_context);
(*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_SP, regbuf, 4);
sp = bfd_getl32 (regbuf);
/* Make sure we have an aligned stack. */
sp &= ~3;
/* Make room for the signal frame, aligned. FIXME: Check that
the memory exists, map it in if absent. (BTW, should also
implement on-access automatic stack allocation). */
sp -= 20;
/* This isn't the same signal frame as the kernel uses, because
we don't want to bother getting all registers on and off the
stack. */
/* First, we store the currently blocked signals. */
blocked = 0;
for (i = 0; i < 32; i++)
blocked
|= current_cpu->thread_data[next].sigdata[i + 1].blocked << i;
sim_core_write_aligned_4 (current_cpu, pc, 0, sp, blocked);
blocked = 0;
for (i = 0; i < 31; i++)
blocked
|= current_cpu->thread_data[next].sigdata[i + 33].blocked << i;
sim_core_write_aligned_4 (current_cpu, pc, 0, sp + 4, blocked);
/* Then, the actual instructions. This is CPU-specific, but we
use instructions from the common subset for v10 and v32 which
should be safe for the time being but could be parametrized
if need be. */
/* MOVU.W [PC+],R9. */
sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 8, 0x9c5f);
/* .WORD TARGET_SYS_sigreturn. */
sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 10,
TARGET_SYS_sigreturn);
/* BREAK 13. */
sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 12, 0xe93d);
/* NOP (on v32; it's SETF on v10, but is the correct compatible
instruction. Still, it doesn't matter because v10 has no
delay slot for BREAK so it will not be executed). */
sim_core_write_aligned_2 (current_cpu, pc, 0, sp + 16, 0x05b0);
/* Modify registers to hold the right values for the sighandler
context: updated stackpointer and return address pointing to
the sigreturn stub. */
bfd_putl32 (sp, regbuf);
(*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_SP, regbuf, 4);
bfd_putl32 (sp + 8, regbuf);
(*CPU_REG_STORE (current_cpu)) (current_cpu, TARGET_SRP_REGNUM,
regbuf, 4);
current_cpu->thread_data[next].sigdata[sig].pending = 0;
/* Block this signal (for the duration of the sighandler). */
current_cpu->thread_data[next].sigdata[sig].blocked = 1;
sim_pc_set (current_cpu, current_cpu->sighandler[sig]);
bfd_putl32 (sig, regbuf);
(*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R10,
regbuf, 4);
/* We ignore a SA_SIGINFO flag in the sigaction call; the code I
needed all this for, specifies a SA_SIGINFO call but treats it
like an ordinary sighandler; only the signal number argument is
inspected. To make future need to implement SA_SIGINFO
correctly possible, we set the siginfo argument register to a
magic (hopefully non-address) number. (NB: then, you should
just need to pass the siginfo argument; it seems you probably
don't need to implement the specific rt_sigreturn.) */
bfd_putl32 (0xbad5161f, regbuf);
(*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R11,
regbuf, 4);
/* The third argument is unused and the kernel sets it to 0. */
bfd_putl32 (0, regbuf);
(*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R12,
regbuf, 4);
return;
}
/* No, there actually was no pending signal for this thread. Reset
this flag. */
current_cpu->thread_data[next].sigpending = 0;
}
}
/* Reschedule the simplest possible way until something else is absolutely
necessary:
- A. Find the next process (round-robin) that doesn't have at_syscall
set, schedule it.
- B. If there is none, just run the next process, round-robin.
- Clear at_syscall for the current process. */
static void
reschedule (SIM_CPU *current_cpu)
{
SIM_DESC sd = CPU_STATE (current_cpu);
int i;
/* Iterate over all thread slots, because after a few thread creations
and exits, we don't know where the live ones are. */
for (i = (current_cpu->threadno + 1) % SIM_TARGET_MAX_THREADS;
i != current_cpu->threadno;
i = (i + 1) % SIM_TARGET_MAX_THREADS)
if (current_cpu->thread_data[i].cpu_context
&& current_cpu->thread_data[i].at_syscall == 0)
{
schedule (current_cpu, i);
return;
}
/* Pick any next live thread. */
for (i = (current_cpu->threadno + 1) % SIM_TARGET_MAX_THREADS;
i != current_cpu->threadno;
i = (i + 1) % SIM_TARGET_MAX_THREADS)
if (current_cpu->thread_data[i].cpu_context)
{
schedule (current_cpu, i);
return;
}
/* More than one live thread, but we couldn't find the next one? */
abort ();
}
/* Set up everything to receive (or IGN) an incoming signal to the
current context. */
static int
deliver_signal (SIM_CPU *current_cpu, int sig, unsigned int pid)
{
int i;
USI pc = sim_pc_get (current_cpu);
/* Find the thread index of the pid. */
for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
/* Apparently it's ok to send signals to zombies (so a check for
current_cpu->thread_data[i].cpu_context != NULL would be
wrong). */
if (current_cpu->thread_data[i].threadid == pid - TARGET_PID)
{
if (sig < 64)
switch (current_cpu->sighandler[sig])
{
case TARGET_SIG_DFL:
switch (sig)
{
/* The following according to the glibc
documentation. (The kernel code has non-obvious
execution paths.) */
case TARGET_SIGFPE:
case TARGET_SIGILL:
case TARGET_SIGSEGV:
case TARGET_SIGBUS:
case TARGET_SIGABRT:
case TARGET_SIGTRAP:
case TARGET_SIGSYS:
case TARGET_SIGTERM:
case TARGET_SIGINT:
case TARGET_SIGQUIT:
case TARGET_SIGKILL:
case TARGET_SIGHUP:
case TARGET_SIGALRM:
case TARGET_SIGVTALRM:
case TARGET_SIGPROF:
case TARGET_SIGSTOP:
case TARGET_SIGPIPE:
case TARGET_SIGLOST:
case TARGET_SIGXCPU:
case TARGET_SIGXFSZ:
case TARGET_SIGUSR1:
case TARGET_SIGUSR2:
sim_io_eprintf (CPU_STATE (current_cpu),
"Exiting pid %d due to signal %d\n",
pid, sig);
sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
NULL, pc, sim_stopped,
sig == TARGET_SIGABRT
? SIM_SIGABRT : SIM_SIGILL);
return 0;
/* The default for all other signals is to be ignored. */
default:
return 0;
}
case TARGET_SIG_IGN:
switch (sig)
{
case TARGET_SIGKILL:
case TARGET_SIGSTOP:
/* Can't ignore these signals. */
sim_io_eprintf (CPU_STATE (current_cpu),
"Exiting pid %d due to signal %d\n",
pid, sig);
sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
NULL, pc, sim_stopped, SIM_SIGILL);
return 0;
default:
return 0;
}
break;
default:
/* Mark the signal as pending, making schedule () check
closer. The signal will be handled when the thread is
scheduled and the signal is unblocked. */
current_cpu->thread_data[i].sigdata[sig].pending = 1;
current_cpu->thread_data[i].sigpending = 1;
return 0;
}
else
{
sim_io_eprintf (CPU_STATE (current_cpu),
"Unimplemented signal: %d\n", sig);
sim_engine_halt (CPU_STATE (current_cpu), current_cpu, NULL, pc,
sim_stopped, SIM_SIGILL);
}
}
return
-cb_host_to_target_errno (STATE_CALLBACK (CPU_STATE (current_cpu)),
ESRCH);
}
/* Make the vector and the first item, the main thread. */
static void
make_first_thread (SIM_CPU *current_cpu)
{
SIM_DESC sd = CPU_STATE (current_cpu);
current_cpu->thread_data
= xcalloc (1,
SIM_TARGET_MAX_THREADS
* sizeof (current_cpu->thread_data[0]));
current_cpu->thread_data[0].cpu_context
= (*current_cpu->make_thread_cpu_data) (current_cpu,
¤t_cpu
->cpu_data_placeholder);
current_cpu->thread_data[0].parent_threadid = -1;
/* For good measure. */
if (TARGET_SIG_DFL != 0)
abort ();
}
/* Handle unknown system calls. Returns (if it does) the syscall
return value. */
static USI
cris_unknown_syscall (SIM_CPU *current_cpu, USI pc, char *s, ...)
{
SIM_DESC sd = CPU_STATE (current_cpu);
host_callback *cb = STATE_CALLBACK (sd);
if (cris_unknown_syscall_action == CRIS_USYSC_MSG_STOP
|| cris_unknown_syscall_action == CRIS_USYSC_MSG_ENOSYS)
{
va_list ap;
va_start (ap, s);
sim_io_evprintf (sd, s, ap);
va_end (ap);
if (cris_unknown_syscall_action == CRIS_USYSC_MSG_STOP)
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
}
return -cb_host_to_target_errno (cb, ENOSYS);
}
/* Main function: the handler of the "break 13" syscall insn. */
USI
cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1,
USI arg2, USI arg3, USI arg4, USI arg5, USI arg6,
USI pc)
{
CB_SYSCALL s;
SIM_DESC sd = CPU_STATE (current_cpu);
host_callback *cb = STATE_CALLBACK (sd);
int retval;
int threadno = current_cpu->threadno;
current_cpu->syscalls++;
CB_SYSCALL_INIT (&s);
s.func = callnum;
s.arg1 = arg1;
s.arg2 = arg2;
s.arg3 = arg3;
/* The type of s.arg2 is long, so for hosts with 64-bit longs, we need
to sign-extend the lseek offset to be passed as a signed number,
else we'll truncate it to something > 2GB on hosts where sizeof
long > sizeof USI. We avoid doing it for all syscalls, as arg2 is
e.g. an address for some syscalls. */
if (callnum == TARGET_SYS_lseek)
s.arg2 = (SI) arg2;
if (callnum == TARGET_SYS_exit_group
|| (callnum == TARGET_SYS_exit && current_cpu->m1threads == 0))
{
if (CPU_CRIS_MISC_PROFILE (current_cpu)->flags
& FLAG_CRIS_MISC_PROFILE_ALL)
dump_statistics (current_cpu);
sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, arg1);
}
s.p1 = (PTR) sd;
s.p2 = (PTR) current_cpu;
s.read_mem = sim_syscall_read_mem;
s.write_mem = sim_syscall_write_mem;
current_cpu_for_cb_callback = current_cpu;
if (cb_syscall (cb, &s) != CB_RC_OK)
{
abort ();
sim_io_eprintf (sd, "Break 13: invalid %d? Returned %ld\n", callnum,
s.result);
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
}
retval = s.result == -1 ? -s.errcode : s.result;
if (s.errcode != 0 && s.errcode == cb_host_to_target_errno (cb, ENOSYS))
{
/* If the generic simulator call said ENOSYS, then let's try the
ones we know ourselves.
The convention is to provide *very limited* functionality on an
as-needed basis, only what's covered by the test-suite, tests
added when functionality changes and abort with a descriptive
message for *everything* else. Where there's no test-case, we
just abort. */
switch (callnum)
{
case 0:
/* It's a pretty safe bet that the "old setup() system call"
number will not be re-used; we can't say the same for higher
numbers. We treat this simulator-generated call as "wait
forever"; we re-run this insn. The wait is ended by a
callback. Sanity check that this is the reason we got
here. */
if (current_cpu->thread_data == NULL
|| (current_cpu->thread_data[threadno].pipe_write_fd == 0))
goto unimplemented_syscall;
sim_pc_set (current_cpu, pc);
retval = arg1;
break;
case TARGET_SYS_fcntl64:
case TARGET_SYS_fcntl:
switch (arg2)
{
case 1:
/* F_GETFD.
Glibc checks stdin, stdout and stderr fd:s for
close-on-exec security sanity. We just need to provide a
OK return value. If we really need to have a
close-on-exec flag true, we could just do a real fcntl
here. */
retval = 0;
break;
case 2:
/* F_SETFD. Just ignore attempts to set the close-on-exec
flag. */
retval = 0;
break;
case 3:
/* F_GETFL. Check for the special case for open+fdopen. */
if (current_cpu->last_syscall == TARGET_SYS_open
&& arg1 == current_cpu->last_open_fd)
{
retval = current_cpu->last_open_flags & TARGET_O_ACCMODE;
break;
}
else if (arg1 == 0)
{
/* Because we can't freopen fd:s 0, 1, 2 to mean
something else than stdin, stdout and stderr
(sim/common/syscall.c:cb_syscall special cases fd
0, 1 and 2), we know what flags that we can
sanely return for these fd:s. */
retval = TARGET_O_RDONLY;
break;
}
else if (arg1 == 1 || arg1 == 2)
{
retval = TARGET_O_WRONLY;
break;
}
/* FALLTHROUGH */
default:
/* Nothing else is implemented. */
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented %s syscall "
"(fd: 0x%lx: cmd: 0x%lx arg: "
"0x%lx)\n",
callnum == TARGET_SYS_fcntl
? "fcntl" : "fcntl64",
(unsigned long) (USI) arg1,
(unsigned long) (USI) arg2,
(unsigned long) (USI) arg3);
break;
}
break;
case TARGET_SYS_uname:
{
/* Fill in a few constants to appease glibc. */
static char sim_utsname[6][65] =
{
"Linux",
"sim-target",
"2.6.27",
TARGET_UTSNAME,
"cris", /* Overwritten below. */
"localdomain"
};
/* Having the hardware type in Linux equal to the bfd
printable name is deliberate: if you make config.guess
work on your Linux-type system the usual way, it
probably will; either the bfd printable_name or the
ambiguous arch_name. */
strcpy (sim_utsname[4], STATE_ARCHITECTURE (sd)->printable_name);
if ((s.write_mem) (cb, &s, arg1, (const char *) sim_utsname,
sizeof (sim_utsname))
!= sizeof (sim_utsname))
retval = -cb_host_to_target_errno (cb, EFAULT);
else
retval = 0;
break;
}
case TARGET_SYS_geteuid32:
/* We tell the truth with these. Maybe we shouldn't, but it
should match the "stat" information. */
retval = geteuid ();
break;
case TARGET_SYS_getuid32:
retval = getuid ();
break;
case TARGET_SYS_getegid32:
retval = getegid ();
break;
case TARGET_SYS_getgid32:
retval = getgid ();
break;
case TARGET_SYS_brk:
/* Most often, we just return the argument, like the Linux
kernel. */
retval = arg1;
if (arg1 == 0)
retval = current_cpu->endbrk;
else if (arg1 <= current_cpu->endmem)
current_cpu->endbrk = arg1;
else
{
USI new_end = (arg1 + 8191) & ~8191;
/* If the simulator wants to brk more than a certain very
large amount, something is wrong. FIXME: Return an error
or abort? Have command-line selectable? */
if (new_end - current_cpu->endmem > SIM_MAX_ALLOC_CHUNK)
{
current_cpu->endbrk = current_cpu->endmem;
retval = current_cpu->endmem;
break;
}
sim_core_attach (sd, NULL, 0, access_read_write_exec, 0,
current_cpu->endmem,
new_end - current_cpu->endmem,
0, NULL, NULL);
current_cpu->endbrk = arg1;
current_cpu->endmem = new_end;
}
break;
case TARGET_SYS_getpid:
/* Correct until CLONE_THREAD is implemented. */
retval = current_cpu->thread_data == NULL
? TARGET_PID
: TARGET_PID + current_cpu->thread_data[threadno].threadid;
break;
case TARGET_SYS_getppid:
/* Correct until CLONE_THREAD is implemented. */
retval = current_cpu->thread_data == NULL
? TARGET_PID - 1
: (TARGET_PID
+ current_cpu->thread_data[threadno].parent_threadid);
break;
case TARGET_SYS_mmap2:
{
USI addr = arg1;
USI len = arg2;
USI prot = arg3;
USI flags = arg4;
USI fd = arg5;
USI pgoff = arg6;
/* At 2.6.27, Linux (many (all?) ports, in the mmap2 syscalls)
still masked away this bit, so let's just ignore
it. */
flags &= ~TARGET_MAP_DENYWRITE;
/* If the simulator wants to mmap more than the very large
limit, something is wrong. FIXME: Return an error or
abort? Have command-line selectable? */
if (len > SIM_MAX_ALLOC_CHUNK)
{
retval = -cb_host_to_target_errno (cb, ENOMEM);
break;
}
if ((prot != (TARGET_PROT_READ | TARGET_PROT_WRITE)
&& (prot
!= (TARGET_PROT_READ
| TARGET_PROT_WRITE
| TARGET_PROT_EXEC))
&& (prot != (TARGET_PROT_READ | TARGET_PROT_EXEC))
&& prot != TARGET_PROT_READ)
|| (flags != (TARGET_MAP_ANONYMOUS | TARGET_MAP_PRIVATE)
&& flags != TARGET_MAP_PRIVATE
&& flags != (TARGET_MAP_ANONYMOUS
| TARGET_MAP_PRIVATE | TARGET_MAP_FIXED)
&& flags != (TARGET_MAP_PRIVATE | TARGET_MAP_FIXED)
&& flags != TARGET_MAP_SHARED)
|| (fd != (USI) -1
&& prot != TARGET_PROT_READ
&& prot != (TARGET_PROT_READ | TARGET_PROT_EXEC)
&& prot != (TARGET_PROT_READ | TARGET_PROT_WRITE))
|| (fd == (USI) -1 && pgoff != 0)
|| (fd != (USI) -1 && (flags & TARGET_MAP_ANONYMOUS)))
{
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented mmap2 call "
"(0x%lx, 0x%lx, 0x%lx, "
"0x%lx, 0x%lx, 0x%lx)\n",
(unsigned long) arg1,
(unsigned long) arg2,
(unsigned long) arg3,
(unsigned long) arg4,
(unsigned long) arg5,
(unsigned long) arg6);
break;
}
else if (fd != (USI) -1)
{
/* Map a file. */
USI newaddr;
USI pos;
/* A non-aligned argument is allowed for files. */
USI newlen = (len + 8191) & ~8191;
/* We only support read, read|exec, and read|write,
which we should already have checked. Check again
anyway. */
if (prot != TARGET_PROT_READ
&& prot != (TARGET_PROT_READ | TARGET_PROT_EXEC)
&& prot != (TARGET_PROT_READ | TARGET_PROT_WRITE))
abort ();
if (flags & TARGET_MAP_FIXED)
unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
addr, newlen);
else if (is_mapped (sd, ¤t_cpu->highest_mmapped_page,
addr, newlen))
addr = 0;
newaddr
= create_map (sd, ¤t_cpu->highest_mmapped_page,
addr != 0 || (flags & TARGET_MAP_FIXED)
? addr : -1,
newlen);
if (newaddr >= (USI) -8191)
{
abort ();
retval = -cb_host_to_target_errno (cb, -(SI) newaddr);
break;
}
/* We were asked for MAP_FIXED, but couldn't. */
if ((flags & TARGET_MAP_FIXED) && newaddr != addr)
{
abort ();
unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
newaddr, newlen);
retval = -cb_host_to_target_errno (cb, EINVAL);
break;
}
/* Find the current position in the file. */
s.func = TARGET_SYS_lseek;
s.arg1 = fd;
s.arg2 = 0;
s.arg3 = SEEK_CUR;
if (cb_syscall (cb, &s) != CB_RC_OK)
abort ();
pos = s.result;
if (s.result < 0)
abort ();
/* Move to the correct offset in the file. */
s.func = TARGET_SYS_lseek;
s.arg1 = fd;
s.arg2 = pgoff*8192;
s.arg3 = SEEK_SET;
if (cb_syscall (cb, &s) != CB_RC_OK)
abort ();
if (s.result < 0)
abort ();
/* Use the standard read callback to read in "len"
bytes. */
s.func = TARGET_SYS_read;
s.arg1 = fd;
s.arg2 = newaddr;
s.arg3 = len;
if (cb_syscall (cb, &s) != CB_RC_OK)
abort ();
/* If the result is a page or more lesser than what
was requested, something went wrong. */
if (len >= 8192 && (USI) s.result <= len - 8192)
abort ();
/* After reading, we need to go back to the previous
position in the file. */
s.func = TARGET_SYS_lseek;
s.arg1 = fd;
s.arg2 = pos;
s.arg3 = SEEK_SET;
if (cb_syscall (cb, &s) != CB_RC_OK)
abort ();
if (pos != (USI) s.result)
abort ();
retval = newaddr;
}
else
{
USI newlen = (len + 8191) & ~8191;
USI newaddr;
if (flags & TARGET_MAP_FIXED)
unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
addr, newlen);
else if (is_mapped (sd, ¤t_cpu->highest_mmapped_page,
addr, newlen))
addr = 0;
newaddr = create_map (sd, ¤t_cpu->highest_mmapped_page,
addr != 0 || (flags & TARGET_MAP_FIXED)
? addr : -1,
newlen);
if (newaddr >= (USI) -8191)
retval = -cb_host_to_target_errno (cb, -(SI) newaddr);
else
retval = newaddr;
if ((flags & TARGET_MAP_FIXED) && newaddr != addr)
{
abort ();
unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
newaddr, newlen);
retval = -cb_host_to_target_errno (cb, EINVAL);
break;
}
}
break;
}
case TARGET_SYS_mprotect:
{
/* We only cover the case of linuxthreads mprotecting out
its stack guard page and of dynamic loading mprotecting
away the data (for some reason the whole library, then
mprotects away the data part and mmap-FIX:es it again. */
USI addr = arg1;
USI len = arg2;
USI prot = arg3;
if (prot != TARGET_PROT_NONE
|| !is_mapped_only (sd, ¤t_cpu->highest_mmapped_page,
addr, (len + 8191) & ~8191))
{
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented mprotect call "
"(0x%lx, 0x%lx, 0x%lx)\n",
(unsigned long) arg1,
(unsigned long) arg2,
(unsigned long) arg3);
break;
}
/* Just ignore this. We could make this equal to munmap,
but then we'd have to make sure no anon mmaps gets this
address before a subsequent MAP_FIXED mmap intended to
override it. */
retval = 0;
break;
}
case TARGET_SYS_ioctl:
{
/* We support only a very limited functionality: checking
stdout with TCGETS to perform the isatty function. The
TCGETS ioctl isn't actually performed or the result used by
an isatty () caller in a "hello, world" program; only the
return value is then used. Maybe we shouldn't care about
the environment of the simulator regarding isatty, but
that's been working before, in the xsim simulator. */
if (arg2 == TARGET_TCGETS && arg1 == 1)
retval = isatty (1) ? 0 : cb_host_to_target_errno (cb, EINVAL);
else
retval = -cb_host_to_target_errno (cb, EINVAL);
break;
}
case TARGET_SYS_munmap:
{
USI addr = arg1;
USI len = arg2;
USI result
= unmap_pages (sd, ¤t_cpu->highest_mmapped_page, addr,
len);
retval = result != 0 ? -cb_host_to_target_errno (cb, result) : 0;
break;
}
case TARGET_SYS_wait4:
{
int i;
USI pid = arg1;
USI saddr = arg2;
USI options = arg3;
USI rusagep = arg4;
/* FIXME: We're not properly implementing __WCLONE, and we
don't really need the special casing so we might as well
make this general. */
if ((!(pid == (USI) -1
&& options == (TARGET___WCLONE | TARGET_WNOHANG)
&& saddr != 0)
&& !(pid > 0
&& (options == TARGET___WCLONE
|| options == TARGET___WALL)))
|| rusagep != 0
|| current_cpu->thread_data == NULL)
{
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented wait4 call "
"(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
(unsigned long) arg1,
(unsigned long) arg2,
(unsigned long) arg3,
(unsigned long) arg4);
break;
}
if (pid == (USI) -1)
for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
{
if (current_cpu->thread_data[threadno].threadid
== current_cpu->thread_data[i].parent_threadid
&& current_cpu->thread_data[i].threadid != 0
&& current_cpu->thread_data[i].cpu_context == NULL)
{
/* A zombied child. Get the exit value and clear the
zombied entry so it will be reused. */
sim_core_write_unaligned_4 (current_cpu, pc, 0, saddr,
current_cpu
->thread_data[i].exitval);
retval
= current_cpu->thread_data[i].threadid + TARGET_PID;
memset (¤t_cpu->thread_data[i], 0,
sizeof (current_cpu->thread_data[i]));
goto outer_break;
}
}
else
{
/* We're waiting for a specific PID. If we don't find
it zombied on this run, rerun the syscall. */
for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
if (pid == current_cpu->thread_data[i].threadid + TARGET_PID
&& current_cpu->thread_data[i].cpu_context == NULL)
{
if (saddr != 0)
/* Get the exit value if the caller wants it. */
sim_core_write_unaligned_4 (current_cpu, pc, 0,
saddr,
current_cpu
->thread_data[i]
.exitval);
retval
= current_cpu->thread_data[i].threadid + TARGET_PID;
memset (¤t_cpu->thread_data[i], 0,
sizeof (current_cpu->thread_data[i]));
goto outer_break;
}
sim_pc_set (current_cpu, pc);
}
retval = -cb_host_to_target_errno (cb, ECHILD);
outer_break:
break;
}
case TARGET_SYS_rt_sigaction:
{
USI signum = arg1;
USI old_sa = arg3;
USI new_sa = arg2;
/* The kernel says:
struct sigaction {
__sighandler_t sa_handler;
unsigned long sa_flags;
void (*sa_restorer)(void);
sigset_t sa_mask;
}; */
if (old_sa != 0)
{
sim_core_write_unaligned_4 (current_cpu, pc, 0, old_sa + 0,
current_cpu->sighandler[signum]);
sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 4, 0);
sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 8, 0);
/* We'll assume _NSIG_WORDS is 2 for the kernel. */
sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 12, 0);
sim_core_write_unaligned_4 (current_cpu, pc, 0, arg3 + 16, 0);
}
if (new_sa != 0)
{
USI target_sa_handler
= sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa);
USI target_sa_flags
= sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 4);
USI target_sa_restorer
= sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 8);
USI target_sa_mask_low
= sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 12);
USI target_sa_mask_high
= sim_core_read_unaligned_4 (current_cpu, pc, 0, new_sa + 16);
/* We won't interrupt a syscall so we won't restart it,
but a signal(2) call ends up syscalling rt_sigaction
with this flag, so we have to handle it. The
sa_restorer field contains garbage when not
TARGET_SA_RESTORER, so don't look at it. For the
time being, we don't nest sighandlers, so we
ignore the sa_mask, which simplifies things. */
if ((target_sa_flags != 0
&& target_sa_flags != TARGET_SA_RESTART
&& target_sa_flags != (TARGET_SA_RESTART|TARGET_SA_SIGINFO))
|| target_sa_handler == 0)
{
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented rt_sigaction "
"syscall "
"(0x%lx, 0x%lx: "
"[0x%x, 0x%x, 0x%x, "
"{0x%x, 0x%x}], 0x%lx)\n",
(unsigned long) arg1,
(unsigned long) arg2,
target_sa_handler,
target_sa_flags,
target_sa_restorer,
target_sa_mask_low,
target_sa_mask_high,
(unsigned long) arg3);
break;
}
current_cpu->sighandler[signum] = target_sa_handler;
/* Because we may have unblocked signals, one may now be
pending, if there are threads, that is. */
if (current_cpu->thread_data)
current_cpu->thread_data[threadno].sigpending = 1;
}
retval = 0;
break;
}
case TARGET_SYS_mremap:
{
USI addr = arg1;
USI old_len = arg2;
USI new_len = arg3;
USI flags = arg4;
USI new_addr = arg5;
USI mapped_addr;
if (new_len == old_len)
/* The program and/or library is possibly confused but
this is a valid call. Happens with ipps-1.40 on file
svs_all. */
retval = addr;
else if (new_len < old_len)
{
/* Shrinking is easy. */
if (unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
addr + new_len, old_len - new_len) != 0)
retval = -cb_host_to_target_errno (cb, EINVAL);
else
retval = addr;
}
else if (! is_mapped (sd, ¤t_cpu->highest_mmapped_page,
addr + old_len, new_len - old_len))
{
/* If the extension isn't mapped, we can just add it. */
mapped_addr
= create_map (sd, ¤t_cpu->highest_mmapped_page,
addr + old_len, new_len - old_len);
if (mapped_addr > (USI) -8192)
retval = -cb_host_to_target_errno (cb, -(SI) mapped_addr);
else
retval = addr;
}
else if (flags & TARGET_MREMAP_MAYMOVE)
{
/* Create a whole new map and copy the contents
block-by-block there. We ignore the new_addr argument
for now. */
char buf[8192];
USI prev_addr = addr;
USI prev_len = old_len;
mapped_addr
= create_map (sd, ¤t_cpu->highest_mmapped_page,
-1, new_len);
if (mapped_addr > (USI) -8192)
{
retval = -cb_host_to_target_errno (cb, -(SI) new_addr);
break;
}
retval = mapped_addr;
for (; old_len > 0;
old_len -= 8192, mapped_addr += 8192, addr += 8192)
{
if (sim_core_read_buffer (sd, current_cpu, read_map, buf,
addr, 8192) != 8192
|| sim_core_write_buffer (sd, current_cpu, 0, buf,
mapped_addr, 8192) != 8192)
abort ();
}
if (unmap_pages (sd, ¤t_cpu->highest_mmapped_page,
prev_addr, prev_len) != 0)
abort ();
}
else
retval = -cb_host_to_target_errno (cb, -ENOMEM);
break;
}
case TARGET_SYS_poll:
{
int npollfds = arg2;
int timeout = arg3;
SI ufds = arg1;
SI fd = -1;
HI events = -1;
HI revents = 0;
struct stat buf;
int i;
/* The kernel says:
struct pollfd {
int fd;
short events;
short revents;
}; */
/* Check that this is the expected poll call from
linuxthreads/manager.c; we don't support anything else.
Remember, fd == 0 isn't supported. */
if (npollfds != 1
|| ((fd = sim_core_read_unaligned_4 (current_cpu, pc,
0, ufds)) <= 0)
|| ((events = sim_core_read_unaligned_2 (current_cpu, pc,
0, ufds + 4))
!= TARGET_POLLIN)
|| ((cb->to_fstat) (cb, fd, &buf) != 0
|| (buf.st_mode & S_IFIFO) == 0)
|| current_cpu->thread_data == NULL)
{
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented poll syscall "
"(0x%lx: [0x%x, 0x%x, x], "
"0x%lx, 0x%lx)\n",
(unsigned long) arg1, fd, events,
(unsigned long) arg2,
(unsigned long) arg3);
break;
}
retval = 0;
/* Iterate over threads; find a marker that a writer is
sleeping, waiting for a reader. */
for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
if (current_cpu->thread_data[i].cpu_context != NULL
&& current_cpu->thread_data[i].pipe_read_fd == fd)
{
revents = TARGET_POLLIN;
retval = 1;
break;
}
/* Timeout decreases with whatever time passed between the
last syscall and this. That's not exactly right for the
first call, but it's close enough that it isn't
worthwhile to complicate matters by making that a special
case. */
timeout
-= (TARGET_TIME_MS (current_cpu)
- (current_cpu->thread_data[threadno].last_execution));
/* Arrange to repeat this syscall until timeout or event,
decreasing timeout at each iteration. */
if (timeout > 0 && revents == 0)
{
bfd_byte timeout_buf[4];
bfd_putl32 (timeout, timeout_buf);
(*CPU_REG_STORE (current_cpu)) (current_cpu,
H_GR_R12, timeout_buf, 4);
sim_pc_set (current_cpu, pc);
retval = arg1;
break;
}
sim_core_write_unaligned_2 (current_cpu, pc, 0, ufds + 4 + 2,
revents);
break;
}
case TARGET_SYS_time:
{
retval = (int) (*cb->time) (cb, 0L);
/* At time of this writing, CB_SYSCALL_time doesn't do the
part of setting *arg1 to the return value. */
if (arg1)
sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1, retval);
break;
}
case TARGET_SYS_gettimeofday:
if (arg1 != 0)
{
USI ts = TARGET_TIME (current_cpu);
USI tms = TARGET_TIME_MS (current_cpu);
/* First dword is seconds since TARGET_EPOCH. */
sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1, ts);
/* Second dword is microseconds. */
sim_core_write_unaligned_4 (current_cpu, pc, 0, arg1 + 4,
(tms % 1000) * 1000);
}
if (arg2 != 0)
{
/* Time-zone info is always cleared. */
sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2, 0);
sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2 + 4, 0);
}
retval = 0;
break;
case TARGET_SYS_llseek:
{
/* If it fits, tweak parameters to fit the "generic" 32-bit
lseek and use that. */
SI fd = arg1;
SI offs_hi = arg2;
SI offs_lo = arg3;
SI resultp = arg4;
SI whence = arg5;
retval = 0;
if (!((offs_hi == 0 && offs_lo >= 0)
|| (offs_hi == -1 && offs_lo < 0)))
{
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented llseek offset,"
" fd %d: 0x%x:0x%x\n",
fd, (unsigned) arg2,
(unsigned) arg3);
break;
}
s.func = TARGET_SYS_lseek;
s.arg2 = offs_lo;
s.arg3 = whence;
if (cb_syscall (cb, &s) != CB_RC_OK)
{
sim_io_eprintf (sd, "Break 13: invalid %d? Returned %ld\n", callnum,
s.result);
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGILL);
}
if (s.result < 0)
retval = -s.errcode;
else
{
sim_core_write_unaligned_4 (current_cpu, pc, 0, resultp,
s.result);
sim_core_write_unaligned_4 (current_cpu, pc, 0, resultp + 4,
s.result < 0 ? -1 : 0);
}
break;
}
/* ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
where:
struct iovec {
void *iov_base; Starting address
size_t iov_len; Number of bytes to transfer
}; */
case TARGET_SYS_writev:
{
SI fd = arg1;
SI iov = arg2;
SI iovcnt = arg3;
SI retcnt = 0;
int i;
/* We'll ignore strict error-handling and just do multiple write calls. */
for (i = 0; i < iovcnt; i++)
{
int sysret;
USI iov_base
= sim_core_read_unaligned_4 (current_cpu, pc, 0,
iov + 8*i);
USI iov_len
= sim_core_read_unaligned_4 (current_cpu, pc, 0,
iov + 8*i + 4);
s.func = TARGET_SYS_write;
s.arg1 = fd;
s.arg2 = iov_base;
s.arg3 = iov_len;
if (cb_syscall (cb, &s) != CB_RC_OK)
abort ();
sysret = s.result == -1 ? -s.errcode : s.result;
if (sysret != iov_len)
{
if (i != 0)
abort ();
retcnt = sysret;
break;
}
retcnt += iov_len;
}
retval = retcnt;
}
break;
/* This one does have a generic callback function, but at the time
of this writing, cb_syscall does not have code for it, and we
need target-specific code for the threads implementation
anyway. */
case TARGET_SYS_kill:
{
USI pid = arg1;
USI sig = arg2;
retval = 0;
/* At kill(2), glibc sets signal masks such that the thread
machinery is initialized. Still, there is and was only
one thread. */
if (current_cpu->max_threadid == 0)
{
if (pid != TARGET_PID)
{
retval = -cb_host_to_target_errno (cb, EPERM);
break;
}
/* FIXME: Signal infrastructure (target-to-sim mapping). */
if (sig == TARGET_SIGABRT)
/* A call "abort ()", i.e. "kill (getpid(), SIGABRT)" is
the end-point for failing GCC test-cases. */
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
SIM_SIGABRT);
else
{
sim_io_eprintf (sd, "Unimplemented signal: %d\n", sig);
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
SIM_SIGILL);
}
/* This will not be reached. */
abort ();
}
else
retval = deliver_signal (current_cpu, sig, pid);
break;
}
case TARGET_SYS_rt_sigprocmask:
{
int i;
USI how = arg1;
USI newsetp = arg2;
USI oldsetp = arg3;
if (how != TARGET_SIG_BLOCK
&& how != TARGET_SIG_SETMASK
&& how != TARGET_SIG_UNBLOCK)
{
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented rt_sigprocmask "
"syscall (0x%x, 0x%x, 0x%x)\n",
arg1, arg2, arg3);
break;
}
if (newsetp)
{
USI set_low
= sim_core_read_unaligned_4 (current_cpu, pc, 0,
newsetp);
USI set_high
= sim_core_read_unaligned_4 (current_cpu, pc, 0,
newsetp + 4);
/* The sigmask is kept in the per-thread data, so we may
need to create the first one. */
if (current_cpu->thread_data == NULL)
make_first_thread (current_cpu);
if (how == TARGET_SIG_SETMASK)
for (i = 0; i < 64; i++)
current_cpu->thread_data[threadno].sigdata[i].blocked = 0;
for (i = 0; i < 32; i++)
if ((set_low & (1 << i)))
current_cpu->thread_data[threadno].sigdata[i + 1].blocked
= (how != TARGET_SIG_UNBLOCK);
for (i = 0; i < 31; i++)
if ((set_high & (1 << i)))
current_cpu->thread_data[threadno].sigdata[i + 33].blocked
= (how != TARGET_SIG_UNBLOCK);
/* The mask changed, so a signal may be unblocked for
execution. */
current_cpu->thread_data[threadno].sigpending = 1;
}
if (oldsetp != 0)
{
USI set_low = 0;
USI set_high = 0;
for (i = 0; i < 32; i++)
if (current_cpu->thread_data[threadno]
.sigdata[i + 1].blocked)
set_low |= 1 << i;
for (i = 0; i < 31; i++)
if (current_cpu->thread_data[threadno]
.sigdata[i + 33].blocked)
set_high |= 1 << i;
sim_core_write_unaligned_4 (current_cpu, pc, 0, oldsetp + 0, set_low);
sim_core_write_unaligned_4 (current_cpu, pc, 0, oldsetp + 4, set_high);
}
retval = 0;
break;
}
case TARGET_SYS_sigreturn:
{
int i;
bfd_byte regbuf[4];
int was_sigsuspended;
if (current_cpu->thread_data == NULL
/* The CPU context is saved with the simulator data, not
on the stack as in the real world. */
|| (current_cpu->thread_data[threadno].cpu_context_atsignal
== NULL))
{
retval
= cris_unknown_syscall (current_cpu, pc,
"Invalid sigreturn syscall: "
"no signal handler active "
"(0x%lx, 0x%lx, 0x%lx, 0x%lx, "
"0x%lx, 0x%lx)\n",
(unsigned long) arg1,
(unsigned long) arg2,
(unsigned long) arg3,
(unsigned long) arg4,
(unsigned long) arg5,
(unsigned long) arg6);
break;
}
was_sigsuspended
= current_cpu->thread_data[threadno].sigsuspended;
/* Restore the sigmask, either from the stack copy made when
the sighandler was called, or from the saved state
specifically for sigsuspend(2). */
if (was_sigsuspended)
{
current_cpu->thread_data[threadno].sigsuspended = 0;
for (i = 0; i < 64; i++)
current_cpu->thread_data[threadno].sigdata[i].blocked
= current_cpu->thread_data[threadno]
.sigdata[i].blocked_suspendsave;
}
else
{
USI sp;
USI set_low;
USI set_high;
(*CPU_REG_FETCH (current_cpu)) (current_cpu,
H_GR_SP, regbuf, 4);
sp = bfd_getl32 (regbuf);
set_low
= sim_core_read_unaligned_4 (current_cpu, pc, 0, sp);
set_high
= sim_core_read_unaligned_4 (current_cpu, pc, 0, sp + 4);
for (i = 0; i < 32; i++)
current_cpu->thread_data[threadno].sigdata[i + 1].blocked
= (set_low & (1 << i)) != 0;
for (i = 0; i < 31; i++)
current_cpu->thread_data[threadno].sigdata[i + 33].blocked
= (set_high & (1 << i)) != 0;
}
/* The mask changed, so a signal may be unblocked for
execution. */
current_cpu->thread_data[threadno].sigpending = 1;
memcpy (¤t_cpu->cpu_data_placeholder,
current_cpu->thread_data[threadno].cpu_context_atsignal,
current_cpu->thread_cpu_data_size);
free (current_cpu->thread_data[threadno].cpu_context_atsignal);
current_cpu->thread_data[threadno].cpu_context_atsignal = NULL;
/* The return value must come from the saved R10. */
(*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_R10, regbuf, 4);
retval = bfd_getl32 (regbuf);
/* We must also break the "sigsuspension loop". */
if (was_sigsuspended)
sim_pc_set (current_cpu, sim_pc_get (current_cpu) + 2);
break;
}
case TARGET_SYS_rt_sigsuspend:
{
USI newsetp = arg1;
USI setsize = arg2;
if (setsize != 8)
{
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented rt_sigsuspend syscall"
" arguments (0x%lx, 0x%lx)\n",
(unsigned long) arg1,
(unsigned long) arg2);
break;
}
/* Don't change the signal mask if we're already in
sigsuspend state (i.e. this syscall is a rerun). */
else if (!current_cpu->thread_data[threadno].sigsuspended)
{
USI set_low
= sim_core_read_unaligned_4 (current_cpu, pc, 0,
newsetp);
USI set_high
= sim_core_read_unaligned_4 (current_cpu, pc, 0,
newsetp + 4);
int i;
/* Save the current sigmask and insert the user-supplied
one. */
for (i = 0; i < 32; i++)
{
current_cpu->thread_data[threadno]
.sigdata[i + 1].blocked_suspendsave
= current_cpu->thread_data[threadno]
.sigdata[i + 1].blocked;
current_cpu->thread_data[threadno]
.sigdata[i + 1].blocked = (set_low & (1 << i)) != 0;
}
for (i = 0; i < 31; i++)
{
current_cpu->thread_data[threadno]
.sigdata[i + 33].blocked_suspendsave
= current_cpu->thread_data[threadno]
.sigdata[i + 33].blocked;
current_cpu->thread_data[threadno]
.sigdata[i + 33].blocked = (set_high & (1 << i)) != 0;
}
current_cpu->thread_data[threadno].sigsuspended = 1;
/* The mask changed, so a signal may be unblocked for
execution. */
current_cpu->thread_data[threadno].sigpending = 1;
}
/* Because we don't use arg1 (newsetp) when this syscall is
rerun, it doesn't matter that we overwrite it with the
(constant) return value. */
retval = -cb_host_to_target_errno (cb, EINTR);
sim_pc_set (current_cpu, pc);
break;
}
/* Add case labels here for other syscalls using the 32-bit
"struct stat", provided they have a corresponding simulator
function of course. */
case TARGET_SYS_stat:
case TARGET_SYS_fstat:
{
/* As long as the infrastructure doesn't cache anything
related to the stat mapping, this trick gets us a dual
"struct stat"-type mapping in the least error-prone way. */
const char *saved_map = cb->stat_map;
CB_TARGET_DEFS_MAP *saved_syscall_map = cb->syscall_map;
cb->syscall_map = (CB_TARGET_DEFS_MAP *) syscall_stat32_map;
cb->stat_map = stat32_map;
if (cb_syscall (cb, &s) != CB_RC_OK)
{
abort ();
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
SIM_SIGILL);
}
retval = s.result == -1 ? -s.errcode : s.result;
cb->stat_map = saved_map;
cb->syscall_map = saved_syscall_map;
break;
}
case TARGET_SYS_getcwd:
{
USI buf = arg1;
USI size = arg2;
char *cwd = xmalloc (SIM_PATHMAX);
if (cwd != getcwd (cwd, SIM_PATHMAX))
abort ();
/* FIXME: When and if we support chdir, we need something
a bit more elaborate. */
if (simulator_sysroot[0] != '\0')
strcpy (cwd, "/");
retval = -cb_host_to_target_errno (cb, ERANGE);
if (strlen (cwd) + 1 <= size)
{
retval = strlen (cwd) + 1;
if (sim_core_write_buffer (sd, current_cpu, 0, cwd,
buf, retval)
!= (unsigned int) retval)
retval = -cb_host_to_target_errno (cb, EFAULT);
}
free (cwd);
break;
}
case TARGET_SYS_access:
{
SI path = arg1;
SI mode = arg2;
char *pbuf = xmalloc (SIM_PATHMAX);
int i;
int o = 0;
int hmode = 0;
if (sim_core_read_unaligned_1 (current_cpu, pc, 0, path) == '/')
{
strcpy (pbuf, simulator_sysroot);
o += strlen (simulator_sysroot);
}
for (i = 0; i + o < SIM_PATHMAX; i++)
{
pbuf[i + o]
= sim_core_read_unaligned_1 (current_cpu, pc, 0, path + i);
if (pbuf[i + o] == 0)
break;
}
if (i + o == SIM_PATHMAX)
{
retval = -cb_host_to_target_errno (cb, ENAMETOOLONG);
break;
}
/* Assert that we don't get calls for files for which we
don't have support. */
if (strncmp (pbuf + strlen (simulator_sysroot),
"/proc/", 6) == 0)
abort ();
#define X_AFLAG(x) if (mode & TARGET_ ## x) hmode |= x
X_AFLAG (R_OK);
X_AFLAG (W_OK);
X_AFLAG (X_OK);
X_AFLAG (F_OK);
#undef X_AFLAG
if (access (pbuf, hmode) != 0)
retval = -cb_host_to_target_errno (cb, errno);
else
retval = 0;
free (pbuf);
break;
}
case TARGET_SYS_readlink:
{
SI path = arg1;
SI buf = arg2;
SI bufsiz = arg3;
char *pbuf = xmalloc (SIM_PATHMAX);
char *lbuf = xmalloc (SIM_PATHMAX);
char *lbuf_alloc = lbuf;
int nchars = -1;
int i;
int o = 0;
if (sim_core_read_unaligned_1 (current_cpu, pc, 0, path) == '/')
{
strcpy (pbuf, simulator_sysroot);
o += strlen (simulator_sysroot);
}
for (i = 0; i + o < SIM_PATHMAX; i++)
{
pbuf[i + o]
= sim_core_read_unaligned_1 (current_cpu, pc, 0, path + i);
if (pbuf[i + o] == 0)
break;
}
if (i + o == SIM_PATHMAX)
{
retval = -cb_host_to_target_errno (cb, ENAMETOOLONG);
break;
}
/* Intervene calls for certain files expected in the target
proc file system. */
if (strcmp (pbuf + strlen (simulator_sysroot),
"/proc/" XSTRING (TARGET_PID) "/exe") == 0)
{
char *argv0
= (STATE_PROG_ARGV (sd) != NULL
? *STATE_PROG_ARGV (sd) : NULL);
if (argv0 == NULL || *argv0 == '.')
{
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented readlink syscall "
"(0x%lx: [\"%s\"], 0x%lx)\n",
(unsigned long) arg1, pbuf,
(unsigned long) arg2);
break;
}
else if (*argv0 == '/')
{
if (strncmp (simulator_sysroot, argv0,
strlen (simulator_sysroot)) == 0)
argv0 += strlen (simulator_sysroot);
strcpy (lbuf, argv0);
nchars = strlen (argv0) + 1;
}
else
{
if (getcwd (lbuf, SIM_PATHMAX) != NULL
&& strlen (lbuf) + 2 + strlen (argv0) < SIM_PATHMAX)
{
if (strncmp (simulator_sysroot, lbuf,
strlen (simulator_sysroot)) == 0)
lbuf += strlen (simulator_sysroot);
strcat (lbuf, "/");
strcat (lbuf, argv0);
nchars = strlen (lbuf) + 1;
}
else
abort ();
}
}
else
nchars = readlink (pbuf, lbuf, SIM_PATHMAX);
/* We trust that the readlink result returns a *relative*
link, or one already adjusted for the file-path-prefix.
(We can't generally tell the difference, so we go with
the easiest decision; no adjustment.) */
if (nchars == -1)
{
retval = -cb_host_to_target_errno (cb, errno);
break;
}
if (bufsiz < nchars)
nchars = bufsiz;
if (sim_core_write_buffer (sd, current_cpu, write_map, lbuf,
buf, nchars) != (unsigned int) nchars)
retval = -cb_host_to_target_errno (cb, EFAULT);
else
retval = nchars;
free (pbuf);
free (lbuf_alloc);
break;
}
case TARGET_SYS_sched_getscheduler:
{
USI pid = arg1;
/* FIXME: Search (other) existing threads. */
if (pid != 0 && pid != TARGET_PID)
retval = -cb_host_to_target_errno (cb, ESRCH);
else
retval = TARGET_SCHED_OTHER;
break;
}
case TARGET_SYS_sched_getparam:
{
USI pid = arg1;
USI paramp = arg2;
/* The kernel says:
struct sched_param {
int sched_priority;
}; */
if (pid != 0 && pid != TARGET_PID)
retval = -cb_host_to_target_errno (cb, ESRCH);
else
{
/* FIXME: Save scheduler setting before threads are
created too. */
sim_core_write_unaligned_4 (current_cpu, pc, 0, paramp,
current_cpu->thread_data != NULL
? (current_cpu
->thread_data[threadno]
.priority)
: 0);
retval = 0;
}
break;
}
case TARGET_SYS_sched_setparam:
{
USI pid = arg1;
USI paramp = arg2;
if ((pid != 0 && pid != TARGET_PID)
|| sim_core_read_unaligned_4 (current_cpu, pc, 0,
paramp) != 0)
retval = -cb_host_to_target_errno (cb, EINVAL);
else
retval = 0;
break;
}
case TARGET_SYS_sched_setscheduler:
{
USI pid = arg1;
USI policy = arg2;
USI paramp = arg3;
if ((pid != 0 && pid != TARGET_PID)
|| policy != TARGET_SCHED_OTHER
|| sim_core_read_unaligned_4 (current_cpu, pc, 0,
paramp) != 0)
retval = -cb_host_to_target_errno (cb, EINVAL);
else
/* FIXME: Save scheduler setting to be read in later
sched_getparam calls. */
retval = 0;
break;
}
case TARGET_SYS_sched_yield:
/* We reschedule to the next thread after a syscall anyway, so
we don't have to do anything here than to set the return
value. */
retval = 0;
break;
case TARGET_SYS_sched_get_priority_min:
case TARGET_SYS_sched_get_priority_max:
if (arg1 != 0)
retval = -cb_host_to_target_errno (cb, EINVAL);
else
retval = 0;
break;
case TARGET_SYS_ugetrlimit:
{
unsigned int curlim, maxlim;
if (arg1 != TARGET_RLIMIT_STACK && arg1 != TARGET_RLIMIT_NOFILE)
{
retval = -cb_host_to_target_errno (cb, EINVAL);
break;
}
/* The kernel says:
struct rlimit {
unsigned long rlim_cur;
unsigned long rlim_max;
}; */
if (arg1 == TARGET_RLIMIT_NOFILE)
{
/* Sadly a very low limit. Better not lie, though. */
maxlim = curlim = MAX_CALLBACK_FDS;
}
else /* arg1 == TARGET_RLIMIT_STACK */
{
maxlim = 0xffffffff;
curlim = 0x800000;
}
sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2, curlim);
sim_core_write_unaligned_4 (current_cpu, pc, 0, arg2 + 4, maxlim);
retval = 0;
break;
}
case TARGET_SYS_setrlimit:
if (arg1 != TARGET_RLIMIT_STACK)
{
retval = -cb_host_to_target_errno (cb, EINVAL);
break;
}
/* FIXME: Save values for future ugetrlimit calls. */
retval = 0;
break;
/* Provide a very limited subset of the sysctl functions, and
abort for the rest. */
case TARGET_SYS__sysctl:
{
/* The kernel says:
struct __sysctl_args {
int *name;
int nlen;
void *oldval;
size_t *oldlenp;
void *newval;
size_t newlen;
unsigned long __unused[4];
}; */
SI name = sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1);
SI name0 = name == 0
? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, name);
SI name1 = name == 0
? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, name + 4);
SI nlen
= sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 4);
SI oldval
= sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 8);
SI oldlenp
= sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 12);
SI oldlen = oldlenp == 0
? 0 : sim_core_read_unaligned_4 (current_cpu, pc, 0, oldlenp);
SI newval
= sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 16);
SI newlen
= sim_core_read_unaligned_4 (current_cpu, pc, 0, arg1 + 20);
if (name0 == TARGET_CTL_KERN && name1 == TARGET_CTL_KERN_VERSION)
{
SI to_write = oldlen < (SI) sizeof (TARGET_UTSNAME)
? oldlen : (SI) sizeof (TARGET_UTSNAME);
sim_core_write_unaligned_4 (current_cpu, pc, 0, oldlenp,
sizeof (TARGET_UTSNAME));
if (sim_core_write_buffer (sd, current_cpu, write_map,
TARGET_UTSNAME, oldval,
to_write)
!= (unsigned int) to_write)
retval = -cb_host_to_target_errno (cb, EFAULT);
else
retval = 0;
break;
}
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented _sysctl syscall "
"(0x%lx: [0x%lx, 0x%lx],"
" 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
(unsigned long) name,
(unsigned long) name0,
(unsigned long) name1,
(unsigned long) nlen,
(unsigned long) oldval,
(unsigned long) oldlenp,
(unsigned long) newval,
(unsigned long) newlen);
break;
}
case TARGET_SYS_exit:
{
/* Here for all but the last thread. */
int i;
int pid
= current_cpu->thread_data[threadno].threadid + TARGET_PID;
int ppid
= (current_cpu->thread_data[threadno].parent_threadid
+ TARGET_PID);
int exitsig = current_cpu->thread_data[threadno].exitsig;
/* Any children are now all orphans. */
for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
if (current_cpu->thread_data[i].parent_threadid
== current_cpu->thread_data[threadno].threadid)
/* Make getppid(2) return 1 for them, poor little ones. */
current_cpu->thread_data[i].parent_threadid = -TARGET_PID + 1;
/* Free the cpu context data. When the parent has received
the exit status, we'll clear the entry too. */
free (current_cpu->thread_data[threadno].cpu_context);
current_cpu->thread_data[threadno].cpu_context = NULL;
current_cpu->m1threads--;
if (arg1 != 0)
{
sim_io_eprintf (sd, "Thread %d exited with status %d\n",
pid, arg1);
sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped,
SIM_SIGILL);
}
/* Still, we may want to support non-zero exit values. */
current_cpu->thread_data[threadno].exitval = arg1 << 8;
if (exitsig)
deliver_signal (current_cpu, exitsig, ppid);
break;
}
case TARGET_SYS_clone:
{
int nthreads = current_cpu->m1threads + 1;
void *thread_cpu_data;
bfd_byte old_sp_buf[4];
bfd_byte sp_buf[4];
const bfd_byte zeros[4] = { 0, 0, 0, 0 };
int i;
/* That's right, the syscall clone arguments are reversed
compared to sys_clone notes in clone(2) and compared to
other Linux ports (i.e. it's the same order as in the
clone(2) libcall). */
USI flags = arg2;
USI newsp = arg1;
if (nthreads == SIM_TARGET_MAX_THREADS)
{
retval = -cb_host_to_target_errno (cb, EAGAIN);
break;
}
/* FIXME: Implement the low byte. */
if ((flags & ~TARGET_CSIGNAL) !=
(TARGET_CLONE_VM
| TARGET_CLONE_FS
| TARGET_CLONE_FILES
| TARGET_CLONE_SIGHAND)
|| newsp == 0)
{
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented clone syscall "
"(0x%lx, 0x%lx)\n",
(unsigned long) arg1,
(unsigned long) arg2);
break;
}
if (current_cpu->thread_data == NULL)
make_first_thread (current_cpu);
/* The created thread will get the new SP and a cleared R10.
Since it's created out of a copy of the old thread and we
don't have a set-register-function that just take the
cpu_data as a parameter, we set the childs values first,
and write back or overwrite them in the parent after the
copy. */
(*CPU_REG_FETCH (current_cpu)) (current_cpu,
H_GR_SP, old_sp_buf, 4);
bfd_putl32 (newsp, sp_buf);
(*CPU_REG_STORE (current_cpu)) (current_cpu,
H_GR_SP, sp_buf, 4);
(*CPU_REG_STORE (current_cpu)) (current_cpu,
H_GR_R10, (bfd_byte *) zeros, 4);
thread_cpu_data
= (*current_cpu
->make_thread_cpu_data) (current_cpu,
¤t_cpu->cpu_data_placeholder);
(*CPU_REG_STORE (current_cpu)) (current_cpu,
H_GR_SP, old_sp_buf, 4);
retval = ++current_cpu->max_threadid + TARGET_PID;
/* Find an unused slot. After a few threads have been created
and exited, the array is expected to be a bit fragmented.
We don't reuse the first entry, though, that of the
original thread. */
for (i = 1; i < SIM_TARGET_MAX_THREADS; i++)
if (current_cpu->thread_data[i].cpu_context == NULL
/* Don't reuse a zombied entry. */
&& current_cpu->thread_data[i].threadid == 0)
break;
memcpy (¤t_cpu->thread_data[i],
¤t_cpu->thread_data[threadno],
sizeof (current_cpu->thread_data[i]));
current_cpu->thread_data[i].cpu_context = thread_cpu_data;
current_cpu->thread_data[i].cpu_context_atsignal = NULL;
current_cpu->thread_data[i].threadid = current_cpu->max_threadid;
current_cpu->thread_data[i].parent_threadid
= current_cpu->thread_data[threadno].threadid;
current_cpu->thread_data[i].pipe_read_fd = 0;
current_cpu->thread_data[i].pipe_write_fd = 0;
current_cpu->thread_data[i].at_syscall = 0;
current_cpu->thread_data[i].sigpending = 0;
current_cpu->thread_data[i].sigsuspended = 0;
current_cpu->thread_data[i].exitsig = flags & TARGET_CSIGNAL;
current_cpu->m1threads = nthreads;
break;
}
/* Better watch these in case they do something necessary. */
case TARGET_SYS_socketcall:
retval = -cb_host_to_target_errno (cb, ENOSYS);
break;
case TARGET_SYS_set_thread_area:
/* Do the same error check as Linux. */
if (arg1 & 255)
{
retval = -cb_host_to_target_errno (cb, EINVAL);
break;
}
(*current_cpu->set_target_thread_data) (current_cpu, arg1);
retval = 0;
break;
unimplemented_syscall:
default:
retval
= cris_unknown_syscall (current_cpu, pc,
"Unimplemented syscall: %d "
"(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
callnum, arg1, arg2, arg3, arg4, arg5,
arg6);
}
}
/* Minimal support for fcntl F_GETFL as used in open+fdopen. */
if (callnum == TARGET_SYS_open)
{
current_cpu->last_open_fd = retval;
current_cpu->last_open_flags = arg2;
}
current_cpu->last_syscall = callnum;
/* A system call is a rescheduling point. For the time being, we don't
reschedule anywhere else. */
if (current_cpu->m1threads != 0
/* We need to schedule off from an exiting thread that is the
second-last one. */
|| (current_cpu->thread_data != NULL
&& current_cpu->thread_data[threadno].cpu_context == NULL))
{
bfd_byte retval_buf[4];
current_cpu->thread_data[threadno].last_execution
= TARGET_TIME_MS (current_cpu);
bfd_putl32 (retval, retval_buf);
(*CPU_REG_STORE (current_cpu)) (current_cpu, H_GR_R10, retval_buf, 4);
current_cpu->thread_data[threadno].at_syscall = 1;
reschedule (current_cpu);
(*CPU_REG_FETCH (current_cpu)) (current_cpu, H_GR_R10, retval_buf, 4);
retval = bfd_getl32 (retval_buf);
}
return retval;
}
/* Callback from simulator write saying that the pipe at (reader, writer)
is now non-empty (so the writer should wait until the pipe is empty, at
least not write to this or any other pipe). Simplest is to just wait
until the pipe is empty. */
static void
cris_pipe_nonempty (host_callback *cb ATTRIBUTE_UNUSED,
int reader, int writer)
{
SIM_CPU *cpu = current_cpu_for_cb_callback;
const bfd_byte zeros[4] = { 0, 0, 0, 0 };
/* It's the current thread: we just have to re-run the current
syscall instruction (presumably "break 13") and change the syscall
to the special simulator-wait code. Oh, and set a marker that
we're waiting, so we can disambiguate the special call from a
program error.
This function may be called multiple times between cris_pipe_empty,
but we must avoid e.g. decreasing PC every time. Check fd markers
to tell. */
if (cpu->thread_data == NULL)
{
sim_io_eprintf (CPU_STATE (cpu),
"Terminating simulation due to writing pipe rd:wr %d:%d"
" from one single thread\n", reader, writer);
sim_engine_halt (CPU_STATE (cpu), cpu,
NULL, sim_pc_get (cpu), sim_stopped, SIM_SIGILL);
}
else if (cpu->thread_data[cpu->threadno].pipe_write_fd == 0)
{
cpu->thread_data[cpu->threadno].pipe_write_fd = writer;
cpu->thread_data[cpu->threadno].pipe_read_fd = reader;
/* FIXME: We really shouldn't change registers other than R10 in
syscalls (like R9), here or elsewhere. */
(*CPU_REG_STORE (cpu)) (cpu, H_GR_R9, (bfd_byte *) zeros, 4);
sim_pc_set (cpu, sim_pc_get (cpu) - 2);
}
}
/* Callback from simulator close or read call saying that the pipe at
(reader, writer) is now empty (so the writer can write again, perhaps
leave a waiting state). If there are bytes remaining, they couldn't be
consumed (perhaps due to the pipe closing). */
static void
cris_pipe_empty (host_callback *cb,
int reader,
int writer)
{
int i;
SIM_CPU *cpu = current_cpu_for_cb_callback;
SIM_DESC sd = CPU_STATE (current_cpu_for_cb_callback);
bfd_byte r10_buf[4];
int remaining
= cb->pipe_buffer[writer].size - cb->pipe_buffer[reader].size;
/* We need to find the thread that waits for this pipe. */
for (i = 0; i < SIM_TARGET_MAX_THREADS; i++)
if (cpu->thread_data[i].cpu_context
&& cpu->thread_data[i].pipe_write_fd == writer)
{
int retval;
/* Temporarily switch to this cpu context, so we can change the
PC by ordinary calls. */
memcpy (cpu->thread_data[cpu->threadno].cpu_context,
&cpu->cpu_data_placeholder,
cpu->thread_cpu_data_size);
memcpy (&cpu->cpu_data_placeholder,
cpu->thread_data[i].cpu_context,
cpu->thread_cpu_data_size);
/* The return value is supposed to contain the number of
written bytes, which is the number of bytes requested and
returned at the write call. You might think the right
thing is to adjust the return-value to be only the
*consumed* number of bytes, but it isn't. We're only
called if the pipe buffer is fully consumed or it is being
closed, possibly with remaining bytes. For the latter
case, the writer is still supposed to see success for
PIPE_BUF bytes (a constant which we happen to know and is
unlikely to change). The return value may also be a
negative number; an error value. This case is covered
because "remaining" is always >= 0. */
(*CPU_REG_FETCH (cpu)) (cpu, H_GR_R10, r10_buf, 4);
retval = (int) bfd_getl_signed_32 (r10_buf);
if (retval - remaining > TARGET_PIPE_BUF)
{
bfd_putl32 (retval - remaining, r10_buf);
(*CPU_REG_STORE (cpu)) (cpu, H_GR_R10, r10_buf, 4);
}
sim_pc_set (cpu, sim_pc_get (cpu) + 2);
memcpy (cpu->thread_data[i].cpu_context,
&cpu->cpu_data_placeholder,
cpu->thread_cpu_data_size);
memcpy (&cpu->cpu_data_placeholder,
cpu->thread_data[cpu->threadno].cpu_context,
cpu->thread_cpu_data_size);
cpu->thread_data[i].pipe_read_fd = 0;
cpu->thread_data[i].pipe_write_fd = 0;
return;
}
abort ();
}
/* We have a simulator-specific notion of time. See TARGET_TIME. */
static long
cris_time (host_callback *cb ATTRIBUTE_UNUSED, long *t)
{
long retval = TARGET_TIME (current_cpu_for_cb_callback);
if (t)
*t = retval;
return retval;
}
/* Set target-specific callback data. */
void
cris_set_callbacks (host_callback *cb)
{
/* Yeargh, have to cast away constness to avoid warnings. */
cb->syscall_map = (CB_TARGET_DEFS_MAP *) syscall_map;
cb->errno_map = (CB_TARGET_DEFS_MAP *) errno_map;
/* The kernel stat64 layout. If we see a file > 2G, the "long"
parameter to cb_store_target_endian will make st_size negative.
Similarly for st_ino. FIXME: Find a 64-bit type, and use it
*unsigned*, and/or add syntax for signed-ness. */
cb->stat_map = stat_map;
cb->open_map = (CB_TARGET_DEFS_MAP *) open_map;
cb->pipe_nonempty = cris_pipe_nonempty;
cb->pipe_empty = cris_pipe_empty;
cb->time = cris_time;
}
/* Process an address exception. */
void
cris_core_signal (SIM_DESC sd, SIM_CPU *current_cpu, sim_cia cia,
unsigned int map, int nr_bytes, address_word addr,
transfer_type transfer, sim_core_signals sig)
{
sim_core_signal (sd, current_cpu, cia, map, nr_bytes, addr,
transfer, sig);
}
|